diff options
-rw-r--r-- | src/config/SSSDConfig/__init__.py.in | 1 | ||||
-rwxr-xr-x | src/config/SSSDConfigTest.py | 2 | ||||
-rw-r--r-- | src/config/etc/sssd.api.conf | 1 | ||||
-rw-r--r-- | src/man/sssd-ipa.5.xml | 20 | ||||
-rw-r--r-- | src/providers/dp_dyndns.c | 327 | ||||
-rw-r--r-- | src/providers/dp_dyndns.h | 28 | ||||
-rw-r--r-- | src/providers/ipa/ipa_dyndns.c | 4 | ||||
-rw-r--r-- | src/providers/ipa/ipa_opts.h | 1 | ||||
-rw-r--r-- | src/providers/ldap/sdap_dyndns.c | 195 | ||||
-rw-r--r-- | src/providers/ldap/sdap_dyndns.h | 1 | ||||
-rw-r--r-- | src/resolv/async_resolv.c | 4 | ||||
-rw-r--r-- | src/resolv/async_resolv.h | 7 |
12 files changed, 463 insertions, 128 deletions
diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in index 003153d0..79bf6aa4 100644 --- a/src/config/SSSDConfig/__init__.py.in +++ b/src/config/SSSDConfig/__init__.py.in @@ -129,6 +129,7 @@ option_strings = { 'dyndns_ttl' : _("The TTL to apply to the client's DNS entry after updating it"), 'dyndns_iface' : _("The interface whose IP should be used for dynamic DNS updates"), 'dyndns_refresh_interval' : _("How often to periodically update the client's DNS entry"), + 'dyndns_update_ptr' : _("Whether the provider should explicitly update the PTR record as well"), # [provider/ipa] 'ipa_domain' : _('IPA domain'), diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py index 18328d06..7add141c 100755 --- a/src/config/SSSDConfigTest.py +++ b/src/config/SSSDConfigTest.py @@ -511,6 +511,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): 'dyndns_ttl', 'dyndns_iface', 'dyndns_refresh_interval', + 'dyndns_update_ptr', 'override_gid', 'case_sensitive', 'override_homedir', @@ -858,6 +859,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): 'dyndns_ttl', 'dyndns_iface', 'dyndns_refresh_interval', + 'dyndns_update_ptr', 'override_gid', 'case_sensitive', 'override_homedir', diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf index b09cbd18..396063b4 100644 --- a/src/config/etc/sssd.api.conf +++ b/src/config/etc/sssd.api.conf @@ -126,6 +126,7 @@ dyndns_update = bool, None, false dyndns_ttl = int, None, false dyndns_iface = str, None, false dyndns_refresh_interval = int, None, false +dyndns_update_ptr = bool, None, false # Special providers [provider/permit] diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml index 426e9a5b..21a28047 100644 --- a/src/man/sssd-ipa.5.xml +++ b/src/man/sssd-ipa.5.xml @@ -220,6 +220,26 @@ </varlistentry> <varlistentry> + <term>dyndns_update_ptr (bool)</term> + <listitem> + <para> + Whether the PTR record should also be explicitly + updated when updating the client's DNS records. + Applicable only when dyndns_update is true. + </para> + <para> + This options should be False in most IPA + deployments as the IPA server generates the + PTR records automatically when forward records + are changed. + </para> + <para> + Default: False (disabled) + </para> + </listitem> + </varlistentry> + + <varlistentry> <term>ipa_hbac_search_base (string)</term> <listitem> <para> diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c index 337817fc..79701c62 100644 --- a/src/providers/dp_dyndns.c +++ b/src/providers/dp_dyndns.c @@ -262,64 +262,14 @@ done: return ret; } -errno_t -be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm, - const char *zone, const char *servername, - const char *hostname, const unsigned int ttl, - uint8_t remove_af, struct sss_iface_addr *addresses, - char **_update_msg) +static char * +nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses, + const char *hostname, int ttl, uint8_t remove_af) { - int ret; - char *realm_directive; + struct sss_iface_addr *new_record; char ip_addr[INET6_ADDRSTRLEN]; const char *ip; - struct sss_iface_addr *new_record; - char *update_msg; - TALLOC_CTX *tmp_ctx; - - /* in some cases realm could have been NULL if we weren't using TSIG */ - if (zone == NULL || hostname == NULL) { - return EINVAL; - } - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) return ENOMEM; - -#ifdef HAVE_NSUPDATE_REALM - realm_directive = talloc_asprintf(tmp_ctx, "realm %s\n", realm); -#else - realm_directive = talloc_asprintf(tmp_ctx, ""); -#endif - if (!realm_directive) { - ret = ENOMEM; - goto done; - } - - /* The realm_directive would now either contain an empty string or be - * completely empty so we don't need to add another newline here - */ - if (servername) { - DEBUG(SSSDBG_FUNC_DATA, - ("Creating update message for server [%s], realm [%s] " - "and zone [%s].\n", servername, realm, zone)); - - /* Add the server, realm and zone headers */ - update_msg = talloc_asprintf(tmp_ctx, "server %s\n%szone %s.\n", - servername, realm_directive, zone); - } else { - DEBUG(SSSDBG_FUNC_DATA, - ("Creating update message for realm [%s] and zone [%s].\n", - realm, zone)); - - /* Add the realm and zone headers */ - update_msg = talloc_asprintf(tmp_ctx, "%szone %s.\n", - realm_directive, zone); - } - talloc_free(realm_directive); - if (update_msg == NULL) { - ret = ENOMEM; - goto done; - } + errno_t ret; /* Remove existing entries as needed */ if (remove_af & DYNDNS_REMOVE_A) { @@ -327,8 +277,7 @@ be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm, "update delete %s. in A\nsend\n", hostname); if (update_msg == NULL) { - ret = ENOMEM; - goto done; + return NULL; } } if (remove_af & DYNDNS_REMOVE_AAAA) { @@ -336,8 +285,7 @@ be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm, "update delete %s. in AAAA\nsend\n", hostname); if (update_msg == NULL) { - ret = ENOMEM; - goto done; + return NULL; } } @@ -349,7 +297,9 @@ be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm, ip_addr, INET6_ADDRSTRLEN); if (ip == NULL) { ret = errno; - goto done; + DEBUG(SSSDBG_OP_FAILURE, + ("inet_ntop failed [%d]: %s\n", ret, strerror(ret))); + return NULL; } break; @@ -359,14 +309,15 @@ be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm, ip_addr, INET6_ADDRSTRLEN); if (ip == NULL) { ret = errno; - goto done; + DEBUG(SSSDBG_OP_FAILURE, + ("inet_ntop failed [%d]: %s\n", ret, strerror(ret))); + return NULL; } break; default: DEBUG(SSSDBG_CRIT_FAILURE, ("Unknown address family\n")); - ret = EINVAL; - goto done; + return NULL; } /* Format the record update */ @@ -376,12 +327,179 @@ be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm, new_record->addr->ss_family == AF_INET ? "A" : "AAAA", ip_addr); if (update_msg == NULL) { + return NULL; + } + + } + + return talloc_asprintf_append(update_msg, "send\n"); +} + +static char * +nsupdate_msg_add_ptr(char *update_msg, struct sss_iface_addr *addresses, + const char *hostname, int ttl, uint8_t remove_af, + struct sss_iface_addr *old_addresses) +{ + struct sss_iface_addr *new_record, *old_record; + char *strptr; + uint8_t *addr; + + DLIST_FOR_EACH(old_record, old_addresses) { + switch(old_record->addr->ss_family) { + case AF_INET: + if (!(remove_af & DYNDNS_REMOVE_A)) { + continue; + } + addr = (uint8_t *) &((struct sockaddr_in *) old_record->addr)->sin_addr; + break; + case AF_INET6: + if (!(remove_af & DYNDNS_REMOVE_AAAA)) { + continue; + } + addr = (uint8_t *) &((struct sockaddr_in6 *) old_record->addr)->sin6_addr; + break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, ("Unknown address family\n")); + return NULL; + } + + strptr = resolv_get_string_ptr_address(update_msg, old_record->addr->ss_family, + addr); + if (strptr == NULL) { + return NULL; + } + + /* example: update delete 38.78.16.10.in-addr.arpa. in PTR */ + update_msg = talloc_asprintf_append(update_msg, + "update delete %s in PTR\n", strptr); + talloc_free(strptr); + if (update_msg == NULL) { + return NULL; + } + } + + /* example: update add 11.78.16.10.in-addr.arpa. 85000 in PTR testvm.example.com */ + DLIST_FOR_EACH(new_record, addresses) { + switch(new_record->addr->ss_family) { + case AF_INET: + addr = (uint8_t *) &((struct sockaddr_in *) new_record->addr)->sin_addr; + break; + case AF_INET6: + addr = (uint8_t *) &((struct sockaddr_in6 *) new_record->addr)->sin6_addr; + break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, ("Unknown address family\n")); + return NULL; + } + + strptr = resolv_get_string_ptr_address(update_msg, new_record->addr->ss_family, + addr); + if (strptr == NULL) { + return NULL; + } + + /* example: update delete 38.78.16.10.in-addr.arpa. in PTR */ + update_msg = talloc_asprintf_append(update_msg, + "update add %s %d in PTR %s.\n", + strptr, ttl, hostname); + talloc_free(strptr); + if (update_msg == NULL) { + return NULL; + } + } + + return talloc_asprintf_append(update_msg, "send\n"); +} + +static char * +nsupdate_msg_create_common(TALLOC_CTX *mem_ctx, const char *realm, + const char *servername) +{ + char *realm_directive; + char *update_msg; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) return NULL; + +#ifdef HAVE_NSUPDATE_REALM + realm_directive = talloc_asprintf(tmp_ctx, "realm %s\n", realm); +#else + realm_directive = talloc_asprintf(tmp_ctx, ""); +#endif + if (!realm_directive) { + goto fail; + } + + /* The realm_directive would now either contain an empty string or be + * completely empty so we don't need to add another newline here + */ + if (servername) { + DEBUG(SSSDBG_FUNC_DATA, + ("Creating update message for server [%s] and realm [%s]\n.", + servername, realm)); + + /* Add the server, realm and headers */ + update_msg = talloc_asprintf(tmp_ctx, "server %s\n%s", + servername, realm_directive); + } else { + DEBUG(SSSDBG_FUNC_DATA, + ("Creating update message for realm [%s].\n", realm)); + /* Add the realm headers */ + update_msg = talloc_asprintf(tmp_ctx, "%s", realm_directive); + } + talloc_free(realm_directive); + if (update_msg == NULL) { + goto fail; + } + + update_msg = talloc_steal(mem_ctx, update_msg); + talloc_free(tmp_ctx); + return update_msg; + +fail: + talloc_free(tmp_ctx); + return NULL; +} + +errno_t +be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm, + const char *zone, const char *servername, + const char *hostname, const unsigned int ttl, + uint8_t remove_af, struct sss_iface_addr *addresses, + struct sss_iface_addr *old_addresses, + char **_update_msg) +{ + int ret; + char *update_msg; + TALLOC_CTX *tmp_ctx; + + /* in some cases realm could have been NULL if we weren't using TSIG */ + if (hostname == NULL) { + return EINVAL; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) return ENOMEM; + + update_msg = nsupdate_msg_create_common(tmp_ctx, realm, servername); + if (update_msg == NULL) { + ret = ENOMEM; + goto done; + } + + if (zone) { + DEBUG(SSSDBG_FUNC_DATA, + ("Setting the zone explicitly to [%s].\n", zone)); + update_msg = talloc_asprintf_append(update_msg, "zone %s.\n", zone); + if (update_msg == NULL) { ret = ENOMEM; goto done; } } - update_msg = talloc_asprintf_append(update_msg, "send\n"); + update_msg = nsupdate_msg_add_fwd(update_msg, addresses, hostname, + ttl, remove_af); if (update_msg == NULL) { ret = ENOMEM; goto done; @@ -400,6 +518,47 @@ done: return ret; } +errno_t +be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm, + const char *servername, const char *hostname, + const unsigned int ttl, uint8_t remove_af, + struct sss_iface_addr *addresses, + struct sss_iface_addr *old_addresses, + char **_update_msg) +{ + errno_t ret; + char *update_msg; + + /* in some cases realm could have been NULL if we weren't using TSIG */ + if (hostname == NULL) { + return EINVAL; + } + + update_msg = nsupdate_msg_create_common(mem_ctx, realm, servername); + if (update_msg == NULL) { + ret = ENOMEM; + goto done; + } + + update_msg = nsupdate_msg_add_ptr(update_msg, addresses, hostname, + ttl, remove_af, old_addresses); + if (update_msg == NULL) { + ret = ENOMEM; + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, + (" -- Begin nsupdate message -- \n%s", + update_msg)); + DEBUG(SSSDBG_TRACE_FUNC, + (" -- End nsupdate message -- \n")); + + ret = ERR_OK; + *_update_msg = talloc_steal(mem_ctx, update_msg); +done: + return ret; +} + struct nsupdate_get_addrs_state { struct tevent_context *ev; struct be_resolv_ctx *be_res; @@ -407,7 +566,7 @@ struct nsupdate_get_addrs_state { const char *hostname; /* Use sss_addr in this request */ - char **addrlist; + struct sss_iface_addr *addrlist; size_t count; }; @@ -472,6 +631,7 @@ nsupdate_get_addrs_done(struct tevent_req *subreq) struct nsupdate_get_addrs_state *state = tevent_req_data(req, struct nsupdate_get_addrs_state); struct resolv_hostent *rhostent; + struct sss_iface_addr *addr; int i; int resolv_status; @@ -509,25 +669,25 @@ nsupdate_get_addrs_done(struct tevent_req *subreq) count = 0; } - state->addrlist = talloc_realloc(state, state->addrlist, char *, - state->count + count + 1); - if (!state->addrlist) { - ret = ENOMEM; - goto done; - } - for (i=0; i < count; i++) { - state->addrlist[state->count + i] = \ - resolv_get_string_address_index(state->addrlist, - rhostent, i); + addr = talloc(state, struct sss_iface_addr); + if (addr == NULL) { + ret = ENOMEM; + goto done; + } - if (state->addrlist[state->count + i] == NULL) { + addr->addr = resolv_get_sockaddr_address_index(addr, rhostent, 0, i); + if (addr == NULL) { ret = ENOMEM; goto done; } + + if (state->addrlist) { + talloc_steal(state->addrlist, addr); + } + DLIST_ADD(state->addrlist, addr); } state->count += count; - state->addrlist[state->count] = NULL; /* If the resolver is set to honor both address families * and the first one matched, retry the second one to @@ -576,14 +736,22 @@ done: errno_t nsupdate_get_addrs_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - char ***_addrlist) + struct sss_iface_addr **_addrlist, + size_t *_count) { struct nsupdate_get_addrs_state *state = tevent_req_data(req, struct nsupdate_get_addrs_state); TEVENT_REQ_RETURN_ON_ERROR(req); - *_addrlist = talloc_steal(mem_ctx, state->addrlist); + if (_addrlist) { + *_addrlist = talloc_steal(mem_ctx, state->addrlist); + } + + if (_count) { + *_count = state->count; + } + return EOK; } @@ -948,6 +1116,7 @@ static struct dp_option default_dyndns_opts[] = { { "dyndns_refresh_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER }, { "dyndns_iface", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "dyndns_ttl", DP_OPT_NUMBER, { .number = 1200 }, NULL_NUMBER }, + { "dyndns_update_ptr", DP_OPT_BOOL, BOOL_TRUE, BOOL_FALSE }, DP_OPTION_TERMINATOR }; diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h index e49ab8f0..8fdbe487 100644 --- a/src/providers/dp_dyndns.h +++ b/src/providers/dp_dyndns.h @@ -46,6 +46,7 @@ enum dp_dyndns_opts { DP_OPT_DYNDNS_REFRESH_INTERVAL, DP_OPT_DYNDNS_IFACE, DP_OPT_DYNDNS_TTL, + DP_OPT_DYNDNS_UPDATE_PTR, DP_OPT_DYNDNS /* attrs counter */ }; @@ -79,11 +80,20 @@ sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx, char ***_straddrs); errno_t -be_nsupdate_create_msg(TALLOC_CTX *mem_ctx, const char *realm, - const char *zone, const char *servername, - const char *hostname, const unsigned int ttl, - uint8_t remove_af, struct sss_iface_addr *addresses, - char **_update_msg); +be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm, + const char *zone, const char *servername, + const char *hostname, const unsigned int ttl, + uint8_t remove_af, struct sss_iface_addr *addresses, + struct sss_iface_addr *old_addresses, + char **_update_msg); + +errno_t +be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm, + const char *servername, const char *hostname, + const unsigned int ttl, uint8_t remove_af, + struct sss_iface_addr *addresses, + struct sss_iface_addr *old_addresses, + char **_update_msg); /* Returns: * * ERR_OK - on success @@ -100,8 +110,10 @@ struct tevent_req * nsupdate_get_addrs_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct be_resolv_ctx *be_res, const char *hostname); -errno_t nsupdate_get_addrs_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - char ***_addrlist); +errno_t +nsupdate_get_addrs_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct sss_iface_addr **_addrlist, + size_t *_count); #endif /* DP_DYNDNS_H_ */ diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c index 52b8051b..bb38d105 100644 --- a/src/providers/ipa/ipa_dyndns.c +++ b/src/providers/ipa/ipa_dyndns.c @@ -242,7 +242,9 @@ ipa_dyndns_update_send(struct ipa_options *ctx) } subreq = sdap_dyndns_update_send(state, sdap_ctx->be->ev, - sdap_ctx->be, sdap_ctx, + sdap_ctx->be, + ctx->dyndns_ctx->opts, + sdap_ctx, dp_opt_get_string(ctx->dyndns_ctx->opts, DP_OPT_DYNDNS_IFACE), dp_opt_get_string(ctx->basic, diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h index 57911082..bfb09e36 100644 --- a/src/providers/ipa/ipa_opts.h +++ b/src/providers/ipa/ipa_opts.h @@ -56,6 +56,7 @@ struct dp_option ipa_dyndns_opts[] = { { "dyndns_refresh_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER }, { "dyndns_iface", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "dyndns_ttl", DP_OPT_NUMBER, { .number = 1200 }, NULL_NUMBER }, + { "dyndns_update_ptr", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, DP_OPTION_TERMINATOR }; diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c index e7fad7ba..ccaec8e0 100644 --- a/src/providers/ldap/sdap_dyndns.c +++ b/src/providers/ldap/sdap_dyndns.c @@ -43,6 +43,7 @@ sdap_dyndns_get_addrs_recv(struct tevent_req *req, struct sdap_dyndns_update_state { struct tevent_context *ev; struct be_resolv_ctx *be_res; + struct dp_option *opts; const char *hostname; const char *dns_zone; @@ -51,22 +52,29 @@ struct sdap_dyndns_update_state { int ttl; struct sss_iface_addr *addresses; + struct sss_iface_addr *dns_addrlist; uint8_t remove_af; + bool update_ptr; bool check_diff; bool use_server_with_nsupdate; char *update_msg; }; static void sdap_dyndns_update_addrs_done(struct tevent_req *subreq); -static void sdap_dyndns_addrs_check_done(struct tevent_req *subreq); +static void sdap_dyndns_dns_addrs_done(struct tevent_req *subreq); +static errno_t sdap_dyndns_addrs_diff(struct sdap_dyndns_update_state *state, + bool *_do_update); static errno_t sdap_dyndns_update_step(struct tevent_req *req); +static errno_t sdap_dyndns_update_ptr_step(struct tevent_req *req); static void sdap_dyndns_update_done(struct tevent_req *subreq); +static void sdap_dyndns_update_ptr_done(struct tevent_req *subreq); struct tevent_req * sdap_dyndns_update_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct be_ctx *be_ctx, + struct dp_option *opts, struct sdap_id_ctx *sdap_ctx, const char *ifname, const char *hostname, @@ -86,6 +94,7 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx, return NULL; } state->check_diff = check_diff; + state->update_ptr = dp_opt_get_bool(opts, DP_OPT_DYNDNS_UPDATE_PTR); state->hostname = hostname; state->dns_zone = dns_zone; state->realm = realm; @@ -94,6 +103,7 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx, state->ttl = ttl; state->be_res = be_ctx->be_res; state->ev = ev; + state->opts = opts; if (ifname) { /* Unless one family is restricted, just replace all @@ -155,8 +165,10 @@ sdap_dyndns_update_addrs_done(struct tevent_req *subreq) return; } - if (state->check_diff) { - /* Check if we need the update at all */ + if (state->check_diff || state->update_ptr) { + /* Check if we need the update at all. In case we are updating the PTR + * records as well, we need to know the old addresses to be able to + * reliably delete the PTR records */ subreq = nsupdate_get_addrs_send(state, state->ev, state->be_res, state->hostname); if (subreq == NULL) { @@ -164,7 +176,7 @@ sdap_dyndns_update_addrs_done(struct tevent_req *subreq) tevent_req_error(req, ret); return; } - tevent_req_set_callback(subreq, sdap_dyndns_addrs_check_done, req); + tevent_req_set_callback(subreq, sdap_dyndns_dns_addrs_done, req); return; } @@ -178,20 +190,17 @@ sdap_dyndns_update_addrs_done(struct tevent_req *subreq) } static void -sdap_dyndns_addrs_check_done(struct tevent_req *subreq) +sdap_dyndns_dns_addrs_done(struct tevent_req *subreq) { - errno_t ret; - int i; struct tevent_req *req; struct sdap_dyndns_update_state *state; - char **str_dnslist = NULL, **str_local_list = NULL; - char **dns_only = NULL, **local_only = NULL; + errno_t ret; bool do_update; req = tevent_req_callback_data(subreq, struct tevent_req); state = tevent_req_data(req, struct sdap_dyndns_update_state); - ret = nsupdate_get_addrs_recv(subreq, state, &str_dnslist); + ret = nsupdate_get_addrs_recv(subreq, state, &state->dns_addrlist, NULL); talloc_zfree(subreq); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, @@ -201,14 +210,61 @@ sdap_dyndns_addrs_check_done(struct tevent_req *subreq) return; } + if (state->check_diff) { + ret = sdap_dyndns_addrs_diff(state, &do_update); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not check the diff between DNS " + "and current addresses [%d]: %s\n", ret, strerror(ret))); + tevent_req_error(req, ret); + return; + } + + if (do_update == false) { + DEBUG(SSSDBG_TRACE_FUNC, + ("No DNS update needed, addresses did not change\n")); + tevent_req_done(req); + return; + } + DEBUG(SSSDBG_TRACE_FUNC, + ("Detected IP addresses change, will perform an update\n")); + } + + /* Either we needed the addresses for updating PTR records only or + * the addresses have changed (or both) */ + ret = sdap_dyndns_update_step(req); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not start the update [%d]: %s\n", + ret, sss_strerror(ret))); + tevent_req_error(req, ret); + } + return; +} + +static errno_t +sdap_dyndns_addrs_diff(struct sdap_dyndns_update_state *state, bool *_do_update) +{ + errno_t ret; + int i; + char **str_dnslist = NULL, **str_local_list = NULL; + char **dns_only = NULL, **local_only = NULL; + bool do_update; + + ret = sss_iface_addr_list_as_str_list(state, + state->dns_addrlist, &str_dnslist); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Converting DNS IP addresses to strings failed: [%d]: %s\n", + ret, sss_strerror(ret))); + return ret; + } + ret = sss_iface_addr_list_as_str_list(state, state->addresses, &str_local_list); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, - ("Converting DNS IP addresses to strings failed: [%d]: %s\n", + ("Converting local IP addresses to strings failed: [%d]: %s\n", ret, sss_strerror(ret))); - tevent_req_error(req, ret); - return; + return ret; } /* Compare the lists */ @@ -217,8 +273,7 @@ sdap_dyndns_addrs_check_done(struct tevent_req *subreq) if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("diff_string_lists failed: [%d]: %s\n", ret, sss_strerror(ret))); - tevent_req_error(req, ret); - return; + return ret; } if (dns_only) { @@ -237,22 +292,8 @@ sdap_dyndns_addrs_check_done(struct tevent_req *subreq) } } - if (do_update) { - DEBUG(SSSDBG_TRACE_FUNC, - ("Detected IP addresses change, will perform an update\n")); - ret = sdap_dyndns_update_step(req); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("Could not start the update [%d]: %s\n", - ret, sss_strerror(ret))); - tevent_req_error(req, ret); - } - return; - } - - DEBUG(SSSDBG_TRACE_FUNC, - ("No DNS update needed, addresses did not change\n")); - tevent_req_done(req); - return; + *_do_update = do_update; + return EOK; } static errno_t @@ -271,11 +312,11 @@ sdap_dyndns_update_step(struct tevent_req *req) servername = state->servername; } - ret = be_nsupdate_create_msg(state, state->realm, state->dns_zone, - servername, state->hostname, - state->ttl, state->remove_af, - state->addresses, - &state->update_msg); + ret = be_nsupdate_create_fwd_msg(state, state->realm, state->dns_zone, + servername, state->hostname, + state->ttl, state->remove_af, + state->addresses, state->dns_addrlist, + &state->update_msg); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Can't get addresses for DNS update\n")); return ret; @@ -321,6 +362,88 @@ sdap_dyndns_update_done(struct tevent_req *subreq) return; } + if (state->update_ptr == false) { + DEBUG(SSSDBG_TRACE_FUNC, ("No PTR update requested, done\n")); + tevent_req_done(req); + return; + } + + talloc_free(state->update_msg); + ret = sdap_dyndns_update_ptr_step(req); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + /* Execution will resume in sdap_dyndns_update_ptr_done */ +} + +static errno_t +sdap_dyndns_update_ptr_step(struct tevent_req *req) +{ + errno_t ret; + struct sdap_dyndns_update_state *state; + const char *servername; + struct tevent_req *subreq; + + state = tevent_req_data(req, struct sdap_dyndns_update_state); + + servername = NULL; + if (state->use_server_with_nsupdate == true && + state->servername) { + servername = state->servername; + } + + ret = be_nsupdate_create_ptr_msg(state, state->realm, + servername, state->hostname, + state->ttl, state->remove_af, + state->addresses, state->dns_addrlist, + &state->update_msg); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Can't get addresses for DNS update\n")); + return ret; + } + + /* Fork a child process to perform the DNS update */ + subreq = be_nsupdate_send(state, state->ev, + state->update_msg); + if (subreq == NULL) { + return EIO; + } + + tevent_req_set_callback(subreq, sdap_dyndns_update_ptr_done, req); + return EOK; +} + +static void +sdap_dyndns_update_ptr_done(struct tevent_req *subreq) +{ + errno_t ret; + int child_status; + struct tevent_req *req; + struct sdap_dyndns_update_state *state; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_dyndns_update_state); + + ret = be_nsupdate_recv(subreq, &child_status); + talloc_zfree(subreq); + if (ret != EOK) { + /* If the update didn't succeed, we can retry using the server name */ + if (state->use_server_with_nsupdate == false && state->servername && + WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) { + state->use_server_with_nsupdate = true; + DEBUG(SSSDBG_MINOR_FAILURE, + ("nsupdate failed, retrying with server name\n")); + ret = sdap_dyndns_update_ptr_step(req); + if (ret == EOK) { + return; + } + } + + tevent_req_error(req, ret); + return; + } + tevent_req_done(req); } diff --git a/src/providers/ldap/sdap_dyndns.h b/src/providers/ldap/sdap_dyndns.h index 1602938e..a18a71fc 100644 --- a/src/providers/ldap/sdap_dyndns.h +++ b/src/providers/ldap/sdap_dyndns.h @@ -33,6 +33,7 @@ struct tevent_req * sdap_dyndns_update_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct be_ctx *be_ctx, + struct dp_option *opts, struct sdap_id_ctx *sdap_ctx, const char *ifname, const char *hostname, diff --git a/src/resolv/async_resolv.c b/src/resolv/async_resolv.c index f673a25c..1eb0acf8 100644 --- a/src/resolv/async_resolv.c +++ b/src/resolv/async_resolv.c @@ -1453,8 +1453,8 @@ resolv_get_string_ptr_address(TALLOC_CTX *mem_ctx, } struct sockaddr_storage * -resolv_get_sockaddr_address(TALLOC_CTX *mem_ctx, struct resolv_hostent *hostent, - int port) +resolv_get_sockaddr_address_index(TALLOC_CTX *mem_ctx, struct resolv_hostent *hostent, + int port, int index) { struct sockaddr_storage *sockaddr; diff --git a/src/resolv/async_resolv.h b/src/resolv/async_resolv.h index d759a82f..9bf5e0c4 100644 --- a/src/resolv/async_resolv.h +++ b/src/resolv/async_resolv.h @@ -129,8 +129,11 @@ resolv_get_string_ptr_address(TALLOC_CTX *mem_ctx, resolv_get_string_address_index(mem_ctx, hostent, 0) struct sockaddr_storage * -resolv_get_sockaddr_address(TALLOC_CTX *mem_ctx, struct resolv_hostent *hostent, - int port); +resolv_get_sockaddr_address_index(TALLOC_CTX *mem_ctx, struct resolv_hostent *hostent, + int port, int index); + +#define resolv_get_sockaddr_address(mem_ctx, rhostent, port) \ + resolv_get_sockaddr_address_index(mem_ctx, rhostent, port, 0) /** Get SRV record **/ struct tevent_req *resolv_getsrv_send(TALLOC_CTX *mem_ctx, |