diff options
Diffstat (limited to 'lib/libskey/skeyaccess.c')
-rw-r--r-- | lib/libskey/skeyaccess.c | 588 |
1 files changed, 0 insertions, 588 deletions
diff --git a/lib/libskey/skeyaccess.c b/lib/libskey/skeyaccess.c deleted file mode 100644 index c71dd81..0000000 --- a/lib/libskey/skeyaccess.c +++ /dev/null @@ -1,588 +0,0 @@ - /* - * Figure out if UNIX passwords are permitted for any combination of user - * name, group member, terminal port, host_name or network: - * - * Programmatic interface: skeyaccess(user, port, host, addr) - * - * 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. - * - * 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_or_ip_addr] - * - * Errors are reported via syslogd. - * - * Author: Wietse Venema, Eindhoven University of Technology. - * - * $FreeBSD$ - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <string.h> -#include <netdb.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <grp.h> -#include <ctype.h> -#include <syslog.h> -#include <unistd.h> -#include <stdlib.h> -#include <sys/param.h> - -#include "pathnames.h" - - /* - * Token input with one-deep pushback. - */ -static char *prev_token = 0; /* push-back buffer */ -static char *line_pointer = NULL; -static char *first_token __P((char *, int, FILE *)); -static int line_number; -static void unget_token __P((char *)); -static char *get_token __P((void)); -static char *need_token __P((void)); -static char *need_internet_addr __P((void)); - - /* - * Various forms of token matching. - */ -#define match_host_name(l) match_token((l)->host_name) -#define match_port(l) match_token((l)->port) -#define match_user(l) match_token((l)->user) -struct login_info; -static int match_internet_addr __P((struct login_info *)); -static int match_group __P((struct login_info *)); -static int match_token __P((char *)); -static int is_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 -#define DENY 0 - -#ifndef CONSOLE -#define CONSOLE "console" -#endif -#ifndef VTY_PREFIX -#define VTY_PREFIX "ttyv" -#endif - -struct login_info { - char *host_name; /* host name */ - struct addrinfo *internet_addr; /* addrinfo chain */ - char *user; /* user name */ - char *port; /* login port */ -}; - -static int _skeyaccess __P((FILE *, struct login_info *)); -int skeyaccess __P((char *, char *, char *, char *)); - -/* skeyaccess - find out if UNIX passwords are permitted */ - -int skeyaccess(user, port, host, addr) -char *user; -char *port; -char *host; -char *addr; -{ - FILE *fp; - struct login_info login_info; - 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; - - if (host != NULL && !is_internet_addr(host)) { - login_info.host_name = host; - } else { - login_info.host_name = NULL; - } - - if (addr != NULL && is_internet_addr(addr)) { - login_info.internet_addr = convert_internet_addr(addr); - } 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 = NULL; - } - - /* - * Print what we think the user wants us to do. - */ -#ifdef TEST - printf("port: %s\n", login_info.port); - 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 == NULL) { - printf("none\n"); - } else { - struct addrinfo *res; - char haddr[NI_MAXHOST]; - - 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); -} - -/* _skeyaccess - find out if UNIX passwords are permitted */ - -static int _skeyaccess(fp, login_info) -FILE *fp; -struct login_info *login_info; -{ - char buf[BUFSIZ]; - char *tok; - int match; - int permission=DENY; - -#ifdef PERMIT_CONSOLE - if (login_info->port != 0 && - (strcmp(login_info->port, CONSOLE) == 0 || - strncmp(login_info->port, VTY_PREFIX, sizeof(VTY_PREFIX) - 1) == 0 - ) - ) - return (1); -#endif - - /* - * Scan the s/key access table until we find an entry that matches. If no - * match is found, assume that UNIX passwords are disallowed. - */ - match = 0; - while (match == 0 && (tok = first_token(buf, sizeof(buf), fp))) { - if (strncasecmp(tok, "permit", 4) == 0) { - permission = PERMIT; - } else if (strncasecmp(tok, "deny", 4) == 0) { - permission = DENY; - } else { - syslog(LOG_ERR, "%s: line %d: bad permission: %s", - _PATH_SKEYACCESS, line_number, tok); - continue; /* error */ - } - - /* - * Process all conditions in this entry until we find one that fails. - */ - match = 1; - while (match != 0 && (tok = get_token())) { - if (strcasecmp(tok, "hostname") == 0) { - match = match_host_name(login_info); - } else if (strcasecmp(tok, "port") == 0) { - match = match_port(login_info); - } else if (strcasecmp(tok, "user") == 0) { - match = match_user(login_info); - } else if (strcasecmp(tok, "group") == 0) { - match = match_group(login_info); - } else if (strcasecmp(tok, "internet") == 0) { - match = match_internet_addr(login_info); - } else if (is_internet_addr(tok)) { - unget_token(tok); - match = match_internet_addr(login_info); - } else { - syslog(LOG_ERR, "%s: line %d: bad condition: %s", - _PATH_SKEYACCESS, line_number, tok); - match = 0; - } - } - } - 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; - 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 == NULL) - return (0); - if ((tok = need_internet_addr()) == 0) - return (0); - 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); - 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 (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); -} - -/* match_group - match username against group */ - -static int match_group(login_info) -struct login_info *login_info; -{ - struct group *group; - char *tok; - char **memp; - - if ((tok = need_token()) && (group = getgrnam(tok))) { - for (memp = group->gr_mem; *memp; memp++) - if (strcmp(login_info->user, *memp) == 0) - return (1); - } - return (0); /* XXX endgrent() */ -} - -/* match_token - get and match token */ - -static int match_token(str) -char *str; -{ - char *tok; - - return (str && (tok = need_token()) && strcasecmp(str, tok) == 0); -} - -/* first_token - read line and return first token */ - -static char *first_token(buf, len, fp) -char *buf; -int len; -FILE *fp; -{ - char *cp; - - prev_token = 0; - for (;;) { - if (fgets(buf, len, fp) == 0) - return (0); - line_number++; - buf[strcspn(buf, "\r\n#")] = 0; -#ifdef TEST - if (buf[0]) - printf("rule: %s\n", buf); -#endif - line_pointer = buf; - while ((cp = strsep(&line_pointer, " \t")) != NULL && *cp == '\0') - ; - if (cp != NULL) - return (cp); - } -} - -/* unget_token - push back last token */ - -static void unget_token(cp) -char *cp; -{ - prev_token = cp; -} - -/* get_token - retrieve next token from buffer */ - -static char *get_token() -{ - char *cp; - - if ( (cp = prev_token) ) { - prev_token = 0; - } else { - while ((cp = strsep(&line_pointer, " \t")) != NULL && *cp == '\0') - ; - } - return (cp); -} - -/* need_token - complain if next token is not available */ - -static char *need_token() -{ - char *cp; - - if ((cp = get_token()) == 0) - syslog(LOG_ERR, "%s: line %d: premature end of rule", - _PATH_SKEYACCESS, line_number); - return (cp); -} - -/* need_internet_addr - complain if next token is not an internet address */ - -static char *need_internet_addr() -{ - char *cp; - - if ((cp = get_token()) == 0) { - syslog(LOG_ERR, "%s: line %d: internet address expected", - _PATH_SKEYACCESS, line_number); - return (0); - } else if (!is_internet_addr(cp)) { - syslog(LOG_ERR, "%s: line %d: bad internet address: %s", - _PATH_SKEYACCESS, line_number, cp); - return (0); - } else { - return (cp); - } -} - -/* is_internet_addr - determine if string is a dotted quad decimal address */ - -static int is_internet_addr(str) -char *str; -{ - struct addrinfo *res; - - 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(aip) -struct addrinfo **aip; -{ - struct addrinfo *ai; - - ai = *aip; - *aip = ai->ai_next; - if (ai->ai_canonname) { - if (ai->ai_next && !ai->ai_next->ai_canonname) - ai->ai_next->ai_canonname = ai->ai_canonname; - else - free(ai->ai_canonname); - } - free(ai); -} - -/* lookup_internet_addr - look up internet addresses with extreme prejudice */ - -static struct addrinfo *lookup_internet_addr(host) -char *host; -{ - struct addrinfo hints, *res0, *res, **resp; - 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 - * 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) - - resp = &res0; - while ((res = *resp) != NULL) { - if (res->ai_family != AF_INET && res->ai_family != AF_INET6) { - nuke_ai(resp); - 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", - haddr, res0->ai_canonname); - nuke_ai(resp); - continue; - } - 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", - haddr, hname, res0->ai_canonname); - nuke_ai(resp); - continue; - } - resp = &res->ai_next; - } - return (res0); -} - -/* convert_internet_addr - convert string to internet address */ - -static struct addrinfo *convert_internet_addr(string) -char *string; -{ - struct addrinfo hints, *res; - - 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 - -main(argc, argv) -int argc; -char **argv; -{ - struct addrinfo hints, *res; - 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", _PATH_SKEYACCESS); - openlog("login", LOG_PID, LOG_AUTH); - - user = argv[1]; - port = argv[2]; - if (argv[3]) { - 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); - printf("UNIX passwords %spermitted\n", verdict ? "" : "NOT "); - return (0); -} - -#endif |