xref: /minix3/usr.bin/su/su.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: su.c,v 1.72 2015/06/16 22:54:11 christos Exp $	*/
24de51eedSBen Gras 
34de51eedSBen Gras /*
44de51eedSBen Gras  * Copyright (c) 1988 The Regents of the University of California.
54de51eedSBen Gras  * All rights reserved.
64de51eedSBen Gras  *
74de51eedSBen Gras  * Redistribution and use in source and binary forms, with or without
84de51eedSBen Gras  * modification, are permitted provided that the following conditions
94de51eedSBen Gras  * are met:
104de51eedSBen Gras  * 1. Redistributions of source code must retain the above copyright
114de51eedSBen Gras  *    notice, this list of conditions and the following disclaimer.
124de51eedSBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
134de51eedSBen Gras  *    notice, this list of conditions and the following disclaimer in the
144de51eedSBen Gras  *    documentation and/or other materials provided with the distribution.
154de51eedSBen Gras  * 3. Neither the name of the University nor the names of its contributors
164de51eedSBen Gras  *    may be used to endorse or promote products derived from this software
174de51eedSBen Gras  *    without specific prior written permission.
184de51eedSBen Gras  *
194de51eedSBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
204de51eedSBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
214de51eedSBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
224de51eedSBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
234de51eedSBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
244de51eedSBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
254de51eedSBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
264de51eedSBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
274de51eedSBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
284de51eedSBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
294de51eedSBen Gras  * SUCH DAMAGE.
304de51eedSBen Gras  */
314de51eedSBen Gras 
324de51eedSBen Gras #include <sys/cdefs.h>
334de51eedSBen Gras #ifndef lint
344de51eedSBen Gras __COPYRIGHT("@(#) Copyright (c) 1988\
354de51eedSBen Gras  The Regents of the University of California.  All rights reserved.");
364de51eedSBen Gras #endif /* not lint */
374de51eedSBen Gras 
384de51eedSBen Gras #ifndef lint
394de51eedSBen Gras #if 0
404de51eedSBen Gras static char sccsid[] = "@(#)su.c	8.3 (Berkeley) 4/2/94";*/
414de51eedSBen Gras #else
42*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: su.c,v 1.72 2015/06/16 22:54:11 christos Exp $");
434de51eedSBen Gras #endif
444de51eedSBen Gras #endif /* not lint */
454de51eedSBen Gras 
464de51eedSBen Gras #include <sys/param.h>
474de51eedSBen Gras #include <sys/time.h>
484de51eedSBen Gras #include <sys/resource.h>
494de51eedSBen Gras #include <err.h>
504de51eedSBen Gras #include <errno.h>
514de51eedSBen Gras #include <grp.h>
524de51eedSBen Gras #include <paths.h>
534de51eedSBen Gras #include <pwd.h>
544de51eedSBen Gras #include <stdio.h>
554de51eedSBen Gras #ifdef SKEY
564de51eedSBen Gras #include <skey.h>
574de51eedSBen Gras #endif
584de51eedSBen Gras #include <stdlib.h>
594de51eedSBen Gras #include <string.h>
604de51eedSBen Gras #include <syslog.h>
614de51eedSBen Gras #include <time.h>
624de51eedSBen Gras #include <tzfile.h>
634de51eedSBen Gras #include <unistd.h>
644de51eedSBen Gras #include <util.h>
654de51eedSBen Gras 
664de51eedSBen Gras #ifdef LOGIN_CAP
674de51eedSBen Gras #include <login_cap.h>
684de51eedSBen Gras #endif
694de51eedSBen Gras 
704de51eedSBen Gras #ifdef KERBEROS5
714de51eedSBen Gras #include <krb5.h>
724de51eedSBen Gras #endif
734de51eedSBen Gras 
744de51eedSBen Gras #ifdef ALLOW_GROUP_CHANGE
754de51eedSBen Gras #include "grutil.h"
764de51eedSBen Gras #endif
774de51eedSBen Gras #include "suutil.h"
784de51eedSBen Gras 
794de51eedSBen Gras #ifdef KERBEROS5
804de51eedSBen Gras #define	ARGSTRX	"-Kdflm"
814de51eedSBen Gras static int kerberos5(char *, const char *, uid_t);
824de51eedSBen Gras int use_kerberos = 1;
834de51eedSBen Gras #else
844de51eedSBen Gras #define	ARGSTRX	"-dflm"
854de51eedSBen Gras #endif
864de51eedSBen Gras 
874de51eedSBen Gras #ifndef	SU_GROUP
884de51eedSBen Gras #define	SU_GROUP	"wheel"
894de51eedSBen Gras #endif
904de51eedSBen Gras 
914de51eedSBen Gras #define GROUP_PASSWORD	"Group Password:"
924de51eedSBen Gras 
934de51eedSBen Gras #ifdef LOGIN_CAP
944de51eedSBen Gras #define ARGSTR	ARGSTRX "c:"
954de51eedSBen Gras #else
964de51eedSBen Gras #define ARGSTR ARGSTRX
974de51eedSBen Gras #endif
984de51eedSBen Gras 
994de51eedSBen Gras static int check_ingroup(int, const char *, const char *, int);
1004de51eedSBen Gras 
1014de51eedSBen Gras int
main(int argc,char ** argv)1024de51eedSBen Gras main(int argc, char **argv)
1034de51eedSBen Gras {
1044de51eedSBen Gras 	extern char **environ;
1054de51eedSBen Gras 	struct passwd *pwd;
1064de51eedSBen Gras 	char *p;
1074de51eedSBen Gras #ifdef BSD4_4
1084de51eedSBen Gras 	struct timeval tp;
1094de51eedSBen Gras #endif
1104de51eedSBen Gras 	uid_t ruid;
1114de51eedSBen Gras 	int asme, ch, asthem, fastlogin, prio, gohome;
1124de51eedSBen Gras 	enum { UNSET, YES, NO } iscsh = UNSET;
1134de51eedSBen Gras 	const char *user, *shell, *avshell;
1144de51eedSBen Gras 	char *username, **np;
115*0a6a1f1dSLionel Sambuc #ifdef SU_ROOTAUTH
116*0a6a1f1dSLionel Sambuc 	char *userpass;
117*0a6a1f1dSLionel Sambuc #endif
118*0a6a1f1dSLionel Sambuc 	char *class;
1194de51eedSBen Gras 	char shellbuf[MAXPATHLEN], avshellbuf[MAXPATHLEN];
1204de51eedSBen Gras 	time_t pw_warntime = _PASSWORD_WARNDAYS * SECSPERDAY;
1214de51eedSBen Gras #ifdef LOGIN_CAP
1224de51eedSBen Gras 	login_cap_t *lc;
1234de51eedSBen Gras #endif
1244de51eedSBen Gras #ifdef ALLOW_GROUP_CHANGE
1254de51eedSBen Gras 	char *gname;
1264de51eedSBen Gras #endif
1274de51eedSBen Gras 
1284de51eedSBen Gras 	(void)setprogname(argv[0]);
1294de51eedSBen Gras 	asme = asthem = fastlogin = 0;
1304de51eedSBen Gras 	gohome = 1;
1314de51eedSBen Gras 	shell = class = NULL;
1324de51eedSBen Gras 	while ((ch = getopt(argc, argv, ARGSTR)) != -1)
1334de51eedSBen Gras 		switch((char)ch) {
1344de51eedSBen Gras #ifdef KERBEROS5
1354de51eedSBen Gras 		case 'K':
1364de51eedSBen Gras 			use_kerberos = 0;
1374de51eedSBen Gras 			break;
1384de51eedSBen Gras #endif
1394de51eedSBen Gras #ifdef LOGIN_CAP
1404de51eedSBen Gras 		case 'c':
1414de51eedSBen Gras 			class = optarg;
1424de51eedSBen Gras 			break;
1434de51eedSBen Gras #endif
1444de51eedSBen Gras 		case 'd':
1454de51eedSBen Gras 			asme = 0;
1464de51eedSBen Gras 			asthem = 1;
1474de51eedSBen Gras 			gohome = 0;
1484de51eedSBen Gras 			break;
1494de51eedSBen Gras 		case 'f':
1504de51eedSBen Gras 			fastlogin = 1;
1514de51eedSBen Gras 			break;
1524de51eedSBen Gras 		case '-':
1534de51eedSBen Gras 		case 'l':
1544de51eedSBen Gras 			asme = 0;
1554de51eedSBen Gras 			asthem = 1;
1564de51eedSBen Gras 			break;
1574de51eedSBen Gras 		case 'm':
1584de51eedSBen Gras 			asme = 1;
1594de51eedSBen Gras 			asthem = 0;
1604de51eedSBen Gras 			break;
1614de51eedSBen Gras 		case '?':
1624de51eedSBen Gras 		default:
1634de51eedSBen Gras 			(void)fprintf(stderr,
1644de51eedSBen Gras #ifdef ALLOW_GROUP_CHANGE
1654de51eedSBen Gras 			    "usage: %s [%s] [login[:group] [shell arguments]]\n",
1664de51eedSBen Gras #else
1674de51eedSBen Gras 			    "usage: %s [%s] [login [shell arguments]]\n",
1684de51eedSBen Gras #endif
1694de51eedSBen Gras 			    getprogname(), ARGSTR);
1704de51eedSBen Gras 			exit(EXIT_FAILURE);
1714de51eedSBen Gras 		}
1724de51eedSBen Gras 	argv += optind;
1734de51eedSBen Gras 
1744de51eedSBen Gras 	/* Lower the priority so su runs faster */
1754de51eedSBen Gras 	errno = 0;
1764de51eedSBen Gras 	prio = getpriority(PRIO_PROCESS, 0);
1774de51eedSBen Gras 	if (errno)
1784de51eedSBen Gras 		prio = 0;
1794de51eedSBen Gras 	if (prio > -2)
1804de51eedSBen Gras 		(void)setpriority(PRIO_PROCESS, 0, -2);
1814de51eedSBen Gras 	openlog("su", 0, LOG_AUTH);
1824de51eedSBen Gras 
1834de51eedSBen Gras 	/* get current login name and shell */
1844de51eedSBen Gras 	ruid = getuid();
1854de51eedSBen Gras 	username = getlogin();
1864de51eedSBen Gras 	if (username == NULL || (pwd = getpwnam(username)) == NULL ||
1874de51eedSBen Gras 	    pwd->pw_uid != ruid)
1884de51eedSBen Gras 		pwd = getpwuid(ruid);
1894de51eedSBen Gras 	if (pwd == NULL)
1904de51eedSBen Gras 		errx(EXIT_FAILURE, "who are you?");
1914de51eedSBen Gras 	username = estrdup(pwd->pw_name);
192*0a6a1f1dSLionel Sambuc #ifdef SU_ROOTAUTH
1934de51eedSBen Gras 	userpass = estrdup(pwd->pw_passwd);
194*0a6a1f1dSLionel Sambuc #endif
1954de51eedSBen Gras 
1964de51eedSBen Gras 	if (asme) {
1974de51eedSBen Gras 		if (pwd->pw_shell && *pwd->pw_shell) {
1984de51eedSBen Gras 			(void)estrlcpy(shellbuf, pwd->pw_shell, sizeof(shellbuf));
1994de51eedSBen Gras 			shell = shellbuf;
2004de51eedSBen Gras 		} else {
2014de51eedSBen Gras 			shell = _PATH_BSHELL;
2024de51eedSBen Gras 			iscsh = NO;
2034de51eedSBen Gras 		}
2044de51eedSBen Gras 	}
2054de51eedSBen Gras 	/* get target login information, default to root */
2064de51eedSBen Gras 	user = *argv ? *argv : "root";
2074de51eedSBen Gras 	np = *argv ? argv : argv - 1;
2084de51eedSBen Gras 
2094de51eedSBen Gras #ifdef ALLOW_GROUP_CHANGE
2104de51eedSBen Gras 	if ((p = strchr(user, ':')) != NULL) {
2114de51eedSBen Gras 		*p = '\0';
2124de51eedSBen Gras 		gname = ++p;
2134de51eedSBen Gras 	}
2144de51eedSBen Gras 	else
2154de51eedSBen Gras 		gname = NULL;
2164de51eedSBen Gras 
2174de51eedSBen Gras #ifdef ALLOW_EMPTY_USER
2184de51eedSBen Gras 	if (user[0] == '\0' && gname != NULL)
2194de51eedSBen Gras 		user = username;
2204de51eedSBen Gras #endif
2214de51eedSBen Gras #endif
2224de51eedSBen Gras 	if ((pwd = getpwnam(user)) == NULL)
2234de51eedSBen Gras 		errx(EXIT_FAILURE, "unknown login `%s'", user);
2244de51eedSBen Gras 
2254de51eedSBen Gras #ifdef LOGIN_CAP
2264de51eedSBen Gras 	/* force the usage of specified class */
2274de51eedSBen Gras 	if (class) {
2284de51eedSBen Gras 		if (ruid)
2294de51eedSBen Gras 			errx(EXIT_FAILURE, "Only root may use -c");
2304de51eedSBen Gras 
2314de51eedSBen Gras 		pwd->pw_class = class;
2324de51eedSBen Gras 	}
2334de51eedSBen Gras 	if ((lc = login_getclass(pwd->pw_class)) == NULL)
234*0a6a1f1dSLionel Sambuc 		errx(EXIT_FAILURE, "Unknown class %s", pwd->pw_class);
2354de51eedSBen Gras 
2364de51eedSBen Gras 	pw_warntime = (time_t)login_getcaptime(lc, "password-warn",
2374de51eedSBen Gras 	    _PASSWORD_WARNDAYS * SECSPERDAY,
2384de51eedSBen Gras 	    _PASSWORD_WARNDAYS * SECSPERDAY);
2394de51eedSBen Gras #endif
2404de51eedSBen Gras 
2414de51eedSBen Gras 	if (ruid
2424de51eedSBen Gras #ifdef KERBEROS5
2434de51eedSBen Gras 	    && (!use_kerberos || kerberos5(username, user, pwd->pw_uid))
2444de51eedSBen Gras #endif
2454de51eedSBen Gras 	    ) {
2464de51eedSBen Gras 		char *pass = pwd->pw_passwd;
2474de51eedSBen Gras 		int ok = pwd->pw_uid != 0;
2484de51eedSBen Gras 
2494de51eedSBen Gras #ifdef SU_ROOTAUTH
2504de51eedSBen Gras 		/*
2514de51eedSBen Gras 		 * Allow those in group rootauth to su to root, by supplying
2524de51eedSBen Gras 		 * their own password.
2534de51eedSBen Gras 		 */
2544de51eedSBen Gras 		if (!ok) {
2554de51eedSBen Gras 			if ((ok = check_ingroup(-1, SU_ROOTAUTH, username, 0))) {
2564de51eedSBen Gras 				pass = userpass;
2574de51eedSBen Gras 				user = username;
2584de51eedSBen Gras 			}
2594de51eedSBen Gras 		}
2604de51eedSBen Gras #endif
2614de51eedSBen Gras 		/*
2624de51eedSBen Gras 		 * Only allow those in group SU_GROUP to su to root,
2634de51eedSBen Gras 		 * but only if that group has any members.
2644de51eedSBen Gras 		 * If SU_GROUP has no members, allow anyone to su root
2654de51eedSBen Gras 		 */
2664de51eedSBen Gras 		if (!ok)
2674de51eedSBen Gras 			ok = check_ingroup(-1, SU_GROUP, username, 1);
2684de51eedSBen Gras 		if (!ok)
2694de51eedSBen Gras 			errx(EXIT_FAILURE,
2704de51eedSBen Gras 	    "you are not listed in the correct secondary group (%s) to su %s.",
2714de51eedSBen Gras 					    SU_GROUP, user);
2724de51eedSBen Gras 		/* if target requires a password, verify it */
2734de51eedSBen Gras 		if (*pass && pwd->pw_uid != ruid) {	/* XXX - OK? */
2744de51eedSBen Gras 			p = getpass("Password:");
2754de51eedSBen Gras #ifdef SKEY
2764de51eedSBen Gras 			if (strcasecmp(p, "s/key") == 0) {
2774de51eedSBen Gras 				if (skey_haskey(user))
2784de51eedSBen Gras 					errx(EXIT_FAILURE,
2794de51eedSBen Gras 					    "Sorry, you have no s/key.");
2804de51eedSBen Gras 				else {
2814de51eedSBen Gras 					if (skey_authenticate(user)) {
2824de51eedSBen Gras 						goto badlogin;
2834de51eedSBen Gras 					}
2844de51eedSBen Gras 				}
2854de51eedSBen Gras 
2864de51eedSBen Gras 			} else
2874de51eedSBen Gras #endif
2884de51eedSBen Gras 			if (strcmp(pass, crypt(p, pass)) != 0) {
2894de51eedSBen Gras #ifdef SKEY
2904de51eedSBen Gras  badlogin:
2914de51eedSBen Gras #endif
2924de51eedSBen Gras 				(void)fprintf(stderr, "Sorry\n");
2934de51eedSBen Gras 				syslog(LOG_WARNING,
2944de51eedSBen Gras 					"BAD SU %s to %s%s", username,
2954de51eedSBen Gras 					pwd->pw_name, ontty());
2964de51eedSBen Gras 				exit(EXIT_FAILURE);
2974de51eedSBen Gras 			}
2984de51eedSBen Gras 		}
2994de51eedSBen Gras 	}
3004de51eedSBen Gras 
3014de51eedSBen Gras 	if (asme) {
3024de51eedSBen Gras 		/* if asme and non-standard target shell, must be root */
3034de51eedSBen Gras 		if (chshell(pwd->pw_shell) == 0 && ruid)
3044de51eedSBen Gras 			errx(EXIT_FAILURE, "permission denied (shell).");
3054de51eedSBen Gras 	} else if (pwd->pw_shell && *pwd->pw_shell) {
3064de51eedSBen Gras 		shell = pwd->pw_shell;
3074de51eedSBen Gras 		iscsh = UNSET;
3084de51eedSBen Gras 	} else {
3094de51eedSBen Gras 		shell = _PATH_BSHELL;
3104de51eedSBen Gras 		iscsh = NO;
3114de51eedSBen Gras 	}
3124de51eedSBen Gras 
3134de51eedSBen Gras 	if ((p = strrchr(shell, '/')) != NULL)
3144de51eedSBen Gras 		avshell = p+1;
3154de51eedSBen Gras 	else
3164de51eedSBen Gras 		avshell = shell;
3174de51eedSBen Gras 
3184de51eedSBen Gras 	/* if we're forking a csh, we want to slightly muck the args */
3194de51eedSBen Gras 	if (iscsh == UNSET)
3204de51eedSBen Gras 		iscsh = strstr(avshell, "csh") ? YES : NO;
3214de51eedSBen Gras 
3224de51eedSBen Gras 	/* set permissions */
3234de51eedSBen Gras #ifdef LOGIN_CAP
3244de51eedSBen Gras # ifdef ALLOW_GROUP_CHANGE
3254de51eedSBen Gras 	/* if we aren't changing users, keep the current group members */
3264de51eedSBen Gras 	if (ruid != pwd->pw_uid &&
3274de51eedSBen Gras 	    setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) == -1)
3284de51eedSBen Gras 		err(EXIT_FAILURE, "setting user context");
3294de51eedSBen Gras 
3304de51eedSBen Gras 	addgroup(lc, gname, pwd, ruid, GROUP_PASSWORD);
3314de51eedSBen Gras 
3324de51eedSBen Gras 	if (setusercontext(lc, pwd, pwd->pw_uid,
3334de51eedSBen Gras 		(u_int)(asthem ? (LOGIN_SETPRIORITY | LOGIN_SETUMASK) : 0) |
3344de51eedSBen Gras 		LOGIN_SETRESOURCES | LOGIN_SETUSER) == -1)
3354de51eedSBen Gras 		err(EXIT_FAILURE, "setting user context");
3364de51eedSBen Gras # else
3374de51eedSBen Gras 	if (setusercontext(lc, pwd, pwd->pw_uid,
3384de51eedSBen Gras 		(u_int)(asthem ? (LOGIN_SETPRIORITY | LOGIN_SETUMASK) : 0) |
3394de51eedSBen Gras 		LOGIN_SETRESOURCES | LOGIN_SETGROUP | LOGIN_SETUSER) == -1)
3404de51eedSBen Gras 		err(EXIT_FAILURE, "setting user context");
3414de51eedSBen Gras # endif
3424de51eedSBen Gras #else
3434de51eedSBen Gras 	if (setgid(pwd->pw_gid) == -1)
3444de51eedSBen Gras 		err(EXIT_FAILURE, "setgid");
3454de51eedSBen Gras 	/* if we aren't changing users, keep the current group members */
3464de51eedSBen Gras 	if (ruid != pwd->pw_uid && initgroups(user, pwd->pw_gid) != 0)
3474de51eedSBen Gras 		errx(EXIT_FAILURE, "initgroups failed");
3484de51eedSBen Gras # ifdef ALLOW_GROUP_CHANGE
3494de51eedSBen Gras 	addgroup(/*EMPTY*/, gname, pwd, ruid, GROUP_PASSWORD);
3504de51eedSBen Gras # endif
3514de51eedSBen Gras 	if (setuid(pwd->pw_uid) == -1)
3524de51eedSBen Gras 		err(EXIT_FAILURE, "setuid");
3534de51eedSBen Gras #endif
3544de51eedSBen Gras 
3554de51eedSBen Gras 	if (!asme) {
3564de51eedSBen Gras 		if (asthem) {
3574de51eedSBen Gras 			p = getenv("TERM");
3584de51eedSBen Gras 			/* Create an empty environment */
3594de51eedSBen Gras 			environ = emalloc(sizeof(char *));
3604de51eedSBen Gras 			environ[0] = NULL;
3614de51eedSBen Gras #ifdef LOGIN_CAP
3624de51eedSBen Gras 			if (setusercontext(lc, pwd, pwd->pw_uid,
3634de51eedSBen Gras 				LOGIN_SETPATH) == -1)
3644de51eedSBen Gras 				err(EXIT_FAILURE, "setting user context");
3654de51eedSBen Gras #else
3664de51eedSBen Gras 			(void)setenv("PATH", _PATH_DEFPATH, 1);
3674de51eedSBen Gras #endif
3684de51eedSBen Gras 			if (p)
3694de51eedSBen Gras 				(void)setenv("TERM", p, 1);
3704de51eedSBen Gras 			if (gohome && chdir(pwd->pw_dir) == -1)
3714de51eedSBen Gras 				errx(EXIT_FAILURE, "no directory");
3724de51eedSBen Gras 		}
3734de51eedSBen Gras 
3744de51eedSBen Gras 		if (asthem || pwd->pw_uid) {
3754de51eedSBen Gras 			(void)setenv("LOGNAME", pwd->pw_name, 1);
3764de51eedSBen Gras 			(void)setenv("USER", pwd->pw_name, 1);
3774de51eedSBen Gras 		}
3784de51eedSBen Gras 		(void)setenv("HOME", pwd->pw_dir, 1);
3794de51eedSBen Gras 		(void)setenv("SHELL", shell, 1);
3804de51eedSBen Gras 	}
3814de51eedSBen Gras 	(void)setenv("SU_FROM", username, 1);
3824de51eedSBen Gras 
3834de51eedSBen Gras 	if (iscsh == YES) {
3844de51eedSBen Gras 		if (fastlogin)
3854de51eedSBen Gras 			*np-- = __UNCONST("-f");
3864de51eedSBen Gras 		if (asme)
3874de51eedSBen Gras 			*np-- = __UNCONST("-m");
3884de51eedSBen Gras 	} else {
3894de51eedSBen Gras 		if (fastlogin)
3904de51eedSBen Gras 			(void)unsetenv("ENV");
3914de51eedSBen Gras 	}
3924de51eedSBen Gras 
3934de51eedSBen Gras 	if (asthem) {
3944de51eedSBen Gras 		avshellbuf[0] = '-';
3954de51eedSBen Gras 		(void)estrlcpy(avshellbuf + 1, avshell, sizeof(avshellbuf) - 1);
3964de51eedSBen Gras 		avshell = avshellbuf;
3974de51eedSBen Gras 	} else if (iscsh == YES) {
3984de51eedSBen Gras 		/* csh strips the first character... */
3994de51eedSBen Gras 		avshellbuf[0] = '_';
4004de51eedSBen Gras 		(void)estrlcpy(avshellbuf + 1, avshell, sizeof(avshellbuf) - 1);
4014de51eedSBen Gras 		avshell = avshellbuf;
4024de51eedSBen Gras 	}
4034de51eedSBen Gras 	*np = __UNCONST(avshell);
4044de51eedSBen Gras 
4054de51eedSBen Gras #ifdef BSD4_4
4064de51eedSBen Gras 	if (pwd->pw_change || pwd->pw_expire)
4074de51eedSBen Gras 		(void)gettimeofday(&tp, NULL);
4084de51eedSBen Gras 	if (pwd->pw_change) {
4094de51eedSBen Gras 		if (tp.tv_sec >= pwd->pw_change) {
4104de51eedSBen Gras 			(void)printf("%s -- %s's password has expired.\n",
4114de51eedSBen Gras 				     (ruid ? "Sorry" : "Note"), user);
4124de51eedSBen Gras 			if (ruid != 0)
4134de51eedSBen Gras 				exit(EXIT_FAILURE);
4144de51eedSBen Gras 		} else if (pwd->pw_change - tp.tv_sec < pw_warntime)
4154de51eedSBen Gras 			(void)printf("Warning: %s's password expires on %s",
4164de51eedSBen Gras 				     user, ctime(&pwd->pw_change));
4174de51eedSBen Gras 	}
4184de51eedSBen Gras 	if (pwd->pw_expire) {
4194de51eedSBen Gras 		if (tp.tv_sec >= pwd->pw_expire) {
4204de51eedSBen Gras 			(void)printf("%s -- %s's account has expired.\n",
4214de51eedSBen Gras 				     (ruid ? "Sorry" : "Note"), user);
4224de51eedSBen Gras 			if (ruid != 0)
4234de51eedSBen Gras 				exit(EXIT_FAILURE);
4244de51eedSBen Gras 		} else if (pwd->pw_expire - tp.tv_sec <
4254de51eedSBen Gras 		    _PASSWORD_WARNDAYS * SECSPERDAY)
4264de51eedSBen Gras 			(void)printf("Warning: %s's account expires on %s",
4274de51eedSBen Gras 				     user, ctime(&pwd->pw_expire));
4284de51eedSBen Gras 	}
4294de51eedSBen Gras #endif
4304de51eedSBen Gras 	if (ruid != 0)
4314de51eedSBen Gras 		syslog(LOG_NOTICE, "%s to %s%s",
4324de51eedSBen Gras 		    username, pwd->pw_name, ontty());
4334de51eedSBen Gras 
4344de51eedSBen Gras 	/* Raise our priority back to what we had before */
4354de51eedSBen Gras 	(void)setpriority(PRIO_PROCESS, 0, prio);
4364de51eedSBen Gras 
4374de51eedSBen Gras 	(void)execv(shell, np);
4384de51eedSBen Gras 	err(EXIT_FAILURE, "%s", shell);
4394de51eedSBen Gras 	/* NOTREACHED */
4404de51eedSBen Gras }
4414de51eedSBen Gras 
4424de51eedSBen Gras 
4434de51eedSBen Gras #ifdef KERBEROS5
4444de51eedSBen Gras static int
kerberos5(char * username,const char * user,uid_t uid)4454de51eedSBen Gras kerberos5(char *username, const char *user, uid_t uid)
4464de51eedSBen Gras {
4474de51eedSBen Gras 	krb5_error_code ret;
4484de51eedSBen Gras 	krb5_context context;
4494de51eedSBen Gras 	krb5_principal princ = NULL;
4504de51eedSBen Gras 	krb5_ccache ccache, ccache2;
4514de51eedSBen Gras 	char *cc_name;
4524de51eedSBen Gras 	const char *filename;
4534de51eedSBen Gras 
4544de51eedSBen Gras 	ret = krb5_init_context(&context);
4554de51eedSBen Gras 	if (ret)
4564de51eedSBen Gras 		return 1;
4574de51eedSBen Gras 
4584de51eedSBen Gras 	if (strcmp(user, "root") == 0)
4594de51eedSBen Gras 		ret = krb5_make_principal(context, &princ,
4604de51eedSBen Gras 					  NULL, username, "root", NULL);
4614de51eedSBen Gras 	else
4624de51eedSBen Gras 		ret = krb5_make_principal(context, &princ,
4634de51eedSBen Gras 					  NULL, user, NULL);
4644de51eedSBen Gras 	if (ret)
4654de51eedSBen Gras 		goto fail;
4664de51eedSBen Gras 	if (!krb5_kuserok(context, princ, user) && !uid) {
4674de51eedSBen Gras 		warnx("kerberos5: not in %s's ACL.", user);
4684de51eedSBen Gras 		goto fail;
4694de51eedSBen Gras 	}
47084d9c625SLionel Sambuc 	ret = krb5_cc_new_unique(context, krb5_mcc_ops.prefix, NULL, &ccache);
4714de51eedSBen Gras 	if (ret)
4724de51eedSBen Gras 		goto fail;
4734de51eedSBen Gras 	ret = krb5_verify_user_lrealm(context, princ, ccache, NULL, TRUE,
4744de51eedSBen Gras 				      NULL);
4754de51eedSBen Gras 	if (ret) {
4764de51eedSBen Gras 		krb5_cc_destroy(context, ccache);
4774de51eedSBen Gras 		switch (ret) {
4784de51eedSBen Gras 		case KRB5_LIBOS_PWDINTR :
4794de51eedSBen Gras 			break;
4804de51eedSBen Gras 		case KRB5KRB_AP_ERR_BAD_INTEGRITY:
4814de51eedSBen Gras 		case KRB5KRB_AP_ERR_MODIFIED:
4824de51eedSBen Gras 			krb5_warnx(context, "Password incorrect");
4834de51eedSBen Gras 			break;
4844de51eedSBen Gras 		default :
4854de51eedSBen Gras 			krb5_warn(context, ret, "krb5_verify_user");
4864de51eedSBen Gras 			break;
4874de51eedSBen Gras 		}
4884de51eedSBen Gras 		goto fail;
4894de51eedSBen Gras 	}
49084d9c625SLionel Sambuc 	ret = krb5_cc_new_unique(context, krb5_mcc_ops.prefix, NULL, &ccache2);
4914de51eedSBen Gras 	if (ret) {
4924de51eedSBen Gras 		krb5_cc_destroy(context, ccache);
4934de51eedSBen Gras 		goto fail;
4944de51eedSBen Gras 	}
4954de51eedSBen Gras 	ret = krb5_cc_copy_cache(context, ccache, ccache2);
4964de51eedSBen Gras 	if (ret) {
4974de51eedSBen Gras 		krb5_cc_destroy(context, ccache);
4984de51eedSBen Gras 		krb5_cc_destroy(context, ccache2);
4994de51eedSBen Gras 		goto fail;
5004de51eedSBen Gras 	}
5014de51eedSBen Gras 
5024de51eedSBen Gras 	filename = krb5_cc_get_name(context, ccache2);
5034de51eedSBen Gras 	(void)easprintf(&cc_name, "%s:%s", krb5_cc_get_type(context, ccache2),
5044de51eedSBen Gras 		 filename);
5054de51eedSBen Gras 	if (chown(filename, uid, NOGROUP) == -1) {
5064de51eedSBen Gras 		warn("chown %s", filename);
5074de51eedSBen Gras 		free(cc_name);
5084de51eedSBen Gras 		krb5_cc_destroy(context, ccache);
5094de51eedSBen Gras 		krb5_cc_destroy(context, ccache2);
5104de51eedSBen Gras 		goto fail;
5114de51eedSBen Gras 	}
5124de51eedSBen Gras 
5134de51eedSBen Gras 	(void)setenv("KRB5CCNAME", cc_name, 1);
5144de51eedSBen Gras 	free(cc_name);
5154de51eedSBen Gras 	krb5_cc_close(context, ccache2);
5164de51eedSBen Gras 	krb5_cc_destroy(context, ccache);
5174de51eedSBen Gras 	return 0;
5184de51eedSBen Gras 
5194de51eedSBen Gras  fail:
5204de51eedSBen Gras 	if (princ != NULL)
5214de51eedSBen Gras 		krb5_free_principal(context, princ);
5224de51eedSBen Gras 	krb5_free_context(context);
5234de51eedSBen Gras 	return 1;
5244de51eedSBen Gras }
5254de51eedSBen Gras #endif /* KERBEROS5 */
5264de51eedSBen Gras 
5274de51eedSBen Gras static int
check_ingroup(int gid,const char * gname,const char * user,int ifempty)5284de51eedSBen Gras check_ingroup(int gid, const char *gname, const char *user, int ifempty)
5294de51eedSBen Gras {
5304de51eedSBen Gras 	struct group *gr;
5314de51eedSBen Gras 	char **g;
5324de51eedSBen Gras #ifdef SU_INDIRECT_GROUP
5334de51eedSBen Gras 	char **gr_mem;
5344de51eedSBen Gras 	int n = 0;
5354de51eedSBen Gras 	int i = 0;
5364de51eedSBen Gras #endif
5374de51eedSBen Gras 	int ok = 0;
5384de51eedSBen Gras 
5394de51eedSBen Gras 	if (gname == NULL)
5404de51eedSBen Gras 		gr = getgrgid((gid_t) gid);
5414de51eedSBen Gras 	else
5424de51eedSBen Gras 		gr = getgrnam(gname);
5434de51eedSBen Gras 
5444de51eedSBen Gras 	/*
5454de51eedSBen Gras 	 * XXX we are relying on the fact that we only set ifempty when
5464de51eedSBen Gras 	 * calling to check for SU_GROUP and that is the only time a
5474de51eedSBen Gras 	 * missing group is acceptable.
5484de51eedSBen Gras 	 */
5494de51eedSBen Gras 	if (gr == NULL)
5504de51eedSBen Gras 		return ifempty;
5514de51eedSBen Gras 	if (!*gr->gr_mem)		/* empty */
5524de51eedSBen Gras 		return ifempty;
5534de51eedSBen Gras 
5544de51eedSBen Gras 	/*
5554de51eedSBen Gras 	 * Ok, first see if user is in gr_mem
5564de51eedSBen Gras 	 */
5574de51eedSBen Gras 	for (g = gr->gr_mem; *g; ++g) {
5584de51eedSBen Gras 		if (strcmp(*g, user) == 0)
5594de51eedSBen Gras 			return 1;	/* ok */
5604de51eedSBen Gras #ifdef SU_INDIRECT_GROUP
5614de51eedSBen Gras 		++n;			/* count them */
5624de51eedSBen Gras #endif
5634de51eedSBen Gras 	}
5644de51eedSBen Gras #ifdef SU_INDIRECT_GROUP
5654de51eedSBen Gras 	/*
5664de51eedSBen Gras 	 * No.
5674de51eedSBen Gras 	 * Now we need to duplicate the gr_mem list, and recurse for
5684de51eedSBen Gras 	 * each member to see if it is a group, and if so whether user is
5694de51eedSBen Gras 	 * in it.
5704de51eedSBen Gras 	 */
5714de51eedSBen Gras 	gr_mem = emalloc((n + 1) * sizeof (char *));
5724de51eedSBen Gras 	for (g = gr->gr_mem, i = 0; *g; ++g) {
5734de51eedSBen Gras 		gr_mem[i] = estrdup(*g);
5744de51eedSBen Gras 		i++;
5754de51eedSBen Gras 	}
5764de51eedSBen Gras 	gr_mem[i++] = NULL;
5774de51eedSBen Gras 
5784de51eedSBen Gras 	for (g = gr_mem; ok == 0 && *g; ++g) {
5794de51eedSBen Gras 		/*
5804de51eedSBen Gras 		 * If we get this far we don't accept empty/missing groups.
5814de51eedSBen Gras 		 */
5824de51eedSBen Gras 		ok = check_ingroup(-1, *g, user, 0);
5834de51eedSBen Gras 	}
5844de51eedSBen Gras 	for (g = gr_mem; *g; ++g) {
5854de51eedSBen Gras 		free(*g);
5864de51eedSBen Gras 	}
5874de51eedSBen Gras 	free(gr_mem);
5884de51eedSBen Gras #endif
5894de51eedSBen Gras 	return ok;
5904de51eedSBen Gras }
591