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