Annotation of embedaddon/sudo/src/net_ifs.c, revision 1.1.1.5

1.1       misho       1: /*
1.1.1.5 ! misho       2:  * Copyright (c) 1996, 1998-2005, 2007-2014
1.1       misho       3:  *     Todd C. Miller <Todd.Miller@courtesan.com>
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  *
                     17:  * Sponsored in part by the Defense Advanced Research Projects
                     18:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
                     19:  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
                     20:  */
                     21: 
                     22: /*
                     23:  * Suppress a warning w/ gcc on Digital UN*X.
                     24:  * The system headers should really do this....
                     25:  */
                     26: #if defined(__osf__) && !defined(__cplusplus)
                     27: struct mbuf;
                     28: struct rtentry;
                     29: #endif
                     30: 
                     31: #include <config.h>
                     32: 
                     33: #include <sys/types.h>
                     34: #include <sys/socket.h>
                     35: #include <sys/time.h>
                     36: #include <sys/ioctl.h>
                     37: #if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFCONF)
                     38: # include <sys/sockio.h>
                     39: #endif
                     40: #include <stdio.h>
                     41: #ifdef STDC_HEADERS
                     42: # include <stdlib.h>
                     43: # include <stddef.h>
                     44: #else
                     45: # ifdef HAVE_STDLIB_H
                     46: #  include <stdlib.h>
                     47: # endif
                     48: #endif /* STDC_HEADERS */
                     49: #ifdef HAVE_STRING_H
                     50: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
                     51: #  include <memory.h>
                     52: # endif
                     53: # include <string.h>
                     54: #endif /* HAVE_STRING_H */
                     55: #ifdef HAVE_STRINGS_H
                     56: # include <strings.h>
                     57: #endif /* HAVE_STRINGS_H */
1.1.1.5 ! misho      58: #ifdef HAVE_STDBOOL_H
        !            59: # include <stdbool.h>
        !            60: #else
        !            61: # include "compat/stdbool.h"
        !            62: #endif /* HAVE_STDBOOL_H */
1.1       misho      63: #ifdef HAVE_UNISTD_H
                     64: # include <unistd.h>
                     65: #endif /* HAVE_UNISTD_H */
                     66: #include <netdb.h>
                     67: #include <errno.h>
                     68: #ifdef _ISC
                     69: # include <sys/stream.h>
                     70: # include <sys/sioctl.h>
                     71: # include <sys/stropts.h>
                     72: # define STRSET(cmd, param, len) {strioctl.ic_cmd=(cmd);\
                     73:                                 strioctl.ic_dp=(param);\
                     74:                                 strioctl.ic_timout=0;\
                     75:                                 strioctl.ic_len=(len);}
                     76: #endif /* _ISC */
                     77: #ifdef _MIPS
                     78: # include <net/soioctl.h>
                     79: #endif /* _MIPS */
                     80: #include <netinet/in.h>
                     81: #include <arpa/inet.h>
                     82: #include <net/if.h>
                     83: #ifdef HAVE_GETIFADDRS
                     84: # include <ifaddrs.h>
                     85: #endif
                     86: 
1.1.1.5 ! misho      87: #define DEFAULT_TEXT_DOMAIN    "sudo"
        !            88: #include "gettext.h"           /* must be included before missing.h */
        !            89: 
1.1       misho      90: #include "missing.h"
                     91: #include "alloc.h"
1.1.1.4   misho      92: #include "fatal.h"
1.1.1.5 ! misho      93: #include "sudo_conf.h"
1.1.1.2   misho      94: #include "sudo_debug.h"
1.1       misho      95: 
                     96: /* Minix apparently lacks IFF_LOOPBACK */
                     97: #ifndef IFF_LOOPBACK
                     98: # define IFF_LOOPBACK  0
                     99: #endif
                    100: 
                    101: #ifndef INET6_ADDRSTRLEN
                    102: # define INET6_ADDRSTRLEN 46
                    103: #endif
                    104: 
                    105: #ifdef HAVE_GETIFADDRS
                    106: 
                    107: /*
                    108:  * Fill in the interfaces string with the machine's ip addresses and netmasks
                    109:  * and return the number of interfaces found.
                    110:  */
                    111: int
                    112: get_net_ifs(char **addrinfo)
                    113: {
                    114:     struct ifaddrs *ifa, *ifaddrs;
                    115:     struct sockaddr_in *sin;
1.1.1.2   misho     116: #ifdef HAVE_STRUCT_IN6_ADDR
1.1       misho     117:     struct sockaddr_in6 *sin6;
                    118:     char addrbuf[INET6_ADDRSTRLEN];
                    119: #endif
1.1.1.4   misho     120:     int ailen, len, num_interfaces = 0;
1.1       misho     121:     char *cp;
1.1.1.2   misho     122:     debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)
1.1       misho     123: 
1.1.1.5 ! misho     124:     if (!sudo_conf_probe_interfaces() || getifaddrs(&ifaddrs) != 0)
1.1.1.2   misho     125:        debug_return_int(0);
1.1       misho     126: 
                    127:     /* Allocate space for the interfaces info string. */
                    128:     for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) {
                    129:        /* Skip interfaces marked "down" and "loopback". */
                    130:        if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
                    131:            !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
                    132:            continue;
                    133: 
                    134:        switch (ifa->ifa_addr->sa_family) {
                    135:            case AF_INET:
1.1.1.2   misho     136: #ifdef HAVE_STRUCT_IN6_ADDR
1.1       misho     137:            case AF_INET6:
                    138: #endif
                    139:                num_interfaces++;
                    140:                break;
                    141:        }
                    142:     }
                    143:     if (num_interfaces == 0)
1.1.1.2   misho     144:        debug_return_int(0);
1.1       misho     145:     ailen = num_interfaces * 2 * INET6_ADDRSTRLEN;
                    146:     *addrinfo = cp = emalloc(ailen);
                    147: 
                    148:     /* Store the IP addr/netmask pairs. */
1.1.1.4   misho     149:     for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) {
1.1       misho     150:        /* Skip interfaces marked "down" and "loopback". */
                    151:        if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
                    152:            !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
                    153:                continue;
                    154: 
                    155:        switch (ifa->ifa_addr->sa_family) {
                    156:            case AF_INET:
                    157:                sin = (struct sockaddr_in *)ifa->ifa_addr;
                    158:                len = snprintf(cp, ailen - (*addrinfo - cp),
                    159:                    "%s%s/", cp == *addrinfo ? "" : " ",
                    160:                    inet_ntoa(sin->sin_addr));
                    161:                if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
1.1.1.5 ! misho     162:                    warningx(U_("load_interfaces: overflow detected"));
1.1       misho     163:                    goto done;
                    164:                }
                    165:                cp += len;
                    166: 
                    167:                sin = (struct sockaddr_in *)ifa->ifa_netmask;
                    168:                len = snprintf(cp, ailen - (*addrinfo - cp),
                    169:                    "%s", inet_ntoa(sin->sin_addr));
                    170:                if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
1.1.1.5 ! misho     171:                    warningx(U_("load_interfaces: overflow detected"));
1.1       misho     172:                    goto done;
                    173:                }
                    174:                cp += len;
                    175:                break;
1.1.1.2   misho     176: #ifdef HAVE_STRUCT_IN6_ADDR
1.1       misho     177:            case AF_INET6:
                    178:                sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
                    179:                inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf));
                    180:                len = snprintf(cp, ailen - (*addrinfo - cp),
                    181:                    "%s%s/", cp == *addrinfo ? "" : " ", addrbuf);
                    182:                if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
1.1.1.5 ! misho     183:                    warningx(U_("load_interfaces: overflow detected"));
1.1       misho     184:                    goto done;
                    185:                }
                    186:                cp += len;
                    187: 
                    188:                sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask;
                    189:                inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf));
                    190:                len = snprintf(cp, ailen - (*addrinfo - cp), "%s", addrbuf);
                    191:                if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
1.1.1.5 ! misho     192:                    warningx(U_("load_interfaces: overflow detected"));
1.1       misho     193:                    goto done;
                    194:                }
                    195:                cp += len;
                    196:                break;
1.1.1.2   misho     197: #endif /* HAVE_STRUCT_IN6_ADDR */
1.1       misho     198:        }
                    199:     }
                    200: 
                    201: done:
                    202: #ifdef HAVE_FREEIFADDRS
                    203:     freeifaddrs(ifaddrs);
                    204: #else
                    205:     efree(ifaddrs);
                    206: #endif
1.1.1.2   misho     207:     debug_return_int(num_interfaces);
1.1       misho     208: }
                    209: 
                    210: #elif defined(SIOCGIFCONF) && !defined(STUB_LOAD_INTERFACES)
                    211: 
                    212: /*
                    213:  * Allocate and fill in the interfaces global variable with the
                    214:  * machine's ip addresses and netmasks.
                    215:  */
                    216: int
                    217: get_net_ifs(char **addrinfo)
                    218: {
                    219:     struct ifconf *ifconf;
                    220:     struct ifreq *ifr, ifr_tmp;
                    221:     struct sockaddr_in *sin;
                    222:     int ailen, i, len, n, sock, num_interfaces = 0;
                    223:     size_t buflen = sizeof(struct ifconf) + BUFSIZ;
                    224:     char *cp, *previfname = "", *ifconf_buf = NULL;
                    225: #ifdef _ISC
                    226:     struct strioctl strioctl;
                    227: #endif /* _ISC */
1.1.1.2   misho     228:     debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)
1.1       misho     229: 
1.1.1.5 ! misho     230:     if (!sudo_conf_probe_interfaces())
        !           231:        debug_return_int(0);
        !           232: 
1.1       misho     233:     sock = socket(AF_INET, SOCK_DGRAM, 0);
                    234:     if (sock < 0)
1.1.1.5 ! misho     235:        fatal(U_("unable to open socket"));
1.1       misho     236: 
                    237:     /*
                    238:      * Get interface configuration or return.
                    239:      */
                    240:     for (;;) {
                    241:        ifconf_buf = emalloc(buflen);
                    242:        ifconf = (struct ifconf *) ifconf_buf;
                    243:        ifconf->ifc_len = buflen - sizeof(struct ifconf);
                    244:        ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf));
                    245: 
                    246: #ifdef _ISC
                    247:        STRSET(SIOCGIFCONF, (caddr_t) ifconf, buflen);
                    248:        if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0)
                    249: #else
                    250:        /* Note that some kernels return EINVAL if the buffer is too small */
                    251:        if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL)
                    252: #endif /* _ISC */
                    253:            goto done;
                    254: 
                    255:        /* Break out of loop if we have a big enough buffer. */
                    256:        if (ifconf->ifc_len + sizeof(struct ifreq) < buflen)
                    257:            break;
                    258:        buflen += BUFSIZ;
                    259:        efree(ifconf_buf);
                    260:     }
                    261: 
                    262:     /* Allocate space for the maximum number of interfaces that could exist. */
                    263:     if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0)
1.1.1.2   misho     264:        debug_return_int(0);
1.1       misho     265:     ailen = n * 2 * INET6_ADDRSTRLEN;
                    266:     *addrinfo = cp = emalloc(ailen);
                    267: 
                    268:     /* For each interface, store the ip address and netmask. */
                    269:     for (i = 0; i < ifconf->ifc_len; ) {
                    270:        /* Get a pointer to the current interface. */
                    271:        ifr = (struct ifreq *) &ifconf->ifc_buf[i];
                    272: 
                    273:        /* Set i to the subscript of the next interface. */
                    274:        i += sizeof(struct ifreq);
1.1.1.2   misho     275: #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1.1       misho     276:        if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
                    277:            i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
1.1.1.2   misho     278: #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
1.1       misho     279: 
                    280:        /* Skip duplicates and interfaces with NULL addresses. */
                    281:        sin = (struct sockaddr_in *) &ifr->ifr_addr;
                    282:        if (sin->sin_addr.s_addr == 0 ||
                    283:            strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0)
                    284:            continue;
                    285: 
                    286:        if (ifr->ifr_addr.sa_family != AF_INET)
                    287:                continue;
                    288: 
                    289: #ifdef SIOCGIFFLAGS
                    290:        memset(&ifr_tmp, 0, sizeof(ifr_tmp));
                    291:        strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
                    292:        if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0)
                    293: #endif
                    294:            ifr_tmp = *ifr;
                    295:        
                    296:        /* Skip interfaces marked "down" and "loopback". */
                    297:        if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) ||
                    298:            ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK))
                    299:                continue;
                    300: 
                    301:        sin = (struct sockaddr_in *) &ifr->ifr_addr;
                    302:        len = snprintf(cp, ailen - (*addrinfo - cp),
                    303:            "%s%s/", cp == *addrinfo ? "" : " ",
                    304:            inet_ntoa(sin->sin_addr));
                    305:        if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
1.1.1.5 ! misho     306:            warningx(U_("load_interfaces: overflow detected"));
1.1       misho     307:            goto done;
                    308:        }
                    309:        cp += len;
                    310: 
                    311:        /* Stash the name of the interface we saved. */
                    312:        previfname = ifr->ifr_name;
                    313: 
                    314:        /* Get the netmask. */
                    315:        memset(&ifr_tmp, 0, sizeof(ifr_tmp));
                    316:        strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
                    317: #ifdef _ISC
                    318:        STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp));
                    319:        if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) {
                    320: #else
                    321:        if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) < 0) {
                    322: #endif /* _ISC */
                    323:            sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
                    324:            sin->sin_addr.s_addr = htonl(IN_CLASSC_NET);
                    325:        }
                    326:        sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
                    327:        len = snprintf(cp, ailen - (*addrinfo - cp),
                    328:            "%s", inet_ntoa(sin->sin_addr));
                    329:        if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
1.1.1.5 ! misho     330:            warningx(U_("load_interfaces: overflow detected"));
1.1       misho     331:            goto done;
                    332:        }
                    333:        cp += len;
                    334:        num_interfaces++;
                    335:     }
                    336: 
                    337: done:
                    338:     efree(ifconf_buf);
                    339:     (void) close(sock);
                    340: 
1.1.1.2   misho     341:     debug_return_int(num_interfaces);
1.1       misho     342: }
                    343: 
                    344: #else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */
                    345: 
                    346: /*
                    347:  * Stub function for those without SIOCGIFCONF or getifaddrs()
                    348:  */
                    349: int
                    350: get_net_ifs(char **addrinfo)
                    351: {
1.1.1.2   misho     352:     debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)
                    353:     debug_return_int(0);
1.1       misho     354: }
                    355: 
                    356: #endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>