summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSumit Bose <sbose@redhat.com>2011-02-25 12:52:59 +0100
committerSimo Sorce <ssorce@redhat.com>2011-03-03 18:36:48 -0500
commitef2c477a605e2130be019d1a4bba6bdd02c54a9d (patch)
tree17a9b384981bbc7816dd12fa4732a78f29cf5d33 /src
parent57d6586b06dd833330f7f9b125a81b5acabfa1a7 (diff)
downloadsssd-ef2c477a605e2130be019d1a4bba6bdd02c54a9d.tar.gz
sssd-ef2c477a605e2130be019d1a4bba6bdd02c54a9d.tar.xz
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.c103
1 files changed, 87 insertions, 16 deletions
diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c
index af942839f..bee4bff5e 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);