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

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 1996, 1998-2005, 2007-2010
        !             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/param.h>
        !            36: #include <sys/time.h>
        !            37: #include <sys/ioctl.h>
        !            38: #if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFCONF)
        !            39: # include <sys/sockio.h>
        !            40: #endif
        !            41: #include <stdio.h>
        !            42: #ifdef STDC_HEADERS
        !            43: # include <stdlib.h>
        !            44: # include <stddef.h>
        !            45: #else
        !            46: # ifdef HAVE_STDLIB_H
        !            47: #  include <stdlib.h>
        !            48: # endif
        !            49: #endif /* STDC_HEADERS */
        !            50: #ifdef HAVE_STRING_H
        !            51: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
        !            52: #  include <memory.h>
        !            53: # endif
        !            54: # include <string.h>
        !            55: #endif /* HAVE_STRING_H */
        !            56: #ifdef HAVE_STRINGS_H
        !            57: # include <strings.h>
        !            58: #endif /* HAVE_STRINGS_H */
        !            59: #ifdef HAVE_UNISTD_H
        !            60: # include <unistd.h>
        !            61: #endif /* HAVE_UNISTD_H */
        !            62: #include <netdb.h>
        !            63: #include <errno.h>
        !            64: #ifdef _ISC
        !            65: # include <sys/stream.h>
        !            66: # include <sys/sioctl.h>
        !            67: # include <sys/stropts.h>
        !            68: # define STRSET(cmd, param, len) {strioctl.ic_cmd=(cmd);\
        !            69:                                 strioctl.ic_dp=(param);\
        !            70:                                 strioctl.ic_timout=0;\
        !            71:                                 strioctl.ic_len=(len);}
        !            72: #endif /* _ISC */
        !            73: #ifdef _MIPS
        !            74: # include <net/soioctl.h>
        !            75: #endif /* _MIPS */
        !            76: #include <netinet/in.h>
        !            77: #include <arpa/inet.h>
        !            78: #include <net/if.h>
        !            79: #ifdef HAVE_GETIFADDRS
        !            80: # include <ifaddrs.h>
        !            81: #endif
        !            82: 
        !            83: #include "missing.h"
        !            84: #include "alloc.h"
        !            85: #include "error.h"
        !            86: 
        !            87: #define DEFAULT_TEXT_DOMAIN    "sudo"
        !            88: #include "gettext.h"
        !            89: 
        !            90: /* Minix apparently lacks IFF_LOOPBACK */
        !            91: #ifndef IFF_LOOPBACK
        !            92: # define IFF_LOOPBACK  0
        !            93: #endif
        !            94: 
        !            95: #ifndef INET6_ADDRSTRLEN
        !            96: # define INET6_ADDRSTRLEN 46
        !            97: #endif
        !            98: 
        !            99: #ifdef HAVE_GETIFADDRS
        !           100: 
        !           101: /*
        !           102:  * Fill in the interfaces string with the machine's ip addresses and netmasks
        !           103:  * and return the number of interfaces found.
        !           104:  */
        !           105: int
        !           106: get_net_ifs(char **addrinfo)
        !           107: {
        !           108:     struct ifaddrs *ifa, *ifaddrs;
        !           109:     struct sockaddr_in *sin;
        !           110: #ifdef HAVE_IN6_ADDR
        !           111:     struct sockaddr_in6 *sin6;
        !           112:     char addrbuf[INET6_ADDRSTRLEN];
        !           113: #endif
        !           114:     int ailen, i, len, num_interfaces = 0;
        !           115:     char *cp;
        !           116: 
        !           117:     if (getifaddrs(&ifaddrs))
        !           118:        return 0;
        !           119: 
        !           120:     /* Allocate space for the interfaces info string. */
        !           121:     for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) {
        !           122:        /* Skip interfaces marked "down" and "loopback". */
        !           123:        if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
        !           124:            !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
        !           125:            continue;
        !           126: 
        !           127:        switch (ifa->ifa_addr->sa_family) {
        !           128:            case AF_INET:
        !           129: #ifdef HAVE_IN6_ADDR
        !           130:            case AF_INET6:
        !           131: #endif
        !           132:                num_interfaces++;
        !           133:                break;
        !           134:        }
        !           135:     }
        !           136:     if (num_interfaces == 0)
        !           137:        return 0;
        !           138:     ailen = num_interfaces * 2 * INET6_ADDRSTRLEN;
        !           139:     *addrinfo = cp = emalloc(ailen);
        !           140: 
        !           141:     /* Store the IP addr/netmask pairs. */
        !           142:     for (ifa = ifaddrs, i = 0; ifa != NULL; ifa = ifa -> ifa_next) {
        !           143:        /* Skip interfaces marked "down" and "loopback". */
        !           144:        if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
        !           145:            !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
        !           146:                continue;
        !           147: 
        !           148:        switch (ifa->ifa_addr->sa_family) {
        !           149:            case AF_INET:
        !           150:                sin = (struct sockaddr_in *)ifa->ifa_addr;
        !           151:                len = snprintf(cp, ailen - (*addrinfo - cp),
        !           152:                    "%s%s/", cp == *addrinfo ? "" : " ",
        !           153:                    inet_ntoa(sin->sin_addr));
        !           154:                if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
        !           155:                    warningx(_("load_interfaces: overflow detected"));
        !           156:                    goto done;
        !           157:                }
        !           158:                cp += len;
        !           159: 
        !           160:                sin = (struct sockaddr_in *)ifa->ifa_netmask;
        !           161:                len = snprintf(cp, ailen - (*addrinfo - cp),
        !           162:                    "%s", inet_ntoa(sin->sin_addr));
        !           163:                if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
        !           164:                    warningx(_("load_interfaces: overflow detected"));
        !           165:                    goto done;
        !           166:                }
        !           167:                cp += len;
        !           168:                break;
        !           169: #ifdef HAVE_IN6_ADDR
        !           170:            case AF_INET6:
        !           171:                sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
        !           172:                inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf));
        !           173:                len = snprintf(cp, ailen - (*addrinfo - cp),
        !           174:                    "%s%s/", cp == *addrinfo ? "" : " ", addrbuf);
        !           175:                if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
        !           176:                    warningx(_("load_interfaces: overflow detected"));
        !           177:                    goto done;
        !           178:                }
        !           179:                cp += len;
        !           180: 
        !           181:                sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask;
        !           182:                inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf));
        !           183:                len = snprintf(cp, ailen - (*addrinfo - cp), "%s", addrbuf);
        !           184:                if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
        !           185:                    warningx(_("load_interfaces: overflow detected"));
        !           186:                    goto done;
        !           187:                }
        !           188:                cp += len;
        !           189:                break;
        !           190: #endif /* HAVE_IN6_ADDR */
        !           191:        }
        !           192:     }
        !           193: 
        !           194: done:
        !           195: #ifdef HAVE_FREEIFADDRS
        !           196:     freeifaddrs(ifaddrs);
        !           197: #else
        !           198:     efree(ifaddrs);
        !           199: #endif
        !           200:     return num_interfaces;
        !           201: }
        !           202: 
        !           203: #elif defined(SIOCGIFCONF) && !defined(STUB_LOAD_INTERFACES)
        !           204: 
        !           205: /*
        !           206:  * Allocate and fill in the interfaces global variable with the
        !           207:  * machine's ip addresses and netmasks.
        !           208:  */
        !           209: int
        !           210: get_net_ifs(char **addrinfo)
        !           211: {
        !           212:     struct ifconf *ifconf;
        !           213:     struct ifreq *ifr, ifr_tmp;
        !           214:     struct sockaddr_in *sin;
        !           215:     int ailen, i, len, n, sock, num_interfaces = 0;
        !           216:     size_t buflen = sizeof(struct ifconf) + BUFSIZ;
        !           217:     char *cp, *previfname = "", *ifconf_buf = NULL;
        !           218: #ifdef _ISC
        !           219:     struct strioctl strioctl;
        !           220: #endif /* _ISC */
        !           221: 
        !           222:     sock = socket(AF_INET, SOCK_DGRAM, 0);
        !           223:     if (sock < 0)
        !           224:        error(1, _("unable to open socket"));
        !           225: 
        !           226:     /*
        !           227:      * Get interface configuration or return.
        !           228:      */
        !           229:     for (;;) {
        !           230:        ifconf_buf = emalloc(buflen);
        !           231:        ifconf = (struct ifconf *) ifconf_buf;
        !           232:        ifconf->ifc_len = buflen - sizeof(struct ifconf);
        !           233:        ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf));
        !           234: 
        !           235: #ifdef _ISC
        !           236:        STRSET(SIOCGIFCONF, (caddr_t) ifconf, buflen);
        !           237:        if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0)
        !           238: #else
        !           239:        /* Note that some kernels return EINVAL if the buffer is too small */
        !           240:        if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL)
        !           241: #endif /* _ISC */
        !           242:            goto done;
        !           243: 
        !           244:        /* Break out of loop if we have a big enough buffer. */
        !           245:        if (ifconf->ifc_len + sizeof(struct ifreq) < buflen)
        !           246:            break;
        !           247:        buflen += BUFSIZ;
        !           248:        efree(ifconf_buf);
        !           249:     }
        !           250: 
        !           251:     /* Allocate space for the maximum number of interfaces that could exist. */
        !           252:     if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0)
        !           253:        return 0;
        !           254:     ailen = n * 2 * INET6_ADDRSTRLEN;
        !           255:     *addrinfo = cp = emalloc(ailen);
        !           256: 
        !           257:     /* For each interface, store the ip address and netmask. */
        !           258:     for (i = 0; i < ifconf->ifc_len; ) {
        !           259:        /* Get a pointer to the current interface. */
        !           260:        ifr = (struct ifreq *) &ifconf->ifc_buf[i];
        !           261: 
        !           262:        /* Set i to the subscript of the next interface. */
        !           263:        i += sizeof(struct ifreq);
        !           264: #ifdef HAVE_SA_LEN
        !           265:        if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
        !           266:            i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
        !           267: #endif /* HAVE_SA_LEN */
        !           268: 
        !           269:        /* Skip duplicates and interfaces with NULL addresses. */
        !           270:        sin = (struct sockaddr_in *) &ifr->ifr_addr;
        !           271:        if (sin->sin_addr.s_addr == 0 ||
        !           272:            strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0)
        !           273:            continue;
        !           274: 
        !           275:        if (ifr->ifr_addr.sa_family != AF_INET)
        !           276:                continue;
        !           277: 
        !           278: #ifdef SIOCGIFFLAGS
        !           279:        memset(&ifr_tmp, 0, sizeof(ifr_tmp));
        !           280:        strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
        !           281:        if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0)
        !           282: #endif
        !           283:            ifr_tmp = *ifr;
        !           284:        
        !           285:        /* Skip interfaces marked "down" and "loopback". */
        !           286:        if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) ||
        !           287:            ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK))
        !           288:                continue;
        !           289: 
        !           290:        sin = (struct sockaddr_in *) &ifr->ifr_addr;
        !           291:        len = snprintf(cp, ailen - (*addrinfo - cp),
        !           292:            "%s%s/", cp == *addrinfo ? "" : " ",
        !           293:            inet_ntoa(sin->sin_addr));
        !           294:        if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
        !           295:            warningx(_("load_interfaces: overflow detected"));
        !           296:            goto done;
        !           297:        }
        !           298:        cp += len;
        !           299: 
        !           300:        /* Stash the name of the interface we saved. */
        !           301:        previfname = ifr->ifr_name;
        !           302: 
        !           303:        /* Get the netmask. */
        !           304:        memset(&ifr_tmp, 0, sizeof(ifr_tmp));
        !           305:        strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
        !           306: #ifdef _ISC
        !           307:        STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp));
        !           308:        if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) {
        !           309: #else
        !           310:        if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) < 0) {
        !           311: #endif /* _ISC */
        !           312:            sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
        !           313:            sin->sin_addr.s_addr = htonl(IN_CLASSC_NET);
        !           314:        }
        !           315:        sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
        !           316:        len = snprintf(cp, ailen - (*addrinfo - cp),
        !           317:            "%s", inet_ntoa(sin->sin_addr));
        !           318:        if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
        !           319:            warningx(_("load_interfaces: overflow detected"));
        !           320:            goto done;
        !           321:        }
        !           322:        cp += len;
        !           323:        num_interfaces++;
        !           324:     }
        !           325: 
        !           326: done:
        !           327:     efree(ifconf_buf);
        !           328:     (void) close(sock);
        !           329: 
        !           330:     return num_interfaces;
        !           331: }
        !           332: 
        !           333: #else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */
        !           334: 
        !           335: /*
        !           336:  * Stub function for those without SIOCGIFCONF or getifaddrs()
        !           337:  */
        !           338: int
        !           339: get_net_ifs(char **addrinfo)
        !           340: {
        !           341:     return 0;
        !           342: }
        !           343: 
        !           344: #endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */

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