xref: /freebsd/usr.bin/login/login.c (revision 1e25eb287f3fdd763df98065dbf2e1eb201e4000)
19b50d902SRodney W. Grimes /*-
2df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro F. Giffuni  *
49b50d902SRodney W. Grimes  * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
59b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
6f2c44cceSDag-Erling Smørgrav  * Copyright (c) 2002 Networks Associates Technologies, Inc.
7f2c44cceSDag-Erling Smørgrav  * All rights reserved.
8f2c44cceSDag-Erling Smørgrav  *
9f2c44cceSDag-Erling Smørgrav  * Portions of this software were developed for the FreeBSD Project by
10f2c44cceSDag-Erling Smørgrav  * ThinkSec AS and NAI Labs, the Security Research Division of Network
11f2c44cceSDag-Erling Smørgrav  * Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
12f2c44cceSDag-Erling Smørgrav  * ("CBOSS"), as part of the DARPA CHATS research program.
139b50d902SRodney W. Grimes  *
149b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
159b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
169b50d902SRodney W. Grimes  * are met:
179b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
189b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
199b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
209b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
219b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
229b50d902SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
239b50d902SRodney W. Grimes  *    must display the following acknowledgement:
249b50d902SRodney W. Grimes  *	This product includes software developed by the University of
259b50d902SRodney W. Grimes  *	California, Berkeley and its contributors.
269b50d902SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
279b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
289b50d902SRodney W. Grimes  *    without specific prior written permission.
299b50d902SRodney W. Grimes  *
309b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
319b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
329b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
339b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
349b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
359b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
369b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
379b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
389b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
399b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
409b50d902SRodney W. Grimes  * SUCH DAMAGE.
419b50d902SRodney W. Grimes  */
429b50d902SRodney W. Grimes 
439f5b04e9SDavid Malone #include <sys/cdefs.h>
449b50d902SRodney W. Grimes /*
459b50d902SRodney W. Grimes  * login [ name ]
469b50d902SRodney W. Grimes  * login -h hostname	(for telnetd, etc.)
479b50d902SRodney W. Grimes  * login -f name	(for pre-authenticated login: datakit, xterm, etc.)
489b50d902SRodney W. Grimes  */
499b50d902SRodney W. Grimes 
501a8b24c2SMark Murray #include <sys/param.h>
51a9648779SMark Murray #include <sys/file.h>
52a9648779SMark Murray #include <sys/stat.h>
539b50d902SRodney W. Grimes #include <sys/time.h>
549b50d902SRodney W. Grimes #include <sys/resource.h>
55a9648779SMark Murray #include <sys/wait.h>
569b50d902SRodney W. Grimes 
579b50d902SRodney W. Grimes #include <err.h>
589b50d902SRodney W. Grimes #include <errno.h>
599b50d902SRodney W. Grimes #include <grp.h>
606717b4a8SJohn Polstra #include <login_cap.h>
619b50d902SRodney W. Grimes #include <pwd.h>
629b50d902SRodney W. Grimes #include <setjmp.h>
639b50d902SRodney W. Grimes #include <signal.h>
649b50d902SRodney W. Grimes #include <stdio.h>
659b50d902SRodney W. Grimes #include <stdlib.h>
669b50d902SRodney W. Grimes #include <string.h>
679b50d902SRodney W. Grimes #include <syslog.h>
689b50d902SRodney W. Grimes #include <ttyent.h>
699b50d902SRodney W. Grimes #include <unistd.h>
709b50d902SRodney W. Grimes 
71e8334816SJohn Polstra #include <security/pam_appl.h>
72519b6a4cSDag-Erling Smørgrav #include <security/openpam.h>
732ddadf84SPaul Traina 
74e317b970SMark Murray #include "login.h"
759b50d902SRodney W. Grimes #include "pathnames.h"
769b50d902SRodney W. Grimes 
77c60ed00aSDag-Erling Smørgrav static int		 auth_pam(void);
78c60ed00aSDag-Erling Smørgrav static void		 bail(int, int);
792482c270SJilles Tjoelker static void		 bail_internal(int, int, int);
80c60ed00aSDag-Erling Smørgrav static int		 export(const char *);
81c60ed00aSDag-Erling Smørgrav static void		 export_pam_environment(void);
82c60ed00aSDag-Erling Smørgrav static int		 motd(const char *);
83c60ed00aSDag-Erling Smørgrav static void		 badlogin(char *);
84c60ed00aSDag-Erling Smørgrav static char		*getloginname(void);
85c60ed00aSDag-Erling Smørgrav static void		 pam_syslog(const char *);
86c60ed00aSDag-Erling Smørgrav static void		 pam_cleanup(void);
87c60ed00aSDag-Erling Smørgrav static void		 refused(const char *, const char *, int);
88c60ed00aSDag-Erling Smørgrav static const char	*stypeof(char *);
89c60ed00aSDag-Erling Smørgrav static void		 sigint(int);
90c60ed00aSDag-Erling Smørgrav static void		 timedout(int);
912482c270SJilles Tjoelker static void		 bail_sig(int);
92c60ed00aSDag-Erling Smørgrav static void		 usage(void);
93142277ceSMark Murray 
94e317b970SMark Murray #define	TTYGRPNAME		"tty"			/* group to own ttys */
95a52c1be6SDavid Nugent #define	DEFAULT_BACKOFF		3
96a52c1be6SDavid Nugent #define	DEFAULT_RETRIES		10
97078ae588SDavid E. O'Brien #define	DEFAULT_PROMPT		"login: "
98078ae588SDavid E. O'Brien #define	DEFAULT_PASSWD_PROMPT	"Password:"
99c60ed00aSDag-Erling Smørgrav #define	TERM_UNKNOWN		"su"
100e317b970SMark Murray #define	DEFAULT_WARN		(2L * 7L * 86400L)	/* Two weeks */
101c60ed00aSDag-Erling Smørgrav #define	NO_SLEEP_EXIT		0
102c60ed00aSDag-Erling Smørgrav #define	SLEEP_EXIT		5
1039b50d902SRodney W. Grimes 
1049b50d902SRodney W. Grimes /*
1059b50d902SRodney W. Grimes  * This bounds the time given to login.  Not a define so it can
1069b50d902SRodney W. Grimes  * be patched on machines where it's too small.
1079b50d902SRodney W. Grimes  */
108c60ed00aSDag-Erling Smørgrav static u_int		timeout = 300;
1099b50d902SRodney W. Grimes 
110b606e33cSEivind Eklund /* Buffer for signal handling of timeout */
111c60ed00aSDag-Erling Smørgrav static jmp_buf		 timeout_buf;
112b606e33cSEivind Eklund 
113a3d80dd8SDag-Erling Smørgrav char			 pwbuf[1024];
114a3d80dd8SDag-Erling Smørgrav struct passwd		 pwres;
1159b50d902SRodney W. Grimes struct passwd		*pwd;
116c60ed00aSDag-Erling Smørgrav static int		 failures;
117c60ed00aSDag-Erling Smørgrav 
118c60ed00aSDag-Erling Smørgrav static char		*envinit[1];	/* empty environment list */
119c60ed00aSDag-Erling Smørgrav 
120c60ed00aSDag-Erling Smørgrav /*
121c60ed00aSDag-Erling Smørgrav  * Command line flags and arguments
122c60ed00aSDag-Erling Smørgrav  */
123c60ed00aSDag-Erling Smørgrav static int		 fflag;		/* -f: do not perform authentication */
124c60ed00aSDag-Erling Smørgrav static int		 hflag;		/* -h: login from remote host */
125c60ed00aSDag-Erling Smørgrav static char		*hostname;	/* hostname from command line */
126c60ed00aSDag-Erling Smørgrav static int		 pflag;		/* -p: preserve environment */
127c60ed00aSDag-Erling Smørgrav 
128c60ed00aSDag-Erling Smørgrav /*
129c60ed00aSDag-Erling Smørgrav  * User name
130c60ed00aSDag-Erling Smørgrav  */
131c60ed00aSDag-Erling Smørgrav static char		*username;	/* user name */
132c60ed00aSDag-Erling Smørgrav static char		*olduser;	/* previous user name */
133c60ed00aSDag-Erling Smørgrav 
134c60ed00aSDag-Erling Smørgrav /*
135c60ed00aSDag-Erling Smørgrav  * Prompts
136c60ed00aSDag-Erling Smørgrav  */
137c60ed00aSDag-Erling Smørgrav static char		 default_prompt[] = DEFAULT_PROMPT;
138f2f306b6SRuslan Ermilov static const char	*prompt;
139c60ed00aSDag-Erling Smørgrav static char		 default_passwd_prompt[] = DEFAULT_PASSWD_PROMPT;
140f2f306b6SRuslan Ermilov static const char	*passwd_prompt;
141c60ed00aSDag-Erling Smørgrav 
142c60ed00aSDag-Erling Smørgrav static char		*tty;
143c60ed00aSDag-Erling Smørgrav 
144c60ed00aSDag-Erling Smørgrav /*
145c60ed00aSDag-Erling Smørgrav  * PAM data
146c60ed00aSDag-Erling Smørgrav  */
147c60ed00aSDag-Erling Smørgrav static pam_handle_t	*pamh = NULL;
148519b6a4cSDag-Erling Smørgrav static struct pam_conv	 pamc = { openpam_ttyconv, NULL };
149c60ed00aSDag-Erling Smørgrav static int		 pam_err;
150c60ed00aSDag-Erling Smørgrav static int		 pam_silent = PAM_SILENT;
151c60ed00aSDag-Erling Smørgrav static int		 pam_cred_established;
152c60ed00aSDag-Erling Smørgrav static int		 pam_session_established;
1539b50d902SRodney W. Grimes 
1549b50d902SRodney W. Grimes int
main(int argc,char * argv[])155c60ed00aSDag-Erling Smørgrav main(int argc, char *argv[])
1569b50d902SRodney W. Grimes {
1579b50d902SRodney W. Grimes 	struct group *gr;
1589b50d902SRodney W. Grimes 	struct stat st;
159c60ed00aSDag-Erling Smørgrav 	int retries, backoff;
160c60ed00aSDag-Erling Smørgrav 	int ask, ch, cnt, quietlog, rootlogin, rval;
161c8ff1808SPeter Wemm 	uid_t uid, euid;
1620514336dSAndrey A. Chernov 	gid_t egid;
163c60ed00aSDag-Erling Smørgrav 	char *term;
1643a6afd0dSBrian Somers 	char *p, *ttyn;
165b606e33cSEivind Eklund 	char tname[sizeof(_PATH_TTY) + 10];
166f2f306b6SRuslan Ermilov 	char *arg0;
16779a20d3bSAndrey A. Chernov 	const char *tp;
168f2f306b6SRuslan Ermilov 	const char *shell = NULL;
1696acc486bSDavid Nugent 	login_cap_t *lc = NULL;
17042dc3715SMaxim Konovalov 	login_cap_t *lc_user = NULL;
1715bc9d93dSMark Murray 	pid_t pid;
1722482c270SJilles Tjoelker 	sigset_t mask, omask;
1732482c270SJilles Tjoelker 	struct sigaction sa;
1740c59c145SChristian S.J. Peron #ifdef USE_BSM_AUDIT
175a1c73d21SWayne Salamon 	char auditsuccess = 1;
1760c59c145SChristian S.J. Peron #endif
1779b50d902SRodney W. Grimes 
1782482c270SJilles Tjoelker 	sa.sa_flags = SA_RESTART;
1792482c270SJilles Tjoelker 	(void)sigfillset(&sa.sa_mask);
1802482c270SJilles Tjoelker 	sa.sa_handler = SIG_IGN;
1812482c270SJilles Tjoelker 	(void)sigaction(SIGQUIT, &sa, NULL);
1822482c270SJilles Tjoelker 	(void)sigaction(SIGINT, &sa, NULL);
1832482c270SJilles Tjoelker 	(void)sigaction(SIGHUP, &sa, NULL);
184b606e33cSEivind Eklund 	if (setjmp(timeout_buf)) {
185b606e33cSEivind Eklund 		if (failures)
186c60ed00aSDag-Erling Smørgrav 			badlogin(username);
18791a72a92SDavid E. O'Brien 		(void)fprintf(stderr, "Login timed out after %d seconds\n",
18891a72a92SDavid E. O'Brien 		    timeout);
189c60ed00aSDag-Erling Smørgrav 		bail(NO_SLEEP_EXIT, 0);
190b606e33cSEivind Eklund 	}
1912482c270SJilles Tjoelker 	sa.sa_handler = timedout;
1922482c270SJilles Tjoelker 	(void)sigaction(SIGALRM, &sa, NULL);
193b606e33cSEivind Eklund 	(void)alarm(timeout);
1949b50d902SRodney W. Grimes 	(void)setpriority(PRIO_PROCESS, 0, 0);
1959b50d902SRodney W. Grimes 
1964d552825SAlex Richardson 	openlog("login", LOG_CONS, LOG_AUTH);
1979b50d902SRodney W. Grimes 
1989b50d902SRodney W. Grimes 	uid = getuid();
199159da441SPeter Wemm 	euid = geteuid();
2000514336dSAndrey A. Chernov 	egid = getegid();
201c60ed00aSDag-Erling Smørgrav 
2021c8af878SWarner Losh 	while ((ch = getopt(argc, argv, "fh:p")) != -1)
2039b50d902SRodney W. Grimes 		switch (ch) {
2049b50d902SRodney W. Grimes 		case 'f':
2059b50d902SRodney W. Grimes 			fflag = 1;
2069b50d902SRodney W. Grimes 			break;
2079b50d902SRodney W. Grimes 		case 'h':
208c60ed00aSDag-Erling Smørgrav 			if (uid != 0)
2099b50d902SRodney W. Grimes 				errx(1, "-h option: %s", strerror(EPERM));
210c60ed00aSDag-Erling Smørgrav 			if (strlen(optarg) >= MAXHOSTNAMELEN)
2119ab4f412SMike Barcroft 				errx(1, "-h option: %s: exceeds maximum "
2129ab4f412SMike Barcroft 				    "hostname size", optarg);
213c60ed00aSDag-Erling Smørgrav 			hflag = 1;
2149b50d902SRodney W. Grimes 			hostname = optarg;
2159b50d902SRodney W. Grimes 			break;
2169b50d902SRodney W. Grimes 		case 'p':
2179b50d902SRodney W. Grimes 			pflag = 1;
2189b50d902SRodney W. Grimes 			break;
2199b50d902SRodney W. Grimes 		case '?':
2209b50d902SRodney W. Grimes 		default:
221c60ed00aSDag-Erling Smørgrav 			if (uid == 0)
2229b50d902SRodney W. Grimes 				syslog(LOG_ERR, "invalid flag %c", ch);
2239c9cb2bfSPhilippe Charnier 			usage();
2249b50d902SRodney W. Grimes 		}
2259b50d902SRodney W. Grimes 	argc -= optind;
2269b50d902SRodney W. Grimes 	argv += optind;
2279b50d902SRodney W. Grimes 
228c60ed00aSDag-Erling Smørgrav 	if (argc > 0) {
229c60ed00aSDag-Erling Smørgrav 		username = strdup(*argv);
230c60ed00aSDag-Erling Smørgrav 		if (username == NULL)
231c60ed00aSDag-Erling Smørgrav 			err(1, "strdup()");
2329b50d902SRodney W. Grimes 		ask = 0;
233c60ed00aSDag-Erling Smørgrav 	} else {
2349b50d902SRodney W. Grimes 		ask = 1;
235c60ed00aSDag-Erling Smørgrav 	}
2369b50d902SRodney W. Grimes 
2372517862eSDag-Erling Smørgrav 	setproctitle("-%s", getprogname());
2382517862eSDag-Erling Smørgrav 
239587250b2SEd Schouten 	closefrom(3);
2409b50d902SRodney W. Grimes 
241c60ed00aSDag-Erling Smørgrav 	/*
242c60ed00aSDag-Erling Smørgrav 	 * Get current TTY
243c60ed00aSDag-Erling Smørgrav 	 */
2449b50d902SRodney W. Grimes 	ttyn = ttyname(STDIN_FILENO);
2459b50d902SRodney W. Grimes 	if (ttyn == NULL || *ttyn == '\0') {
2469b50d902SRodney W. Grimes 		(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
2479b50d902SRodney W. Grimes 		ttyn = tname;
2489b50d902SRodney W. Grimes 	}
24995e7b94aSEd Schouten 	if (strncmp(ttyn, _PATH_DEV, sizeof _PATH_DEV - 1) == 0)
25095e7b94aSEd Schouten 		tty = ttyn + sizeof _PATH_DEV - 1;
2519b50d902SRodney W. Grimes 	else
2529b50d902SRodney W. Grimes 		tty = ttyn;
2539b50d902SRodney W. Grimes 
254a52c1be6SDavid Nugent 	/*
255a52c1be6SDavid Nugent 	 * Get "login-retries" & "login-backoff" from default class
256a52c1be6SDavid Nugent 	 */
257a52c1be6SDavid Nugent 	lc = login_getclass(NULL);
2585c4b7a56SDag-Erling Smørgrav 	prompt = login_getcapstr(lc, "login_prompt",
259c60ed00aSDag-Erling Smørgrav 	    default_prompt, default_prompt);
260078ae588SDavid E. O'Brien 	passwd_prompt = login_getcapstr(lc, "passwd_prompt",
261e317b970SMark Murray 	    default_passwd_prompt, default_passwd_prompt);
262c60ed00aSDag-Erling Smørgrav 	retries = login_getcapnum(lc, "login-retries",
263c60ed00aSDag-Erling Smørgrav 	    DEFAULT_RETRIES, DEFAULT_RETRIES);
264c60ed00aSDag-Erling Smørgrav 	backoff = login_getcapnum(lc, "login-backoff",
265c60ed00aSDag-Erling Smørgrav 	    DEFAULT_BACKOFF, DEFAULT_BACKOFF);
266a52c1be6SDavid Nugent 	login_close(lc);
267a52c1be6SDavid Nugent 	lc = NULL;
2686acc486bSDavid Nugent 
269c60ed00aSDag-Erling Smørgrav 	/*
270c60ed00aSDag-Erling Smørgrav 	 * Try to authenticate the user until we succeed or time out.
271c60ed00aSDag-Erling Smørgrav 	 */
2729b50d902SRodney W. Grimes 	for (cnt = 0;; ask = 1) {
2739b50d902SRodney W. Grimes 		if (ask) {
2749b50d902SRodney W. Grimes 			fflag = 0;
275c60ed00aSDag-Erling Smørgrav 			if (olduser != NULL)
276c60ed00aSDag-Erling Smørgrav 				free(olduser);
277c60ed00aSDag-Erling Smørgrav 			olduser = username;
278c60ed00aSDag-Erling Smørgrav 			username = getloginname();
2799b50d902SRodney W. Grimes 		}
2809b50d902SRodney W. Grimes 		rootlogin = 0;
2819b50d902SRodney W. Grimes 
2829b50d902SRodney W. Grimes 		/*
2839b50d902SRodney W. Grimes 		 * Note if trying multiple user names; log failures for
2849b50d902SRodney W. Grimes 		 * previous user name, but don't bother logging one failure
2859b50d902SRodney W. Grimes 		 * for nonexistent name (mistyped username).
2869b50d902SRodney W. Grimes 		 */
287c60ed00aSDag-Erling Smørgrav 		if (failures && strcmp(olduser, username) != 0) {
2889b50d902SRodney W. Grimes 			if (failures > (pwd ? 0 : 1))
289c60ed00aSDag-Erling Smørgrav 				badlogin(olduser);
2909b50d902SRodney W. Grimes 		}
291c60ed00aSDag-Erling Smørgrav 
292c60ed00aSDag-Erling Smørgrav 		/*
293c60ed00aSDag-Erling Smørgrav 		 * Load the PAM policy and set some variables
294c60ed00aSDag-Erling Smørgrav 		 */
295c60ed00aSDag-Erling Smørgrav 		pam_err = pam_start("login", username, &pamc, &pamh);
296c60ed00aSDag-Erling Smørgrav 		if (pam_err != PAM_SUCCESS) {
297c60ed00aSDag-Erling Smørgrav 			pam_syslog("pam_start()");
2980c59c145SChristian S.J. Peron #ifdef USE_BSM_AUDIT
299a1c73d21SWayne Salamon 			au_login_fail("PAM Error", 1);
3000c59c145SChristian S.J. Peron #endif
301c60ed00aSDag-Erling Smørgrav 			bail(NO_SLEEP_EXIT, 1);
302c60ed00aSDag-Erling Smørgrav 		}
303c60ed00aSDag-Erling Smørgrav 		pam_err = pam_set_item(pamh, PAM_TTY, tty);
304c60ed00aSDag-Erling Smørgrav 		if (pam_err != PAM_SUCCESS) {
305c60ed00aSDag-Erling Smørgrav 			pam_syslog("pam_set_item(PAM_TTY)");
3060c59c145SChristian S.J. Peron #ifdef USE_BSM_AUDIT
307a1c73d21SWayne Salamon 			au_login_fail("PAM Error", 1);
3080c59c145SChristian S.J. Peron #endif
309c60ed00aSDag-Erling Smørgrav 			bail(NO_SLEEP_EXIT, 1);
310c60ed00aSDag-Erling Smørgrav 		}
311d477c0caSDag-Erling Smørgrav 		pam_err = pam_set_item(pamh, PAM_RHOST, hostname);
312c60ed00aSDag-Erling Smørgrav 		if (pam_err != PAM_SUCCESS) {
313c60ed00aSDag-Erling Smørgrav 			pam_syslog("pam_set_item(PAM_RHOST)");
3140c59c145SChristian S.J. Peron #ifdef USE_BSM_AUDIT
315a1c73d21SWayne Salamon 			au_login_fail("PAM Error", 1);
3160c59c145SChristian S.J. Peron #endif
317c60ed00aSDag-Erling Smørgrav 			bail(NO_SLEEP_EXIT, 1);
318c60ed00aSDag-Erling Smørgrav 		}
3199b50d902SRodney W. Grimes 
320a3d80dd8SDag-Erling Smørgrav 		(void)getpwnam_r(username, &pwres, pwbuf, sizeof(pwbuf), &pwd);
321e8334816SJohn Polstra 		if (pwd != NULL && pwd->pw_uid == 0)
322e8334816SJohn Polstra 			rootlogin = 1;
323e8334816SJohn Polstra 
3249b50d902SRodney W. Grimes 		/*
325c60ed00aSDag-Erling Smørgrav 		 * If the -f option was specified and the caller is
326c60ed00aSDag-Erling Smørgrav 		 * root or the caller isn't changing their uid, don't
327c60ed00aSDag-Erling Smørgrav 		 * authenticate.
3289b50d902SRodney W. Grimes 		 */
329c60ed00aSDag-Erling Smørgrav 		if (pwd != NULL && fflag &&
330c60ed00aSDag-Erling Smørgrav 		    (uid == (uid_t)0 || uid == (uid_t)pwd->pw_uid)) {
331c60ed00aSDag-Erling Smørgrav 			/* already authenticated */
332c60ed00aSDag-Erling Smørgrav 			rval = 0;
3330c59c145SChristian S.J. Peron #ifdef USE_BSM_AUDIT
334a1c73d21SWayne Salamon 			auditsuccess = 0; /* opened a terminal window only */
3350c59c145SChristian S.J. Peron #endif
336c60ed00aSDag-Erling Smørgrav 		} else {
337c60ed00aSDag-Erling Smørgrav 			fflag = 0;
338c60ed00aSDag-Erling Smørgrav 			(void)setpriority(PRIO_PROCESS, 0, -4);
339c60ed00aSDag-Erling Smørgrav 			rval = auth_pam();
340c60ed00aSDag-Erling Smørgrav 			(void)setpriority(PRIO_PROCESS, 0, 0);
341d8a7b347SDavid Nugent 		}
3429b50d902SRodney W. Grimes 
343a3d80dd8SDag-Erling Smørgrav 		if (pwd != NULL && rval == 0)
344c60ed00aSDag-Erling Smørgrav 			break;
345c60ed00aSDag-Erling Smørgrav 
346c60ed00aSDag-Erling Smørgrav 		pam_cleanup();
347c60ed00aSDag-Erling Smørgrav 
348a1c73d21SWayne Salamon 		/*
349a1c73d21SWayne Salamon 		 * We are not exiting here, but this corresponds to a failed
350a1c73d21SWayne Salamon 		 * login event, so set exitstatus to 1.
351a1c73d21SWayne Salamon 		 */
3520c59c145SChristian S.J. Peron #ifdef USE_BSM_AUDIT
353a1c73d21SWayne Salamon 		au_login_fail("Login incorrect", 1);
3540c59c145SChristian S.J. Peron #endif
355a1c73d21SWayne Salamon 
3569b50d902SRodney W. Grimes 		(void)printf("Login incorrect\n");
3579b50d902SRodney W. Grimes 		failures++;
358a52c1be6SDavid Nugent 
3598f9370b0SOlivier Houchard 		pwd = NULL;
3608f9370b0SOlivier Houchard 
361a52c1be6SDavid Nugent 		/*
362c60ed00aSDag-Erling Smørgrav 		 * Allow up to 'retry' (10) attempts, but start
363c60ed00aSDag-Erling Smørgrav 		 * backing off after 'backoff' (3) attempts.
364a52c1be6SDavid Nugent 		 */
365a52c1be6SDavid Nugent 		if (++cnt > backoff) {
366a52c1be6SDavid Nugent 			if (cnt >= retries) {
3679b50d902SRodney W. Grimes 				badlogin(username);
368c60ed00aSDag-Erling Smørgrav 				bail(SLEEP_EXIT, 1);
3699b50d902SRodney W. Grimes 			}
370580367f2SJoseph Koshy 			sleep((u_int)((cnt - backoff) * 5));
3719b50d902SRodney W. Grimes 		}
3729b50d902SRodney W. Grimes 	}
3739b50d902SRodney W. Grimes 
3749b50d902SRodney W. Grimes 	/* committed to login -- turn off timeout */
3759b50d902SRodney W. Grimes 	(void)alarm((u_int)0);
3762482c270SJilles Tjoelker 
3772482c270SJilles Tjoelker 	(void)sigemptyset(&mask);
3782482c270SJilles Tjoelker 	(void)sigaddset(&mask, SIGHUP);
3792482c270SJilles Tjoelker 	(void)sigaddset(&mask, SIGTERM);
3802482c270SJilles Tjoelker 	(void)sigprocmask(SIG_BLOCK, &mask, &omask);
3812482c270SJilles Tjoelker 	sa.sa_handler = bail_sig;
3822482c270SJilles Tjoelker 	(void)sigaction(SIGHUP, &sa, NULL);
3832482c270SJilles Tjoelker 	(void)sigaction(SIGTERM, &sa, NULL);
3849b50d902SRodney W. Grimes 
3859b50d902SRodney W. Grimes 	endpwent();
3869b50d902SRodney W. Grimes 
3870c59c145SChristian S.J. Peron #ifdef USE_BSM_AUDIT
388a1c73d21SWayne Salamon 	/* Audit successful login. */
389a1c73d21SWayne Salamon 	if (auditsuccess)
390a1c73d21SWayne Salamon 		au_login_success();
3910c59c145SChristian S.J. Peron #endif
392a1c73d21SWayne Salamon 
393e8334816SJohn Polstra 	/*
394ba675b41SDoug Rabson 	 * This needs to happen before login_getpwclass to support
395ba675b41SDoug Rabson 	 * home directories on GSS-API authenticated NFS where the
396ba675b41SDoug Rabson 	 * kerberos credentials need to be saved so that the kernel
397ba675b41SDoug Rabson 	 * can authenticate to the NFS server.
398ba675b41SDoug Rabson 	 */
399ba675b41SDoug Rabson 	pam_err = pam_setcred(pamh, pam_silent|PAM_ESTABLISH_CRED);
400ba675b41SDoug Rabson 	if (pam_err != PAM_SUCCESS) {
401ba675b41SDoug Rabson 		pam_syslog("pam_setcred()");
402ba675b41SDoug Rabson 		bail(NO_SLEEP_EXIT, 1);
403ba675b41SDoug Rabson 	}
404ba675b41SDoug Rabson 	pam_cred_established = 1;
405ba675b41SDoug Rabson 
406ba675b41SDoug Rabson 	/*
407e8334816SJohn Polstra 	 * Establish the login class.
408e8334816SJohn Polstra 	 */
409e8334816SJohn Polstra 	lc = login_getpwclass(pwd);
41042dc3715SMaxim Konovalov 	lc_user = login_getuserclass(pwd);
411e8334816SJohn Polstra 
41242dc3715SMaxim Konovalov 	if (!(quietlog = login_getcapbool(lc_user, "hushlogin", 0)))
4136acc486bSDavid Nugent 		quietlog = login_getcapbool(lc, "hushlogin", 0);
414c60ed00aSDag-Erling Smørgrav 
4152c19b38fSRobert Watson 	/*
4162c19b38fSRobert Watson 	 * Switching needed for NFS with root access disabled.
4172c19b38fSRobert Watson 	 *
4182c19b38fSRobert Watson 	 * XXX: This change fails to modify the additional groups for the
4192c19b38fSRobert Watson 	 * process, and as such, may restrict rights normally granted
4202c19b38fSRobert Watson 	 * through those groups.
4212c19b38fSRobert Watson 	 */
4220514336dSAndrey A. Chernov 	(void)setegid(pwd->pw_gid);
423159da441SPeter Wemm 	(void)seteuid(rootlogin ? 0 : pwd->pw_uid);
4246acc486bSDavid Nugent 	if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
4254b2fab75SPaul Traina 		if (login_getcapbool(lc, "requirehome", 0))
426a52c1be6SDavid Nugent 			refused("Home directory not available", "HOMEDIR", 1);
427f72b1ff3SDavid Nugent 		if (chdir("/") < 0)
428a52c1be6SDavid Nugent 			refused("Cannot find root directory", "ROOTDIR", 1);
429a52c1be6SDavid Nugent 		if (!quietlog || *pwd->pw_dir)
430a52c1be6SDavid Nugent 			printf("No home directory.\nLogging in with home = \"/\".\n");
431e317b970SMark Murray 		pwd->pw_dir = strdup("/");
432e317b970SMark Murray 		if (pwd->pw_dir == NULL) {
433e317b970SMark Murray 			syslog(LOG_NOTICE, "strdup(): %m");
434c60ed00aSDag-Erling Smørgrav 			bail(SLEEP_EXIT, 1);
435e317b970SMark Murray 		}
4366acc486bSDavid Nugent 	}
437159da441SPeter Wemm 	(void)seteuid(euid);
4380514336dSAndrey A. Chernov 	(void)setegid(egid);
43971f4a30dSMax Khon 	if (!quietlog) {
4409b50d902SRodney W. Grimes 		quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
44171f4a30dSMax Khon 		if (!quietlog)
44271f4a30dSMax Khon 			pam_silent = 0;
44371f4a30dSMax Khon 	}
4449b50d902SRodney W. Grimes 
445a52c1be6SDavid Nugent 	shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
446a52c1be6SDavid Nugent 	if (*pwd->pw_shell == '\0')
447e317b970SMark Murray 		pwd->pw_shell = strdup(_PATH_BSHELL);
448e317b970SMark Murray 	if (pwd->pw_shell == NULL) {
449e317b970SMark Murray 		syslog(LOG_NOTICE, "strdup(): %m");
450c60ed00aSDag-Erling Smørgrav 		bail(SLEEP_EXIT, 1);
451e317b970SMark Murray 	}
452a52c1be6SDavid Nugent 	if (*shell == '\0')   /* Not overridden */
453a52c1be6SDavid Nugent 		shell = pwd->pw_shell;
454a52c1be6SDavid Nugent 	if ((shell = strdup(shell)) == NULL) {
4559ab4f412SMike Barcroft 		syslog(LOG_NOTICE, "strdup(): %m");
456c60ed00aSDag-Erling Smørgrav 		bail(SLEEP_EXIT, 1);
4576acc486bSDavid Nugent 	}
4586acc486bSDavid Nugent 
459f88fe867SGuido van Rooij 	/*
460f88fe867SGuido van Rooij 	 * Set device protections, depending on what terminal the
461f88fe867SGuido van Rooij 	 * user is logged in. This feature is used on Suns to give
462f88fe867SGuido van Rooij 	 * console users better privacy.
463f88fe867SGuido van Rooij 	 */
464f88fe867SGuido van Rooij 	login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
465f88fe867SGuido van Rooij 
466a761a465SWarner Losh 	/*
467a761a465SWarner Losh 	 * Clear flags of the tty.  None should be set, and when the
468a761a465SWarner Losh 	 * user sets them otherwise, this can cause the chown to fail.
469a761a465SWarner Losh 	 * Since it isn't clear that flags are useful on character
470a761a465SWarner Losh 	 * devices, we just clear them.
47184bbb6caSWarner Losh 	 *
47284bbb6caSWarner Losh 	 * We don't log in the case of EOPNOTSUPP because dev might be
47384bbb6caSWarner Losh 	 * on NFS, which doesn't support chflags.
47484bbb6caSWarner Losh 	 *
47584bbb6caSWarner Losh 	 * We don't log in the EROFS because that means that /dev is on
47684bbb6caSWarner Losh 	 * a read only file system and we assume that the permissions there
47784bbb6caSWarner Losh 	 * are sane.
478a761a465SWarner Losh 	 */
47984bbb6caSWarner Losh 	if (ttyn != tname && chflags(ttyn, 0))
48084bbb6caSWarner Losh 		if (errno != EOPNOTSUPP && errno != EROFS)
481c60ed00aSDag-Erling Smørgrav 			syslog(LOG_ERR, "chflags(%s): %m", ttyn);
482c60ed00aSDag-Erling Smørgrav 	if (ttyn != tname && chown(ttyn, pwd->pw_uid,
483a761a465SWarner Losh 	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid))
48484bbb6caSWarner Losh 		if (errno != EROFS)
485a2ba8df6SRobert Watson 			syslog(LOG_ERR, "chown(%s): %m", ttyn);
486a761a465SWarner Losh 
487c9bdc152SPaul Traina #ifdef LOGALL
488c9bdc152SPaul Traina 	/*
489c60ed00aSDag-Erling Smørgrav 	 * Syslog each successful login, so we don't have to watch
490c60ed00aSDag-Erling Smørgrav 	 * hundreds of wtmp or lastlogin files.
491c9bdc152SPaul Traina 	 */
492c60ed00aSDag-Erling Smørgrav 	if (hflag)
493a52c1be6SDavid Nugent 		syslog(LOG_INFO, "login from %s on %s as %s",
494c60ed00aSDag-Erling Smørgrav 		       hostname, tty, pwd->pw_name);
495a52c1be6SDavid Nugent 	else
496a52c1be6SDavid Nugent 		syslog(LOG_INFO, "login on %s as %s",
497a52c1be6SDavid Nugent 		       tty, pwd->pw_name);
4986acc486bSDavid Nugent #endif
4996acc486bSDavid Nugent 
500a52c1be6SDavid Nugent 	/*
501c60ed00aSDag-Erling Smørgrav 	 * If fflag is on, assume caller/authenticator has logged root
502c60ed00aSDag-Erling Smørgrav 	 * login.
503a52c1be6SDavid Nugent 	 */
504c60ed00aSDag-Erling Smørgrav 	if (rootlogin && fflag == 0) {
505c60ed00aSDag-Erling Smørgrav 		if (hflag)
506a52c1be6SDavid Nugent 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
507c60ed00aSDag-Erling Smørgrav 			    username, tty, hostname);
508a52c1be6SDavid Nugent 		else
509a52c1be6SDavid Nugent 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
510a52c1be6SDavid Nugent 			    username, tty);
511a52c1be6SDavid Nugent 	}
512a52c1be6SDavid Nugent 
513a52c1be6SDavid Nugent 	/*
514c60ed00aSDag-Erling Smørgrav 	 * Destroy environment unless user has requested its
515c60ed00aSDag-Erling Smørgrav 	 * preservation - but preserve TERM in all cases
516a52c1be6SDavid Nugent 	 */
517c60ed00aSDag-Erling Smørgrav 	term = getenv("TERM");
5186acc486bSDavid Nugent 	if (!pflag)
5196acc486bSDavid Nugent 		environ = envinit;
520c60ed00aSDag-Erling Smørgrav 	if (term != NULL)
521c60ed00aSDag-Erling Smørgrav 		setenv("TERM", term, 0);
5226acc486bSDavid Nugent 
5235bc9d93dSMark Murray 	/*
5245bc9d93dSMark Murray 	 * PAM modules might add supplementary groups during pam_setcred().
5255bc9d93dSMark Murray 	 */
5265bc9d93dSMark Murray 	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
5275bc9d93dSMark Murray 		syslog(LOG_ERR, "setusercontext() failed - exiting");
528c60ed00aSDag-Erling Smørgrav 		bail(NO_SLEEP_EXIT, 1);
5295bc9d93dSMark Murray 	}
5305bc9d93dSMark Murray 
531ba675b41SDoug Rabson 	pam_err = pam_setcred(pamh, pam_silent|PAM_REINITIALIZE_CRED);
532c60ed00aSDag-Erling Smørgrav 	if (pam_err != PAM_SUCCESS) {
533c60ed00aSDag-Erling Smørgrav 		pam_syslog("pam_setcred()");
534c60ed00aSDag-Erling Smørgrav 		bail(NO_SLEEP_EXIT, 1);
5355bc9d93dSMark Murray 	}
5365bc9d93dSMark Murray 
537c60ed00aSDag-Erling Smørgrav 	pam_err = pam_open_session(pamh, pam_silent);
538c60ed00aSDag-Erling Smørgrav 	if (pam_err != PAM_SUCCESS) {
539c60ed00aSDag-Erling Smørgrav 		pam_syslog("pam_open_session()");
540c60ed00aSDag-Erling Smørgrav 		bail(NO_SLEEP_EXIT, 1);
5419567ba9dSMark Murray 	}
542c60ed00aSDag-Erling Smørgrav 	pam_session_established = 1;
5439567ba9dSMark Murray 
5449567ba9dSMark Murray 	/*
5455bc9d93dSMark Murray 	 * We must fork() before setuid() because we need to call
5465bc9d93dSMark Murray 	 * pam_close_session() as root.
5475bc9d93dSMark Murray 	 */
5485bc9d93dSMark Murray 	pid = fork();
5495bc9d93dSMark Murray 	if (pid < 0) {
5505bc9d93dSMark Murray 		err(1, "fork");
551c60ed00aSDag-Erling Smørgrav 	} else if (pid != 0) {
552c60ed00aSDag-Erling Smørgrav 		/*
553c60ed00aSDag-Erling Smørgrav 		 * Parent: wait for child to finish, then clean up
554c60ed00aSDag-Erling Smørgrav 		 * session.
5552482c270SJilles Tjoelker 		 *
5562482c270SJilles Tjoelker 		 * If we get SIGHUP or SIGTERM, clean up the session
5572482c270SJilles Tjoelker 		 * and exit right away. This will make the terminal
5582482c270SJilles Tjoelker 		 * inaccessible and send SIGHUP to the foreground
5592482c270SJilles Tjoelker 		 * process group.
560c60ed00aSDag-Erling Smørgrav 		 */
561fea1e414SDag-Erling Smørgrav 		int status;
5622517862eSDag-Erling Smørgrav 		setproctitle("-%s [pam]", getprogname());
5632482c270SJilles Tjoelker 		(void)sigprocmask(SIG_SETMASK, &omask, NULL);
564fea1e414SDag-Erling Smørgrav 		waitpid(pid, &status, 0);
5652482c270SJilles Tjoelker 		(void)sigprocmask(SIG_BLOCK, &mask, NULL);
566c60ed00aSDag-Erling Smørgrav 		bail(NO_SLEEP_EXIT, 0);
5675bc9d93dSMark Murray 	}
56817ada684SJacques Vidrine 
569a52c1be6SDavid Nugent 	/*
570c60ed00aSDag-Erling Smørgrav 	 * NOTICE: We are now in the child process!
571c60ed00aSDag-Erling Smørgrav 	 */
572c60ed00aSDag-Erling Smørgrav 
573c60ed00aSDag-Erling Smørgrav 	/*
574c60ed00aSDag-Erling Smørgrav 	 * Add any environment variables the PAM modules may have set.
575c60ed00aSDag-Erling Smørgrav 	 */
576c60ed00aSDag-Erling Smørgrav 	export_pam_environment();
577c60ed00aSDag-Erling Smørgrav 
578c60ed00aSDag-Erling Smørgrav 	/*
579c60ed00aSDag-Erling Smørgrav 	 * We're done with PAM now; our parent will deal with the rest.
580c60ed00aSDag-Erling Smørgrav 	 */
581519b6a4cSDag-Erling Smørgrav 	pam_end(pamh, 0);
582c60ed00aSDag-Erling Smørgrav 	pamh = NULL;
583c60ed00aSDag-Erling Smørgrav 
584c60ed00aSDag-Erling Smørgrav 	/*
585c60ed00aSDag-Erling Smørgrav 	 * We don't need to be root anymore, so set the login name and
586c60ed00aSDag-Erling Smørgrav 	 * the UID.
5876acc486bSDavid Nugent 	 */
588e8334816SJohn Polstra 	if (setlogin(username) != 0) {
589e8334816SJohn Polstra 		syslog(LOG_ERR, "setlogin(%s): %m - exiting", username);
590c60ed00aSDag-Erling Smørgrav 		bail(NO_SLEEP_EXIT, 1);
591e8334816SJohn Polstra 	}
592e8334816SJohn Polstra 	if (setusercontext(lc, pwd, pwd->pw_uid,
5935bc9d93dSMark Murray 	    LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) {
5946acc486bSDavid Nugent 		syslog(LOG_ERR, "setusercontext() failed - exiting");
5956acc486bSDavid Nugent 		exit(1);
596c9bdc152SPaul Traina 	}
5976acc486bSDavid Nugent 
5987adec208SAndrey A. Chernov 	(void)setenv("SHELL", pwd->pw_shell, 1);
5996acc486bSDavid Nugent 	(void)setenv("HOME", pwd->pw_dir, 1);
60079a20d3bSAndrey A. Chernov 	/* Overwrite "term" from login.conf(5) for any known TERM */
60155f0377cSAndrey A. Chernov 	if (term == NULL && (tp = stypeof(tty)) != NULL)
60279a20d3bSAndrey A. Chernov 		(void)setenv("TERM", tp, 1);
60379a20d3bSAndrey A. Chernov 	else
60479a20d3bSAndrey A. Chernov 		(void)setenv("TERM", TERM_UNKNOWN, 0);
605e8334816SJohn Polstra 	(void)setenv("LOGNAME", username, 1);
606e8334816SJohn Polstra 	(void)setenv("USER", username, 1);
6076acc486bSDavid Nugent 	(void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
608c9bdc152SPaul Traina 
609a52c1be6SDavid Nugent 	if (!quietlog) {
610f2f306b6SRuslan Ermilov 		const char *cw;
611a52c1be6SDavid Nugent 
6126acc486bSDavid Nugent 		cw = login_getcapstr(lc, "welcome", NULL, NULL);
613c60ed00aSDag-Erling Smørgrav 		if (cw != NULL && access(cw, F_OK) == 0)
6146acc486bSDavid Nugent 			motd(cw);
615c60ed00aSDag-Erling Smørgrav 		else
616c60ed00aSDag-Erling Smørgrav 			motd(_PATH_MOTDFILE);
617a52c1be6SDavid Nugent 
61842dc3715SMaxim Konovalov 		if (login_getcapbool(lc_user, "nocheckmail", 0) == 0 &&
61942dc3715SMaxim Konovalov 		    login_getcapbool(lc, "nocheckmail", 0) == 0) {
62081b4504bSDavid Malone 			char *cx;
62181b4504bSDavid Malone 
6220e80e8b2SRobert Watson 			/* $MAIL may have been set by class. */
62381b4504bSDavid Malone 			cx = getenv("MAIL");
62481b4504bSDavid Malone 			if (cx == NULL) {
62581b4504bSDavid Malone 				asprintf(&cx, "%s/%s",
6260e80e8b2SRobert Watson 				    _PATH_MAILDIR, pwd->pw_name);
627c60ed00aSDag-Erling Smørgrav 			}
62881b4504bSDavid Malone 			if (cx && stat(cx, &st) == 0 && st.st_size != 0)
629a52c1be6SDavid Nugent 				(void)printf("You have %smail.\n",
630a52c1be6SDavid Nugent 				    (st.st_mtime > st.st_atime) ? "new " : "");
631c60ed00aSDag-Erling Smørgrav 			if (getenv("MAIL") == NULL)
63281b4504bSDavid Malone 				free(cx);
6339b50d902SRodney W. Grimes 		}
6340e80e8b2SRobert Watson 	}
6359b50d902SRodney W. Grimes 
63642dc3715SMaxim Konovalov 	login_close(lc_user);
6376acc486bSDavid Nugent 	login_close(lc);
638c9bdc152SPaul Traina 
6392482c270SJilles Tjoelker 	sa.sa_handler = SIG_DFL;
6402482c270SJilles Tjoelker 	(void)sigaction(SIGALRM, &sa, NULL);
6412482c270SJilles Tjoelker 	(void)sigaction(SIGQUIT, &sa, NULL);
6422482c270SJilles Tjoelker 	(void)sigaction(SIGINT, &sa, NULL);
6432482c270SJilles Tjoelker 	(void)sigaction(SIGTERM, &sa, NULL);
6442482c270SJilles Tjoelker 	(void)sigaction(SIGHUP, &sa, NULL);
6452482c270SJilles Tjoelker 	sa.sa_handler = SIG_IGN;
6462482c270SJilles Tjoelker 	(void)sigaction(SIGTSTP, &sa, NULL);
6472482c270SJilles Tjoelker 	(void)sigprocmask(SIG_SETMASK, &omask, NULL);
6489b50d902SRodney W. Grimes 
649a52c1be6SDavid Nugent 	/*
650a52c1be6SDavid Nugent 	 * Login shells have a leading '-' in front of argv[0]
651a52c1be6SDavid Nugent 	 */
652c60ed00aSDag-Erling Smørgrav 	p = strrchr(pwd->pw_shell, '/');
653c60ed00aSDag-Erling Smørgrav 	if (asprintf(&arg0, "-%s", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) {
6549ab4f412SMike Barcroft 		syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size",
6559ab4f412SMike Barcroft 		    username);
6569ab4f412SMike Barcroft 		errx(1, "shell exceeds maximum pathname size");
657c60ed00aSDag-Erling Smørgrav 	} else if (arg0 == NULL) {
658c60ed00aSDag-Erling Smørgrav 		err(1, "asprintf()");
6599ab4f412SMike Barcroft 	}
660a52c1be6SDavid Nugent 
661c60ed00aSDag-Erling Smørgrav 	execlp(shell, arg0, (char *)0);
6626acc486bSDavid Nugent 	err(1, "%s", shell);
663c60ed00aSDag-Erling Smørgrav 
664c60ed00aSDag-Erling Smørgrav 	/*
665c60ed00aSDag-Erling Smørgrav 	 * That's it, folks!
666c60ed00aSDag-Erling Smørgrav 	 */
6679b50d902SRodney W. Grimes }
6689b50d902SRodney W. Grimes 
669e8334816SJohn Polstra /*
670e8334816SJohn Polstra  * Attempt to authenticate the user using PAM.  Returns 0 if the user is
671e8334816SJohn Polstra  * authenticated, or 1 if not authenticated.  If some sort of PAM system
672e8334816SJohn Polstra  * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
673e8334816SJohn Polstra  * function returns -1.  This can be used as an indication that we should
674e8334816SJohn Polstra  * fall back to a different authentication mechanism.
675e8334816SJohn Polstra  */
676e8334816SJohn Polstra static int
auth_pam(void)677c60ed00aSDag-Erling Smørgrav auth_pam(void)
678e8334816SJohn Polstra {
679e8334816SJohn Polstra 	const char *tmpl_user;
680e8334816SJohn Polstra 	const void *item;
681e8334816SJohn Polstra 	int rval;
682e8334816SJohn Polstra 
683c60ed00aSDag-Erling Smørgrav 	pam_err = pam_authenticate(pamh, pam_silent);
684c60ed00aSDag-Erling Smørgrav 	switch (pam_err) {
685e8334816SJohn Polstra 
686e8334816SJohn Polstra 	case PAM_SUCCESS:
687e8334816SJohn Polstra 		/*
688e8334816SJohn Polstra 		 * With PAM we support the concept of a "template"
689e8334816SJohn Polstra 		 * user.  The user enters a login name which is
690e8334816SJohn Polstra 		 * authenticated by PAM, usually via a remote service
691e8334816SJohn Polstra 		 * such as RADIUS or TACACS+.  If authentication
692e8334816SJohn Polstra 		 * succeeds, a different but related "template" name
693e8334816SJohn Polstra 		 * is used for setting the credentials, shell, and
694e8334816SJohn Polstra 		 * home directory.  The name the user enters need only
695e8334816SJohn Polstra 		 * exist on the remote authentication server, but the
696e8334816SJohn Polstra 		 * template name must be present in the local password
697e8334816SJohn Polstra 		 * database.
698e8334816SJohn Polstra 		 *
699e8334816SJohn Polstra 		 * This is supported by two various mechanisms in the
700e8334816SJohn Polstra 		 * individual modules.  However, from the application's
701e8334816SJohn Polstra 		 * point of view, the template user is always passed
702e8334816SJohn Polstra 		 * back as a changed value of the PAM_USER item.
703e8334816SJohn Polstra 		 */
704c60ed00aSDag-Erling Smørgrav 		pam_err = pam_get_item(pamh, PAM_USER, &item);
705c60ed00aSDag-Erling Smørgrav 		if (pam_err == PAM_SUCCESS) {
706e8334816SJohn Polstra 			tmpl_user = (const char *)item;
707*1e25eb28SDag-Erling Smørgrav 			if (strcmp(username, tmpl_user) != 0) {
708*1e25eb28SDag-Erling Smørgrav 				(void)getpwnam_r(tmpl_user, &pwres, pwbuf,
709*1e25eb28SDag-Erling Smørgrav 				    sizeof(pwbuf), &pwd);
710*1e25eb28SDag-Erling Smørgrav 			}
711c60ed00aSDag-Erling Smørgrav 		} else {
712c60ed00aSDag-Erling Smørgrav 			pam_syslog("pam_get_item(PAM_USER)");
713c60ed00aSDag-Erling Smørgrav 		}
714e8334816SJohn Polstra 		rval = 0;
715e8334816SJohn Polstra 		break;
716e8334816SJohn Polstra 
717e8334816SJohn Polstra 	case PAM_AUTH_ERR:
718e8334816SJohn Polstra 	case PAM_USER_UNKNOWN:
719e8334816SJohn Polstra 	case PAM_MAXTRIES:
720e8334816SJohn Polstra 		rval = 1;
721e8334816SJohn Polstra 		break;
722e8334816SJohn Polstra 
723e8334816SJohn Polstra 	default:
724c60ed00aSDag-Erling Smørgrav 		pam_syslog("pam_authenticate()");
725e8334816SJohn Polstra 		rval = -1;
726e8334816SJohn Polstra 		break;
727e8334816SJohn Polstra 	}
7285bc9d93dSMark Murray 
7295bc9d93dSMark Murray 	if (rval == 0) {
730c60ed00aSDag-Erling Smørgrav 		pam_err = pam_acct_mgmt(pamh, pam_silent);
731c60ed00aSDag-Erling Smørgrav 		switch (pam_err) {
732c60ed00aSDag-Erling Smørgrav 		case PAM_SUCCESS:
733c60ed00aSDag-Erling Smørgrav 			break;
734c60ed00aSDag-Erling Smørgrav 		case PAM_NEW_AUTHTOK_REQD:
735c60ed00aSDag-Erling Smørgrav 			pam_err = pam_chauthtok(pamh,
736c60ed00aSDag-Erling Smørgrav 			    pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK);
737c60ed00aSDag-Erling Smørgrav 			if (pam_err != PAM_SUCCESS) {
738c60ed00aSDag-Erling Smørgrav 				pam_syslog("pam_chauthtok()");
7395bc9d93dSMark Murray 				rval = 1;
7405bc9d93dSMark Murray 			}
741c60ed00aSDag-Erling Smørgrav 			break;
742c60ed00aSDag-Erling Smørgrav 		default:
743c60ed00aSDag-Erling Smørgrav 			pam_syslog("pam_acct_mgmt()");
7445bc9d93dSMark Murray 			rval = 1;
745c60ed00aSDag-Erling Smørgrav 			break;
7465bc9d93dSMark Murray 		}
7475bc9d93dSMark Murray 	}
7485bc9d93dSMark Murray 
7495bc9d93dSMark Murray 	if (rval != 0) {
750c60ed00aSDag-Erling Smørgrav 		pam_end(pamh, pam_err);
7515bc9d93dSMark Murray 		pamh = NULL;
752e8334816SJohn Polstra 	}
753c60ed00aSDag-Erling Smørgrav 	return (rval);
75417ada684SJacques Vidrine }
75517ada684SJacques Vidrine 
75617ada684SJacques Vidrine /*
757c60ed00aSDag-Erling Smørgrav  * Export any environment variables PAM modules may have set
758c60ed00aSDag-Erling Smørgrav  */
759c60ed00aSDag-Erling Smørgrav static void
export_pam_environment(void)760ef636796SEd Schouten export_pam_environment(void)
761c60ed00aSDag-Erling Smørgrav {
762c60ed00aSDag-Erling Smørgrav 	char **pam_env;
763c60ed00aSDag-Erling Smørgrav 	char **pp;
764c60ed00aSDag-Erling Smørgrav 
765c60ed00aSDag-Erling Smørgrav 	pam_env = pam_getenvlist(pamh);
766c60ed00aSDag-Erling Smørgrav 	if (pam_env != NULL) {
767c60ed00aSDag-Erling Smørgrav 		for (pp = pam_env; *pp != NULL; pp++) {
768ba174a5eSAndrey A. Chernov 			(void)export(*pp);
7698673ed15SAndrey A. Chernov 			free(*pp);
770c60ed00aSDag-Erling Smørgrav 		}
771c60ed00aSDag-Erling Smørgrav 	}
772c60ed00aSDag-Erling Smørgrav }
773c60ed00aSDag-Erling Smørgrav 
774c60ed00aSDag-Erling Smørgrav /*
775c60ed00aSDag-Erling Smørgrav  * Perform sanity checks on an environment variable:
77617ada684SJacques Vidrine  * - Make sure there is an '=' in the string.
77717ada684SJacques Vidrine  * - Make sure the string doesn't run on too long.
77817ada684SJacques Vidrine  * - Do not export certain variables.  This list was taken from the
77917ada684SJacques Vidrine  *   Solaris pam_putenv(3) man page.
780c60ed00aSDag-Erling Smørgrav  * Then export it.
78117ada684SJacques Vidrine  */
78217ada684SJacques Vidrine static int
export(const char * s)783c60ed00aSDag-Erling Smørgrav export(const char *s)
78417ada684SJacques Vidrine {
78517ada684SJacques Vidrine 	static const char *noexport[] = {
78617ada684SJacques Vidrine 		"SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
78717ada684SJacques Vidrine 		"IFS", "PATH", NULL
78817ada684SJacques Vidrine 	};
7892966d28cSSean Farley 	char *p;
79017ada684SJacques Vidrine 	const char **pp;
79117ada684SJacques Vidrine 	size_t n;
792dcc6f625SPedro F. Giffuni 	int rv;
79317ada684SJacques Vidrine 
7942966d28cSSean Farley 	if (strlen(s) > 1024 || (p = strchr(s, '=')) == NULL)
795c60ed00aSDag-Erling Smørgrav 		return (0);
79617ada684SJacques Vidrine 	if (strncmp(s, "LD_", 3) == 0)
797c60ed00aSDag-Erling Smørgrav 		return (0);
79817ada684SJacques Vidrine 	for (pp = noexport; *pp != NULL; pp++) {
79917ada684SJacques Vidrine 		n = strlen(*pp);
80017ada684SJacques Vidrine 		if (s[n] == '=' && strncmp(s, *pp, n) == 0)
801c60ed00aSDag-Erling Smørgrav 			return (0);
80217ada684SJacques Vidrine 	}
8032966d28cSSean Farley 	*p = '\0';
804dcc6f625SPedro F. Giffuni 	rv = setenv(s, p + 1, 1);
8052966d28cSSean Farley 	*p = '=';
806dcc6f625SPedro F. Giffuni 	if (rv == -1)
807dcc6f625SPedro F. Giffuni 		return (0);
808c60ed00aSDag-Erling Smørgrav 	return (1);
80917ada684SJacques Vidrine }
810e8334816SJohn Polstra 
8119c9cb2bfSPhilippe Charnier static void
usage(void)812ef636796SEd Schouten usage(void)
8139c9cb2bfSPhilippe Charnier {
8145de20e57SDavid E. O'Brien 
8159c9cb2bfSPhilippe Charnier 	(void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n");
8169c9cb2bfSPhilippe Charnier 	exit(1);
8179c9cb2bfSPhilippe Charnier }
8186acc486bSDavid Nugent 
819a52c1be6SDavid Nugent /*
820c60ed00aSDag-Erling Smørgrav  * Prompt user and read login name from stdin.
8215bc9d93dSMark Murray  */
822c60ed00aSDag-Erling Smørgrav static char *
getloginname(void)823ef636796SEd Schouten getloginname(void)
8249b50d902SRodney W. Grimes {
825c60ed00aSDag-Erling Smørgrav 	char *nbuf, *p;
8269b50d902SRodney W. Grimes 	int ch;
8279b50d902SRodney W. Grimes 
828c60ed00aSDag-Erling Smørgrav 	nbuf = malloc(MAXLOGNAME);
829c60ed00aSDag-Erling Smørgrav 	if (nbuf == NULL)
830c60ed00aSDag-Erling Smørgrav 		err(1, "malloc()");
831c60ed00aSDag-Erling Smørgrav 	do {
8329ab4f412SMike Barcroft 		(void)printf("%s", prompt);
8339b50d902SRodney W. Grimes 		for (p = nbuf; (ch = getchar()) != '\n'; ) {
8349b50d902SRodney W. Grimes 			if (ch == EOF) {
8359b50d902SRodney W. Grimes 				badlogin(username);
836c60ed00aSDag-Erling Smørgrav 				bail(NO_SLEEP_EXIT, 0);
8379b50d902SRodney W. Grimes 			}
838c60ed00aSDag-Erling Smørgrav 			if (p < nbuf + MAXLOGNAME - 1)
8399b50d902SRodney W. Grimes 				*p++ = ch;
8409b50d902SRodney W. Grimes 		}
841c60ed00aSDag-Erling Smørgrav 	} while (p == nbuf);
842c60ed00aSDag-Erling Smørgrav 
8439b50d902SRodney W. Grimes 	*p = '\0';
844c60ed00aSDag-Erling Smørgrav 	if (nbuf[0] == '-') {
845c60ed00aSDag-Erling Smørgrav 		pam_silent = 0;
846c60ed00aSDag-Erling Smørgrav 		memmove(nbuf, nbuf + 1, strlen(nbuf));
847c60ed00aSDag-Erling Smørgrav 	} else {
848c60ed00aSDag-Erling Smørgrav 		pam_silent = PAM_SILENT;
8499b50d902SRodney W. Grimes 	}
850c60ed00aSDag-Erling Smørgrav 	return nbuf;
85169f2cf17SSheldon Hearn }
8529b50d902SRodney W. Grimes 
853c60ed00aSDag-Erling Smørgrav /*
854c60ed00aSDag-Erling Smørgrav  * SIGINT handler for motd().
855c60ed00aSDag-Erling Smørgrav  */
856c60ed00aSDag-Erling Smørgrav static volatile int motdinterrupt;
857c60ed00aSDag-Erling Smørgrav static void
sigint(int signo __unused)858c60ed00aSDag-Erling Smørgrav sigint(int signo __unused)
8596acc486bSDavid Nugent {
8606acc486bSDavid Nugent 	motdinterrupt = 1;
8616acc486bSDavid Nugent }
8629b50d902SRodney W. Grimes 
863c60ed00aSDag-Erling Smørgrav /*
864c60ed00aSDag-Erling Smørgrav  * Display the contents of a file (such as /etc/motd).
865c60ed00aSDag-Erling Smørgrav  */
866c60ed00aSDag-Erling Smørgrav static int
motd(const char * motdfile)867c60ed00aSDag-Erling Smørgrav motd(const char *motdfile)
8689b50d902SRodney W. Grimes {
8692482c270SJilles Tjoelker 	struct sigaction newint, oldint;
870c60ed00aSDag-Erling Smørgrav 	FILE *f;
871c60ed00aSDag-Erling Smørgrav 	int ch;
8729b50d902SRodney W. Grimes 
873c60ed00aSDag-Erling Smørgrav 	if ((f = fopen(motdfile, "r")) == NULL)
874c60ed00aSDag-Erling Smørgrav 		return (-1);
8756acc486bSDavid Nugent 	motdinterrupt = 0;
8762482c270SJilles Tjoelker 	newint.sa_handler = sigint;
8772482c270SJilles Tjoelker 	newint.sa_flags = 0;
8782482c270SJilles Tjoelker 	sigfillset(&newint.sa_mask);
8792482c270SJilles Tjoelker 	sigaction(SIGINT, &newint, &oldint);
880c60ed00aSDag-Erling Smørgrav 	while ((ch = fgetc(f)) != EOF && !motdinterrupt)
881c60ed00aSDag-Erling Smørgrav 		putchar(ch);
8822482c270SJilles Tjoelker 	sigaction(SIGINT, &oldint, NULL);
883c60ed00aSDag-Erling Smørgrav 	if (ch != EOF || ferror(f)) {
884c60ed00aSDag-Erling Smørgrav 		fclose(f);
885c60ed00aSDag-Erling Smørgrav 		return (-1);
886c60ed00aSDag-Erling Smørgrav 	}
887c60ed00aSDag-Erling Smørgrav 	fclose(f);
888c60ed00aSDag-Erling Smørgrav 	return (0);
8899b50d902SRodney W. Grimes }
8909b50d902SRodney W. Grimes 
891c60ed00aSDag-Erling Smørgrav /*
892c60ed00aSDag-Erling Smørgrav  * SIGALRM handler, to enforce login prompt timeout.
893c60ed00aSDag-Erling Smørgrav  *
894c60ed00aSDag-Erling Smørgrav  * XXX This can potentially confuse the hell out of PAM.  We should
895c60ed00aSDag-Erling Smørgrav  * XXX instead implement a conversation function that returns
896c60ed00aSDag-Erling Smørgrav  * XXX PAM_CONV_ERR when interrupted by a signal, and have the signal
897c60ed00aSDag-Erling Smørgrav  * XXX handler just set a flag.
898c60ed00aSDag-Erling Smørgrav  */
899c60ed00aSDag-Erling Smørgrav static void
timedout(int signo __unused)900c60ed00aSDag-Erling Smørgrav timedout(int signo __unused)
9019b50d902SRodney W. Grimes {
90291a72a92SDavid E. O'Brien 
903b606e33cSEivind Eklund 	longjmp(timeout_buf, signo);
9049b50d902SRodney W. Grimes }
9059b50d902SRodney W. Grimes 
9060845b8faSPoul-Henning Kamp static void
badlogin(char * name)907c60ed00aSDag-Erling Smørgrav badlogin(char *name)
9089b50d902SRodney W. Grimes {
9099b50d902SRodney W. Grimes 
9109b50d902SRodney W. Grimes 	if (failures == 0)
9119b50d902SRodney W. Grimes 		return;
912c60ed00aSDag-Erling Smørgrav 	if (hflag) {
9139b50d902SRodney W. Grimes 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
914c60ed00aSDag-Erling Smørgrav 		    failures, failures > 1 ? "S" : "", hostname);
9159b50d902SRodney W. Grimes 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
9169b50d902SRodney W. Grimes 		    "%d LOGIN FAILURE%s FROM %s, %s",
917c60ed00aSDag-Erling Smørgrav 		    failures, failures > 1 ? "S" : "", hostname, name);
9189b50d902SRodney W. Grimes 	} else {
9199b50d902SRodney W. Grimes 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
9209b50d902SRodney W. Grimes 		    failures, failures > 1 ? "S" : "", tty);
9219b50d902SRodney W. Grimes 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
9229b50d902SRodney W. Grimes 		    "%d LOGIN FAILURE%s ON %s, %s",
9239b50d902SRodney W. Grimes 		    failures, failures > 1 ? "S" : "", tty, name);
9249b50d902SRodney W. Grimes 	}
925b606e33cSEivind Eklund 	failures = 0;
9269b50d902SRodney W. Grimes }
9279b50d902SRodney W. Grimes 
928e317b970SMark Murray const char *
stypeof(char * ttyid)929c60ed00aSDag-Erling Smørgrav stypeof(char *ttyid)
9309b50d902SRodney W. Grimes {
9319b50d902SRodney W. Grimes 	struct ttyent *t;
932a52c1be6SDavid Nugent 
9339ab4f412SMike Barcroft 	if (ttyid != NULL && *ttyid != '\0') {
9349ab4f412SMike Barcroft 		t = getttynam(ttyid);
9359ab4f412SMike Barcroft 		if (t != NULL && t->ty_type != NULL)
9369ab4f412SMike Barcroft 			return (t->ty_type);
9379ab4f412SMike Barcroft 	}
93879a20d3bSAndrey A. Chernov 	return (NULL);
9399b50d902SRodney W. Grimes }
9409b50d902SRodney W. Grimes 
9410845b8faSPoul-Henning Kamp static void
refused(const char * msg,const char * rtype,int lout)942c60ed00aSDag-Erling Smørgrav refused(const char *msg, const char *rtype, int lout)
943a52c1be6SDavid Nugent {
944a52c1be6SDavid Nugent 
945a52c1be6SDavid Nugent 	if (msg != NULL)
946a52c1be6SDavid Nugent 	    printf("%s.\n", msg);
947c60ed00aSDag-Erling Smørgrav 	if (hflag)
948a52c1be6SDavid Nugent 		syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
949c60ed00aSDag-Erling Smørgrav 		    pwd->pw_name, rtype, hostname, tty);
950a52c1be6SDavid Nugent 	else
951a52c1be6SDavid Nugent 		syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
952a52c1be6SDavid Nugent 		    pwd->pw_name, rtype, tty);
953a52c1be6SDavid Nugent 	if (lout)
954c60ed00aSDag-Erling Smørgrav 		bail(SLEEP_EXIT, 1);
955a52c1be6SDavid Nugent }
956a52c1be6SDavid Nugent 
957c60ed00aSDag-Erling Smørgrav /*
958c60ed00aSDag-Erling Smørgrav  * Log a PAM error
959c60ed00aSDag-Erling Smørgrav  */
9600845b8faSPoul-Henning Kamp static void
pam_syslog(const char * msg)961c60ed00aSDag-Erling Smørgrav pam_syslog(const char *msg)
962c60ed00aSDag-Erling Smørgrav {
963c60ed00aSDag-Erling Smørgrav 	syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err));
964c60ed00aSDag-Erling Smørgrav }
965c60ed00aSDag-Erling Smørgrav 
966c60ed00aSDag-Erling Smørgrav /*
967c60ed00aSDag-Erling Smørgrav  * Shut down PAM
968c60ed00aSDag-Erling Smørgrav  */
9690845b8faSPoul-Henning Kamp static void
pam_cleanup(void)970ef636796SEd Schouten pam_cleanup(void)
9719b50d902SRodney W. Grimes {
972a52c1be6SDavid Nugent 
973c60ed00aSDag-Erling Smørgrav 	if (pamh != NULL) {
974c60ed00aSDag-Erling Smørgrav 		if (pam_session_established) {
975c60ed00aSDag-Erling Smørgrav 			pam_err = pam_close_session(pamh, 0);
976c60ed00aSDag-Erling Smørgrav 			if (pam_err != PAM_SUCCESS)
977c60ed00aSDag-Erling Smørgrav 				pam_syslog("pam_close_session()");
978c60ed00aSDag-Erling Smørgrav 		}
979c60ed00aSDag-Erling Smørgrav 		pam_session_established = 0;
980c60ed00aSDag-Erling Smørgrav 		if (pam_cred_established) {
981c60ed00aSDag-Erling Smørgrav 			pam_err = pam_setcred(pamh, pam_silent|PAM_DELETE_CRED);
982c60ed00aSDag-Erling Smørgrav 			if (pam_err != PAM_SUCCESS)
983c60ed00aSDag-Erling Smørgrav 				pam_syslog("pam_setcred()");
984c60ed00aSDag-Erling Smørgrav 		}
985c60ed00aSDag-Erling Smørgrav 		pam_cred_established = 0;
986c60ed00aSDag-Erling Smørgrav 		pam_end(pamh, pam_err);
987c60ed00aSDag-Erling Smørgrav 		pamh = NULL;
988c60ed00aSDag-Erling Smørgrav 	}
989c60ed00aSDag-Erling Smørgrav }
990c60ed00aSDag-Erling Smørgrav 
9912482c270SJilles Tjoelker static void
bail_internal(int sec,int eval,int signo)9922482c270SJilles Tjoelker bail_internal(int sec, int eval, int signo)
993c60ed00aSDag-Erling Smørgrav {
9942482c270SJilles Tjoelker 	struct sigaction sa;
995c60ed00aSDag-Erling Smørgrav 
996c60ed00aSDag-Erling Smørgrav 	pam_cleanup();
9970c59c145SChristian S.J. Peron #ifdef USE_BSM_AUDIT
9988f9370b0SOlivier Houchard 	if (pwd != NULL)
999a1c73d21SWayne Salamon 		audit_logout();
10000c59c145SChristian S.J. Peron #endif
1001c60ed00aSDag-Erling Smørgrav 	(void)sleep(sec);
10022482c270SJilles Tjoelker 	if (signo == 0)
10039b50d902SRodney W. Grimes 		exit(eval);
10042482c270SJilles Tjoelker 	else {
10052482c270SJilles Tjoelker 		sa.sa_handler = SIG_DFL;
10062482c270SJilles Tjoelker 		sa.sa_flags = 0;
10072482c270SJilles Tjoelker 		(void)sigemptyset(&sa.sa_mask);
10082482c270SJilles Tjoelker 		(void)sigaction(signo, &sa, NULL);
10092482c270SJilles Tjoelker 		(void)sigaddset(&sa.sa_mask, signo);
10102482c270SJilles Tjoelker 		(void)sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
10112482c270SJilles Tjoelker 		raise(signo);
10122482c270SJilles Tjoelker 		exit(128 + signo);
10132482c270SJilles Tjoelker 	}
10142482c270SJilles Tjoelker }
10152482c270SJilles Tjoelker 
10162482c270SJilles Tjoelker /*
10172482c270SJilles Tjoelker  * Exit, optionally after sleeping a few seconds
10182482c270SJilles Tjoelker  */
10192482c270SJilles Tjoelker static void
bail(int sec,int eval)10202482c270SJilles Tjoelker bail(int sec, int eval)
10212482c270SJilles Tjoelker {
10222482c270SJilles Tjoelker 	bail_internal(sec, eval, 0);
10232482c270SJilles Tjoelker }
10242482c270SJilles Tjoelker 
10252482c270SJilles Tjoelker /*
10262482c270SJilles Tjoelker  * Exit because of a signal.
10272482c270SJilles Tjoelker  * This is not async-signal safe, so only call async-signal safe functions
10282482c270SJilles Tjoelker  * while the signal is unmasked.
10292482c270SJilles Tjoelker  */
10302482c270SJilles Tjoelker static void
bail_sig(int signo)10312482c270SJilles Tjoelker bail_sig(int signo)
10322482c270SJilles Tjoelker {
10332482c270SJilles Tjoelker 	bail_internal(NO_SLEEP_EXIT, 0, signo);
10349b50d902SRodney W. Grimes }
1035