File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / src / net_ifs.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:12:55 2014 UTC (10 years ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_10p3_0, v1_8_10p3, HEAD
sudo v 1.8.10p3

    1: /*
    2:  * Copyright (c) 1996, 1998-2005, 2007-2014
    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 */
   58: #ifdef HAVE_STDBOOL_H
   59: # include <stdbool.h>
   60: #else
   61: # include "compat/stdbool.h"
   62: #endif /* HAVE_STDBOOL_H */
   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: 
   87: #define DEFAULT_TEXT_DOMAIN	"sudo"
   88: #include "gettext.h"		/* must be included before missing.h */
   89: 
   90: #include "missing.h"
   91: #include "alloc.h"
   92: #include "fatal.h"
   93: #include "sudo_conf.h"
   94: #include "sudo_debug.h"
   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;
  116: #ifdef HAVE_STRUCT_IN6_ADDR
  117:     struct sockaddr_in6 *sin6;
  118:     char addrbuf[INET6_ADDRSTRLEN];
  119: #endif
  120:     int ailen, len, num_interfaces = 0;
  121:     char *cp;
  122:     debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)
  123: 
  124:     if (!sudo_conf_probe_interfaces() || getifaddrs(&ifaddrs) != 0)
  125: 	debug_return_int(0);
  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:
  136: #ifdef HAVE_STRUCT_IN6_ADDR
  137: 	    case AF_INET6:
  138: #endif
  139: 		num_interfaces++;
  140: 		break;
  141: 	}
  142:     }
  143:     if (num_interfaces == 0)
  144: 	debug_return_int(0);
  145:     ailen = num_interfaces * 2 * INET6_ADDRSTRLEN;
  146:     *addrinfo = cp = emalloc(ailen);
  147: 
  148:     /* Store the IP addr/netmask pairs. */
  149:     for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) {
  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)) {
  162: 		    warningx(U_("load_interfaces: overflow detected"));
  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)) {
  171: 		    warningx(U_("load_interfaces: overflow detected"));
  172: 		    goto done;
  173: 		}
  174: 		cp += len;
  175: 		break;
  176: #ifdef HAVE_STRUCT_IN6_ADDR
  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)) {
  183: 		    warningx(U_("load_interfaces: overflow detected"));
  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)) {
  192: 		    warningx(U_("load_interfaces: overflow detected"));
  193: 		    goto done;
  194: 		}
  195: 		cp += len;
  196: 		break;
  197: #endif /* HAVE_STRUCT_IN6_ADDR */
  198: 	}
  199:     }
  200: 
  201: done:
  202: #ifdef HAVE_FREEIFADDRS
  203:     freeifaddrs(ifaddrs);
  204: #else
  205:     efree(ifaddrs);
  206: #endif
  207:     debug_return_int(num_interfaces);
  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 */
  228:     debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)
  229: 
  230:     if (!sudo_conf_probe_interfaces())
  231: 	debug_return_int(0);
  232: 
  233:     sock = socket(AF_INET, SOCK_DGRAM, 0);
  234:     if (sock < 0)
  235: 	fatal(U_("unable to open socket"));
  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)
  264: 	debug_return_int(0);
  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);
  275: #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
  276: 	if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
  277: 	    i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
  278: #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
  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)) {
  306: 	    warningx(U_("load_interfaces: overflow detected"));
  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)) {
  330: 	    warningx(U_("load_interfaces: overflow detected"));
  331: 	    goto done;
  332: 	}
  333: 	cp += len;
  334: 	num_interfaces++;
  335:     }
  336: 
  337: done:
  338:     efree(ifconf_buf);
  339:     (void) close(sock);
  340: 
  341:     debug_return_int(num_interfaces);
  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: {
  352:     debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)
  353:     debug_return_int(0);
  354: }
  355: 
  356: #endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */

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