summaryrefslogtreecommitdiff
path: root/src/providers/ldap/sdap_dyndns.c
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2013-04-30 16:40:09 +0200
committerJakub Hrozek <jhrozek@redhat.com>2013-05-03 20:25:46 +0200
commit38ebc764eeb7693e0c4f0894d6687e54fbba871b (patch)
treea02094f8985977fc2846b98c385c6169c5864e84 /src/providers/ldap/sdap_dyndns.c
parenta398adc5b40381fc567a2aee1841b26af78aea17 (diff)
downloadsssd-38ebc764eeb7693e0c4f0894d6687e54fbba871b.tar.gz
sssd-38ebc764eeb7693e0c4f0894d6687e54fbba871b.tar.bz2
sssd-38ebc764eeb7693e0c4f0894d6687e54fbba871b.zip
dyndns: New option dyndns_update_ptr
https://fedorahosted.org/sssd/ticket/1832 While some servers, such as FreeIPA allow the PTR record to be synchronized when the forward record is updated, other servers, including Active Directory, require that the PTR record is synchronized manually. This patch adds a new option, dyndns_update_ptr that automatically generates appropriate DNS update message for updating the reverse zone. This option is off by default in the IPA provider. Also renames be_nsupdate_create_msg to be_nsupdate_create_fwd_msg
Diffstat (limited to 'src/providers/ldap/sdap_dyndns.c')
-rw-r--r--src/providers/ldap/sdap_dyndns.c195
1 files changed, 159 insertions, 36 deletions
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);
}