xref: /netbsd/usr.bin/login/login.c (revision c4a72b64)
1 /*     $NetBSD: login.c,v 1.71 2002/11/16 04:38:45 itojun 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.71 2002/11/16 04:38:45 itojun 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 #include <sys/socket.h>
63 
64 #include <err.h>
65 #include <errno.h>
66 #include <grp.h>
67 #include <pwd.h>
68 #include <setjmp.h>
69 #include <signal.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <syslog.h>
74 #include <time.h>
75 #include <ttyent.h>
76 #include <tzfile.h>
77 #include <unistd.h>
78 #ifdef SUPPORT_UTMP
79 #include <utmp.h>
80 #endif
81 #ifdef SUPPORT_UTMPX
82 #include <utmpx.h>
83 #endif
84 #include <util.h>
85 #ifdef SKEY
86 #include <skey.h>
87 #endif
88 #ifdef KERBEROS5
89 #include <krb5/krb5.h>
90 #include <com_err.h>
91 #endif
92 #ifdef LOGIN_CAP
93 #include <login_cap.h>
94 #endif
95 
96 #include "pathnames.h"
97 
98 #ifdef KERBEROS5
99 int login_krb5_get_tickets = 1;
100 int login_krb4_get_tickets = 0;
101 int login_krb5_forwardable_tgt = 0;
102 int login_krb5_retain_ccache = 0;
103 #endif
104 
105 void	 badlogin __P((char *));
106 void	 checknologin __P((char *));
107 #ifdef SUPPORT_UTMP
108 static void	 doutmp __P((void));
109 static void	 dolastlog __P((int));
110 #endif
111 #ifdef SUPPORT_UTMPX
112 static void	 doutmpx __P((void));
113 static void	 dolastlogx __P((int));
114 #endif
115 static void	 update_db __P((int));
116 void	 getloginname __P((void));
117 int	 main __P((int, char *[]));
118 void	 motd __P((char *));
119 int	 rootterm __P((char *));
120 void	 sigint __P((int));
121 void	 sleepexit __P((int));
122 const	 char *stypeof __P((const char *));
123 void	 timedout __P((int));
124 #if defined(KERBEROS)
125 int	 klogin __P((struct passwd *, char *, char *, char *));
126 void	 kdestroy __P((void));
127 #endif
128 #ifdef KERBEROS5
129 int	 k5login __P((struct passwd *, char *, char *, char *));
130 void	 k5destroy __P((void));
131 int	 k5_read_creds __P((char*));
132 int	 k5_write_creds __P((void));
133 #endif
134 #if defined(KERBEROS) || defined(KERBEROS5)
135 void	 dofork __P((void));
136 #endif
137 
138 #define	TTYGRPNAME	"tty"		/* name of group to own ttys */
139 
140 #define DEFAULT_BACKOFF 3
141 #define DEFAULT_RETRIES 10
142 
143 /*
144  * This bounds the time given to login.  Not a define so it can
145  * be patched on machines where it's too small.
146  */
147 u_int	timeout = 300;
148 
149 #if defined(KERBEROS) || defined(KERBEROS5)
150 int	notickets = 1;
151 char	*instance;
152 int	has_ccache = 0;
153 #endif
154 #ifdef KERBEROS
155 extern char	*krbtkfile_env;
156 extern int	krb_configured;
157 #endif
158 #ifdef KERBEROS5
159 extern krb5_context kcontext;
160 extern int	have_forward;
161 extern char	*krb5tkfile_env;
162 extern int	krb5_configured;
163 #endif
164 
165 #if defined(KERBEROS) && defined(KERBEROS5)
166 #define	KERBEROS_CONFIGURED	(krb_configured || krb5_configured)
167 #elif defined(KERBEROS)
168 #define	KERBEROS_CONFIGURED	krb_configured
169 #elif defined(KERBEROS5)
170 #define	KERBEROS_CONFIGURED	krb5_configured
171 #endif
172 
173 struct	passwd *pwd;
174 int	failures;
175 char	term[64], *envinit[1], *hostname, *username, *tty, *nested;
176 struct timeval now;
177 struct sockaddr_storage ss;
178 
179 static const char copyrightstr[] = "\
180 Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002\n\
181 \tThe NetBSD Foundation, Inc.  All rights reserved.\n\
182 Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994\n\
183 \tThe Regents of the University of California.  All rights reserved.\n\n";
184 
185 int
186 main(argc, argv)
187 	int argc;
188 	char *argv[];
189 {
190 	extern char **environ;
191 	struct group *gr;
192 	struct stat st;
193 	int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval;
194 	int Fflag;
195 	uid_t uid, saved_uid;
196 	gid_t saved_gid, saved_gids[NGROUPS_MAX];
197 	int nsaved_gids;
198 	char *domain, *p, *ttyn, *pwprompt;
199 	const char *salt;
200 	char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
201 	char localhost[MAXHOSTNAMELEN + 1];
202 	int need_chpass, require_chpass;
203 	int login_retries = DEFAULT_RETRIES,
204 	    login_backoff = DEFAULT_BACKOFF;
205 	time_t pw_warntime = _PASSWORD_WARNDAYS * SECSPERDAY;
206 #ifdef KERBEROS5
207 	krb5_error_code kerror;
208 #endif
209 #if defined(KERBEROS) || defined(KERBEROS5)
210 	int got_tickets = 0;
211 #endif
212 #ifdef LOGIN_CAP
213 	char *shell = NULL;
214 	login_cap_t *lc = NULL;
215 #endif
216 
217 	tbuf[0] = '\0';
218 	rval = 0;
219 	pwprompt = NULL;
220 	nested = NULL;
221 	need_chpass = require_chpass = 0;
222 
223 	(void)signal(SIGALRM, timedout);
224 	(void)alarm(timeout);
225 	(void)signal(SIGQUIT, SIG_IGN);
226 	(void)signal(SIGINT, SIG_IGN);
227 	(void)setpriority(PRIO_PROCESS, 0, 0);
228 
229 	openlog("login", 0, LOG_AUTH);
230 
231 	/*
232 	 * -p is used by getty to tell login not to destroy the environment
233 	 * -f is used to skip a second login authentication
234 	 * -h is used by other servers to pass the name of the remote host to
235 	 *    login so that it may be placed in utmp/utmpx and wtmp/wtmpx
236 	 * -s is used to force use of S/Key or equivalent.
237 	 */
238 	domain = NULL;
239 	if (gethostname(localhost, sizeof(localhost)) < 0)
240 		syslog(LOG_ERR, "couldn't get local hostname: %m");
241 	else
242 		domain = strchr(localhost, '.');
243 	localhost[sizeof(localhost) - 1] = '\0';
244 
245 	Fflag = fflag = hflag = pflag = sflag = 0;
246 #ifdef KERBEROS5
247 	have_forward = 0;
248 #endif
249 	uid = getuid();
250 	while ((ch = getopt(argc, argv, "Ffh:ps")) != -1)
251 		switch (ch) {
252 		case 'F':
253 			Fflag = 1;
254 			/* FALLTHROUGH */
255 		case 'f':
256 			fflag = 1;
257 			break;
258 		case 'h':
259 			if (uid)
260 				errx(1, "-h option: %s", strerror(EPERM));
261 			hflag = 1;
262 			if (domain && (p = strchr(optarg, '.')) != NULL &&
263 			    strcasecmp(p, domain) == 0)
264 				*p = 0;
265 			hostname = optarg;
266 			break;
267 		case 'p':
268 			pflag = 1;
269 			break;
270 		case 's':
271 			sflag = 1;
272 			break;
273 		default:
274 		case '?':
275 			(void)fprintf(stderr,
276 			    "usage: login [-fps] [-h hostname] [username]\n");
277 			exit(1);
278 		}
279 	argc -= optind;
280 	argv += optind;
281 
282 	if (*argv) {
283 		username = *argv;
284 		ask = 0;
285 	} else
286 		ask = 1;
287 
288 	for (cnt = getdtablesize(); cnt > 2; cnt--)
289 		(void)close(cnt);
290 
291 	ttyn = ttyname(STDIN_FILENO);
292 	if (ttyn == NULL || *ttyn == '\0') {
293 		(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
294 		ttyn = tname;
295 	}
296 	if ((tty = strrchr(ttyn, '/')) != NULL)
297 		++tty;
298 	else
299 		tty = ttyn;
300 
301 	if (issetugid()) {
302 		nested = strdup(user_from_uid(getuid(), 0));
303 		if (nested == NULL) {
304                 	syslog(LOG_ERR, "strdup: %m");
305                 	sleepexit(1);
306 		}
307 	}
308 
309 #ifdef LOGIN_CAP
310 	/* Get "login-retries" and "login-backoff" from default class */
311 	if ((lc = login_getclass(NULL)) != NULL) {
312 		login_retries = (int)login_getcapnum(lc, "login-retries",
313 		    DEFAULT_RETRIES, DEFAULT_RETRIES);
314 		login_backoff = (int)login_getcapnum(lc, "login-backoff",
315 		    DEFAULT_BACKOFF, DEFAULT_BACKOFF);
316 		login_close(lc);
317 		lc = NULL;
318 	}
319 #endif
320 
321 #ifdef KERBEROS5
322 	kerror = krb5_init_context(&kcontext);
323 	if (kerror) {
324 		/*
325 		 * If Kerberos is not configured, that is, we are
326 		 * not using Kerberos, do not log the error message.
327 		 * However, if Kerberos is configured,  and the
328 		 * context init fails for some other reason, we need
329 		 * to issue a no tickets warning to the user when the
330 		 * login succeeds.
331 		 */
332 		if (kerror != ENXIO) {	/* XXX NetBSD-local Heimdal hack */
333 			syslog(LOG_NOTICE,
334 			    "%s when initializing Kerberos context",
335 			    error_message(kerror));
336 			krb5_configured = 1;
337 		}
338 		login_krb5_get_tickets = 0;
339 	}
340 #endif /* KERBEROS5 */
341 
342 	for (cnt = 0;; ask = 1) {
343 #if defined(KERBEROS)
344 	        kdestroy();
345 #endif
346 #if defined(KERBEROS5)
347 		if (login_krb5_get_tickets)
348 			k5destroy();
349 #endif
350 		if (ask) {
351 			fflag = 0;
352 			getloginname();
353 		}
354 		rootlogin = 0;
355 #ifdef KERBEROS
356 		if ((instance = strchr(username, '.')) != NULL)
357 			*instance++ = '\0';
358 		else
359 			instance = "";
360 #endif
361 #ifdef KERBEROS5
362 		if ((instance = strchr(username, '/')) != NULL)
363 			*instance++ = '\0';
364 		else
365 			instance = "";
366 #endif
367 		if (strlen(username) > MAXLOGNAME)
368 			username[MAXLOGNAME] = '\0';
369 
370 		/*
371 		 * Note if trying multiple user names; log failures for
372 		 * previous user name, but don't bother logging one failure
373 		 * for nonexistent name (mistyped username).
374 		 */
375 		if (failures && strcmp(tbuf, username)) {
376 			if (failures > (pwd ? 0 : 1))
377 				badlogin(tbuf);
378 			failures = 0;
379 		}
380 		(void)strlcpy(tbuf, username, sizeof(tbuf));
381 
382 		if ((pwd = getpwnam(username)) != NULL)
383 			salt = pwd->pw_passwd;
384 		else
385 			salt = "xx";
386 
387 #ifdef LOGIN_CAP
388 		/*
389 		 * Establish the class now, before we might goto
390 		 * within the next block. pwd can be NULL since it
391 		 * falls back to the "default" class if it is.
392 		 */
393 		lc = login_getclass(pwd ? pwd->pw_class : NULL);
394 #endif
395 		/*
396 		 * if we have a valid account name, and it doesn't have a
397 		 * password, or the -f option was specified and the caller
398 		 * is root or the caller isn't changing their uid, don't
399 		 * authenticate.
400 		 */
401 		if (pwd) {
402 			if (pwd->pw_uid == 0)
403 				rootlogin = 1;
404 
405 			if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
406 				/* already authenticated */
407 #ifdef KERBEROS5
408 				if (login_krb5_get_tickets && Fflag)
409 					k5_read_creds(username);
410 #endif
411 				break;
412 			} else if (pwd->pw_passwd[0] == '\0') {
413 				/* pretend password okay */
414 				rval = 0;
415 				goto ttycheck;
416 			}
417 		}
418 
419 		fflag = 0;
420 
421 		(void)setpriority(PRIO_PROCESS, 0, -4);
422 
423 #ifdef SKEY
424 		if (skey_haskey(username) == 0) {
425 			static char skprompt[80];
426 			const char *skinfo = skey_keyinfo(username);
427 
428 			(void)snprintf(skprompt, sizeof(skprompt)-1,
429 			    "Password [%s]:",
430 			    skinfo ? skinfo : "error getting challenge");
431 			pwprompt = skprompt;
432 		} else
433 #endif
434 			pwprompt = "Password:";
435 
436 		p = getpass(pwprompt);
437 
438 		if (pwd == NULL) {
439 			rval = 1;
440 			goto skip;
441 		}
442 #ifdef KERBEROS
443 		if (
444 #ifdef KERBEROS5
445 		    /* allow a user to get both krb4 and krb5 tickets, if
446 		     * desired.  If krb5 is compiled in, the default action
447 		     * is to ignore krb4 and get krb5 tickets, but the user
448 		     * can override this in the krb5.conf. */
449 		    login_krb4_get_tickets &&
450 #endif
451 		    klogin(pwd, instance, localhost, p) == 0) {
452 			rval = 0;
453 			got_tickets = 1;
454 		}
455 #endif
456 #ifdef KERBEROS5
457 		if (login_krb5_get_tickets &&
458 		    k5login(pwd, instance, localhost, p) == 0) {
459 			rval = 0;
460 			got_tickets = 1;
461 		}
462 #endif
463 #if defined(KERBEROS) || defined(KERBEROS5)
464 		if (got_tickets)
465 			goto skip;
466 #endif
467 #ifdef SKEY
468 		if (skey_haskey(username) == 0 &&
469 		    skey_passcheck(username, p) != -1) {
470 			rval = 0;
471 			goto skip;
472 		}
473 #endif
474 		if (!sflag && *pwd->pw_passwd != '\0' &&
475 		    !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
476 			rval = 0;
477 			require_chpass = 1;
478 			goto skip;
479 		}
480 		rval = 1;
481 
482 	skip:
483 		memset(p, 0, strlen(p));
484 
485 		(void)setpriority(PRIO_PROCESS, 0, 0);
486 
487 	ttycheck:
488 		/*
489 		 * If trying to log in as root without Kerberos,
490 		 * but with insecure terminal, refuse the login attempt.
491 		 */
492 		if (pwd && !rval && rootlogin && !rootterm(tty)) {
493 			(void)fprintf(stderr,
494 			    "%s login refused on this terminal.\n",
495 			    pwd->pw_name);
496 			if (hostname)
497 				syslog(LOG_NOTICE,
498 				    "LOGIN %s REFUSED FROM %s ON TTY %s",
499 				    pwd->pw_name, hostname, tty);
500 			else
501 				syslog(LOG_NOTICE,
502 				    "LOGIN %s REFUSED ON TTY %s",
503 				     pwd->pw_name, tty);
504 			continue;
505 		}
506 
507 		if (pwd && !rval)
508 			break;
509 
510 		(void)printf("Login incorrect\n");
511 		failures++;
512 		cnt++;
513 		/* we allow 10 tries, but after 3 we start backing off */
514 		if (cnt > login_backoff) {
515 			if (cnt >= login_retries) {
516 				badlogin(username);
517 				sleepexit(1);
518 			}
519 			sleep((u_int)((cnt - 3) * 5));
520 		}
521 	}
522 
523 	/* committed to login -- turn off timeout */
524 	(void)alarm((u_int)0);
525 
526 	endpwent();
527 
528 	/* if user not super-user, check for disabled logins */
529 #ifdef LOGIN_CAP
530         if (!login_getcapbool(lc, "ignorenologin", rootlogin))
531 		checknologin(login_getcapstr(lc, "nologin", NULL, NULL));
532 #else
533         if (!rootlogin)
534                 checknologin(NULL);
535 #endif
536 
537 #ifdef LOGIN_CAP
538         quietlog = login_getcapbool(lc, "hushlogin", 0);
539 #else
540         quietlog = 0;
541 #endif
542 	/* Temporarily give up special privileges so we can change */
543 	/* into NFS-mounted homes that are exported for non-root */
544 	/* access and have mode 7x0 */
545 	saved_uid = geteuid();
546 	saved_gid = getegid();
547 	nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
548 
549 	(void)setegid(pwd->pw_gid);
550 	initgroups(username, pwd->pw_gid);
551 	(void)seteuid(pwd->pw_uid);
552 
553 	if (chdir(pwd->pw_dir) < 0) {
554 #ifdef LOGIN_CAP
555                 if (login_getcapbool(lc, "requirehome", 0)) {
556 			(void)printf("Home directory %s required\n",
557 			    pwd->pw_dir);
558                         sleepexit(1);
559 		}
560 #endif
561 		(void)printf("No home directory %s!\n", pwd->pw_dir);
562 		if (chdir("/"))
563 			exit(0);
564 		pwd->pw_dir = "/";
565 		(void)printf("Logging in with home = \"/\".\n");
566 	}
567 
568 	if (!quietlog)
569 		quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
570 
571 	/* regain special privileges */
572 	(void)seteuid(saved_uid);
573 	setgroups(nsaved_gids, saved_gids);
574 	(void)setegid(saved_gid);
575 
576 #ifdef LOGIN_CAP
577         pw_warntime = login_getcaptime(lc, "password-warn",
578             _PASSWORD_WARNDAYS * SECSPERDAY,
579             _PASSWORD_WARNDAYS * SECSPERDAY);
580 #endif
581 
582 	(void)gettimeofday(&now, (struct timezone *)NULL);
583 	if (pwd->pw_expire) {
584 		if (now.tv_sec >= pwd->pw_expire) {
585 			(void)printf("Sorry -- your account has expired.\n");
586 			sleepexit(1);
587 		} else if (pwd->pw_expire - now.tv_sec < pw_warntime &&
588 		    !quietlog)
589 			(void)printf("Warning: your account expires on %s",
590 			    ctime(&pwd->pw_expire));
591 	}
592 	if (pwd->pw_change) {
593 		if (pwd->pw_change == _PASSWORD_CHGNOW)
594 			need_chpass = 1;
595 		else if (now.tv_sec >= pwd->pw_change) {
596 			(void)printf("Sorry -- your password has expired.\n");
597 			sleepexit(1);
598 		} else if (pwd->pw_change - now.tv_sec < pw_warntime &&
599 		    !quietlog)
600 			(void)printf("Warning: your password expires on %s",
601 			    ctime(&pwd->pw_change));
602 
603 	}
604 	/* Nothing else left to fail -- really log in. */
605 	update_db(quietlog);
606 
607 	(void)chown(ttyn, pwd->pw_uid,
608 	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
609 
610 	if (ttyaction(ttyn, "login", pwd->pw_name))
611 		(void)printf("Warning: ttyaction failed.\n");
612 
613 #if defined(KERBEROS) || defined(KERBEROS5)
614 	/* Fork so that we can call kdestroy */
615 	if (
616 #ifdef KERBEROS5
617 	    ! login_krb5_retain_ccache &&
618 #endif
619 	    has_ccache)
620 		dofork();
621 #endif
622 
623 	/* Destroy environment unless user has requested its preservation. */
624 	if (!pflag)
625 		environ = envinit;
626 
627 #ifdef LOGIN_CAP
628 	if (nested == NULL && setusercontext(lc, pwd, pwd->pw_uid,
629 	    LOGIN_SETLOGIN) != 0) {
630 		syslog(LOG_ERR, "setusercontext failed");
631 		exit(1);
632 	}
633 	if (setusercontext(lc, pwd, pwd->pw_uid,
634 	    (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETLOGIN))) != 0) {
635 		syslog(LOG_ERR, "setusercontext failed");
636 		exit(1);
637 	}
638 #else
639 	(void)setgid(pwd->pw_gid);
640 
641 	initgroups(username, pwd->pw_gid);
642 
643 	if (nested == NULL && setlogin(pwd->pw_name) < 0)
644 		syslog(LOG_ERR, "setlogin() failure: %m");
645 
646 	/* Discard permissions last so can't get killed and drop core. */
647 	if (rootlogin)
648 		(void)setuid(0);
649 	else
650 		(void)setuid(pwd->pw_uid);
651 #endif
652 
653 	if (*pwd->pw_shell == '\0')
654 		pwd->pw_shell = _PATH_BSHELL;
655 #ifdef LOGIN_CAP
656 	if ((shell = login_getcapstr(lc, "shell", NULL, NULL)) != NULL) {
657 		if ((shell = strdup(shell)) == NULL) {
658                 	syslog(LOG_ERR, "Cannot alloc mem");
659                 	sleepexit(1);
660 		}
661 		pwd->pw_shell = shell;
662 	}
663 #endif
664 
665 	(void)setenv("HOME", pwd->pw_dir, 1);
666 	(void)setenv("SHELL", pwd->pw_shell, 1);
667 	if (term[0] == '\0') {
668 		char *tt = (char *)stypeof(tty);
669 #ifdef LOGIN_CAP
670 		if (tt == NULL)
671 			tt = login_getcapstr(lc, "term", NULL, NULL);
672 #endif
673 		/* unknown term -> "su" */
674 		(void)strlcpy(term, tt != NULL ? tt : "su", sizeof(term));
675 	}
676 	(void)setenv("TERM", term, 0);
677 	(void)setenv("LOGNAME", pwd->pw_name, 1);
678 	(void)setenv("USER", pwd->pw_name, 1);
679 
680 #ifdef LOGIN_CAP
681 	setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH);
682 #else
683 	(void)setenv("PATH", _PATH_DEFPATH, 0);
684 #endif
685 
686 #ifdef KERBEROS
687 	if (krbtkfile_env)
688 		(void)setenv("KRBTKFILE", krbtkfile_env, 1);
689 #endif
690 #ifdef KERBEROS5
691 	if (krb5tkfile_env)
692 		(void)setenv("KRB5CCNAME", krb5tkfile_env, 1);
693 #endif
694 
695 	if (tty[sizeof("tty")-1] == 'd')
696 		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
697 
698 	/* If fflag is on, assume caller/authenticator has logged root login. */
699 	if (rootlogin && fflag == 0) {
700 		if (hostname)
701 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
702 			    username, tty, hostname);
703 		else
704 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
705 			    username, tty);
706 	}
707 
708 #if defined(KERBEROS) || defined(KERBEROS5)
709 	if (KERBEROS_CONFIGURED && !quietlog && notickets == 1)
710 		(void)printf("Warning: no Kerberos tickets issued.\n");
711 #endif
712 
713 	if (!quietlog) {
714 		char *fname;
715 #ifdef LOGIN_CAP
716 		fname = login_getcapstr(lc, "copyright", NULL, NULL);
717 		if (fname != NULL && access(fname, F_OK) == 0)
718 			motd(fname);
719 		else
720 #endif
721 			(void)printf("%s", copyrightstr);
722 
723 #ifdef LOGIN_CAP
724                 fname = login_getcapstr(lc, "welcome", NULL, NULL);
725                 if (fname == NULL || access(fname, F_OK) != 0)
726 #endif
727                         fname = _PATH_MOTDFILE;
728                 motd(fname);
729 
730 		(void)snprintf(tbuf,
731 		    sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
732 		if (stat(tbuf, &st) == 0 && st.st_size != 0)
733 			(void)printf("You have %smail.\n",
734 			    (st.st_mtime > st.st_atime) ? "new " : "");
735 	}
736 
737 #ifdef LOGIN_CAP
738 	login_close(lc);
739 #endif
740 
741 	(void)signal(SIGALRM, SIG_DFL);
742 	(void)signal(SIGQUIT, SIG_DFL);
743 	(void)signal(SIGINT, SIG_DFL);
744 	(void)signal(SIGTSTP, SIG_IGN);
745 
746 	tbuf[0] = '-';
747 	(void)strlcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
748 	    p + 1 : pwd->pw_shell, sizeof(tbuf) - 1);
749 
750 	/* Wait to change password until we're unprivileged */
751 	if (need_chpass) {
752 		if (!require_chpass)
753 			(void)printf(
754 "Warning: your password has expired. Please change it as soon as possible.\n");
755 		else {
756 			int	status;
757 
758 			(void)printf(
759 		    "Your password has expired. Please choose a new one.\n");
760 			switch (fork()) {
761 			case -1:
762 				warn("fork");
763 				sleepexit(1);
764 			case 0:
765 				execl(_PATH_BINPASSWD, "passwd", 0);
766 				_exit(1);
767 			default:
768 				if (wait(&status) == -1 ||
769 				    WEXITSTATUS(status))
770 					sleepexit(1);
771 			}
772 		}
773 	}
774 
775 #ifdef KERBEROS5
776 	if (login_krb5_get_tickets)
777 		k5_write_creds();
778 #endif
779 	execlp(pwd->pw_shell, tbuf, 0);
780 	err(1, "%s", pwd->pw_shell);
781 }
782 
783 #if defined(KERBEROS) || defined(KERBEROS5)
784 #define	NBUFSIZ		(MAXLOGNAME + 1 + 5)	/* .root suffix */
785 #else
786 #define	NBUFSIZ		(MAXLOGNAME + 1)
787 #endif
788 
789 #if defined(KERBEROS) || defined(KERBEROS5)
790 /*
791  * This routine handles cleanup stuff, and the like.
792  * It exists only in the child process.
793  */
794 #include <sys/wait.h>
795 void
796 dofork()
797 {
798 	int child;
799 
800 	if (!(child = fork()))
801 		return; /* Child process */
802 
803 	/*
804 	 * Setup stuff?  This would be things we could do in parallel
805 	 * with login
806 	 */
807 	(void)chdir("/");	/* Let's not keep the fs busy... */
808 
809 	/* If we're the parent, watch the child until it dies */
810 	while (wait(0) != child)
811 		;
812 
813 	/* Cleanup stuff */
814 	/* Run kdestroy to destroy tickets */
815 #ifdef KERBEROS
816 	kdestroy();
817 #endif
818 #ifdef KERBEROS5
819 	if (login_krb5_get_tickets)
820 		k5destroy();
821 #endif
822 
823 	/* Leave */
824 	exit(0);
825 }
826 #endif
827 
828 void
829 getloginname()
830 {
831 	int ch;
832 	char *p;
833 	static char nbuf[NBUFSIZ];
834 
835 	for (;;) {
836 		(void)printf("login: ");
837 		for (p = nbuf; (ch = getchar()) != '\n'; ) {
838 			if (ch == EOF) {
839 				badlogin(username);
840 				exit(0);
841 			}
842 			if (p < nbuf + (NBUFSIZ - 1))
843 				*p++ = ch;
844 		}
845 		if (p > nbuf) {
846 			if (nbuf[0] == '-')
847 				(void)fprintf(stderr,
848 				    "login names may not start with '-'.\n");
849 			else {
850 				*p = '\0';
851 				username = nbuf;
852 				break;
853 			}
854 		}
855 	}
856 }
857 
858 int
859 rootterm(ttyn)
860 	char *ttyn;
861 {
862 	struct ttyent *t;
863 
864 	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
865 }
866 
867 jmp_buf motdinterrupt;
868 
869 void
870 motd(fname)
871 	char *fname;
872 {
873 	int fd, nchars;
874 	sig_t oldint;
875 	char tbuf[8192];
876 
877 	if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0)
878 		return;
879 	oldint = signal(SIGINT, sigint);
880 	if (setjmp(motdinterrupt) == 0)
881 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
882 			(void)write(fileno(stdout), tbuf, nchars);
883 	(void)signal(SIGINT, oldint);
884 	(void)close(fd);
885 }
886 
887 /* ARGSUSED */
888 void
889 sigint(signo)
890 	int signo;
891 {
892 
893 	longjmp(motdinterrupt, 1);
894 }
895 
896 /* ARGSUSED */
897 void
898 timedout(signo)
899 	int signo;
900 {
901 
902 	(void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
903 	exit(0);
904 }
905 
906 void
907 checknologin(fname)
908 	char *fname;
909 {
910 	int fd, nchars;
911 	char tbuf[8192];
912 
913 	if ((fd = open(fname ? fname : _PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
914 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
915 			(void)write(fileno(stdout), tbuf, nchars);
916 		sleepexit(0);
917 	}
918 }
919 
920 static void
921 update_db(int quietlog)
922 {
923 	if (nested != NULL) {
924 		if (hostname != NULL)
925 			syslog(LOG_NOTICE, "%s to %s on tty %s from %s",
926 			    nested, pwd->pw_name, tty, hostname);
927 		else
928 			syslog(LOG_NOTICE, "%s to %s on tty %s", nested,
929 			    pwd->pw_name, tty);
930 
931 		return;
932 	}
933 	if (hostname != NULL) {
934 		socklen_t len = sizeof(ss);
935 		(void)getpeername(STDIN_FILENO, (struct sockaddr *)&ss, &len);
936 	}
937 	(void)gettimeofday(&now, NULL);
938 #ifdef SUPPORT_UTMPX
939 	doutmpx();
940 	dolastlogx(quietlog);
941 	quietlog = 1;
942 #endif
943 #ifdef SUPPORT_UTMP
944 	doutmp();
945 	dolastlog(quietlog);
946 #endif
947 }
948 
949 #ifdef SUPPORT_UTMPX
950 static void
951 doutmpx()
952 {
953 	struct utmpx utmpx;
954 	char *t;
955 
956 	memset((void *)&utmpx, 0, sizeof(utmpx));
957 	utmpx.ut_tv = now;
958 	(void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name));
959 	if (hostname) {
960 		(void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host));
961 		utmpx.ut_ss = ss;
962 	}
963 	(void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line));
964 	utmpx.ut_type = USER_PROCESS;
965 	utmpx.ut_pid = getpid();
966 	t = tty + strlen(tty);
967 	if (t - tty >= sizeof(utmpx.ut_id)) {
968 	    (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id),
969 		sizeof(utmpx.ut_id));
970 	} else {
971 	    (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id));
972 	}
973 	if (pututxline(&utmpx) == NULL)
974 		syslog(LOG_NOTICE, "Cannot update utmpx %m");
975 	endutxent();
976 	if (updwtmpx(_PATH_WTMPX, &utmpx) != 0)
977 		syslog(LOG_NOTICE, "Cannot update wtmpx %m");
978 }
979 
980 static void
981 dolastlogx(quiet)
982 	int quiet;
983 {
984 	struct lastlogx ll;
985 	if (getlastlogx(pwd->pw_uid, &ll) != NULL) {
986 		time_t t = (time_t)ll.ll_tv.tv_sec;
987 		(void)printf("Last login: %.24s ", ctime(&t));
988 		if (*ll.ll_host != '\0')
989 			(void)printf("from %.*s ",
990 			    (int)sizeof(ll.ll_host),
991 			    ll.ll_host);
992 		(void)printf("on %.*s\n",
993 		    (int)sizeof(ll.ll_line),
994 		    ll.ll_line);
995 	}
996 	ll.ll_tv = now;
997 	(void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
998 	if (hostname) {
999 		(void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
1000 		ll.ll_ss = ss;
1001 	}
1002 	if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0)
1003 		syslog(LOG_NOTICE, "Cannot update lastlogx %m");
1004 }
1005 #endif
1006 
1007 #ifdef SUPPORT_UTMP
1008 static void
1009 doutmp()
1010 {
1011 	struct utmp utmp;
1012 
1013 	(void)memset((void *)&utmp, 0, sizeof(utmp));
1014 	utmp.ut_time = now.tv_sec;
1015 	(void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
1016 	if (hostname)
1017 		(void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
1018 	(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
1019 	login(&utmp);
1020 }
1021 
1022 static void
1023 dolastlog(quiet)
1024 	int quiet;
1025 {
1026 	struct lastlog ll;
1027 	int fd;
1028 
1029 	if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
1030 		(void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
1031 		if (!quiet) {
1032 			if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
1033 			    ll.ll_time != 0) {
1034 				(void)printf("Last login: %.24s ",
1035 				    ctime(&ll.ll_time));
1036 				if (*ll.ll_host != '\0')
1037 					(void)printf("from %.*s ",
1038 					    (int)sizeof(ll.ll_host),
1039 					    ll.ll_host);
1040 				(void)printf("on %.*s\n",
1041 				    (int)sizeof(ll.ll_line), ll.ll_line);
1042 			}
1043 			(void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
1044 			    SEEK_SET);
1045 		}
1046 		memset((void *)&ll, 0, sizeof(ll));
1047 		ll.ll_time = now.tv_sec;
1048 		(void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
1049 		if (hostname)
1050 			(void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
1051 		(void)write(fd, (char *)&ll, sizeof(ll));
1052 		(void)close(fd);
1053 	}
1054 }
1055 #endif
1056 
1057 void
1058 badlogin(name)
1059 	char *name;
1060 {
1061 
1062 	if (failures == 0)
1063 		return;
1064 	if (hostname) {
1065 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
1066 		    failures, failures > 1 ? "S" : "", hostname);
1067 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
1068 		    "%d LOGIN FAILURE%s FROM %s, %s",
1069 		    failures, failures > 1 ? "S" : "", hostname, name);
1070 	} else {
1071 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
1072 		    failures, failures > 1 ? "S" : "", tty);
1073 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
1074 		    "%d LOGIN FAILURE%s ON %s, %s",
1075 		    failures, failures > 1 ? "S" : "", tty, name);
1076 	}
1077 }
1078 
1079 const char *
1080 stypeof(ttyid)
1081 	const char *ttyid;
1082 {
1083 	struct ttyent *t;
1084 
1085 	return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL);
1086 }
1087 
1088 void
1089 sleepexit(eval)
1090 	int eval;
1091 {
1092 
1093 	(void)sleep(5);
1094 	exit(eval);
1095 }
1096