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