login.c revision 264192
1/*-
2 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 2002 Networks Associates Technologies, Inc.
5 * All rights reserved.
6 *
7 * Portions of this software were developed for the FreeBSD Project by
8 * ThinkSec AS and NAI Labs, the Security Research Division of Network
9 * Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
10 * ("CBOSS"), as part of the DARPA CHATS research program.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 *    must display the following acknowledgement:
22 *	This product includes software developed by the University of
23 *	California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 *    may be used to endorse or promote products derived from this software
26 *    without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40
41#if 0
42#ifndef lint
43static char sccsid[] = "@(#)login.c	8.4 (Berkeley) 4/2/94";
44#endif
45#endif
46
47#include <sys/cdefs.h>
48__FBSDID("$FreeBSD: stable/10/usr.bin/login/login.c 264192 2014-04-06 10:56:27Z jilles $");
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/file.h>
58#include <sys/stat.h>
59#include <sys/time.h>
60#include <sys/resource.h>
61#include <sys/wait.h>
62
63#include <err.h>
64#include <errno.h>
65#include <grp.h>
66#include <libutil.h>
67#include <login_cap.h>
68#include <pwd.h>
69#include <setjmp.h>
70#include <signal.h>
71#include <stdio.h>
72#include <stdlib.h>
73#include <string.h>
74#include <syslog.h>
75#include <ttyent.h>
76#include <unistd.h>
77
78#include <security/pam_appl.h>
79#include <security/openpam.h>
80
81#include "login.h"
82#include "pathnames.h"
83
84static int		 auth_pam(void);
85static void		 bail(int, int);
86static void		 bail_internal(int, int, int);
87static int		 export(const char *);
88static void		 export_pam_environment(void);
89static int		 motd(const char *);
90static void		 badlogin(char *);
91static char		*getloginname(void);
92static void		 pam_syslog(const char *);
93static void		 pam_cleanup(void);
94static void		 refused(const char *, const char *, int);
95static const char	*stypeof(char *);
96static void		 sigint(int);
97static void		 timedout(int);
98static void		 bail_sig(int);
99static void		 usage(void);
100
101#define	TTYGRPNAME		"tty"			/* group to own ttys */
102#define	DEFAULT_BACKOFF		3
103#define	DEFAULT_RETRIES		10
104#define	DEFAULT_PROMPT		"login: "
105#define	DEFAULT_PASSWD_PROMPT	"Password:"
106#define	TERM_UNKNOWN		"su"
107#define	DEFAULT_WARN		(2L * 7L * 86400L)	/* Two weeks */
108#define NO_SLEEP_EXIT		0
109#define SLEEP_EXIT		5
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 */
115static u_int		timeout = 300;
116
117/* Buffer for signal handling of timeout */
118static jmp_buf		 timeout_buf;
119
120struct passwd		*pwd;
121static int		 failures;
122
123static char		*envinit[1];	/* empty environment list */
124
125/*
126 * Command line flags and arguments
127 */
128static int		 fflag;		/* -f: do not perform authentication */
129static int		 hflag;		/* -h: login from remote host */
130static char		*hostname;	/* hostname from command line */
131static int		 pflag;		/* -p: preserve environment */
132
133/*
134 * User name
135 */
136static char		*username;	/* user name */
137static char		*olduser;	/* previous user name */
138
139/*
140 * Prompts
141 */
142static char		 default_prompt[] = DEFAULT_PROMPT;
143static const char	*prompt;
144static char		 default_passwd_prompt[] = DEFAULT_PASSWD_PROMPT;
145static const char	*passwd_prompt;
146
147static char		*tty;
148
149/*
150 * PAM data
151 */
152static pam_handle_t	*pamh = NULL;
153static struct pam_conv	 pamc = { openpam_ttyconv, NULL };
154static int		 pam_err;
155static int		 pam_silent = PAM_SILENT;
156static int		 pam_cred_established;
157static int		 pam_session_established;
158
159int
160main(int argc, char *argv[])
161{
162	struct group *gr;
163	struct stat st;
164	int retries, backoff;
165	int ask, ch, cnt, quietlog, rootlogin, rval;
166	uid_t uid, euid;
167	gid_t egid;
168	char *term;
169	char *p, *ttyn;
170	char tname[sizeof(_PATH_TTY) + 10];
171	char *arg0;
172	const char *tp;
173	const char *shell = NULL;
174	login_cap_t *lc = NULL;
175	login_cap_t *lc_user = NULL;
176	pid_t pid;
177	sigset_t mask, omask;
178	struct sigaction sa;
179#ifdef USE_BSM_AUDIT
180	char auditsuccess = 1;
181#endif
182
183	sa.sa_flags = SA_RESTART;
184	(void)sigfillset(&sa.sa_mask);
185	sa.sa_handler = SIG_IGN;
186	(void)sigaction(SIGQUIT, &sa, NULL);
187	(void)sigaction(SIGINT, &sa, NULL);
188	(void)sigaction(SIGHUP, &sa, NULL);
189	if (setjmp(timeout_buf)) {
190		if (failures)
191			badlogin(username);
192		(void)fprintf(stderr, "Login timed out after %d seconds\n",
193		    timeout);
194		bail(NO_SLEEP_EXIT, 0);
195	}
196	sa.sa_handler = timedout;
197	(void)sigaction(SIGALRM, &sa, NULL);
198	(void)alarm(timeout);
199	(void)setpriority(PRIO_PROCESS, 0, 0);
200
201	openlog("login", LOG_ODELAY, LOG_AUTH);
202
203	uid = getuid();
204	euid = geteuid();
205	egid = getegid();
206
207	while ((ch = getopt(argc, argv, "fh:p")) != -1)
208		switch (ch) {
209		case 'f':
210			fflag = 1;
211			break;
212		case 'h':
213			if (uid != 0)
214				errx(1, "-h option: %s", strerror(EPERM));
215			if (strlen(optarg) >= MAXHOSTNAMELEN)
216				errx(1, "-h option: %s: exceeds maximum "
217				    "hostname size", optarg);
218			hflag = 1;
219			hostname = optarg;
220			break;
221		case 'p':
222			pflag = 1;
223			break;
224		case '?':
225		default:
226			if (uid == 0)
227				syslog(LOG_ERR, "invalid flag %c", ch);
228			usage();
229		}
230	argc -= optind;
231	argv += optind;
232
233	if (argc > 0) {
234		username = strdup(*argv);
235		if (username == NULL)
236			err(1, "strdup()");
237		ask = 0;
238	} else {
239		ask = 1;
240	}
241
242	setproctitle("-%s", getprogname());
243
244	closefrom(3);
245
246	/*
247	 * Get current TTY
248	 */
249	ttyn = ttyname(STDIN_FILENO);
250	if (ttyn == NULL || *ttyn == '\0') {
251		(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
252		ttyn = tname;
253	}
254	if (strncmp(ttyn, _PATH_DEV, sizeof _PATH_DEV - 1) == 0)
255		tty = ttyn + sizeof _PATH_DEV - 1;
256	else
257		tty = ttyn;
258
259	/*
260	 * Get "login-retries" & "login-backoff" from default class
261	 */
262	lc = login_getclass(NULL);
263	prompt = login_getcapstr(lc, "login_prompt",
264	    default_prompt, default_prompt);
265	passwd_prompt = login_getcapstr(lc, "passwd_prompt",
266	    default_passwd_prompt, default_passwd_prompt);
267	retries = login_getcapnum(lc, "login-retries",
268	    DEFAULT_RETRIES, DEFAULT_RETRIES);
269	backoff = login_getcapnum(lc, "login-backoff",
270	    DEFAULT_BACKOFF, DEFAULT_BACKOFF);
271	login_close(lc);
272	lc = NULL;
273
274	/*
275	 * Try to authenticate the user until we succeed or time out.
276	 */
277	for (cnt = 0;; ask = 1) {
278		if (ask) {
279			fflag = 0;
280			if (olduser != NULL)
281				free(olduser);
282			olduser = username;
283			username = getloginname();
284		}
285		rootlogin = 0;
286
287		/*
288		 * Note if trying multiple user names; log failures for
289		 * previous user name, but don't bother logging one failure
290		 * for nonexistent name (mistyped username).
291		 */
292		if (failures && strcmp(olduser, username) != 0) {
293			if (failures > (pwd ? 0 : 1))
294				badlogin(olduser);
295		}
296
297		/*
298		 * Load the PAM policy and set some variables
299		 */
300		pam_err = pam_start("login", username, &pamc, &pamh);
301		if (pam_err != PAM_SUCCESS) {
302			pam_syslog("pam_start()");
303#ifdef USE_BSM_AUDIT
304			au_login_fail("PAM Error", 1);
305#endif
306			bail(NO_SLEEP_EXIT, 1);
307		}
308		pam_err = pam_set_item(pamh, PAM_TTY, tty);
309		if (pam_err != PAM_SUCCESS) {
310			pam_syslog("pam_set_item(PAM_TTY)");
311#ifdef USE_BSM_AUDIT
312			au_login_fail("PAM Error", 1);
313#endif
314			bail(NO_SLEEP_EXIT, 1);
315		}
316		pam_err = pam_set_item(pamh, PAM_RHOST, hostname);
317		if (pam_err != PAM_SUCCESS) {
318			pam_syslog("pam_set_item(PAM_RHOST)");
319#ifdef USE_BSM_AUDIT
320			au_login_fail("PAM Error", 1);
321#endif
322			bail(NO_SLEEP_EXIT, 1);
323		}
324
325		pwd = getpwnam(username);
326		if (pwd != NULL && pwd->pw_uid == 0)
327			rootlogin = 1;
328
329		/*
330		 * If the -f option was specified and the caller is
331		 * root or the caller isn't changing their uid, don't
332		 * authenticate.
333		 */
334		if (pwd != NULL && fflag &&
335		    (uid == (uid_t)0 || uid == (uid_t)pwd->pw_uid)) {
336			/* already authenticated */
337			rval = 0;
338#ifdef USE_BSM_AUDIT
339			auditsuccess = 0; /* opened a terminal window only */
340#endif
341		} else {
342			fflag = 0;
343			(void)setpriority(PRIO_PROCESS, 0, -4);
344			rval = auth_pam();
345			(void)setpriority(PRIO_PROCESS, 0, 0);
346		}
347
348		if (pwd && rval == 0)
349			break;
350
351		pam_cleanup();
352
353		/*
354		 * We are not exiting here, but this corresponds to a failed
355		 * login event, so set exitstatus to 1.
356		 */
357#ifdef USE_BSM_AUDIT
358		au_login_fail("Login incorrect", 1);
359#endif
360
361		(void)printf("Login incorrect\n");
362		failures++;
363
364		pwd = NULL;
365
366		/*
367		 * Allow up to 'retry' (10) attempts, but start
368		 * backing off after 'backoff' (3) attempts.
369		 */
370		if (++cnt > backoff) {
371			if (cnt >= retries) {
372				badlogin(username);
373				bail(SLEEP_EXIT, 1);
374			}
375			sleep((u_int)((cnt - backoff) * 5));
376		}
377	}
378
379	/* committed to login -- turn off timeout */
380	(void)alarm((u_int)0);
381
382	(void)sigemptyset(&mask);
383	(void)sigaddset(&mask, SIGHUP);
384	(void)sigaddset(&mask, SIGTERM);
385	(void)sigprocmask(SIG_BLOCK, &mask, &omask);
386	sa.sa_handler = bail_sig;
387	(void)sigaction(SIGHUP, &sa, NULL);
388	(void)sigaction(SIGTERM, &sa, NULL);
389
390	endpwent();
391
392#ifdef USE_BSM_AUDIT
393	/* Audit successful login. */
394	if (auditsuccess)
395		au_login_success();
396#endif
397
398        /*
399         * This needs to happen before login_getpwclass to support
400         * home directories on GSS-API authenticated NFS where the
401         * kerberos credentials need to be saved so that the kernel
402         * can authenticate to the NFS server.
403         */
404	pam_err = pam_setcred(pamh, pam_silent|PAM_ESTABLISH_CRED);
405	if (pam_err != PAM_SUCCESS) {
406		pam_syslog("pam_setcred()");
407		bail(NO_SLEEP_EXIT, 1);
408	}
409	pam_cred_established = 1;
410
411	/*
412	 * Establish the login class.
413	 */
414	lc = login_getpwclass(pwd);
415	lc_user = login_getuserclass(pwd);
416
417	if (!(quietlog = login_getcapbool(lc_user, "hushlogin", 0)))
418		quietlog = login_getcapbool(lc, "hushlogin", 0);
419
420	/*
421	 * Switching needed for NFS with root access disabled.
422	 *
423	 * XXX: This change fails to modify the additional groups for the
424	 * process, and as such, may restrict rights normally granted
425	 * through those groups.
426	 */
427	(void)setegid(pwd->pw_gid);
428	(void)seteuid(rootlogin ? 0 : pwd->pw_uid);
429	if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
430		if (login_getcapbool(lc, "requirehome", 0))
431			refused("Home directory not available", "HOMEDIR", 1);
432		if (chdir("/") < 0)
433			refused("Cannot find root directory", "ROOTDIR", 1);
434		if (!quietlog || *pwd->pw_dir)
435			printf("No home directory.\nLogging in with home = \"/\".\n");
436		pwd->pw_dir = strdup("/");
437		if (pwd->pw_dir == NULL) {
438			syslog(LOG_NOTICE, "strdup(): %m");
439			bail(SLEEP_EXIT, 1);
440		}
441	}
442	(void)seteuid(euid);
443	(void)setegid(egid);
444	if (!quietlog) {
445		quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
446		if (!quietlog)
447			pam_silent = 0;
448	}
449
450	shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
451	if (*pwd->pw_shell == '\0')
452		pwd->pw_shell = strdup(_PATH_BSHELL);
453	if (pwd->pw_shell == NULL) {
454		syslog(LOG_NOTICE, "strdup(): %m");
455		bail(SLEEP_EXIT, 1);
456	}
457	if (*shell == '\0')   /* Not overridden */
458		shell = pwd->pw_shell;
459	if ((shell = strdup(shell)) == NULL) {
460		syslog(LOG_NOTICE, "strdup(): %m");
461		bail(SLEEP_EXIT, 1);
462	}
463
464	/*
465	 * Set device protections, depending on what terminal the
466	 * user is logged in. This feature is used on Suns to give
467	 * console users better privacy.
468	 */
469	login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
470
471	/*
472	 * Clear flags of the tty.  None should be set, and when the
473	 * user sets them otherwise, this can cause the chown to fail.
474	 * Since it isn't clear that flags are useful on character
475	 * devices, we just clear them.
476	 *
477	 * We don't log in the case of EOPNOTSUPP because dev might be
478	 * on NFS, which doesn't support chflags.
479	 *
480	 * We don't log in the EROFS because that means that /dev is on
481	 * a read only file system and we assume that the permissions there
482	 * are sane.
483	 */
484	if (ttyn != tname && chflags(ttyn, 0))
485		if (errno != EOPNOTSUPP && errno != EROFS)
486			syslog(LOG_ERR, "chflags(%s): %m", ttyn);
487	if (ttyn != tname && chown(ttyn, pwd->pw_uid,
488	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid))
489		if (errno != EROFS)
490			syslog(LOG_ERR, "chown(%s): %m", ttyn);
491
492	/*
493	 * Exclude cons/vt/ptys only, assume dialup otherwise
494	 * TODO: Make dialup tty determination a library call
495	 * for consistency (finger etc.)
496	 */
497	if (hflag && isdialuptty(tty))
498		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
499
500#ifdef LOGALL
501	/*
502	 * Syslog each successful login, so we don't have to watch
503	 * hundreds of wtmp or lastlogin files.
504	 */
505	if (hflag)
506		syslog(LOG_INFO, "login from %s on %s as %s",
507		       hostname, tty, pwd->pw_name);
508	else
509		syslog(LOG_INFO, "login on %s as %s",
510		       tty, pwd->pw_name);
511#endif
512
513	/*
514	 * If fflag is on, assume caller/authenticator has logged root
515	 * login.
516	 */
517	if (rootlogin && fflag == 0) {
518		if (hflag)
519			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
520			    username, tty, hostname);
521		else
522			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
523			    username, tty);
524	}
525
526	/*
527	 * Destroy environment unless user has requested its
528	 * preservation - but preserve TERM in all cases
529	 */
530	term = getenv("TERM");
531	if (!pflag)
532		environ = envinit;
533	if (term != NULL)
534		setenv("TERM", term, 0);
535
536	/*
537	 * PAM modules might add supplementary groups during pam_setcred().
538	 */
539	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
540		syslog(LOG_ERR, "setusercontext() failed - exiting");
541		bail(NO_SLEEP_EXIT, 1);
542	}
543
544	pam_err = pam_setcred(pamh, pam_silent|PAM_REINITIALIZE_CRED);
545	if (pam_err != PAM_SUCCESS) {
546		pam_syslog("pam_setcred()");
547		bail(NO_SLEEP_EXIT, 1);
548	}
549
550	pam_err = pam_open_session(pamh, pam_silent);
551	if (pam_err != PAM_SUCCESS) {
552		pam_syslog("pam_open_session()");
553		bail(NO_SLEEP_EXIT, 1);
554	}
555	pam_session_established = 1;
556
557	/*
558	 * We must fork() before setuid() because we need to call
559	 * pam_close_session() as root.
560	 */
561	pid = fork();
562	if (pid < 0) {
563		err(1, "fork");
564	} else if (pid != 0) {
565		/*
566		 * Parent: wait for child to finish, then clean up
567		 * session.
568		 *
569		 * If we get SIGHUP or SIGTERM, clean up the session
570		 * and exit right away. This will make the terminal
571		 * inaccessible and send SIGHUP to the foreground
572		 * process group.
573		 */
574		int status;
575		setproctitle("-%s [pam]", getprogname());
576		(void)sigprocmask(SIG_SETMASK, &omask, NULL);
577		waitpid(pid, &status, 0);
578		(void)sigprocmask(SIG_BLOCK, &mask, NULL);
579		bail(NO_SLEEP_EXIT, 0);
580	}
581
582	/*
583	 * NOTICE: We are now in the child process!
584	 */
585
586	/*
587	 * Add any environment variables the PAM modules may have set.
588	 */
589	export_pam_environment();
590
591	/*
592	 * We're done with PAM now; our parent will deal with the rest.
593	 */
594	pam_end(pamh, 0);
595	pamh = NULL;
596
597	/*
598	 * We don't need to be root anymore, so set the login name and
599	 * the UID.
600	 */
601	if (setlogin(username) != 0) {
602		syslog(LOG_ERR, "setlogin(%s): %m - exiting", username);
603		bail(NO_SLEEP_EXIT, 1);
604	}
605	if (setusercontext(lc, pwd, pwd->pw_uid,
606	    LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) {
607		syslog(LOG_ERR, "setusercontext() failed - exiting");
608		exit(1);
609	}
610
611	(void)setenv("SHELL", pwd->pw_shell, 1);
612	(void)setenv("HOME", pwd->pw_dir, 1);
613	/* Overwrite "term" from login.conf(5) for any known TERM */
614	if (term == NULL && (tp = stypeof(tty)) != NULL)
615		(void)setenv("TERM", tp, 1);
616	else
617		(void)setenv("TERM", TERM_UNKNOWN, 0);
618	(void)setenv("LOGNAME", username, 1);
619	(void)setenv("USER", username, 1);
620	(void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
621
622	if (!quietlog) {
623		const char *cw;
624
625		cw = login_getcapstr(lc, "welcome", NULL, NULL);
626		if (cw != NULL && access(cw, F_OK) == 0)
627			motd(cw);
628		else
629			motd(_PATH_MOTDFILE);
630
631		if (login_getcapbool(lc_user, "nocheckmail", 0) == 0 &&
632		    login_getcapbool(lc, "nocheckmail", 0) == 0) {
633			char *cx;
634
635			/* $MAIL may have been set by class. */
636			cx = getenv("MAIL");
637			if (cx == NULL) {
638				asprintf(&cx, "%s/%s",
639				    _PATH_MAILDIR, pwd->pw_name);
640			}
641			if (cx && stat(cx, &st) == 0 && st.st_size != 0)
642				(void)printf("You have %smail.\n",
643				    (st.st_mtime > st.st_atime) ? "new " : "");
644			if (getenv("MAIL") == NULL)
645				free(cx);
646		}
647	}
648
649	login_close(lc_user);
650	login_close(lc);
651
652	sa.sa_handler = SIG_DFL;
653	(void)sigaction(SIGALRM, &sa, NULL);
654	(void)sigaction(SIGQUIT, &sa, NULL);
655	(void)sigaction(SIGINT, &sa, NULL);
656	(void)sigaction(SIGTERM, &sa, NULL);
657	(void)sigaction(SIGHUP, &sa, NULL);
658	sa.sa_handler = SIG_IGN;
659	(void)sigaction(SIGTSTP, &sa, NULL);
660	(void)sigprocmask(SIG_SETMASK, &omask, NULL);
661
662	/*
663	 * Login shells have a leading '-' in front of argv[0]
664	 */
665	p = strrchr(pwd->pw_shell, '/');
666	if (asprintf(&arg0, "-%s", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) {
667		syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size",
668		    username);
669		errx(1, "shell exceeds maximum pathname size");
670	} else if (arg0 == NULL) {
671		err(1, "asprintf()");
672	}
673
674	execlp(shell, arg0, (char *)0);
675	err(1, "%s", shell);
676
677	/*
678	 * That's it, folks!
679	 */
680}
681
682/*
683 * Attempt to authenticate the user using PAM.  Returns 0 if the user is
684 * authenticated, or 1 if not authenticated.  If some sort of PAM system
685 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
686 * function returns -1.  This can be used as an indication that we should
687 * fall back to a different authentication mechanism.
688 */
689static int
690auth_pam(void)
691{
692	const char *tmpl_user;
693	const void *item;
694	int rval;
695
696	pam_err = pam_authenticate(pamh, pam_silent);
697	switch (pam_err) {
698
699	case PAM_SUCCESS:
700		/*
701		 * With PAM we support the concept of a "template"
702		 * user.  The user enters a login name which is
703		 * authenticated by PAM, usually via a remote service
704		 * such as RADIUS or TACACS+.  If authentication
705		 * succeeds, a different but related "template" name
706		 * is used for setting the credentials, shell, and
707		 * home directory.  The name the user enters need only
708		 * exist on the remote authentication server, but the
709		 * template name must be present in the local password
710		 * database.
711		 *
712		 * This is supported by two various mechanisms in the
713		 * individual modules.  However, from the application's
714		 * point of view, the template user is always passed
715		 * back as a changed value of the PAM_USER item.
716		 */
717		pam_err = pam_get_item(pamh, PAM_USER, &item);
718		if (pam_err == PAM_SUCCESS) {
719			tmpl_user = (const char *)item;
720			if (strcmp(username, tmpl_user) != 0)
721				pwd = getpwnam(tmpl_user);
722		} else {
723			pam_syslog("pam_get_item(PAM_USER)");
724		}
725		rval = 0;
726		break;
727
728	case PAM_AUTH_ERR:
729	case PAM_USER_UNKNOWN:
730	case PAM_MAXTRIES:
731		rval = 1;
732		break;
733
734	default:
735		pam_syslog("pam_authenticate()");
736		rval = -1;
737		break;
738	}
739
740	if (rval == 0) {
741		pam_err = pam_acct_mgmt(pamh, pam_silent);
742		switch (pam_err) {
743		case PAM_SUCCESS:
744			break;
745		case PAM_NEW_AUTHTOK_REQD:
746			pam_err = pam_chauthtok(pamh,
747			    pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK);
748			if (pam_err != PAM_SUCCESS) {
749				pam_syslog("pam_chauthtok()");
750				rval = 1;
751			}
752			break;
753		default:
754			pam_syslog("pam_acct_mgmt()");
755			rval = 1;
756			break;
757		}
758	}
759
760	if (rval != 0) {
761		pam_end(pamh, pam_err);
762		pamh = NULL;
763	}
764	return (rval);
765}
766
767/*
768 * Export any environment variables PAM modules may have set
769 */
770static void
771export_pam_environment(void)
772{
773	char **pam_env;
774	char **pp;
775
776	pam_env = pam_getenvlist(pamh);
777	if (pam_env != NULL) {
778		for (pp = pam_env; *pp != NULL; pp++) {
779			(void)export(*pp);
780			free(*pp);
781		}
782	}
783}
784
785/*
786 * Perform sanity checks on an environment variable:
787 * - Make sure there is an '=' in the string.
788 * - Make sure the string doesn't run on too long.
789 * - Do not export certain variables.  This list was taken from the
790 *   Solaris pam_putenv(3) man page.
791 * Then export it.
792 */
793static int
794export(const char *s)
795{
796	static const char *noexport[] = {
797		"SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
798		"IFS", "PATH", NULL
799	};
800	char *p;
801	const char **pp;
802	size_t n;
803
804	if (strlen(s) > 1024 || (p = strchr(s, '=')) == NULL)
805		return (0);
806	if (strncmp(s, "LD_", 3) == 0)
807		return (0);
808	for (pp = noexport; *pp != NULL; pp++) {
809		n = strlen(*pp);
810		if (s[n] == '=' && strncmp(s, *pp, n) == 0)
811			return (0);
812	}
813	*p = '\0';
814	(void)setenv(s, p + 1, 1);
815	*p = '=';
816	return (1);
817}
818
819static void
820usage(void)
821{
822
823	(void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n");
824	exit(1);
825}
826
827/*
828 * Prompt user and read login name from stdin.
829 */
830static char *
831getloginname(void)
832{
833	char *nbuf, *p;
834	int ch;
835
836	nbuf = malloc(MAXLOGNAME);
837	if (nbuf == NULL)
838		err(1, "malloc()");
839	do {
840		(void)printf("%s", prompt);
841		for (p = nbuf; (ch = getchar()) != '\n'; ) {
842			if (ch == EOF) {
843				badlogin(username);
844				bail(NO_SLEEP_EXIT, 0);
845			}
846			if (p < nbuf + MAXLOGNAME - 1)
847				*p++ = ch;
848		}
849	} while (p == nbuf);
850
851	*p = '\0';
852	if (nbuf[0] == '-') {
853		pam_silent = 0;
854		memmove(nbuf, nbuf + 1, strlen(nbuf));
855	} else {
856		pam_silent = PAM_SILENT;
857	}
858	return nbuf;
859}
860
861/*
862 * SIGINT handler for motd().
863 */
864static volatile int motdinterrupt;
865static void
866sigint(int signo __unused)
867{
868	motdinterrupt = 1;
869}
870
871/*
872 * Display the contents of a file (such as /etc/motd).
873 */
874static int
875motd(const char *motdfile)
876{
877	struct sigaction newint, oldint;
878	FILE *f;
879	int ch;
880
881	if ((f = fopen(motdfile, "r")) == NULL)
882		return (-1);
883	motdinterrupt = 0;
884	newint.sa_handler = sigint;
885	newint.sa_flags = 0;
886	sigfillset(&newint.sa_mask);
887	sigaction(SIGINT, &newint, &oldint);
888	while ((ch = fgetc(f)) != EOF && !motdinterrupt)
889		putchar(ch);
890	sigaction(SIGINT, &oldint, NULL);
891	if (ch != EOF || ferror(f)) {
892		fclose(f);
893		return (-1);
894	}
895	fclose(f);
896	return (0);
897}
898
899/*
900 * SIGALRM handler, to enforce login prompt timeout.
901 *
902 * XXX This can potentially confuse the hell out of PAM.  We should
903 * XXX instead implement a conversation function that returns
904 * XXX PAM_CONV_ERR when interrupted by a signal, and have the signal
905 * XXX handler just set a flag.
906 */
907static void
908timedout(int signo __unused)
909{
910
911	longjmp(timeout_buf, signo);
912}
913
914static void
915badlogin(char *name)
916{
917
918	if (failures == 0)
919		return;
920	if (hflag) {
921		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
922		    failures, failures > 1 ? "S" : "", hostname);
923		syslog(LOG_AUTHPRIV|LOG_NOTICE,
924		    "%d LOGIN FAILURE%s FROM %s, %s",
925		    failures, failures > 1 ? "S" : "", hostname, name);
926	} else {
927		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
928		    failures, failures > 1 ? "S" : "", tty);
929		syslog(LOG_AUTHPRIV|LOG_NOTICE,
930		    "%d LOGIN FAILURE%s ON %s, %s",
931		    failures, failures > 1 ? "S" : "", tty, name);
932	}
933	failures = 0;
934}
935
936const char *
937stypeof(char *ttyid)
938{
939	struct ttyent *t;
940
941	if (ttyid != NULL && *ttyid != '\0') {
942		t = getttynam(ttyid);
943		if (t != NULL && t->ty_type != NULL)
944			return (t->ty_type);
945	}
946	return (NULL);
947}
948
949static void
950refused(const char *msg, const char *rtype, int lout)
951{
952
953	if (msg != NULL)
954	    printf("%s.\n", msg);
955	if (hflag)
956		syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
957		    pwd->pw_name, rtype, hostname, tty);
958	else
959		syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
960		    pwd->pw_name, rtype, tty);
961	if (lout)
962		bail(SLEEP_EXIT, 1);
963}
964
965/*
966 * Log a PAM error
967 */
968static void
969pam_syslog(const char *msg)
970{
971	syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err));
972}
973
974/*
975 * Shut down PAM
976 */
977static void
978pam_cleanup(void)
979{
980
981	if (pamh != NULL) {
982		if (pam_session_established) {
983			pam_err = pam_close_session(pamh, 0);
984			if (pam_err != PAM_SUCCESS)
985				pam_syslog("pam_close_session()");
986		}
987		pam_session_established = 0;
988		if (pam_cred_established) {
989			pam_err = pam_setcred(pamh, pam_silent|PAM_DELETE_CRED);
990			if (pam_err != PAM_SUCCESS)
991				pam_syslog("pam_setcred()");
992		}
993		pam_cred_established = 0;
994		pam_end(pamh, pam_err);
995		pamh = NULL;
996	}
997}
998
999static void
1000bail_internal(int sec, int eval, int signo)
1001{
1002	struct sigaction sa;
1003
1004	pam_cleanup();
1005#ifdef USE_BSM_AUDIT
1006	if (pwd != NULL)
1007		audit_logout();
1008#endif
1009	(void)sleep(sec);
1010	if (signo == 0)
1011		exit(eval);
1012	else {
1013		sa.sa_handler = SIG_DFL;
1014		sa.sa_flags = 0;
1015		(void)sigemptyset(&sa.sa_mask);
1016		(void)sigaction(signo, &sa, NULL);
1017		(void)sigaddset(&sa.sa_mask, signo);
1018		(void)sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
1019		raise(signo);
1020		exit(128 + signo);
1021	}
1022}
1023
1024/*
1025 * Exit, optionally after sleeping a few seconds
1026 */
1027static void
1028bail(int sec, int eval)
1029{
1030	bail_internal(sec, eval, 0);
1031}
1032
1033/*
1034 * Exit because of a signal.
1035 * This is not async-signal safe, so only call async-signal safe functions
1036 * while the signal is unmasked.
1037 */
1038static void
1039bail_sig(int signo)
1040{
1041	bail_internal(NO_SLEEP_EXIT, 0, signo);
1042}
1043