From 57614e56dd272db0f71abc442b1515d79fd16169 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Fri, 7 May 2010 17:19:00 -0400 Subject: Revert "Add dynamic DNS updates to FreeIPA" This reverts commit 973b7c27c0b294b8b2f120296f64c6a3a36e44b7. While this patch applied cleanly, it was uncompilable. Reverting until it can be properly merged. --- src/providers/ipa/ipa_dyndns.c | 580 ----------------------------------------- 1 file changed, 580 deletions(-) delete mode 100644 src/providers/ipa/ipa_dyndns.c (limited to 'src/providers/ipa/ipa_dyndns.c') diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c deleted file mode 100644 index b1edc194c..000000000 --- a/src/providers/ipa/ipa_dyndns.c +++ /dev/null @@ -1,580 +0,0 @@ -/* - SSSD - - ipa_dyndns.c - - Authors: - Stephen Gallagher - - Copyright (C) 2010 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "util/util.h" -#include "confdb/confdb.h" -#include "providers/ipa/ipa_common.h" -#include "providers/ipa/ipa_dyndns.h" -#include "providers/child_common.h" -#include "providers/data_provider.h" -#include "providers/ldap/ldap_common.h" -#include "providers/ldap/sdap_async_private.h" -#include "resolv/async_resolv.h" - -#define IPA_DYNDNS_TIMEOUT 15 - -struct ipa_ipaddress { - struct ipa_ipaddress *next; - struct ipa_ipaddress *prev; - - struct sockaddr *addr; - bool matched; -}; - -struct ipa_dyndns_ctx { - struct ipa_options *ipa_ctx; - char *hostname; - struct ipa_ipaddress *addresses; - int child_status; -}; - - -static struct tevent_req * ipa_dyndns_update_send(struct ipa_options *ctx); - -static void ipa_dyndns_update_done(struct tevent_req *req); - -void ipa_dyndns_update(void *pvt) -{ - struct ipa_options *ctx = talloc_get_type(pvt, struct ipa_options); - struct tevent_req *req = ipa_dyndns_update_send(ctx); - if (req == NULL) { - DEBUG(1, ("Could not update DNS\n")); - return; - } - tevent_req_set_callback(req, ipa_dyndns_update_done, req); -} - - -static struct tevent_req * -ipa_dyndns_gss_tsig_update_send(struct ipa_dyndns_ctx *ctx); - -static void ipa_dyndns_gss_tsig_update_done(struct tevent_req *subreq); - -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; - struct tevent_req *req, *subreq; - - DEBUG (9, ("Performing update\n")); - - req = tevent_req_create(ctx, &state, struct ipa_dyndns_ctx); - if (req == NULL) { - return NULL; - } - state->ipa_ctx = ctx; - - iface = dp_opt_get_string(ctx->basic, IPA_DYNDNS_IFACE); - - if (iface) { - /* Get the IP addresses associated with the - * specified interface - */ - errno = 0; - ret = getifaddrs(&ifaces); - if (ret == -1) { - ret = errno; - DEBUG(0, ("Could not read interfaces [%d][%s]\n", - ret, strerror(ret))); - goto failed; - } - - for(ifa = ifaces; ifa != NULL; ifa=ifa->ifa_next) { - /* Some interfaces don't have an ifa_addr */ - if (!ifa->ifa_addr) continue; - - /* Add IP addresses to the list */ - if((ifa->ifa_addr->sa_family == AF_INET || - ifa->ifa_addr->sa_family == AF_INET6) && - strcasecmp(ifa->ifa_name, iface) == 0) { - /* Add this address to the IP address list */ - address = talloc_zero(state, struct ipa_ipaddress); - if (!address) { - goto failed; - } - - address->addr = talloc_memdup(address, ifa->ifa_addr, - sizeof(struct sockaddr)); - if(address->addr == NULL) { - goto failed; - } - DLIST_ADD(state->addresses, address); - } - } - - freeifaddrs(ifaces); - } - - else { - /* Get the file descriptor for the primary LDAP connection */ - ret = get_fd_from_ldap(ctx->id_ctx->gsh->ldap, &fd); - if (ret != EOK) { - goto failed; - } - - ret = getsockname(fd, &sa, &sa_len); - if (ret == -1) { - DEBUG(0,("Failed to get socket name\n")); - 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; - goto failed; - } - } - - /* Get the IPA hostname */ - ipa_hostname = dp_opt_get_string(state->ipa_ctx->basic, - IPA_HOSTNAME); - if (!ipa_hostname) { - /* This should never happen, but we'll protect - * against it anyway. - */ - talloc_free(req); - return NULL; - } - - state->hostname = talloc_strdup(state, ipa_hostname); - if(state->hostname == NULL) { - talloc_free(req); - return NULL; - } - - /* In the future, it might be best to check that an update - * needs to be run before running it, but this is such a - * rare event that it's probably fine to just run an update - * every time we come online. - */ - subreq = ipa_dyndns_gss_tsig_update_send(state); - if(subreq == NULL) { - tevent_req_error(req, EIO); - } - tevent_req_set_callback(subreq, - ipa_dyndns_gss_tsig_update_done, - req); - return req; - -failed: - talloc_free(req); - return NULL; -} - -struct ipa_nsupdate_ctx { - char *update_msg; - struct ipa_dyndns_ctx *dyndns_ctx; - int pipefd_to_child; - struct tevent_timer *timeout_handler; -}; - - -static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx); - -static struct tevent_req * -fork_nsupdate_send(struct ipa_nsupdate_ctx *ctx); - -static void fork_nsupdate_done(struct tevent_req *subreq); - -static struct tevent_req * -ipa_dyndns_gss_tsig_update_send(struct ipa_dyndns_ctx *ctx) -{ - int ret; - struct ipa_nsupdate_ctx *state; - struct tevent_req *req; - struct tevent_req *subreq; - - req = tevent_req_create(ctx, &state, struct ipa_nsupdate_ctx); - if(req == NULL) { - return NULL; - } - state->dyndns_ctx = ctx; - - /* Format the message to pass to the nsupdate command */ - ret = create_nsupdate_message(state); - if (ret != EOK) { - goto failed; - } - - /* Fork a child process to perform the DNS update */ - subreq = fork_nsupdate_send(state); - if(subreq == NULL) { - goto failed; - } - tevent_req_set_callback(subreq, fork_nsupdate_done, req); - - return req; - -failed: - talloc_free(req); - return NULL; -} - -struct nsupdate_send_ctx { - struct ipa_nsupdate_ctx *nsupdate_ctx; -}; - -static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx) -{ - int ret, i; - char *servername; - 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) { - return EIO; - } - - zone = dp_opt_get_string(ctx->dyndns_ctx->ipa_ctx->basic, - IPA_DOMAIN); - if (!zone) { - return EIO; - } - - /* The DNS zone for IPA is the lower-case - * version of hte IPA domain - */ - for(i = 0; zone[i] != '\0'; i++) { - 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 (ctx->update_msg == NULL) { - ret = ENOMEM; - goto done; - } - - /* Remove any existing entries */ - ctx->update_msg = talloc_asprintf_append(ctx->update_msg, - "update delete %s. in A\nsend\n" - "update delete %s. in AAAA\nsend\n", - ctx->dyndns_ctx->hostname, - ctx->dyndns_ctx->hostname); - if (ctx->update_msg == NULL) { - ret = ENOMEM; - goto done; - } - - DLIST_FOR_EACH(new_record, ctx->dyndns_ctx->addresses) { - switch(new_record->addr->sa_family) { - case AF_INET: - ip = inet_ntop(new_record->addr->sa_family, - &(((struct sockaddr_in *)new_record->addr)->sin_addr), - ip_addr, INET6_ADDRSTRLEN); - if (ip == NULL) { - ret = EIO; - goto done; - } - break; - - case AF_INET6: - ip = inet_ntop(new_record->addr->sa_family, - &(((struct sockaddr_in6 *)new_record->addr)->sin6_addr), - ip_addr, INET6_ADDRSTRLEN); - if (ip == NULL) { - ret = EIO; - goto done; - } - break; - - default: - DEBUG(0, ("Unknown address family\n")); - ret = EIO; - goto done; - } - - /* Format the record update */ - ctx->update_msg = talloc_asprintf_append( - ctx->update_msg, - "update add %s. 86400 in %s %s\n", - ctx->dyndns_ctx->hostname, - new_record->addr->sa_family == AF_INET ? "A" : "AAAA", - ip_addr); - if (ctx->update_msg == NULL) { - ret = ENOMEM; - goto done; - } - } - - ctx->update_msg = talloc_asprintf_append(ctx->update_msg, "send\n"); - if (ctx->update_msg == NULL) { - ret = ENOMEM; - goto done; - } - - ret = EOK; - -done: - return ret; -} - -static void ipa_dyndns_stdin_done(struct tevent_req *subreq); - -static void ipa_dyndns_child_handler(int child_status, - struct tevent_signal *sige, - void *pvt); - -static void ipa_dyndns_timeout(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt); - -static struct tevent_req * -fork_nsupdate_send(struct ipa_nsupdate_ctx *ctx) -{ - int pipefd_to_child[2]; - pid_t pid; - int ret; - errno_t err; - struct timeval tv; - struct tevent_req *req = NULL; - struct tevent_req *subreq = NULL; - struct nsupdate_send_ctx *state; - char *args[3]; - - req = tevent_req_create(ctx, &state, struct nsupdate_send_ctx); - if (req == NULL) { - return NULL; - } - state->nsupdate_ctx = ctx; - - ret = pipe(pipefd_to_child); - if (ret == -1) { - err = errno; - DEBUG(1, ("pipe failed [%d][%s].\n", err, strerror(err))); - return NULL; - } - - pid = fork(); - - if (pid == 0) { /* child */ - args[0] = talloc_strdup(ctx, NSUPDATE_PATH); - args[1] = talloc_strdup(ctx, "-g"); - args[2] = NULL; - if (args[0] == NULL || args[1] == NULL) { - return NULL; - } - - close(pipefd_to_child[1]); - ret = dup2(pipefd_to_child[0], STDIN_FILENO); - if (ret == -1) { - err = errno; - DEBUG(1, ("dup2 failed [%d][%s].\n", err, strerror(err))); - return NULL; - } - - errno = 0; - ret = execv(NSUPDATE_PATH, args); - if(ret == -1) { - err = errno; - DEBUG(1, ("execv failed [%d][%s].\n", err, strerror(err))); - } - return NULL; - } - - else if (pid > 0) { /* parent */ - close(pipefd_to_child[0]); - - ctx->pipefd_to_child = pipefd_to_child[1]; - - /* Write the update message to the nsupdate child */ - subreq = write_pipe_send(req, - ctx->dyndns_ctx->ipa_ctx->id_ctx->be->ev, - (uint8_t *)ctx->update_msg, - strlen(ctx->update_msg)+1, - ctx->pipefd_to_child); - if (subreq == NULL) { - return NULL; - } - tevent_req_set_callback(subreq, ipa_dyndns_stdin_done, req); - - /* Set up SIGCHLD handler */ - ret = child_handler_setup(ctx->dyndns_ctx->ipa_ctx->id_ctx->be->ev, - pid, ipa_dyndns_child_handler, req); - if (ret != EOK) { - return NULL; - } - - /* Set up timeout handler */ - tv = tevent_timeval_current_ofs(IPA_DYNDNS_TIMEOUT, 0); - ctx->timeout_handler = tevent_add_timer( - ctx->dyndns_ctx->ipa_ctx->id_ctx->be->ev, - req, tv, ipa_dyndns_timeout, req); - if(ctx->timeout_handler == NULL) { - return NULL; - } - } - - else { /* error */ - err = errno; - DEBUG(1, ("fork failed [%d][%s].\n", err, strerror(err))); - return NULL; - } - - return req; -} - -static void ipa_dyndns_timeout(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt) -{ - struct tevent_req *req = - talloc_get_type(pvt, struct tevent_req); - - DEBUG(1, ("Timeout reached for dynamic DNS update\n")); - - tevent_req_error(req, ETIMEDOUT); -} - -static void ipa_dyndns_stdin_done(struct tevent_req *subreq) -{ - /* Verify that the buffer was sent, then return - * and wait for the sigchld handler to finish. - */ - DEBUG(9, ("Sending nsupdate data complete\n")); - - int ret; - struct tevent_req *req = - tevent_req_callback_data(subreq, struct tevent_req); - struct nsupdate_send_ctx *state = - tevent_req_data(req, struct nsupdate_send_ctx); - - ret = write_pipe_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - DEBUG(1, ("Sending nsupdate data failed\n")); - tevent_req_error(req, ret); - return; - } - - close(state->nsupdate_ctx->pipefd_to_child); - state->nsupdate_ctx->pipefd_to_child = -1; -} - -static void ipa_dyndns_child_handler(int child_status, - struct tevent_signal *sige, - void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - - if (WEXITSTATUS(child_status) != 0) { - DEBUG(1, ("Dynamic DNS child failed with status [%d]\n", - child_status)); - tevent_req_error(req, EIO); - return; - } - - tevent_req_done(req); -} - -static int ipa_dyndns_generic_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - -static void fork_nsupdate_done(struct tevent_req *subreq) -{ - int ret; - struct tevent_req *req = - tevent_req_callback_data(subreq, struct tevent_req); - - ret = ipa_dyndns_generic_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -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; - - struct tevent_req *req = - tevent_req_callback_data(subreq, struct tevent_req); - - ret = ipa_dyndns_generic_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -static void ipa_dyndns_update_done(struct tevent_req *req) -{ - int ret = ipa_dyndns_generic_recv(req); - talloc_free(req); - if (ret != EOK) { - DEBUG(1, ("Updating DNS entry failed\n")); - return; - } - - DEBUG(1,("Updated DNS entry\n")); -} -- cgit