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