diff options
author | Jakub Hrozek <jhrozek@redhat.com> | 2013-05-15 17:36:44 +0200 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2013-06-07 00:14:13 +0200 |
commit | 55d80b1301fe969fb4ba2b9481027887b9462dbb (patch) | |
tree | 7f4f7fdc4a1f913c08506452450ac2972b01acdb /src | |
parent | d27d7f2c270b69d0805633c4bedcf6d806acd5cd (diff) | |
download | sssd-55d80b1301fe969fb4ba2b9481027887b9462dbb.tar.gz sssd-55d80b1301fe969fb4ba2b9481027887b9462dbb.tar.bz2 sssd-55d80b1301fe969fb4ba2b9481027887b9462dbb.zip |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/providers/ad/ad_common.c | 190 | ||||
-rw-r--r-- | src/providers/ad/ad_common.h | 5 | ||||
-rw-r--r-- | src/providers/ad/ad_init.c | 16 |
3 files changed, 178 insertions, 33 deletions
diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c index 713f3194..ea124d96 100644 --- a/src/providers/ad/ad_common.c +++ b/src/providers/ad/ad_common.c @@ -25,6 +25,10 @@ #include "providers/ad/ad_opts.h" #include "providers/dp_dyndns.h" +struct ad_server_data { + bool gc; +}; + errno_t ad_get_common_options(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb, @@ -142,6 +146,7 @@ ad_resolve_callback(void *private_data, struct fo_server *server); 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, @@ -151,6 +156,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); @@ -176,9 +182,33 @@ _ad_servers_init(TALLOC_CTX *mem_ctx, continue; } + sdata = talloc(service, struct ad_server_data); + if (sdata == NULL) { + ret = ENOMEM; + goto done; + } + sdata->gc = true; + + ret = be_fo_add_srv_server(bectx, AD_SERVICE_NAME, "gc", + ad_domain, BE_FO_PROTO_TCP, + false, sdata); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + ("Failed to add service discovery to failover: [%s]", + strerror(ret))); + goto done; + } + + sdata = talloc(service, struct ad_server_data); + if (sdata == NULL) { + ret = ENOMEM; + goto done; + } + sdata->gc = false; + ret = be_fo_add_srv_server(bectx, AD_SERVICE_NAME, "ldap", ad_domain, BE_FO_PROTO_TCP, - false, NULL); + false, sdata); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to add service discovery to failover: [%s]", @@ -197,7 +227,27 @@ _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; + + 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; + + 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; @@ -211,22 +261,53 @@ done: } static inline errno_t -ad_primary_servers_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx, - const char *servers, struct ad_options *options) +ad_primary_servers_init(TALLOC_CTX *mem_ctx, struct ad_service *service, + struct be_ctx *bectx, const char *servers, + struct ad_options *options) { - return _ad_servers_init(mem_ctx, bectx, servers, options, true); + return _ad_servers_init(mem_ctx, service, bectx, servers, options, true); } static inline errno_t -ad_backup_servers_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx, - const char *servers, struct ad_options *options) +ad_backup_servers_init(TALLOC_CTX *mem_ctx, struct ad_service *service, + struct be_ctx *bectx, const char *servers, + struct ad_options *options) { - return _ad_servers_init(mem_ctx, bectx, servers, options, false); + return _ad_servers_init(mem_ctx, service, bectx, servers, options, false); } 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 with %s\n", + sd1->gc ? "GC" : "LDAP", + sd2->gc ? "GC" : "LDAP")); + + if (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 @@ -251,7 +332,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; } @@ -268,18 +357,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) { @@ -300,18 +385,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) { @@ -341,6 +434,7 @@ ad_resolve_callback(void *private_data, struct fo_server *server) const char *safe_address; char *new_uri; const char *srv_name; + struct ad_server_data *sdata = NULL; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { @@ -348,6 +442,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; @@ -363,13 +463,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")); @@ -384,7 +477,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; @@ -392,12 +485,53 @@ ad_resolve_callback(void *private_data, struct fo_server *server) } DEBUG(SSSDBG_CONF_SETTINGS, ("Constructed uri '%s'\n", new_uri)); + 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); + + talloc_zfree(service->gc->uri); + talloc_zfree(service->gc->sockaddr); + if (sdata && sdata->gc) { + service->gc->uri = talloc_asprintf(service->gc, "%s:%d", + new_uri, AD_GC_PORT); + + service->gc->sockaddr = resolv_get_sockaddr_address(service->gc, + srvaddr, + AD_GC_PORT); + } else { + /* Make sure there always is an URI even if we know that this + * server doesn't support GC. That way the lookup would go through + * just not return anything + */ + service->gc->uri = talloc_strdup(service->gc, service->sdap->uri); + service->gc->sockaddr = talloc_memdup(service->gc, service->sdap->sockaddr, + sizeof(struct sockaddr_storage)); + } + + if (!service->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", service->gc->uri)); + + if (service->gc->sockaddr == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("resolv_get_sockaddr_address failed.\n")); + ret = EIO; + goto done; + } + /* 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 792f32e0..80181552 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 aada14ec..cb73aca3 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; |