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