Home | History | Annotate | Line # | Download | only in login
login.c revision 1.1
      1  1.1  cgd /*-
      2  1.1  cgd  * Copyright (c) 1980, 1987, 1988, 1991 The Regents of the University
      3  1.1  cgd  * of California.  All rights reserved.
      4  1.1  cgd  *
      5  1.1  cgd  * Redistribution and use in source and binary forms, with or without
      6  1.1  cgd  * modification, are permitted provided that the following conditions
      7  1.1  cgd  * are met:
      8  1.1  cgd  * 1. Redistributions of source code must retain the above copyright
      9  1.1  cgd  *    notice, this list of conditions and the following disclaimer.
     10  1.1  cgd  * 2. Redistributions in binary form must reproduce the above copyright
     11  1.1  cgd  *    notice, this list of conditions and the following disclaimer in the
     12  1.1  cgd  *    documentation and/or other materials provided with the distribution.
     13  1.1  cgd  * 3. All advertising materials mentioning features or use of this software
     14  1.1  cgd  *    must display the following acknowledgement:
     15  1.1  cgd  *	This product includes software developed by the University of
     16  1.1  cgd  *	California, Berkeley and its contributors.
     17  1.1  cgd  * 4. Neither the name of the University nor the names of its contributors
     18  1.1  cgd  *    may be used to endorse or promote products derived from this software
     19  1.1  cgd  *    without specific prior written permission.
     20  1.1  cgd  *
     21  1.1  cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  1.1  cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  1.1  cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  1.1  cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  1.1  cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  1.1  cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  1.1  cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  1.1  cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  1.1  cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  1.1  cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  1.1  cgd  * SUCH DAMAGE.
     32  1.1  cgd  */
     33  1.1  cgd 
     34  1.1  cgd #ifndef lint
     35  1.1  cgd char copyright[] =
     36  1.1  cgd "@(#) Copyright (c) 1980, 1987, 1988, 1991 The Regents of the University of California.\n\
     37  1.1  cgd  All rights reserved.\n";
     38  1.1  cgd #endif /* not lint */
     39  1.1  cgd 
     40  1.1  cgd #ifndef lint
     41  1.1  cgd static char sccsid[] = "@(#)login.c	5.73 (Berkeley) 6/29/91";
     42  1.1  cgd #endif /* not lint */
     43  1.1  cgd 
     44  1.1  cgd /*
     45  1.1  cgd  * login [ name ]
     46  1.1  cgd  * login -h hostname	(for telnetd, etc.)
     47  1.1  cgd  * login -f name	(for pre-authenticated login: datakit, xterm, etc.)
     48  1.1  cgd  */
     49  1.1  cgd 
     50  1.1  cgd #include <sys/param.h>
     51  1.1  cgd #include <sys/stat.h>
     52  1.1  cgd #include <sys/time.h>
     53  1.1  cgd #include <sys/resource.h>
     54  1.1  cgd #include <sys/file.h>
     55  1.1  cgd 
     56  1.1  cgd #include <utmp.h>
     57  1.1  cgd #include <signal.h>
     58  1.1  cgd #include <errno.h>
     59  1.1  cgd #include <ttyent.h>
     60  1.1  cgd #include <syslog.h>
     61  1.1  cgd #include <grp.h>
     62  1.1  cgd #include <pwd.h>
     63  1.1  cgd #include <setjmp.h>
     64  1.1  cgd #include <stdio.h>
     65  1.1  cgd #include <string.h>
     66  1.1  cgd #include <tzfile.h>
     67  1.1  cgd #include "pathnames.h"
     68  1.1  cgd 
     69  1.1  cgd #define	TTYGRPNAME	"tty"		/* name of group to own ttys */
     70  1.1  cgd 
     71  1.1  cgd /*
     72  1.1  cgd  * This bounds the time given to login.  Not a define so it can
     73  1.1  cgd  * be patched on machines where it's too small.
     74  1.1  cgd  */
     75  1.1  cgd int	timeout = 300;
     76  1.1  cgd int	rootlogin;
     77  1.1  cgd #ifdef KERBEROS
     78  1.1  cgd int	notickets = 1;
     79  1.1  cgd char	*instance;
     80  1.1  cgd char	*krbtkfile_env;
     81  1.1  cgd int	authok;
     82  1.1  cgd #endif
     83  1.1  cgd 
     84  1.1  cgd struct	passwd *pwd;
     85  1.1  cgd int	failures;
     86  1.1  cgd char	term[64], *envinit[1], *hostname, *username, *tty;
     87  1.1  cgd 
     88  1.1  cgd main(argc, argv)
     89  1.1  cgd 	int argc;
     90  1.1  cgd 	char **argv;
     91  1.1  cgd {
     92  1.1  cgd 	extern int optind;
     93  1.1  cgd 	extern char *optarg, **environ;
     94  1.1  cgd 	struct timeval tp;
     95  1.1  cgd 	struct group *gr;
     96  1.1  cgd 	register int ch;
     97  1.1  cgd 	register char *p;
     98  1.1  cgd 	int ask, fflag, hflag, pflag, cnt, uid;
     99  1.1  cgd 	int quietlog, rval;
    100  1.1  cgd 	char *domain, *salt, *ttyn;
    101  1.1  cgd 	char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
    102  1.1  cgd 	char localhost[MAXHOSTNAMELEN];
    103  1.1  cgd 	char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass();
    104  1.1  cgd 	time_t time();
    105  1.1  cgd 	off_t lseek();
    106  1.1  cgd 	void timedout();
    107  1.1  cgd 
    108  1.1  cgd 	(void)signal(SIGALRM, timedout);
    109  1.1  cgd 	(void)alarm((u_int)timeout);
    110  1.1  cgd 	(void)signal(SIGQUIT, SIG_IGN);
    111  1.1  cgd 	(void)signal(SIGINT, SIG_IGN);
    112  1.1  cgd 	(void)setpriority(PRIO_PROCESS, 0, 0);
    113  1.1  cgd 
    114  1.1  cgd 	openlog("login", LOG_ODELAY, LOG_AUTH);
    115  1.1  cgd 
    116  1.1  cgd 	/*
    117  1.1  cgd 	 * -p is used by getty to tell login not to destroy the environment
    118  1.1  cgd  	 * -f is used to skip a second login authentication
    119  1.1  cgd 	 * -h is used by other servers to pass the name of the remote
    120  1.1  cgd 	 *    host to login so that it may be placed in utmp and wtmp
    121  1.1  cgd 	 */
    122  1.1  cgd 	domain = NULL;
    123  1.1  cgd 	if (gethostname(localhost, sizeof(localhost)) < 0)
    124  1.1  cgd 		syslog(LOG_ERR, "couldn't get local hostname: %m");
    125  1.1  cgd 	else
    126  1.1  cgd 		domain = index(localhost, '.');
    127  1.1  cgd 
    128  1.1  cgd 	fflag = hflag = pflag = 0;
    129  1.1  cgd 	uid = getuid();
    130  1.1  cgd 	while ((ch = getopt(argc, argv, "fh:p")) != EOF)
    131  1.1  cgd 		switch (ch) {
    132  1.1  cgd 		case 'f':
    133  1.1  cgd 			fflag = 1;
    134  1.1  cgd 			break;
    135  1.1  cgd 		case 'h':
    136  1.1  cgd 			if (uid) {
    137  1.1  cgd 				(void)fprintf(stderr,
    138  1.1  cgd 				    "login: -h option: %s\n", strerror(EPERM));
    139  1.1  cgd 				exit(1);
    140  1.1  cgd 			}
    141  1.1  cgd 			hflag = 1;
    142  1.1  cgd 			if (domain && (p = index(optarg, '.')) &&
    143  1.1  cgd 			    strcasecmp(p, domain) == 0)
    144  1.1  cgd 				*p = 0;
    145  1.1  cgd 			hostname = optarg;
    146  1.1  cgd 			break;
    147  1.1  cgd 		case 'p':
    148  1.1  cgd 			pflag = 1;
    149  1.1  cgd 			break;
    150  1.1  cgd 		case '?':
    151  1.1  cgd 		default:
    152  1.1  cgd 			if (!uid)
    153  1.1  cgd 				syslog(LOG_ERR, "invalid flag %c", ch);
    154  1.1  cgd 			(void)fprintf(stderr,
    155  1.1  cgd 			    "usage: login [-fp] [-h hostname] [username]\n");
    156  1.1  cgd 			exit(1);
    157  1.1  cgd 		}
    158  1.1  cgd 	argc -= optind;
    159  1.1  cgd 	argv += optind;
    160  1.1  cgd 	if (*argv) {
    161  1.1  cgd 		username = *argv;
    162  1.1  cgd 		ask = 0;
    163  1.1  cgd 	} else
    164  1.1  cgd 		ask = 1;
    165  1.1  cgd 
    166  1.1  cgd 	for (cnt = getdtablesize(); cnt > 2; cnt--)
    167  1.1  cgd 		close(cnt);
    168  1.1  cgd 
    169  1.1  cgd 	ttyn = ttyname(0);
    170  1.1  cgd 	if (ttyn == NULL || *ttyn == '\0') {
    171  1.1  cgd 		(void)sprintf(tname, "%s??", _PATH_TTY);
    172  1.1  cgd 		ttyn = tname;
    173  1.1  cgd 	}
    174  1.1  cgd 	if (tty = rindex(ttyn, '/'))
    175  1.1  cgd 		++tty;
    176  1.1  cgd 	else
    177  1.1  cgd 		tty = ttyn;
    178  1.1  cgd 
    179  1.1  cgd 	for (cnt = 0;; ask = 1) {
    180  1.1  cgd 		if (ask) {
    181  1.1  cgd 			fflag = 0;
    182  1.1  cgd 			getloginname();
    183  1.1  cgd 		}
    184  1.1  cgd #ifdef	KERBEROS
    185  1.1  cgd 		if ((instance = index(username, '.')) != NULL) {
    186  1.1  cgd 			if (strncmp(instance, ".root", 5) == 0)
    187  1.1  cgd 				rootlogin++;
    188  1.1  cgd 			*instance++ = '\0';
    189  1.1  cgd 		} else {
    190  1.1  cgd 			rootlogin = 0;
    191  1.1  cgd 			instance = "";
    192  1.1  cgd 		}
    193  1.1  cgd #else
    194  1.1  cgd 		rootlogin = 0;
    195  1.1  cgd #endif
    196  1.1  cgd 		if (strlen(username) > UT_NAMESIZE)
    197  1.1  cgd 			username[UT_NAMESIZE] = '\0';
    198  1.1  cgd 
    199  1.1  cgd 		/*
    200  1.1  cgd 		 * Note if trying multiple user names; log failures for
    201  1.1  cgd 		 * previous user name, but don't bother logging one failure
    202  1.1  cgd 		 * for nonexistent name (mistyped username).
    203  1.1  cgd 		 */
    204  1.1  cgd 		if (failures && strcmp(tbuf, username)) {
    205  1.1  cgd 			if (failures > (pwd ? 0 : 1))
    206  1.1  cgd 				badlogin(tbuf);
    207  1.1  cgd 			failures = 0;
    208  1.1  cgd 		}
    209  1.1  cgd 		(void)strcpy(tbuf, username);
    210  1.1  cgd 
    211  1.1  cgd 		if (pwd = getpwnam(username))
    212  1.1  cgd 			salt = pwd->pw_passwd;
    213  1.1  cgd 		else
    214  1.1  cgd 			salt = "xx";
    215  1.1  cgd 
    216  1.1  cgd 		/*
    217  1.1  cgd 		 * if we have a valid account name, and it doesn't have a
    218  1.1  cgd 		 * password, or the -f option was specified and the caller
    219  1.1  cgd 		 * is root or the caller isn't changing their uid, don't
    220  1.1  cgd 		 * authenticate.
    221  1.1  cgd 		 */
    222  1.1  cgd 		if (pwd && (*pwd->pw_passwd == '\0' ||
    223  1.1  cgd 		    fflag && (uid == 0 || uid == pwd->pw_uid)))
    224  1.1  cgd 			break;
    225  1.1  cgd 		fflag = 0;
    226  1.1  cgd 		if (pwd && pwd->pw_uid == 0)
    227  1.1  cgd 			rootlogin = 1;
    228  1.1  cgd 
    229  1.1  cgd 		(void)setpriority(PRIO_PROCESS, 0, -4);
    230  1.1  cgd 
    231  1.1  cgd 		p = getpass("Password:");
    232  1.1  cgd 
    233  1.1  cgd 		if (pwd) {
    234  1.1  cgd #ifdef KERBEROS
    235  1.1  cgd 			rval = klogin(pwd, instance, localhost, p);
    236  1.1  cgd 			if (rval == 0)
    237  1.1  cgd 				authok = 1;
    238  1.1  cgd 			else if (rval == 1) {
    239  1.1  cgd 				if (pwd->pw_uid != 0)
    240  1.1  cgd 					rootlogin = 0;
    241  1.1  cgd 				rval = strcmp(crypt(p, salt), pwd->pw_passwd);
    242  1.1  cgd 			}
    243  1.1  cgd #else
    244  1.1  cgd 			if (pwd->pw_uid != 0)
    245  1.1  cgd 				rootlogin = 0;
    246  1.1  cgd #ifdef DES
    247  1.1  cgd 			rval = strcmp(crypt(p, salt), pwd->pw_passwd);
    248  1.1  cgd #else
    249  1.1  cgd 			rval = strcmp(p, pwd->pw_passwd);
    250  1.1  cgd #endif
    251  1.1  cgd #endif
    252  1.1  cgd 		}
    253  1.1  cgd 		bzero(p, strlen(p));
    254  1.1  cgd 
    255  1.1  cgd 		(void)setpriority(PRIO_PROCESS, 0, 0);
    256  1.1  cgd 
    257  1.1  cgd 		/*
    258  1.1  cgd 		 * If trying to log in as root without Kerberos,
    259  1.1  cgd 		 * but with insecure terminal, refuse the login attempt.
    260  1.1  cgd 		 */
    261  1.1  cgd #ifdef KERBEROS
    262  1.1  cgd 		if (authok == 0)
    263  1.1  cgd #endif
    264  1.1  cgd 		if (pwd && rootlogin && !rootterm(tty)) {
    265  1.1  cgd 			(void)fprintf(stderr,
    266  1.1  cgd 			    "%s login refused on this terminal.\n",
    267  1.1  cgd 			    pwd->pw_name);
    268  1.1  cgd 			if (hostname)
    269  1.1  cgd 				syslog(LOG_NOTICE,
    270  1.1  cgd 				    "LOGIN %s REFUSED FROM %s ON TTY %s",
    271  1.1  cgd 				    pwd->pw_name, hostname, tty);
    272  1.1  cgd 			else
    273  1.1  cgd 				syslog(LOG_NOTICE,
    274  1.1  cgd 				    "LOGIN %s REFUSED ON TTY %s",
    275  1.1  cgd 				     pwd->pw_name, tty);
    276  1.1  cgd 			continue;
    277  1.1  cgd 		}
    278  1.1  cgd 
    279  1.1  cgd 		if (pwd && !rval)
    280  1.1  cgd 			break;
    281  1.1  cgd 
    282  1.1  cgd 		(void)printf("Login incorrect\n");
    283  1.1  cgd 		failures++;
    284  1.1  cgd 		/* we allow 10 tries, but after 3 we start backing off */
    285  1.1  cgd 		if (++cnt > 3) {
    286  1.1  cgd 			if (cnt >= 10) {
    287  1.1  cgd 				badlogin(username);
    288  1.1  cgd 				sleepexit(1);
    289  1.1  cgd 			}
    290  1.1  cgd 			sleep((u_int)((cnt - 3) * 5));
    291  1.1  cgd 		}
    292  1.1  cgd 	}
    293  1.1  cgd 
    294  1.1  cgd 	/* committed to login -- turn off timeout */
    295  1.1  cgd 	(void)alarm((u_int)0);
    296  1.1  cgd 
    297  1.1  cgd 	endpwent();
    298  1.1  cgd 
    299  1.1  cgd 	/* if user not super-user, check for disabled logins */
    300  1.1  cgd 	if (!rootlogin)
    301  1.1  cgd 		checknologin();
    302  1.1  cgd 
    303  1.1  cgd 	if (chdir(pwd->pw_dir) < 0) {
    304  1.1  cgd 		(void)printf("No home directory %s!\n", pwd->pw_dir);
    305  1.1  cgd 		if (chdir("/"))
    306  1.1  cgd 			exit(0);
    307  1.1  cgd 		pwd->pw_dir = "/";
    308  1.1  cgd 		(void)printf("Logging in with home = \"/\".\n");
    309  1.1  cgd 	}
    310  1.1  cgd 
    311  1.1  cgd 	quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
    312  1.1  cgd 
    313  1.1  cgd 	if (pwd->pw_change || pwd->pw_expire)
    314  1.1  cgd 		(void)gettimeofday(&tp, (struct timezone *)NULL);
    315  1.1  cgd 	if (pwd->pw_change)
    316  1.1  cgd 		if (tp.tv_sec >= pwd->pw_change) {
    317  1.1  cgd 			(void)printf("Sorry -- your password has expired.\n");
    318  1.1  cgd 			sleepexit(1);
    319  1.1  cgd 		} else if (pwd->pw_change - tp.tv_sec <
    320  1.1  cgd 		    2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
    321  1.1  cgd 			(void)printf("Warning: your password expires on %s",
    322  1.1  cgd 			    ctime(&pwd->pw_expire));
    323  1.1  cgd 	if (pwd->pw_expire)
    324  1.1  cgd 		if (tp.tv_sec >= pwd->pw_expire) {
    325  1.1  cgd 			(void)printf("Sorry -- your account has expired.\n");
    326  1.1  cgd 			sleepexit(1);
    327  1.1  cgd 		} else if (pwd->pw_expire - tp.tv_sec <
    328  1.1  cgd 		    2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
    329  1.1  cgd 			(void)printf("Warning: your account expires on %s",
    330  1.1  cgd 			    ctime(&pwd->pw_expire));
    331  1.1  cgd 
    332  1.1  cgd 	/* nothing else left to fail -- really log in */
    333  1.1  cgd 	{
    334  1.1  cgd 		struct utmp utmp;
    335  1.1  cgd 
    336  1.1  cgd 		bzero((void *)&utmp, sizeof(utmp));
    337  1.1  cgd 		(void)time(&utmp.ut_time);
    338  1.1  cgd 		strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
    339  1.1  cgd 		if (hostname)
    340  1.1  cgd 			strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
    341  1.1  cgd 		strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
    342  1.1  cgd 		login(&utmp);
    343  1.1  cgd 	}
    344  1.1  cgd 
    345  1.1  cgd 	dolastlog(quietlog);
    346  1.1  cgd 
    347  1.1  cgd 	(void)chown(ttyn, pwd->pw_uid,
    348  1.1  cgd 	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
    349  1.1  cgd 	(void)setgid(pwd->pw_gid);
    350  1.1  cgd 
    351  1.1  cgd 	initgroups(username, pwd->pw_gid);
    352  1.1  cgd 
    353  1.1  cgd 	if (*pwd->pw_shell == '\0')
    354  1.1  cgd 		pwd->pw_shell = _PATH_BSHELL;
    355  1.1  cgd 
    356  1.1  cgd 	/* destroy environment unless user has requested preservation */
    357  1.1  cgd 	if (!pflag)
    358  1.1  cgd 		environ = envinit;
    359  1.1  cgd 	(void)setenv("HOME", pwd->pw_dir, 1);
    360  1.1  cgd 	(void)setenv("SHELL", pwd->pw_shell, 1);
    361  1.1  cgd 	if (term[0] == '\0')
    362  1.1  cgd 		strncpy(term, stypeof(tty), sizeof(term));
    363  1.1  cgd 	(void)setenv("TERM", term, 0);
    364  1.1  cgd 	(void)setenv("LOGNAME", pwd->pw_name, 1);
    365  1.1  cgd 	(void)setenv("USER", pwd->pw_name, 1);
    366  1.1  cgd 	(void)setenv("PATH", _PATH_DEFPATH, 0);
    367  1.1  cgd #ifdef KERBEROS
    368  1.1  cgd 	if (krbtkfile_env)
    369  1.1  cgd 		(void)setenv("KRBTKFILE", krbtkfile_env, 1);
    370  1.1  cgd #endif
    371  1.1  cgd 
    372  1.1  cgd 	if (tty[sizeof("tty")-1] == 'd')
    373  1.1  cgd 		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
    374  1.1  cgd 	/* if fflag is on, assume caller/authenticator has logged root login */
    375  1.1  cgd 	if (rootlogin && fflag == 0)
    376  1.1  cgd 		if (hostname)
    377  1.1  cgd 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
    378  1.1  cgd 			    username, tty, hostname);
    379  1.1  cgd 		else
    380  1.1  cgd 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
    381  1.1  cgd 
    382  1.1  cgd #ifdef KERBEROS
    383  1.1  cgd 	if (!quietlog && notickets == 1)
    384  1.1  cgd 		(void)printf("Warning: no Kerberos tickets issued.\n");
    385  1.1  cgd #endif
    386  1.1  cgd 
    387  1.1  cgd 	if (!quietlog) {
    388  1.1  cgd 		struct stat st;
    389  1.1  cgd 
    390  1.1  cgd 		printf("%s%s",
    391  1.1  cgd 			"386BSD Release 0.1 by William and Lynne Jolitz.\n",
    392  1.1  cgd "Copyright (c) 1989,1990,1991,1992 William F. Jolitz. All rights reserved.\n\
    393  1.1  cgd Based in part on work by the 386BSD User Community and the\n\
    394  1.1  cgd BSD Networking Software, Release 2 by UCB EECS Department.\n");
    395  1.1  cgd 
    396  1.1  cgd 		motd();
    397  1.1  cgd 		(void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name);
    398  1.1  cgd 		if (stat(tbuf, &st) == 0 && st.st_size != 0)
    399  1.1  cgd 			(void)printf("You have %smail.\n",
    400  1.1  cgd 			    (st.st_mtime > st.st_atime) ? "new " : "");
    401  1.1  cgd 	}
    402  1.1  cgd 
    403  1.1  cgd 	(void)signal(SIGALRM, SIG_DFL);
    404  1.1  cgd 	(void)signal(SIGQUIT, SIG_DFL);
    405  1.1  cgd 	(void)signal(SIGINT, SIG_DFL);
    406  1.1  cgd 	(void)signal(SIGTSTP, SIG_IGN);
    407  1.1  cgd 
    408  1.1  cgd 	tbuf[0] = '-';
    409  1.1  cgd 	strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ?
    410  1.1  cgd 	    p + 1 : pwd->pw_shell);
    411  1.1  cgd 
    412  1.1  cgd 	if (setlogin(pwd->pw_name) < 0)
    413  1.1  cgd 		syslog(LOG_ERR, "setlogin() failure: %m");
    414  1.1  cgd 
    415  1.1  cgd 	/* discard permissions last so can't get killed and drop core */
    416  1.1  cgd 	if (rootlogin)
    417  1.1  cgd 		(void) setuid(0);
    418  1.1  cgd 	else
    419  1.1  cgd 		(void) setuid(pwd->pw_uid);
    420  1.1  cgd 
    421  1.1  cgd 	execlp(pwd->pw_shell, tbuf, 0);
    422  1.1  cgd 	(void)fprintf(stderr, "%s: %s\n", pwd->pw_shell, strerror(errno));
    423  1.1  cgd 	exit(1);
    424  1.1  cgd }
    425  1.1  cgd 
    426  1.1  cgd #ifdef	KERBEROS
    427  1.1  cgd #define	NBUFSIZ		(UT_NAMESIZE + 1 + 5) /* .root suffix */
    428  1.1  cgd #else
    429  1.1  cgd #define	NBUFSIZ		(UT_NAMESIZE + 1)
    430  1.1  cgd #endif
    431  1.1  cgd 
    432  1.1  cgd getloginname()
    433  1.1  cgd {
    434  1.1  cgd 	register int ch;
    435  1.1  cgd 	register char *p;
    436  1.1  cgd 	static char nbuf[NBUFSIZ];
    437  1.1  cgd 
    438  1.1  cgd 	for (;;) {
    439  1.1  cgd 		(void)printf("login: ");
    440  1.1  cgd 		for (p = nbuf; (ch = getchar()) != '\n'; ) {
    441  1.1  cgd 			if (ch == EOF) {
    442  1.1  cgd 				badlogin(username);
    443  1.1  cgd 				exit(0);
    444  1.1  cgd 			}
    445  1.1  cgd 			if (p < nbuf + (NBUFSIZ - 1))
    446  1.1  cgd 				*p++ = ch;
    447  1.1  cgd 		}
    448  1.1  cgd 		if (p > nbuf)
    449  1.1  cgd 			if (nbuf[0] == '-')
    450  1.1  cgd 				(void)fprintf(stderr,
    451  1.1  cgd 				    "login names may not start with '-'.\n");
    452  1.1  cgd 			else {
    453  1.1  cgd 				*p = '\0';
    454  1.1  cgd 				username = nbuf;
    455  1.1  cgd 				break;
    456  1.1  cgd 			}
    457  1.1  cgd 	}
    458  1.1  cgd }
    459  1.1  cgd 
    460  1.1  cgd void
    461  1.1  cgd timedout()
    462  1.1  cgd {
    463  1.1  cgd 	(void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
    464  1.1  cgd 	exit(0);
    465  1.1  cgd }
    466  1.1  cgd 
    467  1.1  cgd rootterm(ttyn)
    468  1.1  cgd 	char *ttyn;
    469  1.1  cgd {
    470  1.1  cgd 	struct ttyent *t;
    471  1.1  cgd 
    472  1.1  cgd 	return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE);
    473  1.1  cgd }
    474  1.1  cgd 
    475  1.1  cgd jmp_buf motdinterrupt;
    476  1.1  cgd 
    477  1.1  cgd motd()
    478  1.1  cgd {
    479  1.1  cgd 	register int fd, nchars;
    480  1.1  cgd 	sig_t oldint;
    481  1.1  cgd 	void sigint();
    482  1.1  cgd 	char tbuf[8192];
    483  1.1  cgd 
    484  1.1  cgd 	if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
    485  1.1  cgd 		return;
    486  1.1  cgd 	oldint = signal(SIGINT, sigint);
    487  1.1  cgd 	if (setjmp(motdinterrupt) == 0)
    488  1.1  cgd 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
    489  1.1  cgd 			(void)write(fileno(stdout), tbuf, nchars);
    490  1.1  cgd 	(void)signal(SIGINT, oldint);
    491  1.1  cgd 	(void)close(fd);
    492  1.1  cgd }
    493  1.1  cgd 
    494  1.1  cgd void
    495  1.1  cgd sigint()
    496  1.1  cgd {
    497  1.1  cgd 	longjmp(motdinterrupt, 1);
    498  1.1  cgd }
    499  1.1  cgd 
    500  1.1  cgd checknologin()
    501  1.1  cgd {
    502  1.1  cgd 	register int fd, nchars;
    503  1.1  cgd 	char tbuf[8192];
    504  1.1  cgd 
    505  1.1  cgd 	if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
    506  1.1  cgd 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
    507  1.1  cgd 			(void)write(fileno(stdout), tbuf, nchars);
    508  1.1  cgd 		sleepexit(0);
    509  1.1  cgd 	}
    510  1.1  cgd }
    511  1.1  cgd 
    512  1.1  cgd dolastlog(quiet)
    513  1.1  cgd 	int quiet;
    514  1.1  cgd {
    515  1.1  cgd 	struct lastlog ll;
    516  1.1  cgd 	int fd;
    517  1.1  cgd 	char *ctime();
    518  1.1  cgd 
    519  1.1  cgd 	if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
    520  1.1  cgd 		(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
    521  1.1  cgd 		if (!quiet) {
    522  1.1  cgd 			if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
    523  1.1  cgd 			    ll.ll_time != 0) {
    524  1.1  cgd 				(void)printf("Last login: %.*s ",
    525  1.1  cgd 				    24-5, (char *)ctime(&ll.ll_time));
    526  1.1  cgd 				if (*ll.ll_host != '\0')
    527  1.1  cgd 					(void)printf("from %.*s\n",
    528  1.1  cgd 					    sizeof(ll.ll_host), ll.ll_host);
    529  1.1  cgd 				else
    530  1.1  cgd 					(void)printf("on %.*s\n",
    531  1.1  cgd 					    sizeof(ll.ll_line), ll.ll_line);
    532  1.1  cgd 			}
    533  1.1  cgd 			(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
    534  1.1  cgd 		}
    535  1.1  cgd 		bzero((void *)&ll, sizeof(ll));
    536  1.1  cgd 		(void)time(&ll.ll_time);
    537  1.1  cgd 		strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
    538  1.1  cgd 		if (hostname)
    539  1.1  cgd 			strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
    540  1.1  cgd 		(void)write(fd, (char *)&ll, sizeof(ll));
    541  1.1  cgd 		(void)close(fd);
    542  1.1  cgd 	}
    543  1.1  cgd }
    544  1.1  cgd 
    545  1.1  cgd badlogin(name)
    546  1.1  cgd 	char *name;
    547  1.1  cgd {
    548  1.1  cgd 	if (failures == 0)
    549  1.1  cgd 		return;
    550  1.1  cgd 	if (hostname) {
    551  1.1  cgd 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
    552  1.1  cgd 		    failures, failures > 1 ? "S" : "", hostname);
    553  1.1  cgd 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
    554  1.1  cgd 		    "%d LOGIN FAILURE%s FROM %s, %s",
    555  1.1  cgd 		    failures, failures > 1 ? "S" : "", hostname, name);
    556  1.1  cgd 	} else {
    557  1.1  cgd 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
    558  1.1  cgd 		    failures, failures > 1 ? "S" : "", tty);
    559  1.1  cgd 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
    560  1.1  cgd 		    "%d LOGIN FAILURE%s ON %s, %s",
    561  1.1  cgd 		    failures, failures > 1 ? "S" : "", tty, name);
    562  1.1  cgd 	}
    563  1.1  cgd }
    564  1.1  cgd 
    565  1.1  cgd #undef	UNKNOWN
    566  1.1  cgd #define	UNKNOWN	"su"
    567  1.1  cgd 
    568  1.1  cgd char *
    569  1.1  cgd stypeof(ttyid)
    570  1.1  cgd 	char *ttyid;
    571  1.1  cgd {
    572  1.1  cgd 	struct ttyent *t;
    573  1.1  cgd 
    574  1.1  cgd 	return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
    575  1.1  cgd }
    576  1.1  cgd 
    577  1.1  cgd sleepexit(eval)
    578  1.1  cgd 	int eval;
    579  1.1  cgd {
    580  1.1  cgd 	sleep((u_int)5);
    581  1.1  cgd 	exit(eval);
    582  1.1  cgd }
    583