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