From 5fd83771641d15c418f747bd343ba6738d3875f7 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Sun, 9 May 2021 14:20:58 -0400 Subject: Import macOS userland adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106 --- shell_cmds/su/su.1 | 213 +++++++++++ shell_cmds/su/su.c | 737 ++++++++++++++++++++++++++++++++++++ shell_cmds/su/su.pam | 7 + shell_cmds/su/su_entitlements.plist | 10 + 4 files changed, 967 insertions(+) create mode 100644 shell_cmds/su/su.1 create mode 100644 shell_cmds/su/su.c create mode 100644 shell_cmds/su/su.pam create mode 100644 shell_cmds/su/su_entitlements.plist (limited to 'shell_cmds/su') diff --git a/shell_cmds/su/su.1 b/shell_cmds/su/su.1 new file mode 100644 index 0000000..014a567 --- /dev/null +++ b/shell_cmds/su/su.1 @@ -0,0 +1,213 @@ +.\" Copyright (c) 1988, 1990, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)su.1 8.2 (Berkeley) 4/18/94 +.\" $FreeBSD: src/usr.bin/su/su.1,v 1.40 2007/07/24 06:41:07 delphij Exp $ +.\" +.Dd September 13, 2006 +.Dt SU 1 +.Os +.Sh NAME +.Nm su +.Nd substitute user identity +.Sh SYNOPSIS +.Nm +.Op Fl +.Op Fl flm +.Op Ar login Op Ar args +.Sh DESCRIPTION +The +.Nm +utility requests appropriate user credentials via PAM +and switches to that user ID +(the default user is the superuser). +A shell is then executed. +.Pp +PAM is used to set the policy +.Xr su 1 +will use. +In particular, by default only users in the +.Dq Li admin +or +.Dq Li wheel +groups can switch to UID 0 +.Pq Dq Li root . +This group requirement may be changed by modifying the +.Dq Li pam_group +section of +.Pa /etc/pam.d/su . +See +.Xr pam_group 8 +for details on how to modify this setting. +.Pp +By default, the environment is unmodified with the exception of +.Ev USER , +.Ev HOME , +and +.Ev SHELL . +.Ev HOME +and +.Ev SHELL +are set to the target login's default values. +.Ev USER +is set to the target login, unless the target login has a user ID of 0, +in which case it is unmodified. +The invoked shell is the one belonging to the target login. +This is the traditional behavior of +.Nm . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl f +If the invoked shell is +.Xr csh 1 , +this option prevents it from reading the +.Dq Pa .cshrc +file. +.It Fl l +Simulate a full login. +The environment is discarded except for +.Ev HOME , +.Ev SHELL , +.Ev PATH , +.Ev TERM , +and +.Ev USER . +.Ev HOME +and +.Ev SHELL +are modified as above. +.Ev USER +is set to the target login. +.Ev PATH +is set to +.Dq Pa /bin:/usr/bin . +.Ev TERM +is imported from your current environment. +The invoked shell is the target login's, and +.Nm +will change directory to the target login's home directory. +.It Fl +(no letter) The same as +.Fl l . +.It Fl m +Leave the environment unmodified. +The invoked shell is your login shell, and no directory changes are made. +As a security precaution, if the target user's shell is a non-standard +shell (as defined by +.Xr getusershell 3 ) +and the caller's real uid is +non-zero, +.Nm +will fail. +.El +.Pp +The +.Fl l +(or +.Fl ) +and +.Fl m +options are mutually exclusive; the last one specified +overrides any previous ones. +.Pp +If the optional +.Ar args +are provided on the command line, they are passed to the login shell of +the target login. +Note that all command line arguments before the target login name are +processed by +.Nm +itself, everything after the target login name gets passed to the login +shell. +.Pp +By default (unless the prompt is reset by a startup file) the super-user +prompt is set to +.Dq Sy \&# +to remind one of its awesome power. +.Sh ENVIRONMENT +Environment variables used by +.Nm : +.Bl -tag -width HOME +.It Ev HOME +Default home directory of real user ID unless modified as +specified above. +.It Ev PATH +Default search path of real user ID unless modified as specified above. +.It Ev TERM +Provides terminal type which may be retained for the substituted +user ID. +.It Ev USER +The user ID is always the effective ID (the target user ID) after an +.Nm +unless the user ID is 0 (root). +.El +.Sh FILES +.Bl -tag -width ".Pa /etc/pam.d/su" -compact +.It Pa /etc/pam.d/su +PAM configuration for +.Nm . +.El +.Sh EXAMPLES +.Bl -tag -width 5n -compact +.It Li "su man -c catman" +Runs the command +.Li catman +as user +.Li man . +You will be asked for man's password unless your real UID is 0. +.It Li "su man -c 'catman /usr/share/man /usr/local/man'" +Same as above, but the target command consists of more than a +single word and hence is quoted for use with the +.Fl c +option being passed to the shell. +(Most shells expect the argument to +.Fl c +to be a single word). +.It Li "su -l foo" +Simulate a login for user foo. +.It Li "su - foo" +Same as above. +.It Li "su -" +Simulate a login for root. +.El +.Sh SEE ALSO +.Xr csh 1 , +.Xr sh 1 , +.Xr group 5 , +.Xr passwd 5 , +.Xr environ 7 , +.Xr pam_group 8 +.Sh HISTORY +A +.Nm +command appeared in +.At v1 . diff --git a/shell_cmds/su/su.c b/shell_cmds/su/su.c new file mode 100644 index 0000000..8ad7434 --- /dev/null +++ b/shell_cmds/su/su.c @@ -0,0 +1,737 @@ +/* + * Copyright (c) 2002, 2005 Networks Associates Technologies, Inc. + * All rights reserved. + * + * Portions of this software were developed for the FreeBSD Project by + * ThinkSec AS and NAI Labs, the Security Research Division of Network + * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 + * ("CBOSS"), as part of the DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/*- + * Copyright (c) 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1988, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)su.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD: src/usr.bin/su/su.c,v 1.91 2009/12/13 03:14:06 delphij Exp $"); + +#include +#include +#include +#include + +#ifdef USE_BSM_AUDIT +#include +#include +#endif + +#include +#include +#include +#ifndef __APPLE__ +#include +#endif /* !__APPLE__ */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef __APPLE__ +#include +#endif /* __APPLE__ */ + +#define PAM_END() do { \ + int local_ret; \ + if (pamh != NULL) { \ + local_ret = pam_setcred(pamh, PAM_DELETE_CRED); \ + if (local_ret != PAM_SUCCESS) \ + syslog(LOG_ERR, "pam_setcred: %s", \ + pam_strerror(pamh, local_ret)); \ + if (asthem) { \ + local_ret = pam_close_session(pamh, 0); \ + if (local_ret != PAM_SUCCESS) \ + syslog(LOG_ERR, "pam_close_session: %s",\ + pam_strerror(pamh, local_ret)); \ + } \ + local_ret = pam_end(pamh, local_ret); \ + if (local_ret != PAM_SUCCESS) \ + syslog(LOG_ERR, "pam_end: %s", \ + pam_strerror(pamh, local_ret)); \ + } \ +} while (0) + + +#define PAM_SET_ITEM(what, item) do { \ + int local_ret; \ + local_ret = pam_set_item(pamh, what, item); \ + if (local_ret != PAM_SUCCESS) { \ + syslog(LOG_ERR, "pam_set_item(" #what "): %s", \ + pam_strerror(pamh, local_ret)); \ + errx(1, "pam_set_item(" #what "): %s", \ + pam_strerror(pamh, local_ret)); \ + /* NOTREACHED */ \ + } \ +} while (0) + +enum tristate { UNSET, YES, NO }; + +static pam_handle_t *pamh = NULL; +static char **environ_pam; + +static char *ontty(void); +static int chshell(const char *); +static void usage(void) __dead2; +static void export_pam_environment(void); +static int ok_to_export(const char *); + +extern char **environ; + +int +main(int argc, char *argv[]) +{ + static char *cleanenv; + struct passwd *pwd; + struct pam_conv conv = { openpam_ttyconv, NULL }; + enum tristate iscsh; +#ifndef __APPLE__ + login_cap_t *lc; +#endif /* !__APPLE__ */ + union { + const char **a; + char * const *b; + } np; + uid_t ruid; + pid_t child_pid, child_pgrp, pid; + int asme, ch, asthem, fastlogin, prio, i, retcode, + statusp, setmaclabel; +#ifndef __APPLE__ + u_int setwhat; +#endif /* !__APPLE__ */ + char *username, *class, shellbuf[MAXPATHLEN]; + const char *p, *user, *shell, *mytty, **nargv; + const void *v; + struct sigaction sa, sa_int, sa_quit, sa_pipe; + int temp, fds[2]; +#ifdef USE_BSM_AUDIT + const char *aerr; + au_id_t auid; +#endif +#ifdef __APPLE__ + /* 4043304 */ + const char *avshell; + char avshellbuf[MAXPATHLEN]; +#endif /* __APPLE__ */ + + shell = class = cleanenv = NULL; + asme = asthem = fastlogin = statusp = 0; + user = "root"; + iscsh = UNSET; + setmaclabel = 0; + +#ifdef __APPLE__ + while ((ch = getopt(argc, argv, "-flm")) != -1) +#else + while ((ch = getopt(argc, argv, "-flmsc:")) != -1) +#endif /* __APPLE__ */ + switch ((char)ch) { + case 'f': + fastlogin = 1; + break; + case '-': + case 'l': + asme = 0; + asthem = 1; + break; + case 'm': + asme = 1; + asthem = 0; + break; +#ifndef __APPLE__ + case 's': + setmaclabel = 1; + break; + case 'c': + class = optarg; + break; +#endif /* !__APPLE__ */ + case '?': + default: + usage(); + /* NOTREACHED */ + } + + if (optind < argc) + user = argv[optind++]; + + if (user == NULL) + usage(); + /* NOTREACHED */ + + /* + * Try to provide more helpful debugging output if su(1) is running + * non-setuid, or was run from a file system not mounted setuid. + */ + if (geteuid() != 0) + errx(1, "not running setuid"); + +#ifdef USE_BSM_AUDIT + if (getauid(&auid) < 0 && errno != ENOSYS) { + syslog(LOG_AUTH | LOG_ERR, "getauid: %s", strerror(errno)); + errx(1, "Permission denied"); + } +#endif + if (strlen(user) > MAXLOGNAME - 1) { +#ifdef USE_BSM_AUDIT + if (audit_submit(AUE_su, auid, + EPERM, 1, "username too long: '%s'", user)) + errx(1, "Permission denied"); +#endif + errx(1, "username too long"); + } + + nargv = malloc(sizeof(char *) * (size_t)(argc + 4)); + if (nargv == NULL) + errx(1, "malloc failure"); + + nargv[argc + 3] = NULL; + for (i = argc; i >= optind; i--) + nargv[i + 3] = argv[i]; + np.a = &nargv[i + 3]; + + argv += optind; + + errno = 0; + prio = getpriority(PRIO_PROCESS, 0); + if (errno) + prio = 0; + + setpriority(PRIO_PROCESS, 0, -2); + openlog("su", LOG_CONS, LOG_AUTH); + + /* get current login name, real uid and shell */ + ruid = getuid(); + username = getlogin(); + pwd = getpwnam(username); + if (username == NULL || pwd == NULL || pwd->pw_uid != ruid) + pwd = getpwuid(ruid); + if (pwd == NULL) { +#ifdef USE_BSM_AUDIT + if (audit_submit(AUE_su, auid, EPERM, 1, + "unable to determine invoking subject: '%s'", username)) + errx(1, "Permission denied"); +#endif + errx(1, "who are you?"); + } + + username = strdup(pwd->pw_name); + if (username == NULL) + err(1, "strdup failure"); + + if (asme) { + if (pwd->pw_shell != NULL && *pwd->pw_shell != '\0') { + /* must copy - pwd memory is recycled */ + shell = strncpy(shellbuf, pwd->pw_shell, + sizeof(shellbuf)); + shellbuf[sizeof(shellbuf) - 1] = '\0'; + } + else { + shell = _PATH_BSHELL; + iscsh = NO; + } + } + + /* Do the whole PAM startup thing */ + retcode = pam_start("su", user, &conv, &pamh); + if (retcode != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, retcode)); + errx(1, "pam_start: %s", pam_strerror(pamh, retcode)); + } + + PAM_SET_ITEM(PAM_RUSER, username); + + mytty = ttyname(STDERR_FILENO); + if (!mytty) + mytty = "tty"; + PAM_SET_ITEM(PAM_TTY, mytty); + + retcode = pam_authenticate(pamh, 0); + if (retcode != PAM_SUCCESS) { +#ifdef USE_BSM_AUDIT + if (audit_submit(AUE_su, auid, EPERM, 1, "bad su %s to %s on %s", + username, user, mytty)) + errx(1, "Permission denied"); +#endif + syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s on %s", + username, user, mytty); + errx(1, "Sorry"); + } +#ifdef USE_BSM_AUDIT + if (audit_submit(AUE_su, auid, 0, 0, "successful authentication")) + errx(1, "Permission denied"); +#endif + retcode = pam_get_item(pamh, PAM_USER, &v); + if (retcode == PAM_SUCCESS) + user = v; + else + syslog(LOG_ERR, "pam_get_item(PAM_USER): %s", + pam_strerror(pamh, retcode)); + pwd = getpwnam(user); + if (pwd == NULL) { +#ifdef USE_BSM_AUDIT + if (audit_submit(AUE_su, auid, EPERM, 1, + "unknown subject: %s", user)) + errx(1, "Permission denied"); +#endif + errx(1, "unknown login: %s", user); + } + + retcode = pam_acct_mgmt(pamh, 0); + if (retcode == PAM_NEW_AUTHTOK_REQD) { + retcode = pam_chauthtok(pamh, + PAM_CHANGE_EXPIRED_AUTHTOK); + if (retcode != PAM_SUCCESS) { +#ifdef USE_BSM_AUDIT + aerr = pam_strerror(pamh, retcode); + if (aerr == NULL) + aerr = "Unknown PAM error"; + if (audit_submit(AUE_su, auid, EPERM, 1, + "pam_chauthtok: %s", aerr)) + errx(1, "Permission denied"); +#endif + syslog(LOG_ERR, "pam_chauthtok: %s", + pam_strerror(pamh, retcode)); + errx(1, "Sorry"); + } + } + if (retcode != PAM_SUCCESS) { +#ifdef USE_BSM_AUDIT + if (audit_submit(AUE_su, auid, EPERM, 1, "pam_acct_mgmt: %s", + pam_strerror(pamh, retcode))) + errx(1, "Permission denied"); +#endif + syslog(LOG_ERR, "pam_acct_mgmt: %s", + pam_strerror(pamh, retcode)); + errx(1, "Sorry"); + } + +#ifndef __APPLE__ + /* get target login information */ + if (class == NULL) + lc = login_getpwclass(pwd); + else { + if (ruid != 0) { +#ifdef USE_BSM_AUDIT + if (audit_submit(AUE_su, auid, EPERM, 1, + "only root may use -c")) + errx(1, "Permission denied"); +#endif + errx(1, "only root may use -c"); + } + lc = login_getclass(class); + if (lc == NULL) + errx(1, "unknown class: %s", class); + } +#endif /* !__APPLE__ */ + + /* if asme and non-standard target shell, must be root */ + if (asme) { + if (ruid != 0 && !chshell(pwd->pw_shell)) + errx(1, "permission denied (shell)"); + } + else if (pwd->pw_shell && *pwd->pw_shell) { +#ifdef __APPLE__ + /* 3825554 */ + shell = strncpy(shellbuf, pwd->pw_shell, sizeof(shellbuf)); + shellbuf[sizeof(shellbuf) - 1] = '\0'; +#else + shell = pwd->pw_shell; +#endif /* __APPLE__ */ + iscsh = UNSET; + } + else { + shell = _PATH_BSHELL; + iscsh = NO; + } + + /* if we're forking a csh, we want to slightly muck the args */ + if (iscsh == UNSET) { + p = strrchr(shell, '/'); + if (p) + ++p; + else + p = shell; + iscsh = strcmp(p, "csh") ? (strcmp(p, "tcsh") ? NO : YES) : YES; + } + setpriority(PRIO_PROCESS, 0, prio); + + /* + * PAM modules might add supplementary groups in pam_setcred(), so + * initialize them first. + */ +#ifdef __APPLE__ + if (initgroups(user, pwd->pw_gid)) + err(1, "initgroups"); +#else + if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) < 0) + err(1, "setusercontext"); +#endif /* __APPLE__ */ + +#ifdef __APPLE__ + /* 8530846 */ + if (asthem) { + auditinfo_addr_t auinfo = { + .ai_termid = { .at_type = AU_IPv4 }, + .ai_asid = AU_ASSIGN_ASID, + .ai_auid = getuid(), + .ai_flags = 0, + }; + if (setaudit_addr(&auinfo, sizeof(auinfo)) == 0) { + char session[16]; + snprintf(session, sizeof(session), "%x", auinfo.ai_asid); + setenv("SECURITYSESSIONID", session, 1); + } else { + errx(1, "failed to create session."); + } + } +#endif /* __APPLE__ */ + + retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED); + if (retcode != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_setcred: %s", + pam_strerror(pamh, retcode)); + errx(1, "failed to establish credentials."); + } + if (asthem) { + retcode = pam_open_session(pamh, 0); + if (retcode != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_open_session: %s", + pam_strerror(pamh, retcode)); + errx(1, "failed to open session."); + } + } + + /* + * We must fork() before setuid() because we need to call + * pam_setcred(pamh, PAM_DELETE_CRED) as root. + */ + sa.sa_flags = SA_RESTART; + sa.sa_handler = SIG_IGN; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, &sa_int); + sigaction(SIGQUIT, &sa, &sa_quit); + sigaction(SIGPIPE, &sa, &sa_pipe); + sa.sa_handler = SIG_DFL; + sigaction(SIGTSTP, &sa, NULL); + statusp = 1; + if (pipe(fds) == -1) { + PAM_END(); + err(1, "pipe"); + } + child_pid = fork(); + switch (child_pid) { + default: + sa.sa_handler = SIG_IGN; + sigaction(SIGTTOU, &sa, NULL); + close(fds[0]); + setpgid(child_pid, child_pid); + if (tcgetpgrp(STDERR_FILENO) == getpgrp()) + tcsetpgrp(STDERR_FILENO, child_pid); + close(fds[1]); + sigaction(SIGPIPE, &sa_pipe, NULL); + while ((pid = waitpid(child_pid, &statusp, WUNTRACED)) != -1) { + if (WIFSTOPPED(statusp)) { + child_pgrp = getpgid(child_pid); + if (tcgetpgrp(STDERR_FILENO) == child_pgrp) + tcsetpgrp(STDERR_FILENO, getpgrp()); + kill(getpid(), SIGSTOP); + if (tcgetpgrp(STDERR_FILENO) == getpgrp()) { + child_pgrp = getpgid(child_pid); + tcsetpgrp(STDERR_FILENO, child_pgrp); + } + kill(child_pid, SIGCONT); + statusp = 1; + continue; + } + break; + } + tcsetpgrp(STDERR_FILENO, getpgrp()); + if (pid == -1) + err(1, "waitpid"); + PAM_END(); + exit(WEXITSTATUS(statusp)); + case -1: + PAM_END(); + err(1, "fork"); + case 0: + close(fds[1]); + read(fds[0], &temp, 1); + close(fds[0]); + sigaction(SIGPIPE, &sa_pipe, NULL); + sigaction(SIGINT, &sa_int, NULL); + sigaction(SIGQUIT, &sa_quit, NULL); + +#ifdef __APPLE__ + if (setgid(pwd->pw_gid)) + err(1, "setgid"); + /* Call initgroups(2) after setgid(2) to re-establish memberd */ + if (initgroups(user, pwd->pw_gid)) + err(1, "initgroups"); + if (setuid(pwd->pw_uid)) + err(1, "setuid"); +#else + /* + * Set all user context except for: Environmental variables + * Umask Login records (wtmp, etc) Path + */ + setwhat = LOGIN_SETALL & ~(LOGIN_SETENV | LOGIN_SETUMASK | + LOGIN_SETLOGIN | LOGIN_SETPATH | LOGIN_SETGROUP | + LOGIN_SETMAC); + /* + * If -s is present, also set the MAC label. + */ + if (setmaclabel) + setwhat |= LOGIN_SETMAC; + /* + * Don't touch resource/priority settings if -m has been used + * or -l and -c hasn't, and we're not su'ing to root. + */ + if ((asme || (!asthem && class == NULL)) && pwd->pw_uid) + setwhat &= ~(LOGIN_SETPRIORITY | LOGIN_SETRESOURCES); + if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) < 0) + err(1, "setusercontext"); +#endif /* __APPLE__ */ + + if (!asme) { + if (asthem) { + p = getenv("TERM"); + environ = &cleanenv; + } + + if (asthem || pwd->pw_uid) + setenv("USER", pwd->pw_name, 1); + setenv("HOME", pwd->pw_dir, 1); + setenv("SHELL", shell, 1); +#ifdef __APPLE__ + unsetenv("TMPDIR"); +#endif /* __APPLE__ */ + + if (asthem) { + /* + * Add any environmental variables that the + * PAM modules may have set. + */ + environ_pam = pam_getenvlist(pamh); + if (environ_pam) + export_pam_environment(); + +#ifdef __APPLE__ + /* 5276965: As documented, set $PATH. */ + setenv("PATH", "/bin:/usr/bin", 1); +#else + /* set the su'd user's environment & umask */ + setusercontext(lc, pwd, pwd->pw_uid, + LOGIN_SETPATH | LOGIN_SETUMASK | + LOGIN_SETENV); +#endif /* __APPLE__ */ + if (p) + setenv("TERM", p, 1); + + p = pam_getenv(pamh, "HOME"); + if (chdir(p ? p : pwd->pw_dir) < 0) + errx(1, "no directory"); + } + } +#ifndef __APPLE__ + login_close(lc); +#endif /* !__APPLE__ */ + + if (iscsh == YES) { + if (fastlogin) + *np.a-- = "-f"; + if (asme) + *np.a-- = "-m"; + } +#ifdef __APPLE__ + /* 4043304 */ + if ((p = strrchr(shell, '/')) != NULL) + avshell = p + 1; + else + avshell = shell; + + if (asthem) { + avshellbuf[0] = '-'; + strlcpy(avshellbuf+1, avshell, sizeof(avshellbuf) - 1); + avshell = avshellbuf; + } + + /* csh *no longer* strips the first character... */ + *np.a = avshell; +#else + /* csh strips the first character... */ + *np.a = asthem ? "-su" : iscsh == YES ? "_su" : "su"; +#endif /* __APPLE__ */ + + if (ruid != 0) + syslog(LOG_NOTICE, "%s to %s%s", username, user, + ontty()); + + execv(shell, np.b); + err(1, "%s", shell); + } +} + +static void +export_pam_environment(void) +{ + char **pp; + char *p; + + for (pp = environ_pam; *pp != NULL; pp++) { + if (ok_to_export(*pp)) { + p = strchr(*pp, '='); + *p = '\0'; + setenv(*pp, p + 1, 1); + } + free(*pp); + } +} + +/* + * Sanity checks on PAM environmental variables: + * - Make sure there is an '=' in the string. + * - Make sure the string doesn't run on too long. + * - Do not export certain variables. This list was taken from the + * Solaris pam_putenv(3) man page. + * Note that if the user is chrooted, PAM may have a better idea than we + * do of where her home directory is. + */ +static int +ok_to_export(const char *s) +{ + static const char *noexport[] = { + "SHELL", /* "HOME", */ "LOGNAME", "MAIL", "CDPATH", + "IFS", "PATH", NULL + }; + const char **pp; + size_t n; + + if (strlen(s) > 1024 || strchr(s, '=') == NULL) + return 0; + if (strncmp(s, "LD_", 3) == 0) + return 0; + for (pp = noexport; *pp != NULL; pp++) { + n = strlen(*pp); + if (s[n] == '=' && strncmp(s, *pp, n) == 0) + return 0; + } + return 1; +} + +static void +usage(void) +{ + +#ifdef __APPLE__ + fprintf(stderr, "usage: su [-] [-flm] [login [args]]\n"); +#else + fprintf(stderr, "usage: su [-] [-flms] [-c class] [login [args]]\n"); +#endif /* __APPLE__ */ + exit(1); + /* NOTREACHED */ +} + +static int +chshell(const char *sh) +{ + int r; + char *cp; + + r = 0; + setusershell(); + while ((cp = getusershell()) != NULL && !r) + r = (strcmp(cp, sh) == 0); + endusershell(); + return r; +} + +static char * +ontty(void) +{ + char *p; + static char buf[MAXPATHLEN + 4]; + + buf[0] = 0; + p = ttyname(STDERR_FILENO); + if (p) + snprintf(buf, sizeof(buf), " on %s", p); + return buf; +} diff --git a/shell_cmds/su/su.pam b/shell_cmds/su/su.pam new file mode 100644 index 0000000..fd8a789 --- /dev/null +++ b/shell_cmds/su/su.pam @@ -0,0 +1,7 @@ +# su: auth account session +auth sufficient pam_rootok.so +auth required pam_opendirectory.so +account required pam_group.so no_warn group=admin,wheel ruser root_only fail_safe +account required pam_opendirectory.so no_check_shell +password required pam_opendirectory.so +session required pam_launchd.so diff --git a/shell_cmds/su/su_entitlements.plist b/shell_cmds/su/su_entitlements.plist new file mode 100644 index 0000000..a96cb44 --- /dev/null +++ b/shell_cmds/su/su_entitlements.plist @@ -0,0 +1,10 @@ + + + + + com.apple.keystore.console + + com.apple.private.security.clear-library-validation + + + -- cgit v1.2.3-56-ge451