From: Todd C. Miller Date: Wed, 8 Sep 2010 19:07:40 +0000 (-0400) Subject: Convert sudoers plugin to use interface list passed in settings. X-Git-Tag: SUDO_1_8_0~253 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e069b74dc88d194478424b6b6c577346c1ce1581;p=sudo Convert sudoers plugin to use interface list passed in settings. --- diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in index 44591de6f..4c7bae6d7 100644 --- a/plugins/sudoers/Makefile.in +++ b/plugins/sudoers/Makefile.in @@ -114,7 +114,8 @@ VISUDO_OBJS = visudo.o goodpath.o find_path.o error.o REPLAY_OBJS = getdate.o sudoreplay.o error.o -TEST_OBJS = interfaces.o testsudoers.o tsgetgrpw.o error.o group_plugin.o +TEST_OBJS = interfaces.o testsudoers.o tsgetgrpw.o error.o group_plugin.o \ + net_ifs.o VERSION = @PACKAGE_VERSION@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ @@ -250,6 +251,8 @@ sudoreplay.o: $(srcdir)/sudoreplay.c $(incdir)/alloc.h $(incdir)/missing.h $(inc testsudoers.o: $(srcdir)/testsudoers.c $(SUDODEP) $(srcdir)/parse.h $(incdir)/list.h $(srcdir)/interfaces.h $(devdir)/gram.h tsgetgrpw.o: $(srcdir)/tsgetgrpw.c $(SUDODEP) visudo.o: $(srcdir)/visudo.c $(SUDODEP) $(devdir)/gram.h +net_ifs.o: $(top_srcdir)/src/net_ifs.c $(SUDODEP) + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(top_srcdir)/src/net_ifs.c install: install-dirs install-plugin install-binaries install-sudoers install-doc diff --git a/plugins/sudoers/interfaces.c b/plugins/sudoers/interfaces.c index 27c452e5f..9280e9692 100644 --- a/plugins/sudoers/interfaces.c +++ b/plugins/sudoers/interfaces.c @@ -1,6 +1,5 @@ /* - * Copyright (c) 1996, 1998-2005, 2007-2010 - * Todd C. Miller + * Copyright (c) 2010 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -13,31 +12,13 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Sponsored in part by the Defense Advanced Research Projects - * Agency (DARPA) and Air Force Research Laboratory, Air Force - * Materiel Command, USAF, under agreement number F39502-99-1-0512. */ -/* - * Suppress a warning w/ gcc on Digital UN*X. - * The system headers should really do this.... - */ -#if defined(__osf__) && !defined(__cplusplus) -struct mbuf; -struct rtentry; -#endif - #include #include #include #include -#include -#include -#if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFCONF) -# include -#endif #include #ifdef STDC_HEADERS # include @@ -59,298 +40,71 @@ struct rtentry; #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ +#include +#include #include #include -#ifdef _ISC -# include -# include -# include -# define STRSET(cmd, param, len) {strioctl.ic_cmd=(cmd);\ - strioctl.ic_dp=(param);\ - strioctl.ic_timout=0;\ - strioctl.ic_len=(len);} -#endif /* _ISC */ -#ifdef _MIPS -# include -#endif /* _MIPS */ -#include -#include -#include -#ifdef HAVE_GETIFADDRS -# include -#endif #include "sudoers.h" #include "interfaces.h" -/* Minix apparently lacks IFF_LOOPBACK */ -#ifndef IFF_LOOPBACK -# define IFF_LOOPBACK 0 -#endif - -#ifdef HAVE_GETIFADDRS - /* - * Allocate and fill in the interfaces global variable with the - * machine's ip addresses and netmasks. + * Parse a space-delimited list of IP address/netmask pairs and + * store in a list of interface structures. */ void -load_interfaces(void) +set_interfaces(const char *ai) { - struct ifaddrs *ifa, *ifaddrs; - struct sockaddr_in *sin; -#ifdef HAVE_IN6_ADDR - struct sockaddr_in6 *sin6; -#endif - int i; + char *addrinfo, *addr, *mask; + struct interface *ifp; - if (getifaddrs(&ifaddrs)) - return; - - /* Allocate space for the interfaces list. */ - for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) { - /* Skip interfaces marked "down" and "loopback". */ - if (ifa->ifa_addr == NULL || !ISSET(ifa->ifa_flags, IFF_UP) || - ISSET(ifa->ifa_flags, IFF_LOOPBACK)) + addrinfo = estrdup(ai); + for (addr = strtok(addrinfo, " \t"); addr != NULL; addr = strtok(NULL, " \t")) { + /* Separate addr and mask. */ + if ((mask = strchr(addr, '/')) == NULL) continue; + *mask++ = '\0'; - switch(ifa->ifa_addr->sa_family) { - case AF_INET: + /* Parse addr and store in list. */ + ifp = emalloc(sizeof(*ifp)); + if (strchr(addr, ':')) { + /* IPv6 */ #ifdef HAVE_IN6_ADDR - case AF_INET6: + ifp->family = AF_INET6; + if (inet_pton(AF_INET6, addr, &ifp->addr.ip6) != 1 || + inet_pton(AF_INET6, mask, &ifp->netmask.ip6) != 1) #endif - num_interfaces++; - break; - } - } - if (num_interfaces == 0) - return; - interfaces = - (struct interface *) emalloc2(num_interfaces, sizeof(struct interface)); - - /* Store the ip addr / netmask pairs. */ - for (ifa = ifaddrs, i = 0; ifa != NULL; ifa = ifa -> ifa_next) { - /* Skip interfaces marked "down" and "loopback". */ - if (ifa->ifa_addr == NULL || !ISSET(ifa->ifa_flags, IFF_UP) || - ISSET(ifa->ifa_flags, IFF_LOOPBACK)) + { + efree(ifp); continue; - - switch(ifa->ifa_addr->sa_family) { - case AF_INET: - sin = (struct sockaddr_in *)ifa->ifa_addr; - if (sin == NULL) - continue; - memcpy(&interfaces[i].addr, &sin->sin_addr, - sizeof(struct in_addr)); - sin = (struct sockaddr_in *)ifa->ifa_netmask; - if (sin == NULL) - continue; - memcpy(&interfaces[i].netmask, &sin->sin_addr, - sizeof(struct in_addr)); - interfaces[i].family = AF_INET; - i++; - break; -#ifdef HAVE_IN6_ADDR - case AF_INET6: - sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; - if (sin6 == NULL) - continue; - memcpy(&interfaces[i].addr, &sin6->sin6_addr, - sizeof(struct in6_addr)); - sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask; - if (sin6 == NULL) - continue; - memcpy(&interfaces[i].netmask, &sin6->sin6_addr, - sizeof(struct in6_addr)); - interfaces[i].family = AF_INET6; - i++; - break; -#endif /* HAVE_IN6_ADDR */ - } - } -#ifdef HAVE_FREEIFADDRS - freeifaddrs(ifaddrs); -#else - efree(ifaddrs); -#endif -} - -#elif defined(SIOCGIFCONF) && !defined(STUB_LOAD_INTERFACES) - -/* - * Allocate and fill in the interfaces global variable with the - * machine's ip addresses and netmasks. - */ -void -load_interfaces(void) -{ - struct ifconf *ifconf; - struct ifreq *ifr, ifr_tmp; - struct sockaddr_in *sin; - int sock, n, i; - size_t len = sizeof(struct ifconf) + BUFSIZ; - char *previfname = "", *ifconf_buf = NULL; -#ifdef _ISC - struct strioctl strioctl; -#endif /* _ISC */ - - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) - error(1, "cannot open socket"); - - /* - * Get interface configuration or return (leaving num_interfaces == 0) - */ - for (;;) { - ifconf_buf = erealloc(ifconf_buf, len); - ifconf = (struct ifconf *) ifconf_buf; - ifconf->ifc_len = len - sizeof(struct ifconf); - ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf)); - -#ifdef _ISC - STRSET(SIOCGIFCONF, (caddr_t) ifconf, len); - if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) { -#else - /* Note that some kernels return EINVAL if the buffer is too small */ - if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL) { -#endif /* _ISC */ - efree(ifconf_buf); - (void) close(sock); - return; - } - - /* Break out of loop if we have a big enough buffer. */ - if (ifconf->ifc_len + sizeof(struct ifreq) < len) - break; - len += BUFSIZ; - } - - /* Allocate space for the maximum number of interfaces that could exist. */ - if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0) - return; - interfaces = (struct interface *) emalloc2(n, sizeof(struct interface)); - - /* For each interface, store the ip address and netmask. */ - for (i = 0; i < ifconf->ifc_len; ) { - /* Get a pointer to the current interface. */ - ifr = (struct ifreq *) &ifconf->ifc_buf[i]; - - /* Set i to the subscript of the next interface. */ - i += sizeof(struct ifreq); -#ifdef HAVE_SA_LEN - if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr)) - i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr); -#endif /* HAVE_SA_LEN */ - - /* Skip duplicates and interfaces with NULL addresses. */ - sin = (struct sockaddr_in *) &ifr->ifr_addr; - if (sin->sin_addr.s_addr == 0 || - strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0) - continue; - - if (ifr->ifr_addr.sa_family != AF_INET) - continue; - -#ifdef SIOCGIFFLAGS - zero_bytes(&ifr_tmp, sizeof(ifr_tmp)); - strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1); - if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0) -#endif - ifr_tmp = *ifr; - - /* Skip interfaces marked "down" and "loopback". */ - if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) || - ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK)) - continue; - - sin = (struct sockaddr_in *) &ifr->ifr_addr; - interfaces[num_interfaces].addr.ip4.s_addr = sin->sin_addr.s_addr; - - /* Stash the name of the interface we saved. */ - previfname = ifr->ifr_name; - - /* Get the netmask. */ - zero_bytes(&ifr_tmp, sizeof(ifr_tmp)); - strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1); -#ifdef SIOCGIFNETMASK -#ifdef _ISC - STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp)); - if (ioctl(sock, I_STR, (caddr_t) &strioctl) == 0) { -#else - if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) == 0) { -#endif /* _ISC */ - sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr; - - interfaces[num_interfaces].netmask.ip4.s_addr = sin->sin_addr.s_addr; + } } else { -#else - { -#endif /* SIOCGIFNETMASK */ - if (IN_CLASSC(interfaces[num_interfaces].addr.ip4.s_addr)) - interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSC_NET); - else if (IN_CLASSB(interfaces[num_interfaces].addr.ip4.s_addr)) - interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSB_NET); - else - interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSA_NET); + /* IPv4 */ + ifp->family = AF_INET6; + ifp->addr.ip4.s_addr = inet_addr(addr); + ifp->netmask.ip4.s_addr = inet_addr(mask); + if (ifp->addr.ip4.s_addr == (in_addr_t)-1 || + ifp->netmask.ip4.s_addr == (in_addr_t)-1) { + efree(ifp); + continue; + } } - - /* Only now can we be sure it was a good/interesting interface. */ - interfaces[num_interfaces].family = AF_INET; - num_interfaces++; + ifp->next = interfaces; + interfaces = ifp; } - - /* If the expected size < real size, realloc the array. */ - if (n != num_interfaces) { - if (num_interfaces != 0) - interfaces = (struct interface *) erealloc3(interfaces, - num_interfaces, sizeof(struct interface)); - else - efree(interfaces); - } - efree(ifconf_buf); - (void) close(sock); + efree(addrinfo); } -#else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */ - -/* - * Stub function for those without SIOCGIFCONF - */ void -load_interfaces(void) +dump_interfaces(const char *ai) { - return; -} + char *cp, *addrinfo; -#endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */ - -void -dump_interfaces(void) -{ - int i; -#ifdef HAVE_IN6_ADDR - char addrbuf[INET6_ADDRSTRLEN], maskbuf[INET6_ADDRSTRLEN]; -#endif + addrinfo = estrdup(ai); sudo_printf(SUDO_CONV_INFO_MSG, "Local IP address and netmask pairs:\n"); - for (i = 0; i < num_interfaces; i++) { - switch(interfaces[i].family) { - case AF_INET: - sudo_printf(SUDO_CONV_INFO_MSG, - "\t%s / ", inet_ntoa(interfaces[i].addr.ip4)); - sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", - inet_ntoa(interfaces[i].netmask.ip4)); - break; -#ifdef HAVE_IN6_ADDR - case AF_INET6: - inet_ntop(AF_INET6, &interfaces[i].addr.ip6, - addrbuf, sizeof(addrbuf)); - inet_ntop(AF_INET6, &interfaces[i].netmask.ip6, - maskbuf, sizeof(maskbuf)); - sudo_printf(SUDO_CONV_INFO_MSG, - "\t%s / %s\n", addrbuf, maskbuf); - break; -#endif /* HAVE_IN6_ADDR */ - } - } + for (cp = strtok(addrinfo, " \t"); cp != NULL; cp = strtok(NULL, " \t")) + sudo_printf(SUDO_CONV_INFO_MSG, "\t%s\n", cp); + + efree(addrinfo); } diff --git a/plugins/sudoers/interfaces.h b/plugins/sudoers/interfaces.h index 20aa7f641..234d31df9 100644 --- a/plugins/sudoers/interfaces.h +++ b/plugins/sudoers/interfaces.h @@ -39,20 +39,21 @@ struct interface { int family; /* AF_INET or AF_INET6 */ union sudo_in_addr_un addr; union sudo_in_addr_un netmask; + struct interface *next; }; /* * Prototypes for external functions. */ -void load_interfaces(void); -void dump_interfaces(void); +int get_net_ifs(char **addrinfo); +void dump_interfaces(const char *); +void set_interfaces(const char *); /* * Definitions for external variables. */ #ifndef _SUDO_MAIN extern struct interface *interfaces; -extern int num_interfaces; #endif #endif /* _SUDO_INTERFACES_H */ diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c index acdabd825..3cda79f36 100644 --- a/plugins/sudoers/match.c +++ b/plugins/sudoers/match.c @@ -578,7 +578,6 @@ command_matches_dir(char *sudoers_dir, size_t dlen) static int addr_matches_if(char *n) { - int i; union sudo_in_addr_un addr; struct interface *ifp; #ifdef HAVE_IN6_ADDR @@ -596,8 +595,7 @@ addr_matches_if(char *n) addr.ip4.s_addr = inet_addr(n); } - for (i = 0; i < num_interfaces; i++) { - ifp = &interfaces[i]; + for (ifp = interfaces; ifp != NULL; ifp = ifp->next) { if (ifp->family != family) continue; switch(family) { @@ -673,8 +671,7 @@ addr_matches_if_netmask(char *n, char *m) } #endif /* HAVE_IN6_ADDR */ - for (i = 0; i < num_interfaces; i++) { - ifp = &interfaces[i]; + for (ifp = interfaces; ifp != NULL; ifp = ifp->next) { if (ifp->family != family) continue; switch(family) { diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 21d702109..18606e7de 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -123,7 +123,7 @@ char *prev_user; struct sudo_user sudo_user; struct passwd *list_pw; struct interface *interfaces; -int num_interfaces; +static const char *interfaces_string; int long_list; int debug_level; uid_t timestamp_uid; @@ -203,9 +203,6 @@ sudoers_policy_open(unsigned int version, sudo_conv_t conversation, /* Setup defaults data structures. */ init_defaults(); - /* Load the list of local ip addresses and netmasks. */ - load_interfaces(); - /* Parse settings and user_info */ sudo_mode = deserialize_info(settings, user_info); @@ -1154,7 +1151,7 @@ sudoers_policy_version(int verbose) dump_auth_methods(); dump_defaults(); sudo_printf(SUDO_CONV_INFO_MSG, "\n"); - dump_interfaces(); + dump_interfaces(interfaces_string); sudo_printf(SUDO_CONV_INFO_MSG, "\n"); } return TRUE; @@ -1257,6 +1254,11 @@ deserialize_info(char * const settings[], char * const user_info[]) continue; } #endif + if (MATCHES(*cur, "network_addrs=")) { + interfaces_string = *cur + sizeof("network_addrs=") - 1; + set_interfaces(interfaces_string); + continue; + } } for (cur = user_info; *cur != NULL; cur++) { diff --git a/plugins/sudoers/testsudoers.c b/plugins/sudoers/testsudoers.c index f72684523..c66298e10 100644 --- a/plugins/sudoers/testsudoers.c +++ b/plugins/sudoers/testsudoers.c @@ -101,7 +101,6 @@ extern struct passwd *getpwuid(uid_t); */ int NewArgc; char **NewArgv; -int num_interfaces; struct interface *interfaces; struct sudo_user sudo_user; struct passwd *list_pw; @@ -234,7 +233,8 @@ main(int argc, char *argv[]) init_defaults(); /* Load ip addr/mask for each interface. */ - load_interfaces(); + if (get_net_ifs(&p) > 0) + set_interfaces(p); /* Allocate space for data structures in the parser. */ init_parser("sudoers", 0); diff --git a/plugins/sudoers/visudo.c b/plugins/sudoers/visudo.c index fb9741937..de3921d82 100644 --- a/plugins/sudoers/visudo.c +++ b/plugins/sudoers/visudo.c @@ -130,7 +130,6 @@ extern int optind; /* * Globals */ -int num_interfaces; struct interface *interfaces; struct sudo_user sudo_user; struct passwd *list_pw; diff --git a/src/net_ifs.c b/src/net_ifs.c index 1a2f455a4..10a34edad 100644 --- a/src/net_ifs.c +++ b/src/net_ifs.c @@ -80,7 +80,9 @@ struct rtentry; # include #endif -#include "sudo.h" +#include "missing.h" +#include "alloc.h" +#include "error.h" /* Minix apparently lacks IFF_LOOPBACK */ #ifndef IFF_LOOPBACK