summaryrefslogtreecommitdiffstats
path: root/lib/libskey/skeyaccess.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libskey/skeyaccess.c')
-rw-r--r--lib/libskey/skeyaccess.c588
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
OpenPOWER on IntegriCloud