LCOV - code coverage report
Current view: top level - providers - dp_dyndns.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 316 570 55.4 %
Date: 2015-10-19 Functions: 28 36 77.8 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     dp_dyndns.c
       5             : 
       6             :     Authors:
       7             :         Stephen Gallagher <sgallagh@redhat.com>
       8             :         Jakub Hrozek <jhrozek@redhat.com>
       9             : 
      10             :     Copyright (C) 2013 Red Hat
      11             : 
      12             :     This program is free software; you can redistribute it and/or modify
      13             :     it under the terms of the GNU General Public License as published by
      14             :     the Free Software Foundation; either version 3 of the License, or
      15             :     (at your option) any later version.
      16             : 
      17             :     This program is distributed in the hope that it will be useful,
      18             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      19             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20             :     GNU General Public License for more details.
      21             : 
      22             :     You should have received a copy of the GNU General Public License
      23             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      24             : */
      25             : 
      26             : #include <sys/types.h>
      27             : #include <sys/socket.h>
      28             : #include <sys/ioctl.h>
      29             : #include <arpa/inet.h>
      30             : #include <net/if.h>
      31             : #include <ifaddrs.h>
      32             : #include <ctype.h>
      33             : #include "util/util.h"
      34             : #include "confdb/confdb.h"
      35             : #include "util/child_common.h"
      36             : #include "providers/data_provider.h"
      37             : #include "providers/dp_backend.h"
      38             : #include "providers/dp_dyndns.h"
      39             : #include "resolv/async_resolv.h"
      40             : 
      41             : #ifndef DYNDNS_TIMEOUT
      42             : #define DYNDNS_TIMEOUT 15
      43             : #endif /* DYNDNS_TIMEOUT */
      44             : 
      45             : /* MASK represents special value for matching all interfaces */
      46             : #define MASK "*"
      47             : 
      48             : struct sss_iface_addr {
      49             :     struct sss_iface_addr *next;
      50             :     struct sss_iface_addr *prev;
      51             : 
      52             :     struct sockaddr_storage *addr;
      53             : };
      54             : 
      55             : struct sockaddr_storage*
      56           4 : sss_iface_addr_get_address(struct sss_iface_addr *address)
      57             : {
      58           4 :     if (address == NULL) {
      59           1 :         return NULL;
      60             :     }
      61             : 
      62           3 :     return address->addr;
      63             : }
      64             : 
      65           4 : struct sss_iface_addr *sss_iface_addr_get_next(struct sss_iface_addr *address)
      66             : {
      67           4 :     if (address) {
      68           3 :         return address->next;
      69             :     }
      70             : 
      71           1 :     return NULL;
      72             : }
      73             : 
      74           0 : void sss_iface_addr_concatenate(struct sss_iface_addr **list,
      75             :                                 struct sss_iface_addr *list2)
      76             : {
      77           0 :     DLIST_CONCATENATE((*list), list2, struct sss_iface_addr*);
      78           0 : }
      79             : 
      80          24 : static errno_t addr_to_str(struct sockaddr_storage *addr,
      81             :                            char *dst, size_t size)
      82             : {
      83             :     const void *src;
      84             :     const char *res;
      85             :     errno_t ret;
      86             : 
      87          24 :     switch(addr->ss_family) {
      88             :     case AF_INET:
      89          12 :         src = &(((struct sockaddr_in *)addr)->sin_addr);
      90          12 :         break;
      91             :     case AF_INET6:
      92          12 :         src = &(((struct sockaddr_in6 *)addr)->sin6_addr);
      93          12 :         break;
      94             :     default:
      95           0 :         ret = ERR_ADDR_FAMILY_NOT_SUPPORTED;
      96           0 :         goto done;
      97             :     }
      98             : 
      99          24 :     res = inet_ntop(addr->ss_family, src, dst, size);
     100          24 :     if (res == NULL) {
     101           0 :         ret = errno;
     102           0 :         DEBUG(SSSDBG_OP_FAILURE, "inet_ntop failed [%d]: %s\n",
     103             :               ret, sss_strerror(ret));
     104           0 :         goto done;
     105             :     }
     106             : 
     107          24 :     ret = EOK;
     108             : 
     109             : done:
     110          24 :     return ret;
     111             : }
     112             : 
     113             : errno_t
     114           1 : sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
     115             :                                 struct sss_iface_addr *ifaddr_list,
     116             :                                 char ***_straddrs)
     117             : {
     118             :     struct sss_iface_addr *ifaddr;
     119             :     size_t count;
     120             :     int ai;
     121             :     char **straddrs;
     122             :     char ip_addr[INET6_ADDRSTRLEN];
     123             :     errno_t ret;
     124             : 
     125           1 :     count = 0;
     126           5 :     DLIST_FOR_EACH(ifaddr, ifaddr_list) {
     127           4 :         count++;
     128             :     }
     129             : 
     130           1 :     straddrs = talloc_array(mem_ctx, char *, count+1);
     131           1 :     if (straddrs == NULL) {
     132           0 :         return ENOMEM;
     133             :     }
     134             : 
     135           1 :     ai = 0;
     136           5 :     DLIST_FOR_EACH(ifaddr, ifaddr_list) {
     137             : 
     138           4 :         ret = addr_to_str(ifaddr->addr, ip_addr, INET6_ADDRSTRLEN);
     139           4 :         if (ret == ERR_ADDR_FAMILY_NOT_SUPPORTED) {
     140           0 :             continue;
     141           4 :         } else if (ret != EOK) {
     142           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "addr_to_str failed: %d:[%s],\n",
     143             :                   ret, sss_strerror(ret));
     144           0 :             goto fail;
     145             :         }
     146             : 
     147           4 :         straddrs[ai] = talloc_strdup(straddrs, ip_addr);
     148           4 :         if (straddrs[ai] == NULL) {
     149           0 :             ret = ENOMEM;
     150           0 :             goto fail;
     151             :         }
     152           4 :         ai++;
     153             :     }
     154             : 
     155           1 :     straddrs[count] = NULL;
     156           1 :     *_straddrs = straddrs;
     157           1 :     return EOK;
     158             : 
     159             : fail:
     160           0 :     talloc_free(straddrs);
     161           0 :     return ret;
     162             : }
     163             : 
     164             : static bool
     165          25 : ok_for_dns(struct sockaddr *sa)
     166             : {
     167             :     struct sockaddr_in sa4;
     168             :     struct sockaddr_in6 sa6;
     169             : 
     170          25 :     switch (sa->sa_family) {
     171             :     case AF_INET6:
     172          12 :         memcpy(&sa6, sa, sizeof(struct sockaddr_in6));
     173          12 :         return check_ipv6_addr(&sa6.sin6_addr, SSS_NO_SPECIAL);
     174             :     case AF_INET:
     175          13 :         memcpy(&sa4, sa, sizeof(struct sockaddr_in));
     176          13 :         return check_ipv4_addr(&sa4.sin_addr, SSS_NO_SPECIAL);
     177             :     default:
     178           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
     179           0 :         return false;
     180             :     }
     181             : 
     182             :     return true;
     183             : }
     184             : 
     185          32 : static bool supported_address_family(sa_family_t sa_family)
     186             : {
     187          32 :     return sa_family == AF_INET || sa_family == AF_INET6;
     188             : }
     189             : 
     190          32 : static bool matching_name(const char *ifname, const char *ifname2)
     191             : {
     192          32 :     return (strcmp(MASK, ifname) == 0) || (strcasecmp(ifname, ifname2) == 0);
     193             : }
     194             : 
     195             : /* Collect IP addresses associated with an interface */
     196             : errno_t
     197          10 : sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname,
     198             :                         struct sss_iface_addr **_addrlist)
     199             : {
     200          10 :     struct ifaddrs *ifaces = NULL;
     201             :     struct ifaddrs *ifa;
     202             :     errno_t ret;
     203             :     size_t addrsize;
     204             :     struct sss_iface_addr *address;
     205          10 :     struct sss_iface_addr *addrlist = NULL;
     206             : 
     207             :     /* Get the IP addresses associated with the
     208             :      * specified interface
     209             :      */
     210          10 :     errno = 0;
     211          10 :     ret = getifaddrs(&ifaces);
     212          10 :     if (ret == -1) {
     213           0 :         ret = errno;
     214           0 :         DEBUG(SSSDBG_OP_FAILURE,
     215             :               "Could not read interfaces [%d][%s]\n", ret, strerror(ret));
     216           0 :         goto done;
     217             :     }
     218             : 
     219          42 :     for (ifa = ifaces; ifa != NULL; ifa = ifa->ifa_next) {
     220             :         /* Some interfaces don't have an ifa_addr */
     221          32 :         if (!ifa->ifa_addr) continue;
     222             : 
     223             :         /* Add IP addresses to the list */
     224          32 :         if (supported_address_family(ifa->ifa_addr->sa_family)
     225          32 :                 && matching_name(ifname, ifa->ifa_name)
     226          25 :                 && ok_for_dns(ifa->ifa_addr)) {
     227             : 
     228             :             /* Add this address to the IP address list */
     229          23 :             address = talloc_zero(mem_ctx, struct sss_iface_addr);
     230          23 :             if (!address) {
     231           0 :                 ret = ENOMEM;
     232           0 :                 goto done;
     233             :             }
     234             : 
     235          46 :             addrsize = ifa->ifa_addr->sa_family == AF_INET ? \
     236          23 :                                 sizeof(struct sockaddr_in) : \
     237             :                                 sizeof(struct sockaddr_in6);
     238             : 
     239          23 :             address->addr = talloc_memdup(address, ifa->ifa_addr,
     240             :                                           addrsize);
     241          23 :             if (address->addr == NULL) {
     242           0 :                 ret = ENOMEM;
     243           0 :                 goto done;
     244             :             }
     245             : 
     246             :             /* steal old dlist to the new head */
     247          23 :             talloc_steal(address, addrlist);
     248          23 :             DLIST_ADD(addrlist, address);
     249             :         }
     250             :     }
     251             : 
     252          10 :     if (addrlist != NULL) {
     253             :         /* OK, some result was found */
     254           9 :         ret = EOK;
     255           9 :         *_addrlist = addrlist;
     256             :     } else {
     257             :         /* No result was found */
     258           1 :         DEBUG(SSSDBG_TRACE_FUNC,
     259             :               "No IPs usable for DNS was found for interface: %s.\n", ifname);
     260           1 :         ret = ENOENT;
     261             :     }
     262             : 
     263             : done:
     264          10 :     freeifaddrs(ifaces);
     265          10 :     return ret;
     266             : }
     267             : 
     268             : static char *
     269           9 : nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses,
     270             :                      const char *hostname, int ttl, uint8_t remove_af)
     271             : {
     272             :     struct sss_iface_addr *new_record;
     273             :     char ip_addr[INET6_ADDRSTRLEN];
     274             :     errno_t ret;
     275             : 
     276             :     /* A addresses first */
     277             :     /* Remove existing entries as needed */
     278           9 :     if (remove_af & DYNDNS_REMOVE_A) {
     279           8 :         update_msg = talloc_asprintf_append(update_msg,
     280             :                                             "update delete %s. in A\n",
     281             :                                             hostname);
     282           8 :         if (update_msg == NULL) {
     283           0 :             return NULL;
     284             :         }
     285             :     }
     286          29 :     DLIST_FOR_EACH(new_record, addresses) {
     287          20 :         if (new_record->addr->ss_family == AF_INET) {
     288          10 :             ret = addr_to_str(new_record->addr, ip_addr, INET6_ADDRSTRLEN);
     289          10 :             if (ret != EOK) {
     290           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "addr_to_str failed: %d:[%s],\n",
     291             :                       ret, sss_strerror(ret));
     292           0 :                 return NULL;
     293             :             }
     294             : 
     295             :             /* Format the record update */
     296          10 :             update_msg = talloc_asprintf_append(update_msg,
     297             :                                                 "update add %s. %d in %s %s\n",
     298             :                                                 hostname, ttl, "A", ip_addr);
     299          10 :             if (update_msg == NULL) {
     300           0 :                 return NULL;
     301             :             }
     302             :         }
     303             :     }
     304           9 :     update_msg = talloc_asprintf_append(update_msg, "send\n");
     305             : 
     306             :     /* AAAA addresses next */
     307             :     /* Remove existing entries as needed */
     308           9 :     if (remove_af & DYNDNS_REMOVE_AAAA) {
     309           8 :         update_msg = talloc_asprintf_append(update_msg,
     310             :                                             "update delete %s. in AAAA\n",
     311             :                                             hostname);
     312           8 :         if (update_msg == NULL) {
     313           0 :             return NULL;
     314             :         }
     315             :     }
     316          29 :     DLIST_FOR_EACH(new_record, addresses) {
     317          20 :         if (new_record->addr->ss_family == AF_INET6) {
     318          10 :             ret = addr_to_str(new_record->addr, ip_addr, INET6_ADDRSTRLEN);
     319          10 :             if (ret != EOK) {
     320           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "addr_to_str failed: %d:[%s],\n",
     321             :                       ret, sss_strerror(ret));
     322           0 :                 return NULL;
     323             :             }
     324             : 
     325             :             /* Format the record update */
     326          10 :             update_msg = talloc_asprintf_append(update_msg,
     327             :                                                 "update add %s. %d in %s %s\n",
     328             :                                                 hostname, ttl, "AAAA", ip_addr);
     329          10 :             if (update_msg == NULL) {
     330           0 :                 return NULL;
     331             :             }
     332             :         }
     333             :     }
     334             : 
     335           9 :     return talloc_asprintf_append(update_msg, "send\n");
     336             : }
     337             : 
     338           0 : static uint8_t *nsupdate_convert_address(struct sockaddr_storage *add_address)
     339             : {
     340             :     uint8_t *addr;
     341             : 
     342           0 :     switch(add_address->ss_family) {
     343             :     case AF_INET:
     344           0 :         addr = (uint8_t *) &((struct sockaddr_in *) add_address)->sin_addr;
     345           0 :         break;
     346             :     case AF_INET6:
     347           0 :         addr = (uint8_t *) &((struct sockaddr_in6 *) add_address)->sin6_addr;
     348           0 :         break;
     349             :     default:
     350           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
     351           0 :         addr = NULL;
     352           0 :         break;
     353             :     }
     354             : 
     355           0 :     return addr;
     356             : }
     357             : 
     358           0 : static char *nsupdate_msg_add_ptr(char *update_msg,
     359             :                                   struct sockaddr_storage *address,
     360             :                                   const char *hostname,
     361             :                                   int ttl,
     362             :                                   bool delete)
     363             : {
     364             :     char *strptr;
     365             :     uint8_t *addr;
     366             : 
     367           0 :     addr = nsupdate_convert_address(address);
     368           0 :     if (addr == NULL) {
     369           0 :         return NULL;
     370             :     }
     371             : 
     372           0 :     strptr = resolv_get_string_ptr_address(update_msg, address->ss_family,
     373             :                                            addr);
     374           0 :     if (strptr == NULL) {
     375           0 :         return NULL;
     376             :     }
     377             : 
     378           0 :     if (delete) {
     379             :         /* example: update delete 38.78.16.10.in-addr.arpa. in PTR */
     380           0 :         update_msg = talloc_asprintf_append(update_msg,
     381             :                                             "update delete %s in PTR\n"
     382             :                                             "send\n",
     383             :                                             strptr);
     384             :     } else {
     385             :         /* example: update delete 38.78.16.10.in-addr.arpa. in PTR */
     386           0 :         update_msg = talloc_asprintf_append(update_msg,
     387             :                                             "update add %s %d in PTR %s.\n"
     388             :                                             "send\n",
     389             :                                             strptr, ttl, hostname);
     390             :     }
     391             : 
     392           0 :     talloc_free(strptr);
     393           0 :     if (update_msg == NULL) {
     394           0 :         return NULL;
     395             :     }
     396             : 
     397           0 :     return update_msg;
     398             : }
     399             : 
     400             : static char *
     401           9 : nsupdate_msg_add_realm_cmd(TALLOC_CTX *mem_ctx, const char *realm)
     402             : {
     403             : #ifdef HAVE_NSUPDATE_REALM
     404           9 :     if (realm != NULL) {
     405           2 :         return talloc_asprintf(mem_ctx, "realm %s\n", realm);
     406             :     }
     407             : #endif
     408           7 :     return talloc_asprintf(mem_ctx, "\n");
     409             : }
     410             : 
     411             : static char *
     412           9 : nsupdate_msg_create_common(TALLOC_CTX *mem_ctx, const char *realm,
     413             :                            const char *servername)
     414             : {
     415             :     char *realm_directive;
     416             :     char *update_msg;
     417             :     TALLOC_CTX *tmp_ctx;
     418             : 
     419           9 :     tmp_ctx = talloc_new(NULL);
     420           9 :     if (tmp_ctx == NULL) return NULL;
     421             : 
     422           9 :     realm_directive = nsupdate_msg_add_realm_cmd(tmp_ctx, realm);
     423           9 :     if (!realm_directive) {
     424           0 :         goto fail;
     425             :     }
     426             : 
     427             :     /* The realm_directive would now either contain an empty string or be
     428             :      * completely empty so we don't need to add another newline here
     429             :      */
     430           9 :     if (servername) {
     431           2 :         DEBUG(SSSDBG_FUNC_DATA,
     432             :               "Creating update message for server [%s] and realm [%s].\n",
     433             :                servername, realm);
     434             : 
     435             :         /* Add the server, realm and headers */
     436           2 :         update_msg = talloc_asprintf(tmp_ctx, "server %s\n%s",
     437             :                                      servername, realm_directive);
     438             :     } else {
     439           7 :         DEBUG(SSSDBG_FUNC_DATA,
     440             :               "Creating update message for realm [%s].\n", realm);
     441             :         /* Add the realm headers */
     442           7 :         update_msg = talloc_asprintf(tmp_ctx, "%s", realm_directive);
     443             :     }
     444           9 :     talloc_free(realm_directive);
     445           9 :     if (update_msg == NULL) {
     446           0 :         goto fail;
     447             :     }
     448             : 
     449           9 :     update_msg = talloc_steal(mem_ctx, update_msg);
     450           9 :     talloc_free(tmp_ctx);
     451           9 :     return update_msg;
     452             : 
     453             : fail:
     454           0 :     talloc_free(tmp_ctx);
     455           0 :     return NULL;
     456             : }
     457             : 
     458             : errno_t
     459           9 : be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
     460             :                            const char *servername,
     461             :                            const char *hostname, const unsigned int ttl,
     462             :                            uint8_t remove_af, struct sss_iface_addr *addresses,
     463             :                            char **_update_msg)
     464             : {
     465             :     int ret;
     466             :     char *update_msg;
     467             :     TALLOC_CTX *tmp_ctx;
     468             : 
     469             :     /* in some cases realm could have been NULL if we weren't using TSIG */
     470           9 :     if (hostname == NULL) {
     471           0 :         return EINVAL;
     472             :     }
     473             : 
     474           9 :     tmp_ctx = talloc_new(NULL);
     475           9 :     if (tmp_ctx == NULL) return ENOMEM;
     476             : 
     477           9 :     update_msg = nsupdate_msg_create_common(tmp_ctx, realm, servername);
     478           9 :     if (update_msg == NULL) {
     479           0 :         ret = ENOMEM;
     480           0 :         goto done;
     481             :     }
     482             : 
     483           9 :     update_msg = nsupdate_msg_add_fwd(update_msg, addresses, hostname,
     484             :                                       ttl, remove_af);
     485           9 :     if (update_msg == NULL) {
     486           0 :         ret = ENOMEM;
     487           0 :         goto done;
     488             :     }
     489             : 
     490           9 :     DEBUG(SSSDBG_TRACE_FUNC,
     491             :           " -- Begin nsupdate message -- \n"
     492             :           "%s"
     493             :           " -- End nsupdate message -- \n",
     494             :           update_msg);
     495             : 
     496           9 :     ret = ERR_OK;
     497           9 :     *_update_msg = talloc_steal(mem_ctx, update_msg);
     498             : done:
     499           9 :     talloc_free(tmp_ctx);
     500           9 :     return ret;
     501             : }
     502             : 
     503             : errno_t
     504           0 : be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
     505             :                            const char *servername, const char *hostname,
     506             :                            const unsigned int ttl,
     507             :                            struct sockaddr_storage *address,
     508             :                            bool delete,
     509             :                            char **_update_msg)
     510             : {
     511             :     errno_t ret;
     512             :     char *update_msg;
     513             : 
     514             :     /* in some cases realm could have been NULL if we weren't using TSIG */
     515           0 :     if (hostname == NULL) {
     516           0 :         return EINVAL;
     517             :     }
     518             : 
     519           0 :     update_msg = nsupdate_msg_create_common(mem_ctx, realm, servername);
     520           0 :     if (update_msg == NULL) {
     521           0 :         ret = ENOMEM;
     522           0 :         goto done;
     523             :     }
     524             : 
     525           0 :     update_msg = nsupdate_msg_add_ptr(update_msg, address, hostname, ttl,
     526             :                                       delete);
     527           0 :     if (update_msg == NULL) {
     528           0 :         ret = ENOMEM;
     529           0 :         goto done;
     530             :     }
     531             : 
     532           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     533             :           " -- Begin nsupdate message -- \n"
     534             :           "%s"
     535             :           " -- End nsupdate message -- \n",
     536             :           update_msg);
     537             : 
     538           0 :     ret = ERR_OK;
     539           0 :     *_update_msg = update_msg;
     540             : 
     541             : done:
     542           0 :     return ret;
     543             : }
     544             : 
     545             : struct nsupdate_get_addrs_state {
     546             :     struct tevent_context *ev;
     547             :     struct be_resolv_ctx *be_res;
     548             :     enum host_database *db;
     549             :     const char *hostname;
     550             : 
     551             :     /* Use sss_addr in this request */
     552             :     struct sss_iface_addr *addrlist;
     553             :     size_t count;
     554             : };
     555             : 
     556             : static void nsupdate_get_addrs_done(struct tevent_req *subreq);
     557             : 
     558             : struct tevent_req *
     559           0 : nsupdate_get_addrs_send(TALLOC_CTX *mem_ctx,
     560             :                         struct tevent_context *ev,
     561             :                         struct be_resolv_ctx *be_res,
     562             :                         const char *hostname)
     563             : {
     564             :     errno_t ret;
     565             :     struct tevent_req *req;
     566             :     struct tevent_req *subreq;
     567             :     struct nsupdate_get_addrs_state *state;
     568             : 
     569           0 :     req = tevent_req_create(mem_ctx, &state, struct nsupdate_get_addrs_state);
     570           0 :     if (req == NULL) {
     571           0 :         return NULL;
     572             :     }
     573           0 :     state->be_res = be_res;
     574           0 :     state->ev = ev;
     575           0 :     state->hostname = talloc_strdup(state, hostname);
     576           0 :     if (state->hostname == NULL) {
     577           0 :         ret = ENOMEM;
     578           0 :         goto done;
     579             :     }
     580             : 
     581           0 :     state->db = talloc_array(state, enum host_database, 2);
     582           0 :     if (state->db == NULL) {
     583           0 :         ret = ENOMEM;
     584           0 :         goto done;
     585             :     }
     586           0 :     state->db[0] = DB_DNS;
     587           0 :     state->db[1] = DB_SENTINEL;
     588             : 
     589           0 :     subreq = resolv_gethostbyname_send(state, ev, be_res->resolv, hostname,
     590           0 :                                        state->be_res->family_order,
     591           0 :                                        state->db);
     592           0 :     if (subreq == NULL) {
     593           0 :         ret = ENOMEM;
     594           0 :         goto done;
     595             :     }
     596           0 :     tevent_req_set_callback(subreq, nsupdate_get_addrs_done, req);
     597             : 
     598           0 :     ret = ERR_OK;
     599             : done:
     600           0 :     if (ret != ERR_OK) {
     601           0 :         tevent_req_error(req, ret);
     602           0 :         tevent_req_post(req, ev);
     603             :     }
     604           0 :     return req;
     605             : }
     606             : 
     607             : static void
     608           0 : nsupdate_get_addrs_done(struct tevent_req *subreq)
     609             : {
     610             :     errno_t ret;
     611             :     size_t count;
     612           0 :     struct tevent_req *req =
     613           0 :             tevent_req_callback_data(subreq, struct tevent_req);
     614           0 :     struct nsupdate_get_addrs_state *state = tevent_req_data(req,
     615             :                                      struct nsupdate_get_addrs_state);
     616             :     struct resolv_hostent *rhostent;
     617             :     struct sss_iface_addr *addr;
     618             :     int i;
     619             :     int resolv_status;
     620             :     enum restrict_family retry_family_order;
     621             : 
     622           0 :     ret = resolv_gethostbyname_recv(subreq, state, &resolv_status, NULL,
     623             :                                     &rhostent);
     624           0 :     talloc_zfree(subreq);
     625             : 
     626             :     /* If the retry did not match, simply quit */
     627           0 :     if (ret == ENOENT) {
     628             :         /* If the resolver is set to honor both address families
     629             :          * it automatically retries the other one internally, so ENOENT
     630             :          * means neither matched and we can simply quit.
     631             :          */
     632           0 :         ret = EOK;
     633           0 :         goto done;
     634           0 :     } else if (ret != EOK) {
     635           0 :         DEBUG(SSSDBG_OP_FAILURE,
     636             :               "Could not resolve address for this machine, error [%d]: %s, "
     637             :                "resolver returned: [%d]: %s\n", ret, sss_strerror(ret),
     638             :                resolv_status, resolv_strerror(resolv_status));
     639           0 :         goto done;
     640             :     }
     641             : 
     642             :     /* EOK */
     643             : 
     644           0 :     if (rhostent->addr_list) {
     645           0 :         for (count=0; rhostent->addr_list[count]; count++);
     646             :     } else {
     647             :         /* The address list is NULL. This is probably a bug in
     648             :          * c-ares, but we need to handle it gracefully.
     649             :          */
     650           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     651             :               "Lookup of [%s] returned no addresses. Skipping.\n",
     652             :                rhostent->name);
     653           0 :         count = 0;
     654             :     }
     655             : 
     656           0 :     for (i=0; i < count; i++) {
     657           0 :         addr = talloc(state, struct sss_iface_addr);
     658           0 :         if (addr == NULL) {
     659           0 :             ret = ENOMEM;
     660           0 :             goto done;
     661             :         }
     662             : 
     663           0 :         addr->addr = resolv_get_sockaddr_address_index(addr, rhostent, 0, i);
     664           0 :         if (addr->addr == NULL) {
     665           0 :             ret = ENOMEM;
     666           0 :             goto done;
     667             :         }
     668             : 
     669           0 :         if (state->addrlist) {
     670           0 :             talloc_steal(state->addrlist, addr);
     671             :         }
     672             : 
     673             :         /* steal old dlist to the new head */
     674           0 :         talloc_steal(addr, state->addrlist);
     675           0 :         DLIST_ADD(state->addrlist, addr);
     676             :     }
     677           0 :     state->count += count;
     678             : 
     679             :     /* If the resolver is set to honor both address families
     680             :      * and the first one matched, retry the second one to
     681             :      * get the complete list.
     682             :      */
     683           0 :     if (((state->be_res->family_order == IPV4_FIRST &&
     684           0 :           rhostent->family == AF_INET) ||
     685           0 :         (state->be_res->family_order == IPV6_FIRST &&
     686           0 :          rhostent->family == AF_INET6))) {
     687             : 
     688           0 :         retry_family_order = (state->be_res->family_order == IPV4_FIRST) ? \
     689             :                              IPV6_ONLY : \
     690             :                              IPV4_ONLY;
     691             : 
     692           0 :         subreq = resolv_gethostbyname_send(state, state->ev,
     693           0 :                                            state->be_res->resolv,
     694             :                                            state->hostname,
     695             :                                            retry_family_order,
     696             :                                            state->db);
     697           0 :         if (!subreq) {
     698           0 :             ret = ENOMEM;
     699           0 :             goto done;
     700             :         }
     701           0 :         tevent_req_set_callback(subreq, nsupdate_get_addrs_done, req);
     702           0 :         return;
     703             :     }
     704             : 
     705             :     /* The second address matched either immediatelly or after a retry.
     706             :      * No need to retry again. */
     707           0 :     ret = EOK;
     708             : 
     709             : done:
     710           0 :     if (ret == EOK) {
     711             :         /* All done */
     712           0 :         tevent_req_done(req);
     713           0 :     } else if (ret != EAGAIN) {
     714           0 :         DEBUG(SSSDBG_OP_FAILURE,
     715             :               "nsupdate_get_addrs_done failed: [%d]: [%s]\n",
     716             :                ret, sss_strerror(ret));
     717           0 :         tevent_req_error(req, ret);
     718             :     }
     719             :     /* EAGAIN - another lookup in progress */
     720             : }
     721             : 
     722             : errno_t
     723           0 : nsupdate_get_addrs_recv(struct tevent_req *req,
     724             :                         TALLOC_CTX *mem_ctx,
     725             :                         struct sss_iface_addr **_addrlist,
     726             :                         size_t *_count)
     727             : {
     728           0 :     struct nsupdate_get_addrs_state *state = tevent_req_data(req,
     729             :                                     struct nsupdate_get_addrs_state);
     730             : 
     731           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     732             : 
     733           0 :     if (_addrlist) {
     734           0 :         *_addrlist = talloc_steal(mem_ctx, state->addrlist);
     735             :     }
     736             : 
     737           0 :     if (_count) {
     738           0 :         *_count = state->count;
     739             :     }
     740             : 
     741           0 :     return EOK;
     742             : }
     743             : 
     744             : /* Write the nsupdate_msg into the already forked child, wait until
     745             :  * the child finishes
     746             :  *
     747             :  * This is not a typical tevent_req styled request as it ends either after
     748             :  * a timeout or when the child finishes operation.
     749             :  */
     750             : struct nsupdate_child_state {
     751             :     int pipefd_to_child;
     752             :     struct tevent_timer *timeout_handler;
     753             :     struct sss_child_ctx_old *child_ctx;
     754             : 
     755             :     int child_status;
     756             : };
     757             : 
     758             : static void
     759             : nsupdate_child_timeout(struct tevent_context *ev,
     760             :                        struct tevent_timer *te,
     761             :                        struct timeval tv, void *pvt);
     762             : static void
     763             : nsupdate_child_handler(int child_status,
     764             :                        struct tevent_signal *sige,
     765             :                        void *pvt);
     766             : 
     767             : static void nsupdate_child_stdin_done(struct tevent_req *subreq);
     768             : 
     769             : static struct tevent_req *
     770           3 : nsupdate_child_send(TALLOC_CTX *mem_ctx,
     771             :                     struct tevent_context *ev,
     772             :                     int pipefd_to_child,
     773             :                     pid_t child_pid,
     774             :                     char *child_stdin)
     775             : {
     776             :     errno_t ret;
     777             :     struct tevent_req *req;
     778             :     struct tevent_req *subreq;
     779             :     struct nsupdate_child_state *state;
     780             :     struct timeval tv;
     781             : 
     782           3 :     req = tevent_req_create(mem_ctx, &state, struct nsupdate_child_state);
     783           3 :     if (req == NULL) {
     784           0 :         return NULL;
     785             :     }
     786           3 :     state->pipefd_to_child = pipefd_to_child;
     787             : 
     788             :     /* Set up SIGCHLD handler */
     789           3 :     ret = child_handler_setup(ev, child_pid, nsupdate_child_handler, req,
     790           3 :                               &state->child_ctx);
     791           3 :     if (ret != EOK) {
     792           0 :         DEBUG(SSSDBG_OP_FAILURE, "Could not set up child handlers [%d]: %s\n",
     793             :               ret, sss_strerror(ret));
     794           0 :         ret = ERR_DYNDNS_FAILED;
     795           0 :         goto done;
     796             :     }
     797             : 
     798             :     /* Set up timeout handler */
     799           3 :     tv = tevent_timeval_current_ofs(DYNDNS_TIMEOUT, 0);
     800           3 :     state->timeout_handler = tevent_add_timer(ev, req, tv,
     801             :                                               nsupdate_child_timeout, req);
     802           3 :     if(state->timeout_handler == NULL) {
     803           0 :         ret = ERR_DYNDNS_FAILED;
     804           0 :         goto done;
     805             :     }
     806             : 
     807             :     /* Write the update message to the nsupdate child */
     808           6 :     subreq = write_pipe_send(req, ev,
     809             :                              (uint8_t *) child_stdin,
     810           3 :                              strlen(child_stdin)+1,
     811           3 :                              state->pipefd_to_child);
     812           3 :     if (subreq == NULL) {
     813           0 :         ret = ERR_DYNDNS_FAILED;
     814           0 :         goto done;
     815             :     }
     816           3 :     tevent_req_set_callback(subreq, nsupdate_child_stdin_done, req);
     817             : 
     818           3 :     ret = EOK;
     819             : done:
     820           3 :     if (ret != EOK) {
     821           0 :         tevent_req_error(req, ret);
     822           0 :         tevent_req_post(req, ev);
     823             :     }
     824           3 :     return req;
     825             : }
     826             : 
     827             : static void
     828           1 : nsupdate_child_timeout(struct tevent_context *ev,
     829             :                        struct tevent_timer *te,
     830             :                        struct timeval tv, void *pvt)
     831             : {
     832           1 :     struct tevent_req *req =
     833             :             talloc_get_type(pvt, struct tevent_req);
     834           1 :     struct nsupdate_child_state *state =
     835           1 :             tevent_req_data(req, struct nsupdate_child_state);
     836             : 
     837           1 :     DEBUG(SSSDBG_CRIT_FAILURE, "Timeout reached for dynamic DNS update\n");
     838           1 :     child_handler_destroy(state->child_ctx);
     839           1 :     state->child_ctx = NULL;
     840           1 :     state->child_status = ETIMEDOUT;
     841           1 :     tevent_req_error(req, ERR_DYNDNS_TIMEOUT);
     842           1 : }
     843             : 
     844             : static void
     845           3 : nsupdate_child_stdin_done(struct tevent_req *subreq)
     846             : {
     847             :     errno_t ret;
     848           3 :     struct tevent_req *req =
     849           3 :             tevent_req_callback_data(subreq, struct tevent_req);
     850           3 :     struct nsupdate_child_state *state =
     851           3 :             tevent_req_data(req, struct nsupdate_child_state);
     852             : 
     853             :     /* Verify that the buffer was sent, then return
     854             :      * and wait for the sigchld handler to finish.
     855             :      */
     856           3 :     DEBUG(SSSDBG_TRACE_LIBS, "Sending nsupdate data complete\n");
     857             : 
     858           3 :     ret = write_pipe_recv(subreq);
     859           3 :     talloc_zfree(subreq);
     860           3 :     if (ret != EOK) {
     861           0 :         DEBUG(SSSDBG_OP_FAILURE, "Sending nsupdate data failed [%d]: %s\n",
     862             :               ret, sss_strerror(ret));
     863           0 :         tevent_req_error(req, ERR_DYNDNS_FAILED);
     864           0 :         return;
     865             :     }
     866             : 
     867           3 :     close(state->pipefd_to_child);
     868           3 :     state->pipefd_to_child = -1;
     869             : 
     870             :     /* Now either wait for the timeout to fire or the child
     871             :      * to finish
     872             :      */
     873             : }
     874             : 
     875             : static void
     876           2 : nsupdate_child_handler(int child_status,
     877             :                        struct tevent_signal *sige,
     878             :                        void *pvt)
     879             : {
     880           2 :     struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
     881           2 :     struct nsupdate_child_state *state =
     882           2 :             tevent_req_data(req, struct nsupdate_child_state);
     883             : 
     884           2 :     state->child_status = child_status;
     885             : 
     886           2 :     if (WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {
     887           1 :         DEBUG(SSSDBG_OP_FAILURE,
     888             :               "Dynamic DNS child failed with status [%d]\n", child_status);
     889           1 :         tevent_req_error(req, ERR_DYNDNS_FAILED);
     890           1 :         return;
     891             :     }
     892             : 
     893           1 :     if (WIFSIGNALED(child_status)) {
     894           0 :         DEBUG(SSSDBG_OP_FAILURE,
     895             :               "Dynamic DNS child was terminated by signal [%d]\n",
     896             :                WTERMSIG(child_status));
     897           0 :         tevent_req_error(req, ERR_DYNDNS_FAILED);
     898           0 :         return;
     899             :     }
     900             : 
     901           1 :     tevent_req_done(req);
     902             : }
     903             : 
     904             : static errno_t
     905           3 : nsupdate_child_recv(struct tevent_req *req, int *child_status)
     906             : {
     907           3 :     struct nsupdate_child_state *state =
     908           3 :             tevent_req_data(req, struct nsupdate_child_state);
     909             : 
     910           3 :     *child_status = state->child_status;
     911             : 
     912           5 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     913             : 
     914           1 :     return ERR_OK;
     915             : }
     916             : 
     917             : /* Fork a nsupdate child, write the nsupdate_msg into stdin and wait for the child
     918             :  * to finish one way or another
     919             :  */
     920             : struct be_nsupdate_state {
     921             :     int child_status;
     922             : };
     923             : 
     924             : static void be_nsupdate_done(struct tevent_req *subreq);
     925             : static char **be_nsupdate_args(TALLOC_CTX *mem_ctx,
     926             :                                enum be_nsupdate_auth auth_type,
     927             :                                bool force_tcp);
     928             : 
     929           3 : struct tevent_req *be_nsupdate_send(TALLOC_CTX *mem_ctx,
     930             :                                     struct tevent_context *ev,
     931             :                                     enum be_nsupdate_auth auth_type,
     932             :                                     char *nsupdate_msg,
     933             :                                     bool force_tcp)
     934             : {
     935             :     int pipefd_to_child[2];
     936             :     pid_t child_pid;
     937             :     errno_t ret;
     938           3 :     struct tevent_req *req = NULL;
     939           3 :     struct tevent_req *subreq = NULL;
     940             :     struct be_nsupdate_state *state;
     941             :     char **args;
     942             :     int debug_fd;
     943             : 
     944           3 :     req = tevent_req_create(mem_ctx, &state, struct be_nsupdate_state);
     945           3 :     if (req == NULL) {
     946           0 :         return NULL;
     947             :     }
     948           3 :     state->child_status = 0;
     949             : 
     950           3 :     ret = pipe(pipefd_to_child);
     951           3 :     if (ret == -1) {
     952           0 :         ret = errno;
     953           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     954             :               "pipe failed [%d][%s].\n", ret, strerror(ret));
     955           0 :         goto done;
     956             :     }
     957             : 
     958           3 :     child_pid = fork();
     959             : 
     960           6 :     if (child_pid == 0) { /* child */
     961           3 :         close(pipefd_to_child[1]);
     962           3 :         ret = dup2(pipefd_to_child[0], STDIN_FILENO);
     963           3 :         if (ret == -1) {
     964           0 :             ret = errno;
     965           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     966             :                   "dup2 failed [%d][%s].\n", ret, strerror(ret));
     967           0 :             goto done;
     968             :         }
     969             : 
     970           3 :         if (debug_level >= SSSDBG_TRACE_LIBS) {
     971           0 :             debug_fd = get_fd_from_debug_file();
     972           0 :             ret = dup2(debug_fd, STDERR_FILENO);
     973           0 :             if (ret == -1) {
     974           0 :                 ret = errno;
     975           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
     976             :                     "dup2 failed [%d][%s].\n", ret, strerror(ret));
     977             :                 /* stderr is not fatal */
     978             :             }
     979             :         }
     980             : 
     981           3 :         args = be_nsupdate_args(state, auth_type, force_tcp);
     982           3 :         if (args == NULL) {
     983           0 :             ret = ENOMEM;
     984           0 :             goto done;
     985             :         }
     986             : 
     987           3 :         errno = 0;
     988           3 :         execv(NSUPDATE_PATH, args);
     989             :         /* The child should never end up here */
     990           3 :         ret = errno;
     991           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "execv failed [%d][%s].\n", ret, strerror(ret));
     992           0 :         goto done;
     993           3 :     } else if (child_pid > 0) { /* parent */
     994           3 :         close(pipefd_to_child[0]);
     995             : 
     996           3 :         subreq = nsupdate_child_send(state, ev, pipefd_to_child[1],
     997             :                                      child_pid, nsupdate_msg);
     998           3 :         if (subreq == NULL) {
     999           0 :             ret = ERR_DYNDNS_FAILED;
    1000           0 :             goto done;
    1001             :         }
    1002           3 :         tevent_req_set_callback(subreq, be_nsupdate_done, req);
    1003             :     } else { /* error */
    1004           0 :         ret = errno;
    1005           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1006             :               "fork failed [%d][%s].\n", ret, strerror(ret));
    1007           0 :         goto done;
    1008             :     }
    1009             : 
    1010           3 :     ret = EOK;
    1011             : done:
    1012           3 :     if (ret != EOK) {
    1013           0 :         tevent_req_error(req, ret);
    1014           0 :         tevent_req_post(req, ev);
    1015             :     }
    1016           3 :     return req;
    1017             : }
    1018             : 
    1019             : static char **
    1020           3 : be_nsupdate_args(TALLOC_CTX *mem_ctx,
    1021             :                  enum be_nsupdate_auth auth_type,
    1022             :                  bool force_tcp)
    1023             : {
    1024             :     char **argv;
    1025           3 :     int argc = 0;
    1026             : 
    1027           3 :     argv = talloc_zero_array(mem_ctx, char *, 6);
    1028           3 :     if (argv == NULL) {
    1029           0 :         return NULL;
    1030             :     }
    1031             : 
    1032           3 :     argv[argc] = talloc_strdup(argv, NSUPDATE_PATH);
    1033           3 :     if (argv[argc] == NULL) {
    1034           0 :         goto fail;
    1035             :     }
    1036           3 :     argc++;
    1037             : 
    1038           3 :     switch (auth_type) {
    1039             :     case BE_NSUPDATE_AUTH_NONE:
    1040           0 :         DEBUG(SSSDBG_FUNC_DATA, "nsupdate auth type: none\n");
    1041           0 :         break;
    1042             :     case BE_NSUPDATE_AUTH_GSS_TSIG:
    1043           3 :         DEBUG(SSSDBG_FUNC_DATA, "nsupdate auth type: GSS-TSIG\n");
    1044           3 :         argv[argc] = talloc_strdup(argv, "-g");
    1045           3 :         if (argv[argc] == NULL) {
    1046           0 :             goto fail;
    1047             :         }
    1048           3 :         argc++;
    1049           3 :         break;
    1050             :     default:
    1051           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unknown nsupdate auth type\n");
    1052           0 :         goto fail;
    1053             :     }
    1054             : 
    1055           3 :     if (force_tcp) {
    1056           0 :         DEBUG(SSSDBG_FUNC_DATA, "TCP is set to on\n");
    1057           0 :         argv[argc] = talloc_strdup(argv, "-v");
    1058           0 :         if (argv[argc] == NULL) {
    1059           0 :             goto fail;
    1060             :         }
    1061           0 :         argc++;
    1062             :     }
    1063             : 
    1064           3 :     if (debug_level >= SSSDBG_TRACE_LIBS) {
    1065           0 :         argv[argc] = talloc_strdup(argv, "-d");
    1066           0 :         if (argv[argc] == NULL) {
    1067           0 :             goto fail;
    1068             :         }
    1069           0 :         argc++;
    1070             :     }
    1071             : 
    1072           3 :     if (debug_level >= SSSDBG_TRACE_INTERNAL) {
    1073           0 :         argv[argc] = talloc_strdup(argv, "-D");
    1074           0 :         if (argv[argc] == NULL) {
    1075           0 :             goto fail;
    1076             :         }
    1077           0 :         argc++;
    1078             :     }
    1079             : 
    1080           3 :     return argv;
    1081             : 
    1082             : fail:
    1083           0 :     talloc_free(argv);
    1084           0 :     return NULL;
    1085             : }
    1086             : 
    1087             : static void
    1088           3 : be_nsupdate_done(struct tevent_req *subreq)
    1089             : {
    1090           3 :     struct tevent_req *req =
    1091           3 :             tevent_req_callback_data(subreq, struct tevent_req);
    1092           3 :     struct be_nsupdate_state *state =
    1093           3 :             tevent_req_data(req, struct be_nsupdate_state);
    1094             :     errno_t ret;
    1095             : 
    1096           3 :     ret = nsupdate_child_recv(subreq, &state->child_status);
    1097           3 :     talloc_zfree(subreq);
    1098           3 :     if (ret != EOK) {
    1099           2 :         DEBUG(SSSDBG_OP_FAILURE, "nsupdate child execution failed [%d]: %s\n",
    1100             :               ret, sss_strerror(ret));
    1101           2 :         tevent_req_error(req, ret);
    1102           2 :         return;
    1103             :     }
    1104             : 
    1105           1 :     DEBUG(SSSDBG_FUNC_DATA,
    1106             :            "nsupdate child status: %d\n", state->child_status);
    1107           1 :     tevent_req_done(req);
    1108             : }
    1109             : 
    1110             : errno_t
    1111           3 : be_nsupdate_recv(struct tevent_req *req, int *child_status)
    1112             : {
    1113           3 :     struct be_nsupdate_state *state =
    1114           3 :             tevent_req_data(req, struct be_nsupdate_state);
    1115             : 
    1116           3 :     *child_status = state->child_status;
    1117             : 
    1118           5 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1119             : 
    1120           1 :     return EOK;
    1121             : }
    1122             : 
    1123           2 : static void be_nsupdate_timer(struct tevent_context *ev,
    1124             :                               struct tevent_timer *te,
    1125             :                               struct timeval current_time,
    1126             :                               void *pvt)
    1127             : {
    1128           2 :     struct be_nsupdate_ctx *ctx = talloc_get_type(pvt, struct be_nsupdate_ctx);
    1129             : 
    1130           2 :     talloc_zfree(ctx->refresh_timer);
    1131           2 :     ctx->timer_callback(ctx->timer_pvt);
    1132             : 
    1133             :     /* timer_callback is responsible for calling be_nsupdate_timer_schedule
    1134             :      * again */
    1135           2 : }
    1136             : 
    1137           2 : void be_nsupdate_timer_schedule(struct tevent_context *ev,
    1138             :                                 struct be_nsupdate_ctx *ctx)
    1139             : {
    1140             :     int refresh;
    1141             :     struct timeval tv;
    1142             : 
    1143           2 :     if (ctx->refresh_timer) {
    1144           0 :         DEBUG(SSSDBG_FUNC_DATA, "Timer already scheduled\n");
    1145           0 :         return;
    1146             :     }
    1147             : 
    1148           2 :     refresh = dp_opt_get_int(ctx->opts, DP_OPT_DYNDNS_REFRESH_INTERVAL);
    1149           2 :     if (refresh == 0) return;
    1150           2 :     DEBUG(SSSDBG_FUNC_DATA, "Scheduling timer in %d seconds\n", refresh);
    1151             : 
    1152           2 :     tv = tevent_timeval_current_ofs(refresh, 0);
    1153           2 :     ctx->refresh_timer = tevent_add_timer(ev, ctx, tv,
    1154             :                                           be_nsupdate_timer, ctx);
    1155             : 
    1156           2 :     if (!ctx->refresh_timer) {
    1157           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1158             :                 "Failed to add dyndns refresh timer event\n");
    1159             :     }
    1160             : }
    1161             : 
    1162             : errno_t
    1163           0 : be_nsupdate_check(void)
    1164             : {
    1165             :     errno_t ret;
    1166             :     struct stat stat_buf;
    1167             : 
    1168             :     /* Ensure that nsupdate exists */
    1169           0 :     errno = 0;
    1170           0 :     ret = stat(NSUPDATE_PATH, &stat_buf);
    1171           0 :     if (ret == -1) {
    1172           0 :         ret = errno;
    1173           0 :         if (ret == ENOENT) {
    1174           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    1175             :                   "%s does not exist. Dynamic DNS updates disabled\n",
    1176             :                   NSUPDATE_PATH);
    1177             :         } else {
    1178           0 :             DEBUG(SSSDBG_OP_FAILURE,
    1179             :                   "Could not set up dynamic DNS updates: [%d][%s]\n",
    1180             :                   ret, strerror(ret));
    1181             :         }
    1182             :     }
    1183             : 
    1184           0 :     return ret;
    1185             : }
    1186             : 
    1187             : static struct dp_option default_dyndns_opts[] = {
    1188             :     { "dyndns_update", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
    1189             :     { "dyndns_refresh_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER },
    1190             :     { "dyndns_iface", DP_OPT_STRING, NULL_STRING, NULL_STRING },
    1191             :     { "dyndns_ttl", DP_OPT_NUMBER, { .number = 1200 }, NULL_NUMBER },
    1192             :     { "dyndns_update_ptr", DP_OPT_BOOL, BOOL_TRUE, BOOL_FALSE },
    1193             :     { "dyndns_force_tcp", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
    1194             :     { "dyndns_auth", DP_OPT_STRING, { "gss-tsig" }, NULL_STRING },
    1195             :     { "dyndns_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
    1196             : 
    1197             :     DP_OPTION_TERMINATOR
    1198             : };
    1199             : 
    1200             : errno_t
    1201           1 : be_nsupdate_init(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx,
    1202             :                  struct dp_option *defopts,
    1203             :                  struct be_nsupdate_ctx **_ctx)
    1204             : {
    1205             :     errno_t ret;
    1206             :     struct dp_option *src_opts;
    1207             :     struct be_nsupdate_ctx *ctx;
    1208             :     char *strauth;
    1209             : 
    1210           1 :     ctx = talloc_zero(mem_ctx, struct be_nsupdate_ctx);
    1211           1 :     if (ctx == NULL) return ENOMEM;
    1212             : 
    1213           1 :     src_opts = defopts ? defopts : default_dyndns_opts;
    1214             : 
    1215           1 :     ret = dp_get_options(ctx, be_ctx->cdb, be_ctx->conf_path,
    1216             :                          src_opts, DP_OPT_DYNDNS, &ctx->opts);
    1217           1 :     if (ret != EOK) {
    1218           0 :         DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve dynamic DNS options\n");
    1219           0 :         return ret;
    1220             :     }
    1221             : 
    1222           1 :     strauth = dp_opt_get_string(ctx->opts, DP_OPT_DYNDNS_AUTH);
    1223           1 :     if (strcasecmp(strauth, "gss-tsig") == 0) {
    1224           1 :         ctx->auth_type = BE_NSUPDATE_AUTH_GSS_TSIG;
    1225           0 :     } else if (strcasecmp(strauth, "none") == 0) {
    1226           0 :         ctx->auth_type = BE_NSUPDATE_AUTH_NONE;
    1227             :     } else {
    1228           0 :         DEBUG(SSSDBG_OP_FAILURE, "Uknown dyndns auth type %s\n", strauth);
    1229           0 :         return EINVAL;
    1230             :     }
    1231             : 
    1232           1 :     *_ctx = ctx;
    1233           1 :     return ERR_OK;
    1234             : }
    1235             : 
    1236           1 : errno_t be_nsupdate_init_timer(struct be_nsupdate_ctx *ctx,
    1237             :                                struct tevent_context *ev,
    1238             :                                nsupdate_timer_fn_t timer_callback,
    1239             :                                void *timer_pvt)
    1240             : {
    1241           1 :     if (ctx == NULL) return EINVAL;
    1242             : 
    1243           1 :     ctx->timer_callback = timer_callback;
    1244           1 :     ctx->timer_pvt = timer_pvt;
    1245           1 :     be_nsupdate_timer_schedule(ev, ctx);
    1246             : 
    1247           1 :     return ERR_OK;
    1248             : }
    1249             : 
    1250          10 : static bool match_ip(const struct sockaddr *sa,
    1251             :                      const struct sockaddr *sb)
    1252             : {
    1253             :     size_t addrsize;
    1254             :     bool res;
    1255             :     const void *addr_a;
    1256             :     const void *addr_b;
    1257             : 
    1258          10 :     if (sa->sa_family == AF_INET) {
    1259           9 :         addrsize = sizeof(struct in_addr);
    1260           9 :         addr_a = (const void *) &((const struct sockaddr_in *) sa)->sin_addr;
    1261           9 :         addr_b = (const void *) &((const struct sockaddr_in *) sb)->sin_addr;
    1262           1 :     } else if (sa->sa_family == AF_INET6) {
    1263           1 :         addrsize = sizeof(struct in6_addr);
    1264           1 :         addr_a = (const void *) &((const struct sockaddr_in6 *) sa)->sin6_addr;
    1265           1 :         addr_b = (const void *) &((const struct sockaddr_in6 *) sb)->sin6_addr;
    1266             :     } else {
    1267           0 :         res = false;
    1268           0 :         goto done;
    1269             :     }
    1270             : 
    1271          10 :     if (sa->sa_family != sb->sa_family) {
    1272           2 :         res = false;
    1273           2 :         goto done;
    1274             :     }
    1275             : 
    1276           8 :     res = memcmp(addr_a, addr_b, addrsize) == 0;
    1277             : 
    1278             : done:
    1279          10 :     return res;
    1280             : }
    1281             : 
    1282           7 : static errno_t find_iface_by_addr(TALLOC_CTX *mem_ctx,
    1283             :                                   const struct sockaddr *ss,
    1284             :                                   const char **_iface_name)
    1285             : {
    1286           7 :     struct ifaddrs *ifaces = NULL;
    1287             :     struct ifaddrs *ifa;
    1288             :     errno_t ret;
    1289             : 
    1290           7 :     ret = getifaddrs(&ifaces);
    1291           7 :     if (ret == -1) {
    1292           0 :         ret = errno;
    1293           0 :         DEBUG(SSSDBG_OP_FAILURE,
    1294             :               "Could not read interfaces [%d][%s]\n", ret, sss_strerror(ret));
    1295           0 :         goto done;
    1296             :     }
    1297             : 
    1298          11 :     for (ifa = ifaces; ifa != NULL; ifa = ifa->ifa_next) {
    1299             : 
    1300             :         /* Some interfaces don't have an ifa_addr */
    1301          10 :         if (!ifa->ifa_addr) continue;
    1302             : 
    1303          10 :         if (match_ip(ss, ifa->ifa_addr)) {
    1304             :             const char *iface_name;
    1305           6 :             iface_name = talloc_strdup(mem_ctx, ifa->ifa_name);
    1306           6 :             if (iface_name == NULL) {
    1307           0 :                 ret = ENOMEM;
    1308             :             } else {
    1309           6 :                 *_iface_name = iface_name;
    1310           6 :                 ret = EOK;
    1311             :             }
    1312           6 :             goto done;
    1313             :         }
    1314             :     }
    1315           1 :     ret = ENOENT;
    1316             : 
    1317             : done:
    1318           7 :     freeifaddrs(ifaces);
    1319           7 :     return ret;
    1320             : }
    1321             : 
    1322           7 : errno_t sss_get_dualstack_addresses(TALLOC_CTX *mem_ctx,
    1323             :                                     struct sockaddr *ss,
    1324             :                                     struct sss_iface_addr **_iface_addrs)
    1325             : {
    1326             :     struct sss_iface_addr *iface_addrs;
    1327           7 :     const char *iface_name = NULL;
    1328             :     TALLOC_CTX *tmp_ctx;
    1329             :     errno_t ret;
    1330             : 
    1331           7 :     tmp_ctx = talloc_new(NULL);
    1332           7 :     if (tmp_ctx == NULL) {
    1333           0 :         ret = ENOMEM;
    1334           0 :         goto done;
    1335             :     }
    1336             : 
    1337           7 :     ret = find_iface_by_addr(tmp_ctx, ss, &iface_name);
    1338           7 :     if (ret != EOK) {
    1339           1 :         DEBUG(SSSDBG_MINOR_FAILURE, "find_iface_by_addr failed: %d:[%s]\n",
    1340             :               ret, sss_strerror(ret));
    1341           1 :         goto done;
    1342             :     }
    1343             : 
    1344           6 :     ret = sss_iface_addr_list_get(tmp_ctx, iface_name, &iface_addrs);
    1345           6 :     if (ret != EOK) {
    1346           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1347             :               "sss_iface_addr_list_get failed: %d:[%s]\n",
    1348             :               ret, sss_strerror(ret));
    1349           0 :         goto done;
    1350             :     }
    1351             : 
    1352           6 :     ret = EOK;
    1353           6 :     *_iface_addrs = talloc_steal(mem_ctx, iface_addrs);
    1354             : 
    1355             : done:
    1356           7 :     talloc_free(tmp_ctx);
    1357           7 :     return ret;
    1358             : }

Generated by: LCOV version 1.10