X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/c89291e2735ee3fd438d0fa2b74afc6f4878e617..f5576df6fd6c54ac0836b6cc9634f63a156f325a:/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 2762be24c3..e0955381ec 100644 --- a/usr/src/usr.bin/login/login.c +++ b/usr/src/usr.bin/login/login.c @@ -1,586 +1,582 @@ -/* - * Copyright (c) 1980 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, 1991 The Regents of the University + * of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ #ifndef lint char copyright[] = -"@(#) Copyright (c) 1980 Regents of the University of California.\n\ +"@(#) Copyright (c) 1980, 1987, 1988, 1991 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.13 (Berkeley) %G%"; -#endif not lint +static char sccsid[] = "@(#)login.c 5.73 (Berkeley) 6/29/91"; +#endif /* not lint */ /* * login [ name ] - * login -r hostname (for rlogind) - * login -h hostname (for telnetd, etc.) + * login -h hostname (for telnetd, etc.) + * login -f name (for pre-authenticated login: datakit, xterm, etc.) */ #include -#include #include #include #include #include -#include #include #include -#include -#include -#include #include #include #include #include +#include +#include +#include +#include +#include +#include "pathnames.h" -#define WRITENAME "write" /* name of group to own ttys */ -#define WRITEGID write_gid() /* gid that owns all ttys */ - -#define SCMPN(a, b) strncmp(a, b, sizeof(a)) -#define SCPYN(a, b) strncpy(a, b, sizeof(a)) - -#define NMAX sizeof(utmp.ut_name) -#define HMAX sizeof(utmp.ut_host) - -#define FALSE 0 -#define TRUE -1 +#define TTYGRPNAME "tty" /* name of group to own ttys */ -char nolog[] = "/etc/nologin"; -char qlog[] = ".hushlogin"; -char maildir[30] = "/usr/spool/mail/"; -char lastlog[] = "/usr/adm/lastlog"; -struct passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" }; -struct sgttyb ttyb; -struct utmp utmp; -char minusnam[16] = "-"; -char *envinit[] = { 0 }; /* now set by setenv calls */ /* - * This bounds the time given to login. We initialize it here - * so it can be patched on machines where it's too small. + * This bounds the time given to login. Not a define so it can + * be patched on machines where it's too small. */ -int timeout = 60; - -char term[64]; +int timeout = 300; +int rootlogin; +#ifdef KERBEROS +int notickets = 1; +char *instance; +char *krbtkfile_env; +int authok; +#endif struct passwd *pwd; -char *strcat(), *rindex(), *index(), *malloc(), *realloc(); -int timedout(); -char *ttyname(); -char *crypt(); -char *getpass(); -char *stypeof(); -extern char **environ; -extern int errno; - -struct tchars tc = { - CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK -}; -struct ltchars ltc = { - CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT -}; - -struct winsize win = { 0, 0, 0, 0 }; - -int rflag; -int usererr = -1; -char rusername[NMAX+1], lusername[NMAX+1]; -char rpassword[NMAX+1]; -char name[NMAX+1]; -char *rhost; +int failures; +char term[64], *envinit[1], *hostname, *username, *tty; main(argc, argv) - char *argv[]; + int argc; + char **argv; { - register char *namep; - int pflag = 0, hflag = 0, t, f, c; - int invalid, quietlog; - FILE *nlfd; - char *ttyn, *tty; - int ldisc = 0, zero = 0, i; - char **envnew; - - signal(SIGALRM, timedout); - alarm(timeout); - signal(SIGQUIT, SIG_IGN); - signal(SIGINT, SIG_IGN); - setpriority(PRIO_PROCESS, 0, 0); - quota(Q_SETUID, 0, 0, 0); + extern int optind; + extern char *optarg, **environ; + struct timeval tp; + struct group *gr; + register int ch; + register char *p; + int ask, fflag, hflag, pflag, cnt, uid; + int quietlog, rval; + char *domain, *salt, *ttyn; + char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; + char localhost[MAXHOSTNAMELEN]; + char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass(); + time_t time(); + off_t lseek(); + void timedout(); + + (void)signal(SIGALRM, timedout); + (void)alarm((u_int)timeout); + (void)signal(SIGQUIT, SIG_IGN); + (void)signal(SIGINT, SIG_IGN); + (void)setpriority(PRIO_PROCESS, 0, 0); + + openlog("login", LOG_ODELAY, LOG_AUTH); + /* * -p is used by getty to tell login not to destroy the environment - * -r is used by rlogind to cause the autologin protocol; - * -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 + * -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 */ - while (argc > 1) { - if (strcmp(argv[1], "-r") == 0) { - if (rflag || hflag) { - printf("Only one of -r and -h allowed\n"); - exit(1); - } - rflag = 1; - usererr = doremotelogin(argv[2]); - SCPYN(utmp.ut_host, argv[2]); - argc -= 2; - argv += 2; - continue; - } - if (strcmp(argv[1], "-h") == 0 && getuid() == 0) { - if (rflag || hflag) { - printf("Only one of -r and -h allowed\n"); + domain = NULL; + if (gethostname(localhost, sizeof(localhost)) < 0) + syslog(LOG_ERR, "couldn't get local hostname: %m"); + else + domain = index(localhost, '.'); + + fflag = hflag = pflag = 0; + uid = getuid(); + while ((ch = getopt(argc, argv, "fh:p")) != EOF) + switch (ch) { + case 'f': + fflag = 1; + break; + case 'h': + if (uid) { + (void)fprintf(stderr, + "login: -h option: %s\n", strerror(EPERM)); exit(1); } hflag = 1; - SCPYN(utmp.ut_host, argv[2]); - argc -= 2; - argv += 2; - continue; - } - if (strcmp(argv[1], "-p") == 0) { - argc--; - argv++; + if (domain && (p = index(optarg, '.')) && + strcasecmp(p, domain) == 0) + *p = 0; + hostname = optarg; + break; + case 'p': pflag = 1; - continue; + break; + case '?': + default: + if (!uid) + syslog(LOG_ERR, "invalid flag %c", ch); + (void)fprintf(stderr, + "usage: login [-fp] [-h hostname] [username]\n"); + exit(1); } - break; - } - ioctl(0, TIOCLSET, &zero); - ioctl(0, TIOCNXCL, 0); - ioctl(0, FIONBIO, &zero); - ioctl(0, FIOASYNC, &zero); - ioctl(0, TIOCGETP, &ttyb); - /* - * If talking to an rlogin process, - * propagate the terminal type and - * baud rate across the network. - */ - if (rflag) - doremoteterm(term, &ttyb); - ttyb.sg_erase = CERASE; - ttyb.sg_kill = CKILL; - ioctl(0, TIOCSLTC, <c); - ioctl(0, TIOCSETC, &tc); - ioctl(0, TIOCSETP, &ttyb); - for (t = getdtablesize(); t > 2; t--) - close(t); + argc -= optind; + argv += optind; + if (*argv) { + username = *argv; + ask = 0; + } else + ask = 1; + + for (cnt = getdtablesize(); cnt > 2; cnt--) + close(cnt); + ttyn = ttyname(0); - if (ttyn == (char *)0 || *ttyn == '\0') - ttyn = "/dev/tty??"; - tty = rindex(ttyn, '/'); - if (tty == NULL) - tty = ttyn; + if (ttyn == NULL || *ttyn == '\0') { + (void)sprintf(tname, "%s??", _PATH_TTY); + ttyn = tname; + } + if (tty = rindex(ttyn, '/')) + ++tty; else - tty++; - openlog("login", LOG_ODELAY, LOG_AUTH); - t = 0; - invalid = FALSE; - do { - ldisc = 0; - ioctl(0, TIOCSETD, &ldisc); - SCPYN(utmp.ut_name, ""); - /* - * Name specified, take it. - */ - if (argc > 1) { - SCPYN(utmp.ut_name, argv[1]); - argc = 0; + tty = ttyn; + + for (cnt = 0;; ask = 1) { + if (ask) { + fflag = 0; + getloginname(); } - /* - * If remote login take given name, - * otherwise prompt user for something. - */ - if (rflag && !invalid) - SCPYN(utmp.ut_name, lusername); - else - getloginname(&utmp); - invalid = FALSE; - if (!strcmp(pwd->pw_shell, "/bin/csh")) { - ldisc = NTTYDISC; - ioctl(0, TIOCSETD, &ldisc); +#ifdef KERBEROS + if ((instance = index(username, '.')) != NULL) { + if (strncmp(instance, ".root", 5) == 0) + rootlogin++; + *instance++ = '\0'; + } else { + rootlogin = 0; + instance = ""; } +#else + rootlogin = 0; +#endif + if (strlen(username) > UT_NAMESIZE) + username[UT_NAMESIZE] = '\0'; + /* - * If no remote login authentication and - * a password exists for this user, prompt - * for one and verify it. + * 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 (usererr == -1 && *pwd->pw_passwd != '\0') { - char *pp; - - setpriority(PRIO_PROCESS, 0, -4); - pp = getpass("Password:"); - namep = crypt(pp, pwd->pw_passwd); - setpriority(PRIO_PROCESS, 0, 0); - if (strcmp(namep, pwd->pw_passwd)) - invalid = TRUE; + 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 logins disabled. + * if we have a valid account name, and it doesn't have a + * password, or the -f option was specified and the caller + * is root or the caller isn't changing their uid, don't + * authenticate. */ - if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) { - while ((c = getc(nlfd)) != EOF) - putchar(c); - fflush(stdout); - sleep(5); - exit(0); + if (pwd && (*pwd->pw_passwd == '\0' || + fflag && (uid == 0 || uid == pwd->pw_uid))) + break; + fflag = 0; + if (pwd && pwd->pw_uid == 0) + rootlogin = 1; + + (void)setpriority(PRIO_PROCESS, 0, -4); + + p = getpass("Password:"); + + if (pwd) { +#ifdef KERBEROS + rval = klogin(pwd, instance, localhost, p); + if (rval == 0) + authok = 1; + else if (rval == 1) { + if (pwd->pw_uid != 0) + rootlogin = 0; + rval = strcmp(crypt(p, salt), pwd->pw_passwd); + } +#else + if (pwd->pw_uid != 0) + rootlogin = 0; +#ifdef DES + rval = strcmp(crypt(p, salt), pwd->pw_passwd); +#else + rval = strcmp(p, pwd->pw_passwd); +#endif +#endif } + bzero(p, strlen(p)); + + (void)setpriority(PRIO_PROCESS, 0, 0); + /* - * If valid so far and root is logging in, - * see if root logins on this terminal are permitted. + * If trying to log in as root without Kerberos, + * but with insecure terminal, refuse the login attempt. */ - if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) { - if (utmp.ut_host[0]) - syslog(LOG_CRIT, - "ROOT LOGIN REFUSED ON %s FROM %.*s", - tty, HMAX, utmp.ut_host); +#ifdef KERBEROS + if (authok == 0) +#endif + if (pwd && rootlogin && !rootterm(tty)) { + (void)fprintf(stderr, + "%s login refused on this terminal.\n", + pwd->pw_name); + if (hostname) + syslog(LOG_NOTICE, + "LOGIN %s REFUSED FROM %s ON TTY %s", + pwd->pw_name, hostname, tty); else - syslog(LOG_CRIT, - "ROOT LOGIN REFUSED ON %s", tty); - invalid = TRUE; - } - if (invalid) { - printf("Login incorrect\n"); - if (++t >= 5) { - if (utmp.ut_host[0]) - syslog(LOG_CRIT, - "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s", - tty, HMAX, utmp.ut_host, - NMAX, utmp.ut_name); - else - syslog(LOG_CRIT, - "REPEATED LOGIN FAILURES ON %s, %.*s", - tty, NMAX, utmp.ut_name); - ioctl(0, TIOCHPCL, (struct sgttyb *) 0); - close(0), close(1), close(2); - sleep(10); - exit(1); - } + syslog(LOG_NOTICE, + "LOGIN %s REFUSED ON TTY %s", + pwd->pw_name, tty); + continue; } - if (*pwd->pw_shell == '\0') - pwd->pw_shell = "/bin/sh"; - if (chdir(pwd->pw_dir) < 0 && !invalid ) { - if (chdir("/") < 0) { - printf("No directory!\n"); - invalid = TRUE; - } else { - printf("No directory! %s\n", - "Logging in with home=/"); - pwd->pw_dir = "/"; + + if (pwd && !rval) + break; + + (void)printf("Login incorrect\n"); + failures++; + /* we allow 10 tries, but after 3 we start backing off */ + if (++cnt > 3) { + if (cnt >= 10) { + badlogin(username); + sleepexit(1); } + sleep((u_int)((cnt - 3) * 5)); } - /* - * Remote login invalid must have been because - * of a restriction of some sort, no extra chances. - */ - if (!usererr && invalid) - exit(1); - } while (invalid); -/* committed to login turn off timeout */ - alarm(0); - - if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { - if (errno == EUSERS) - printf("%s.\n%s.\n", - "Too many users logged on already", - "Try again later"); - else if (errno == EPROCLIM) - printf("You have too many processes running.\n"); - else - perror("quota (Q_SETUID)"); - sleep(5); - exit(0); - } - time(&utmp.ut_time); - t = ttyslot(); - if (t > 0 && (f = open("/etc/utmp", O_WRONLY)) >= 0) { - lseek(f, (long)(t*sizeof(utmp)), 0); - SCPYN(utmp.ut_line, tty); - write(f, (char *)&utmp, sizeof(utmp)); - close(f); } - if ((f = open("/usr/adm/wtmp", O_WRONLY|O_APPEND)) >= 0) { - write(f, (char *)&utmp, sizeof(utmp)); - close(f); + + /* committed to login -- turn off timeout */ + (void)alarm((u_int)0); + + endpwent(); + + /* if user not super-user, check for disabled logins */ + if (!rootlogin) + checknologin(); + + if (chdir(pwd->pw_dir) < 0) { + (void)printf("No home directory %s!\n", pwd->pw_dir); + if (chdir("/")) + exit(0); + pwd->pw_dir = "/"; + (void)printf("Logging in with home = \"/\".\n"); } - quietlog = access(qlog, F_OK) == 0; - if ((f = open(lastlog, O_RDWR)) >= 0) { - struct lastlog ll; - - lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); - if (read(f, (char *) &ll, sizeof ll) == sizeof ll && - ll.ll_time != 0 && !quietlog) { - printf("Last login: %.*s ", - 24-5, (char *)ctime(&ll.ll_time)); - if (*ll.ll_host != '\0') - printf("from %.*s\n", - sizeof (ll.ll_host), ll.ll_host); - else - printf("on %.*s\n", - sizeof (ll.ll_line), ll.ll_line); - } - lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); - time(&ll.ll_time); - SCPYN(ll.ll_line, tty); - SCPYN(ll.ll_host, utmp.ut_host); - write(f, (char *) &ll, sizeof ll); - close(f); + + quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; + + if (pwd->pw_change || pwd->pw_expire) + (void)gettimeofday(&tp, (struct timezone *)NULL); + if (pwd->pw_change) + if (tp.tv_sec >= pwd->pw_change) { + (void)printf("Sorry -- your password has expired.\n"); + sleepexit(1); + } else if (pwd->pw_change - tp.tv_sec < + 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) + (void)printf("Warning: your password expires on %s", + ctime(&pwd->pw_expire)); + if (pwd->pw_expire) + if (tp.tv_sec >= pwd->pw_expire) { + (void)printf("Sorry -- your account has expired.\n"); + sleepexit(1); + } else if (pwd->pw_expire - tp.tv_sec < + 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) + (void)printf("Warning: your account expires on %s", + ctime(&pwd->pw_expire)); + + /* nothing else left to fail -- really log in */ + { + struct utmp utmp; + + bzero((void *)&utmp, sizeof(utmp)); + (void)time(&utmp.ut_time); + strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); + if (hostname) + strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); + strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); + login(&utmp); } - chown(ttyn, pwd->pw_uid, WRITEGID); - if (!hflag && !rflag) /* XXX */ - ioctl(0, TIOCSWINSZ, &win); - chmod(ttyn, 0620); - setgid(pwd->pw_gid); - strncpy(name, utmp.ut_name, NMAX); - name[NMAX] = '\0'; - initgroups(name, pwd->pw_gid); - quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); - setuid(pwd->pw_uid); - /* destroy environment unless user has asked to preserve it */ + + dolastlog(quietlog); + + (void)chown(ttyn, pwd->pw_uid, + (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); + (void)setgid(pwd->pw_gid); + + initgroups(username, pwd->pw_gid); + + if (*pwd->pw_shell == '\0') + pwd->pw_shell = _PATH_BSHELL; + + /* destroy environment unless user has requested preservation */ if (!pflag) environ = envinit; - - /* set up environment, this time without destruction */ - /* copy the environment before setenving */ - i = 0; - while (environ[i] != NULL) - i++; - envnew = (char **) malloc(sizeof (char *) * (i + 1)); - for (; i >= 0; i--) - envnew[i] = environ[i]; - environ = envnew; - - 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("LOGNAME", pwd->pw_name, 1); + (void)setenv("USER", pwd->pw_name, 1); + (void)setenv("PATH", _PATH_DEFPATH, 0); +#ifdef KERBEROS + if (krbtkfile_env) + (void)setenv("KRBTKFILE", krbtkfile_env, 1); +#endif - if ((namep = rindex(pwd->pw_shell, '/')) == NULL) - namep = pwd->pw_shell; - else - namep++; - strcat(minusnam, namep); if (tty[sizeof("tty")-1] == 'd') syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); - if (pwd->pw_uid == 0) - if (utmp.ut_host[0]) - syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s", - tty, HMAX, utmp.ut_host); + /* if fflag is on, assume caller/authenticator has logged root login */ + if (rootlogin && fflag == 0) + if (hostname) + syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", + username, tty, hostname); else - syslog(LOG_NOTICE, "ROOT LOGIN %s", tty); + syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty); + +#ifdef KERBEROS + if (!quietlog && notickets == 1) + (void)printf("Warning: no Kerberos tickets issued.\n"); +#endif + if (!quietlog) { struct stat st; - showmotd(); - strcat(maildir, pwd->pw_name); - if (stat(maildir, &st) == 0 && st.st_size != 0) - printf("You have %smail.\n", - (st.st_mtime > st.st_atime) ? "new " : ""); + printf("%s%s", + "386BSD Release 0.1 by William and Lynne Jolitz.\n", +"Copyright (c) 1989,1990,1991,1992 William F. Jolitz. All rights reserved.\n\ +Based in part on work by the 386BSD User Community and the\n\ +BSD Networking Software, Release 2 by UCB EECS Department.\n"); + + motd(); + (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name); + if (stat(tbuf, &st) == 0 && st.st_size != 0) + (void)printf("You have %smail.\n", + (st.st_mtime > st.st_atime) ? "new " : ""); } - signal(SIGALRM, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGTSTP, SIG_IGN); - execlp(pwd->pw_shell, minusnam, 0); - perror(pwd->pw_shell); - printf("No shell\n"); - exit(0); + + (void)signal(SIGALRM, SIG_DFL); + (void)signal(SIGQUIT, SIG_DFL); + (void)signal(SIGINT, SIG_DFL); + (void)signal(SIGTSTP, SIG_IGN); + + tbuf[0] = '-'; + strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? + p + 1 : pwd->pw_shell); + + if (setlogin(pwd->pw_name) < 0) + syslog(LOG_ERR, "setlogin() failure: %m"); + + /* discard permissions last so can't get killed and drop core */ + if (rootlogin) + (void) setuid(0); + else + (void) setuid(pwd->pw_uid); + + execlp(pwd->pw_shell, tbuf, 0); + (void)fprintf(stderr, "%s: %s\n", pwd->pw_shell, strerror(errno)); + exit(1); } -getloginname(up) - register struct utmp *up; +#ifdef KERBEROS +#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */ +#else +#define NBUFSIZ (UT_NAMESIZE + 1) +#endif + +getloginname() { - register char *namep; - char c; - - while (up->ut_name[0] == '\0') { - namep = up->ut_name; - printf("login: "); - while ((c = getchar()) != '\n') { - if (c == ' ') - c = '_'; - if (c == EOF) + register int ch; + register char *p; + static char nbuf[NBUFSIZ]; + + for (;;) { + (void)printf("login: "); + for (p = nbuf; (ch = getchar()) != '\n'; ) { + if (ch == EOF) { + badlogin(username); exit(0); - if (namep < up->ut_name+NMAX) - *namep++ = c; + } + if (p < nbuf + (NBUFSIZ - 1)) + *p++ = ch; } + if (p > nbuf) + if (nbuf[0] == '-') + (void)fprintf(stderr, + "login names may not start with '-'.\n"); + else { + *p = '\0'; + username = nbuf; + break; + } } - strncpy(lusername, up->ut_name, NMAX); - lusername[NMAX] = 0; - if ((pwd = getpwnam(lusername)) == NULL) - pwd = &nouser; } +void timedout() { - - printf("Login timed out after %d seconds\n", timeout); + (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); exit(0); } -int stopmotd; -catch() +rootterm(ttyn) + char *ttyn; { + struct ttyent *t; - signal(SIGINT, SIG_IGN); - stopmotd++; -} - -rootterm(tty) - char *tty; -{ - register struct ttyent *t; - - if ((t = getttynam(tty)) != NULL) { - if (t->ty_status & TTY_SECURE) - return (1); - } - return (0); -} - -showmotd() -{ - FILE *mf; - register c; - - signal(SIGINT, catch); - if ((mf = fopen("/etc/motd", "r")) != NULL) { - while ((c = getc(mf)) != EOF && stopmotd == 0) - putchar(c); - fclose(mf); - } - signal(SIGINT, SIG_IGN); + return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); } -#undef UNKNOWN -#define UNKNOWN "su" +jmp_buf motdinterrupt; -char * -stypeof(ttyid) - char *ttyid; +motd() { - register struct ttyent *t; - - if (ttyid == NULL || (t = getttynam(ttyid)) == NULL) - return (UNKNOWN); - return (t->ty_type); + register int fd, nchars; + sig_t oldint; + void sigint(); + char tbuf[8192]; + + if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) + return; + oldint = signal(SIGINT, sigint); + if (setjmp(motdinterrupt) == 0) + while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) + (void)write(fileno(stdout), tbuf, nchars); + (void)signal(SIGINT, oldint); + (void)close(fd); } -doremotelogin(host) - char *host; +void +sigint() { - getstr(rusername, sizeof (rusername), "remuser"); - getstr(lusername, sizeof (lusername), "locuser"); - getstr(term, sizeof(term), "Terminal type"); - if (getuid()) { - pwd = &nouser; - return(-1); - } - pwd = getpwnam(lusername); - if (pwd == NULL) { - pwd = &nouser; - return(-1); - } - return(ruserok(host, (pwd->pw_uid == 0), rusername, lusername)); + longjmp(motdinterrupt, 1); } -getstr(buf, cnt, err) - char *buf; - int cnt; - char *err; +checknologin() { - char c; + register int fd, nchars; + char tbuf[8192]; - do { - if (read(0, &c, 1) != 1) - exit(1); - if (--cnt < 0) { - printf("%s too long\r\n", err); - exit(1); - } - *buf++ = c; - } while (c != 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); + } } -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(term, tp) - char *term; - struct sgttyb *tp; +dolastlog(quiet) + int quiet; { - 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; + struct lastlog ll; + int fd; + char *ctime(); + + 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) { + (void)printf("Last login: %.*s ", + 24-5, (char *)ctime(&ll.ll_time)); + if (*ll.ll_host != '\0') + (void)printf("from %.*s\n", + sizeof(ll.ll_host), ll.ll_host); + else + (void)printf("on %.*s\n", + sizeof(ll.ll_line), ll.ll_line); } + (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); + } + bzero((void *)&ll, sizeof(ll)); + (void)time(&ll.ll_time); + strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); + if (hostname) + strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); + (void)write(fd, (char *)&ll, sizeof(ll)); + (void)close(fd); } - tp->sg_flags = ECHO|CRMOD|ANYP|XTABS; } -/* - * Set the value of var to be arg in the Unix 4.2 BSD environment env. - * Var should end with '='. - * (bindings are of the form "var=value") - * This procedure assumes the memory for the first level of environ - * was allocated using malloc. - */ -setenv(var, value, clobber) - char *var, *value; +badlogin(name) + char *name; { - extern char **environ; - int index = 0; - int varlen = strlen(var); - int vallen = strlen(value); - - for (index = 0; environ[index] != NULL; index++) { - if (strncmp(environ[index], var, varlen) == 0) { - /* found it */ - if (!clobber) - return; - environ[index] = malloc(varlen + vallen + 1); - strcpy(environ[index], var); - strcat(environ[index], value); - return; - } + if (failures == 0) + return; + if (hostname) { + syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", + failures, failures > 1 ? "S" : "", hostname); + syslog(LOG_AUTHPRIV|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", + failures, failures > 1 ? "S" : "", tty); + syslog(LOG_AUTHPRIV|LOG_NOTICE, + "%d LOGIN FAILURE%s ON %s, %s", + failures, failures > 1 ? "S" : "", tty, name); } - environ = (char **) realloc(environ, sizeof (char *) * (index + 2)); - if (environ == NULL) { - fprintf(stderr, "login: malloc out of memory\n"); - exit(1); - } - environ[index] = malloc(varlen + vallen + 1); - strcpy(environ[index], var); - strcat(environ[index], value); - environ[++index] = NULL; } -write_gid() -{ - struct group *getgrnam(), *gr; - int gid = 0; +#undef UNKNOWN +#define UNKNOWN "su" - gr = getgrnam(WRITENAME); - if (gr != (struct group *) 0) - gid = gr->gr_gid; +char * +stypeof(ttyid) + char *ttyid; +{ + struct ttyent *t; - endgrent(); + return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); +} - return gid; +sleepexit(eval) + int eval; +{ + sleep((u_int)5); + exit(eval); }