File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / src / net_ifs.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 07:56:35 2013 UTC (10 years, 9 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_8p0, v1_8_8, HEAD
v 1.8.8

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

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