su.c revision 121236
124139Sjoerg/* 224139Sjoerg * Copyright (c) 1988, 1993, 1994 324139Sjoerg * The Regents of the University of California. All rights reserved. 424139Sjoerg * Copyright (c) 2002 Networks Associates Technologies, Inc. 524139Sjoerg * All rights reserved. 624139Sjoerg * 724139Sjoerg * Portions of this software were developed for the FreeBSD Project by 824139Sjoerg * ThinkSec AS and NAI Labs, the Security Research Division of Network 924139Sjoerg * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 1024139Sjoerg * ("CBOSS"), as part of the DARPA CHATS research program. 1124139Sjoerg * 1289757Sdwmalone * Redistribution and use in source and binary forms, with or without 1389757Sdwmalone * modification, are permitted provided that the following conditions 1489757Sdwmalone * are met: 1566641Simp * 1. Redistributions of source code must retain the above copyright 1666641Simp * notice, this list of conditions and the following disclaimer. 1724139Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1824139Sjoerg * notice, this list of conditions and the following disclaimer in the 1924139Sjoerg * documentation and/or other materials provided with the distribution. 2024139Sjoerg * 3. All advertising materials mentioning features or use of this software 2124139Sjoerg * must display the following acknowledgement: 2224139Sjoerg * This product includes software developed by the University of 2324139Sjoerg * California, Berkeley and its contributors. 2424139Sjoerg * 4. Neither the name of the University nor the names of its contributors 2524139Sjoerg * may be used to endorse or promote products derived from this software 2624139Sjoerg * without specific prior written permission. 2724139Sjoerg * 2824139Sjoerg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2924139Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3024139Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3124139Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3224139Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3324139Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3424139Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3524139Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3624139Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3786042Sdwmalone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3824139Sjoerg * SUCH DAMAGE. 3924139Sjoerg */ 4024139Sjoerg 4124139Sjoerg#ifndef lint 4224139Sjoergstatic const char copyright[] = 4324139Sjoerg"@(#) Copyright (c) 1988, 1993, 1994\n\ 4424139Sjoerg The Regents of the University of California. All rights reserved.\n"; 4524139Sjoerg#endif /* not lint */ 4624139Sjoerg 4724139Sjoerg#ifndef lint 4824139Sjoerg#if 0 4924139Sjoergstatic char sccsid[] = "@(#)su.c 8.3 (Berkeley) 4/2/94"; 5024139Sjoerg#endif 5124139Sjoergstatic const char rcsid[] = 5224139Sjoerg "$FreeBSD: head/usr.bin/su/su.c 121236 2003-10-19 02:09:36Z cognet $"; 5324139Sjoerg#endif /* not lint */ 5424139Sjoerg 5524139Sjoerg#include <sys/param.h> 5624139Sjoerg#include <sys/time.h> 5724139Sjoerg#include <sys/resource.h> 5824139Sjoerg#include <sys/wait.h> 5924139Sjoerg 6024139Sjoerg#include <err.h> 6124139Sjoerg#include <errno.h> 6224139Sjoerg#include <grp.h> 6324139Sjoerg#include <libutil.h> 6424139Sjoerg#include <login_cap.h> 6524139Sjoerg#include <paths.h> 6624139Sjoerg#include <pwd.h> 6724139Sjoerg#include <signal.h> 68168710Sstas#include <stdio.h> 69175420Speter#include <stdlib.h> 70168710Sstas#include <string.h> 7124139Sjoerg#include <syslog.h> 7224139Sjoerg#include <unistd.h> 7324139Sjoerg 7424139Sjoerg#include <security/pam_appl.h> 7524139Sjoerg#include <security/openpam.h> 7624139Sjoerg 7724139Sjoerg#define PAM_END() do { \ 7824139Sjoerg int local_ret; \ 7981187Skris if (pamh != NULL) { \ 8081187Skris local_ret = pam_setcred(pamh, PAM_DELETE_CRED); \ 8181187Skris if (local_ret != PAM_SUCCESS) \ 8281187Skris syslog(LOG_ERR, "pam_setcred: %s", \ 8324139Sjoerg pam_strerror(pamh, local_ret)); \ 8424139Sjoerg if (asthem) { \ 8524139Sjoerg local_ret = pam_close_session(pamh, 0); \ 8624139Sjoerg if (local_ret != PAM_SUCCESS) \ 8724139Sjoerg syslog(LOG_ERR, "pam_close_session: %s",\ 8824139Sjoerg pam_strerror(pamh, local_ret)); \ 8924139Sjoerg } \ 90145073Skeramida local_ret = pam_end(pamh, local_ret); \ 9124139Sjoerg if (local_ret != PAM_SUCCESS) \ 9224139Sjoerg syslog(LOG_ERR, "pam_end: %s", \ 9324139Sjoerg pam_strerror(pamh, local_ret)); \ 9424139Sjoerg } \ 9524139Sjoerg} while (0) 9624139Sjoerg 9724139Sjoerg 9824139Sjoerg#define PAM_SET_ITEM(what, item) do { \ 9924139Sjoerg int local_ret; \ 10024139Sjoerg local_ret = pam_set_item(pamh, what, item); \ 10124139Sjoerg if (local_ret != PAM_SUCCESS) { \ 102133817Salfred syslog(LOG_ERR, "pam_set_item(" #what "): %s", \ 10324139Sjoerg pam_strerror(pamh, local_ret)); \ 10424139Sjoerg errx(1, "pam_set_item(" #what "): %s", \ 105131829Skeramida pam_strerror(pamh, local_ret)); \ 10624139Sjoerg } \ 10724139Sjoerg} while (0) 10824139Sjoerg 10924139Sjoergenum tristate { UNSET, YES, NO }; 11024139Sjoerg 11124139Sjoergstatic pam_handle_t *pamh = NULL; 11224139Sjoergstatic char **environ_pam; 11324139Sjoerg 11424139Sjoergstatic char *ontty(void); 11524139Sjoergstatic int chshell(char *); 11624139Sjoergstatic void usage(void); 11724139Sjoergstatic int export_pam_environment(void); 11824139Sjoergstatic int ok_to_export(const char *); 11924139Sjoerg 12024139Sjoergextern char **environ; 12124139Sjoerg 12224139Sjoergint 12324139Sjoergmain(int argc, char *argv[]) 12424139Sjoerg{ 12524142Sjoerg struct passwd *pwd; 12624142Sjoerg struct pam_conv conv = { openpam_ttyconv, NULL }; 12724139Sjoerg enum tristate iscsh; 12824139Sjoerg login_cap_t *lc; 12924139Sjoerg union { 13024139Sjoerg const char **a; 13124139Sjoerg char * const *b; 13224139Sjoerg } np; 13324139Sjoerg uid_t ruid; 13424139Sjoerg pid_t child_pid, child_pgrp, pid; 13524139Sjoerg int asme, ch, asthem, fastlogin, prio, i, setwhat, retcode, 13624139Sjoerg statusp, setmaclabel; 13724139Sjoerg char *username, *cleanenv, *class, shellbuf[MAXPATHLEN]; 13824139Sjoerg const char *p, *user, *shell, *mytty, **nargv; 13924142Sjoerg struct sigaction sa, sa_int, sa_quit, sa_pipe; 14024139Sjoerg int temp, fds[2]; 14124139Sjoerg 14224139Sjoerg shell = class = cleanenv = NULL; 14324139Sjoerg asme = asthem = fastlogin = statusp = 0; 14424139Sjoerg user = "root"; 14524139Sjoerg iscsh = UNSET; 14624139Sjoerg setmaclabel = 0; 14724139Sjoerg 14824139Sjoerg while ((ch = getopt(argc, argv, "-flmsc:")) != -1) 14924139Sjoerg switch ((char)ch) { 15024139Sjoerg case 'f': 15124139Sjoerg fastlogin = 1; 15224139Sjoerg break; 15324139Sjoerg case '-': 15424139Sjoerg case 'l': 15524139Sjoerg asme = 0; 15624139Sjoerg asthem = 1; 15724139Sjoerg break; 15824139Sjoerg case 'm': 15924139Sjoerg asme = 1; 16024139Sjoerg asthem = 0; 16124139Sjoerg break; 16224139Sjoerg case 's': 16324139Sjoerg setmaclabel = 1; 16424139Sjoerg break; 16586042Sdwmalone case 'c': 16624139Sjoerg class = optarg; 16724139Sjoerg break; 16824139Sjoerg case '?': 16924139Sjoerg default: 17024139Sjoerg usage(); 17124139Sjoerg } 17224139Sjoerg 17324139Sjoerg if (optind < argc) 17424139Sjoerg user = argv[optind++]; 17524139Sjoerg 17624139Sjoerg if (user == NULL) 17724139Sjoerg usage(); 17824139Sjoerg 17924139Sjoerg if (strlen(user) > MAXLOGNAME - 1) 18024139Sjoerg errx(1, "username too long"); 18124139Sjoerg 18224139Sjoerg nargv = malloc(sizeof(char *) * (argc + 4)); 18324139Sjoerg if (nargv == NULL) 18424139Sjoerg errx(1, "malloc failure"); 18524139Sjoerg 18624139Sjoerg nargv[argc + 3] = NULL; 18724139Sjoerg for (i = argc; i >= optind; i--) 18824139Sjoerg nargv[i + 3] = argv[i]; 18924139Sjoerg np.a = &nargv[i + 3]; 19024139Sjoerg 19124139Sjoerg argv += optind; 19224139Sjoerg 19324139Sjoerg errno = 0; 19489757Sdwmalone prio = getpriority(PRIO_PROCESS, 0); 19524139Sjoerg if (errno) 19624139Sjoerg prio = 0; 19724139Sjoerg 19824139Sjoerg setpriority(PRIO_PROCESS, 0, -2); 199223936Sjhb openlog("su", LOG_CONS, LOG_AUTH); 20024139Sjoerg 201223936Sjhb /* get current login name, real uid and shell */ 20224139Sjoerg ruid = getuid(); 20324139Sjoerg username = getlogin(); 20424139Sjoerg pwd = getpwnam(username); 20524139Sjoerg if (username == NULL || pwd == NULL || pwd->pw_uid != ruid) 20624139Sjoerg pwd = getpwuid(ruid); 20724139Sjoerg if (pwd == NULL) 20824139Sjoerg errx(1, "who are you?"); 20924139Sjoerg 21024139Sjoerg username = strdup(pwd->pw_name); 21124139Sjoerg if (username == NULL) 21224139Sjoerg err(1, "strdup failure"); 21324139Sjoerg 21424139Sjoerg if (asme) { 21524139Sjoerg if (pwd->pw_shell != NULL && *pwd->pw_shell != '\0') { 21624139Sjoerg /* must copy - pwd memory is recycled */ 21724139Sjoerg shell = strncpy(shellbuf, pwd->pw_shell, 21824139Sjoerg sizeof(shellbuf)); 21924139Sjoerg shellbuf[sizeof(shellbuf) - 1] = '\0'; 22038090Sdes } 221117709Sjulian else { 222131402Salfred shell = _PATH_BSHELL; 223132005Salfred iscsh = NO; 224146342Skeramida } 225168710Sstas } 226168799Srafan 227222530Sjhb /* Do the whole PAM startup thing */ 228223936Sjhb retcode = pam_start("su", user, &conv, &pamh); 22924139Sjoerg if (retcode != PAM_SUCCESS) { 230223936Sjhb syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, retcode)); 23124139Sjoerg errx(1, "pam_start: %s", pam_strerror(pamh, retcode)); 23224139Sjoerg } 23324139Sjoerg 23424139Sjoerg PAM_SET_ITEM(PAM_RUSER, username); 23589757Sdwmalone 23689757Sdwmalone mytty = ttyname(STDERR_FILENO); 23724139Sjoerg if (!mytty) 23824139Sjoerg mytty = "tty"; 23924139Sjoerg PAM_SET_ITEM(PAM_TTY, mytty); 24024139Sjoerg 24124139Sjoerg retcode = pam_authenticate(pamh, 0); 24224139Sjoerg if (retcode != PAM_SUCCESS) { 24324139Sjoerg#if 0 24424139Sjoerg syslog(LOG_ERR, "pam_authenticate: %s", 24524139Sjoerg pam_strerror(pamh, retcode)); 24624139Sjoerg#endif 24724139Sjoerg syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s on %s", 24824139Sjoerg username, user, mytty); 24924139Sjoerg errx(1, "Sorry"); 25024139Sjoerg } 25124139Sjoerg retcode = pam_get_item(pamh, PAM_USER, (const void **)&p); 25224139Sjoerg if (retcode == PAM_SUCCESS) 25324139Sjoerg user = p; 25424139Sjoerg else 25524139Sjoerg syslog(LOG_ERR, "pam_get_item(PAM_USER): %s", 25624139Sjoerg pam_strerror(pamh, retcode)); 25738090Sdes 25824139Sjoerg retcode = pam_acct_mgmt(pamh, 0); 25924139Sjoerg if (retcode == PAM_NEW_AUTHTOK_REQD) { 260117709Sjulian retcode = pam_chauthtok(pamh, 261146342Skeramida PAM_CHANGE_EXPIRED_AUTHTOK); 262168799Srafan if (retcode != PAM_SUCCESS) { 263222530Sjhb syslog(LOG_ERR, "pam_chauthtok: %s", 26424139Sjoerg pam_strerror(pamh, retcode)); 26524139Sjoerg errx(1, "Sorry"); 26624139Sjoerg } 26724139Sjoerg } 26824139Sjoerg if (retcode != PAM_SUCCESS) { 26924139Sjoerg syslog(LOG_ERR, "pam_acct_mgmt: %s", 27024139Sjoerg pam_strerror(pamh, retcode)); 27124139Sjoerg errx(1, "Sorry"); 27224139Sjoerg } 27324139Sjoerg 27424139Sjoerg /* get target login information, default to root */ 27524139Sjoerg pwd = getpwnam(user); 27624139Sjoerg if (pwd == NULL) 27724139Sjoerg errx(1, "unknown login: %s", user); 27824139Sjoerg if (class == NULL) 27924139Sjoerg lc = login_getpwclass(pwd); 28024139Sjoerg else { 28124139Sjoerg if (ruid != 0) 28224139Sjoerg errx(1, "only root may use -c"); 28324139Sjoerg lc = login_getclass(class); 28424139Sjoerg if (lc == NULL) 28524139Sjoerg errx(1, "unknown class: %s", class); 28624139Sjoerg } 28724139Sjoerg 28824139Sjoerg /* if asme and non-standard target shell, must be root */ 289222530Sjhb if (asme) { 29024139Sjoerg if (ruid != 0 && !chshell(pwd->pw_shell)) 29124139Sjoerg errx(1, "permission denied (shell)."); 29224139Sjoerg } 29389757Sdwmalone else if (pwd->pw_shell && *pwd->pw_shell) { 29489757Sdwmalone shell = pwd->pw_shell; 29589757Sdwmalone iscsh = UNSET; 29689757Sdwmalone } 29789757Sdwmalone else { 29889757Sdwmalone shell = _PATH_BSHELL; 29924139Sjoerg iscsh = NO; 30024139Sjoerg } 30124139Sjoerg 30224139Sjoerg /* if we're forking a csh, we want to slightly muck the args */ 30324139Sjoerg if (iscsh == UNSET) { 30424139Sjoerg p = strrchr(shell, '/'); 30524139Sjoerg if (p) 30624139Sjoerg ++p; 30724139Sjoerg else 30824139Sjoerg p = shell; 30924139Sjoerg iscsh = strcmp(p, "csh") ? (strcmp(p, "tcsh") ? NO : YES) : YES; 31024139Sjoerg } 31124139Sjoerg setpriority(PRIO_PROCESS, 0, prio); 31224139Sjoerg 31324139Sjoerg /* Switch to home directory */ 31424139Sjoerg if (asthem) { 31524139Sjoerg if (chdir(pwd->pw_dir) < 0) 31624139Sjoerg errx(1, "no directory"); 31724139Sjoerg } 31824139Sjoerg 31924139Sjoerg /* 32024139Sjoerg * PAM modules might add supplementary groups in pam_setcred(), so 32124139Sjoerg * initialize them first. 32224139Sjoerg */ 32324139Sjoerg if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) < 0) 32424139Sjoerg err(1, "setusercontext"); 32524139Sjoerg 32624139Sjoerg retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED); 32724139Sjoerg if (retcode != PAM_SUCCESS) { 328168710Sstas syslog(LOG_ERR, "pam_setcred: %s", 329168710Sstas pam_strerror(pamh, retcode)); 330168710Sstas errx(1, "failed to establish credentials."); 331168710Sstas } 33224139Sjoerg if (asthem) { 33324139Sjoerg retcode = pam_open_session(pamh, 0); 33424139Sjoerg if (retcode != PAM_SUCCESS) { 33524139Sjoerg syslog(LOG_ERR, "pam_open_session: %s", 33624139Sjoerg pam_strerror(pamh, retcode)); 33724139Sjoerg errx(1, "failed to open session."); 33824139Sjoerg } 33924139Sjoerg } 34024139Sjoerg 34124139Sjoerg /* 34224139Sjoerg * We must fork() before setuid() because we need to call 34324139Sjoerg * pam_setcred(pamh, PAM_DELETE_CRED) as root. 34424139Sjoerg */ 34524139Sjoerg sa.sa_flags = SA_RESTART; 34624139Sjoerg sa.sa_handler = SIG_IGN; 34789757Sdwmalone sigemptyset(&sa.sa_mask); 34824139Sjoerg sigaction(SIGINT, &sa, &sa_int); 34924139Sjoerg sigaction(SIGQUIT, &sa, &sa_quit); 35089757Sdwmalone sigaction(SIGPIPE, &sa, &sa_pipe); 35124139Sjoerg sa.sa_handler = SIG_DFL; 35224139Sjoerg sigaction(SIGTSTP, &sa, NULL); 35324139Sjoerg statusp = 1; 35424139Sjoerg if (pipe(fds) == -1) { 35524139Sjoerg err(1, "pipe"); 35624139Sjoerg PAM_END(); 35724139Sjoerg exit(1); 35824139Sjoerg } 35924139Sjoerg child_pid = fork(); 36024139Sjoerg switch (child_pid) { 36124139Sjoerg default: 36224139Sjoerg close(fds[0]); 36324139Sjoerg setpgid(child_pid, child_pid); 36424139Sjoerg tcsetpgrp(1, child_pid); 36524139Sjoerg close(fds[1]); 36624139Sjoerg sigaction(SIGPIPE, &sa_pipe, NULL); 36724139Sjoerg while ((pid = waitpid(child_pid, &statusp, WUNTRACED)) != -1) { 36824139Sjoerg if (WIFSTOPPED(statusp)) { 36924139Sjoerg kill(getpid(), SIGSTOP); 37024139Sjoerg child_pgrp = getpgid(child_pid); 37124139Sjoerg tcsetpgrp(1, child_pgrp); 37224139Sjoerg kill(child_pid, SIGCONT); 373131616Sdes statusp = 1; 374131402Salfred continue; 375131402Salfred } 376131402Salfred break; 377131402Salfred } 378131402Salfred if (pid == -1) 379131402Salfred err(1, "waitpid"); 380131402Salfred PAM_END(); 381131402Salfred exit(statusp); 382131402Salfred case -1: 383131402Salfred err(1, "fork"); 384131402Salfred PAM_END(); 385131402Salfred exit(1); 386131402Salfred case 0: 38724139Sjoerg close(fds[1]); 38824139Sjoerg read(fds[0], &temp, 1); 38924139Sjoerg close(fds[0]); 39024139Sjoerg sigaction(SIGPIPE, &sa_pipe, NULL); 39124139Sjoerg sigaction(SIGINT, &sa_int, NULL); 39224139Sjoerg sigaction(SIGQUIT, &sa_quit, NULL); 39324139Sjoerg 39424139Sjoerg /* 39524139Sjoerg * Set all user context except for: Environmental variables 39624139Sjoerg * Umask Login records (wtmp, etc) Path 39724139Sjoerg */ 39838090Sdes setwhat = LOGIN_SETALL & ~(LOGIN_SETENV | LOGIN_SETUMASK | 39938090Sdes LOGIN_SETLOGIN | LOGIN_SETPATH | LOGIN_SETGROUP | 40038090Sdes LOGIN_SETMAC); 401146342Skeramida /* 402146342Skeramida * If -s is present, also set the MAC label. 403146342Skeramida */ 404146342Skeramida if (setmaclabel) 405146342Skeramida setwhat |= LOGIN_SETMAC; 406117709Sjulian /* 407117709Sjulian * Don't touch resource/priority settings if -m has been used 408117709Sjulian * or -l and -c hasn't, and we're not su'ing to root. 409146342Skeramida */ 410168799Srafan if ((asme || (!asthem && class == NULL)) && pwd->pw_uid) 411168799Srafan setwhat &= ~(LOGIN_SETPRIORITY | LOGIN_SETRESOURCES); 412168799Srafan if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) < 0) 413168799Srafan err(1, "setusercontext"); 414175420Speter 415223936Sjhb if (!asme) { 416175420Speter if (asthem) { 417175420Speter p = getenv("TERM"); 418222530Sjhb environ = &cleanenv; 419222530Sjhb } 420222530Sjhb 421222530Sjhb if (asthem || pwd->pw_uid) 42224139Sjoerg setenv("USER", pwd->pw_name, 1); 423157842Sru setenv("HOME", pwd->pw_dir, 1); 424157842Sru setenv("SHELL", shell, 1); 425222530Sjhb 426157842Sru if (asthem) { 42724139Sjoerg /* 42824139Sjoerg * Add any environmental variables that the 42924139Sjoerg * PAM modules may have set. 43024139Sjoerg */ 43124139Sjoerg environ_pam = pam_getenvlist(pamh); 43224139Sjoerg if (environ_pam) 43324139Sjoerg export_pam_environment(); 43424139Sjoerg 43524139Sjoerg /* set the su'd user's environment & umask */ 43624139Sjoerg setusercontext(lc, pwd, pwd->pw_uid, 43724139Sjoerg LOGIN_SETPATH | LOGIN_SETUMASK | 43824139Sjoerg LOGIN_SETENV); 43924139Sjoerg if (p) 44024139Sjoerg setenv("TERM", p, 1); 44124139Sjoerg } 44224139Sjoerg } 44324139Sjoerg login_close(lc); 44424139Sjoerg 44524139Sjoerg if (iscsh == YES) { 44624139Sjoerg if (fastlogin) 44724139Sjoerg *np.a-- = "-f"; 44824139Sjoerg if (asme) 44924139Sjoerg *np.a-- = "-m"; 45024139Sjoerg } 45124139Sjoerg /* csh strips the first character... */ 45224139Sjoerg *np.a = asthem ? "-su" : iscsh == YES ? "_su" : "su"; 45324139Sjoerg 45424139Sjoerg if (ruid != 0) 45524139Sjoerg syslog(LOG_NOTICE, "%s to %s%s", username, user, 45624139Sjoerg ontty()); 45724139Sjoerg 45824139Sjoerg execv(shell, np.b); 45924139Sjoerg err(1, "%s", shell); 46024139Sjoerg } 46124139Sjoerg} 46224139Sjoerg 46324139Sjoergstatic int 46424139Sjoergexport_pam_environment(void) 465175195Sobrien{ 46624139Sjoerg char **pp; 46724139Sjoerg 46824139Sjoerg for (pp = environ_pam; *pp != NULL; pp++) { 46924139Sjoerg if (ok_to_export(*pp)) 47024139Sjoerg putenv(*pp); 47124139Sjoerg free(*pp); 47224139Sjoerg } 47324139Sjoerg return PAM_SUCCESS; 47424139Sjoerg} 47524139Sjoerg 47624139Sjoerg/* 47724139Sjoerg * Sanity checks on PAM environmental variables: 47824139Sjoerg * - Make sure there is an '=' in the string. 47924139Sjoerg * - Make sure the string doesn't run on too long. 48024139Sjoerg * - Do not export certain variables. This list was taken from the 48124139Sjoerg * Solaris pam_putenv(3) man page. 48224139Sjoerg * Note that if the user is chrooted, PAM may have a better idea than we 48324139Sjoerg * do of where her home directory is. 48424139Sjoerg */ 48524139Sjoergstatic int 48624139Sjoergok_to_export(const char *s) 48724139Sjoerg{ 48824139Sjoerg static const char *noexport[] = { 48924139Sjoerg "SHELL", /* "HOME", */ "LOGNAME", "MAIL", "CDPATH", 49024139Sjoerg "IFS", "PATH", NULL 49124139Sjoerg }; 49224139Sjoerg const char **pp; 49324139Sjoerg size_t n; 49424139Sjoerg 49524139Sjoerg if (strlen(s) > 1024 || strchr(s, '=') == NULL) 49624139Sjoerg return 0; 49724139Sjoerg if (strncmp(s, "LD_", 3) == 0) 49824139Sjoerg return 0; 49924139Sjoerg for (pp = noexport; *pp != NULL; pp++) { 50024139Sjoerg n = strlen(*pp); 50124139Sjoerg if (s[n] == '=' && strncmp(s, *pp, n) == 0) 50224139Sjoerg return 0; 50324139Sjoerg } 50424139Sjoerg return 1; 50524139Sjoerg} 50624139Sjoerg 50724139Sjoergstatic void 50824139Sjoergusage(void) 50924139Sjoerg{ 51024139Sjoerg 51124139Sjoerg fprintf(stderr, "usage: su [-] [-flms] [-c class] [login [args]]\n"); 51224139Sjoerg exit(1); 51324139Sjoerg} 51424139Sjoerg 51524139Sjoergstatic int 51624139Sjoergchshell(char *sh) 51724139Sjoerg{ 51824139Sjoerg int r; 51924139Sjoerg char *cp; 52024139Sjoerg 52124139Sjoerg r = 0; 52224139Sjoerg setusershell(); 52324139Sjoerg while ((cp = getusershell()) != NULL && !r) 52424139Sjoerg r = (strcmp(cp, sh) == 0); 52524139Sjoerg endusershell(); 52624139Sjoerg return r; 52724139Sjoerg} 52824139Sjoerg 52924139Sjoergstatic char * 53024139Sjoergontty(void) 53124139Sjoerg{ 53224139Sjoerg char *p; 53324139Sjoerg static char buf[MAXPATHLEN + 4]; 53424139Sjoerg 53524139Sjoerg buf[0] = 0; 53624139Sjoerg p = ttyname(STDERR_FILENO); 53724139Sjoerg if (p) 53824139Sjoerg snprintf(buf, sizeof(buf), " on %s", p); 53924139Sjoerg return buf; 54024139Sjoerg} 54124139Sjoerg