Home | History | Annotate | Line # | Download | only in login
login.c revision 1.32
      1 /*	$NetBSD: login.c,v 1.32 1997/11/07 20:32:05 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.32 1997/11/07 20:32:05 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 
     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;
    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 	if (chdir(pwd->pw_dir) < 0) {
    392 		(void)printf("No home directory %s!\n", pwd->pw_dir);
    393 		if (chdir("/"))
    394 			exit(0);
    395 		pwd->pw_dir = "/";
    396 		(void)printf("Logging in with home = \"/\".\n");
    397 	}
    398 
    399 	quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
    400 
    401 	if (pwd->pw_change || pwd->pw_expire)
    402 		(void)gettimeofday(&tp, (struct timezone *)NULL);
    403 	if (pwd->pw_expire)
    404 		if (tp.tv_sec >= pwd->pw_expire) {
    405 			(void)printf("Sorry -- your account has expired.\n");
    406 			sleepexit(1);
    407 		} else if (pwd->pw_expire - tp.tv_sec <
    408 		    _PASSWORD_WARNDAYS * SECSPERDAY && !quietlog)
    409 			(void)printf("Warning: your account expires on %s",
    410 			    ctime(&pwd->pw_expire));
    411 	if (pwd->pw_change)
    412 		if (pwd->pw_change == _PASSWORD_CHGNOW)
    413 			need_chpass = 1;
    414 		else if (tp.tv_sec >= pwd->pw_change) {
    415 			(void)printf("Sorry -- your password has expired.\n");
    416 			sleepexit(1);
    417 		} else if (pwd->pw_change - tp.tv_sec <
    418 		    _PASSWORD_WARNDAYS * SECSPERDAY && !quietlog)
    419 			(void)printf("Warning: your password expires on %s",
    420 			    ctime(&pwd->pw_change));
    421 
    422 	/* Nothing else left to fail -- really log in. */
    423 	memset((void *)&utmp, 0, sizeof(utmp));
    424 	(void)time(&utmp.ut_time);
    425 	(void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
    426 	if (hostname)
    427 		(void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
    428 	(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
    429 	login(&utmp);
    430 
    431 	dolastlog(quietlog);
    432 
    433 	(void)chown(ttyn, pwd->pw_uid,
    434 	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
    435 
    436 	if (ttyaction(ttyn, "login", pwd->pw_name))
    437 		(void)printf("Warning: ttyaction failed.\n");
    438 
    439 #if defined(KERBEROS) || defined(KERBEROS5)
    440 	/* Fork so that we can call kdestroy */
    441 	if (krbtkfile_env)
    442 		dofork();
    443 #endif
    444 	(void)setgid(pwd->pw_gid);
    445 
    446 	initgroups(username, pwd->pw_gid);
    447 
    448 	if (*pwd->pw_shell == '\0')
    449 		pwd->pw_shell = _PATH_BSHELL;
    450 
    451 	/* Destroy environment unless user has requested its preservation. */
    452 	if (!pflag)
    453 		environ = envinit;
    454 	(void)setenv("HOME", pwd->pw_dir, 1);
    455 	(void)setenv("SHELL", pwd->pw_shell, 1);
    456 	if (term[0] == '\0')
    457 		(void)strncpy(term, stypeof(tty), sizeof(term));
    458 	(void)setenv("TERM", term, 0);
    459 	(void)setenv("LOGNAME", pwd->pw_name, 1);
    460 	(void)setenv("USER", pwd->pw_name, 1);
    461 	(void)setenv("PATH", _PATH_DEFPATH, 0);
    462 #ifdef KERBEROS
    463 	if (krbtkfile_env)
    464 		(void)setenv("KRBTKFILE", krbtkfile_env, 1);
    465 #endif
    466 #ifdef KERBEROS5
    467 	if (krbtkfile_env)
    468 		(void)setenv("KRB5CCNAME", krbtkfile_env, 1);
    469 #endif
    470 
    471 	if (tty[sizeof("tty")-1] == 'd')
    472 		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
    473 
    474 	/* If fflag is on, assume caller/authenticator has logged root login. */
    475 	if (rootlogin && fflag == 0)
    476 		if (hostname)
    477 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
    478 			    username, tty, hostname);
    479 		else
    480 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
    481 
    482 #if defined(KERBEROS) || defined(KERBEROS5)
    483 	if (!quietlog && notickets == 1)
    484 		(void)printf("Warning: no Kerberos tickets issued.\n");
    485 #endif
    486 
    487 	if (!quietlog) {
    488 		(void)printf("%s  %s\n%s\n\t%s  %s\n\n",
    489  	    "Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.",
    490 	    "All rights reserved.",
    491 	    "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
    492 		    "The Regents of the University of California. ",
    493 		    "All rights reserved.");
    494 		motd();
    495 		(void)snprintf(tbuf,
    496 		    sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
    497 		if (stat(tbuf, &st) == 0 && st.st_size != 0)
    498 			(void)printf("You have %smail.\n",
    499 			    (st.st_mtime > st.st_atime) ? "new " : "");
    500 	}
    501 
    502 	(void)signal(SIGALRM, SIG_DFL);
    503 	(void)signal(SIGQUIT, SIG_DFL);
    504 	(void)signal(SIGINT, SIG_DFL);
    505 	(void)signal(SIGTSTP, SIG_IGN);
    506 
    507 	tbuf[0] = '-';
    508 	(void)strncpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
    509 	    p + 1 : pwd->pw_shell, sizeof(tbuf) - 2);
    510 
    511 	if (setlogin(pwd->pw_name) < 0)
    512 		syslog(LOG_ERR, "setlogin() failure: %m");
    513 
    514 	/* Discard permissions last so can't get killed and drop core. */
    515 	if (rootlogin)
    516 		(void)setuid(0);
    517 	else
    518 		(void)setuid(pwd->pw_uid);
    519 
    520 	/* Wait to change password until we're unprivileged */
    521 	if (need_chpass) {
    522 		if (!require_chpass)
    523 			(void)printf(
    524 "Warning: your password has expired. Please change it as soon as possible.\n");
    525 		else {
    526 			(void)printf(
    527 		    "Your password has expired. Please choose a new one.\n");
    528 			if (system(_PATH_BINPASSWD) != 0)
    529 				sleepexit(1);
    530 		}
    531 	}
    532 
    533 	execlp(pwd->pw_shell, tbuf, 0);
    534 	err(1, "%s", pwd->pw_shell);
    535 }
    536 
    537 #if defined(KERBEROS) || defined(KERBEROS5)
    538 #define	NBUFSIZ		(MAXLOGNAME + 1 + 5)	/* .root suffix */
    539 #else
    540 #define	NBUFSIZ		(MAXLOGNAME + 1)
    541 #endif
    542 
    543 #if defined(KERBEROS) || defined(KERBEROS5)
    544 /*
    545  * This routine handles cleanup stuff, and the like.
    546  * It exists only in the child process.
    547  */
    548 #include <sys/wait.h>
    549 void
    550 dofork()
    551 {
    552     int child;
    553 
    554     if (!(child = fork()))
    555 	    return; /* Child process */
    556 
    557     /* Setup stuff?  This would be things we could do in parallel with login */
    558     (void) chdir("/");	/* Let's not keep the fs busy... */
    559 
    560     /* If we're the parent, watch the child until it dies */
    561     while (wait(0) != child)
    562 	    ;
    563 
    564     /* Cleanup stuff */
    565     /* Run kdestroy to destroy tickets */
    566     kdestroy();
    567 
    568     /* Leave */
    569     exit(0);
    570 }
    571 #endif
    572 
    573 void
    574 getloginname()
    575 {
    576 	int ch;
    577 	char *p;
    578 	static char nbuf[NBUFSIZ];
    579 
    580 	for (;;) {
    581 		(void)printf("login: ");
    582 		for (p = nbuf; (ch = getchar()) != '\n'; ) {
    583 			if (ch == EOF) {
    584 				badlogin(username);
    585 				exit(0);
    586 			}
    587 			if (p < nbuf + (NBUFSIZ - 1))
    588 				*p++ = ch;
    589 		}
    590 		if (p > nbuf)
    591 			if (nbuf[0] == '-')
    592 				(void)fprintf(stderr,
    593 				    "login names may not start with '-'.\n");
    594 			else {
    595 				*p = '\0';
    596 				username = nbuf;
    597 				break;
    598 			}
    599 	}
    600 }
    601 
    602 int
    603 rootterm(ttyn)
    604 	char *ttyn;
    605 {
    606 	struct ttyent *t;
    607 
    608 	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
    609 }
    610 
    611 jmp_buf motdinterrupt;
    612 
    613 void
    614 motd()
    615 {
    616 	int fd, nchars;
    617 	sig_t oldint;
    618 	char tbuf[8192];
    619 
    620 	if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
    621 		return;
    622 	oldint = signal(SIGINT, sigint);
    623 	if (setjmp(motdinterrupt) == 0)
    624 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
    625 			(void)write(fileno(stdout), tbuf, nchars);
    626 	(void)signal(SIGINT, oldint);
    627 	(void)close(fd);
    628 }
    629 
    630 /* ARGSUSED */
    631 void
    632 sigint(signo)
    633 	int signo;
    634 {
    635 	longjmp(motdinterrupt, 1);
    636 }
    637 
    638 /* ARGSUSED */
    639 void
    640 timedout(signo)
    641 	int signo;
    642 {
    643 	(void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
    644 	exit(0);
    645 }
    646 
    647 void
    648 checknologin()
    649 {
    650 	int fd, nchars;
    651 	char tbuf[8192];
    652 
    653 	if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
    654 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
    655 			(void)write(fileno(stdout), tbuf, nchars);
    656 		sleepexit(0);
    657 	}
    658 }
    659 
    660 void
    661 dolastlog(quiet)
    662 	int quiet;
    663 {
    664 	struct lastlog ll;
    665 	int fd;
    666 
    667 	if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
    668 		(void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
    669 		if (!quiet) {
    670 			if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
    671 			    ll.ll_time != 0) {
    672 				(void)printf("Last login: %.*s ",
    673 				    24-5, (char *)ctime(&ll.ll_time));
    674 				if (*ll.ll_host != '\0')
    675 					(void)printf("from %.*s\n",
    676 					    (int)sizeof(ll.ll_host),
    677 					    ll.ll_host);
    678 				else
    679 					(void)printf("on %.*s\n",
    680 					    (int)sizeof(ll.ll_line),
    681 					    ll.ll_line);
    682 			}
    683 			(void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
    684 			    SEEK_SET);
    685 		}
    686 		memset((void *)&ll, 0, sizeof(ll));
    687 		(void)time(&ll.ll_time);
    688 		(void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
    689 		if (hostname)
    690 			(void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
    691 		(void)write(fd, (char *)&ll, sizeof(ll));
    692 		(void)close(fd);
    693 	}
    694 }
    695 
    696 void
    697 badlogin(name)
    698 	char *name;
    699 {
    700 	if (failures == 0)
    701 		return;
    702 	if (hostname) {
    703 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
    704 		    failures, failures > 1 ? "S" : "", hostname);
    705 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
    706 		    "%d LOGIN FAILURE%s FROM %s, %s",
    707 		    failures, failures > 1 ? "S" : "", hostname, name);
    708 	} else {
    709 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
    710 		    failures, failures > 1 ? "S" : "", tty);
    711 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
    712 		    "%d LOGIN FAILURE%s ON %s, %s",
    713 		    failures, failures > 1 ? "S" : "", tty, name);
    714 	}
    715 }
    716 
    717 #undef	UNKNOWN
    718 #define	UNKNOWN	"su"
    719 
    720 char *
    721 stypeof(ttyid)
    722 	char *ttyid;
    723 {
    724 	struct ttyent *t;
    725 
    726 	return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
    727 }
    728 
    729 void
    730 sleepexit(eval)
    731 	int eval;
    732 {
    733 	(void)sleep(5);
    734 	exit(eval);
    735 }
    736