X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/80f91e3f5a3bb9e578fa691d5938a1df6e5c7895..9a448eeeeabdfc4bfdb708d7db19bcb936e8c671:/usr/src/usr.bin/login/login.c diff --git a/usr/src/usr.bin/login/login.c b/usr/src/usr.bin/login/login.c index 49b62b1808..33baab4718 100644 --- a/usr/src/usr.bin/login/login.c +++ b/usr/src/usr.bin/login/login.c @@ -1,22 +1,32 @@ /* - * Copyright (c) 1980, 1987 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. + * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef lint char copyright[] = -"@(#) Copyright (c) 1980 Regents of the University of California.\n\ +"@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ All rights reserved.\n"; -#endif not lint +#endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)login.c 5.24 (Berkeley) %G%"; -#endif not lint +static char sccsid[] = "@(#)login.c 5.36 (Berkeley) %G%"; +#endif /* not lint */ /* * login [ name ] - * login -r hostname (for rlogind) * login -h hostname (for telnetd, etc.) * login -f name (for pre-authenticated login: datakit, xterm, etc.) */ @@ -27,7 +37,6 @@ static char sccsid[] = "@(#)login.c 5.24 (Berkeley) %G%"; #include #include #include -#include #include #include @@ -38,50 +47,57 @@ static char sccsid[] = "@(#)login.c 5.24 (Berkeley) %G%"; #include #include #include +#include #include #include +#include "pathnames.h" #define TTYGRPNAME "tty" /* name of group to own ttys */ -#define MOTDFILE "/etc/motd" -#define MAILDIR "/usr/spool/mail" -#define NOLOGIN "/etc/nologin" -#define HUSHLOGIN ".hushlogin" -#define LASTLOG "/usr/adm/lastlog" -#define BSHELL "/bin/sh" - /* * This bounds the time given to login. Not a define so it can * be patched on machines where it's too small. */ int timeout = 300; -struct passwd nouser = {"", "NOLOGIN", -1, -1, -1, "", "", "", "" }; -struct sgttyb ttyb; -struct passwd *pwd; -char term[64], *hostname, *username; +struct passwd *pwd; +int failures; +char term[64], *hostname, *username, *tty; -struct tchars tc = { +struct sgttyb sgttyb; +struct tchars tc = { CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK }; -struct ltchars ltc = { +struct ltchars ltc = { CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT }; +char *months[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" }; + +char *months[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" }; + main(argc, argv) int argc; char **argv; { extern int errno, optind; extern char *optarg, **environ; + struct timeval tp; + struct tm *ttp; + struct timeval tp; + struct tm *ttp; struct group *gr; register int ch; register char *p; - int fflag, hflag, pflag, rflag, cnt; + int ask, fflag, hflag, pflag, cnt; int quietlog, passwd_req, ioctlval, timedout(); - char *domain, *envinit[1], *ttyn, *tty; + char *domain, *salt, *envinit[1], *ttyn, *pp; char tbuf[MAXPATHLEN + 2]; - char *ttyname(), *stypeof(), *crypt(), *getpass(); + char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass(); time_t time(); off_t lseek(); @@ -94,26 +110,19 @@ main(argc, argv) /* * -p is used by getty to tell login not to destroy the environment - * -r is used by rlogind to cause the autologin protocol; * -f is used to skip a second login authentication - * -h is used by other servers to pass the name of the - * remote host to login so that it may be placed in utmp and wtmp + * -h is used by other servers to pass the name of the remote + * host to login so that it may be placed in utmp and wtmp */ (void)gethostname(tbuf, sizeof(tbuf)); domain = index(tbuf, '.'); - fflag = hflag = pflag = rflag = 0; + fflag = hflag = pflag = 0; passwd_req = 1; - while ((ch = getopt(argc, argv, "f:h:pr:")) != EOF) - switch(ch) { + while ((ch = getopt(argc, argv, "fh:p")) != EOF) + switch (ch) { case 'f': - if (rflag) { - fprintf(stderr, - "login: only one of -r and -f allowed.\n"); - exit(1); - } fflag = 1; - username = optarg; break; case 'h': if (getuid()) { @@ -121,61 +130,38 @@ main(argc, argv) "login: -h for super-user only.\n"); exit(1); } - if (rflag) { - fprintf(stderr, - "login: only one of -r and -h allowed.\n"); - exit(1); - } hflag = 1; if (domain && (p = index(optarg, '.')) && - strcmp(p, domain) == 0) + strcasecmp(p, domain) == 0) *p = 0; hostname = optarg; break; case 'p': pflag = 1; break; - case 'r': - if (hflag || fflag) { - fprintf(stderr, - "login: -f and -h not allowed with -r.\n"); - exit(1); - } - rflag = 1; - passwd_req = doremotelogin(optarg); - if (domain && (p = index(optarg, '.')) && - !strcmp(p, domain)) - *p = '\0'; - hostname = optarg; - break; case '?': default: - fprintf(stderr, "usage: login [-p] [username]\n"); + fprintf(stderr, "usage: login [-fp] [username]\n"); exit(1); } argc -= optind; argv += optind; - if (*argv) + if (*argv) { username = *argv; + ask = 0; + } else + ask = 1; ioctlval = 0; (void)ioctl(0, TIOCLSET, &ioctlval); (void)ioctl(0, TIOCNXCL, 0); - (void)ioctl(0, FIONBIO, &ioctlval); - (void)ioctl(0, FIOASYNC, &ioctlval); - (void)ioctl(0, TIOCGETP, &ttyb); - - /* - * If talking to an rlogin process, propagate the terminal type and - * baud rate across the network. - */ - if (rflag) - doremoteterm(&ttyb); - ttyb.sg_erase = CERASE; - ttyb.sg_kill = CKILL; + (void)fcntl(0, F_SETFL, ioctlval); + (void)ioctl(0, TIOCGETP, &sgttyb); + sgttyb.sg_erase = CERASE; + sgttyb.sg_kill = CKILL; (void)ioctl(0, TIOCSLTC, <c); (void)ioctl(0, TIOCSETC, &tc); - (void)ioctl(0, TIOCSETP, &ttyb); + (void)ioctl(0, TIOCSETP, &sgttyb); for (cnt = getdtablesize(); cnt > 2; cnt--) close(cnt); @@ -190,61 +176,72 @@ main(argc, argv) openlog("login", LOG_ODELAY, LOG_AUTH); - for (cnt = 0;; username = NULL) { + for (cnt = 0;; ask = 1) { ioctlval = 0; (void)ioctl(0, TIOCSETD, &ioctlval); - if (!username) + if (ask) { + fflag = 0; getloginname(); - if ((pwd = getpwnam(username)) == NULL) - pwd = &nouser; + } + /* + * Note if trying multiple user names; + * log failures for previous user name, + * but don't bother logging one failure + * for nonexistent name (mistyped username). + */ + if (failures && strcmp(tbuf, username)) { + if (failures > (pwd ? 0 : 1)) + badlogin(tbuf); + failures = 0; + } + (void)strcpy(tbuf, username); + if (pwd = getpwnam(username)) + salt = pwd->pw_passwd; + else + salt = "xx"; /* if user not super-user, check for disabled logins */ - if (pwd->pw_uid) + if (pwd == NULL || pwd->pw_uid) checknologin(); - if (!strcmp(pwd->pw_shell, "/bin/csh")) { - ioctlval = NTTYDISC; - (void)ioctl(0, TIOCSETD, &ioctlval); - } - /* - * disallow automatic login to root, or if not root - * and the uid's differ + * Disallow automatic login to root; if not invoked by + * root, disallow if the uid's differ. */ - if (fflag) { + if (fflag && pwd) { int uid = getuid(); - passwd_req = !pwd->pw_uid || uid && uid != pwd->pw_uid; + passwd_req = pwd->pw_uid == 0 || + (uid && uid != pwd->pw_uid); } /* - * If no remote login authentication and a password exists + * If no pre-authentication and a password exists * for this user, prompt for one and verify it. */ - if (!passwd_req || !*pwd->pw_passwd) + if (!passwd_req || (pwd && !*pwd->pw_passwd)) break; setpriority(PRIO_PROCESS, 0, -4); - p = getpass("Password:"); - p = crypt(p, pwd->pw_passwd); + pp = getpass("Password:"); + p = crypt(pp, salt); setpriority(PRIO_PROCESS, 0, 0); - if (!strcmp(p, pwd->pw_passwd)) + + (void) bzero(pp, strlen(pp)); + if (pwd && !strcmp(p, pwd->pw_passwd)) break; printf("Login incorrect\n"); - if (++cnt >= 5) { - if (hostname) - syslog(LOG_ERR, - "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s", - tty, UT_HOSTSIZE, hostname, UT_NAMESIZE, - username); - else - syslog(LOG_ERR, - "REPEATED LOGIN FAILURES ON %s, %.*s", - tty, UT_NAMESIZE, username); - (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL); - sleepexit(1); + failures++; + /* we allow 10 tries, but after 3 we start backing off */ + if (++cnt > 3) { + if (cnt >= 10) { + badlogin(username); + (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL); + sleepexit(1); + } + sleep((u_int)((cnt - 3) * 5)); } } @@ -255,27 +252,16 @@ main(argc, argv) * If valid so far and root is logging in, see if root logins on * this terminal are permitted. */ - if (!pwd->pw_uid && !rootterm(tty)) { + if (pwd->pw_uid == 0 && !rootterm(tty)) { if (hostname) - syslog(LOG_CRIT, "ROOT LOGIN REFUSED ON %s FROM %.*s", - tty, UT_HOSTSIZE, hostname); + syslog(LOG_NOTICE, "ROOT LOGIN REFUSED FROM %s", + hostname); else - syslog(LOG_CRIT, "ROOT LOGIN REFUSED ON %s", tty); + syslog(LOG_NOTICE, "ROOT LOGIN REFUSED ON %s", tty); printf("Login incorrect\n"); sleepexit(1); } - if (*pwd->pw_shell == '\0') - pwd->pw_shell = BSHELL; - - if (chdir(pwd->pw_dir) < 0) { - printf("No directory %s!\n", pwd->pw_dir); - if (chdir("/")) - exit(0); - pwd->pw_dir = "/"; - printf("Logging in with home = \"/\".\n"); - } - if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { switch(errno) { case EUSERS: @@ -292,20 +278,79 @@ main(argc, argv) sleepexit(0); } + if (chdir(pwd->pw_dir) < 0) { + printf("No directory %s!\n", pwd->pw_dir); + if (chdir("/")) + exit(0); + pwd->pw_dir = "/"; + printf("Logging in with home = \"/\".\n"); + } + +#define TWOWEEKS (14*24*60*60) + if (pwd->pw_change || pwd->pw_expire) + (void)gettimeofday(&tp, (struct timezone *)NULL); + if (pwd->pw_change) + if (tp.tv_sec >= pwd->pw_change) { + printf("Sorry -- your password has expired.\n"); + sleepexit(1); + } + else if (tp.tv_sec - pwd->pw_change < TWOWEEKS) { + ttp = localtime(&pwd->pw_change); + printf("Warning: your password expires on %s %d, 19%d\n", + months[ttp->tm_mon], ttp->tm_mday, ttp->tm_year); + } + if (pwd->pw_expire) + if (tp.tv_sec >= pwd->pw_expire) { + printf("Sorry -- your account has expired.\n"); + sleepexit(1); + } + else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS) { + ttp = localtime(&pwd->pw_expire); + printf("Warning: your account expires on %s %d, 19%d\n", + months[ttp->tm_mon], ttp->tm_mday, ttp->tm_year); + } + +#define TWOWEEKS (14*24*60*60) + if (pwd->pw_change || pwd->pw_expire) + (void)gettimeofday(&tp, (struct timezone *)NULL); + if (pwd->pw_change) + if (tp.tv_sec >= pwd->pw_change) { + printf("Sorry -- your password has expired.\n"); + sleepexit(1); + } + else if (tp.tv_sec - pwd->pw_change < TWOWEEKS) { + ttp = localtime(&pwd->pw_change); + printf("Warning: your password expires on %s %d, 19%d\n", + months[ttp->tm_mon], ttp->tm_mday, ttp->tm_year); + } + if (pwd->pw_expire) + if (tp.tv_sec >= pwd->pw_expire) { + printf("Sorry -- your account has expired.\n"); + sleepexit(1); + } + else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS) { + ttp = localtime(&pwd->pw_expire); + printf("Warning: your account expires on %s %d, 19%d\n", + months[ttp->tm_mon], ttp->tm_mday, ttp->tm_year); + } + + /* nothing else left to fail -- really log in */ { struct utmp utmp; + bzero((char *)&utmp, sizeof(utmp)); (void)time(&utmp.ut_time); strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); - strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); + if (hostname) + strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); login(&utmp); } - quietlog = access(HUSHLOGIN, F_OK) == 0; - dolastlog(quietlog, tty); + quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; + dolastlog(quietlog); - if (!hflag && !rflag) { /* XXX */ + if (!hflag) { /* XXX */ static struct winsize win = { 0, 0, 0, 0 }; (void)ioctl(0, TIOCSWINSZ, &win); @@ -321,31 +366,39 @@ main(argc, argv) quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); (void)setuid(pwd->pw_uid); + if (*pwd->pw_shell == '\0') + pwd->pw_shell = _PATH_BSHELL; + /* turn on new line discipline for the csh */ + else if (!strcmp(pwd->pw_shell, _PATH_CSHELL)) { + ioctlval = NTTYDISC; + (void)ioctl(0, TIOCSETD, &ioctlval); + } + /* destroy environment unless user has requested preservation */ if (!pflag) environ = envinit; - setenv("HOME", pwd->pw_dir, 1); - setenv("SHELL", pwd->pw_shell, 1); + (void)setenv("HOME", pwd->pw_dir, 1); + (void)setenv("SHELL", pwd->pw_shell, 1); if (term[0] == '\0') strncpy(term, stypeof(tty), sizeof(term)); - setenv("TERM", term, 0); - setenv("USER", pwd->pw_name, 1); - setenv("PATH", ":/usr/ucb:/bin:/usr/bin", 0); + (void)setenv("TERM", term, 0); + (void)setenv("USER", pwd->pw_name, 1); + (void)setenv("PATH", "/usr/ucb:/bin:/usr/bin:", 0); if (tty[sizeof("tty")-1] == 'd') syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); if (pwd->pw_uid == 0) if (hostname) - syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s", - tty, UT_HOSTSIZE, hostname); + syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", + tty, hostname); else - syslog(LOG_NOTICE, "ROOT LOGIN %s", tty); + syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); if (!quietlog) { struct stat st; motd(); - (void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name); + (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name); if (stat(tbuf, &st) == 0 && st.st_size != 0) printf("You have %smail.\n", (st.st_mtime > st.st_atime) ? "new " : ""); @@ -360,8 +413,8 @@ main(argc, argv) strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell); execlp(pwd->pw_shell, tbuf, 0); + fprintf(stderr, "login: no shell: "); perror(pwd->pw_shell); - fprintf(stderr, "login: no shell\n"); exit(0); } @@ -372,14 +425,13 @@ getloginname() static char nbuf[UT_NAMESIZE + 1]; for (;;) { - p = nbuf; printf("login: "); - while ((ch = getchar()) != '\n') { - if (ch == ' ') - ch = '_'; - if (ch == EOF) + for (p = nbuf; (ch = getchar()) != '\n'; ) { + if (ch == EOF) { + badlogin(username); exit(0); - if (p < nbuf+UT_NAMESIZE) + } + if (p < nbuf + UT_NAMESIZE) *p++ = ch; } if (p > nbuf) @@ -389,10 +441,9 @@ getloginname() else { *p = '\0'; username = nbuf; - return; + break; } } - /* NOTREACHED */ } timedout() @@ -401,58 +452,59 @@ timedout() exit(0); } -rootterm(tty) - char *tty; +rootterm(ttyn) + char *ttyn; { struct ttyent *t; - return((t = getttynam(tty)) && t->ty_status&TTY_SECURE); + return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); } -int motdinterrupt; +jmp_buf motdinterrupt; + motd() { - register int ch; - FILE *fp; + register int fd, nchars; int (*oldint)(), sigint(); + char tbuf[8192]; - if ((fp = fopen(MOTDFILE, "r")) == NULL) + if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) return; oldint = signal(SIGINT, sigint); - while ((ch = getc(fp)) != EOF && !motdinterrupt) - (void)putchar(ch); + if (setjmp(motdinterrupt) == 0) + while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) + (void)write(fileno(stdout), tbuf, nchars); (void)signal(SIGINT, oldint); - if (motdinterrupt) - fpurge(fp); - (void)fclose(fp); + (void)close(fd); } sigint() { - motdinterrupt = 1; + longjmp(motdinterrupt, 1); } checknologin() { register int fd, nchars; - char tbuf[1024]; + char tbuf[8192]; - if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) { + if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) (void)write(fileno(stdout), tbuf, nchars); sleepexit(0); } } -dolastlog(quiet, tty) +dolastlog(quiet) int quiet; - char *tty; { struct lastlog ll; int fd; + char *ctime(); + char *ctime(); - if ((fd = open(LASTLOG, O_RDWR, 0)) >= 0) { - (void)lseek(fd, (long)pwd->pw_uid * sizeof(ll), L_SET); + if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { + (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); if (!quiet) { if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && ll.ll_time != 0) { @@ -465,16 +517,31 @@ dolastlog(quiet, tty) printf("on %.*s\n", sizeof(ll.ll_line), ll.ll_line); } - (void)lseek(fd, (long)pwd->pw_uid * sizeof(ll), L_SET); + (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); } + bzero((char *)&ll, sizeof(ll)); (void)time(&ll.ll_time); strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); - strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); + if (hostname) + strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); (void)write(fd, (char *)&ll, sizeof(ll)); (void)close(fd); } } +badlogin(name) + char *name; +{ + if (failures == 0) + return; + if (hostname) + syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", + failures, failures > 1 ? "S" : "", hostname, name); + else + syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", + failures, failures > 1 ? "S" : "", tty, name); +} + #undef UNKNOWN #define UNKNOWN "su" @@ -487,28 +554,6 @@ stypeof(ttyid) return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); } -doremotelogin(host) - char *host; -{ - static char lusername[UT_NAMESIZE+1]; - char rusername[UT_NAMESIZE+1]; - - getstr(rusername, sizeof(rusername), "remuser"); - getstr(lusername, sizeof(lusername), "locuser"); - getstr(term, sizeof(term), "Terminal type"); - username = lusername; - if (getuid()) { - pwd = &nouser; - return(-1); - } - pwd = getpwnam(username); - if (pwd == NULL) { - pwd = &nouser; - return(-1); - } - return(ruserok(host, (pwd->pw_uid == 0), rusername, username)); -} - getstr(buf, cnt, err) char *buf, *err; int cnt; @@ -526,33 +571,6 @@ getstr(buf, cnt, err) } while (ch); } -char *speeds[] = { - "0", "50", "75", "110", "134", "150", "200", "300", "600", - "1200", "1800", "2400", "4800", "9600", "19200", "38400", -}; -#define NSPEEDS (sizeof(speeds) / sizeof(speeds[0])) - -doremoteterm(tp) - struct sgttyb *tp; -{ - register char *cp = index(term, '/'), **cpp; - char *speed; - - if (cp) { - *cp++ = '\0'; - speed = cp; - cp = index(speed, '/'); - if (cp) - *cp++ = '\0'; - for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) - if (strcmp(*cpp, speed) == 0) { - tp->sg_ispeed = tp->sg_ospeed = cpp-speeds; - break; - } - } - tp->sg_flags = ECHO|CRMOD|ANYP|XTABS; -} - sleepexit(eval) int eval; {