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