Home | History | Annotate | Line # | Download | only in login
login_pam.c revision 1.4.2.4.2.2
      1  1.4.2.4.2.1      tron /*     $NetBSD: login_pam.c,v 1.4.2.4.2.2 2006/03/10 13:28:24 tron Exp $       */
      2          1.1      manu 
      3          1.1      manu /*-
      4          1.1      manu  * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
      5          1.1      manu  *	The Regents of the University of California.  All rights reserved.
      6          1.1      manu  *
      7          1.1      manu  * Redistribution and use in source and binary forms, with or without
      8          1.1      manu  * modification, are permitted provided that the following conditions
      9          1.1      manu  * are met:
     10          1.1      manu  * 1. Redistributions of source code must retain the above copyright
     11          1.1      manu  *    notice, this list of conditions and the following disclaimer.
     12          1.1      manu  * 2. Redistributions in binary form must reproduce the above copyright
     13          1.1      manu  *    notice, this list of conditions and the following disclaimer in the
     14          1.1      manu  *    documentation and/or other materials provided with the distribution.
     15          1.1      manu  * 3. Neither the name of the University nor the names of its contributors
     16          1.1      manu  *    may be used to endorse or promote products derived from this software
     17          1.1      manu  *    without specific prior written permission.
     18          1.1      manu  *
     19          1.1      manu  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20          1.1      manu  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21          1.1      manu  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22          1.1      manu  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23          1.1      manu  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24          1.1      manu  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25          1.1      manu  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26          1.1      manu  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27          1.1      manu  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28          1.1      manu  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29          1.1      manu  * SUCH DAMAGE.
     30          1.1      manu  */
     31          1.1      manu 
     32          1.1      manu #include <sys/cdefs.h>
     33          1.1      manu #ifndef lint
     34          1.1      manu __COPYRIGHT(
     35          1.1      manu "@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\
     36          1.1      manu 	The Regents of the University of California.  All rights reserved.\n");
     37          1.1      manu #endif /* not lint */
     38          1.1      manu 
     39          1.1      manu #ifndef lint
     40          1.1      manu #if 0
     41          1.1      manu static char sccsid[] = "@(#)login.c	8.4 (Berkeley) 4/2/94";
     42          1.1      manu #endif
     43  1.4.2.4.2.1      tron __RCSID("$NetBSD: login_pam.c,v 1.4.2.4.2.2 2006/03/10 13:28:24 tron Exp $");
     44          1.1      manu #endif /* not lint */
     45          1.1      manu 
     46          1.1      manu /*
     47          1.1      manu  * login [ name ]
     48          1.1      manu  * login -h hostname	(for telnetd, etc.)
     49          1.1      manu  * login -f name	(for pre-authenticated login: datakit, xterm, etc.)
     50          1.1      manu  */
     51          1.1      manu 
     52          1.1      manu #include <sys/param.h>
     53          1.1      manu #include <sys/stat.h>
     54          1.1      manu #include <sys/time.h>
     55          1.1      manu #include <sys/resource.h>
     56          1.1      manu #include <sys/file.h>
     57          1.1      manu #include <sys/wait.h>
     58          1.1      manu #include <sys/socket.h>
     59          1.1      manu 
     60          1.1      manu #include <err.h>
     61          1.1      manu #include <errno.h>
     62          1.1      manu #include <grp.h>
     63          1.1      manu #include <pwd.h>
     64          1.1      manu #include <setjmp.h>
     65          1.1      manu #include <signal.h>
     66          1.1      manu #include <stdio.h>
     67          1.1      manu #include <stdlib.h>
     68          1.1      manu #include <string.h>
     69          1.1      manu #include <syslog.h>
     70          1.1      manu #include <time.h>
     71          1.1      manu #include <ttyent.h>
     72          1.1      manu #include <tzfile.h>
     73          1.1      manu #include <unistd.h>
     74          1.1      manu #include <util.h>
     75          1.1      manu #include <login_cap.h>
     76          1.1      manu #include <vis.h>
     77          1.1      manu 
     78          1.1      manu #include <security/pam_appl.h>
     79          1.1      manu #include <security/openpam.h>
     80          1.1      manu 
     81          1.1      manu #include "pathnames.h"
     82          1.1      manu 
     83          1.1      manu void	 badlogin (char *);
     84          1.1      manu static void	 update_db (int);
     85          1.1      manu void	 getloginname (void);
     86          1.1      manu int	 main (int, char *[]);
     87          1.1      manu void	 motd (char *);
     88          1.1      manu int	 rootterm (char *);
     89          1.1      manu void	 sigint (int);
     90          1.1      manu void	 sleepexit (int);
     91          1.1      manu const	 char *stypeof (const char *);
     92          1.1      manu void	 timedout (int);
     93          1.1      manu void	 decode_ss (const char *);
     94          1.1      manu void	 usage (void);
     95          1.1      manu 
     96          1.1      manu static struct pam_conv pamc = { openpam_ttyconv, NULL };
     97          1.1      manu 
     98          1.1      manu #define	TTYGRPNAME	"tty"		/* name of group to own ttys */
     99          1.1      manu 
    100          1.1      manu #define DEFAULT_BACKOFF 3
    101          1.1      manu #define DEFAULT_RETRIES 10
    102          1.1      manu 
    103          1.1      manu /*
    104          1.1      manu  * This bounds the time given to login.  Not a define so it can
    105          1.1      manu  * be patched on machines where it's too small.
    106          1.1      manu  */
    107          1.1      manu u_int	timeout = 300;
    108          1.1      manu 
    109      1.4.2.1      tron struct	passwd *pwd, pwres;
    110      1.4.2.1      tron char	pwbuf[1024];
    111          1.3  christos struct	group *gr;
    112          1.1      manu int	failures, have_ss;
    113          1.1      manu char	term[64], *envinit[1], *hostname, *username, *tty, *nested;
    114          1.1      manu struct timeval now;
    115          1.1      manu struct sockaddr_storage ss;
    116          1.1      manu 
    117          1.1      manu extern const char copyrightstr[];
    118          1.1      manu 
    119          1.1      manu int
    120          1.1      manu main(int argc, char *argv[])
    121          1.1      manu {
    122          1.1      manu 	extern char **environ;
    123          1.1      manu 	struct stat st;
    124          1.1      manu 	int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin;
    125          1.1      manu 	int auth_passed;
    126          1.1      manu 	int Fflag;
    127          1.1      manu 	uid_t uid, saved_uid;
    128          1.1      manu 	gid_t saved_gid, saved_gids[NGROUPS_MAX];
    129          1.1      manu 	int nsaved_gids;
    130          1.1      manu 	char *domain, *p, *ttyn, *pwprompt;
    131          1.1      manu 	char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
    132          1.1      manu 	char localhost[MAXHOSTNAMELEN + 1];
    133          1.1      manu 	int need_chpass, require_chpass;
    134          1.1      manu 	int login_retries = DEFAULT_RETRIES,
    135          1.1      manu 	    login_backoff = DEFAULT_BACKOFF;
    136          1.1      manu 	char *shell = NULL;
    137          1.1      manu 	login_cap_t *lc = NULL;
    138          1.1      manu 	pam_handle_t *pamh = NULL;
    139          1.1      manu 	int pam_err;
    140          1.1      manu 	void *oint;
    141          1.1      manu 	void *oabrt;
    142          1.1      manu 	const void *newuser;
    143          1.1      manu 	int pam_silent = PAM_SILENT;
    144          1.1      manu 	pid_t xpid, pid;
    145          1.1      manu 	int status;
    146          1.1      manu 	char *saved_term;
    147          1.1      manu 	char **pamenv;
    148          1.1      manu 
    149          1.1      manu 	tbuf[0] = '\0';
    150          1.1      manu 	pwprompt = NULL;
    151          1.1      manu 	nested = NULL;
    152          1.1      manu 	need_chpass = require_chpass = 0;
    153          1.1      manu 
    154          1.1      manu 	(void)signal(SIGALRM, timedout);
    155          1.1      manu 	(void)alarm(timeout);
    156          1.1      manu 	(void)signal(SIGQUIT, SIG_IGN);
    157          1.1      manu 	(void)signal(SIGINT, SIG_IGN);
    158          1.1      manu 	(void)setpriority(PRIO_PROCESS, 0, 0);
    159          1.1      manu 
    160          1.1      manu 	openlog("login", 0, LOG_AUTH);
    161          1.1      manu 
    162          1.1      manu 	/*
    163          1.1      manu 	 * -p is used by getty to tell login not to destroy the environment
    164          1.1      manu 	 * -f is used to skip a second login authentication
    165          1.1      manu 	 * -h is used by other servers to pass the name of the remote host to
    166          1.1      manu 	 *    login so that it may be placed in utmp/utmpx and wtmp/wtmpx
    167          1.1      manu 	 * -a in addition to -h, a server my supply -a to pass the actual
    168          1.1      manu 	 *    server address.
    169          1.1      manu 	 * -s is used to force use of S/Key or equivalent.
    170          1.1      manu 	 */
    171          1.1      manu 	domain = NULL;
    172          1.1      manu 	if (gethostname(localhost, sizeof(localhost)) < 0)
    173          1.1      manu 		syslog(LOG_ERR, "couldn't get local hostname: %m");
    174          1.1      manu 	else
    175          1.1      manu 		domain = strchr(localhost, '.');
    176          1.1      manu 	localhost[sizeof(localhost) - 1] = '\0';
    177          1.1      manu 
    178          1.1      manu 	Fflag = fflag = hflag = pflag = sflag = 0;
    179          1.1      manu 	have_ss = 0;
    180          1.1      manu 	uid = getuid();
    181          1.1      manu 	while ((ch = getopt(argc, argv, "a:Ffh:ps")) != -1)
    182          1.1      manu 		switch (ch) {
    183          1.1      manu 		case 'a':
    184      1.4.2.1      tron 			if (uid) {
    185      1.4.2.1      tron 				errno = EPERM;
    186      1.4.2.1      tron 				err(EXIT_FAILURE, "-a option");
    187      1.4.2.1      tron 			}
    188          1.1      manu 			decode_ss(optarg);
    189          1.3  christos #ifdef notdef
    190          1.3  christos 			(void)sockaddr_snprintf(optarg,
    191          1.3  christos 			    sizeof(struct sockaddr_storage), "%a", (void *)&ss);
    192          1.3  christos #endif
    193          1.1      manu 			break;
    194          1.1      manu 		case 'F':
    195          1.1      manu 			Fflag = 1;
    196          1.1      manu 			/* FALLTHROUGH */
    197          1.1      manu 		case 'f':
    198          1.1      manu 			fflag = 1;
    199          1.1      manu 			break;
    200          1.1      manu 		case 'h':
    201      1.4.2.1      tron 			if (uid) {
    202      1.4.2.1      tron 				errno = EPERM;
    203      1.4.2.1      tron 				err(EXIT_FAILURE, "-h option");
    204      1.4.2.1      tron 			}
    205          1.1      manu 			hflag = 1;
    206          1.1      manu 			if (domain && (p = strchr(optarg, '.')) != NULL &&
    207          1.1      manu 			    strcasecmp(p, domain) == 0)
    208          1.1      manu 				*p = '\0';
    209          1.1      manu 			hostname = optarg;
    210          1.1      manu 			break;
    211          1.1      manu 		case 'p':
    212          1.1      manu 			pflag = 1;
    213          1.1      manu 			break;
    214          1.1      manu 		case 's':
    215          1.1      manu 			sflag = 1;
    216          1.1      manu 			break;
    217          1.1      manu 		default:
    218          1.1      manu 		case '?':
    219          1.1      manu 			usage();
    220          1.1      manu 			break;
    221          1.1      manu 		}
    222          1.3  christos 
    223          1.3  christos 	setproctitle(NULL);
    224          1.1      manu 	argc -= optind;
    225          1.1      manu 	argv += optind;
    226          1.1      manu 
    227          1.1      manu 	if (*argv) {
    228          1.1      manu 		username = *argv;
    229          1.1      manu 		ask = 0;
    230          1.1      manu 	} else
    231          1.1      manu 		ask = 1;
    232          1.1      manu 
    233          1.3  christos #ifdef F_CLOSEM
    234          1.3  christos 	(void)fcntl(3, F_CLOSEM, 0);
    235          1.3  christos #else
    236          1.1      manu 	for (cnt = getdtablesize(); cnt > 2; cnt--)
    237          1.1      manu 		(void)close(cnt);
    238          1.3  christos #endif
    239          1.1      manu 
    240          1.1      manu 	ttyn = ttyname(STDIN_FILENO);
    241          1.1      manu 	if (ttyn == NULL || *ttyn == '\0') {
    242          1.1      manu 		(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
    243          1.1      manu 		ttyn = tname;
    244          1.1      manu 	}
    245          1.3  christos 	if ((tty = strstr(ttyn, "/pts/")) != NULL)
    246          1.3  christos 		++tty;
    247          1.3  christos 	else if ((tty = strrchr(ttyn, '/')) != NULL)
    248          1.1      manu 		++tty;
    249          1.1      manu 	else
    250          1.1      manu 		tty = ttyn;
    251          1.1      manu 
    252          1.1      manu 	if (issetugid()) {
    253          1.1      manu 		nested = strdup(user_from_uid(getuid(), 0));
    254          1.1      manu 		if (nested == NULL) {
    255          1.1      manu                 	syslog(LOG_ERR, "strdup: %m");
    256      1.4.2.1      tron                 	sleepexit(EXIT_FAILURE);
    257          1.1      manu 		}
    258          1.1      manu 	}
    259          1.1      manu 
    260          1.1      manu 	/* Get "login-retries" and "login-backoff" from default class */
    261          1.1      manu 	if ((lc = login_getclass(NULL)) != NULL) {
    262          1.1      manu 		login_retries = (int)login_getcapnum(lc, "login-retries",
    263          1.1      manu 		    DEFAULT_RETRIES, DEFAULT_RETRIES);
    264          1.1      manu 		login_backoff = (int)login_getcapnum(lc, "login-backoff",
    265          1.1      manu 		    DEFAULT_BACKOFF, DEFAULT_BACKOFF);
    266          1.1      manu 		login_close(lc);
    267          1.1      manu 		lc = NULL;
    268          1.1      manu 	}
    269          1.1      manu 
    270          1.1      manu 
    271          1.1      manu 	for (cnt = 0;; ask = 1) {
    272          1.1      manu 		if (ask) {
    273          1.1      manu 			fflag = 0;
    274          1.1      manu 			getloginname();
    275          1.1      manu 		}
    276          1.1      manu 		rootlogin = 0;
    277          1.1      manu 		auth_passed = 0;
    278          1.1      manu 		if (strlen(username) > MAXLOGNAME)
    279          1.1      manu 			username[MAXLOGNAME] = '\0';
    280          1.1      manu 
    281          1.1      manu 		/*
    282          1.1      manu 		 * Note if trying multiple user names; log failures for
    283          1.1      manu 		 * previous user name, but don't bother logging one failure
    284          1.1      manu 		 * for nonexistent name (mistyped username).
    285          1.1      manu 		 */
    286          1.1      manu 		if (failures && strcmp(tbuf, username)) {
    287          1.1      manu 			if (failures > (pwd ? 0 : 1))
    288          1.1      manu 				badlogin(tbuf);
    289          1.1      manu 			failures = 0;
    290          1.1      manu 		}
    291          1.1      manu 
    292          1.1      manu #define PAM_END(msg) do { 						\
    293          1.1      manu 	syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err)); 	\
    294          1.1      manu 	warnx("%s: %s", msg, pam_strerror(pamh, pam_err));		\
    295          1.1      manu 	pam_end(pamh, pam_err);						\
    296      1.4.2.1      tron 	sleepexit(EXIT_FAILURE);					\
    297          1.1      manu } while (/*CONSTCOND*/0)
    298          1.1      manu 
    299          1.1      manu 		pam_err = pam_start("login", username, &pamc, &pamh);
    300          1.1      manu 		if (pam_err != PAM_SUCCESS) {
    301          1.1      manu 			if (pamh != NULL)
    302          1.1      manu 				PAM_END("pam_start");
    303          1.1      manu 			/* Things went really bad... */
    304          1.1      manu 			syslog(LOG_ERR, "pam_start failed: %s",
    305          1.1      manu 			    pam_strerror(pamh, pam_err));
    306      1.4.2.1      tron 			errx(EXIT_FAILURE, "pam_start failed");
    307          1.1      manu 		}
    308          1.1      manu 
    309          1.1      manu #define PAM_SET_ITEM(item, var)	do {					\
    310          1.1      manu 	pam_err = pam_set_item(pamh, (item), (var));			\
    311          1.1      manu 	if (pam_err != PAM_SUCCESS)					\
    312          1.1      manu 		PAM_END("pam_set_item(" # item ")");			\
    313          1.1      manu } while (/*CONSTCOND*/0)
    314          1.1      manu 
    315          1.1      manu 		/*
    316          1.4  christos 		 * Fill hostname tty, and nested user
    317          1.1      manu 		 */
    318          1.1      manu 		PAM_SET_ITEM(PAM_RHOST, hostname);
    319          1.1      manu 		PAM_SET_ITEM(PAM_TTY, tty);
    320          1.4  christos 		if (nested)
    321          1.4  christos 			PAM_SET_ITEM(PAM_NUSER, nested);
    322          1.2  christos 		if (have_ss)
    323          1.2  christos 			PAM_SET_ITEM(PAM_SOCKADDR, &ss);
    324          1.1      manu 
    325      1.4.2.2      tron 		/*
    326      1.4.2.2      tron 		 * Don't check for errors, because we don't want to give
    327      1.4.2.2      tron 		 * out any information.
    328      1.4.2.2      tron 		 */
    329      1.4.2.3      tron 		pwd = NULL;
    330      1.4.2.2      tron 		(void)getpwnam_r(username, &pwres, pwbuf, sizeof(pwbuf), &pwd);
    331          1.1      manu 
    332          1.1      manu 		/*
    333          1.1      manu 		 * Establish the class now, before we might goto
    334          1.1      manu 		 * within the next block. pwd can be NULL since it
    335          1.1      manu 		 * falls back to the "default" class if it is.
    336          1.1      manu 		 */
    337          1.1      manu 		lc = login_getclass(pwd ? pwd->pw_class : NULL);
    338          1.1      manu 
    339          1.1      manu 		/*
    340          1.1      manu 		 * if we have a valid account name, and it doesn't have a
    341          1.1      manu 		 * password, or the -f option was specified and the caller
    342          1.1      manu 		 * is root or the caller isn't changing their uid, don't
    343          1.1      manu 		 * authenticate.
    344          1.1      manu 		 */
    345          1.1      manu 		if (pwd) {
    346          1.1      manu 			if (pwd->pw_uid == 0)
    347          1.1      manu 				rootlogin = 1;
    348          1.1      manu 
    349          1.1      manu 			if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
    350          1.1      manu 				/* already authenticated */
    351          1.1      manu 				auth_passed = 1;
    352          1.1      manu 				goto skip_auth;
    353          1.1      manu 			}
    354          1.1      manu 		}
    355          1.1      manu 
    356          1.1      manu 		(void)setpriority(PRIO_PROCESS, 0, -4);
    357          1.1      manu 
    358          1.1      manu 		switch(pam_err = pam_authenticate(pamh, pam_silent)) {
    359          1.1      manu 		case PAM_SUCCESS:
    360          1.1      manu 			/*
    361          1.1      manu 			 * PAM can change the user, refresh
    362          1.1      manu 			 * username, pwd, and lc.
    363          1.1      manu 			 */
    364          1.1      manu 			pam_err = pam_get_item(pamh, PAM_USER, &newuser);
    365          1.1      manu 			if (pam_err != PAM_SUCCESS)
    366          1.1      manu 				PAM_END("pam_get_item(PAM_USER)");
    367          1.1      manu 
    368          1.1      manu 			username = (char *)newuser;
    369      1.4.2.2      tron 			/*
    370      1.4.2.2      tron 			 * Don't check for errors, because we don't want to give
    371      1.4.2.2      tron 			 * out any information.
    372      1.4.2.2      tron 			 */
    373      1.4.2.3      tron 			pwd = NULL;
    374      1.4.2.2      tron 			(void)getpwnam_r(username, &pwres, pwbuf, sizeof(pwbuf),
    375      1.4.2.2      tron 			    &pwd);
    376          1.1      manu 			lc = login_getpwclass(pwd);
    377          1.1      manu 			auth_passed = 1;
    378          1.1      manu 
    379          1.1      manu 			switch (pam_err = pam_acct_mgmt(pamh, pam_silent)) {
    380          1.1      manu 			case PAM_SUCCESS:
    381          1.1      manu 				break;
    382          1.1      manu 
    383          1.1      manu 			case PAM_NEW_AUTHTOK_REQD:
    384          1.1      manu 				pam_err = pam_chauthtok(pamh,
    385          1.1      manu 				    pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK);
    386          1.1      manu 
    387          1.1      manu 				if (pam_err != PAM_SUCCESS)
    388          1.1      manu 					PAM_END("pam_chauthtok");
    389          1.1      manu 				break;
    390          1.1      manu 
    391  1.4.2.4.2.1      tron 			case PAM_AUTH_ERR:
    392  1.4.2.4.2.1      tron 			case PAM_USER_UNKNOWN:
    393  1.4.2.4.2.1      tron 			case PAM_MAXTRIES:
    394  1.4.2.4.2.1      tron 				auth_passed = 0;
    395  1.4.2.4.2.1      tron 				break;
    396  1.4.2.4.2.1      tron 
    397          1.1      manu 			default:
    398          1.1      manu 				PAM_END("pam_acct_mgmt");
    399          1.1      manu 				break;
    400          1.1      manu 			}
    401          1.1      manu 			break;
    402          1.1      manu 
    403          1.1      manu 		case PAM_AUTH_ERR:
    404          1.1      manu 		case PAM_USER_UNKNOWN:
    405          1.1      manu 		case PAM_MAXTRIES:
    406          1.1      manu 			auth_passed = 0;
    407          1.1      manu 			break;
    408          1.1      manu 
    409          1.1      manu 		default:
    410          1.1      manu 			PAM_END("pam_authenticate");
    411          1.1      manu 			break;
    412          1.1      manu 		}
    413          1.1      manu 
    414          1.1      manu 		(void)setpriority(PRIO_PROCESS, 0, 0);
    415          1.1      manu 
    416          1.1      manu skip_auth:
    417          1.1      manu 		/*
    418          1.1      manu 		 * If the user exists and authentication passed,
    419          1.1      manu 		 * get out of the loop and login the user.
    420          1.1      manu 		 */
    421          1.1      manu 		if (pwd && auth_passed)
    422          1.1      manu 			break;
    423          1.1      manu 
    424  1.4.2.4.2.1      tron 		(void)printf("Login incorrect or refused on this terminal.\n");
    425          1.1      manu 		failures++;
    426          1.1      manu 		cnt++;
    427  1.4.2.4.2.2      tron 		/*
    428  1.4.2.4.2.2      tron 		 * We allow login_retries tries, but after login_backoff
    429  1.4.2.4.2.2      tron 		 * we start backing off.  These default to 10 and 3
    430  1.4.2.4.2.2      tron 		 * respectively.
    431  1.4.2.4.2.2      tron 		 */
    432          1.1      manu 		if (cnt > login_backoff) {
    433          1.1      manu 			if (cnt >= login_retries) {
    434          1.1      manu 				badlogin(username);
    435          1.1      manu 				pam_end(pamh, PAM_SUCCESS);
    436      1.4.2.1      tron 				sleepexit(EXIT_FAILURE);
    437          1.1      manu 			}
    438  1.4.2.4.2.2      tron 			sleep((u_int)((cnt - login_backoff) * 5));
    439          1.1      manu 		}
    440          1.1      manu 	}
    441          1.1      manu 
    442          1.1      manu 	/* committed to login -- turn off timeout */
    443          1.1      manu 	(void)alarm((u_int)0);
    444          1.1      manu 
    445          1.1      manu 	endpwent();
    446          1.1      manu 
    447          1.1      manu         quietlog = login_getcapbool(lc, "hushlogin", 0);
    448          1.1      manu 
    449          1.1      manu 	/*
    450          1.1      manu 	 * Temporarily give up special privileges so we can change
    451          1.1      manu 	 * into NFS-mounted homes that are exported for non-root
    452          1.1      manu 	 * access and have mode 7x0
    453          1.1      manu 	 */
    454          1.1      manu 	saved_uid = geteuid();
    455          1.1      manu 	saved_gid = getegid();
    456          1.1      manu 	nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
    457          1.1      manu 
    458          1.1      manu 	(void)setegid(pwd->pw_gid);
    459          1.1      manu 	initgroups(username, pwd->pw_gid);
    460          1.1      manu 	(void)seteuid(pwd->pw_uid);
    461          1.1      manu 
    462          1.1      manu 	if (chdir(pwd->pw_dir) != 0) {
    463          1.1      manu                 if (login_getcapbool(lc, "requirehome", 0)) {
    464          1.1      manu 			(void)printf("Home directory %s required\n",
    465          1.1      manu 			    pwd->pw_dir);
    466          1.1      manu 			pam_end(pamh, PAM_SUCCESS);
    467      1.4.2.1      tron                         exit(EXIT_FAILURE);
    468          1.1      manu 		}
    469          1.1      manu 
    470          1.1      manu 		(void)printf("No home directory %s!\n", pwd->pw_dir);
    471          1.1      manu 		if (chdir("/")) {
    472          1.1      manu 			pam_end(pamh, PAM_SUCCESS);
    473      1.4.2.1      tron 			exit(EXIT_SUCCESS);
    474          1.1      manu 		}
    475          1.1      manu 		pwd->pw_dir = "/";
    476          1.1      manu 		(void)printf("Logging in with home = \"/\".\n");
    477          1.1      manu 	}
    478          1.1      manu 
    479          1.1      manu 	if (!quietlog) {
    480          1.1      manu 		quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
    481          1.1      manu 		pam_silent = 0;
    482          1.1      manu 	}
    483          1.1      manu 
    484          1.1      manu 	/* regain special privileges */
    485          1.1      manu 	setegid(saved_gid);
    486          1.1      manu 	setgroups(nsaved_gids, saved_gids);
    487          1.1      manu 	seteuid(saved_uid);
    488          1.1      manu 
    489          1.3  christos 	(void)chown(ttyn, pwd->pw_uid,
    490          1.3  christos 	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
    491          1.3  christos 
    492          1.4  christos 	if (ttyaction(ttyn, "login", pwd->pw_name))
    493          1.4  christos 		(void)printf("Warning: ttyaction failed.\n");
    494          1.4  christos 
    495          1.1      manu 	/* Nothing else left to fail -- really log in. */
    496          1.1      manu         update_db(quietlog);
    497          1.1      manu 
    498          1.1      manu 	if (nested == NULL && setusercontext(lc, pwd, pwd->pw_uid,
    499          1.1      manu 	    LOGIN_SETLOGIN) != 0) {
    500          1.1      manu 		syslog(LOG_ERR, "setusercontext failed");
    501          1.1      manu 		pam_end(pamh, PAM_SUCCESS);
    502      1.4.2.1      tron 		exit(EXIT_FAILURE);
    503          1.1      manu 	}
    504          1.1      manu 
    505          1.1      manu 	if (tty[sizeof("tty")-1] == 'd')
    506          1.1      manu 		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
    507          1.1      manu 
    508          1.1      manu 	/* If fflag is on, assume caller/authenticator has logged root login. */
    509          1.1      manu 	if (rootlogin && fflag == 0) {
    510          1.1      manu 		if (hostname)
    511          1.1      manu 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
    512          1.1      manu 			    username, tty, hostname);
    513          1.1      manu 		else
    514          1.1      manu 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
    515          1.1      manu 			    username, tty);
    516          1.1      manu 	}
    517          1.1      manu 
    518          1.1      manu 	/*
    519          1.1      manu 	 * Establish groups
    520          1.1      manu 	 */
    521          1.1      manu 	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
    522          1.1      manu 		syslog(LOG_ERR, "setusercontext failed");
    523          1.1      manu 		pam_end(pamh, PAM_SUCCESS);
    524      1.4.2.1      tron 		exit(EXIT_FAILURE);
    525          1.1      manu 	}
    526          1.1      manu 
    527          1.1      manu 	pam_err = pam_setcred(pamh, pam_silent|PAM_ESTABLISH_CRED);
    528          1.1      manu 	if (pam_err != PAM_SUCCESS)
    529          1.1      manu 		PAM_END("pam_setcred");
    530          1.1      manu 
    531          1.1      manu 	pam_err = pam_open_session(pamh, pam_silent);
    532          1.1      manu 	if (pam_err != PAM_SUCCESS)
    533          1.1      manu 		PAM_END("pam_open_session");
    534          1.1      manu 
    535          1.1      manu 	/*
    536          1.1      manu 	 * Fork because we need to call pam_closesession as root.
    537          1.1      manu 	 * Make sure signals cannot kill the parent.
    538          1.1      manu 	 * This is copied from crontab(8), which has to
    539          1.1      manu          * cope with a similar situation.
    540          1.1      manu 	 */
    541          1.1      manu 	oint = signal(SIGINT, SIG_IGN);
    542          1.1      manu 	oabrt = signal(SIGABRT, SIG_IGN);
    543          1.1      manu 
    544          1.1      manu 	switch(pid = fork()) {
    545          1.1      manu 	case -1:
    546          1.1      manu 		pam_err = pam_close_session(pamh, 0);
    547          1.1      manu 		if (pam_err != PAM_SUCCESS) {
    548          1.1      manu 			syslog(LOG_ERR, "pam_close_session: %s",
    549          1.1      manu 			    pam_strerror(pamh, pam_err));
    550          1.1      manu 			warnx("pam_close_session: %s",
    551          1.1      manu 			    pam_strerror(pamh, pam_err));
    552          1.1      manu 		}
    553          1.1      manu 		syslog(LOG_ERR, "fork failed: %m");
    554          1.1      manu 		warn("fork failed");
    555          1.1      manu 		pam_end(pamh, pam_err);
    556      1.4.2.1      tron 		exit(EXIT_FAILURE);
    557          1.1      manu 		break;
    558          1.1      manu 
    559          1.1      manu 	case 0: /* Child */
    560          1.1      manu 		break;
    561          1.1      manu 
    562          1.1      manu 	default:
    563          1.1      manu 		/*
    564          1.1      manu 		 * Parent: wait for the child to terminate
    565          1.1      manu 		 * and call pam_close_session.
    566          1.1      manu 		 */
    567          1.3  christos 		if ((xpid = waitpid(pid, &status, 0)) != pid) {
    568          1.1      manu 			pam_err = pam_close_session(pamh, 0);
    569          1.1      manu 			if (pam_err != PAM_SUCCESS) {
    570          1.1      manu 				syslog(LOG_ERR,
    571          1.1      manu 				    "pam_close_session: %s",
    572          1.1      manu 				    pam_strerror(pamh, pam_err));
    573          1.1      manu 				warnx("pam_close_session: %s",
    574          1.1      manu 				    pam_strerror(pamh, pam_err));
    575          1.1      manu 			}
    576          1.1      manu 			pam_end(pamh, pam_err);
    577          1.3  christos 			if (xpid != -1)
    578          1.3  christos 				warnx("wrong PID: %d != %d", pid, xpid);
    579          1.3  christos 			else
    580          1.3  christos 				warn("wait for pid %d failed", pid);
    581      1.4.2.1      tron 			exit(EXIT_FAILURE);
    582          1.1      manu 		}
    583          1.1      manu 
    584          1.1      manu 		(void)signal(SIGINT, oint);
    585          1.1      manu 		(void)signal(SIGABRT, oabrt);
    586          1.1      manu 		if ((pam_err = pam_close_session(pamh, 0)) != PAM_SUCCESS) {
    587          1.1      manu 			syslog(LOG_ERR, "pam_close_session: %s",
    588          1.1      manu 			    pam_strerror(pamh, pam_err));
    589          1.1      manu 			warnx("pam_close_session: %s",
    590          1.1      manu 			    pam_strerror(pamh, pam_err));
    591          1.1      manu 		}
    592          1.1      manu 		pam_end(pamh, PAM_SUCCESS);
    593      1.4.2.1      tron 		exit(EXIT_SUCCESS);
    594          1.1      manu 		break;
    595          1.1      manu 	}
    596          1.1      manu 
    597          1.1      manu 	/*
    598          1.1      manu 	 * The child: starting here, we don't have to care about
    599          1.1      manu 	 * handling PAM issues if we exit, the parent will do the
    600          1.1      manu 	 * job when we exit.
    601          1.1      manu          *
    602          1.1      manu 	 * Destroy environment unless user has requested its preservation.
    603          1.1      manu 	 * Try to preserve TERM anyway.
    604          1.1      manu 	 */
    605          1.1      manu 	saved_term = getenv("TERM");
    606          1.1      manu 	if (!pflag) {
    607          1.1      manu 		environ = envinit;
    608          1.1      manu 		if (saved_term)
    609          1.1      manu 			setenv("TERM", saved_term, 0);
    610          1.1      manu 	}
    611          1.1      manu 
    612          1.1      manu 	if (*pwd->pw_shell == '\0')
    613          1.1      manu 		pwd->pw_shell = _PATH_BSHELL;
    614          1.1      manu 
    615          1.1      manu 	shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
    616          1.1      manu 	if (*shell == '\0')
    617          1.1      manu 		shell = pwd->pw_shell;
    618          1.1      manu 
    619          1.1      manu 	if ((pwd->pw_shell = strdup(shell)) == NULL) {
    620          1.1      manu 		syslog(LOG_ERR, "Cannot alloc mem");
    621      1.4.2.1      tron 		exit(EXIT_FAILURE);
    622          1.1      manu 	}
    623          1.1      manu 
    624          1.1      manu 	(void)setenv("HOME", pwd->pw_dir, 1);
    625          1.1      manu 	(void)setenv("SHELL", pwd->pw_shell, 1);
    626          1.1      manu 	if (term[0] == '\0') {
    627          1.1      manu 		char *tt = (char *)stypeof(tty);
    628          1.1      manu 
    629          1.1      manu 		if (tt == NULL)
    630          1.1      manu 			tt = login_getcapstr(lc, "term", NULL, NULL);
    631          1.1      manu 
    632          1.1      manu 		/* unknown term -> "su" */
    633          1.1      manu 		(void)strlcpy(term, tt != NULL ? tt : "su", sizeof(term));
    634          1.1      manu 	}
    635          1.1      manu 	(void)setenv("TERM", term, 0);
    636          1.1      manu 	(void)setenv("LOGNAME", pwd->pw_name, 1);
    637          1.1      manu 	(void)setenv("USER", pwd->pw_name, 1);
    638          1.1      manu 
    639          1.1      manu 	/*
    640          1.1      manu 	 * Add PAM environement
    641          1.1      manu 	 */
    642          1.1      manu 	if ((pamenv = pam_getenvlist(pamh)) != NULL) {
    643          1.1      manu 		char **envitem;
    644          1.1      manu 
    645          1.1      manu 		for (envitem = pamenv; *envitem; envitem++) {
    646          1.1      manu 			putenv(*envitem);
    647          1.1      manu 			free(*envitem);
    648          1.1      manu 		}
    649          1.1      manu 
    650          1.1      manu 		free(pamenv);
    651          1.1      manu 	}
    652          1.1      manu 
    653          1.1      manu 	/* This drops root privs */
    654          1.1      manu 	if (setusercontext(lc, pwd, pwd->pw_uid,
    655          1.1      manu 	    (LOGIN_SETALL & ~LOGIN_SETLOGIN)) != 0) {
    656          1.1      manu 		syslog(LOG_ERR, "setusercontext failed");
    657      1.4.2.1      tron 		exit(EXIT_FAILURE);
    658          1.1      manu 	}
    659          1.1      manu 
    660          1.1      manu 	if (!quietlog) {
    661          1.1      manu 		char *fname;
    662          1.1      manu 
    663          1.1      manu 		fname = login_getcapstr(lc, "copyright", NULL, NULL);
    664          1.1      manu 		if (fname != NULL && access(fname, F_OK) == 0)
    665          1.1      manu 			motd(fname);
    666          1.1      manu 		else
    667          1.1      manu 			(void)printf("%s", copyrightstr);
    668          1.1      manu 
    669          1.1      manu                 fname = login_getcapstr(lc, "welcome", NULL, NULL);
    670          1.1      manu                 if (fname == NULL || access(fname, F_OK) != 0)
    671          1.1      manu                         fname = _PATH_MOTDFILE;
    672          1.1      manu                 motd(fname);
    673          1.1      manu 
    674          1.1      manu 		(void)snprintf(tbuf,
    675          1.1      manu 		    sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
    676          1.1      manu 		if (stat(tbuf, &st) == 0 && st.st_size != 0)
    677          1.1      manu 			(void)printf("You have %smail.\n",
    678          1.1      manu 			    (st.st_mtime > st.st_atime) ? "new " : "");
    679          1.1      manu 	}
    680          1.1      manu 
    681          1.1      manu 	login_close(lc);
    682          1.1      manu 
    683          1.1      manu 	(void)signal(SIGALRM, SIG_DFL);
    684          1.1      manu 	(void)signal(SIGQUIT, SIG_DFL);
    685          1.1      manu 	(void)signal(SIGINT, SIG_DFL);
    686          1.1      manu 	(void)signal(SIGTSTP, SIG_IGN);
    687          1.1      manu 
    688          1.1      manu 	tbuf[0] = '-';
    689          1.1      manu 	(void)strlcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
    690          1.1      manu 	    p + 1 : pwd->pw_shell, sizeof(tbuf) - 1);
    691          1.1      manu 
    692      1.4.2.4      tron 	execlp(pwd->pw_shell, tbuf, NULL);
    693      1.4.2.1      tron 	err(EXIT_FAILURE, "%s", pwd->pw_shell);
    694          1.1      manu }
    695          1.1      manu 
    696          1.1      manu #define	NBUFSIZ		(MAXLOGNAME + 1)
    697          1.1      manu 
    698          1.1      manu 
    699          1.1      manu void
    700          1.1      manu getloginname(void)
    701          1.1      manu {
    702          1.1      manu 	int ch;
    703          1.1      manu 	char *p;
    704          1.1      manu 	static char nbuf[NBUFSIZ];
    705          1.1      manu 
    706          1.1      manu 	for (;;) {
    707          1.1      manu 		(void)printf("login: ");
    708          1.1      manu 		for (p = nbuf; (ch = getchar()) != '\n'; ) {
    709          1.1      manu 			if (ch == EOF) {
    710          1.1      manu 				badlogin(username);
    711      1.4.2.1      tron 				exit(EXIT_SUCCESS);
    712          1.1      manu 			}
    713          1.1      manu 			if (p < nbuf + (NBUFSIZ - 1))
    714          1.1      manu 				*p++ = ch;
    715          1.1      manu 		}
    716          1.1      manu 		if (p > nbuf) {
    717          1.1      manu 			if (nbuf[0] == '-')
    718          1.1      manu 				(void)fprintf(stderr,
    719          1.1      manu 				    "login names may not start with '-'.\n");
    720          1.1      manu 			else {
    721          1.1      manu 				*p = '\0';
    722          1.1      manu 				username = nbuf;
    723          1.1      manu 				break;
    724          1.1      manu 			}
    725          1.1      manu 		}
    726          1.1      manu 	}
    727          1.1      manu }
    728          1.1      manu 
    729          1.1      manu int
    730          1.1      manu rootterm(char *ttyn)
    731          1.1      manu {
    732          1.1      manu 	struct ttyent *t;
    733          1.1      manu 
    734          1.1      manu 	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
    735          1.1      manu }
    736          1.1      manu 
    737          1.1      manu jmp_buf motdinterrupt;
    738          1.1      manu 
    739          1.1      manu void
    740          1.1      manu motd(char *fname)
    741          1.1      manu {
    742          1.1      manu 	int fd, nchars;
    743          1.1      manu 	sig_t oldint;
    744          1.1      manu 	char tbuf[8192];
    745          1.1      manu 
    746          1.1      manu 	if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0)
    747          1.1      manu 		return;
    748          1.1      manu 	oldint = signal(SIGINT, sigint);
    749          1.1      manu 	if (setjmp(motdinterrupt) == 0)
    750          1.1      manu 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
    751          1.1      manu 			(void)write(fileno(stdout), tbuf, nchars);
    752          1.1      manu 	(void)signal(SIGINT, oldint);
    753          1.1      manu 	(void)close(fd);
    754          1.1      manu }
    755          1.1      manu 
    756          1.1      manu /* ARGSUSED */
    757          1.1      manu void
    758          1.1      manu sigint(int signo)
    759          1.1      manu {
    760          1.1      manu 
    761          1.1      manu 	longjmp(motdinterrupt, 1);
    762          1.1      manu }
    763          1.1      manu 
    764          1.1      manu /* ARGSUSED */
    765          1.1      manu void
    766          1.1      manu timedout(int signo)
    767          1.1      manu {
    768          1.1      manu 
    769          1.1      manu 	(void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
    770      1.4.2.1      tron 	exit(EXIT_SUCCESS);
    771          1.1      manu }
    772          1.1      manu 
    773          1.1      manu static void
    774          1.1      manu update_db(int quietlog)
    775          1.1      manu {
    776          1.1      manu 	if (nested != NULL) {
    777          1.1      manu 		if (hostname != NULL)
    778          1.1      manu 			syslog(LOG_NOTICE, "%s to %s on tty %s from %s",
    779          1.1      manu 			    nested, pwd->pw_name, tty, hostname);
    780          1.1      manu 		else
    781          1.1      manu 			syslog(LOG_NOTICE, "%s to %s on tty %s", nested,
    782          1.1      manu 			    pwd->pw_name, tty);
    783          1.1      manu 
    784          1.1      manu 	}
    785          1.1      manu 	if (hostname != NULL && have_ss == 0) {
    786          1.1      manu 		socklen_t len = sizeof(ss);
    787          1.1      manu 		(void)getpeername(STDIN_FILENO, (struct sockaddr *)&ss, &len);
    788          1.1      manu 	}
    789          1.1      manu 	(void)gettimeofday(&now, NULL);
    790          1.1      manu }
    791          1.1      manu 
    792          1.1      manu void
    793          1.1      manu badlogin(char *name)
    794          1.1      manu {
    795          1.1      manu 
    796          1.1      manu 	if (failures == 0)
    797          1.1      manu 		return;
    798          1.1      manu 	if (hostname) {
    799          1.1      manu 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
    800          1.1      manu 		    failures, failures > 1 ? "S" : "", hostname);
    801          1.1      manu 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
    802          1.1      manu 		    "%d LOGIN FAILURE%s FROM %s, %s",
    803          1.1      manu 		    failures, failures > 1 ? "S" : "", hostname, name);
    804          1.1      manu 	} else {
    805          1.1      manu 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
    806          1.1      manu 		    failures, failures > 1 ? "S" : "", tty);
    807          1.1      manu 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
    808          1.1      manu 		    "%d LOGIN FAILURE%s ON %s, %s",
    809          1.1      manu 		    failures, failures > 1 ? "S" : "", tty, name);
    810          1.1      manu 	}
    811          1.1      manu }
    812          1.1      manu 
    813          1.1      manu const char *
    814          1.1      manu stypeof(const char *ttyid)
    815          1.1      manu {
    816          1.1      manu 	struct ttyent *t;
    817          1.1      manu 
    818          1.1      manu 	return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL);
    819          1.1      manu }
    820          1.1      manu 
    821          1.1      manu void
    822          1.1      manu sleepexit(int eval)
    823          1.1      manu {
    824          1.1      manu 
    825          1.1      manu 	(void)sleep(5);
    826          1.1      manu 	exit(eval);
    827          1.1      manu }
    828          1.1      manu 
    829          1.1      manu void
    830          1.1      manu decode_ss(const char *arg)
    831          1.1      manu {
    832          1.1      manu 	struct sockaddr_storage *ssp;
    833          1.1      manu 	size_t len = strlen(arg);
    834          1.1      manu 
    835          1.1      manu 	if (len > sizeof(*ssp) * 4 + 1 || len < sizeof(*ssp))
    836      1.4.2.1      tron 		errx(EXIT_FAILURE, "Bad argument");
    837          1.1      manu 
    838          1.1      manu 	if ((ssp = malloc(len)) == NULL)
    839      1.4.2.1      tron 		err(EXIT_FAILURE, NULL);
    840          1.1      manu 
    841          1.1      manu 	if (strunvis((char *)ssp, arg) != sizeof(*ssp))
    842      1.4.2.1      tron 		errx(EXIT_FAILURE, "Decoding error");
    843          1.1      manu 
    844          1.1      manu 	(void)memcpy(&ss, ssp, sizeof(ss));
    845          1.1      manu 	have_ss = 1;
    846          1.1      manu }
    847          1.1      manu 
    848          1.1      manu void
    849          1.1      manu usage(void)
    850          1.1      manu {
    851          1.1      manu 	(void)fprintf(stderr,
    852          1.1      manu 	    "Usage: %s [-Ffps] [-a address] [-h hostname] [username]\n",
    853          1.1      manu 	    getprogname());
    854      1.4.2.1      tron 	exit(EXIT_FAILURE);
    855          1.1      manu }
    856