diff options
author | Guido van Rooij <guido@FreeBSD.org> | 1994-08-21 19:26:22 +0000 |
---|---|---|
committer | Guido van Rooij <guido@FreeBSD.org> | 1994-08-21 19:26:22 +0000 |
commit | 7c4c6e58bab1d0587a3bf061b0bdddf5e73c9efd (patch) | |
tree | 2a64077f9871e464ae6f709a8bf4e1b2cc63c8d9 /usr.bin/login | |
parent | d9e9aec7adca69ebefc318c4851c3fb91a17acef (diff) | |
download | src-7c4c6e58bab1d0587a3bf061b0bdddf5e73c9efd.tar.gz src-7c4c6e58bab1d0587a3bf061b0bdddf5e73c9efd.zip |
Notes
Diffstat (limited to 'usr.bin/login')
-rw-r--r-- | usr.bin/login/Makefile | 10 | ||||
-rw-r--r-- | usr.bin/login/README | 10 | ||||
-rw-r--r-- | usr.bin/login/login.access.5 | 50 | ||||
-rw-r--r-- | usr.bin/login/login_access.c | 236 | ||||
-rw-r--r-- | usr.bin/login/login_skey.c | 105 | ||||
-rw-r--r-- | usr.bin/login/pathnames.h | 1 |
6 files changed, 409 insertions, 3 deletions
diff --git a/usr.bin/login/Makefile b/usr.bin/login/Makefile index 8be09a62f4fc..8b8c35f406d0 100644 --- a/usr.bin/login/Makefile +++ b/usr.bin/login/Makefile @@ -2,14 +2,18 @@ #CFLAGS+=-DKERBEROS PROG= login -SRCS= login.c +MAN1= login.1 +MAN5= login.access.5 +SRCS= login.c login_access.c login_skey.c #klogin.c -DPADD= ${LIBUTIL} +DPADD= ${LIBUTIL} ${LIBSKEY} #${LIBKRB} ${LIBDES} -LDADD= -lutil -lcrypt +LDADD= -lutil -lcrypt -lskey #-lkrb -ldes BINOWN= root BINMODE=4555 +CFLAGS+= -DLOGIN_ACCESS -DSKEY -DLOGALL INSTALLFLAGS=-fschg .include <bsd.prog.mk> + diff --git a/usr.bin/login/README b/usr.bin/login/README new file mode 100644 index 000000000000..6ad7a10d4796 --- /dev/null +++ b/usr.bin/login/README @@ -0,0 +1,10 @@ +This login has additional functionalities. They are all based on (part of) +Wietse Venema's logdaemon package. + + +The following defines can be used: +1) LOGIN_ACCESS to allow access control on a per tty/user combination +2) SKEY to allow the use of s/key one time passwords +3) LOGALL to log all logins + +-Guido diff --git a/usr.bin/login/login.access.5 b/usr.bin/login/login.access.5 new file mode 100644 index 000000000000..28d423c9156c --- /dev/null +++ b/usr.bin/login/login.access.5 @@ -0,0 +1,50 @@ +.\" this is comment +.Dd April 30, 1994 +.Dt SKEY.ACCESS 5 +.Os FreeBSD 1.2 +.Sh NAME +.Nm login.access +.Nd Login access control table +.Sh DESCRIPTION +The +.Nm login.access +file specifies (user, host) combinations and/or (user, tty) +combinations for which a login will be either accepted or refused. +.Pp +When someone logs in, the +.Nm login.access +is scanned for the first entry that +matches the (user, host) combination, or, in case of non-networked +logins, the first entry that matches the (user, tty) combination. The +permissions field of that table entry determines whether the login will +be accepted or refused. +.Pp +Each line of the login access control table has three fields separated by a +":" character: permission : users : origins + +The first field should be a "+" (access granted) or "-" (access denied) +character. The second field should be a list of one or more login names, +group names, or ALL (always matches). The third field should be a list +of one or more tty names (for non-networked logins), host names, domain +names (begin with "."), host addresses, internet network numbers (end +with "."), ALL (always matches) or LOCAL (matches any string that does +not contain a "." character). If you run NIS you can use @netgroupname +in host or user patterns. + +The EXCEPT operator makes it possible to write very compact rules. + +The group file is searched only when a name does not match that of the +logged-in user. Only groups are matched in which users are explicitly +listed: the program does not look at a user's primary group id value. +.Sh FILES +.Bl -tag -width /etc/login.access -compact +.It Pa /etc/login.access +The +.Nm login.access +file resides in +.Pa /etc . +.El +.Sh SEE ALSO +.Xr login 1 +.Sh AUTHOR +Guido van Rooij diff --git a/usr.bin/login/login_access.c b/usr.bin/login/login_access.c new file mode 100644 index 000000000000..90de8e0ae368 --- /dev/null +++ b/usr.bin/login/login_access.c @@ -0,0 +1,236 @@ + /* + * This module implements a simple but effective form of login access + * control based on login names and on host (or domain) names, internet + * addresses (or network numbers), or on terminal line names in case of + * non-networked logins. Diagnostics are reported through syslog(3). + * + * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. + */ + +#ifdef LOGIN_ACCESS +#ifndef lint +static char sccsid[] = "%Z% %M% %I% %E% %U%"; +#endif + +#include <stdio.h> +#include <syslog.h> +#include <ctype.h> +#include <sys/types.h> +#include <grp.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> + +#include "pathnames.h" + + /* Delimiters for fields and for lists of users, ttys or hosts. */ + +static char fs[] = ":"; /* field separator */ +static char sep[] = ", \t"; /* list-element separator */ + + /* Constants to be used in assignments only, not in comparisons... */ + +#define YES 1 +#define NO 0 + +static int list_match(); +static int user_match(); +static int from_match(); +static int string_match(); + +/* login_access - match username/group and host/tty with access control file */ + +login_access(user, from) +char *user; +char *from; +{ + FILE *fp; + char line[BUFSIZ]; + char *perm; /* becomes permission field */ + char *users; /* becomes list of login names */ + char *froms; /* becomes list of terminals or hosts */ + int match = NO; + int end; + int lineno = 0; /* for diagnostics */ + + /* + * Process the table one line at a time and stop at the first match. + * Blank lines and lines that begin with a '#' character are ignored. + * Non-comment lines are broken at the ':' character. All fields are + * mandatory. The first field should be a "+" or "-" character. A + * non-existing table means no access control. + */ + + if (fp = fopen(_PATH_LOGACCESS, "r")) { + while (!match && fgets(line, sizeof(line), fp)) { + lineno++; + if (line[end = strlen(line) - 1] != '\n') { + syslog(LOG_ERR, "%s: line %d: missing newline or line too long", + _PATH_LOGACCESS, lineno); + continue; + } + if (line[0] == '#') + continue; /* comment line */ + while (end > 0 && isspace(line[end - 1])) + end--; + line[end] = 0; /* strip trailing whitespace */ + if (line[0] == 0) /* skip blank lines */ + continue; + if (!(perm = strtok(line, fs)) + || !(users = strtok((char *) 0, fs)) + || !(froms = strtok((char *) 0, fs)) + || strtok((char *) 0, fs)) { + syslog(LOG_ERR, "%s: line %d: bad field count", _PATH_LOGACCESS, + lineno); + continue; + } + if (perm[0] != '+' && perm[0] != '-') { + syslog(LOG_ERR, "%s: line %d: bad first field", _PATH_LOGACCESS, + lineno); + continue; + } + match = (list_match(froms, from, from_match) + && list_match(users, user, user_match)); + } + (void) fclose(fp); + } else if (errno != ENOENT) { + syslog(LOG_ERR, "cannot open %s: %m", _PATH_LOGACCESS); + } + return (match == 0 || (line[0] == '+')); +} + +/* list_match - match an item against a list of tokens with exceptions */ + +static int list_match(list, item, match_fn) +char *list; +char *item; +int (*match_fn) (); +{ + char *tok; + int match = NO; + + /* + * Process tokens one at a time. We have exhausted all possible matches + * when we reach an "EXCEPT" token or the end of the list. If we do find + * a match, look for an "EXCEPT" list and recurse to determine whether + * the match is affected by any exceptions. + */ + + for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) { + if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */ + break; + if (match = (*match_fn) (tok, item)) /* YES */ + break; + } + /* Process exceptions to matches. */ + + if (match != NO) { + while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT")) + /* VOID */ ; + if (tok == 0 || list_match((char *) 0, item, match_fn) == NO) + return (match); + } + return (NO); +} + +/* netgroup_match - match group against machine or user */ + +static int netgroup_match(group, machine, user) +char *machine; +char *user; +{ +#ifdef NIS + static char *mydomain = 0; + + if (mydomain == 0) + yp_get_default_domain(&mydomain); + return (innetgr(group, machine, user, mydomain)); +#else + syslog(LOG_ERR, "NIS netgroup support not configured"); +#endif +} + +/* user_match - match a username against one token */ + +static int user_match(tok, string) +char *tok; +char *string; +{ + struct group *group; + int i; + + /* + * If a token has the magic value "ALL" the match always succeeds. + * Otherwise, return YES if the token fully matches the username, or if + * the token is a group that contains the username. + */ + + if (tok[0] == '@') { /* netgroup */ + return (netgroup_match(tok + 1, (char *) 0, string)); + } else if (string_match(tok, string)) { /* ALL or exact match */ + return (YES); + } else if (group = getgrnam(tok)) { /* try group membership */ + for (i = 0; group->gr_mem[i]; i++) + if (strcasecmp(string, group->gr_mem[i]) == 0) + return (YES); + } + return (NO); +} + +/* from_match - match a host or tty against a list of tokens */ + +static int from_match(tok, string) +char *tok; +char *string; +{ + int tok_len; + int str_len; + + /* + * If a token has the magic value "ALL" the match always succeeds. Return + * YES if the token fully matches the string. If the token is a domain + * name, return YES if it matches the last fields of the string. If the + * token has the magic value "LOCAL", return YES if the string does not + * contain a "." character. If the token is a network number, return YES + * if it matches the head of the string. + */ + + if (tok[0] == '@') { /* netgroup */ + return (netgroup_match(tok + 1, string, (char *) 0)); + } else if (string_match(tok, string)) { /* ALL or exact match */ + return (YES); + } else if (tok[0] == '.') { /* domain: match last fields */ + if ((str_len = strlen(string)) > (tok_len = strlen(tok)) + && strcasecmp(tok, string + str_len - tok_len) == 0) + return (YES); + } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */ + if (strchr(string, '.') == 0) + return (YES); + } else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */ + && strncmp(tok, string, tok_len) == 0) { + return (YES); + } + return (NO); +} + +/* string_match - match a string against one token */ + +static int string_match(tok, string) +char *tok; +char *string; +{ + + /* + * If the token has the magic value "ALL" the match always succeeds. + * Otherwise, return YES if the token fully matches the string. + */ + + if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */ + return (YES); + } else if (strcasecmp(tok, string) == 0) { /* try exact match */ + return (YES); + } + return (NO); +} +#endif /* LOGIN_ACCES */ diff --git a/usr.bin/login/login_skey.c b/usr.bin/login/login_skey.c new file mode 100644 index 000000000000..b94bd28ad9cb --- /dev/null +++ b/usr.bin/login/login_skey.c @@ -0,0 +1,105 @@ + /* Portions taken from the skey distribution on Oct 21 1993 */ +#ifdef SKEY +#include <sys/types.h> +#include <netinet/in.h> +#include <string.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <termios.h> +#include <pwd.h> +#include <syslog.h> + +#include <skey.h> + +/* skey_getpass - read regular or s/key password */ + +char *skey_getpass(prompt, pwd, pwok) +char *prompt; +struct passwd *pwd; +int pwok; +{ + static char buf[128]; + struct skey skey; + char *cp; + void rip(); + struct termios saved_ttymode; + struct termios noecho_ttymode; + char *username = pwd ? pwd->pw_name : "nope"; + int sflag; + + /* Attempt an s/key challenge. */ + + if ((sflag = skeychallenge(&skey, username, buf)) == 0) { + printf("%s\n", buf); + } + if (!pwok) { + printf("(s/key required)\n"); + } + fputs(prompt, stdout); + fflush(stdout); + + /* Save current input modes and turn echo off. */ + + tcgetattr(0, &saved_ttymode); + tcgetattr(0, &noecho_ttymode); + noecho_ttymode.c_lflag &= ~ECHO; + tcsetattr(0, TCSANOW, &noecho_ttymode); + + /* Read password. */ + + buf[0] = 0; + fgets(buf, sizeof(buf), stdin); + rip(buf); + + /* Restore previous input modes. */ + + tcsetattr(0, TCSANOW, &saved_ttymode); + + /* Give S/Key users a chance to do it with echo on. */ + + if (sflag == 0 && feof(stdin) == 0 && buf[0] == 0) { + fputs(" (turning echo on)\n", stdout); + fputs(prompt, stdout); + fflush(stdout); + fgets(buf, sizeof(buf), stdin); + rip(buf); + } else { + putchar('\n'); + } + return (buf); +} + +/* skey_crypt - return encrypted UNIX passwd if s/key or regular password ok */ + +char *skey_crypt(pp, salt, pwd, pwok) +char *pp; +char *salt; +struct passwd *pwd; +int pwok; +{ + struct skey skey; + char *p; + char *crypt(); + + /* Try s/key authentication even when the UNIX password is permitted. */ + + if (pwd != 0 && skeylookup(&skey, pwd->pw_name) == 0 + && skeyverify(&skey, pp) == 0) { + /* s/key authentication succeeded */ + if (skey.n < 5) + printf("Warning! Change s/key password soon\n"); + return (pwd->pw_passwd); + } + + /* When s/key authentication does not work, always invoke crypt(). */ + + p = crypt(pp, salt); + if (pwok && pwd != 0 && strcmp(p, pwd->pw_passwd) == 0) + return (pwd->pw_passwd); + + /* The user does not exist or entered bad input. */ + + return (":"); +} +#endif SKEY diff --git a/usr.bin/login/pathnames.h b/usr.bin/login/pathnames.h index a9e1a0779f74..a9f5c1ab17d9 100644 --- a/usr.bin/login/pathnames.h +++ b/usr.bin/login/pathnames.h @@ -37,3 +37,4 @@ #define _PATH_HUSHLOGIN ".hushlogin" #define _PATH_MOTDFILE "/etc/motd" +#define _PATH_LOGACCESS "/etc/login.access" |