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