diff options
Diffstat (limited to 'usr.bin/sudo/parse.c')
-rw-r--r-- | usr.bin/sudo/parse.c | 154 |
1 files changed, 131 insertions, 23 deletions
diff --git a/usr.bin/sudo/parse.c b/usr.bin/sudo/parse.c index 243a463c0a0..5abf5f4ffe7 100644 --- a/usr.bin/sudo/parse.c +++ b/usr.bin/sudo/parse.c @@ -25,6 +25,7 @@ #include <sys/types.h> #include <sys/param.h> +#include <sys/socket.h> #include <sys/stat.h> #include <stdio.h> #ifdef STDC_HEADERS @@ -89,7 +90,7 @@ #endif /* HAVE_EXTENDED_GLOB */ #ifndef lint -__unused static const char rcsid[] = "$Sudo: parse.c,v 1.160.2.11 2007/08/02 02:09:10 millert Exp $"; +__unused static const char rcsid[] = "$Sudo: parse.c,v 1.160.2.12 2007/08/13 16:30:02 millert Exp $"; #endif /* lint */ /* @@ -382,22 +383,85 @@ command_matches(sudoers_cmnd, sudoers_args) } } -/* - * Returns TRUE if "n" is one of our ip addresses or if - * "n" is a network that we are on, else returns FALSE. - */ -int -addr_matches(n) +static int +addr_matches_if(n) char *n; { int i; + struct in_addr addr; + struct interface *ifp; +#ifdef AF_INET6 + struct in6_addr addr6; + int j; +#endif + int family = AF_UNSPEC; + +#ifdef AF_INET6 + if (inet_pton(AF_INET6, n, &addr6) > 0) { + family = AF_INET6; + } else +#else + { + family = AF_INET; + addr.s_addr = inet_addr(n); + } +#endif + + for (i = 0; i < num_interfaces; i++) { + ifp = &interfaces[i]; + if (ifp->family != family) + continue; + switch(family) { + case AF_INET: + if (ifp->addr.ip4.s_addr == addr.s_addr || + (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr) + == addr.s_addr) + return(TRUE); + break; +#ifdef AF_INET6 + case AF_INET6: + if (memcmp(ifp->addr.ip6.s6_addr, addr6.s6_addr, + sizeof(addr6.s6_addr)) == 0) + return(TRUE); + for (j = 0; j < sizeof(addr6.s6_addr); j++) { + if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr6.s6_addr[j]) + break; + } + if (j == sizeof(addr6.s6_addr)) + return(TRUE); +#endif /* AF_INET6 */ + } + } + + return(FALSE); +} + +static int +addr_matches_if_netmask(n, m) + char *n; char *m; +{ + int i; struct in_addr addr, mask; + struct interface *ifp; +#ifdef AF_INET6 + struct in6_addr addr6, mask6; + int j; +#endif + int family = AF_UNSPEC; - /* If there's an explicit netmask, use it. */ - if ((m = strchr(n, '/'))) { - *m++ = '\0'; +#ifdef AF_INET6 + if (inet_pton(AF_INET6, n, &addr6) > 0) + family = AF_INET6; + else +#else + { + family = AF_INET; addr.s_addr = inet_addr(n); + } +#endif + + if (family == AF_INET) { if (strchr(m, '.')) mask.s_addr = inet_addr(m); else { @@ -407,25 +471,69 @@ addr_matches(n) mask.s_addr <<= i; mask.s_addr = htonl(mask.s_addr); } - *(m - 1) = '/'; - - for (i = 0; i < num_interfaces; i++) - if ((interfaces[i].addr.s_addr & mask.s_addr) == addr.s_addr) - return(TRUE); - } else { - addr.s_addr = inet_addr(n); - - for (i = 0; i < num_interfaces; i++) - if (interfaces[i].addr.s_addr == addr.s_addr || - (interfaces[i].addr.s_addr & interfaces[i].netmask.s_addr) - == addr.s_addr) - return(TRUE); + } +#ifdef AF_INET6 + else { + if (inet_pton(AF_INET6, m, &mask6) <= 0) { + j = atoi(m); + for (i = 0; i < 16; i++) { + if (j < i * 8) + mask6.s6_addr[i] = 0; + else if (i * 8 + 8 <= j) + mask6.s6_addr[i] = 0xff; + else + mask6.s6_addr[i] = 0xff00 >> (j - i * 8); + } + } + } +#endif /* AF_INET6 */ + + for (i = 0; i < num_interfaces; i++) { + ifp = &interfaces[i]; + if (ifp->family != family) + continue; + switch(family) { + case AF_INET: + if ((ifp->addr.ip4.s_addr & mask.s_addr) == addr.s_addr) + return(TRUE); +#ifdef AF_INET6 + case AF_INET6: + for (j = 0; j < sizeof(addr6.s6_addr); j++) { + if ((ifp->addr.ip6.s6_addr[j] & mask6.s6_addr[j]) != addr6.s6_addr[j]) + break; + } + if (j == sizeof(addr6.s6_addr)) + return(TRUE); +#endif /* AF_INET6 */ + } } return(FALSE); } /* + * Returns TRUE if "n" is one of our ip addresses or if + * "n" is a network that we are on, else returns FALSE. + */ +int +addr_matches(n) + char *n; +{ + char *m; + int retval; + + /* If there's an explicit netmask, use it. */ + if ((m = strchr(n, '/'))) { + *m++ = '\0'; + retval = addr_matches_if_netmask(n, m); + *(m - 1) = '/'; + } else + retval = addr_matches_if(n); + + return(retval); +} + +/* * Returns 0 if the hostname matches the pattern and non-zero otherwise. */ int |