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