Home | History | Annotate | Line # | Download | only in login
login.c revision 1.41
      1 /*     $NetBSD: login.c,v 1.41 1999/01/06 13:52:23 lukem Exp $       */
      2 
      3 /*-
      4  * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 #ifndef lint
     38 __COPYRIGHT(
     39 "@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\
     40 	The Regents of the University of California.  All rights reserved.\n");
     41 #endif /* not lint */
     42 
     43 #ifndef lint
     44 #if 0
     45 static char sccsid[] = "@(#)login.c	8.4 (Berkeley) 4/2/94";
     46 #endif
     47 __RCSID("$NetBSD: login.c,v 1.41 1999/01/06 13:52:23 lukem Exp $");
     48 #endif /* not lint */
     49 
     50 /*
     51  * login [ name ]
     52  * login -h hostname	(for telnetd, etc.)
     53  * login -f name	(for pre-authenticated login: datakit, xterm, etc.)
     54  */
     55 
     56 #include <sys/param.h>
     57 #include <sys/stat.h>
     58 #include <sys/time.h>
     59 #include <sys/resource.h>
     60 #include <sys/file.h>
     61 #include <sys/wait.h>
     62 
     63 #include <err.h>
     64 #include <errno.h>
     65 #include <grp.h>
     66 #include <pwd.h>
     67 #include <setjmp.h>
     68 #include <signal.h>
     69 #include <stdio.h>
     70 #include <stdlib.h>
     71 #include <string.h>
     72 #include <syslog.h>
     73 #include <time.h>
     74 #include <ttyent.h>
     75 #include <tzfile.h>
     76 #include <unistd.h>
     77 #include <utmp.h>
     78 #include <util.h>
     79 #ifdef SKEY
     80 #include <skey.h>
     81 #endif
     82 #ifdef KERBEROS5
     83 #include <krb5.h>
     84 #endif
     85 
     86 #include "pathnames.h"
     87 
     88 void	 badlogin __P((char *));
     89 void	 checknologin __P((void));
     90 void	 dolastlog __P((int));
     91 void	 getloginname __P((void));
     92 int	 main __P((int, char *[]));
     93 void	 motd __P((void));
     94 int	 rootterm __P((char *));
     95 void	 sigint __P((int));
     96 void	 sleepexit __P((int));
     97 const	 char *stypeof __P((const char *));
     98 void	 timedout __P((int));
     99 #if defined(KERBEROS) || defined(KERBEROS5)
    100 int	 klogin __P((struct passwd *, char *, char *, char *));
    101 void	 kdestroy __P((void));
    102 void	 dofork __P((void));
    103 #endif
    104 
    105 extern void login __P((struct utmp *));
    106 
    107 #define	TTYGRPNAME	"tty"		/* name of group to own ttys */
    108 
    109 /*
    110  * This bounds the time given to login.  Not a define so it can
    111  * be patched on machines where it's too small.
    112  */
    113 u_int	timeout = 300;
    114 
    115 #if defined(KERBEROS) || defined(KERBEROS5)
    116 int	notickets = 1;
    117 char	*instance;
    118 char	*krbtkfile_env;
    119 #endif
    120 #ifdef KERBEROS5
    121 extern krb5_context kcontext;
    122 #endif
    123 
    124 struct	passwd *pwd;
    125 int	failures;
    126 char	term[64], *envinit[1], *hostname, *username, *tty;
    127 
    128 static const char copyrightstr[] = "\
    129 Copyright (c) 1996, 1997, 1998, 1999
    130 \tThe NetBSD Foundation, Inc.  All rights reserved.
    131 Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
    132 \tThe Regents of the University of California.  All rights reserved.\n\n";
    133 
    134 int
    135 main(argc, argv)
    136 	int argc;
    137 	char *argv[];
    138 {
    139 	extern char **environ;
    140 	struct group *gr;
    141 	struct stat st;
    142 	struct timeval tp;
    143 	struct utmp utmp;
    144 	int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval;
    145 	uid_t uid, saved_uid;
    146 	gid_t saved_gid, saved_gids[NGROUPS_MAX];
    147 	int nsaved_gids;
    148 	char *domain, *p, *ttyn, *pwprompt;
    149 	const char *salt;
    150 	char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
    151 	char localhost[MAXHOSTNAMELEN + 1];
    152 	int need_chpass, require_chpass;
    153 #ifdef KERBEROS5
    154 	krb5_error_code kerror;
    155 #endif
    156 
    157 	tbuf[0] = '\0';
    158 	rval = 0;
    159 	pwprompt = NULL;
    160 	need_chpass = require_chpass = 0;
    161 
    162 	(void)signal(SIGALRM, timedout);
    163 	(void)alarm(timeout);
    164 	(void)signal(SIGQUIT, SIG_IGN);
    165 	(void)signal(SIGINT, SIG_IGN);
    166 	(void)setpriority(PRIO_PROCESS, 0, 0);
    167 
    168 	openlog("login", LOG_ODELAY, LOG_AUTH);
    169 
    170 	/*
    171 	 * -p is used by getty to tell login not to destroy the environment
    172 	 * -f is used to skip a second login authentication
    173 	 * -h is used by other servers to pass the name of the remote
    174 	 *    host to login so that it may be placed in utmp and wtmp
    175 	 * -s is used to force use of S/Key or equivalent.
    176 	 */
    177 	domain = NULL;
    178 	if (gethostname(localhost, sizeof(localhost)) < 0)
    179 		syslog(LOG_ERR, "couldn't get local hostname: %m");
    180 	else
    181 		domain = strchr(localhost, '.');
    182 	localhost[sizeof(localhost) - 1] = '\0';
    183 
    184 	fflag = hflag = pflag = sflag = 0;
    185 	uid = getuid();
    186 	while ((ch = getopt(argc, argv, "fh:ps")) != -1)
    187 		switch (ch) {
    188 		case 'f':
    189 			fflag = 1;
    190 			break;
    191 		case 'h':
    192 			if (uid)
    193 				errx(1, "-h option: %s", strerror(EPERM));
    194 			hflag = 1;
    195 			if (domain && (p = strchr(optarg, '.')) != NULL &&
    196 			    strcasecmp(p, domain) == 0)
    197 				*p = 0;
    198 			hostname = optarg;
    199 			break;
    200 		case 'p':
    201 			pflag = 1;
    202 			break;
    203 		case 's':
    204 			sflag = 1;
    205 			break;
    206 		default:
    207 		case '?':
    208 			(void)fprintf(stderr,
    209 			    "usage: login [-fps] [-h hostname] [username]\n");
    210 			exit(1);
    211 		}
    212 	argc -= optind;
    213 	argv += optind;
    214 
    215 	if (*argv) {
    216 		username = *argv;
    217 		ask = 0;
    218 	} else
    219 		ask = 1;
    220 
    221 	for (cnt = getdtablesize(); cnt > 2; cnt--)
    222 		(void)close(cnt);
    223 
    224 	ttyn = ttyname(STDIN_FILENO);
    225 	if (ttyn == NULL || *ttyn == '\0') {
    226 		(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
    227 		ttyn = tname;
    228 	}
    229 	if ((tty = strrchr(ttyn, '/')) != NULL)
    230 		++tty;
    231 	else
    232 		tty = ttyn;
    233 
    234 #ifdef KERBEROS5
    235 	kerror = krb5_init_context(&kcontext);
    236 	if (kerror) {
    237 		syslog(LOG_NOTICE, "%s when initializing Kerberos context",
    238 		    error_message(kerror));
    239 		exit(1);
    240 	}
    241 #endif KERBEROS5
    242 
    243 	for (cnt = 0;; ask = 1) {
    244 #if defined(KERBEROS) || defined(KERBEROS5)
    245 	        kdestroy();
    246 #endif
    247 		if (ask) {
    248 			fflag = 0;
    249 			getloginname();
    250 		}
    251 		rootlogin = 0;
    252 #ifdef KERBEROS
    253 		if ((instance = strchr(username, '.')) != NULL)
    254 			*instance++ = '\0';
    255 		else
    256 			instance = "";
    257 #endif
    258 #ifdef KERBEROS5
    259 		if ((instance = strchr(username, '/')) != NULL)
    260 			*instance++ = '\0';
    261 		else
    262 			instance = "";
    263 #endif
    264 		if (strlen(username) > MAXLOGNAME)
    265 			username[MAXLOGNAME] = '\0';
    266 
    267 		/*
    268 		 * Note if trying multiple user names; log failures for
    269 		 * previous user name, but don't bother logging one failure
    270 		 * for nonexistent name (mistyped username).
    271 		 */
    272 		if (failures && strcmp(tbuf, username)) {
    273 			if (failures > (pwd ? 0 : 1))
    274 				badlogin(tbuf);
    275 			failures = 0;
    276 		}
    277 		(void)strncpy(tbuf, username, sizeof(tbuf) - 1);
    278 		tbuf[sizeof(tbuf) - 1] = '\0';
    279 
    280 		if ((pwd = getpwnam(username)) != NULL)
    281 			salt = pwd->pw_passwd;
    282 		else
    283 			salt = "xx";
    284 
    285 		/*
    286 		 * if we have a valid account name, and it doesn't have a
    287 		 * password, or the -f option was specified and the caller
    288 		 * is root or the caller isn't changing their uid, don't
    289 		 * authenticate.
    290 		 */
    291 		if (pwd) {
    292 			if (pwd->pw_uid == 0)
    293 				rootlogin = 1;
    294 
    295 			if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
    296 				/* already authenticated */
    297 				break;
    298 			} else if (pwd->pw_passwd[0] == '\0') {
    299 				/* pretend password okay */
    300 				rval = 0;
    301 				goto ttycheck;
    302 			}
    303 		}
    304 
    305 		fflag = 0;
    306 
    307 		(void)setpriority(PRIO_PROCESS, 0, -4);
    308 
    309 #ifdef SKEY
    310 		if (skey_haskey(username) == 0) {
    311 			static char skprompt[80];
    312 			char *skinfo = skey_keyinfo(username);
    313 
    314 			(void)snprintf(skprompt, sizeof(skprompt)-1,
    315 			    "Password [%s]:",
    316 			    skinfo ? skinfo : "error getting challenge");
    317 			pwprompt = skprompt;
    318 		} else
    319 #endif
    320 			pwprompt = "Password:";
    321 
    322 		p = getpass(pwprompt);
    323 
    324 		if (pwd == NULL) {
    325 			rval = 1;
    326 			goto skip;
    327 		}
    328 #ifdef KERBEROS
    329 		if (klogin(pwd, instance, localhost, p) == 0) {
    330 			rval = 0;
    331 			goto skip;
    332 		}
    333 #endif
    334 #ifdef KERBEROS5
    335 		if (klogin(pwd, instance, localhost, p) == 0) {
    336 			rval = 0;
    337 			goto skip;
    338 		}
    339 #endif
    340 #ifdef SKEY
    341 		if (skey_haskey(username) == 0 &&
    342 		    skey_passcheck(username, p) != -1) {
    343 			rval = 0;
    344 			goto skip;
    345 		}
    346 #endif
    347 		if (!sflag && *pwd->pw_passwd != '\0' &&
    348 		    !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
    349 			rval = 0;
    350 			require_chpass = 1;
    351 			goto skip;
    352 		}
    353 		rval = 1;
    354 
    355 	skip:
    356 		memset(p, 0, strlen(p));
    357 
    358 		(void)setpriority(PRIO_PROCESS, 0, 0);
    359 
    360 	ttycheck:
    361 		/*
    362 		 * If trying to log in as root without Kerberos,
    363 		 * but with insecure terminal, refuse the login attempt.
    364 		 */
    365 		if (pwd && !rval && rootlogin && !rootterm(tty)) {
    366 			(void)fprintf(stderr,
    367 			    "%s login refused on this terminal.\n",
    368 			    pwd->pw_name);
    369 			if (hostname)
    370 				syslog(LOG_NOTICE,
    371 				    "LOGIN %s REFUSED FROM %s ON TTY %s",
    372 				    pwd->pw_name, hostname, tty);
    373 			else
    374 				syslog(LOG_NOTICE,
    375 				    "LOGIN %s REFUSED ON TTY %s",
    376 				     pwd->pw_name, tty);
    377 			continue;
    378 		}
    379 
    380 		if (pwd && !rval)
    381 			break;
    382 
    383 		(void)printf("Login incorrect\n");
    384 		failures++;
    385 		/* we allow 10 tries, but after 3 we start backing off */
    386 		if (++cnt > 3) {
    387 			if (cnt >= 10) {
    388 				badlogin(username);
    389 				sleepexit(1);
    390 			}
    391 			sleep((u_int)((cnt - 3) * 5));
    392 		}
    393 	}
    394 
    395 	/* committed to login -- turn off timeout */
    396 	(void)alarm((u_int)0);
    397 
    398 	endpwent();
    399 
    400 	/* if user not super-user, check for disabled logins */
    401 	if (!rootlogin)
    402 		checknologin();
    403 
    404 	/* Temporarily give up special privileges so we can change */
    405 	/* into NFS-mounted homes that are exported for non-root */
    406 	/* access and have mode 7x0 */
    407 	saved_uid = geteuid();
    408 	saved_gid = getegid();
    409 	nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
    410 
    411 	(void)setegid(pwd->pw_gid);
    412 	initgroups(username, pwd->pw_gid);
    413 	(void)seteuid(pwd->pw_uid);
    414 
    415 	if (chdir(pwd->pw_dir) < 0) {
    416 		(void)printf("No home directory %s!\n", pwd->pw_dir);
    417 		if (chdir("/"))
    418 			exit(0);
    419 		pwd->pw_dir = "/";
    420 		(void)printf("Logging in with home = \"/\".\n");
    421 	}
    422 
    423 	quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
    424 
    425 	/* regain special privileges */
    426 	(void)seteuid(saved_uid);
    427 	setgroups(nsaved_gids, saved_gids);
    428 	(void)setegid(saved_gid);
    429 
    430 	if (pwd->pw_change || pwd->pw_expire)
    431 		(void)gettimeofday(&tp, (struct timezone *)NULL);
    432 	if (pwd->pw_expire) {
    433 		if (tp.tv_sec >= pwd->pw_expire) {
    434 			(void)printf("Sorry -- your account has expired.\n");
    435 			sleepexit(1);
    436 		} else if (pwd->pw_expire - tp.tv_sec <
    437 		    _PASSWORD_WARNDAYS * SECSPERDAY && !quietlog)
    438 			(void)printf("Warning: your account expires on %s",
    439 			    ctime(&pwd->pw_expire));
    440 	}
    441 	if (pwd->pw_change) {
    442 		if (pwd->pw_change == _PASSWORD_CHGNOW)
    443 			need_chpass = 1;
    444 		else if (tp.tv_sec >= pwd->pw_change) {
    445 			(void)printf("Sorry -- your password has expired.\n");
    446 			sleepexit(1);
    447 		} else if (pwd->pw_change - tp.tv_sec <
    448 		    _PASSWORD_WARNDAYS * SECSPERDAY && !quietlog)
    449 			(void)printf("Warning: your password expires on %s",
    450 			    ctime(&pwd->pw_change));
    451 
    452 	}
    453 	/* Nothing else left to fail -- really log in. */
    454 	memset((void *)&utmp, 0, sizeof(utmp));
    455 	(void)time(&utmp.ut_time);
    456 	(void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
    457 	if (hostname)
    458 		(void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
    459 	(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
    460 	login(&utmp);
    461 
    462 	dolastlog(quietlog);
    463 
    464 	(void)chown(ttyn, pwd->pw_uid,
    465 	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
    466 
    467 	if (ttyaction(ttyn, "login", pwd->pw_name))
    468 		(void)printf("Warning: ttyaction failed.\n");
    469 
    470 #if defined(KERBEROS) || defined(KERBEROS5)
    471 	/* Fork so that we can call kdestroy */
    472 	if (krbtkfile_env)
    473 		dofork();
    474 #endif
    475 	(void)setgid(pwd->pw_gid);
    476 
    477 	initgroups(username, pwd->pw_gid);
    478 
    479 	if (*pwd->pw_shell == '\0')
    480 		pwd->pw_shell = _PATH_BSHELL;
    481 
    482 	/* Destroy environment unless user has requested its preservation. */
    483 	if (!pflag)
    484 		environ = envinit;
    485 	(void)setenv("HOME", pwd->pw_dir, 1);
    486 	(void)setenv("SHELL", pwd->pw_shell, 1);
    487 	if (term[0] == '\0')
    488 		(void)strncpy(term, stypeof(tty), sizeof(term));
    489 	(void)setenv("TERM", term, 0);
    490 	(void)setenv("LOGNAME", pwd->pw_name, 1);
    491 	(void)setenv("USER", pwd->pw_name, 1);
    492 	(void)setenv("PATH", _PATH_DEFPATH, 0);
    493 #ifdef KERBEROS
    494 	if (krbtkfile_env)
    495 		(void)setenv("KRBTKFILE", krbtkfile_env, 1);
    496 #endif
    497 #ifdef KERBEROS5
    498 	if (krbtkfile_env)
    499 		(void)setenv("KRB5CCNAME", krbtkfile_env, 1);
    500 #endif
    501 
    502 	if (tty[sizeof("tty")-1] == 'd')
    503 		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
    504 
    505 	/* If fflag is on, assume caller/authenticator has logged root login. */
    506 	if (rootlogin && fflag == 0) {
    507 		if (hostname)
    508 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
    509 			    username, tty, hostname);
    510 		else
    511 			syslog(LOG_NOTICE,
    512 				"ROOT LOGIN (%s) ON %s", username, tty);
    513 	}
    514 
    515 #if defined(KERBEROS) || defined(KERBEROS5)
    516 	if (!quietlog && notickets == 1)
    517 		(void)printf("Warning: no Kerberos tickets issued.\n");
    518 #endif
    519 
    520 	if (!quietlog) {
    521 		(void)printf(copyrightstr);
    522 		motd();
    523 		(void)snprintf(tbuf,
    524 		    sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
    525 		if (stat(tbuf, &st) == 0 && st.st_size != 0)
    526 			(void)printf("You have %smail.\n",
    527 			    (st.st_mtime > st.st_atime) ? "new " : "");
    528 	}
    529 
    530 	(void)signal(SIGALRM, SIG_DFL);
    531 	(void)signal(SIGQUIT, SIG_DFL);
    532 	(void)signal(SIGINT, SIG_DFL);
    533 	(void)signal(SIGTSTP, SIG_IGN);
    534 
    535 	tbuf[0] = '-';
    536 	(void)strncpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
    537 	    p + 1 : pwd->pw_shell, sizeof(tbuf) - 2);
    538 
    539 	if (setlogin(pwd->pw_name) < 0)
    540 		syslog(LOG_ERR, "setlogin() failure: %m");
    541 
    542 	/* Discard permissions last so can't get killed and drop core. */
    543 	if (rootlogin)
    544 		(void)setuid(0);
    545 	else
    546 		(void)setuid(pwd->pw_uid);
    547 
    548 	/* Wait to change password until we're unprivileged */
    549 	if (need_chpass) {
    550 		if (!require_chpass)
    551 			(void)printf(
    552 "Warning: your password has expired. Please change it as soon as possible.\n");
    553 		else {
    554 			int	status;
    555 
    556 			(void)printf(
    557 		    "Your password has expired. Please choose a new one.\n");
    558 			switch (fork()) {
    559 			case -1:
    560 				warn("fork");
    561 				sleepexit(1);
    562 			case 0:
    563 				execl(_PATH_BINPASSWD, "passwd", 0);
    564 				_exit(1);
    565 			default:
    566 				if (wait(&status) == -1 ||
    567 				    WEXITSTATUS(status))
    568 					sleepexit(1);
    569 			}
    570 		}
    571 	}
    572 
    573 	execlp(pwd->pw_shell, tbuf, 0);
    574 	err(1, "%s", pwd->pw_shell);
    575 }
    576 
    577 #if defined(KERBEROS) || defined(KERBEROS5)
    578 #define	NBUFSIZ		(MAXLOGNAME + 1 + 5)	/* .root suffix */
    579 #else
    580 #define	NBUFSIZ		(MAXLOGNAME + 1)
    581 #endif
    582 
    583 #if defined(KERBEROS) || defined(KERBEROS5)
    584 /*
    585  * This routine handles cleanup stuff, and the like.
    586  * It exists only in the child process.
    587  */
    588 #include <sys/wait.h>
    589 void
    590 dofork()
    591 {
    592 	int child;
    593 
    594 	if (!(child = fork()))
    595 		return; /* Child process */
    596 
    597 	/* Setup stuff?  This would be things we could do in parallel with login */
    598 	(void) chdir("/");	/* Let's not keep the fs busy... */
    599 
    600 	/* If we're the parent, watch the child until it dies */
    601 	while (wait(0) != child)
    602 		;
    603 
    604 	/* Cleanup stuff */
    605 	/* Run kdestroy to destroy tickets */
    606 	kdestroy();
    607 
    608 	/* Leave */
    609 	exit(0);
    610 }
    611 #endif
    612 
    613 void
    614 getloginname()
    615 {
    616 	int ch;
    617 	char *p;
    618 	static char nbuf[NBUFSIZ];
    619 
    620 	for (;;) {
    621 		(void)printf("login: ");
    622 		for (p = nbuf; (ch = getchar()) != '\n'; ) {
    623 			if (ch == EOF) {
    624 				badlogin(username);
    625 				exit(0);
    626 			}
    627 			if (p < nbuf + (NBUFSIZ - 1))
    628 				*p++ = ch;
    629 		}
    630 		if (p > nbuf) {
    631 			if (nbuf[0] == '-')
    632 				(void)fprintf(stderr,
    633 				    "login names may not start with '-'.\n");
    634 			else {
    635 				*p = '\0';
    636 				username = nbuf;
    637 				break;
    638 			}
    639 		}
    640 	}
    641 }
    642 
    643 int
    644 rootterm(ttyn)
    645 	char *ttyn;
    646 {
    647 	struct ttyent *t;
    648 
    649 	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
    650 }
    651 
    652 jmp_buf motdinterrupt;
    653 
    654 void
    655 motd()
    656 {
    657 	int fd, nchars;
    658 	sig_t oldint;
    659 	char tbuf[8192];
    660 
    661 	if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
    662 		return;
    663 	oldint = signal(SIGINT, sigint);
    664 	if (setjmp(motdinterrupt) == 0)
    665 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
    666 			(void)write(fileno(stdout), tbuf, nchars);
    667 	(void)signal(SIGINT, oldint);
    668 	(void)close(fd);
    669 }
    670 
    671 /* ARGSUSED */
    672 void
    673 sigint(signo)
    674 	int signo;
    675 {
    676 
    677 	longjmp(motdinterrupt, 1);
    678 }
    679 
    680 /* ARGSUSED */
    681 void
    682 timedout(signo)
    683 	int signo;
    684 {
    685 
    686 	(void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
    687 	exit(0);
    688 }
    689 
    690 void
    691 checknologin()
    692 {
    693 	int fd, nchars;
    694 	char tbuf[8192];
    695 
    696 	if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
    697 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
    698 			(void)write(fileno(stdout), tbuf, nchars);
    699 		sleepexit(0);
    700 	}
    701 }
    702 
    703 void
    704 dolastlog(quiet)
    705 	int quiet;
    706 {
    707 	struct lastlog ll;
    708 	int fd;
    709 
    710 	if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
    711 		(void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
    712 		if (!quiet) {
    713 			if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
    714 			    ll.ll_time != 0) {
    715 				(void)printf("Last login: %.*s ",
    716 				    24-5, (char *)ctime(&ll.ll_time));
    717 				if (*ll.ll_host != '\0')
    718 					(void)printf("from %.*s\n",
    719 					    (int)sizeof(ll.ll_host),
    720 					    ll.ll_host);
    721 				else
    722 					(void)printf("on %.*s\n",
    723 					    (int)sizeof(ll.ll_line),
    724 					    ll.ll_line);
    725 			}
    726 			(void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
    727 			    SEEK_SET);
    728 		}
    729 		memset((void *)&ll, 0, sizeof(ll));
    730 		(void)time(&ll.ll_time);
    731 		(void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
    732 		if (hostname)
    733 			(void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
    734 		(void)write(fd, (char *)&ll, sizeof(ll));
    735 		(void)close(fd);
    736 	}
    737 }
    738 
    739 void
    740 badlogin(name)
    741 	char *name;
    742 {
    743 	if (failures == 0)
    744 		return;
    745 	if (hostname) {
    746 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
    747 		    failures, failures > 1 ? "S" : "", hostname);
    748 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
    749 		    "%d LOGIN FAILURE%s FROM %s, %s",
    750 		    failures, failures > 1 ? "S" : "", hostname, name);
    751 	} else {
    752 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
    753 		    failures, failures > 1 ? "S" : "", tty);
    754 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
    755 		    "%d LOGIN FAILURE%s ON %s, %s",
    756 		    failures, failures > 1 ? "S" : "", tty, name);
    757 	}
    758 }
    759 
    760 #undef	UNKNOWN
    761 #define	UNKNOWN	"su"
    762 
    763 const char *
    764 stypeof(ttyid)
    765 	const char *ttyid;
    766 {
    767 	struct ttyent *t;
    768 
    769 	return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
    770 }
    771 
    772 void
    773 sleepexit(eval)
    774 	int eval;
    775 {
    776 
    777 	(void)sleep(5);
    778 	exit(eval);
    779 }
    780