From 780ffc9f6d5e1fcd4df3d390b56cb98878223cc0 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Tue, 1 Jun 2010 15:36:56 +0200 Subject: Add dns_discovery_domain option The service discovery used to use the SSSD domain name to perform DNS queries. This is not an optimal solution, for example from the point of view of authconfig. This patch introduces a new option "dns_discovery_domain" that allows to set the domain part of a DNS SRV query. If this option is not set, the default behavior is to use the domain part of the machine's hostname. Fixes: #479 --- src/confdb/confdb.h | 1 + src/config/SSSDConfig.py | 1 + src/config/SSSDConfigTest.py | 2 + src/config/etc/sssd.api.conf | 1 + src/config/upgrade_config.py | 26 ++++- src/man/include/service_discovery.xml | 9 +- src/man/sssd.conf.5.xml | 13 +++ src/providers/data_provider_fo.c | 13 ++- src/providers/dp_backend.h | 3 +- src/providers/fail_over.c | 198 ++++++++++++++++++++++++++++++---- src/providers/ipa/ipa_common.c | 2 +- src/providers/krb5/krb5_common.c | 2 +- src/providers/ldap/ldap_common.c | 1 - 13 files changed, 242 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index ae7502f8..e5a0d9ab 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -101,6 +101,7 @@ #define CONFDB_DOMAIN_FQ "use_fully_qualified_names" #define CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT "entry_cache_timeout" #define CONFDB_DOMAIN_RESOLV_TIMEOUT "dns_resolver_timeout" +#define CONFDB_DOMAIN_DNS_DISCOVERY_NAME "dns_discovery_domain" #define CONFDB_DOMAIN_FAMILY_ORDER "lookup_family_order" #define CONFDB_DOMAIN_ACCOUNT_CACHE_EXPIRATION "account_cache_expiration" diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py index f1ff02aa..22013eeb 100644 --- a/src/config/SSSDConfig.py +++ b/src/config/SSSDConfig.py @@ -82,6 +82,7 @@ option_strings = { 'lookup_family_order' : _('Restrict or prefer a specific address family when performing DNS lookups'), 'account_cache_expiration' : _('How long to keep cached entries after last successful login (days)'), 'dns_resolver_timeout' : _('How long to wait for replies from DNS when resolving servers (seconds)'), + 'dns_discovery_domain' : _('The domain part of service discovery DNS query'), # [provider/ipa] 'ipa_domain' : _('IPA domain'), diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py index 63d1ad11..e99a7876 100755 --- a/src/config/SSSDConfigTest.py +++ b/src/config/SSSDConfigTest.py @@ -478,6 +478,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): 'lookup_family_order', 'account_cache_expiration', 'dns_resolver_timeout', + 'dns_discovery_domain', 'id_provider', 'auth_provider', 'access_provider', @@ -795,6 +796,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): 'account_cache_expiration', 'lookup_family_order', 'dns_resolver_timeout', + 'dns_discovery_domain', 'id_provider', 'auth_provider', 'access_provider', diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf index f0ef4114..ca85ed70 100644 --- a/src/config/etc/sssd.api.conf +++ b/src/config/etc/sssd.api.conf @@ -59,6 +59,7 @@ account_cache_expiration = int, None, false filter_users = list, str, false filter_groups = list, str, false dns_resolver_timeout = int, None, false +dns_discovery_domain = str, None, false # Special providers [provider/permit] diff --git a/src/config/upgrade_config.py b/src/config/upgrade_config.py index d47fcd38..ff22b489 100644 --- a/src/config/upgrade_config.py +++ b/src/config/upgrade_config.py @@ -59,6 +59,28 @@ class SSSDConfigFile(SSSDChangeConf): if item: item['name'] = new_name + def _add_dns_domain_name(self, domain): + id_provider = self.findOpts(domain['value'], 'option', 'id_provider')[1] + dns_domain_name = { 'type' : 'option', + 'name' : 'dns_discovery_domain', + 'value' : domain['name'].lstrip('domain/') } + if id_provider['value'] == 'ldap': + server = self.findOpts(domain['value'], 'option', 'ldap_uri')[1] + if not server or "__srv__" in server['value']: + domain['value'].insert(0, dns_domain_name) + return + elif id_provider['value'] == 'ipa': + server = self.findOpts(domain['value'], 'option', 'ipa_server')[1] + if not server or "__srv__" in server['value']: + domain['value'].insert(0, dns_domain_name) + return + + auth_provider = self.findOpts(domain['value'], 'option', 'auth_provider')[1] + if auth_provider and auth_provider['value'] == 'krb5': + server = self.findOpts(domain['value'], 'option', 'krb5_kdcip')[1] + if not server or "__srv__" in server['value']: + domain['value'].insert(0, dns_domain_name) + def _do_v2_changes(self): # remove Data Provider srvlist = self.get_option_index('sssd', 'services')[1] @@ -69,9 +91,11 @@ class SSSDConfigFile(SSSDChangeConf): srvlist['value'] = ", ".join([srv for srv in services]) self.delete_option('section', 'dp') - # remove magic_private_groups from all domains for domain in [ s for s in self.sections() if s['name'].startswith("domain/") ]: + # remove magic_private_groups from all domains self.delete_option_subtree(domain['value'], 'option', 'magic_private_groups') + # check if we need to add dns_domain + self._add_dns_domain_name(domain) def _update_option(self, to_section_name, from_section_name, opts): to_section = [ s for s in self.sections() if s['name'].strip() == to_section_name ] diff --git a/src/man/include/service_discovery.xml b/src/man/include/service_discovery.xml index 16d016ea..d33b4c21 100644 --- a/src/man/include/service_discovery.xml +++ b/src/man/include/service_discovery.xml @@ -22,8 +22,13 @@ The domain name - The name of the SSSD domain is used as the domain part of the - service discovery DNS query. + Please refer to the dns_discovery_domain + parameter in the + + sssd.conf + 5 + + manual page for more defails. diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index 497fae63..3bc3efdc 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -682,6 +682,19 @@ + + + dns_discovery_domain (string) + + + If service discovery is used in the back end, specifies + the domain part of the service discovery DNS query. + + + Default: Use the domain part of machine's hostname + + + diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c index 56a072ae..1654e222 100644 --- a/src/providers/data_provider_fo.c +++ b/src/providers/data_provider_fo.c @@ -243,9 +243,10 @@ int be_fo_service_add_callback(TALLOC_CTX *memctx, int be_fo_add_srv_server(struct be_ctx *ctx, const char *service_name, const char *query_service, const char *proto, - const char *domain, void *user_data) + void *user_data) { struct be_svc_data *svc; + char *domain; int ret; DLIST_FOR_EACH(svc, ctx->be_fo->svcs) { @@ -257,6 +258,15 @@ int be_fo_add_srv_server(struct be_ctx *ctx, const char *service_name, return ENOENT; } + ret = confdb_get_string(ctx->cdb, svc, ctx->conf_path, + CONFDB_DOMAIN_DNS_DISCOVERY_NAME, + NULL, &domain); + if (ret != EOK) { + DEBUG(1, ("Failed reading %s from confdb\n", + CONFDB_DOMAIN_DNS_DISCOVERY_NAME)); + return ret; + } + ret = fo_add_srv_server(svc->fo_service, query_service, domain, proto, user_data); if (ret && ret != EEXIST) { @@ -461,3 +471,4 @@ int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx, return EOK; } + diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h index 0668859b..61917b99 100644 --- a/src/providers/dp_backend.h +++ b/src/providers/dp_backend.h @@ -167,7 +167,7 @@ int be_fo_service_add_callback(TALLOC_CTX *memctx, be_svc_callback_fn_t *fn, void *private_data); int be_fo_add_srv_server(struct be_ctx *ctx, const char *service_name, const char *query_service, const char *proto, - const char *domain, void *user_data); + void *user_data); int be_fo_add_server(struct be_ctx *ctx, const char *service_name, const char *server, int port, void *user_data); @@ -179,4 +179,5 @@ int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv); int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx, const char *service_name); + #endif /* __DP_BACKEND_H___ */ diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c index 4fb05c1f..c965c0e3 100644 --- a/src/providers/fail_over.c +++ b/src/providers/fail_over.c @@ -97,7 +97,7 @@ struct server_common { }; struct srv_data { - char *domain; + char *dns_domain; char *proto; char *srv; @@ -212,7 +212,7 @@ get_srv_query(TALLOC_CTX *mem_ctx, struct fo_server *server) query = talloc_asprintf(mem_ctx, "_%s._%s.%s", server->srv_data->srv, server->srv_data->proto, - server->srv_data->domain); + server->srv_data->dns_domain); return query; } @@ -222,7 +222,7 @@ collapse_srv_lookup(struct fo_server *server) struct fo_server *tmp, *meta; meta = server->srv_data->meta; - DEBUG(4, ("Need to refresh SRV lookup for domain %s\n", meta->srv_data->domain)) + DEBUG(4, ("Need to refresh SRV lookup for domain %s\n", meta->srv_data->dns_domain)) if (server != meta) { while (server->prev && server->prev->srv_data == meta->srv_data) { @@ -498,19 +498,20 @@ create_server_common(TALLOC_CTX *mem_ctx, struct fo_ctx *ctx, const char *name) int fo_add_srv_server(struct fo_service *service, const char *srv, - const char *domain, const char *proto, void *user_data) + const char *dns_domain, const char *proto, void *user_data) { struct fo_server *server; DEBUG(3, ("Adding new SRV server in domain '%s', to service '%s'\n", - domain, service->name)); + dns_domain ? dns_domain : "unknown", service->name)); DLIST_FOR_EACH(server, service->server_list) { if (server->user_data != user_data) continue; if (fo_is_srv_lookup(server)) { - if (strcasecmp(server->srv_data->domain, domain) == 0 && + if (((dns_domain == NULL && server->srv_data->dns_domain == NULL) || + strcasecmp(server->srv_data->dns_domain, dns_domain) == 0) && strcasecmp(server->srv_data->proto, proto) == 0) { return EEXIST; } @@ -530,14 +531,18 @@ fo_add_srv_server(struct fo_service *service, const char *srv, if (server->srv_data == NULL) return ENOMEM; - server->srv_data->domain = talloc_strdup(server->srv_data, domain); server->srv_data->proto = talloc_strdup(server->srv_data, proto); server->srv_data->srv = talloc_strdup(server->srv_data, srv); - if (server->srv_data->domain == NULL || - server->srv_data->proto == NULL || + if (server->srv_data->proto == NULL || server->srv_data->srv == NULL) return ENOMEM; + if (dns_domain) { + server->srv_data->dns_domain = talloc_strdup(server->srv_data, dns_domain); + if (server->srv_data->dns_domain == NULL) + return ENOMEM; + } + server->srv_data->meta = server; server->srv_data->srv_lookup_status = DEFAULT_SRV_STATUS; server->srv_data->last_status_change.tv_sec = 0; @@ -895,6 +900,17 @@ fo_resolve_service_recv(struct tevent_req *req, struct fo_server **server) *******************************************************************/ static void resolve_srv_done(struct tevent_req *subreq); +static void resolve_srv_cont(struct tevent_req *req); + +struct tevent_req *resolve_get_domain_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct fo_ctx *foctx, + struct resolv_ctx *resolv); + +static void resolve_getsrv_domain_done(struct tevent_req *req); +int resolve_get_domain_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + char **dns_domain); struct resolve_srv_state { struct fo_server *meta; @@ -913,7 +929,6 @@ resolve_srv_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct fo_server *server) { int ret; - char *query; struct tevent_req *req; struct tevent_req *subreq; struct resolve_srv_state *state; @@ -937,19 +952,18 @@ resolve_srv_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, state->meta = collapse_srv_lookup(server); /* FALLTHROUGH */ case SRV_NEUTRAL: /* Request SRV lookup */ - query = get_srv_query(state, state->meta); - if (!query) { - ret = ENOMEM; - goto done; - } - DEBUG(4, ("Searching for servers via SRV query '%s'\n", query)); - - subreq = resolv_getsrv_send(state, ev, resolv, query); - if (subreq == NULL) { - ret = ENOMEM; - goto done; + if (server->srv_data->dns_domain == NULL) { + /* we need to look up our DNS domain first */ + subreq = resolve_get_domain_send(state, ev, ctx, resolv); + if (subreq == NULL) { + ret = ENOMEM; + goto done; + } + tevent_req_set_callback(subreq, resolve_getsrv_domain_done, req); + break; } - tevent_req_set_callback(subreq, resolve_srv_done, req); + /* we know the DNS domain, just do the lookup */ + resolve_srv_cont(req); break; case SRV_NOT_RESOLVED: /* query could not be resolved but don't retry yet */ ret = EIO; @@ -974,6 +988,49 @@ done: return req; } +static void +resolve_getsrv_domain_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct resolve_srv_state *state = tevent_req_data(req, + struct resolve_srv_state); + int ret; + + ret = resolve_get_domain_recv(subreq, state->meta->srv_data, + &state->meta->srv_data->dns_domain); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + resolve_srv_cont(req); +} + +static void +resolve_srv_cont(struct tevent_req *req) +{ + struct resolve_srv_state *state = tevent_req_data(req, + struct resolve_srv_state); + char *query; + struct tevent_req *subreq; + + query = get_srv_query(state, state->meta); + if (!query) { + tevent_req_error(req, ENOMEM); + return; + } + DEBUG(4, ("Searching for servers via SRV query '%s'\n", query)); + + subreq = resolv_getsrv_send(state, state->ev, state->resolv, query); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, resolve_srv_done, req); +} + static void resolve_srv_done(struct tevent_req *subreq) { @@ -1072,6 +1129,103 @@ resolve_srv_recv(struct tevent_req *req, struct fo_server **server) return EOK; } +/******************************************************************* + * Get Fully Qualified Domain Name of the host machine * + *******************************************************************/ +struct resolve_get_domain_state { + char *fqdn; + char hostname[HOST_NAME_MAX]; +}; + +static void resolve_get_domain_done(struct tevent_req *subreq); + +struct tevent_req * +resolve_get_domain_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct fo_ctx *foctx, + struct resolv_ctx *resolv) +{ + int ret; + struct resolve_get_domain_state *state; + struct tevent_req *req, *subreq; + + req = tevent_req_create(mem_ctx, &state, struct resolve_get_domain_state); + if (!req) { + return NULL; + } + + ret = gethostname(state->hostname, HOST_NAME_MAX); + if (ret) { + DEBUG(2, ("gethostname() failed: [%d]: %s\n",ret, strerror(ret))); + return NULL; + } + state->hostname[HOST_NAME_MAX-1] = '\0'; + DEBUG(7, ("Host name is: %s\n", state->hostname)); + + subreq = resolv_gethostbyname_send(mem_ctx, ev, resolv, + state->hostname, + foctx->opts->family_order); + if (!subreq) { + talloc_zfree(req); + return NULL; + } + tevent_req_set_callback(subreq, resolve_get_domain_done, req); + + return req; +} + +static void resolve_get_domain_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct resolve_get_domain_state *state = tevent_req_data(req, + struct resolve_get_domain_state); + struct hostent *hostent; + int ret; + + ret = resolv_gethostbyname_recv(subreq, req, NULL, NULL, &hostent); + talloc_zfree(subreq); + if (ret) { + DEBUG(2, ("Could not get fully qualified name for host name %s " + "resolver returned: [%d]: %s\n", + state->hostname, ret, strerror(ret))); + /* We'll proceed with hostname in this case */ + } else { + DEBUG(7, ("The full FQDN is: %s\n", hostent->h_name)); + state->fqdn = hostent->h_name; + } + tevent_req_done(req); +} + +int resolve_get_domain_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + char **dns_domain) +{ + struct resolve_get_domain_state *state = tevent_req_data(req, + struct resolve_get_domain_state); + char *fqdn; + char *domptr; + + TEVENT_REQ_RETURN_ON_ERROR(req); + + fqdn = state->fqdn ? state->fqdn : state->hostname; + domptr = strchr(fqdn, '.'); + + if (!domptr || (*(domptr+1) == '\0')) { + /* If the FQDN did not contain a dot or the dot was the last character + * (broken DNS server perhaps */ + *dns_domain = talloc_strdup(mem_ctx, fqdn); + } else { + domptr++; + *dns_domain = talloc_strdup(mem_ctx, domptr); + } + + if (*dns_domain == NULL) { + return ENOMEM; + } + + return EOK; +} + static void set_server_common_status(struct server_common *common, enum server_status status) diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c index 3ada423e..99b1508f 100644 --- a/src/providers/ipa/ipa_common.c +++ b/src/providers/ipa/ipa_common.c @@ -570,7 +570,7 @@ int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, if (be_fo_is_srv_identifier(list[i])) { ret = be_fo_add_srv_server(ctx, "IPA", "ldap", - FO_PROTO_TCP, ctx->domain->name, NULL); + FO_PROTO_TCP, NULL); if (ret) { DEBUG(0, ("Failed to add server\n")); goto done; diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c index 57d7b1d0..e5471e3f 100644 --- a/src/providers/krb5/krb5_common.c +++ b/src/providers/krb5/krb5_common.c @@ -338,7 +338,7 @@ int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, if (be_fo_is_srv_identifier(server_spec)) { ret = be_fo_add_srv_server(ctx, service_name, service_name, - FO_PROTO_TCP, ctx->domain->name, NULL); + FO_PROTO_TCP, NULL); if (ret) { DEBUG(0, ("Failed to add server\n")); goto done; diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c index 4f1dc067..978e2327 100644 --- a/src/providers/ldap/ldap_common.c +++ b/src/providers/ldap/ldap_common.c @@ -638,7 +638,6 @@ int sdap_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, ret = be_fo_add_srv_server(ctx, service_name, dns_service_name, FO_PROTO_TCP, - ctx->domain->name, srv_user_data); if (ret) { DEBUG(0, ("Failed to add server\n")); -- cgit