From 3bbaa5903cdfa6d903256d9ad37d1d8c20c79437 Mon Sep 17 00:00:00 2001 From: pst Date: Wed, 19 Oct 1994 00:03:45 +0000 Subject: Include most of the logdaemon v4.4 S/key changes --- lib/libskey/skeyaccess.c | 200 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 142 insertions(+), 58 deletions(-) (limited to 'lib/libskey/skeyaccess.c') diff --git a/lib/libskey/skeyaccess.c b/lib/libskey/skeyaccess.c index 67ed549..3cd877f 100644 --- a/lib/libskey/skeyaccess.c +++ b/lib/libskey/skeyaccess.c @@ -2,9 +2,14 @@ * Figure out if UNIX passwords are permitted for any combination of user * name, group member, terminal port, host_name or network: * - * Programmatic interface: skeyaccess(char *user, char *port, char *host) + * Programmatic interface: skeyaccess(user, port, host, addr) * - * Specify a null character pointer where information is not available. + * All arguments are null-terminated strings. Specify a null character pointer + * where information is not available. + * + * When no address information is given this code performs the host (internet) + * address lookup itself. It rejects addresses that appear to belong to + * someone else. * * When compiled with -DPERMIT_CONSOLE always permits UNIX passwords with * console logins, no matter what the configuration file says. @@ -12,7 +17,9 @@ * To build a stand-alone test version, compile with -DTEST and run it off an * skey.access file in the current directory: * - * Command-line interface: ./skeyaccess user port [host] + * Command-line interface: ./skeyaccess user port [host_or_ip_addr] + * + * Errors are reported via syslogd. * * Author: Wietse Venema, Eindhoven University of Technology. */ @@ -54,6 +61,8 @@ static int match_internet_addr(); static int match_group(); static int match_token(); static int is_internet_addr(); +static struct in_addr *convert_internet_addr(); +static struct in_addr *lookup_internet_addr(); #define MAX_ADDR 32 #define PERMIT 1 @@ -68,40 +77,53 @@ struct login_info { /* skeyaccess - find out if UNIX passwords are permitted */ -int skeyaccess(user, port, host) +int skeyaccess(user, port, host, addr) char *user; char *port; char *host; +char *addr; { - struct hostent *hp; + FILE *fp; struct login_info login_info; - struct in_addr internet_addr[MAX_ADDR + 1]; - char hostname_buf[MAXHOSTNAMELEN + 1]; - int i; + int result; + /* + * Assume no restriction on the use of UNIX passwords when the s/key + * acces table does not exist. + */ + if ((fp = fopen(_PATH_SKEYACCESS, "r")) == 0) { +#ifdef TEST + fprintf(stderr, "No file %s, thus no access control\n", _PATH_SKEYACCESS); +#endif + return (PERMIT); + } + + /* + * Bundle up the arguments in a structure so we won't have to drag around + * boring long argument lists. + * + * Look up the host address when only the name is given. We try to reject + * addresses that belong to someone else. + */ login_info.user = user; login_info.port = port; - login_info.host_name = 0; - login_info.internet_addr = 0; - - if (host) { - if (is_internet_addr(host)) { /* not DECnet */ - internet_addr[0].s_addr = inet_addr(host); - internet_addr[1].s_addr = 0; - login_info.internet_addr = internet_addr; + + if (host != 0 && !is_internet_addr(host)) { + login_info.host_name = host; + } else { + login_info.host_name = 0; + } + + if (addr != 0 && is_internet_addr(addr)) { + login_info.internet_addr = convert_internet_addr(addr); + } else if (host != 0) { + if (is_internet_addr(host)) { + login_info.internet_addr = convert_internet_addr(host); } else { - if ((hp = gethostbyname(host)) != 0 && hp->h_addrtype == AF_INET) { - for (i = 0; i < MAX_ADDR && hp->h_addr_list[i]; i++) - memcpy((char *) &internet_addr[i], - hp->h_addr_list[i], hp->h_length); - internet_addr[i].s_addr = 0; - login_info.internet_addr = internet_addr; - host = hp->h_name; - } - strncpy(hostname_buf, host, MAXHOSTNAMELEN); - hostname_buf[MAXHOSTNAMELEN] = 0; - login_info.host_name = hostname_buf; + login_info.internet_addr = lookup_internet_addr(host); } + } else { + login_info.internet_addr = 0; } /* @@ -115,20 +137,25 @@ char *host; if (login_info.internet_addr == 0) { printf("none\n"); } else { + int i; + for (i = 0; login_info.internet_addr[i].s_addr; i++) - printf("%s%s", inet_ntoa(login_info.internet_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"); } #endif - return (_skeyaccess(&login_info)); + result = _skeyaccess(fp, &login_info); + fclose(fp); + return (result); } /* _skeyaccess - find out if UNIX passwords are permitted */ -int _skeyaccess(login_info) +int _skeyaccess(fp, login_info) +FILE *fp; struct login_info *login_info; { - FILE *fp; char buf[BUFSIZ]; char *tok; int match; @@ -140,13 +167,6 @@ struct login_info *login_info; #endif /* - * Assume no restriction on the use of UNIX passwords when the s/key - * acces table does not exist. - */ - if ((fp = fopen(_PATH_SKEYACCESS, "r")) == 0) - return (PERMIT); - - /* * Scan the s/key access table until we find an entry that matches. If no * match is found, assume that UNIX passwords are disallowed. */ @@ -187,7 +207,6 @@ struct login_info *login_info; } } } - fclose(fp); return (match ? permission : DENY); } @@ -200,7 +219,6 @@ struct login_info *login_info; long pattern; long mask; struct in_addr *addrp; - struct hostent *hp; if (login_info->internet_addr == 0) return (0); @@ -212,26 +230,13 @@ struct login_info *login_info; mask = inet_addr(tok); /* - * See if any of the addresses matches a pattern in the control file. - * Report and skip the address if it does not belong to the remote host. - * Assume localhost == localhost.domain. + * 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. */ -#define NEQ(x,y) (strcasecmp((x),(y)) != 0) - - for (addrp = login_info->internet_addr; addrp->s_addr; addrp++) { - if ((addrp->s_addr & mask) == pattern) { - if (login_info->host_name != 0 && - ((hp = gethostbyaddr((char *) addrp, sizeof(*addrp), AF_INET)) == 0 - || (NEQ(login_info->host_name, hp->h_name) - && NEQ(login_info->host_name, "localhost")))) { - syslog(LOG_ERR, "address %s not registered for host %s", - inet_ntoa(*addrp), login_info->host_name); - continue; - } + for (addrp = login_info->internet_addr; addrp->s_addr; addrp++) + if (addrp->s_addr != -1 && (addrp->s_addr & mask) == pattern) return (1); - } - } return (0); } @@ -365,18 +370,97 @@ char *str; return (runs == 4); } +/* lookup_internet_addr - look up internet addresses with extreme prejudice */ + +static struct in_addr *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], hp->h_length); + list[i].s_addr = 0; + + strncpy(buf, hp->h_name, MAXHOSTNAMELEN); + buf[MAXHOSTNAMELEN] = 0; + length = hp->h_length; + + /* + * Wipe addresses that appear to belong to someone else. We will get + * false alarms when when the hostname comes from DNS, while its + * addresses are listed under different names in local databases. + */ +#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) { + syslog(LOG_ERR, "address %s not registered for host %s", + inet_ntoa(list[i]), buf); + list[i].s_addr = -1; + } + if (NEQ(buf, hp->h_name) && NEQ3(buf, "localhost.", 10)) { + syslog(LOG_ERR, "address %s registered for host %s and %s", + inet_ntoa(list[i]), hp->h_name, buf); + list[i].s_addr = -1; + } + } + return (list); +} + +/* convert_internet_addr - convert string to internet address */ + +static struct in_addr *convert_internet_addr(string) +char *string; +{ + static struct in_addr list[2]; + + list[0].s_addr = inet_addr(string); + list[1].s_addr = 0; + return (list); +} + #ifdef TEST main(argc, argv) int argc; char **argv; { + struct hostent *hp; + char host[MAXHOSTNAMELEN + 1]; + int verdict; + char *user; + char *port; + if (argc != 3 && argc != 4) { fprintf(stderr, "usage: %s user port [host_or_ip_address]\n", argv[0]); exit(0); } + if (_PATH_SKEYACCESS[0] != '/') + printf("Warning: this program uses control file: %s\n", KEYACCESS); openlog("login", LOG_PID, LOG_AUTH); - printf("%s\n", skeyaccess(argv[1], argv[2], argv[3]) ? "YES" : "NO"); + + user = argv[1]; + port = argv[2]; + if (argv[3]) { + strncpy(host, (hp = gethostbyname(argv[3])) ? + hp->h_name : argv[3], MAXHOSTNAMELEN); + host[MAXHOSTNAMELEN] = 0; + } + verdict = skeyaccess(user, port, argv[3] ? host : (char *) 0, (char *) 0); + printf("UNIX passwords %spermitted\n", verdict ? "" : "NOT "); return (0); } -- cgit v1.1