Date: Sat, 17 Mar 2001 23:37:58 +0900 (JST) From: Hajimu UMEMOTO <ume@FreeBSD.org> To: audit@FreeBSD.org, net@FreeBSD.org Subject: [CFR] IPv6 support for skeyaccess(3) Message-ID: <20010317.233758.21880242.ume@FreeBSD.org>
next in thread | raw e-mail | index | archive | help
Hi, I wish to support IPv6 for skeyaccess(3). With this patch, you can specify IPv6 address using `internet' keyword into /etc/skey.access. Please review it. Index: lib/libskey/skeyaccess.c diff -u lib/libskey/skeyaccess.c.orig lib/libskey/skeyaccess.c --- lib/libskey/skeyaccess.c.orig Mon Oct 26 20:54:36 1998 +++ lib/libskey/skeyaccess.c Fri Mar 16 03:04:48 2001 @@ -63,8 +63,8 @@ static int match_group __P((struct login_info *)); static int match_token __P((char *)); static int is_internet_addr __P((char *)); -static struct in_addr *convert_internet_addr __P((char *)); -static struct in_addr *lookup_internet_addr __P((char *)); +static struct addrinfo *convert_internet_addr __P((char *)); +static struct addrinfo *lookup_internet_addr __P((char *)); #define MAX_ADDR 32 #define PERMIT 1 @@ -79,7 +79,7 @@ struct login_info { char *host_name; /* host name */ - struct in_addr *internet_addr; /* null terminated list */ + struct addrinfo *internet_addr; /* addrinfo chain */ char *user; /* user name */ char *port; /* login port */ }; @@ -120,22 +120,22 @@ login_info.user = user; login_info.port = port; - if (host != 0 && !is_internet_addr(host)) { + if (host != NULL && !is_internet_addr(host)) { login_info.host_name = host; } else { - login_info.host_name = 0; + login_info.host_name = NULL; } - if (addr != 0 && is_internet_addr(addr)) { + if (addr != NULL && is_internet_addr(addr)) { login_info.internet_addr = convert_internet_addr(addr); - } else if (host != 0) { + } else if (host != NULL) { if (is_internet_addr(host)) { login_info.internet_addr = convert_internet_addr(host); } else { login_info.internet_addr = lookup_internet_addr(host); } } else { - login_info.internet_addr = 0; + login_info.internet_addr = NULL; } /* @@ -146,19 +146,23 @@ printf("user: %s\n", login_info.user); printf("host: %s\n", login_info.host_name ? login_info.host_name : "none"); printf("addr: "); - if (login_info.internet_addr == 0) { + if (login_info.internet_addr == NULL) { printf("none\n"); } else { - int i; + struct addrinfo *res; + char haddr[NI_MAXHOST]; - for (i = 0; login_info.internet_addr[i].s_addr; i++) - printf("%s%s", login_info.internet_addr[i].s_addr == -1 ? - "(see error log)" : inet_ntoa(login_info.internet_addr[i]), - login_info.internet_addr[i + 1].s_addr ? " " : "\n"); + for (res = login_info.internet_addr; res; res = res->ai_next) { + getnameinfo(res->ai_addr, res->ai_addrlen, haddr, sizeof(haddr), + NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); + printf("%s%s", haddr, res->ai_next ? " " : "\n"); + } } #endif result = _skeyaccess(fp, &login_info); fclose(fp); + if (login_info.internet_addr) + freeaddrinfo(login_info.internet_addr); return (result); } @@ -226,33 +230,99 @@ return (match ? permission : DENY); } +/* translate IPv4 mapped IPv6 address to IPv4 address */ + +static void +ai_unmapped(struct addrinfo *ai) +{ + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin4; + u_int32_t addr; + int port; + + if (ai->ai_family != AF_INET6) + return; + sin6 = (struct sockaddr_in6 *)ai->ai_addr; + if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + return; + sin4 = (struct sockaddr_in *)ai->ai_addr; + addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12]; + port = sin6->sin6_port; + memset(sin4, 0, sizeof(struct sockaddr_in)); + sin4->sin_addr.s_addr = addr; + sin4->sin_port = port; + sin4->sin_family = AF_INET; + sin4->sin_len = sizeof(struct sockaddr_in); + ai->ai_family = AF_INET; + ai->ai_addrlen = sizeof(struct sockaddr_in); +} + /* match_internet_addr - match internet network address */ static int match_internet_addr(login_info) struct login_info *login_info; { - char * tok; - u_int32_t pattern; - u_int32_t mask; - struct in_addr *addrp; + char *tok; + struct addrinfo *res; + struct sockaddr_storage pattern, mask; + struct sockaddr_in *addr4, *pattern4, *mask4; + struct sockaddr_in6 *addr6, *pattern6, *mask6; + int i, match; - if (login_info->internet_addr == 0) + if (login_info->internet_addr == NULL) return (0); if ((tok = need_internet_addr()) == 0) return (0); - pattern = inet_addr(tok); + if ((res = convert_internet_addr(tok)) == NULL) + return (0); + memcpy(&pattern, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); if ((tok = need_internet_addr()) == 0) return (0); - mask = inet_addr(tok); + if ((res = convert_internet_addr(tok)) == NULL) + return (0); + memcpy(&mask, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + if (pattern.ss_family != mask.ss_family) + return (0); + mask4 = (struct sockaddr_in *)&mask; + pattern4 = (struct sockaddr_in *)&pattern; + mask6 = (struct sockaddr_in6 *)&mask; + pattern6 = (struct sockaddr_in6 *)&pattern; /* * See if any of the addresses matches a pattern in the control file. We * have already tried to drop addresses that belong to someone else. */ - for (addrp = login_info->internet_addr; addrp->s_addr; addrp++) - if (addrp->s_addr != INADDR_NONE && (addrp->s_addr & mask) == pattern) - return (1); + for (res = login_info->internet_addr; res; res = res->ai_next) { + ai_unmapped(res); + if (res->ai_family != pattern.ss_family) + continue; + switch (res->ai_family) { + case AF_INET: + addr4 = (struct sockaddr_in *)res->ai_addr; + if (addr4->sin_addr.s_addr != INADDR_NONE && + (addr4->sin_addr.s_addr & mask4->sin_addr.s_addr) == pattern4->sin_addr.s_addr) + return (1); + break; + case AF_INET6: + addr6 = (struct sockaddr_in6 *)res->ai_addr; + if (pattern6->sin6_scope_id != 0 && + addr6->sin6_scope_id != pattern6->sin6_scope_id) + break; + match = 1; + for (i = 0; i < 16; ++i) { + if ((addr6->sin6_addr.s6_addr[i] & mask6->sin6_addr.s6_addr[i]) != pattern6->sin6_addr.s6_addr[i]) { + match = 0; + break; + } + } + if (match) + return (1); + break; + } + } return (0); } @@ -369,53 +439,49 @@ static int is_internet_addr(str) char *str; { - int in_run = 0; - int runs = 0; + struct addrinfo *res; - /* Count the number of runs of characters between the dots. */ - - while (*str) { - if (*str == '.') { - in_run = 0; - } else { - if (!isdigit(*str)) - return (0); - if (in_run == 0) { - in_run = 1; - runs++; - } - } - str++; + if ((res = convert_internet_addr(str)) != NULL) + freeaddrinfo(res); + return (res != NULL); +} + +/* + * Nuke addrinfo entry from list. + * XXX: Depending on the implementation of KAME's getaddrinfo(3). + */ +static void nuke_ai(rp, res) +struct addrinfo **rp, *res; +{ + *rp = res->ai_next; + if (res->ai_canonname) { + if (res->ai_next && !res->ai_next->ai_canonname) + res->ai_next->ai_canonname = res->ai_canonname; + else + free(res->ai_canonname); } - return (runs == 4); + free(res); } /* lookup_internet_addr - look up internet addresses with extreme prejudice */ -static struct in_addr *lookup_internet_addr(host) +static struct addrinfo *lookup_internet_addr(host) char *host; { - struct hostent *hp; - static struct in_addr list[MAX_ADDR + 1]; - char buf[MAXHOSTNAMELEN + 1]; - int length; - int i; - - if ((hp = gethostbyname(host)) == 0 || hp->h_addrtype != AF_INET) - return (0); - - /* - * Save a copy of the results before gethostbyaddr() clobbers them. - */ - - for (i = 0; i < MAX_ADDR && hp->h_addr_list[i]; i++) - memcpy((char *) &list[i], - hp->h_addr_list[i], (size_t)hp->h_length); - list[i].s_addr = 0; - - strncpy(buf, hp->h_name, MAXHOSTNAMELEN); - buf[MAXHOSTNAMELEN] = 0; - length = hp->h_length; + struct addrinfo hints, *res0, *res, **rp; + char hname[NI_MAXHOST], haddr[NI_MAXHOST]; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_CANONNAME; + if (getaddrinfo(host, NULL, &hints, &res0) != 0) + return (NULL); + if (res0->ai_canonname == NULL) { + freeaddrinfo(res0); + return (NULL); + } /* * Wipe addresses that appear to belong to someone else. We will get @@ -425,31 +491,51 @@ #define NEQ(x,y) (strcasecmp((x),(y)) != 0) #define NEQ3(x,y,n) (strncasecmp((x),(y), (n)) != 0) - while (--i >= 0) { - if ((hp = gethostbyaddr((char *) &list[i], length, AF_INET)) == 0) { + rp = &res0; + for (res = res0; res; res = res->ai_next) { + if (res->ai_family != AF_INET && res->ai_family != AF_INET6) { + nuke_ai(rp, res); + continue; + } + error = getnameinfo(res->ai_addr, res->ai_addrlen, + hname, sizeof(hname), + NULL, 0, NI_NAMEREQD | NI_WITHSCOPEID); + if (error) { + getnameinfo(res->ai_addr, res->ai_addrlen, haddr, sizeof(haddr), + NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); syslog(LOG_ERR, "address %s not registered for host %s", - inet_ntoa(list[i]), buf); - list[i].s_addr = (u_int32_t) -1; + haddr, res0->ai_canonname); + nuke_ai(rp, res); + continue; } - if (NEQ(buf, hp->h_name) && NEQ3(buf, "localhost.", 10)) { + if (NEQ(res0->ai_canonname, hname) && + NEQ3(res0->ai_canonname, "localhost.", 10)) { + getnameinfo(res->ai_addr, res->ai_addrlen, haddr, sizeof(haddr), + NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); syslog(LOG_ERR, "address %s registered for host %s and %s", - inet_ntoa(list[i]), hp->h_name, buf); - list[i].s_addr = (u_int32_t) -1; + haddr, hname, res0->ai_canonname); + nuke_ai(rp, res); + continue; } + rp = &res->ai_next; } - return (list); + return (res0); } /* convert_internet_addr - convert string to internet address */ -static struct in_addr *convert_internet_addr(string) +static struct addrinfo *convert_internet_addr(string) char *string; { - static struct in_addr list[2]; + struct addrinfo hints, *res; - list[0].s_addr = inet_addr(string); - list[1].s_addr = 0; - return (list); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + if (getaddrinfo(string, NULL, &hints, &res) != 0) + return (NULL); + return (res); } #ifdef TEST @@ -458,7 +544,7 @@ int argc; char **argv; { - struct hostent *hp; + struct addrinfo hints, *res; char host[MAXHOSTNAMELEN + 1]; int verdict; char *user; @@ -475,8 +561,18 @@ user = argv[1]; port = argv[2]; if (argv[3]) { - strncpy(host, (hp = gethostbyname(argv[3])) ? - hp->h_name : argv[3], MAXHOSTNAMELEN); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_CANONNAME; + if (getaddrinfo(argv[3], NULL, &hints, &res) == 0) { + if (res->ai_canonname == NULL) + strncpy(host, argv[3], MAXHOSTNAMELEN); + else + strncpy(host, res->ai_canonname, MAXHOSTNAMELEN); + freeaddrinfo(res); + } else + strncpy(host, argv[3], MAXHOSTNAMELEN); host[MAXHOSTNAMELEN] = 0; } verdict = skeyaccess(user, port, argv[3] ? host : (char *) 0, (char *) 0); -- Hajimu UMEMOTO @ Internet Mutual Aid Society Yokohama, Japan ume@mahoroba.org ume@bisd.hitachi.co.jp ume@{,jp.}FreeBSD.org http://www.imasy.org/~ume/ To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-audit" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010317.233758.21880242.ume>