diff options
author | Sumit Bose <sbose@redhat.com> | 2011-02-25 12:52:59 +0100 |
---|---|---|
committer | Simo Sorce <ssorce@redhat.com> | 2011-03-03 18:36:48 -0500 |
commit | ef2c477a605e2130be019d1a4bba6bdd02c54a9d (patch) | |
tree | 17a9b384981bbc7816dd12fa4732a78f29cf5d33 /src | |
parent | 57d6586b06dd833330f7f9b125a81b5acabfa1a7 (diff) | |
download | sssd-ef2c477a605e2130be019d1a4bba6bdd02c54a9d.tar.gz sssd-ef2c477a605e2130be019d1a4bba6bdd02c54a9d.tar.bz2 sssd-ef2c477a605e2130be019d1a4bba6bdd02c54a9d.zip |
Fixes for dynamic DNS update
The current code assumed that only one server is given in the ipa_server
config option and fails if multiple servers were given. To fix this
nsupdate is first called without a server name assuming that nsupdate is
able to find the name of the master DNS server of the zone by reading
the SOA record. If this fails the IP address of the currently active
LDAP server is used and nsupdate is called again.
If there is no default realm given in /etc/krb5.conf nsupdate start
trying to find a realm based on the DNS domain which might lead to wrong
results. To be on the safe side the realm was added to the message send
to nsupdate.
Diffstat (limited to 'src')
-rw-r--r-- | src/providers/ipa/ipa_dyndns.c | 103 |
1 files changed, 87 insertions, 16 deletions
diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c index af942839..bee4bff5 100644 --- a/src/providers/ipa/ipa_dyndns.c +++ b/src/providers/ipa/ipa_dyndns.c @@ -54,7 +54,7 @@ struct ipa_dyndns_ctx { struct sdap_id_op* sdap_op; char *hostname; struct ipa_ipaddress *addresses; - int child_status; + bool use_server_with_nsupdate; }; @@ -101,6 +101,7 @@ ipa_dyndns_update_send(struct ipa_options *ctx) return NULL; } state->ipa_ctx = ctx; + state->use_server_with_nsupdate = false; iface = dp_opt_get_string(ctx->basic, IPA_DYNDNS_IFACE); @@ -301,10 +302,12 @@ struct ipa_nsupdate_ctx { struct ipa_dyndns_ctx *dyndns_ctx; int pipefd_to_child; struct tevent_timer *timeout_handler; + int child_status; }; -static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx); +static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx, + bool use_server_with_nsupdate); static struct tevent_req * fork_nsupdate_send(struct ipa_nsupdate_ctx *ctx); @@ -324,9 +327,10 @@ ipa_dyndns_gss_tsig_update_send(struct ipa_dyndns_ctx *ctx) return NULL; } state->dyndns_ctx = ctx; + state->child_status = 0; /* Format the message to pass to the nsupdate command */ - ret = create_nsupdate_message(state); + ret = create_nsupdate_message(state, ctx->use_server_with_nsupdate); if (ret != EOK) { goto failed; } @@ -347,20 +351,22 @@ failed: struct nsupdate_send_ctx { struct ipa_nsupdate_ctx *nsupdate_ctx; + int child_status; }; -static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx) +static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx, + bool use_server_with_nsupdate) { int ret, i; - char *servername; + char *servername = NULL; + char *realm; char *zone; char ip_addr[INET6_ADDRSTRLEN]; const char *ip; struct ipa_ipaddress *new_record; - servername = dp_opt_get_string(ctx->dyndns_ctx->ipa_ctx->basic, - IPA_SERVER); - if (!servername) { + realm = dp_opt_get_string(ctx->dyndns_ctx->ipa_ctx->basic, IPA_KRB5_REALM); + if (!realm) { return EIO; } @@ -377,10 +383,31 @@ static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx) zone[i] = tolower(zone[i]); } - /* Add the server and zone headers */ - ctx->update_msg = talloc_asprintf(ctx, "server %s\nzone %s.\n", - servername, - zone); + if (use_server_with_nsupdate) { + if (strncmp(ctx->dyndns_ctx->ipa_ctx->service->sdap->uri, + "ldap://", 7) != 0) { + DEBUG(1, ("Unexpected format of LDAP URI.\n")); + return EIO; + } + servername = ctx->dyndns_ctx->ipa_ctx->service->sdap->uri + 7; + if (!servername) { + return EIO; + } + + DEBUG(9, ("Creating update message for server [%s], realm [%s] " + "and zone [%s].\n", servername, realm, zone)); + + /* Add the server, realm and zone headers */ + ctx->update_msg = talloc_asprintf(ctx, "server %s\nrealm %s\nzone %s.\n", + servername, realm, zone); + } else { + DEBUG(9, ("Creating update message for realm [%s] and zone [%s].\n", + realm, zone)); + + /* Add the realm and zone headers */ + ctx->update_msg = talloc_asprintf(ctx, "realm %s\nzone %s.\n", + realm, zone); + } if (ctx->update_msg == NULL) { ret = ENOMEM; goto done; @@ -478,6 +505,7 @@ fork_nsupdate_send(struct ipa_nsupdate_ctx *ctx) return NULL; } state->nsupdate_ctx = ctx; + state->child_status = 0; ret = pipe(pipefd_to_child); if (ret == -1) { @@ -597,6 +625,10 @@ static void ipa_dyndns_child_handler(int child_status, void *pvt) { struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); + struct nsupdate_send_ctx *state = + tevent_req_data(req, struct nsupdate_send_ctx); + + state->child_status = child_status; if (WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) { DEBUG(1, ("Dynamic DNS child failed with status [%d]\n", @@ -615,6 +647,18 @@ static void ipa_dyndns_child_handler(int child_status, tevent_req_done(req); } +static int ipa_dyndns_child_recv(struct tevent_req *req, int *child_status) +{ + struct nsupdate_send_ctx *state = + tevent_req_data(req, struct nsupdate_send_ctx); + + *child_status = state->child_status; + + TEVENT_REQ_RETURN_ON_ERROR(req); + + return EOK; +} + static int ipa_dyndns_generic_recv(struct tevent_req *req) { TEVENT_REQ_RETURN_ON_ERROR(req); @@ -627,8 +671,10 @@ static void fork_nsupdate_done(struct tevent_req *subreq) int ret; struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); + struct ipa_nsupdate_ctx *state = tevent_req_data(req, + struct ipa_nsupdate_ctx); - ret = ipa_dyndns_generic_recv(subreq); + ret = ipa_dyndns_child_recv(subreq, &state->child_status); talloc_zfree(subreq); if (ret != EOK) { tevent_req_error(req, ret); @@ -638,21 +684,46 @@ static void fork_nsupdate_done(struct tevent_req *subreq) tevent_req_done(req); } +static int fork_nsupdate_recv(struct tevent_req *req, int *child_status) +{ + struct ipa_nsupdate_ctx *state = + tevent_req_data(req, struct ipa_nsupdate_ctx); + + *child_status = state->child_status; + + TEVENT_REQ_RETURN_ON_ERROR(req); + + return EOK; +} + static void ipa_dyndns_gss_tsig_update_done(struct tevent_req *subreq) { /* Check the return code from the sigchld handler * and return it to the parent request. */ int ret; + int child_status; struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); + struct ipa_dyndns_ctx *state = tevent_req_data(req, struct ipa_dyndns_ctx); - ret = ipa_dyndns_generic_recv(subreq); + ret = fork_nsupdate_recv(subreq, &child_status); talloc_zfree(subreq); if (ret != EOK) { - tevent_req_error(req, ret); - return; + if (state->use_server_with_nsupdate == false && + WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) { + DEBUG(9, ("nsupdate failed, retrying with server name.\n")); + state->use_server_with_nsupdate = true; + ret = ipa_dyndns_gss_tsig_update_step(req); + if (ret != EOK) { + tevent_req_error(req, ret); + } + return; + } else { + tevent_req_error(req, ret); + return; + } } tevent_req_done(req); |