>From 85d46691d35f795b51477cadda944ed2b3cb35ef Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 15 May 2013 17:36:44 +0200 Subject: [PATCH 13/15] AD: Add additional service to support Global Catalog lookups When fixed host names of AD servers are configured in the config file, we can't know (unlike when service discovery is at play) if the servers are Global Catalogs or not. This patch adds a private data to servers read from the config file that denote whether the server can be tried for contacting the Global Catalog port or just LDAP. The GC or LDAP URIs are generated based on contents of this private data structure. Because SSSD sticks to a working server, we don't have to disable or remove the faulty GC servers from the list. --- src/providers/ad/ad_common.c | 163 ++++++++++++++++++++++++++++++++++++------- src/providers/ad/ad_common.h | 5 ++ src/providers/ad/ad_init.c | 16 +++-- 3 files changed, 153 insertions(+), 31 deletions(-) diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c index b32237b7b74508d2936729ae5e049dc8201b37a2..608188c4eacbdbe9417d6395e2506d9425c931b0 100644 --- a/src/providers/ad/ad_common.c +++ b/src/providers/ad/ad_common.c @@ -25,6 +25,11 @@ #include "providers/ad/ad_opts.h" #include "providers/dp_dyndns.h" +struct ad_server_data { + bool gc; + const char *server; +}; + errno_t ad_get_common_options(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb, @@ -140,13 +145,14 @@ done: static void ad_resolve_callback(void *private_data, struct fo_server *server); -#define ad_primary_servers_init(mem_ctx, bectx, servers, options) \ - _ad_servers_init(mem_ctx, bectx, servers, options, true) -#define ad_backup_servers_init(mem_ctx, bectx, servers, options) \ - _ad_servers_init(mem_ctx, bectx, servers, options, false) +#define ad_primary_servers_init(mem_ctx, service, bectx, servers, options) \ + _ad_servers_init(mem_ctx, service, bectx, servers, options, true) +#define ad_backup_servers_init(mem_ctx, service, bectx, servers, options) \ + _ad_servers_init(mem_ctx, service, bectx, servers, options, false) static errno_t _ad_servers_init(TALLOC_CTX *mem_ctx, + struct ad_service *service, struct be_ctx *bectx, const char *servers, struct ad_options *options, @@ -156,6 +162,7 @@ _ad_servers_init(TALLOC_CTX *mem_ctx, errno_t ret = 0; char **list; char *ad_domain; + struct ad_server_data *sdata; TALLOC_CTX *tmp_ctx; tmp_ctx = talloc_new(NULL); @@ -202,7 +209,37 @@ _ad_servers_init(TALLOC_CTX *mem_ctx, goto done; } - ret = be_fo_add_server(bectx, AD_SERVICE_NAME, list[i], 0, NULL, primary); + sdata = talloc(service, struct ad_server_data); + if (sdata == NULL) { + ret = ENOMEM; + goto done; + } + sdata->gc = true; + sdata->server = talloc_strdup(sdata, list[i]); + if (sdata->server == NULL) { + ret = ENOMEM; + goto done; + } + + ret = be_fo_add_server(bectx, AD_SERVICE_NAME, list[i], 0, sdata, primary); + if (ret && ret != EEXIST) { + DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to add server\n")); + goto done; + } + + sdata = talloc(service, struct ad_server_data); + if (sdata == NULL) { + ret = ENOMEM; + goto done; + } + sdata->gc = false; + sdata->server = talloc_strdup(sdata, list[i]); + if (sdata->server == NULL) { + ret = ENOMEM; + goto done; + } + + ret = be_fo_add_server(bectx, AD_SERVICE_NAME, list[i], 0, sdata, primary); if (ret && ret != EEXIST) { DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to add server\n")); goto done; @@ -217,7 +254,37 @@ done: static int ad_user_data_cmp(void *ud1, void *ud2) { - return strcasecmp((char*) ud1, (char*) ud2); + struct ad_server_data *sd1, *sd2; + + sd1 = talloc_get_type(ud1, struct ad_server_data); + sd2 = talloc_get_type(ud2, struct ad_server_data); + if (sd1 == NULL || sd2 == NULL) { + DEBUG(SSSDBG_TRACE_FUNC, ("No user data\n")); + return sd1 == sd2 ? 0 : 1; + } + + DEBUG(SSSDBG_TRACE_LIBS, ("Comparing %s (%s) with %s (%s)\n", + sd1->server, sd1->gc ? "GC" : "LDAP", + sd2->server, sd2->gc ? "GC" : "LDAP")); + + if (strcasecmp(sd1->server, sd2->server) == 0 && + sd1->gc == sd2->gc) { + return 0; + } + + return 1; +} + +static void ad_online_cb(void *pvt) +{ + struct ad_service *service = talloc_get_type(pvt, struct ad_service); + + if (service == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid private pointer\n")); + return; + } + + DEBUG(SSSDBG_TRACE_FUNC, ("The AD provider is online\n")); } errno_t @@ -242,7 +309,15 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx, } service->sdap = talloc_zero(service, struct sdap_service); - if (!service->sdap) { + service->gc = talloc_zero(service, struct sdap_service); + if (!service->sdap || !service->gc) { + ret = ENOMEM; + goto done; + } + + service->sdap->name = talloc_strdup(service->sdap, AD_SERVICE_NAME); + service->gc->name = talloc_strdup(service->gc, AD_SERVICE_NAME); + if (!service->sdap->name || !service->gc->name) { ret = ENOMEM; goto done; } @@ -259,18 +334,14 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx, goto done; } - service->sdap->name = talloc_strdup(service, AD_SERVICE_NAME); - if (!service->sdap->name) { - ret = ENOMEM; - goto done; - } - - service->krb5_service->name = talloc_strdup(service, AD_SERVICE_NAME); + service->krb5_service->name = talloc_strdup(service->krb5_service, + AD_SERVICE_NAME); if (!service->krb5_service->name) { ret = ENOMEM; goto done; } service->sdap->kinit_service_name = service->krb5_service->name; + service->gc->kinit_service_name = service->krb5_service->name; realm = dp_opt_get_string(options->basic, AD_KRB5_REALM); if (!realm) { @@ -291,18 +362,26 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx, primary_servers = BE_SRV_IDENTIFIER; } - ret = ad_primary_servers_init(mem_ctx, bectx, primary_servers, options); + ret = ad_primary_servers_init(mem_ctx, service, bectx, + primary_servers, options); if (ret != EOK) { goto done; } if (backup_servers) { - ret = ad_backup_servers_init(mem_ctx, bectx, backup_servers, options); + ret = ad_backup_servers_init(mem_ctx, service, bectx, + backup_servers, options); if (ret != EOK) { goto done; } } + ret = be_add_online_cb(bectx, bectx, ad_online_cb, service, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Could not set up AD online callback\n")); + return ret; + } + ret = be_fo_service_add_callback(mem_ctx, bectx, AD_SERVICE_NAME, ad_resolve_callback, service); if (ret != EOK) { @@ -330,8 +409,9 @@ ad_resolve_callback(void *private_data, struct fo_server *server) struct sockaddr_storage *sockaddr; char *address; const char *safe_address; - char *new_uri; + char *new_uri, *new_gc_uri; const char *srv_name; + struct ad_server_data *sdata = NULL; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { @@ -339,6 +419,12 @@ ad_resolve_callback(void *private_data, struct fo_server *server) return; } + sdata = fo_get_server_user_data(server); + if (fo_is_srv_lookup(server) == false && sdata == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("No user data?\n")); + return; + } + service = talloc_get_type(private_data, struct ad_service); if (!service) { ret = EINVAL; @@ -354,13 +440,6 @@ ad_resolve_callback(void *private_data, struct fo_server *server) goto done; } - sockaddr = resolv_get_sockaddr_address(tmp_ctx, srvaddr, LDAP_PORT); - if (sockaddr == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, ("resolv_get_sockaddr_address failed.\n")); - ret = EIO; - goto done; - } - address = resolv_get_string_address(tmp_ctx, srvaddr); if (address == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, ("resolv_get_string_address failed.\n")); @@ -375,7 +454,7 @@ ad_resolve_callback(void *private_data, struct fo_server *server) goto done; } - new_uri = talloc_asprintf(service, "ldap://%s", srv_name); + new_uri = talloc_asprintf(service->sdap, "ldap://%s", srv_name); if (!new_uri) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to copy URI\n")); ret = ENOMEM; @@ -383,12 +462,44 @@ ad_resolve_callback(void *private_data, struct fo_server *server) } DEBUG(SSSDBG_CONF_SETTINGS, ("Constructed uri '%s'\n", new_uri)); + talloc_zfree(service->gc->uri); + talloc_zfree(service->gc->sockaddr); + if (sdata && sdata->gc) { + new_gc_uri = talloc_asprintf(service->gc, "%s:%d", + new_uri, AD_GC_PORT); + if (!new_gc_uri) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to append to URI\n")); + ret = ENOMEM; + goto done; + } + DEBUG(SSSDBG_CONF_SETTINGS, ("Constructed GC uri '%s'\n", new_gc_uri)); + + sockaddr = resolv_get_sockaddr_address(tmp_ctx, srvaddr, AD_GC_PORT); + if (sockaddr == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("resolv_get_sockaddr_address failed.\n")); + ret = EIO; + goto done; + } + + service->gc->uri = new_gc_uri; + service->gc->sockaddr = talloc_steal(service->gc, sockaddr); + } + + sockaddr = resolv_get_sockaddr_address(tmp_ctx, srvaddr, LDAP_PORT); + if (sockaddr == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("resolv_get_sockaddr_address failed.\n")); + ret = EIO; + goto done; + } + /* free old one and replace with new one */ talloc_zfree(service->sdap->uri); service->sdap->uri = new_uri; talloc_zfree(service->sdap->sockaddr); - service->sdap->sockaddr = talloc_steal(service, sockaddr); + service->sdap->sockaddr = talloc_steal(service->sdap, sockaddr); + /* Write krb5 info files */ safe_address = sss_escape_ip_address(tmp_ctx, srvaddr->family, address); diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h index 792f32e0876ad73b0fb422c4cc7ebc86058e7ed6..801815528c30ef05956eb51dce7cc6f8b161ffa8 100644 --- a/src/providers/ad/ad_common.h +++ b/src/providers/ad/ad_common.h @@ -27,6 +27,8 @@ #include "providers/ldap/ldap_common.h" #define AD_SERVICE_NAME "AD" +/* The port the Global Catalog runs on */ +#define AD_GC_PORT 3268 struct ad_options; @@ -44,11 +46,14 @@ enum ad_basic_opt { struct ad_id_ctx { struct sdap_id_ctx *sdap_id_ctx; + struct sdap_id_conn_ctx *ldap_ctx; + struct sdap_id_conn_ctx *gc_ctx; struct ad_options *ad_options; }; struct ad_service { struct sdap_service *sdap; + struct sdap_service *gc; struct krb5_service *krb5_service; }; diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c index aada14ec7dadb2db5cc67ecc0e1d9c631c974f07..cb73aca3afb2cd80b165670e1fa84d375a80ace1 100644 --- a/src/providers/ad/ad_init.c +++ b/src/providers/ad/ad_init.c @@ -140,6 +140,12 @@ sssm_ad_id_init(struct be_ctx *bectx, return ENOMEM; } ad_ctx->sdap_id_ctx = sdap_ctx; + ad_ctx->ldap_ctx = sdap_ctx->conn; + + ad_ctx->gc_ctx = sdap_id_ctx_conn_add(sdap_ctx, ad_options->service->gc); + if (sdap_ctx == NULL) { + return ENOMEM; + } ret = ad_dyndns_init(sdap_ctx->be, ad_options); if (ret != EOK) { @@ -148,11 +154,6 @@ sssm_ad_id_init(struct be_ctx *bectx, /* Continue without DNS updates */ } - ret = sdap_id_setup_tasks(sdap_ctx); - if (ret != EOK) { - goto done; - } - ret = sdap_setup_child(); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, @@ -169,6 +170,11 @@ sssm_ad_id_init(struct be_ctx *bectx, goto done; } + ret = sdap_id_setup_tasks(sdap_ctx); + if (ret != EOK) { + goto done; + } + /* Set up the ID mapping object */ ret = sdap_idmap_init(sdap_ctx, sdap_ctx, &sdap_ctx->opts->idmap_ctx); if (ret != EOK) goto done; -- 1.8.2.1