From 1639954090616f9e868a083f358c87e381b3fb78 Mon Sep 17 00:00:00 2001 From: eindenbom Date: Fri, 9 Jul 2010 18:03:37 +0400 Subject: Use new LDAP connection framework in IPA dynamic DNS forwarder. --- src/providers/ipa/ipa_dyndns.c | 160 ++++++++++++++++++++++------- src/providers/ldap/sdap_async_connection.c | 7 -- src/providers/ldap/sdap_id_op.c | 4 + 3 files changed, 126 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c index a86c69680..af942839f 100644 --- a/src/providers/ipa/ipa_dyndns.c +++ b/src/providers/ipa/ipa_dyndns.c @@ -51,6 +51,7 @@ struct ipa_ipaddress { struct ipa_dyndns_ctx { struct ipa_options *ipa_ctx; + struct sdap_id_op* sdap_op; char *hostname; struct ipa_ipaddress *addresses; int child_status; @@ -72,6 +73,10 @@ void ipa_dyndns_update(void *pvt) tevent_req_set_callback(req, ipa_dyndns_update_done, req); } +static void ipa_dyndns_sdap_connect_done(struct tevent_req *subreq); +static int ipa_dyndns_add_ldap_iface(struct ipa_dyndns_ctx *state, + struct sdap_handle *sh); +static int ipa_dyndns_gss_tsig_update_step(struct tevent_req *req); static struct tevent_req * ipa_dyndns_gss_tsig_update_send(struct ipa_dyndns_ctx *ctx); @@ -82,12 +87,8 @@ static struct tevent_req * ipa_dyndns_update_send(struct ipa_options *ctx) { int ret; - int fd; char *iface; - char *ipa_hostname; struct ipa_dyndns_ctx *state; - struct sockaddr sa; - socklen_t sa_len = sizeof(sa); struct ifaddrs *ifaces; struct ifaddrs *ifa; struct ipa_ipaddress *address; @@ -140,42 +141,131 @@ ipa_dyndns_update_send(struct ipa_options *ctx) } freeifaddrs(ifaces); - } - else { - /* Get the file descriptor for the primary LDAP connection */ - ret = get_fd_from_ldap(ctx->id_ctx->gsh->ldap, &fd); + ret = ipa_dyndns_gss_tsig_update_step(req); if (ret != EOK) { goto failed; } + } - ret = getsockname(fd, &sa, &sa_len); - if (ret == -1) { - DEBUG(0,("Failed to get socket name\n")); + else { + /* Detect DYNDNS interface from LDAP connection */ + state->sdap_op = sdap_id_op_create(state, state->ipa_ctx->id_ctx->conn_cache); + if (!state->sdap_op) { + DEBUG(1, ("sdap_id_op_create failed\n")); + ret = ENOMEM; goto failed; } - switch(sa.sa_family) { - case AF_INET: - case AF_INET6: - address = talloc(state, struct ipa_ipaddress); - if (!address) { - goto failed; - } - address->addr = talloc_memdup(address, &sa, - sizeof(struct sockaddr)); - if(address->addr == NULL) { - goto failed; - } - DLIST_ADD(state->addresses, address); - break; - default: - DEBUG(1, ("Connection to LDAP is neither IPv4 nor IPv6\n")); - ret = EIO; + subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret); + if (!subreq) { + DEBUG(1, ("sdap_id_op_connect_send failed: [%d](%s)\n", + ret, strerror(ret))); + goto failed; } + + tevent_req_set_callback(subreq, ipa_dyndns_sdap_connect_done, req); + } + + return req; + +failed: + talloc_free(req); + return NULL; +} + +static void ipa_dyndns_sdap_connect_done(struct tevent_req *subreq) +{ + 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); + int ret, dp_error; + + ret = sdap_id_op_connect_recv(subreq, &dp_error); + talloc_zfree(subreq); + + if (ret != EOK) { + if (dp_error == DP_ERR_OFFLINE) { + DEBUG(9,("No LDAP server is available, dynamic DNS update is skipped in OFFLINE mode.\n")); + } else { + DEBUG(9,("Failed to connect to LDAP server: [%d](%s)\n", + ret, strerror(ret))); + } + + goto failed; + } + + ret = ipa_dyndns_add_ldap_iface(state, sdap_id_op_handle(state->sdap_op)); + talloc_zfree(state->sdap_op); + if (ret != EOK) { + goto failed; + } + + ret = ipa_dyndns_gss_tsig_update_step(req); + if (ret != EOK) { + goto failed; + } + + return; + +failed: + tevent_req_error(req, ret); +} + +static int ipa_dyndns_add_ldap_iface(struct ipa_dyndns_ctx *state, + struct sdap_handle *sh) +{ + int ret; + int fd; + struct ipa_ipaddress *address; + struct sockaddr sa; + socklen_t sa_len = sizeof(sa); + + if (!sh) { + return EINVAL; + } + + /* Get the file descriptor for the primary LDAP connection */ + ret = get_fd_from_ldap(sh->ldap, &fd); + if (ret != EOK) { + return ret; + } + + ret = getsockname(fd, &sa, &sa_len); + if (ret == -1) { + DEBUG(0,("Failed to get socket name\n")); + return errno; + } + + switch(sa.sa_family) { + case AF_INET: + case AF_INET6: + address = talloc(state, struct ipa_ipaddress); + if (!address) { + return ENOMEM; + } + address->addr = talloc_memdup(address, &sa, + sizeof(struct sockaddr)); + if(address->addr == NULL) { + talloc_zfree(address); + return ENOMEM; + } + DLIST_ADD(state->addresses, address); + break; + default: + DEBUG(1, ("Connection to LDAP is neither IPv4 nor IPv6\n")); + return EIO; } + return EOK; +} + +static int ipa_dyndns_gss_tsig_update_step(struct tevent_req *req) +{ + struct ipa_dyndns_ctx *state = tevent_req_data(req, struct ipa_dyndns_ctx); + char *ipa_hostname; + struct tevent_req *subreq; + /* Get the IPA hostname */ ipa_hostname = dp_opt_get_string(state->ipa_ctx->basic, IPA_HOSTNAME); @@ -183,14 +273,12 @@ ipa_dyndns_update_send(struct ipa_options *ctx) /* This should never happen, but we'll protect * against it anyway. */ - talloc_free(req); - return NULL; + return EINVAL; } state->hostname = talloc_strdup(state, ipa_hostname); if(state->hostname == NULL) { - talloc_free(req); - return NULL; + return ENOMEM; } /* In the future, it might be best to check that an update @@ -200,16 +288,12 @@ ipa_dyndns_update_send(struct ipa_options *ctx) */ subreq = ipa_dyndns_gss_tsig_update_send(state); if(subreq == NULL) { - tevent_req_error(req, EIO); + return ENOMEM; } tevent_req_set_callback(subreq, ipa_dyndns_gss_tsig_update_done, req); - return req; - -failed: - talloc_free(req); - return NULL; + return EOK; } struct ipa_nsupdate_ctx { diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c index 2af6aaeab..2be0af208 100644 --- a/src/providers/ldap/sdap_async_connection.c +++ b/src/providers/ldap/sdap_async_connection.c @@ -1184,8 +1184,6 @@ static void sdap_cli_auth_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); - struct sdap_cli_connect_state *state = tevent_req_data(req, - struct sdap_cli_connect_state); enum sdap_result result; int ret; @@ -1200,11 +1198,6 @@ static void sdap_cli_auth_done(struct tevent_req *subreq) return; } - /* Reconnection succeeded - * Run any post-connection routines - */ - be_run_online_cb(state->be); - tevent_req_done(req); } diff --git a/src/providers/ldap/sdap_id_op.c b/src/providers/ldap/sdap_id_op.c index 1e20c75e1..a005f0f70 100644 --- a/src/providers/ldap/sdap_id_op.c +++ b/src/providers/ldap/sdap_id_op.c @@ -627,6 +627,10 @@ static void sdap_id_op_connect_done(struct tevent_req *subreq) if (ret == EOK && conn_data->sh->connected && !be_is_offline(conn_cache->be)) { DEBUG(9, ("caching successful connection after %d notifies\n", notify_count)); conn_cache->cached_connection = conn_data; + + /* Run any post-connection routines */ + be_run_online_cb(conn_cache->be); + } else { if (conn_cache->cached_connection == conn_data) { conn_cache->cached_connection = NULL; -- cgit