su.c revision 130409
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1988, 1993, 1994 31590Srgrimes * The Regents of the University of California. All rights reserved. 497377Sdes * Copyright (c) 2002 Networks Associates Technologies, Inc. 597377Sdes * All rights reserved. 61590Srgrimes * 797377Sdes * Portions of this software were developed for the FreeBSD Project by 897377Sdes * ThinkSec AS and NAI Labs, the Security Research Division of Network 997377Sdes * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 1097377Sdes * ("CBOSS"), as part of the DARPA CHATS research program. 1197377Sdes * 121590Srgrimes * Redistribution and use in source and binary forms, with or without 131590Srgrimes * modification, are permitted provided that the following conditions 141590Srgrimes * are met: 151590Srgrimes * 1. Redistributions of source code must retain the above copyright 161590Srgrimes * notice, this list of conditions and the following disclaimer. 171590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 181590Srgrimes * notice, this list of conditions and the following disclaimer in the 191590Srgrimes * documentation and/or other materials provided with the distribution. 201590Srgrimes * 3. All advertising materials mentioning features or use of this software 211590Srgrimes * must display the following acknowledgement: 221590Srgrimes * This product includes software developed by the University of 231590Srgrimes * California, Berkeley and its contributors. 241590Srgrimes * 4. Neither the name of the University nor the names of its contributors 251590Srgrimes * may be used to endorse or promote products derived from this software 261590Srgrimes * without specific prior written permission. 271590Srgrimes * 281590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 291590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 301590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 311590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 321590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 331590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 341590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 351590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 361590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 371590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 381590Srgrimes * SUCH DAMAGE. 391590Srgrimes */ 401590Srgrimes 411590Srgrimes#ifndef lint 4214440Smarkmstatic const char copyright[] = 431590Srgrimes"@(#) Copyright (c) 1988, 1993, 1994\n\ 441590Srgrimes The Regents of the University of California. All rights reserved.\n"; 451590Srgrimes#endif /* not lint */ 461590Srgrimes 47127848Scharnier#if 0 481590Srgrimes#ifndef lint 491590Srgrimesstatic char sccsid[] = "@(#)su.c 8.3 (Berkeley) 4/2/94"; 50127848Scharnier#endif /* not lint */ 5128099Scharnier#endif 521590Srgrimes 53127848Scharnier#include <sys/cdefs.h> 54127848Scharnier__FBSDID("$FreeBSD: head/usr.bin/su/su.c 130409 2004-06-13 11:21:06Z markm $"); 55127848Scharnier 561590Srgrimes#include <sys/param.h> 571590Srgrimes#include <sys/time.h> 581590Srgrimes#include <sys/resource.h> 5977220Smarkm#include <sys/wait.h> 601590Srgrimes 611590Srgrimes#include <err.h> 621590Srgrimes#include <errno.h> 631590Srgrimes#include <grp.h> 6477220Smarkm#include <login_cap.h> 651590Srgrimes#include <paths.h> 661590Srgrimes#include <pwd.h> 6777220Smarkm#include <signal.h> 681590Srgrimes#include <stdio.h> 691590Srgrimes#include <stdlib.h> 701590Srgrimes#include <string.h> 711590Srgrimes#include <syslog.h> 721590Srgrimes#include <unistd.h> 7321646Sdavidn 7474874Smarkm#include <security/pam_appl.h> 7591745Sdes#include <security/openpam.h> 7674874Smarkm 77113262Sdes#define PAM_END() do { \ 78113262Sdes int local_ret; \ 79113262Sdes if (pamh != NULL) { \ 80113262Sdes local_ret = pam_setcred(pamh, PAM_DELETE_CRED); \ 81113262Sdes if (local_ret != PAM_SUCCESS) \ 82113262Sdes syslog(LOG_ERR, "pam_setcred: %s", \ 83113262Sdes pam_strerror(pamh, local_ret)); \ 84113262Sdes if (asthem) { \ 85113262Sdes local_ret = pam_close_session(pamh, 0); \ 86113262Sdes if (local_ret != PAM_SUCCESS) \ 87113262Sdes syslog(LOG_ERR, "pam_close_session: %s",\ 88113262Sdes pam_strerror(pamh, local_ret)); \ 89113262Sdes } \ 90113262Sdes local_ret = pam_end(pamh, local_ret); \ 91113262Sdes if (local_ret != PAM_SUCCESS) \ 92113262Sdes syslog(LOG_ERR, "pam_end: %s", \ 93113262Sdes pam_strerror(pamh, local_ret)); \ 94113262Sdes } \ 9577220Smarkm} while (0) 9674874Smarkm 9774874Smarkm 98113262Sdes#define PAM_SET_ITEM(what, item) do { \ 99113262Sdes int local_ret; \ 100113262Sdes local_ret = pam_set_item(pamh, what, item); \ 101113262Sdes if (local_ret != PAM_SUCCESS) { \ 102113262Sdes syslog(LOG_ERR, "pam_set_item(" #what "): %s", \ 103113262Sdes pam_strerror(pamh, local_ret)); \ 104113262Sdes errx(1, "pam_set_item(" #what "): %s", \ 105113262Sdes pam_strerror(pamh, local_ret)); \ 106130409Smarkm /* NOTREACHED */ \ 107113262Sdes } \ 10877220Smarkm} while (0) 1093702Spst 11077220Smarkmenum tristate { UNSET, YES, NO }; 1111590Srgrimes 11277220Smarkmstatic pam_handle_t *pamh = NULL; 11377220Smarkmstatic char **environ_pam; 11477220Smarkm 11577220Smarkmstatic char *ontty(void); 116130409Smarkmstatic int chshell(const char *); 117130409Smarkmstatic void usage(void) __dead2; 118130409Smarkmstatic void export_pam_environment(void); 11977220Smarkmstatic int ok_to_export(const char *); 12077220Smarkm 12177220Smarkmextern char **environ; 12277220Smarkm 1231590Srgrimesint 12477220Smarkmmain(int argc, char *argv[]) 1251590Srgrimes{ 126130409Smarkm static char *cleanenv; 12777220Smarkm struct passwd *pwd; 12891745Sdes struct pam_conv conv = { openpam_ttyconv, NULL }; 12977220Smarkm enum tristate iscsh; 13077220Smarkm login_cap_t *lc; 13183373Smarkm union { 13283373Smarkm const char **a; 13383373Smarkm char * const *b; 13497377Sdes } np; 13577220Smarkm uid_t ruid; 136113262Sdes pid_t child_pid, child_pgrp, pid; 137130409Smarkm int asme, ch, asthem, fastlogin, prio, i, retcode, 138113262Sdes statusp, setmaclabel; 139130409Smarkm u_int setwhat; 140130409Smarkm char *username, *class, shellbuf[MAXPATHLEN]; 14183373Smarkm const char *p, *user, *shell, *mytty, **nargv; 142112695Sdavidxu struct sigaction sa, sa_int, sa_quit, sa_pipe; 143112695Sdavidxu int temp, fds[2]; 14498837Sdillon 14577220Smarkm shell = class = cleanenv = NULL; 14677220Smarkm asme = asthem = fastlogin = statusp = 0; 14710586Sjoerg user = "root"; 14877220Smarkm iscsh = UNSET; 149105758Srwatson setmaclabel = 0; 15077220Smarkm 151105758Srwatson while ((ch = getopt(argc, argv, "-flmsc:")) != -1) 15277220Smarkm switch ((char)ch) { 1531590Srgrimes case 'f': 1541590Srgrimes fastlogin = 1; 1551590Srgrimes break; 1561590Srgrimes case '-': 1571590Srgrimes case 'l': 1581590Srgrimes asme = 0; 1591590Srgrimes asthem = 1; 1601590Srgrimes break; 1611590Srgrimes case 'm': 1621590Srgrimes asme = 1; 1631590Srgrimes asthem = 0; 1641590Srgrimes break; 165105758Srwatson case 's': 166105758Srwatson setmaclabel = 1; 167105758Srwatson break; 16830793Sguido case 'c': 16930793Sguido class = optarg; 17030793Sguido break; 1711590Srgrimes case '?': 1721590Srgrimes default: 17328099Scharnier usage(); 174130409Smarkm /* NOTREACHED */ 17528099Scharnier } 17639538Sroberto 17739538Sroberto if (optind < argc) 17810586Sjoerg user = argv[optind++]; 17910586Sjoerg 18028612Sjoerg if (user == NULL) 18128612Sjoerg usage(); 182130409Smarkm /* NOTREACHED */ 18328612Sjoerg 18477220Smarkm if (strlen(user) > MAXLOGNAME - 1) 18577220Smarkm errx(1, "username too long"); 18610586Sjoerg 187130409Smarkm nargv = malloc(sizeof(char *) * (size_t)(argc + 4)); 18877220Smarkm if (nargv == NULL) 18977220Smarkm errx(1, "malloc failure"); 19077220Smarkm 19110586Sjoerg nargv[argc + 3] = NULL; 19210586Sjoerg for (i = argc; i >= optind; i--) 19377220Smarkm nargv[i + 3] = argv[i]; 19483373Smarkm np.a = &nargv[i + 3]; 19510586Sjoerg 1961590Srgrimes argv += optind; 1971590Srgrimes 1981590Srgrimes errno = 0; 1991590Srgrimes prio = getpriority(PRIO_PROCESS, 0); 2001590Srgrimes if (errno) 2011590Srgrimes prio = 0; 20277220Smarkm 20377220Smarkm setpriority(PRIO_PROCESS, 0, -2); 20474874Smarkm openlog("su", LOG_CONS, LOG_AUTH); 2051590Srgrimes 20677220Smarkm /* get current login name, real uid and shell */ 2071590Srgrimes ruid = getuid(); 2081590Srgrimes username = getlogin(); 20977220Smarkm pwd = getpwnam(username); 21077220Smarkm if (username == NULL || pwd == NULL || pwd->pw_uid != ruid) 2111590Srgrimes pwd = getpwuid(ruid); 2121590Srgrimes if (pwd == NULL) 2131590Srgrimes errx(1, "who are you?"); 21477220Smarkm 2151590Srgrimes username = strdup(pwd->pw_name); 2161590Srgrimes if (username == NULL) 21777220Smarkm err(1, "strdup failure"); 21877220Smarkm 21921646Sdavidn if (asme) { 22021646Sdavidn if (pwd->pw_shell != NULL && *pwd->pw_shell != '\0') { 22177220Smarkm /* must copy - pwd memory is recycled */ 22277220Smarkm shell = strncpy(shellbuf, pwd->pw_shell, 22377220Smarkm sizeof(shellbuf)); 22477220Smarkm shellbuf[sizeof(shellbuf) - 1] = '\0'; 22577220Smarkm } 22677220Smarkm else { 2271590Srgrimes shell = _PATH_BSHELL; 2281590Srgrimes iscsh = NO; 2291590Srgrimes } 23021646Sdavidn } 2311590Srgrimes 23277220Smarkm /* Do the whole PAM startup thing */ 23374874Smarkm retcode = pam_start("su", user, &conv, &pamh); 23474874Smarkm if (retcode != PAM_SUCCESS) { 23574874Smarkm syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, retcode)); 23674874Smarkm errx(1, "pam_start: %s", pam_strerror(pamh, retcode)); 23774874Smarkm } 23874874Smarkm 239110456Sdes PAM_SET_ITEM(PAM_RUSER, username); 24081529Smarkm 24174874Smarkm mytty = ttyname(STDERR_FILENO); 24274874Smarkm if (!mytty) 24374874Smarkm mytty = "tty"; 24477220Smarkm PAM_SET_ITEM(PAM_TTY, mytty); 24577220Smarkm 24677220Smarkm retcode = pam_authenticate(pamh, 0); 24774874Smarkm if (retcode != PAM_SUCCESS) { 248105386Smarkm syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s on %s", 249105386Smarkm username, user, mytty); 25077220Smarkm errx(1, "Sorry"); 25174874Smarkm } 25277220Smarkm retcode = pam_get_item(pamh, PAM_USER, (const void **)&p); 25377220Smarkm if (retcode == PAM_SUCCESS) 25477220Smarkm user = p; 25577220Smarkm else 25677220Smarkm syslog(LOG_ERR, "pam_get_item(PAM_USER): %s", 25777220Smarkm pam_strerror(pamh, retcode)); 258124166Sdes pwd = getpwnam(user); 259124166Sdes if (pwd == NULL) 260124166Sdes errx(1, "unknown login: %s", user); 26174874Smarkm 26277220Smarkm retcode = pam_acct_mgmt(pamh, 0); 26377220Smarkm if (retcode == PAM_NEW_AUTHTOK_REQD) { 26477220Smarkm retcode = pam_chauthtok(pamh, 26577220Smarkm PAM_CHANGE_EXPIRED_AUTHTOK); 26674874Smarkm if (retcode != PAM_SUCCESS) { 26777220Smarkm syslog(LOG_ERR, "pam_chauthtok: %s", 26877220Smarkm pam_strerror(pamh, retcode)); 26974874Smarkm errx(1, "Sorry"); 27074874Smarkm } 27174874Smarkm } 27277220Smarkm if (retcode != PAM_SUCCESS) { 27377220Smarkm syslog(LOG_ERR, "pam_acct_mgmt: %s", 27477220Smarkm pam_strerror(pamh, retcode)); 27577220Smarkm errx(1, "Sorry"); 27677220Smarkm } 27774874Smarkm 278124166Sdes /* get target login information */ 27977220Smarkm if (class == NULL) 28030793Sguido lc = login_getpwclass(pwd); 28177220Smarkm else { 28277220Smarkm if (ruid != 0) 28330793Sguido errx(1, "only root may use -c"); 28430793Sguido lc = login_getclass(class); 28530793Sguido if (lc == NULL) 28630793Sguido errx(1, "unknown class: %s", class); 28730793Sguido } 2881590Srgrimes 28977220Smarkm /* if asme and non-standard target shell, must be root */ 2901590Srgrimes if (asme) { 29177220Smarkm if (ruid != 0 && !chshell(pwd->pw_shell)) 292127848Scharnier errx(1, "permission denied (shell)"); 293130409Smarkm shell = _PATH_BSHELL; 294130409Smarkm iscsh = NO; 29577220Smarkm } 29677220Smarkm else if (pwd->pw_shell && *pwd->pw_shell) { 2971590Srgrimes shell = pwd->pw_shell; 2981590Srgrimes iscsh = UNSET; 29977220Smarkm } 30077220Smarkm else { 3011590Srgrimes shell = _PATH_BSHELL; 3021590Srgrimes iscsh = NO; 3031590Srgrimes } 3041590Srgrimes 3051590Srgrimes /* if we're forking a csh, we want to slightly muck the args */ 3061590Srgrimes if (iscsh == UNSET) { 30714440Smarkm p = strrchr(shell, '/'); 30814440Smarkm if (p) 3091590Srgrimes ++p; 3101590Srgrimes else 3111590Srgrimes p = shell; 31277220Smarkm iscsh = strcmp(p, "csh") ? (strcmp(p, "tcsh") ? NO : YES) : YES; 3131590Srgrimes } 31477220Smarkm setpriority(PRIO_PROCESS, 0, prio); 3151590Srgrimes 316113262Sdes /* Switch to home directory */ 317113262Sdes if (asthem) { 318113262Sdes if (chdir(pwd->pw_dir) < 0) 319113262Sdes errx(1, "no directory"); 320113262Sdes } 321113262Sdes 32221646Sdavidn /* 32377220Smarkm * PAM modules might add supplementary groups in pam_setcred(), so 32477220Smarkm * initialize them first. 32574874Smarkm */ 32674874Smarkm if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) < 0) 32774874Smarkm err(1, "setusercontext"); 32874874Smarkm 32974874Smarkm retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED); 330113262Sdes if (retcode != PAM_SUCCESS) { 331113262Sdes syslog(LOG_ERR, "pam_setcred: %s", 33277220Smarkm pam_strerror(pamh, retcode)); 333113262Sdes errx(1, "failed to establish credentials."); 334113262Sdes } 335113262Sdes if (asthem) { 336113262Sdes retcode = pam_open_session(pamh, 0); 337113262Sdes if (retcode != PAM_SUCCESS) { 338113262Sdes syslog(LOG_ERR, "pam_open_session: %s", 339113262Sdes pam_strerror(pamh, retcode)); 340113262Sdes errx(1, "failed to open session."); 341113262Sdes } 342113262Sdes } 34374874Smarkm 34474874Smarkm /* 34574874Smarkm * We must fork() before setuid() because we need to call 34674874Smarkm * pam_setcred(pamh, PAM_DELETE_CRED) as root. 34774874Smarkm */ 34898837Sdillon sa.sa_flags = SA_RESTART; 349105362Stjr sa.sa_handler = SIG_IGN; 35098837Sdillon sigemptyset(&sa.sa_mask); 35198837Sdillon sigaction(SIGINT, &sa, &sa_int); 35298837Sdillon sigaction(SIGQUIT, &sa, &sa_quit); 353112695Sdavidxu sigaction(SIGPIPE, &sa, &sa_pipe); 354112085Sdavidxu sa.sa_handler = SIG_DFL; 355112085Sdavidxu sigaction(SIGTSTP, &sa, NULL); 35674874Smarkm statusp = 1; 357112695Sdavidxu if (pipe(fds) == -1) { 358130409Smarkm PAM_END(); 359112695Sdavidxu err(1, "pipe"); 360112695Sdavidxu } 36177220Smarkm child_pid = fork(); 36277220Smarkm switch (child_pid) { 36374874Smarkm default: 364122013Sdavidxu sa.sa_handler = SIG_IGN; 365122013Sdavidxu sigaction(SIGTTOU, &sa, NULL); 366112695Sdavidxu close(fds[0]); 367112695Sdavidxu setpgid(child_pid, child_pid); 368122061Sdavidxu tcsetpgrp(STDERR_FILENO, child_pid); 369112695Sdavidxu close(fds[1]); 370112695Sdavidxu sigaction(SIGPIPE, &sa_pipe, NULL); 371113262Sdes while ((pid = waitpid(child_pid, &statusp, WUNTRACED)) != -1) { 37277220Smarkm if (WIFSTOPPED(statusp)) { 37377220Smarkm kill(getpid(), SIGSTOP); 374101722Sache child_pgrp = getpgid(child_pid); 375112695Sdavidxu tcsetpgrp(1, child_pgrp); 376112695Sdavidxu kill(child_pid, SIGCONT); 37777220Smarkm statusp = 1; 37877220Smarkm continue; 37977220Smarkm } 38077220Smarkm break; 38174874Smarkm } 382122061Sdavidxu tcsetpgrp(STDERR_FILENO, getpgrp()); 383113262Sdes if (pid == -1) 38477220Smarkm err(1, "waitpid"); 38581528Smarkm PAM_END(); 386130409Smarkm exit(WEXITSTATUS(statusp)); 38774874Smarkm case -1: 388130409Smarkm PAM_END(); 38977220Smarkm err(1, "fork"); 39074874Smarkm case 0: 391112695Sdavidxu close(fds[1]); 392112695Sdavidxu read(fds[0], &temp, 1); 393112695Sdavidxu close(fds[0]); 394112695Sdavidxu sigaction(SIGPIPE, &sa_pipe, NULL); 39598837Sdillon sigaction(SIGINT, &sa_int, NULL); 39698837Sdillon sigaction(SIGQUIT, &sa_quit, NULL); 397112695Sdavidxu 39877220Smarkm /* 39977220Smarkm * Set all user context except for: Environmental variables 40077220Smarkm * Umask Login records (wtmp, etc) Path 40177220Smarkm */ 40277220Smarkm setwhat = LOGIN_SETALL & ~(LOGIN_SETENV | LOGIN_SETUMASK | 403105758Srwatson LOGIN_SETLOGIN | LOGIN_SETPATH | LOGIN_SETGROUP | 404105758Srwatson LOGIN_SETMAC); 40577220Smarkm /* 406105758Srwatson * If -s is present, also set the MAC label. 407105758Srwatson */ 408105758Srwatson if (setmaclabel) 409105758Srwatson setwhat |= LOGIN_SETMAC; 410105758Srwatson /* 41177220Smarkm * Don't touch resource/priority settings if -m has been used 41277220Smarkm * or -l and -c hasn't, and we're not su'ing to root. 41377220Smarkm */ 41477220Smarkm if ((asme || (!asthem && class == NULL)) && pwd->pw_uid) 41577220Smarkm setwhat &= ~(LOGIN_SETPRIORITY | LOGIN_SETRESOURCES); 41677220Smarkm if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) < 0) 41777220Smarkm err(1, "setusercontext"); 41874874Smarkm 41977220Smarkm if (!asme) { 42077220Smarkm if (asthem) { 42177220Smarkm p = getenv("TERM"); 42277220Smarkm environ = &cleanenv; 423113262Sdes } 42469427Srwatson 425113262Sdes if (asthem || pwd->pw_uid) 426113262Sdes setenv("USER", pwd->pw_name, 1); 427113262Sdes setenv("HOME", pwd->pw_dir, 1); 428113262Sdes setenv("SHELL", shell, 1); 429113262Sdes 430113262Sdes if (asthem) { 43177220Smarkm /* 43277220Smarkm * Add any environmental variables that the 43377220Smarkm * PAM modules may have set. 43477220Smarkm */ 43577220Smarkm environ_pam = pam_getenvlist(pamh); 43677220Smarkm if (environ_pam) 43777220Smarkm export_pam_environment(); 4381590Srgrimes 43977220Smarkm /* set the su'd user's environment & umask */ 44077220Smarkm setusercontext(lc, pwd, pwd->pw_uid, 44177220Smarkm LOGIN_SETPATH | LOGIN_SETUMASK | 44277220Smarkm LOGIN_SETENV); 44377220Smarkm if (p) 44477220Smarkm setenv("TERM", p, 1); 44577220Smarkm } 44677220Smarkm } 44777220Smarkm login_close(lc); 44874874Smarkm 44977220Smarkm if (iscsh == YES) { 45077220Smarkm if (fastlogin) 45183373Smarkm *np.a-- = "-f"; 45277220Smarkm if (asme) 45383373Smarkm *np.a-- = "-m"; 4541590Srgrimes } 45577220Smarkm /* csh strips the first character... */ 45683373Smarkm *np.a = asthem ? "-su" : iscsh == YES ? "_su" : "su"; 45774874Smarkm 45877220Smarkm if (ruid != 0) 45977220Smarkm syslog(LOG_NOTICE, "%s to %s%s", username, user, 46077220Smarkm ontty()); 46174874Smarkm 46283373Smarkm execv(shell, np.b); 46377220Smarkm err(1, "%s", shell); 4641590Srgrimes } 4651590Srgrimes} 4661590Srgrimes 467130409Smarkmstatic void 46877220Smarkmexport_pam_environment(void) 46974874Smarkm{ 47074874Smarkm char **pp; 47174874Smarkm 47274874Smarkm for (pp = environ_pam; *pp != NULL; pp++) { 47374874Smarkm if (ok_to_export(*pp)) 47477220Smarkm putenv(*pp); 47574874Smarkm free(*pp); 47674874Smarkm } 47774874Smarkm} 47874874Smarkm 47974874Smarkm/* 48074874Smarkm * Sanity checks on PAM environmental variables: 48174874Smarkm * - Make sure there is an '=' in the string. 48274874Smarkm * - Make sure the string doesn't run on too long. 48374874Smarkm * - Do not export certain variables. This list was taken from the 48474874Smarkm * Solaris pam_putenv(3) man page. 485113262Sdes * Note that if the user is chrooted, PAM may have a better idea than we 486113262Sdes * do of where her home directory is. 48774874Smarkm */ 48874874Smarkmstatic int 48977220Smarkmok_to_export(const char *s) 49074874Smarkm{ 49174874Smarkm static const char *noexport[] = { 492113262Sdes "SHELL", /* "HOME", */ "LOGNAME", "MAIL", "CDPATH", 49374874Smarkm "IFS", "PATH", NULL 49474874Smarkm }; 49574874Smarkm const char **pp; 49674874Smarkm size_t n; 49774874Smarkm 49874874Smarkm if (strlen(s) > 1024 || strchr(s, '=') == NULL) 49974874Smarkm return 0; 50074874Smarkm if (strncmp(s, "LD_", 3) == 0) 50174874Smarkm return 0; 50274874Smarkm for (pp = noexport; *pp != NULL; pp++) { 50374874Smarkm n = strlen(*pp); 50474874Smarkm if (s[n] == '=' && strncmp(s, *pp, n) == 0) 50574874Smarkm return 0; 50674874Smarkm } 50774874Smarkm return 1; 50874874Smarkm} 50974874Smarkm 51028099Scharnierstatic void 51177220Smarkmusage(void) 51228099Scharnier{ 51381702Sru 514105758Srwatson fprintf(stderr, "usage: su [-] [-flms] [-c class] [login [args]]\n"); 51581702Sru exit(1); 516130409Smarkm /* NOTREACHED */ 51728099Scharnier} 51828099Scharnier 51977220Smarkmstatic int 520130409Smarkmchshell(const char *sh) 5211590Srgrimes{ 52277220Smarkm int r; 5231590Srgrimes char *cp; 5241590Srgrimes 52577220Smarkm r = 0; 52621646Sdavidn setusershell(); 527121236Scognet while ((cp = getusershell()) != NULL && !r) 528121236Scognet r = (strcmp(cp, sh) == 0); 52921646Sdavidn endusershell(); 53021646Sdavidn return r; 5311590Srgrimes} 5321590Srgrimes 53377220Smarkmstatic char * 53477220Smarkmontty(void) 5351590Srgrimes{ 5361590Srgrimes char *p; 5371590Srgrimes static char buf[MAXPATHLEN + 4]; 5381590Srgrimes 5391590Srgrimes buf[0] = 0; 54014440Smarkm p = ttyname(STDERR_FILENO); 54114440Smarkm if (p) 5421590Srgrimes snprintf(buf, sizeof(buf), " on %s", p); 54377220Smarkm return buf; 5441590Srgrimes} 545