Home | History | Annotate | Line # | Download | only in login
login.c revision 1.38
      1 /*     $NetBSD: login.c,v 1.38 1998/07/11 08:12:51 mrg 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.38 1998/07/11 08:12:51 mrg 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 char	*stypeof __P((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
    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, *salt, *ttyn, *pwprompt;
    149 	char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
    150 	char localhost[MAXHOSTNAMELEN + 1];
    151 	int need_chpass, require_chpass;
    152 #ifdef KERBEROS5
    153 	krb5_error_code kerror;
    154 #endif
    155 
    156 	tbuf[0] = '\0';
    157 	rval = 0;
    158 	pwprompt = NULL;
    159 	need_chpass = require_chpass = 0;
    160 
    161 	(void)signal(SIGALRM, timedout);
    162 	(void)alarm(timeout);
    163 	(void)signal(SIGQUIT, SIG_IGN);
    164 	(void)signal(SIGINT, SIG_IGN);
    165 	(void)setpriority(PRIO_PROCESS, 0, 0);
    166 
    167 	openlog("login", LOG_ODELAY, LOG_AUTH);
    168 
    169 	/*
    170 	 * -p is used by getty to tell login not to destroy the environment
    171 	 * -f is used to skip a second login authentication
    172 	 * -h is used by other servers to pass the name of the remote
    173 	 *    host to login so that it may be placed in utmp and wtmp
    174 	 * -s is used to force use of S/Key or equivalent.
    175 	 */
    176 	domain = NULL;
    177 	if (gethostname(localhost, sizeof(localhost)) < 0)
    178 		syslog(LOG_ERR, "couldn't get local hostname: %m");
    179 	else
    180 		domain = strchr(localhost, '.');
    181 	localhost[sizeof(localhost) - 1] = '\0';
    182 
    183 	fflag = hflag = pflag = sflag = 0;
    184 	uid = getuid();
    185 	while ((ch = getopt(argc, argv, "fh:ps")) != -1)
    186 		switch (ch) {
    187 		case 'f':
    188 			fflag = 1;
    189 			break;
    190 		case 'h':
    191 			if (uid)
    192 				errx(1, "-h option: %s", strerror(EPERM));
    193 			hflag = 1;
    194 			if (domain && (p = strchr(optarg, '.')) != NULL &&
    195 			    strcasecmp(p, domain) == 0)
    196 				*p = 0;
    197 			hostname = optarg;
    198 			break;
    199 		case 'p':
    200 			pflag = 1;
    201 			break;
    202 		case 's':
    203 			sflag = 1;
    204 			break;
    205 		default:
    206 		case '?':
    207 			(void)fprintf(stderr,
    208 			    "usage: login [-fps] [-h hostname] [username]\n");
    209 			exit(1);
    210 		}
    211 	argc -= optind;
    212 	argv += optind;
    213 
    214 	if (*argv) {
    215 		username = *argv;
    216 		ask = 0;
    217 	} else
    218 		ask = 1;
    219 
    220 	for (cnt = getdtablesize(); cnt > 2; cnt--)
    221 		(void)close(cnt);
    222 
    223 	ttyn = ttyname(STDIN_FILENO);
    224 	if (ttyn == NULL || *ttyn == '\0') {
    225 		(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
    226 		ttyn = tname;
    227 	}
    228 	if ((tty = strrchr(ttyn, '/')) != NULL)
    229 		++tty;
    230 	else
    231 		tty = ttyn;
    232 
    233 #ifdef KERBEROS5
    234 	kerror = krb5_init_context(&kcontext);
    235 	if (kerror) {
    236 		syslog(LOG_NOTICE, "%s when initializing Kerberos context",
    237 		    error_message(kerror));
    238 		exit(1);
    239 	}
    240 #endif KERBEROS5
    241 
    242 	for (cnt = 0;; ask = 1) {
    243 #if defined(KERBEROS) || defined(KERBEROS5)
    244 	        kdestroy();
    245 #endif
    246 		if (ask) {
    247 			fflag = 0;
    248 			getloginname();
    249 		}
    250 		rootlogin = 0;
    251 #ifdef KERBEROS
    252 		if ((instance = strchr(username, '.')) != NULL)
    253 			*instance++ = '\0';
    254 		else
    255 			instance = "";
    256 #endif
    257 #ifdef KERBEROS5
    258 		if ((instance = strchr(username, '/')) != NULL)
    259 			*instance++ = '\0';
    260 		else
    261 			instance = "";
    262 #endif
    263 		if (strlen(username) > MAXLOGNAME)
    264 			username[MAXLOGNAME] = '\0';
    265 
    266 		/*
    267 		 * Note if trying multiple user names; log failures for
    268 		 * previous user name, but don't bother logging one failure
    269 		 * for nonexistent name (mistyped username).
    270 		 */
    271 		if (failures && strcmp(tbuf, username)) {
    272 			if (failures > (pwd ? 0 : 1))
    273 				badlogin(tbuf);
    274 			failures = 0;
    275 		}
    276 		(void)strncpy(tbuf, username, sizeof(tbuf) - 1);
    277 		tbuf[sizeof(tbuf) - 1] = '\0';
    278 
    279 		if ((pwd = getpwnam(username)) != NULL)
    280 			salt = pwd->pw_passwd;
    281 		else
    282 			salt = "xx";
    283 
    284 		/*
    285 		 * if we have a valid account name, and it doesn't have a
    286 		 * password, or the -f option was specified and the caller
    287 		 * is root or the caller isn't changing their uid, don't
    288 		 * authenticate.
    289 		 */
    290 		if (pwd) {
    291 			if (pwd->pw_uid == 0)
    292 				rootlogin = 1;
    293 
    294 			if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
    295 				/* already authenticated */
    296 				break;
    297 			} else if (pwd->pw_passwd[0] == '\0') {
    298 				/* pretend password okay */
    299 				rval = 0;
    300 				goto ttycheck;
    301 			}
    302 		}
    303 
    304 		fflag = 0;
    305 
    306 		(void)setpriority(PRIO_PROCESS, 0, -4);
    307 
    308 #ifdef SKEY
    309 		if (skey_haskey(username) == 0) {
    310 			static char skprompt[80];
    311 			char *skinfo = skey_keyinfo(username);
    312 
    313 			(void)snprintf(skprompt, sizeof(skprompt)-1,
    314 			    "Password [%s]:",
    315 			    skinfo ? skinfo : "error getting challenge");
    316 			pwprompt = skprompt;
    317 		} else
    318 #endif
    319 			pwprompt = "Password:";
    320 
    321 		p = getpass(pwprompt);
    322 
    323 		if (pwd == NULL) {
    324 			rval = 1;
    325 			goto skip;
    326 		}
    327 #ifdef KERBEROS
    328 		if (klogin(pwd, instance, localhost, p) == 0) {
    329 			rval = 0;
    330 			goto skip;
    331 		}
    332 #endif
    333 #ifdef KERBEROS5
    334 		if (klogin(pwd, instance, localhost, p) == 0) {
    335 			rval = 0;
    336 			goto skip;
    337 		}
    338 #endif
    339 #ifdef SKEY
    340 		if (skey_haskey(username) == 0 &&
    341 		    skey_passcheck(username, p) != -1) {
    342 			rval = 0;
    343 			goto skip;
    344 		}
    345 #endif
    346 		if (!sflag && *pwd->pw_passwd != '\0' &&
    347 		    !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
    348 			rval = 0;
    349 			require_chpass = 1;
    350 			goto skip;
    351 		}
    352 		rval = 1;
    353 
    354 	skip:
    355 		memset(p, 0, strlen(p));
    356 
    357 		(void)setpriority(PRIO_PROCESS, 0, 0);
    358 
    359 	ttycheck:
    360 		/*
    361 		 * If trying to log in as root without Kerberos,
    362 		 * but with insecure terminal, refuse the login attempt.
    363 		 */
    364 		if (pwd && !rval && rootlogin && !rootterm(tty)) {
    365 			(void)fprintf(stderr,
    366 			    "%s login refused on this terminal.\n",
    367 			    pwd->pw_name);
    368 			if (hostname)
    369 				syslog(LOG_NOTICE,
    370 				    "LOGIN %s REFUSED FROM %s ON TTY %s",
    371 				    pwd->pw_name, hostname, tty);
    372 			else
    373 				syslog(LOG_NOTICE,
    374 				    "LOGIN %s REFUSED ON TTY %s",
    375 				     pwd->pw_name, tty);
    376 			continue;
    377 		}
    378 
    379 		if (pwd && !rval)
    380 			break;
    381 
    382 		(void)printf("Login incorrect\n");
    383 		failures++;
    384 		/* we allow 10 tries, but after 3 we start backing off */
    385 		if (++cnt > 3) {
    386 			if (cnt >= 10) {
    387 				badlogin(username);
    388 				sleepexit(1);
    389 			}
    390 			sleep((u_int)((cnt - 3) * 5));
    391 		}
    392 	}
    393 
    394 	/* committed to login -- turn off timeout */
    395 	(void)alarm((u_int)0);
    396 
    397 	endpwent();
    398 
    399 	/* if user not super-user, check for disabled logins */
    400 	if (!rootlogin)
    401 		checknologin();
    402 
    403 	/* Temporarily give up special privileges so we can change */
    404 	/* into NFS-mounted homes that are exported for non-root */
    405 	/* access and have mode 7x0 */
    406 	saved_uid = geteuid();
    407 	saved_gid = getegid();
    408 	nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
    409 
    410 	(void)setegid(pwd->pw_gid);
    411 	initgroups(username, pwd->pw_gid);
    412 	(void)seteuid(pwd->pw_uid);
    413 
    414 	if (chdir(pwd->pw_dir) < 0) {
    415 		(void)printf("No home directory %s!\n", pwd->pw_dir);
    416 		if (chdir("/"))
    417 			exit(0);
    418 		pwd->pw_dir = "/";
    419 		(void)printf("Logging in with home = \"/\".\n");
    420 	}
    421 
    422 	quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
    423 
    424 	/* regain special privileges */
    425 	(void)seteuid(saved_uid);
    426 	setgroups(nsaved_gids, saved_gids);
    427 	(void)setegid(saved_gid);
    428 
    429 	if (pwd->pw_change || pwd->pw_expire)
    430 		(void)gettimeofday(&tp, (struct timezone *)NULL);
    431 	if (pwd->pw_expire)
    432 		if (tp.tv_sec >= pwd->pw_expire) {
    433 			(void)printf("Sorry -- your account has expired.\n");
    434 			sleepexit(1);
    435 		} else if (pwd->pw_expire - tp.tv_sec <
    436 		    _PASSWORD_WARNDAYS * SECSPERDAY && !quietlog)
    437 			(void)printf("Warning: your account expires on %s",
    438 			    ctime(&pwd->pw_expire));
    439 	if (pwd->pw_change)
    440 		if (pwd->pw_change == _PASSWORD_CHGNOW)
    441 			need_chpass = 1;
    442 		else if (tp.tv_sec >= pwd->pw_change) {
    443 			(void)printf("Sorry -- your password has expired.\n");
    444 			sleepexit(1);
    445 		} else if (pwd->pw_change - tp.tv_sec <
    446 		    _PASSWORD_WARNDAYS * SECSPERDAY && !quietlog)
    447 			(void)printf("Warning: your password expires on %s",
    448 			    ctime(&pwd->pw_change));
    449 
    450 	/* Nothing else left to fail -- really log in. */
    451 	memset((void *)&utmp, 0, sizeof(utmp));
    452 	(void)time(&utmp.ut_time);
    453 	(void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
    454 	if (hostname)
    455 		(void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
    456 	(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
    457 	login(&utmp);
    458 
    459 	dolastlog(quietlog);
    460 
    461 	(void)chown(ttyn, pwd->pw_uid,
    462 	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
    463 
    464 	if (ttyaction(ttyn, "login", pwd->pw_name))
    465 		(void)printf("Warning: ttyaction failed.\n");
    466 
    467 #if defined(KERBEROS) || defined(KERBEROS5)
    468 	/* Fork so that we can call kdestroy */
    469 	if (krbtkfile_env)
    470 		dofork();
    471 #endif
    472 	(void)setgid(pwd->pw_gid);
    473 
    474 	initgroups(username, pwd->pw_gid);
    475 
    476 	if (*pwd->pw_shell == '\0')
    477 		pwd->pw_shell = _PATH_BSHELL;
    478 
    479 	/* Destroy environment unless user has requested its preservation. */
    480 	if (!pflag)
    481 		environ = envinit;
    482 	(void)setenv("HOME", pwd->pw_dir, 1);
    483 	(void)setenv("SHELL", pwd->pw_shell, 1);
    484 	if (term[0] == '\0')
    485 		(void)strncpy(term, stypeof(tty), sizeof(term));
    486 	(void)setenv("TERM", term, 0);
    487 	(void)setenv("LOGNAME", pwd->pw_name, 1);
    488 	(void)setenv("USER", pwd->pw_name, 1);
    489 	(void)setenv("PATH", _PATH_DEFPATH, 0);
    490 #ifdef KERBEROS
    491 	if (krbtkfile_env)
    492 		(void)setenv("KRBTKFILE", krbtkfile_env, 1);
    493 #endif
    494 #ifdef KERBEROS5
    495 	if (krbtkfile_env)
    496 		(void)setenv("KRB5CCNAME", krbtkfile_env, 1);
    497 #endif
    498 
    499 	if (tty[sizeof("tty")-1] == 'd')
    500 		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
    501 
    502 	/* If fflag is on, assume caller/authenticator has logged root login. */
    503 	if (rootlogin && fflag == 0)
    504 		if (hostname)
    505 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
    506 			    username, tty, hostname);
    507 		else
    508 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
    509 
    510 #if defined(KERBEROS) || defined(KERBEROS5)
    511 	if (!quietlog && notickets == 1)
    512 		(void)printf("Warning: no Kerberos tickets issued.\n");
    513 #endif
    514 
    515 	if (!quietlog) {
    516 		(void)printf(copyrightstr);
    517 		motd();
    518 		(void)snprintf(tbuf,
    519 		    sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
    520 		if (stat(tbuf, &st) == 0 && st.st_size != 0)
    521 			(void)printf("You have %smail.\n",
    522 			    (st.st_mtime > st.st_atime) ? "new " : "");
    523 	}
    524 
    525 	(void)signal(SIGALRM, SIG_DFL);
    526 	(void)signal(SIGQUIT, SIG_DFL);
    527 	(void)signal(SIGINT, SIG_DFL);
    528 	(void)signal(SIGTSTP, SIG_IGN);
    529 
    530 	tbuf[0] = '-';
    531 	(void)strncpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
    532 	    p + 1 : pwd->pw_shell, sizeof(tbuf) - 2);
    533 
    534 	if (setlogin(pwd->pw_name) < 0)
    535 		syslog(LOG_ERR, "setlogin() failure: %m");
    536 
    537 	/* Discard permissions last so can't get killed and drop core. */
    538 	if (rootlogin)
    539 		(void)setuid(0);
    540 	else
    541 		(void)setuid(pwd->pw_uid);
    542 
    543 	/* Wait to change password until we're unprivileged */
    544 	if (need_chpass) {
    545 		if (!require_chpass)
    546 			(void)printf(
    547 "Warning: your password has expired. Please change it as soon as possible.\n");
    548 		else {
    549 			int	status;
    550 
    551 			(void)printf(
    552 		    "Your password has expired. Please choose a new one.\n");
    553 			switch (fork()) {
    554 			case -1:
    555 				warn("fork");
    556 				sleepexit(1);
    557 			case 0:
    558 				execl(_PATH_BINPASSWD, "passwd", 0);
    559 				_exit(1);
    560 			default:
    561 				if (wait(&status) == -1 ||
    562 				    WEXITSTATUS(status))
    563 					sleepexit(1);
    564 			}
    565 		}
    566 	}
    567 
    568 	execlp(pwd->pw_shell, tbuf, 0);
    569 	err(1, "%s", pwd->pw_shell);
    570 }
    571 
    572 #if defined(KERBEROS) || defined(KERBEROS5)
    573 #define	NBUFSIZ		(MAXLOGNAME + 1 + 5)	/* .root suffix */
    574 #else
    575 #define	NBUFSIZ		(MAXLOGNAME + 1)
    576 #endif
    577 
    578 #if defined(KERBEROS) || defined(KERBEROS5)
    579 /*
    580  * This routine handles cleanup stuff, and the like.
    581  * It exists only in the child process.
    582  */
    583 #include <sys/wait.h>
    584 void
    585 dofork()
    586 {
    587 	int child;
    588 
    589 	if (!(child = fork()))
    590 		return; /* Child process */
    591 
    592 	/* Setup stuff?  This would be things we could do in parallel with login */
    593 	(void) chdir("/");	/* Let's not keep the fs busy... */
    594 
    595 	/* If we're the parent, watch the child until it dies */
    596 	while (wait(0) != child)
    597 		;
    598 
    599 	/* Cleanup stuff */
    600 	/* Run kdestroy to destroy tickets */
    601 	kdestroy();
    602 
    603 	/* Leave */
    604 	exit(0);
    605 }
    606 #endif
    607 
    608 void
    609 getloginname()
    610 {
    611 	int ch;
    612 	char *p;
    613 	static char nbuf[NBUFSIZ];
    614 
    615 	for (;;) {
    616 		(void)printf("login: ");
    617 		for (p = nbuf; (ch = getchar()) != '\n'; ) {
    618 			if (ch == EOF) {
    619 				badlogin(username);
    620 				exit(0);
    621 			}
    622 			if (p < nbuf + (NBUFSIZ - 1))
    623 				*p++ = ch;
    624 		}
    625 		if (p > nbuf)
    626 			if (nbuf[0] == '-')
    627 				(void)fprintf(stderr,
    628 				    "login names may not start with '-'.\n");
    629 			else {
    630 				*p = '\0';
    631 				username = nbuf;
    632 				break;
    633 			}
    634 	}
    635 }
    636 
    637 int
    638 rootterm(ttyn)
    639 	char *ttyn;
    640 {
    641 	struct ttyent *t;
    642 
    643 	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
    644 }
    645 
    646 jmp_buf motdinterrupt;
    647 
    648 void
    649 motd()
    650 {
    651 	int fd, nchars;
    652 	sig_t oldint;
    653 	char tbuf[8192];
    654 
    655 	if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
    656 		return;
    657 	oldint = signal(SIGINT, sigint);
    658 	if (setjmp(motdinterrupt) == 0)
    659 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
    660 			(void)write(fileno(stdout), tbuf, nchars);
    661 	(void)signal(SIGINT, oldint);
    662 	(void)close(fd);
    663 }
    664 
    665 /* ARGSUSED */
    666 void
    667 sigint(signo)
    668 	int signo;
    669 {
    670 
    671 	longjmp(motdinterrupt, 1);
    672 }
    673 
    674 /* ARGSUSED */
    675 void
    676 timedout(signo)
    677 	int signo;
    678 {
    679 
    680 	(void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
    681 	exit(0);
    682 }
    683 
    684 void
    685 checknologin()
    686 {
    687 	int fd, nchars;
    688 	char tbuf[8192];
    689 
    690 	if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
    691 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
    692 			(void)write(fileno(stdout), tbuf, nchars);
    693 		sleepexit(0);
    694 	}
    695 }
    696 
    697 void
    698 dolastlog(quiet)
    699 	int quiet;
    700 {
    701 	struct lastlog ll;
    702 	int fd;
    703 
    704 	if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
    705 		(void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
    706 		if (!quiet) {
    707 			if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
    708 			    ll.ll_time != 0) {
    709 				(void)printf("Last login: %.*s ",
    710 				    24-5, (char *)ctime(&ll.ll_time));
    711 				if (*ll.ll_host != '\0')
    712 					(void)printf("from %.*s\n",
    713 					    (int)sizeof(ll.ll_host),
    714 					    ll.ll_host);
    715 				else
    716 					(void)printf("on %.*s\n",
    717 					    (int)sizeof(ll.ll_line),
    718 					    ll.ll_line);
    719 			}
    720 			(void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
    721 			    SEEK_SET);
    722 		}
    723 		memset((void *)&ll, 0, sizeof(ll));
    724 		(void)time(&ll.ll_time);
    725 		(void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
    726 		if (hostname)
    727 			(void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
    728 		(void)write(fd, (char *)&ll, sizeof(ll));
    729 		(void)close(fd);
    730 	}
    731 }
    732 
    733 void
    734 badlogin(name)
    735 	char *name;
    736 {
    737 	if (failures == 0)
    738 		return;
    739 	if (hostname) {
    740 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
    741 		    failures, failures > 1 ? "S" : "", hostname);
    742 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
    743 		    "%d LOGIN FAILURE%s FROM %s, %s",
    744 		    failures, failures > 1 ? "S" : "", hostname, name);
    745 	} else {
    746 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
    747 		    failures, failures > 1 ? "S" : "", tty);
    748 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
    749 		    "%d LOGIN FAILURE%s ON %s, %s",
    750 		    failures, failures > 1 ? "S" : "", tty, name);
    751 	}
    752 }
    753 
    754 #undef	UNKNOWN
    755 #define	UNKNOWN	"su"
    756 
    757 char *
    758 stypeof(ttyid)
    759 	char *ttyid;
    760 {
    761 	struct ttyent *t;
    762 
    763 	return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
    764 }
    765 
    766 void
    767 sleepexit(eval)
    768 	int eval;
    769 {
    770 
    771 	(void)sleep(5);
    772 	exit(eval);
    773 }
    774