#include <malloc.h>
#include <netdb.h>
#include <sys/syslog.h>
+#include <ctype.h>
#include "nls.h"
#include <sys/sysmacros.h>
return 0;
}
-/* match the hostname hn against the pattern pat */
+
+/* IPv4 -- pattern is x.x.x.x/y.y.y.y (net/mask)*/
static int
-hnmatch(const char *hn, const char *pat)
+hnmatch_ip4(const char *pat)
{
- int x1, x2, x3, x4, y1, y2, y3, y4;
- unsigned long p, mask, a;
- unsigned char *ha;
- int n, m;
+ int x1, x2, x3, x4, y1, y2, y3, y4;
+ unsigned long p, mask, a;
+ unsigned char *ha;
- if ((hn == NULL) && (strcmp(pat, "localhost") == 0)) return 1;
- if ((hn == NULL) || hn[0] == 0) return 0;
-
- if (pat[0] >= '0' && pat[0] <= '9') {
/* pattern is an IP QUAD address and a mask x.x.x.x/y.y.y.y */
- sscanf(pat, "%d.%d.%d.%d/%d.%d.%d.%d", &x1, &x2, &x3, &x4,
- &y1, &y2, &y3, &y4);
+ if (sscanf(pat, "%d.%d.%d.%d/%d.%d.%d.%d",
+ &x1, &x2, &x3, &x4, &y1, &y2, &y3, &y4) < 8)
+ return 0;
+
p = (((unsigned long)x1<<24)+((unsigned long)x2<<16)
+((unsigned long)x3<<8)+((unsigned long)x4));
mask = (((unsigned long)y1<<24)+((unsigned long)y2<<16)
a = (((unsigned long)ha[0]<<24)+((unsigned long)ha[1]<<16)
+((unsigned long)ha[2]<<8)+((unsigned long)ha[3]));
return ((p & mask) == (a & mask));
- } else {
- /* pattern is a suffix of a FQDN */
- n = strlen(pat);
- m = strlen(hn);
- if (n > m) return 0;
- return (strcasecmp(pat, hn + m - n) == 0);
- }
+}
+
+/* IPv6 -- pattern is [hex:hex:....]/number ([net]/mask) */
+static int
+hnmatch_ip6(const char *pat)
+{
+ char *patnet;
+ char *patmask;
+ struct in6_addr addr;
+ struct addrinfo hints, *res;
+ struct sockaddr_in6 net;
+ int mask_len, i = 0;
+ char *p;
+
+ if (pat == NULL || *pat != '[')
+ return 0;
+
+ memcpy(&addr, hostaddress, sizeof(addr));
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+ patnet = strdup(pat);
+
+ /* match IPv6 address against [netnumber]/prefixlen */
+ if (!(p = strchr(patnet, ']')))
+ goto mismatch;
+
+ *p++ = '\0';
+
+ if (! (*p == '/' && isdigit((unsigned char) *(p + 1))))
+ goto mismatch;
+
+ patmask = p + 1;
+
+ /* prepare net address */
+ if (getaddrinfo(patnet + 1, NULL, &hints, &res) != 0)
+ goto mismatch;
+
+ memcpy(&net, res->ai_addr, sizeof(net));
+ freeaddrinfo(res);
+
+ /* convert mask to number */
+ if ((mask_len = atoi(patmask)) < 0 || mask_len > 128)
+ goto mismatch;
+
+ /* compare */
+ while (mask_len > 0) {
+ if (mask_len < 32) {
+ u_int32_t mask = htonl(~(0xffffffff >> mask_len));
+
+ if ((*(u_int32_t *)&addr.s6_addr[i] & mask) !=
+ (*(u_int32_t *)&net.sin6_addr.s6_addr[i] & mask))
+ goto mismatch;
+ break;
+ }
+ if (*(u_int32_t *)&addr.s6_addr[i] !=
+ *(u_int32_t *)&net.sin6_addr.s6_addr[i])
+ goto mismatch;
+ i += 4;
+ mask_len -= 32;
+ }
+
+ free(patnet);
+ return 1;
+
+mismatch:
+ free(patnet);
+ return 0;
+}
+
+/* match the hostname hn against the pattern pat */
+static int
+hnmatch(const char *hn, const char *pat)
+{
+
+ if ((hn == NULL) && (strcmp(pat, "localhost") == 0))
+ return 1;
+ if ((hn == NULL) || *hn == '\0')
+ return 0;
+
+ if (*pat >= '0' && *pat <= '9')
+ return hostfamily == AF_INET ? hnmatch_ip4(pat) : 0;
+ else if (*pat == '[')
+ return hostfamily == AF_INET6 ? hnmatch_ip6(pat) : 0;
+ else {
+ /* pattern is a suffix of a FQDN */
+ int n = strlen(pat),
+ m = strlen(hn);
+
+ if (n > m)
+ return 0;
+ return (strcasecmp(pat, hn + m - n) == 0);
+ }
}
#ifdef MAIN_TEST_CHECKTTY
-char hostaddress[4];
+char hostaddress[16];
+sa_family_t hostfamily;
char *hostname;
void sleepexit(int eval) {} /* dummy for this test */
void badlogin(const char *s) {} /* dummy for this test */
const char *range;
const char *ip;
} alist[] = {
- { "130.225.16.0/255.255.254.0", "130.225.16.1" },
- { "130.225.16.0/255.255.254.0", "10.20.30.1" },
- { "130.225.0.0/255.254.0.0", "130.225.16.1" },
- { "130.225.0.0/255.254.0.0", "130.225.17.1" },
- { "130.225.0.0/255.254.0.0", "150.160.170.180" },
+ { "130.225.16.0/255.255.254.0", "130.225.16.1" },
+ { "130.225.16.0/255.255.254.0", "10.20.30.1" },
+ { "130.225.0.0/255.254.0.0", "130.225.16.1" },
+ { "130.225.0.0/255.254.0.0", "130.225.17.1" },
+ { "130.225.0.0/255.254.0.0", "150.160.170.180" },
+ { "[3ffe:505:2:1::]/64", "3ffe:505:2:1::" },
+ { "[3ffe:505:2:1::]/64", "3ffe:505:2:2::" },
+ { "[3ffe:505:2:1::]/64", "3ffe:505:2:1:ffff:ffff::" },
{ NULL, NULL }
}, *item;
memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET;
+ hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE | AI_ADDRCONFIG;
hints.ai_socktype = SOCK_STREAM;
memcpy(hostaddress, &(sa->sin_addr),
sizeof(sa->sin_addr));
}
-/***
- if (info->ai_family == AF_INET6) {
+ else if (info->ai_family == AF_INET6) {
struct sockaddr_in6 *sa =
(struct sockaddr_in6 *) info->ai_addr;
memcpy(hostaddress, &(sa->sin6_addr),
sizeof(sa->sin6_addr));
}
-***/
+ hostfamily = info->ai_family;
freeaddrinfo(info);
printf("%s\n", hnmatch("dummy", item->range) ?
"match" : "mismatch");
#ifdef HAVE_SECURITY_PAM_MISC_H
static struct passwd pwdcopy;
#endif
-char hostaddress[4]; /* used in checktty.c */
+char hostaddress[16]; /* used in checktty.c */
+sa_family_t hostfamily; /* used in checktty.c */
char *hostname; /* idem */
static char *username, *tty_name, *tty_number;
static char thishost[100];
if (hostname) {
xstrncpy(ut.ut_host, hostname, sizeof(ut.ut_host));
if (hostaddress[0])
- memcpy(&ut.ut_addr, hostaddress, sizeof(ut.ut_addr));
+ memcpy(&ut.ut_addr_v6, hostaddress, sizeof(ut.ut_addr_v6));
}
#if HAVE_UPDWTMP /* bad luck for ancient systems */
updwtmp(_PATH_BTMP, &ut);
hostname = strdup(optarg); /* strdup: Ambrose C. Li */
{
- struct hostent *he = gethostbyname(hostname);
-
- /* he points to static storage; copy the part we use */
- hostaddress[0] = 0;
- if (he && he->h_addr_list && he->h_addr_list[0])
- memcpy(hostaddress, he->h_addr_list[0],
- sizeof(hostaddress));
+ struct addrinfo hints, *info = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_ADDRCONFIG;
+
+ hostaddress[0] = 0;
+
+ if (getaddrinfo(hostname, NULL, &hints, &info)==0 && info) {
+ if (info->ai_family == AF_INET) {
+ struct sockaddr_in *sa =
+ (struct sockaddr_in *) info->ai_addr;
+ memcpy(hostaddress, &(sa->sin_addr),
+ sizeof(sa->sin_addr));
+ }
+ else if (info->ai_family == AF_INET6) {
+ struct sockaddr_in6 *sa =
+ (struct sockaddr_in6 *) info->ai_addr;
+ memcpy(hostaddress, &(sa->sin6_addr),
+ sizeof(sa->sin6_addr));
+ }
+ hostfamily = info->ai_family;
+ freeaddrinfo(info);
+ }
}
break;
if (hostname) {
xstrncpy(ut.ut_host, hostname, sizeof(ut.ut_host));
if (hostaddress[0])
- memcpy(&ut.ut_addr, hostaddress, sizeof(ut.ut_addr));
+ memcpy(&ut.ut_addr_v6, hostaddress, sizeof(ut.ut_addr_v6));
}
pututline(&ut);