LCOV - code coverage report
Current view: top level - providers/ldap - sdap_async_sudo_hostinfo.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 241 0.0 %
Date: 2016-06-29 Functions: 0 7 0.0 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Pavel Březina <pbrezina@redhat.com>
       4             : 
       5             :     Copyright (C) 2012 Red Hat
       6             : 
       7             :     This program is free software; you can redistribute it and/or modify
       8             :     it under the terms of the GNU General Public License as published by
       9             :     the Free Software Foundation; either version 3 of the License, or
      10             :     (at your option) any later version.
      11             : 
      12             :     This program is distributed in the hope that it will be useful,
      13             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :     GNU General Public License for more details.
      16             : 
      17             :     You should have received a copy of the GNU General Public License
      18             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include <errno.h>
      22             : #include <tevent.h>
      23             : #include <talloc.h>
      24             : #include <sys/types.h>
      25             : #include <sys/socket.h>
      26             : #include <arpa/inet.h>
      27             : #include <ifaddrs.h>
      28             : #include <unistd.h>
      29             : #include <limits.h>
      30             : #include <string.h>
      31             : 
      32             : #include "util/util.h"
      33             : #include "providers/ldap/sdap.h"
      34             : #include "providers/ldap/sdap_id_op.h"
      35             : #include "providers/ldap/sdap_sudo.h"
      36             : #include "resolv/async_resolv.h"
      37             : 
      38             : static int sdap_sudo_get_ip_addresses(TALLOC_CTX *mem_ctx, char ***_ip_addr);
      39             : 
      40             : struct sdap_sudo_get_hostinfo_state {
      41             :     char **hostnames;
      42             :     char **ip_addr;
      43             : };
      44             : 
      45             : struct sdap_sudo_get_hostnames_state {
      46             :     struct tevent_context *ev;
      47             :     struct resolv_ctx *resolv_ctx;
      48             :     enum host_database *host_db;
      49             :     enum restrict_family family_order;
      50             :     char **hostnames;
      51             : };
      52             : 
      53             : static void sdap_sudo_get_hostinfo_done(struct tevent_req *req);
      54             : 
      55             : static struct tevent_req *sdap_sudo_get_hostnames_send(TALLOC_CTX *mem_ctx,
      56             :                                                        struct be_ctx *be_ctx);
      57             : 
      58             : static void sdap_sudo_get_hostnames_done(struct tevent_req *subreq);
      59             : 
      60             : static int sdap_sudo_get_hostnames_recv(TALLOC_CTX *mem_ctx,
      61             :                                         struct tevent_req *req,
      62             :                                         char ***hostnames);
      63             : 
      64             : 
      65           0 : struct tevent_req * sdap_sudo_get_hostinfo_send(TALLOC_CTX *mem_ctx,
      66             :                                                 struct sdap_options *opts,
      67             :                                                 struct be_ctx *be_ctx)
      68             : {
      69           0 :     struct tevent_req *req = NULL;
      70           0 :     struct tevent_req *subreq = NULL;
      71           0 :     struct sdap_sudo_get_hostinfo_state *state = NULL;
      72           0 :     char *conf_hostnames = NULL;
      73           0 :     char *conf_ip_addr = NULL;
      74           0 :     int ret = EOK;
      75             : 
      76             :     /* create request */
      77           0 :     req = tevent_req_create(mem_ctx, &state,
      78             :                             struct sdap_sudo_get_hostinfo_state);
      79           0 :     if (req == NULL) {
      80           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "tevent_req_create() failed\n");
      81           0 :         return NULL;
      82             :     }
      83             : 
      84           0 :     state->hostnames = NULL;
      85           0 :     state->ip_addr = NULL;
      86             : 
      87             :     /* load info from configuration */
      88           0 :     conf_hostnames = dp_opt_get_string(opts->basic, SDAP_SUDO_HOSTNAMES);
      89           0 :     conf_ip_addr = dp_opt_get_string(opts->basic, SDAP_SUDO_IP);
      90             : 
      91           0 :     if (conf_hostnames != NULL) {
      92           0 :         ret = split_on_separator(state, conf_hostnames, ' ', true, true,
      93           0 :                                  &state->hostnames, NULL);
      94           0 :         if (ret != EOK) {
      95           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
      96             :                   "Unable to parse hostnames [%d]: %s\n", ret, strerror(ret));
      97           0 :             goto done;
      98             :         } else {
      99           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
     100             :                   "Hostnames set to: %s\n", conf_hostnames);
     101             :         }
     102             :     }
     103             : 
     104           0 :     if (conf_ip_addr != NULL) {
     105           0 :         ret = split_on_separator(state, conf_ip_addr, ' ', true, true,
     106           0 :                                  &state->ip_addr, NULL);
     107           0 :         if (ret != EOK) {
     108           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     109             :                   "Unable to parse IP addresses [%d]: %s\n",
     110             :                    ret, strerror(ret));
     111           0 :             goto done;
     112             :         } else {
     113           0 :             DEBUG(SSSDBG_CONF_SETTINGS, "IP addresses set to: %s\n",
     114             :                   conf_ip_addr);
     115             :         }
     116             :     }
     117             : 
     118             :     /* if IP addresses are not specified, configure it automatically */
     119           0 :     if (state->ip_addr == NULL) {
     120           0 :         ret = sdap_sudo_get_ip_addresses(state, &state->ip_addr);
     121           0 :         if (ret != EOK) {
     122           0 :             DEBUG(SSSDBG_OP_FAILURE,
     123             :                   "Unable to detect IP addresses [%d]: %s\n",
     124             :                    ret, strerror(ret));
     125             :         }
     126             :     }
     127             : 
     128             :     /* if hostnames are not specified, configure it automatically */
     129           0 :     if (state->hostnames == NULL) {
     130           0 :         subreq = sdap_sudo_get_hostnames_send(state, be_ctx);
     131           0 :         if (subreq == NULL) {
     132           0 :             ret = ENOMEM;
     133           0 :             goto done;
     134             :         }
     135             : 
     136           0 :         tevent_req_set_callback(subreq, sdap_sudo_get_hostinfo_done, req);
     137           0 :         ret = EAGAIN;
     138             :     }
     139             : 
     140             : done:
     141           0 :     if (ret != EAGAIN) {
     142           0 :         if (ret == EOK) {
     143           0 :             tevent_req_done(req);
     144             :         } else {
     145           0 :             tevent_req_error(req, ret);
     146             :         }
     147           0 :         tevent_req_post(req, be_ctx->ev);
     148             :     }
     149             : 
     150           0 :     return req;
     151             : }
     152             : 
     153           0 : static void sdap_sudo_get_hostinfo_done(struct tevent_req *subreq)
     154             : {
     155           0 :     struct tevent_req *req = NULL;
     156           0 :     struct sdap_sudo_get_hostinfo_state *state = NULL;
     157             :     int ret;
     158             : 
     159           0 :     req = tevent_req_callback_data(subreq, struct tevent_req);
     160           0 :     state = tevent_req_data(req, struct sdap_sudo_get_hostinfo_state);
     161             : 
     162           0 :     ret = sdap_sudo_get_hostnames_recv(state, subreq, &state->hostnames);
     163           0 :     talloc_zfree(subreq);
     164           0 :     if (ret != EOK) {
     165           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to retrieve hostnames [%d]: %s\n",
     166             :                                     ret, strerror(ret));
     167           0 :         tevent_req_error(req, ret);
     168           0 :         return;
     169             :     }
     170             : 
     171           0 :     tevent_req_done(req);
     172             : }
     173             : 
     174           0 : int sdap_sudo_get_hostinfo_recv(TALLOC_CTX *mem_ctx,
     175             :                                 struct tevent_req *req,
     176             :                                 char ***hostnames, char ***ip_addr)
     177             : {
     178           0 :     struct sdap_sudo_get_hostinfo_state *state = NULL;
     179           0 :     state = tevent_req_data(req, struct sdap_sudo_get_hostinfo_state);
     180             : 
     181           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     182             : 
     183           0 :     *hostnames = talloc_steal(mem_ctx, state->hostnames);
     184           0 :     *ip_addr = talloc_steal(mem_ctx, state->ip_addr);
     185             : 
     186           0 :     return EOK;
     187             : }
     188             : 
     189           0 : static int sdap_sudo_get_ip_addresses(TALLOC_CTX *mem_ctx,
     190             :                                       char ***_ip_addr_list)
     191             : {
     192           0 :     TALLOC_CTX *tmp_ctx = NULL;
     193           0 :     char **ip_addr_list = NULL;
     194           0 :     struct ifaddrs *ifaces = NULL;
     195           0 :     struct ifaddrs *iface = NULL;
     196             :     struct sockaddr_in ip4_addr;
     197             :     struct sockaddr_in ip4_network;
     198             :     struct sockaddr_in6 ip6_addr;
     199             :     struct sockaddr_in6 ip6_network;
     200             :     char ip_addr[INET6_ADDRSTRLEN + 1];
     201             :     char network_addr[INET6_ADDRSTRLEN + 1];
     202           0 :     in_addr_t ip4_netmask = 0;
     203           0 :     uint32_t ip6_netmask = 0;
     204           0 :     unsigned int netmask = 0;
     205           0 :     void *sinx_addr = NULL;
     206           0 :     void *sinx_network = NULL;
     207           0 :     int addr_count = 0;
     208             :     int ret;
     209             :     int i;
     210             : 
     211           0 :     tmp_ctx = talloc_new(NULL);
     212           0 :     if (tmp_ctx == NULL) {
     213           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
     214           0 :         return ENOMEM;
     215             :     }
     216             : 
     217           0 :     errno = 0;
     218           0 :     ret = getifaddrs(&ifaces);
     219           0 :     if (ret == -1) {
     220           0 :         ret = errno;
     221           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not read interfaces [%d][%s]\n",
     222             :                                     ret, strerror(ret));
     223           0 :         goto done;
     224             :     }
     225             : 
     226           0 :     for (iface = ifaces; iface != NULL; iface = iface->ifa_next) {
     227             :         /* Some interfaces don't have an ifa_addr */
     228           0 :         if (!iface->ifa_addr) continue;
     229             : 
     230           0 :         netmask = 0;
     231           0 :         switch (iface->ifa_addr->sa_family) {
     232             :         case AF_INET:
     233           0 :             memcpy(&ip4_addr, iface->ifa_addr, sizeof(struct sockaddr_in));
     234           0 :             memcpy(&ip4_network, iface->ifa_netmask, sizeof(struct sockaddr_in));
     235             : 
     236           0 :             if (!check_ipv4_addr(&ip4_addr.sin_addr,
     237             :                                   SSS_NO_LOOPBACK|SSS_NO_MULTICAST
     238             :                                   |SSS_NO_BROADCAST)) {
     239           0 :                 continue;
     240             :             }
     241             : 
     242             :             /* get network mask length */
     243           0 :             ip4_netmask = ntohl(ip4_network.sin_addr.s_addr);
     244           0 :             while (ip4_netmask) {
     245           0 :                 netmask++;
     246           0 :                 ip4_netmask <<= 1;
     247             :             }
     248             : 
     249             :             /* get network address */
     250           0 :             ip4_network.sin_addr.s_addr = ip4_addr.sin_addr.s_addr
     251           0 :                                            & ip4_network.sin_addr.s_addr;
     252             : 
     253           0 :             sinx_addr = &ip4_addr.sin_addr;
     254           0 :             sinx_network = &ip4_network.sin_addr;
     255           0 :             break;
     256             :         case AF_INET6:
     257           0 :             memcpy(&ip6_addr, iface->ifa_addr, sizeof(struct sockaddr_in6));
     258           0 :             memcpy(&ip6_network, iface->ifa_netmask, sizeof(struct sockaddr_in6));
     259             : 
     260           0 :             if (!check_ipv6_addr(&ip6_addr.sin6_addr,
     261             :                                   SSS_NO_LOOPBACK|SSS_NO_MULTICAST)) {
     262           0 :                 continue;
     263             :             }
     264             : 
     265             :             /* get network mask length */
     266           0 :             for (i = 0; i < 4; i++) {
     267           0 :                 ip6_netmask = ntohl(((uint32_t*)(&ip6_network.sin6_addr))[i]);
     268           0 :                 while (ip6_netmask) {
     269           0 :                     netmask++;
     270           0 :                     ip6_netmask <<= 1;
     271             :                 }
     272             :             }
     273             : 
     274             :             /* get network address */
     275           0 :             for (i = 0; i < 4; i++) {
     276           0 :                 ((uint32_t*)(&ip6_network.sin6_addr))[i] =
     277           0 :                           ((uint32_t*)(&ip6_addr.sin6_addr))[i]
     278           0 :                         & ((uint32_t*)(&ip6_network.sin6_addr))[i];
     279             :             }
     280             : 
     281           0 :             sinx_addr = &ip6_addr.sin6_addr;
     282           0 :             sinx_network = &ip6_network.sin6_addr;
     283           0 :             break;
     284             :         default:
     285             :             /* skip other families */
     286           0 :             continue;
     287             :         }
     288             : 
     289             :         /* ip address */
     290           0 :         errno = 0;
     291           0 :         if (inet_ntop(iface->ifa_addr->sa_family, sinx_addr,
     292             :                       ip_addr, INET6_ADDRSTRLEN) == NULL) {
     293           0 :             ret = errno;
     294           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "inet_ntop() failed [%d]: %s\n",
     295             :                                          ret, strerror(ret));
     296           0 :             goto done;
     297             :         }
     298             : 
     299             :         /* network */
     300           0 :         errno = 0;
     301           0 :         if (inet_ntop(iface->ifa_addr->sa_family, sinx_network,
     302             :                       network_addr, INET6_ADDRSTRLEN) == NULL) {
     303           0 :             ret = errno;
     304           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "inet_ntop() failed [%d]: %s\n",
     305             :                                          ret, strerror(ret));
     306           0 :             goto done;
     307             :         }
     308             : 
     309           0 :         addr_count += 2;
     310           0 :         ip_addr_list = talloc_realloc(tmp_ctx, ip_addr_list, char*,
     311             :                                       addr_count + 1);
     312           0 :         if (ip_addr_list == NULL) {
     313           0 :             ret = ENOMEM;
     314           0 :             goto done;
     315             :         }
     316             : 
     317           0 :         ip_addr_list[addr_count - 2] = talloc_strdup(ip_addr_list, ip_addr);
     318           0 :         if (ip_addr_list[addr_count - 2] == NULL) {
     319           0 :             ret = ENOMEM;
     320           0 :             goto done;
     321             :         }
     322             : 
     323           0 :         ip_addr_list[addr_count - 1] = talloc_asprintf(ip_addr_list, "%s/%d",
     324             :                                                        network_addr, netmask);
     325           0 :         if (ip_addr_list[addr_count - 1] == NULL) {
     326           0 :             ret = ENOMEM;
     327           0 :             goto done;
     328             :         }
     329             : 
     330           0 :         DEBUG(SSSDBG_TRACE_INTERNAL,
     331             :               "Found IP address: %s in network %s/%d\n",
     332             :                ip_addr, network_addr, netmask);
     333             :     }
     334             : 
     335           0 :     if (ip_addr_list) {
     336           0 :         ip_addr_list[addr_count] = NULL;
     337             :     }
     338           0 :     *_ip_addr_list = talloc_steal(mem_ctx, ip_addr_list);
     339             : 
     340             : done:
     341           0 :     freeifaddrs(ifaces);
     342           0 :     talloc_free(tmp_ctx);
     343             : 
     344           0 :     return ret;
     345             : }
     346             : 
     347             : /*
     348             :  * SUDO allows only one hostname that is returned from gethostname()
     349             :  * (and set to "localhost" if the returned value is empty)
     350             :  * and then - if allowed - resolves its fqdn using gethostbyname() or
     351             :  * getaddrinfo() if available.
     352             :  */
     353           0 : static struct tevent_req *sdap_sudo_get_hostnames_send(TALLOC_CTX *mem_ctx,
     354             :                                                        struct be_ctx *be_ctx)
     355             : {
     356           0 :     struct tevent_req *req = NULL;
     357           0 :     struct tevent_req *subreq = NULL;
     358           0 :     struct sdap_sudo_get_hostnames_state *state = NULL;
     359           0 :     char *dot = NULL;
     360             :     char hostname[HOST_NAME_MAX + 1];
     361             :     int ret;
     362             : 
     363           0 :     req = tevent_req_create(mem_ctx, &state,
     364             :                             struct sdap_sudo_get_hostnames_state);
     365           0 :     if (req == NULL) {
     366           0 :         return NULL;
     367             :     }
     368             : 
     369           0 :     state->ev = be_ctx->ev;
     370           0 :     state->hostnames = NULL;
     371             : 
     372             :     /* hostname, fqdn and NULL */
     373           0 :     state->hostnames = talloc_zero_array(state, char*, 3);
     374           0 :     if (state->hostnames == NULL) {
     375           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n");
     376           0 :         ret = ENOMEM;
     377           0 :         goto done;
     378             :     }
     379             : 
     380             :     /* get hostname */
     381             : 
     382           0 :     errno = 0;
     383           0 :     ret = gethostname(hostname, HOST_NAME_MAX);
     384           0 :     if (ret != EOK) {
     385           0 :         ret = errno;
     386           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to retrieve machine hostname "
     387             :                                     "[%d]: %s\n", ret, strerror(ret));
     388           0 :         goto done;
     389             :     }
     390           0 :     hostname[HOST_NAME_MAX] = '\0';
     391             : 
     392           0 :     state->hostnames[0] = talloc_strdup(state->hostnames, hostname);
     393           0 :     if (state->hostnames[0] == NULL) {
     394           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
     395           0 :         ret = ENOMEM;
     396           0 :         goto done;
     397             :     }
     398             : 
     399           0 :     dot = strchr(hostname, '.');
     400           0 :     if (dot != NULL) {
     401             :         /* already a fqdn, determine hostname and finish */
     402           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Found fqdn: %s\n", hostname);
     403             : 
     404           0 :         *dot = '\0';
     405           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Found hostname: %s\n", hostname);
     406             : 
     407           0 :         state->hostnames[1] = talloc_strdup(state->hostnames, hostname);
     408           0 :         if (state->hostnames[1] == NULL) {
     409           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
     410           0 :             ret = ENOMEM;
     411           0 :             goto done;
     412             :         }
     413             : 
     414           0 :         ret = EOK;
     415           0 :         goto done;
     416             :     } else {
     417           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Found hostname: %s\n", hostname);
     418             :     }
     419             : 
     420           0 :     state->resolv_ctx = be_ctx->be_res->resolv;
     421           0 :     state->host_db = default_host_dbs;
     422             : 
     423             :     /* get fqdn */
     424           0 :     subreq = resolv_gethostbyname_send(state, state->ev, state->resolv_ctx,
     425           0 :                                        hostname, be_ctx->be_res->family_order,
     426           0 :                                        state->host_db);
     427           0 :     if (subreq == NULL) {
     428           0 :         ret = ENOMEM;
     429           0 :         goto done;
     430             :     }
     431             : 
     432           0 :     tevent_req_set_callback(subreq, sdap_sudo_get_hostnames_done, req);
     433             : 
     434           0 :     ret = EAGAIN;
     435             : 
     436             : done:
     437           0 :     if (ret != EAGAIN) {
     438           0 :         if (ret == EOK) {
     439           0 :             tevent_req_done(req);
     440             :         } else {
     441           0 :             tevent_req_error(req, ret);
     442             :         }
     443           0 :         tevent_req_post(req, be_ctx->ev);
     444             :     }
     445             : 
     446           0 :     return req;
     447             : }
     448             : 
     449           0 : static void sdap_sudo_get_hostnames_done(struct tevent_req *subreq)
     450             : {
     451           0 :     struct tevent_req *req = NULL;
     452           0 :     struct sdap_sudo_get_hostnames_state *state = NULL;
     453           0 :     struct resolv_hostent *rhostent = NULL;
     454             :     int resolv_status;
     455             :     int ret;
     456             : 
     457           0 :     req = tevent_req_callback_data(subreq, struct tevent_req);
     458           0 :     state = tevent_req_data(req, struct sdap_sudo_get_hostnames_state);
     459             : 
     460           0 :     ret = resolv_gethostbyname_recv(subreq, state, &resolv_status, NULL,
     461             :                                     &rhostent);
     462           0 :     talloc_zfree(subreq);
     463           0 :     if (ret == ENOENT) {
     464             :         /* Empty result, just quit */
     465           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "No hostent found\n");
     466           0 :         goto done;
     467           0 :     } else if (ret != EOK) {
     468           0 :         DEBUG(SSSDBG_OP_FAILURE,
     469             :               "Could not resolve fqdn for this machine, error [%d]: %s, "
     470             :                "resolver returned: [%d]: %s\n", ret, strerror(ret),
     471             :                resolv_status, resolv_strerror(resolv_status));
     472           0 :         tevent_req_error(req, ret);
     473           0 :         return;
     474             :     }
     475             : 
     476             :     /* EOK */
     477             : 
     478           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Found fqdn: %s\n", rhostent->name);
     479             : 
     480           0 :     if (state->hostnames == NULL) {
     481           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "state->hostnames is NULL\n");
     482           0 :         ret = EINVAL;
     483           0 :         goto done;
     484             :     }
     485             : 
     486           0 :     state->hostnames[1] = talloc_strdup(state->hostnames, rhostent->name);
     487           0 :     if (state->hostnames[1] == NULL) {
     488           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
     489           0 :         ret = ENOMEM;
     490           0 :         goto done;
     491             :     }
     492             : 
     493           0 :     ret = EOK;
     494             : 
     495             : done:
     496           0 :     if (ret == EOK) {
     497           0 :         tevent_req_done(req);
     498             :     } else {
     499           0 :         tevent_req_error(req, ret);
     500             :     }
     501             : }
     502             : 
     503           0 : static int sdap_sudo_get_hostnames_recv(TALLOC_CTX *mem_ctx,
     504             :                                         struct tevent_req *req,
     505             :                                         char ***hostnames)
     506             : {
     507           0 :     struct sdap_sudo_get_hostnames_state *state = NULL;
     508             : 
     509           0 :     state = tevent_req_data(req, struct sdap_sudo_get_hostnames_state);
     510             : 
     511           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     512             : 
     513           0 :     *hostnames = talloc_steal(mem_ctx, state->hostnames);
     514             : 
     515           0 :     return EOK;
     516             : }

Generated by: LCOV version 1.10