1*0a6a1f1dSLionel Sambuc /* $NetBSD: su_pam.c,v 1.20 2015/08/09 09:39:21 shm 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_pam.c,v 1.20 2015/08/09 09:39:21 shm 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 <sys/wait.h>
504de51eedSBen Gras #include <err.h>
514de51eedSBen Gras #include <errno.h>
524de51eedSBen Gras #include <grp.h>
534de51eedSBen Gras #include <paths.h>
544de51eedSBen Gras #include <pwd.h>
554de51eedSBen Gras #include <signal.h>
564de51eedSBen Gras #include <stdio.h>
574de51eedSBen Gras #include <stdlib.h>
584de51eedSBen Gras #include <string.h>
594de51eedSBen Gras #include <syslog.h>
604de51eedSBen Gras #include <time.h>
614de51eedSBen Gras #include <tzfile.h>
624de51eedSBen Gras #include <unistd.h>
634de51eedSBen Gras #include <util.h>
644de51eedSBen Gras #include <login_cap.h>
654de51eedSBen Gras
664de51eedSBen Gras #include <security/pam_appl.h>
674de51eedSBen Gras #include <security/openpam.h> /* for openpam_ttyconv() */
684de51eedSBen Gras
694de51eedSBen Gras #ifdef ALLOW_GROUP_CHANGE
704de51eedSBen Gras #include "grutil.h"
714de51eedSBen Gras #endif
724de51eedSBen Gras #include "suutil.h"
734de51eedSBen Gras
744de51eedSBen Gras static const struct pam_conv pamc = { &openpam_ttyconv, NULL };
754de51eedSBen Gras
764de51eedSBen Gras #define ARGSTRX "-dflm"
774de51eedSBen Gras
784de51eedSBen Gras #ifdef LOGIN_CAP
794de51eedSBen Gras #define ARGSTR ARGSTRX "c:"
804de51eedSBen Gras #else
814de51eedSBen Gras #define ARGSTR ARGSTRX
824de51eedSBen Gras #endif
834de51eedSBen Gras
8484d9c625SLionel Sambuc static void logit(const char *, ...) __printflike(1, 2);
8584d9c625SLionel Sambuc
8684d9c625SLionel Sambuc static const char *
safe_pam_strerror(pam_handle_t * pamh,int pam_err)8784d9c625SLionel Sambuc safe_pam_strerror(pam_handle_t *pamh, int pam_err) {
8884d9c625SLionel Sambuc const char *msg;
8984d9c625SLionel Sambuc
9084d9c625SLionel Sambuc if ((msg = pam_strerror(pamh, pam_err)) != NULL)
9184d9c625SLionel Sambuc return msg;
9284d9c625SLionel Sambuc
9384d9c625SLionel Sambuc static char buf[1024];
9484d9c625SLionel Sambuc snprintf(buf, sizeof(buf), "Unknown pam error %d", pam_err);
9584d9c625SLionel Sambuc return buf;
9684d9c625SLionel Sambuc }
974de51eedSBen Gras
984de51eedSBen Gras int
main(int argc,char ** argv)994de51eedSBen Gras main(int argc, char **argv)
1004de51eedSBen Gras {
1014de51eedSBen Gras extern char **environ;
1024de51eedSBen Gras struct passwd *pwd, pwres;
1034de51eedSBen Gras char *p;
1044de51eedSBen Gras uid_t ruid;
1054de51eedSBen Gras int asme, ch, asthem, fastlogin, prio, gohome;
1064de51eedSBen Gras u_int setwhat;
1074de51eedSBen Gras enum { UNSET, YES, NO } iscsh = UNSET;
1084de51eedSBen Gras const char *user, *shell, *avshell;
1094de51eedSBen Gras char *username, *class;
1104de51eedSBen Gras char **np;
1114de51eedSBen Gras char shellbuf[MAXPATHLEN], avshellbuf[MAXPATHLEN];
1124de51eedSBen Gras int pam_err;
1134de51eedSBen Gras char hostname[MAXHOSTNAMELEN];
1144de51eedSBen Gras char *tty;
1154de51eedSBen Gras const char *func;
1164de51eedSBen Gras const void *newuser;
1174de51eedSBen Gras login_cap_t *lc;
1184de51eedSBen Gras pam_handle_t *pamh = NULL;
1194de51eedSBen Gras char pwbuf[1024];
1204de51eedSBen Gras #ifdef PAM_DEBUG
1214de51eedSBen Gras extern int _openpam_debug;
1224de51eedSBen Gras
1234de51eedSBen Gras _openpam_debug = 1;
1244de51eedSBen Gras #endif
1254de51eedSBen Gras #ifdef ALLOW_GROUP_CHANGE
1264de51eedSBen Gras char *gname;
1274de51eedSBen Gras #endif
1284de51eedSBen Gras
1294de51eedSBen Gras (void)setprogname(argv[0]);
1304de51eedSBen Gras asme = asthem = fastlogin = 0;
1314de51eedSBen Gras gohome = 1;
1324de51eedSBen Gras shell = class = NULL;
1334de51eedSBen Gras while ((ch = getopt(argc, argv, ARGSTR)) != -1)
1344de51eedSBen Gras switch((char)ch) {
1354de51eedSBen Gras case 'c':
1364de51eedSBen Gras class = optarg;
1374de51eedSBen Gras break;
1384de51eedSBen Gras case 'd':
1394de51eedSBen Gras asme = 0;
1404de51eedSBen Gras asthem = 1;
1414de51eedSBen Gras gohome = 0;
1424de51eedSBen Gras break;
1434de51eedSBen Gras case 'f':
1444de51eedSBen Gras fastlogin = 1;
1454de51eedSBen Gras break;
1464de51eedSBen Gras case '-':
1474de51eedSBen Gras case 'l':
1484de51eedSBen Gras asme = 0;
1494de51eedSBen Gras asthem = 1;
1504de51eedSBen Gras break;
1514de51eedSBen Gras case 'm':
1524de51eedSBen Gras asme = 1;
1534de51eedSBen Gras asthem = 0;
1544de51eedSBen Gras break;
1554de51eedSBen Gras case '?':
1564de51eedSBen Gras default:
1574de51eedSBen Gras (void)fprintf(stderr,
1584de51eedSBen Gras #ifdef ALLOW_GROUP_CHANGE
1594de51eedSBen Gras "Usage: %s [%s] [login[:group] [shell arguments]]\n",
1604de51eedSBen Gras #else
1614de51eedSBen Gras "Usage: %s [%s] [login [shell arguments]]\n",
1624de51eedSBen Gras #endif
1634de51eedSBen Gras getprogname(), ARGSTR);
1644de51eedSBen Gras exit(EXIT_FAILURE);
1654de51eedSBen Gras }
1664de51eedSBen Gras argv += optind;
1674de51eedSBen Gras
1684de51eedSBen Gras /* Lower the priority so su runs faster */
1694de51eedSBen Gras errno = 0;
1704de51eedSBen Gras prio = getpriority(PRIO_PROCESS, 0);
1714de51eedSBen Gras if (errno)
1724de51eedSBen Gras prio = 0;
1734de51eedSBen Gras if (prio > -2)
1744de51eedSBen Gras (void)setpriority(PRIO_PROCESS, 0, -2);
1754de51eedSBen Gras openlog("su", 0, LOG_AUTH);
1764de51eedSBen Gras
1774de51eedSBen Gras /* get current login name and shell */
1784de51eedSBen Gras ruid = getuid();
1794de51eedSBen Gras username = getlogin();
1804de51eedSBen Gras if (username == NULL ||
1814de51eedSBen Gras getpwnam_r(username, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
1824de51eedSBen Gras pwd == NULL || pwd->pw_uid != ruid) {
1834de51eedSBen Gras if (getpwuid_r(ruid, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0)
1844de51eedSBen Gras pwd = NULL;
1854de51eedSBen Gras }
1864de51eedSBen Gras if (pwd == NULL)
1874de51eedSBen Gras errx(EXIT_FAILURE, "who are you?");
1884de51eedSBen Gras username = estrdup(pwd->pw_name);
1894de51eedSBen Gras
1904de51eedSBen Gras if (asme) {
1914de51eedSBen Gras if (pwd->pw_shell && *pwd->pw_shell) {
1924de51eedSBen Gras (void)estrlcpy(shellbuf, pwd->pw_shell, sizeof(shellbuf));
1934de51eedSBen Gras shell = shellbuf;
1944de51eedSBen Gras } else {
1954de51eedSBen Gras shell = _PATH_BSHELL;
1964de51eedSBen Gras iscsh = NO;
1974de51eedSBen Gras }
1984de51eedSBen Gras }
1994de51eedSBen Gras /* get target login information, default to root */
2004de51eedSBen Gras user = *argv ? *argv : "root";
2014de51eedSBen Gras np = *argv ? argv : argv - 1;
2024de51eedSBen Gras
2034de51eedSBen Gras #ifdef ALLOW_GROUP_CHANGE
2044de51eedSBen Gras if ((p = strchr(user, ':')) != NULL) {
2054de51eedSBen Gras *p = '\0';
2064de51eedSBen Gras gname = ++p;
2074de51eedSBen Gras }
2084de51eedSBen Gras else
2094de51eedSBen Gras gname = NULL;
2104de51eedSBen Gras
2114de51eedSBen Gras #ifdef ALLOW_EMPTY_USER
2124de51eedSBen Gras if (user[0] == '\0')
2134de51eedSBen Gras user = username;
2144de51eedSBen Gras #endif
2154de51eedSBen Gras #endif
2164de51eedSBen Gras if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
2174de51eedSBen Gras pwd == NULL)
2184de51eedSBen Gras errx(EXIT_FAILURE, "unknown login %s", user);
2194de51eedSBen Gras
2204de51eedSBen Gras /*
2214de51eedSBen Gras * PAM initialization
2224de51eedSBen Gras */
2234de51eedSBen Gras #define PAM_END(msg) do { func = msg; goto done;} /* NOTREACHED */ while (/*CONSTCOND*/0)
2244de51eedSBen Gras
2254de51eedSBen Gras if ((pam_err = pam_start("su", user, &pamc, &pamh)) != PAM_SUCCESS) {
2264de51eedSBen Gras if (pamh != NULL)
2274de51eedSBen Gras PAM_END("pam_start");
2284de51eedSBen Gras /* Things went really bad... */
2294de51eedSBen Gras syslog(LOG_ERR, "pam_start failed: %s",
23084d9c625SLionel Sambuc safe_pam_strerror(pamh, pam_err));
2314de51eedSBen Gras errx(EXIT_FAILURE, "pam_start failed");
2324de51eedSBen Gras }
2334de51eedSBen Gras
2344de51eedSBen Gras #define PAM_END_ITEM(item) PAM_END("pam_set_item(" # item ")")
2354de51eedSBen Gras #define PAM_SET_ITEM(item, var) \
2364de51eedSBen Gras if ((pam_err = pam_set_item(pamh, (item), (var))) != PAM_SUCCESS) \
2374de51eedSBen Gras PAM_END_ITEM(item)
2384de51eedSBen Gras
2394de51eedSBen Gras /*
2404de51eedSBen Gras * Fill hostname, username and tty
2414de51eedSBen Gras */
2424de51eedSBen Gras PAM_SET_ITEM(PAM_RUSER, username);
2434de51eedSBen Gras if (gethostname(hostname, sizeof(hostname)) != -1)
2444de51eedSBen Gras PAM_SET_ITEM(PAM_RHOST, hostname);
2454de51eedSBen Gras
2464de51eedSBen Gras if ((tty = ttyname(STDERR_FILENO)) != NULL)
2474de51eedSBen Gras PAM_SET_ITEM(PAM_TTY, tty);
2484de51eedSBen Gras
2494de51eedSBen Gras /*
2504de51eedSBen Gras * Authentication
2514de51eedSBen Gras */
2524de51eedSBen Gras if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
2534de51eedSBen Gras syslog(LOG_WARNING, "BAD SU %s to %s%s: %s",
25484d9c625SLionel Sambuc username, user, ontty(), safe_pam_strerror(pamh, pam_err));
2554de51eedSBen Gras (void)pam_end(pamh, pam_err);
256*0a6a1f1dSLionel Sambuc errx(EXIT_FAILURE, "Sorry: %s", safe_pam_strerror(NULL, pam_err));
2574de51eedSBen Gras }
2584de51eedSBen Gras
2594de51eedSBen Gras /*
2604de51eedSBen Gras * Authorization
2614de51eedSBen Gras */
2624de51eedSBen Gras switch(pam_err = pam_acct_mgmt(pamh, 0)) {
2634de51eedSBen Gras case PAM_NEW_AUTHTOK_REQD:
2644de51eedSBen Gras pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
2654de51eedSBen Gras if (pam_err != PAM_SUCCESS)
2664de51eedSBen Gras PAM_END("pam_chauthok");
2674de51eedSBen Gras break;
2684de51eedSBen Gras case PAM_SUCCESS:
2694de51eedSBen Gras break;
2704de51eedSBen Gras default:
2714de51eedSBen Gras PAM_END("pam_acct_mgmt");
2724de51eedSBen Gras break;
2734de51eedSBen Gras }
2744de51eedSBen Gras
2754de51eedSBen Gras /*
2764de51eedSBen Gras * pam_authenticate might have changed the target user.
2774de51eedSBen Gras * refresh pwd and user
2784de51eedSBen Gras */
2794de51eedSBen Gras pam_err = pam_get_item(pamh, PAM_USER, &newuser);
2804de51eedSBen Gras if (pam_err != PAM_SUCCESS) {
2814de51eedSBen Gras syslog(LOG_WARNING,
28284d9c625SLionel Sambuc "pam_get_item(PAM_USER): %s", safe_pam_strerror(pamh, pam_err));
2834de51eedSBen Gras } else {
2844de51eedSBen Gras user = (char *)__UNCONST(newuser);
2854de51eedSBen Gras if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
2864de51eedSBen Gras pwd == NULL) {
2874de51eedSBen Gras (void)pam_end(pamh, pam_err);
2884de51eedSBen Gras syslog(LOG_ERR, "unknown login: %s", username);
2894de51eedSBen Gras errx(EXIT_FAILURE, "unknown login: %s", username);
2904de51eedSBen Gras }
2914de51eedSBen Gras }
2924de51eedSBen Gras
2934de51eedSBen Gras #define ERRX_PAM_END(args) do { \
2944de51eedSBen Gras (void)pam_end(pamh, pam_err); \
2954de51eedSBen Gras errx args; \
2964de51eedSBen Gras } while (/* CONSTCOND */0)
2974de51eedSBen Gras
2984de51eedSBen Gras #define ERR_PAM_END(args) do { \
2994de51eedSBen Gras (void)pam_end(pamh, pam_err); \
3004de51eedSBen Gras err args; \
3014de51eedSBen Gras } while (/* CONSTCOND */0)
3024de51eedSBen Gras
3034de51eedSBen Gras /* force the usage of specified class */
3044de51eedSBen Gras if (class) {
3054de51eedSBen Gras if (ruid)
3064de51eedSBen Gras ERRX_PAM_END((EXIT_FAILURE, "Only root may use -c"));
3074de51eedSBen Gras
3084de51eedSBen Gras pwd->pw_class = class;
3094de51eedSBen Gras }
3104de51eedSBen Gras
3114de51eedSBen Gras if ((lc = login_getclass(pwd->pw_class)) == NULL)
3124de51eedSBen Gras ERRX_PAM_END((EXIT_FAILURE,
3134de51eedSBen Gras "Unknown class %s\n", pwd->pw_class));
3144de51eedSBen Gras
3154de51eedSBen Gras if (asme) {
3164de51eedSBen Gras /* if asme and non-standard target shell, must be root */
3174de51eedSBen Gras if (chshell(pwd->pw_shell) == 0 && ruid)
3184de51eedSBen Gras ERRX_PAM_END((EXIT_FAILURE,
3194de51eedSBen Gras "permission denied (shell)."));
3204de51eedSBen Gras } else if (pwd->pw_shell && *pwd->pw_shell) {
3214de51eedSBen Gras shell = pwd->pw_shell;
3224de51eedSBen Gras iscsh = UNSET;
3234de51eedSBen Gras } else {
3244de51eedSBen Gras shell = _PATH_BSHELL;
3254de51eedSBen Gras iscsh = NO;
3264de51eedSBen Gras }
3274de51eedSBen Gras
3284de51eedSBen Gras if ((p = strrchr(shell, '/')) != NULL)
3294de51eedSBen Gras avshell = p + 1;
3304de51eedSBen Gras else
3314de51eedSBen Gras avshell = shell;
3324de51eedSBen Gras
3334de51eedSBen Gras /* if we're forking a csh, we want to slightly muck the args */
3344de51eedSBen Gras if (iscsh == UNSET)
3354de51eedSBen Gras iscsh = strstr(avshell, "csh") ? YES : NO;
3364de51eedSBen Gras
3374de51eedSBen Gras /*
3384de51eedSBen Gras * Initialize the supplemental groups before pam gets to them,
3394de51eedSBen Gras * so that other pam modules get a chance to add more when
3404de51eedSBen Gras * we do setcred. Note, we don't relinguish our set-userid yet
3414de51eedSBen Gras */
3424de51eedSBen Gras /* if we aren't changing users, keep the current group members */
3434de51eedSBen Gras if (ruid != pwd->pw_uid &&
3444de51eedSBen Gras setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) == -1)
3454de51eedSBen Gras ERR_PAM_END((EXIT_FAILURE, "setting user context"));
3464de51eedSBen Gras
3474de51eedSBen Gras #ifdef ALLOW_GROUP_CHANGE
3484de51eedSBen Gras addgroup(lc, gname, pwd, ruid, "Group Password:");
3494de51eedSBen Gras #endif
3504de51eedSBen Gras if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
3514de51eedSBen Gras PAM_END("pam_setcred");
3524de51eedSBen Gras
3534de51eedSBen Gras /*
3544de51eedSBen Gras * Manage session.
3554de51eedSBen Gras */
3564de51eedSBen Gras if (asthem) {
3574de51eedSBen Gras pid_t pid, xpid;
3584de51eedSBen Gras int status = 1;
3594de51eedSBen Gras struct sigaction sa, sa_int, sa_pipe, sa_quit;
3604de51eedSBen Gras int fds[2];
3614de51eedSBen Gras
3624de51eedSBen Gras if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
3634de51eedSBen Gras PAM_END("pam_open_session");
3644de51eedSBen Gras
3654de51eedSBen Gras /*
3664de51eedSBen Gras * In order to call pam_close_session after the
3674de51eedSBen Gras * command terminates, we need to fork.
3684de51eedSBen Gras */
3694de51eedSBen Gras sa.sa_flags = SA_RESTART;
3704de51eedSBen Gras sa.sa_handler = SIG_IGN;
3714de51eedSBen Gras (void)sigemptyset(&sa.sa_mask);
3724de51eedSBen Gras (void)sigaction(SIGINT, &sa, &sa_int);
3734de51eedSBen Gras (void)sigaction(SIGQUIT, &sa, &sa_quit);
3744de51eedSBen Gras (void)sigaction(SIGPIPE, &sa, &sa_pipe);
3754de51eedSBen Gras sa.sa_handler = SIG_DFL;
3764de51eedSBen Gras (void)sigaction(SIGTSTP, &sa, NULL);
3774de51eedSBen Gras /*
3784de51eedSBen Gras * Use a pipe to guarantee the order of execution of
3794de51eedSBen Gras * the parent and the child.
3804de51eedSBen Gras */
3814de51eedSBen Gras if (pipe(fds) == -1) {
3824de51eedSBen Gras warn("pipe failed");
3834de51eedSBen Gras goto out;
3844de51eedSBen Gras }
3854de51eedSBen Gras
3864de51eedSBen Gras switch (pid = fork()) {
3874de51eedSBen Gras case -1:
3884de51eedSBen Gras logit("fork failed (%s)", strerror(errno));
3894de51eedSBen Gras goto out;
3904de51eedSBen Gras
3914de51eedSBen Gras case 0: /* Child */
3924de51eedSBen Gras (void)close(fds[1]);
3934de51eedSBen Gras (void)read(fds[0], &status, 1);
3944de51eedSBen Gras (void)close(fds[0]);
3954de51eedSBen Gras (void)sigaction(SIGINT, &sa_int, NULL);
3964de51eedSBen Gras (void)sigaction(SIGQUIT, &sa_quit, NULL);
3974de51eedSBen Gras (void)sigaction(SIGPIPE, &sa_pipe, NULL);
3984de51eedSBen Gras break;
3994de51eedSBen Gras
4004de51eedSBen Gras default:
4014de51eedSBen Gras sa.sa_handler = SIG_IGN;
4024de51eedSBen Gras (void)sigaction(SIGTTOU, &sa, NULL);
4034de51eedSBen Gras (void)close(fds[0]);
4044de51eedSBen Gras (void)setpgid(pid, pid);
4054de51eedSBen Gras (void)tcsetpgrp(STDERR_FILENO, pid);
4064de51eedSBen Gras (void)close(fds[1]);
4074de51eedSBen Gras (void)sigaction(SIGPIPE, &sa_pipe, NULL);
4084de51eedSBen Gras /*
4094de51eedSBen Gras * Parent: wait for the child to terminate
4104de51eedSBen Gras * and call pam_close_session.
4114de51eedSBen Gras */
4124de51eedSBen Gras while ((xpid = waitpid(pid, &status, WUNTRACED))
4134de51eedSBen Gras == pid) {
4144de51eedSBen Gras if (WIFSTOPPED(status)) {
4154de51eedSBen Gras (void)kill(getpid(), SIGSTOP);
4164de51eedSBen Gras (void)tcsetpgrp(STDERR_FILENO,
4174de51eedSBen Gras getpgid(pid));
4184de51eedSBen Gras (void)kill(pid, SIGCONT);
4194de51eedSBen Gras status = 1;
4204de51eedSBen Gras continue;
4214de51eedSBen Gras }
4224de51eedSBen Gras break;
4234de51eedSBen Gras }
4244de51eedSBen Gras
4254de51eedSBen Gras (void)tcsetpgrp(STDERR_FILENO, getpgid(0));
4264de51eedSBen Gras
4274de51eedSBen Gras if (xpid == -1) {
4284de51eedSBen Gras logit("Error waiting for pid %d (%s)", pid,
4294de51eedSBen Gras strerror(errno));
4304de51eedSBen Gras } else if (xpid != pid) {
4314de51eedSBen Gras /* Can't happen. */
4324de51eedSBen Gras logit("Wrong PID: %d != %d", pid, xpid);
4334de51eedSBen Gras }
4344de51eedSBen Gras out:
4354de51eedSBen Gras pam_err = pam_setcred(pamh, PAM_DELETE_CRED);
4364de51eedSBen Gras if (pam_err != PAM_SUCCESS)
4374de51eedSBen Gras logit("pam_setcred: %s",
43884d9c625SLionel Sambuc safe_pam_strerror(pamh, pam_err));
4394de51eedSBen Gras pam_err = pam_close_session(pamh, 0);
4404de51eedSBen Gras if (pam_err != PAM_SUCCESS)
4414de51eedSBen Gras logit("pam_close_session: %s",
44284d9c625SLionel Sambuc safe_pam_strerror(pamh, pam_err));
4434de51eedSBen Gras (void)pam_end(pamh, pam_err);
4444de51eedSBen Gras exit(WEXITSTATUS(status));
4454de51eedSBen Gras break;
4464de51eedSBen Gras }
4474de51eedSBen Gras }
4484de51eedSBen Gras
4494de51eedSBen Gras /*
4504de51eedSBen Gras * The child: starting here, we don't have to care about
4514de51eedSBen Gras * handling PAM issues if we exit, the parent will do the
4524de51eedSBen Gras * job when we exit.
4534de51eedSBen Gras */
4544de51eedSBen Gras #undef PAM_END
4554de51eedSBen Gras #undef ERR_PAM_END
4564de51eedSBen Gras #undef ERRX_PAM_END
4574de51eedSBen Gras
4584de51eedSBen Gras if (!asme) {
4594de51eedSBen Gras if (asthem) {
4604de51eedSBen Gras char **pamenv;
4614de51eedSBen Gras
4624de51eedSBen Gras p = getenv("TERM");
4634de51eedSBen Gras /*
4644de51eedSBen Gras * Create an empty environment
4654de51eedSBen Gras */
4664de51eedSBen Gras environ = emalloc(sizeof(char *));
4674de51eedSBen Gras environ[0] = NULL;
4684de51eedSBen Gras
4694de51eedSBen Gras /*
4704de51eedSBen Gras * Add PAM environement, before the LOGIN_CAP stuff:
4714de51eedSBen Gras * if the login class is unspecified, we'll get the
4724de51eedSBen Gras * same data from PAM, if -c was used, the specified
4734de51eedSBen Gras * class must override PAM.
4744de51eedSBen Gras */
4754de51eedSBen Gras if ((pamenv = pam_getenvlist(pamh)) != NULL) {
4764de51eedSBen Gras char **envitem;
4774de51eedSBen Gras
4784de51eedSBen Gras /*
4794de51eedSBen Gras * XXX Here FreeBSD filters out
4804de51eedSBen Gras * SHELL, LOGNAME, MAIL, CDPATH, IFS, PATH
4814de51eedSBen Gras * how could we get untrusted data here?
4824de51eedSBen Gras */
4834de51eedSBen Gras for (envitem = pamenv; *envitem; envitem++) {
4844de51eedSBen Gras if (putenv(*envitem) == -1)
4854de51eedSBen Gras free(*envitem);
4864de51eedSBen Gras }
4874de51eedSBen Gras
4884de51eedSBen Gras free(pamenv);
4894de51eedSBen Gras }
4904de51eedSBen Gras
4914de51eedSBen Gras if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH |
4924de51eedSBen Gras LOGIN_SETENV | LOGIN_SETUMASK) == -1)
4934de51eedSBen Gras err(EXIT_FAILURE, "setting user context");
4944de51eedSBen Gras if (p)
4954de51eedSBen Gras (void)setenv("TERM", p, 1);
4964de51eedSBen Gras }
4974de51eedSBen Gras
4984de51eedSBen Gras if (asthem || pwd->pw_uid) {
4994de51eedSBen Gras (void)setenv("LOGNAME", pwd->pw_name, 1);
5004de51eedSBen Gras (void)setenv("USER", pwd->pw_name, 1);
5014de51eedSBen Gras }
5024de51eedSBen Gras (void)setenv("HOME", pwd->pw_dir, 1);
5034de51eedSBen Gras (void)setenv("SHELL", shell, 1);
5044de51eedSBen Gras }
5054de51eedSBen Gras (void)setenv("SU_FROM", username, 1);
5064de51eedSBen Gras
5074de51eedSBen Gras if (iscsh == YES) {
5084de51eedSBen Gras if (fastlogin)
5094de51eedSBen Gras *np-- = __UNCONST("-f");
5104de51eedSBen Gras if (asme)
5114de51eedSBen Gras *np-- = __UNCONST("-m");
5124de51eedSBen Gras } else {
5134de51eedSBen Gras if (fastlogin)
5144de51eedSBen Gras (void)unsetenv("ENV");
5154de51eedSBen Gras }
5164de51eedSBen Gras
5174de51eedSBen Gras if (asthem) {
5184de51eedSBen Gras avshellbuf[0] = '-';
5194de51eedSBen Gras (void)estrlcpy(avshellbuf + 1, avshell, sizeof(avshellbuf) - 1);
5204de51eedSBen Gras avshell = avshellbuf;
5214de51eedSBen Gras } else if (iscsh == YES) {
5224de51eedSBen Gras /* csh strips the first character... */
5234de51eedSBen Gras avshellbuf[0] = '_';
5244de51eedSBen Gras (void)estrlcpy(avshellbuf + 1, avshell, sizeof(avshellbuf) - 1);
5254de51eedSBen Gras avshell = avshellbuf;
5264de51eedSBen Gras }
5274de51eedSBen Gras *np = __UNCONST(avshell);
5284de51eedSBen Gras
5294de51eedSBen Gras if (ruid != 0)
5304de51eedSBen Gras syslog(LOG_NOTICE, "%s to %s%s",
5314de51eedSBen Gras username, pwd->pw_name, ontty());
5324de51eedSBen Gras
5334de51eedSBen Gras /* Raise our priority back to what we had before */
5344de51eedSBen Gras (void)setpriority(PRIO_PROCESS, 0, prio);
5354de51eedSBen Gras
5364de51eedSBen Gras /*
5374de51eedSBen Gras * Set user context, except for umask, and the stuff
5384de51eedSBen Gras * we have done before.
5394de51eedSBen Gras */
5404de51eedSBen Gras setwhat = LOGIN_SETALL & ~(LOGIN_SETENV | LOGIN_SETUMASK |
5414de51eedSBen Gras LOGIN_SETLOGIN | LOGIN_SETPATH | LOGIN_SETGROUP);
5424de51eedSBen Gras
5434de51eedSBen Gras /*
5444de51eedSBen Gras * Don't touch resource/priority settings if -m has been used
5454de51eedSBen Gras * or -l and -c hasn't, and we're not su'ing to root.
5464de51eedSBen Gras */
5474de51eedSBen Gras if ((asme || (!asthem && class == NULL)) && pwd->pw_uid)
5484de51eedSBen Gras setwhat &= ~(LOGIN_SETPRIORITY | LOGIN_SETRESOURCES);
5494de51eedSBen Gras
5504de51eedSBen Gras if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) == -1)
5514de51eedSBen Gras err(EXIT_FAILURE, "setusercontext");
5524de51eedSBen Gras
55384d9c625SLionel Sambuc if (!asme) {
55484d9c625SLionel Sambuc if (asthem) {
55584d9c625SLionel Sambuc if (gohome && chdir(pwd->pw_dir) == -1)
55684d9c625SLionel Sambuc errx(EXIT_FAILURE, "no directory");
55784d9c625SLionel Sambuc }
55884d9c625SLionel Sambuc }
55984d9c625SLionel Sambuc
5604de51eedSBen Gras (void)execv(shell, np);
5614de51eedSBen Gras err(EXIT_FAILURE, "%s", shell);
5624de51eedSBen Gras done:
56384d9c625SLionel Sambuc logit("%s: %s", func, safe_pam_strerror(pamh, pam_err));
5644de51eedSBen Gras (void)pam_end(pamh, pam_err);
5654de51eedSBen Gras return EXIT_FAILURE;
5664de51eedSBen Gras }
5674de51eedSBen Gras
5684de51eedSBen Gras static void
logit(const char * fmt,...)5694de51eedSBen Gras logit(const char *fmt, ...)
5704de51eedSBen Gras {
5714de51eedSBen Gras va_list ap;
5724de51eedSBen Gras
5734de51eedSBen Gras va_start(ap, fmt);
5744de51eedSBen Gras vwarnx(fmt, ap);
57584d9c625SLionel Sambuc va_end(ap);
57684d9c625SLionel Sambuc va_start(ap, fmt);
5774de51eedSBen Gras vsyslog(LOG_ERR, fmt, ap);
5784de51eedSBen Gras va_end(ap);
5794de51eedSBen Gras }
580