File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / src / net_ifs.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:26:49 2012 UTC (12 years, 2 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_5p1, HEAD
sudo 1.8.5p1

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

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