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