--- sudo-1.6.8p12/Makefile.in.ipv6 2005-11-08 19:21:58.000000000 +0100 +++ sudo-1.6.8p12/Makefile.in 2006-07-16 23:33:58.000000000 +0200 @@ -187,14 +187,14 @@ @DEV@PARSESRCS = sudo.tab.h sudo.tab.c lex.yy.c def_data.c def_data.h # Uncomment the following if you intend to modify parse.yacc -@DEV@sudo.tab.c sudo.tab.h: parse.yacc -@DEV@ rm -f sudo.tab.h sudo.tab.c -@DEV@ $(YACC) -d -b sudo $(srcdir)/parse.yacc +sudo.tab.c sudo.tab.h: parse.yacc + rm -f sudo.tab.h sudo.tab.c + $(YACC) -d -b sudo $(srcdir)/parse.yacc # Uncomment the following if you intend to modify parse.lex -@DEV@lex.yy.c: parse.lex -@DEV@ rm -f lex.yy.c -@DEV@ $(LEX) $(srcdir)/parse.lex +lex.yy.c: parse.lex + rm -f lex.yy.c + $(LEX) $(srcdir)/parse.lex # Uncomment the following if you intend to modify def_data.in @DEV@def_data.h def_data.c: def_data.in --- sudo-1.6.8p12/visudo.c.ipv6 2004-11-25 18:32:40.000000000 +0100 +++ sudo-1.6.8p12/visudo.c 2006-07-16 23:33:58.000000000 +0200 @@ -87,6 +87,7 @@ static int check_syntax __P((int)); int command_matches __P((char *, char *)); int addr_matches __P((char *)); +int addr6_matches __P((char *)); int hostname_matches __P((char *, char *, char *)); int netgr_matches __P((char *, char *, char *, char *)); int usergr_matches __P((char *, char *, struct passwd *)); @@ -515,6 +516,12 @@ return(TRUE); } +int addr6_matches(n) + char *n; +{ + return(TRUE); +} + int hostname_matches(s, l, p) char *s, *l, *p; --- sudo-1.6.8p12/parse.lex.ipv6 2004-05-17 22:51:13.000000000 +0200 +++ sudo-1.6.8p12/parse.lex 2006-07-16 23:33:58.000000000 +0200 @@ -84,6 +84,29 @@ OCTET (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]) DOTTEDQUAD {OCTET}(\.{OCTET}){3} + +IPV6_8HEX ([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4} + +IPV6_COMP0 :(:[0-9A-Fa-f]{1,4}){1,7} +IPV6_COMP1 ([0-9A-Fa-f]{1,4}){1}:(:[0-9A-Fa-f]{1,4}){0,6} +IPV6_COMP2 ([0-9A-Fa-f]{1,4}){2}:(:[0-9A-Fa-f]{1,4}){0,5} +IPV6_COMP3 ([0-9A-Fa-f]{1,4}){3}:(:[0-9A-Fa-f]{1,4}){0,4} +IPV6_COMP4 ([0-9A-Fa-f]{1,4}){4}:(:[0-9A-Fa-f]{1,4}){0,3} +IPV6_COMP5 ([0-9A-Fa-f]{1,4}){5}:(:[0-9A-Fa-f]{1,4}){0,2} +IPV6_COMP6 ([0-9A-Fa-f]{1,4}){6}:(:[0-9A-Fa-f]{1,4}){0,1} +IPV6_COMPHEX {IPV6_COMP0}|{IPV6_COMP1}|{IPV6_COMP2}|{IPV6_COMP3}|{IPV6_COMP4}|{IPV6_COMP5}|{IPV6_COMP6} + +IPV6_6H4D [0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){5}{DOTTEDQUAD} + +IPV6_COMP6H4D0 ([0-9A-Fa-f]{1,4}){1}:(:[0-9A-Fa-f]{1,4}){1,4}:{DOTTEDQUAD} +IPV6_COMP6H4D1 ([0-9A-Fa-f]{1,4}){2}:(:[0-9A-Fa-f]{1,4}){1,3}:{DOTTEDQUAD} +IPV6_COMP6H4D2 ([0-9A-Fa-f]{1,4}){3}:(:[0-9A-Fa-f]{1,4}){1,2}:{DOTTEDQUAD} +IPV6_COMP6H4D3 ([0-9A-Fa-f]{1,4}){4}:(:[0-9A-Fa-f]{1,4}){1}:{DOTTEDQUAD} +IPV6_COMP6H4D {IPV6_COMP6H4D0}|{IPV6_COMP6H4D1}|{IPV6_COMP6H4D2}|{IPV6_COMP6H4D3} + +IPV6ADDR {IPV6_8HEX}|{IPV6_COMPHEX}|{IPV6_6H4D}|{IPV6_COMP6H4D} +IPV6PREFIX [1-9]|[1-9][0-9]|10[0-9]|11[0-9]|12[0-8] + HOSTNAME [[:alnum:]_-]+ WORD ([^#>@!=:,\(\) \t\n\\]|\\[^\n])+ ENVAR ([^#!=, \t\n\\]|\\[^\n])([^#=, \t\n\\]|\\[^\n])* @@ -253,6 +276,11 @@ LEXTRACE("NTWKADDR "); return(NTWKADDR); } +{IPV6ADDR}(\/{IPV6PREFIX})? { + fill(yytext, yyleng); + LEXTRACE("NTWKADDR6 "); + return(NTWKADDR6); + } \( { BEGIN GOTRUNAS; --- sudo-1.6.8p12/ldap.c.ipv6 2006-07-16 23:45:35.000000000 +0200 +++ sudo-1.6.8p12/ldap.c 2006-07-16 23:59:56.000000000 +0200 @@ -160,6 +160,7 @@ if ( !strcasecmp(*p,"ALL") || addr_matches(*p) || + addr6_matches(*p) || netgr_matches(*p,user_host,user_shost,NULL) || !hostname_matches(user_shost,user_host,*p) ) --- sudo-1.6.8p12/parse.h.ipv6 2005-06-19 20:58:19.000000000 +0200 +++ sudo-1.6.8p12/parse.h 2006-07-16 23:33:58.000000000 +0200 @@ -93,6 +93,7 @@ * Prototypes */ int addr_matches __P((char *)); +int addr6_matches __P((char *)); int command_matches __P((char *, char *)); int hostname_matches __P((char *, char *, char *)); int netgr_matches __P((char *, char *, char *, char *)); --- sudo-1.6.8p12/interfaces.h.ipv6 2004-02-13 22:36:43.000000000 +0100 +++ sudo-1.6.8p12/interfaces.h 2006-07-16 23:33:58.000000000 +0200 @@ -27,8 +27,11 @@ * IP address and netmask pairs for checking against local interfaces. */ struct interface { - struct in_addr addr; + struct in_addr addr; /* IPv4 */ struct in_addr netmask; + struct in6_addr addr6; /* IPv6 */ + struct in6_addr netmask6; + sa_family_t sa_family; /* AF_INET ? AF_INET6 */ }; /* --- sudo-1.6.8p12/parse.c.ipv6 2005-06-19 22:03:24.000000000 +0200 +++ sudo-1.6.8p12/parse.c 2006-07-16 23:57:20.000000000 +0200 @@ -370,38 +370,134 @@ int i; char *m; struct in_addr addr, mask; + struct addrinfo hints, *ai; + + memset(&hints, '\0', sizeof(hints)); + hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; + hints.ai_family = AF_INET; /* If there's an explicit netmask, use it. */ if ((m = strchr(n, '/'))) { + *m++ = '\0'; - addr.s_addr = inet_addr(n); + if (getaddrinfo(n, NULL, &hints, &ai)!=0) + return(FALSE); + memcpy(&addr.s_addr, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, + sizeof(struct in_addr)); + freeaddrinfo(ai); + if (strchr(m, '.')) - mask.s_addr = inet_addr(m); - else { - i = 32 - atoi(m); - mask.s_addr = 0xffffffff; - mask.s_addr >>= i; - mask.s_addr <<= i; - mask.s_addr = htonl(mask.s_addr); + { + if (getaddrinfo(m, NULL, &hints, &ai)!=0) + return(FALSE); + memcpy(&mask.s_addr, /* IPv4 netmask from dotted quad */ + &((struct sockaddr_in *)ai->ai_addr)->sin_addr, + sizeof(struct in_addr)); } + else + { + i = 32 - atoi(m); /* IPv4 netmask from CIDR */ + mask.s_addr = 0xffffffff; + mask.s_addr >>= i; + 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); + for (i = 0; i < num_interfaces; ++i) + if (interfaces[i].sa_family == AF_INET) /* IPv4 intf. only */ + if ((interfaces[i].addr.s_addr & mask.s_addr) == addr.s_addr) + return (TRUE); } else { - addr.s_addr = inet_addr(n); + if (getaddrinfo(n, NULL, &hints, &ai)!=0) + return(FALSE); + memcpy(&addr.s_addr, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, + sizeof(struct in_addr)); + freeaddrinfo(ai); 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); + if (interfaces[i].sa_family == AF_INET) /* IPv4 intf. only */ + if (interfaces[i].addr.s_addr == addr.s_addr || + (interfaces[i].addr.s_addr & interfaces[i].netmask.s_addr) + == addr.s_addr) + return(TRUE); } return(FALSE); } +int +addr6_matches(n) +char *n; +{ + int i, j; + uint32_t msk[4] = {0, 0, 0, 0}; /* 32x4 */ + uint32_t addr[4], i_msk[4], i_addr[4]; + char *m; + struct addrinfo hints, *ai; + + memset(&hints, '\0', sizeof(hints)); + hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; + hints.ai_family = AF_INET6; + + /* we have IPv6 prefix */ + if ((m = strchr(n, '/'))) { + *m++ = '\0'; + if (getaddrinfo(n, NULL, &hints, &ai)!=0) + return(FALSE); + memcpy(&addr, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, 16); + freeaddrinfo(ai); + + for (i=0; i < (atoi(m)/32); ++i) + msk[i] = 0xffffffff; + if (atoi(m)<128 && (atoi(m) % 32)) + { + msk[atoi(m)/32] = 0xffffffff; + msk[atoi(m)/32] >>= ( 32 - (atoi(m) % 32) ); + msk[atoi(m)/32] <<= ( 32 - (atoi(m) % 32) ); + } + for (i=0; i<4; ++i) + msk[i] = htonl(msk[i]); + + *(m - 1) = '/'; + + for (i=0; i < num_interfaces; i++) + if (interfaces[i].sa_family == AF_INET6) /* compare only IPv6 intf. */ + { + /* nasty */ + memcpy(&i_addr, &interfaces[i].addr6, 16); + if ( ((i_addr[0] & msk[0]) == addr[0]) && + ((i_addr[1] & msk[1]) == addr[1]) && + ((i_addr[2] & msk[2]) == addr[2]) && + ((i_addr[3] & msk[3]) == addr[3])) + return(TRUE); + } + } else { + if (getaddrinfo(n, NULL, &hints, &ai)!=0) + return(FALSE); + memcpy(&addr, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, 16); + freeaddrinfo(ai); + + for (i=0; i < num_interfaces; ++i) + if (interfaces[i].sa_family == AF_INET6) /* IPv6 intf. only */ + { + memcpy(&i_addr, &interfaces[i].addr6, 16); + if ((i_addr[0] == addr[0]) && (i_addr[1] == addr[1]) && + (i_addr[2] == addr[2]) && (i_addr[3] == addr[3])) + return(TRUE); /* found my own address in sudoers */ + + memcpy(&i_msk, &interfaces[i].netmask6, 16); + if (((i_addr[0]&i_msk[0]) == addr[0]) && + ((i_addr[1]&i_msk[1]) == addr[1]) && + ((i_addr[2]&i_msk[2]) == addr[2]) && + ((i_addr[3]&i_msk[3]) == addr[3])) + return(TRUE); /* found my netw. address in sudoers */ + } + } + return(FALSE); +} + /* * Returns 0 if the hostname matches the pattern and non-zero otherwise. */ --- sudo-1.6.8p12/sudo.c.ipv6 2006-07-16 23:33:58.000000000 +0200 +++ sudo-1.6.8p12/sudo.c 2006-07-16 23:33:58.000000000 +0200 @@ -1007,24 +1007,34 @@ void set_fqdn() { - struct hostent *hp; + struct addrinfo hints, *ai; char *p; - if (!(hp = gethostbyname(user_host))) { - log_error(MSG_ONLY|NO_EXIT, - "unable to lookup %s via gethostbyname()", user_host); - } else { - if (user_shost != user_host) + memset(&hints, '\0', sizeof(hints)); + hints.ai_flags = AI_ADDRCONFIG; + + if (getaddrinfo(user_host, NULL, &hints, &ai) != 0) + { + log_error(MSG_ONLY|NO_EXIT, + "unable to lookup %s via gethostbyname()", user_host); + } + else + { + char h_name[NI_MAXHOST]; + + if (user_host != user_host) free(user_shost); + + getnameinfo(ai->ai_addr, ai->ai_addrlen, h_name, sizeof(h_name), NULL, 0, 0); free(user_host); - user_host = estrdup(hp->h_name); + user_host = estrdup(h_name); } if ((p = strchr(user_host, '.'))) { - *p = '\0'; - user_shost = estrdup(user_host); - *p = '.'; + *p = '\0'; + user_shost = estrdup(user_host); + *p = '.'; } else { - user_shost = user_host; + user_shost = user_host; } } --- sudo-1.6.8p12/parse.yacc.ipv6 2005-06-19 20:24:32.000000000 +0200 +++ sudo-1.6.8p12/parse.yacc 2006-07-16 23:33:58.000000000 +0200 @@ -250,6 +250,7 @@ %token RUNASALIAS /* Runas_Alias keyword */ %token ':' '=' ',' '!' '+' '-' /* union member tokens */ %token ERROR +%token NTWKADDR6 /* IPv6 address */ /* * NOTE: these are not true booleans as there are actually 4 possible values: @@ -395,6 +396,13 @@ $$ = NOMATCH; free($1); } + | NTWKADDR6 { + if (addr6_matches($1)) + $$ = TRUE; + else + $$ = NOMATCH; + free($1); + } | NETGROUP { if (netgr_matches($1, user_host, user_shost, NULL)) $$ = TRUE; --- sudo-1.6.8p12/testsudoers.c.ipv6 2004-08-02 20:44:58.000000000 +0200 +++ sudo-1.6.8p12/testsudoers.c 2006-07-17 00:03:50.000000000 +0200 @@ -175,6 +175,10 @@ } } +/* + * 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; @@ -182,39 +186,136 @@ int i; char *m; struct in_addr addr, mask; + struct addrinfo hints, *ai; + + memset(&hints, '\0', sizeof(hints)); + hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; + hints.ai_family = AF_INET; /* If there's an explicit netmask, use it. */ if ((m = strchr(n, '/'))) { - *m++ = '\0'; - addr.s_addr = inet_addr(n); - if (strchr(m, '.')) - mask.s_addr = inet_addr(m); - else { - i = 32 - atoi(m); - mask.s_addr = 0xffffffff; - mask.s_addr >>= i; - 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); + *m++ = '\0'; + if (getaddrinfo(n, NULL, &hints, &ai)!=0) + return(FALSE); + memcpy(&addr.s_addr, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, + sizeof(struct in_addr)); + freeaddrinfo(ai); + + if (strchr(m, '.')) + { + if (getaddrinfo(m, NULL, &hints, &ai)!=0) + return(FALSE); + memcpy(&mask.s_addr, /* IPv4 netmask from dotted quad */ + &((struct sockaddr_in *)ai->ai_addr)->sin_addr, + sizeof(struct in_addr)); + } + else + { + i = 32 - atoi(m); /* IPv4 netmask from CIDR */ + mask.s_addr = 0xffffffff; + mask.s_addr >>= i; + mask.s_addr <<= i; + mask.s_addr = htonl(mask.s_addr); + } + + *(m - 1) = '/'; + + for (i = 0; i < num_interfaces; ++i) + if (interfaces[i].sa_family == AF_INET) /* IPv4 intf. only */ + 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); + if (getaddrinfo(n, NULL, &hints, &ai)!=0) + return(FALSE); + memcpy(&addr.s_addr, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, + sizeof(struct in_addr)); + freeaddrinfo(ai); + + for (i = 0; i < num_interfaces; i++) + if (interfaces[i].sa_family == AF_INET) /* IPv4 intf. only */ + if (interfaces[i].addr.s_addr == addr.s_addr || + (interfaces[i].addr.s_addr & interfaces[i].netmask.s_addr) + == addr.s_addr) + return(TRUE); } return(FALSE); } int +addr6_matches(n) +char *n; +{ + int i, j; + uint32_t msk[4] = {0, 0, 0, 0}; /* 32x4 */ + uint32_t addr[4], i_msk[4], i_addr[4]; + char *m; + struct addrinfo hints, *ai; + + memset(&hints, '\0', sizeof(hints)); + hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; + hints.ai_family = AF_INET6; + + /* we have IPv6 prefix */ + if ((m = strchr(n, '/'))) { + *m++ = '\0'; + if (getaddrinfo(n, NULL, &hints, &ai)!=0) + return(FALSE); + memcpy(&addr, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, 16); + freeaddrinfo(ai); + + for (i=0; i < (atoi(m)/32); ++i) + msk[i] = 0xffffffff; + if (atoi(m)<128 && (atoi(m) % 32)) + { + msk[atoi(m)/32] = 0xffffffff; + msk[atoi(m)/32] >>= ( 32 - (atoi(m) % 32) ); + msk[atoi(m)/32] <<= ( 32 - (atoi(m) % 32) ); + } + for (i=0; i<4; ++i) + msk[i] = htonl(msk[i]); + + *(m - 1) = '/'; + + for (i=0; i < num_interfaces; i++) + if (interfaces[i].sa_family == AF_INET6) /* compare only IPv6 intf. */ + { + /* nasty */ + memcpy(&i_addr, &interfaces[i].addr6, 16); + if ( ((i_addr[0] & msk[0]) == addr[0]) && + ((i_addr[1] & msk[1]) == addr[1]) && + ((i_addr[2] & msk[2]) == addr[2]) && + ((i_addr[3] & msk[3]) == addr[3])) + return (TRUE); + } + } else { + if (getaddrinfo(n, NULL, &hints, &ai)!=0) + return(FALSE); + memcpy(&addr, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, 16); + freeaddrinfo(ai); + + for (i=0; i < num_interfaces; ++i) + if (interfaces[i].sa_family == AF_INET6) /* IPv6 intf. only */ + { + memcpy(&i_addr, &interfaces[i].addr6, 16); + if ((i_addr[0] == addr[0]) && (i_addr[1] == addr[1]) && + (i_addr[2] == addr[2]) && (i_addr[3] == addr[3])) + return (TRUE); /* found my own address in sudoers */ + + memcpy(&i_msk, &interfaces[i].netmask6, 16); + if (((i_addr[0]&i_msk[0]) == addr[0]) && + ((i_addr[1]&i_msk[1]) == addr[1]) && + ((i_addr[2]&i_msk[2]) == addr[2]) && + ((i_addr[3]&i_msk[3]) == addr[3])) + return (TRUE); /* found my netw. address in sudoers */ + } + } + return(FALSE); +} + + +int hostname_matches(shost, lhost, pattern) char *shost; char *lhost; --- sudo-1.6.8p12/interfaces.c.ipv6 2004-02-13 22:36:43.000000000 +0100 +++ sudo-1.6.8p12/interfaces.c 2006-07-16 23:33:58.000000000 +0200 @@ -102,7 +102,7 @@ load_interfaces() { struct ifaddrs *ifa, *ifaddrs; - /* XXX - sockaddr_in6 sin6; */ + struct sockaddr_in6 *sin6; struct sockaddr_in *sin; int i; @@ -117,12 +117,15 @@ continue; switch(ifa->ifa_addr->sa_family) { - /* XXX - AF_INET6 */ case AF_INET: num_interfaces++; break; + case AF_INET6: + num_interfaces++; + break; } } + if (num_interfaces == 0) return; interfaces = @@ -136,8 +139,8 @@ continue; switch(ifa->ifa_addr->sa_family) { - /* XXX - AF_INET6 */ case AF_INET: + interfaces[i].sa_family = AF_INET; sin = (struct sockaddr_in *)ifa->ifa_addr; memcpy(&interfaces[i].addr, &sin->sin_addr, sizeof(struct in_addr)); @@ -146,6 +149,16 @@ sizeof(struct in_addr)); i++; break; + case AF_INET6: + interfaces[i].sa_family = AF_INET6; + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + memcpy(&interfaces[i].addr6, &sin6->sin6_addr, + sizeof(struct in6_addr)); + sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask; + memcpy(&interfaces[i].netmask6, &sin6->sin6_addr, + sizeof(struct in6_addr)); + i++; + break; } } #ifdef HAVE_FREEIFADDRS @@ -306,10 +319,30 @@ void dump_interfaces() { - int i; + int i, j, ip6_prefix=0; /* for counting IPv6 prefix length (in bits!!) */ + uint8_t u6_addr8[16]; /* for storing IPv6 netmask */ puts("Local IP address and netmask pairs:"); for (i = 0; i < num_interfaces; i++) - printf("\t%s / 0x%x\n", inet_ntoa(interfaces[i].addr), - (unsigned int)ntohl(interfaces[i].netmask.s_addr)); + { + char name[NI_MAXHOST], netmask[NI_MAXHOST]; + ip6_prefix=0; + + switch (interfaces[i].sa_family) + { + case AF_INET: + inet_ntop(AF_INET, &interfaces[i].addr, name, NI_MAXHOST); + inet_ntop(AF_INET, &interfaces[i].netmask, netmask, NI_MAXHOST); + printf("\t%s / %s\n", name, netmask); + break; + case AF_INET6: + inet_ntop(AF_INET6, &interfaces[i].addr6, name, NI_MAXHOST); + memcpy(u6_addr8, &interfaces[i].netmask6, 16); + for (j=0; j<16; ++j) + if (u6_addr8[j] == 255) /* 255 == 0xff */ + ip6_prefix=ip6_prefix+8; /* eight bits */ + printf("\t%s / %d\n", name, ip6_prefix); + break; + } + } }