su.c revision 113262
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 471590Srgrimes#ifndef lint 4828099Scharnier#if 0 491590Srgrimesstatic char sccsid[] = "@(#)su.c 8.3 (Berkeley) 4/2/94"; 5028099Scharnier#endif 5114440Smarkmstatic const char rcsid[] = 5250477Speter "$FreeBSD: head/usr.bin/su/su.c 113262 2003-04-08 16:59:53Z des $"; 531590Srgrimes#endif /* not lint */ 541590Srgrimes 551590Srgrimes#include <sys/param.h> 561590Srgrimes#include <sys/time.h> 571590Srgrimes#include <sys/resource.h> 5877220Smarkm#include <sys/wait.h> 591590Srgrimes 601590Srgrimes#include <err.h> 611590Srgrimes#include <errno.h> 621590Srgrimes#include <grp.h> 6377220Smarkm#include <libutil.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)); \ 106113262Sdes } \ 10777220Smarkm} while (0) 1083702Spst 10977220Smarkmenum tristate { UNSET, YES, NO }; 1101590Srgrimes 11177220Smarkmstatic pam_handle_t *pamh = NULL; 11277220Smarkmstatic char **environ_pam; 11377220Smarkm 11477220Smarkmstatic char *ontty(void); 11577220Smarkmstatic int chshell(char *); 11677220Smarkmstatic void usage(void); 11777220Smarkmstatic int export_pam_environment(void); 11877220Smarkmstatic int ok_to_export(const char *); 11977220Smarkm 12077220Smarkmextern char **environ; 12177220Smarkm 1221590Srgrimesint 12377220Smarkmmain(int argc, char *argv[]) 1241590Srgrimes{ 12577220Smarkm struct passwd *pwd; 12691745Sdes struct pam_conv conv = { openpam_ttyconv, NULL }; 12777220Smarkm enum tristate iscsh; 12877220Smarkm login_cap_t *lc; 12983373Smarkm union { 13083373Smarkm const char **a; 13183373Smarkm char * const *b; 13297377Sdes } np; 13377220Smarkm uid_t ruid; 134113262Sdes pid_t child_pid, child_pgrp, pid; 13577220Smarkm int asme, ch, asthem, fastlogin, prio, i, setwhat, retcode, 136113262Sdes statusp, setmaclabel; 13789746Sdes char *username, *cleanenv, *class, shellbuf[MAXPATHLEN]; 13883373Smarkm const char *p, *user, *shell, *mytty, **nargv; 139112695Sdavidxu struct sigaction sa, sa_int, sa_quit, sa_pipe; 140112695Sdavidxu int temp, fds[2]; 14198837Sdillon 14277220Smarkm shell = class = cleanenv = NULL; 14377220Smarkm asme = asthem = fastlogin = statusp = 0; 14410586Sjoerg user = "root"; 14577220Smarkm iscsh = UNSET; 146105758Srwatson setmaclabel = 0; 14777220Smarkm 148105758Srwatson while ((ch = getopt(argc, argv, "-flmsc:")) != -1) 14977220Smarkm switch ((char)ch) { 1501590Srgrimes case 'f': 1511590Srgrimes fastlogin = 1; 1521590Srgrimes break; 1531590Srgrimes case '-': 1541590Srgrimes case 'l': 1551590Srgrimes asme = 0; 1561590Srgrimes asthem = 1; 1571590Srgrimes break; 1581590Srgrimes case 'm': 1591590Srgrimes asme = 1; 1601590Srgrimes asthem = 0; 1611590Srgrimes break; 162105758Srwatson case 's': 163105758Srwatson setmaclabel = 1; 164105758Srwatson break; 16530793Sguido case 'c': 16630793Sguido class = optarg; 16730793Sguido break; 1681590Srgrimes case '?': 1691590Srgrimes default: 17028099Scharnier usage(); 17128099Scharnier } 17239538Sroberto 17339538Sroberto if (optind < argc) 17410586Sjoerg user = argv[optind++]; 17510586Sjoerg 17628612Sjoerg if (user == NULL) 17728612Sjoerg usage(); 17828612Sjoerg 17977220Smarkm if (strlen(user) > MAXLOGNAME - 1) 18077220Smarkm errx(1, "username too long"); 18110586Sjoerg 18277220Smarkm nargv = malloc(sizeof(char *) * (argc + 4)); 18377220Smarkm if (nargv == NULL) 18477220Smarkm errx(1, "malloc failure"); 18577220Smarkm 18610586Sjoerg nargv[argc + 3] = NULL; 18710586Sjoerg for (i = argc; i >= optind; i--) 18877220Smarkm nargv[i + 3] = argv[i]; 18983373Smarkm np.a = &nargv[i + 3]; 19010586Sjoerg 1911590Srgrimes argv += optind; 1921590Srgrimes 1931590Srgrimes errno = 0; 1941590Srgrimes prio = getpriority(PRIO_PROCESS, 0); 1951590Srgrimes if (errno) 1961590Srgrimes prio = 0; 19777220Smarkm 19877220Smarkm setpriority(PRIO_PROCESS, 0, -2); 19974874Smarkm openlog("su", LOG_CONS, LOG_AUTH); 2001590Srgrimes 20177220Smarkm /* get current login name, real uid and shell */ 2021590Srgrimes ruid = getuid(); 2031590Srgrimes username = getlogin(); 20477220Smarkm pwd = getpwnam(username); 20577220Smarkm if (username == NULL || pwd == NULL || pwd->pw_uid != ruid) 2061590Srgrimes pwd = getpwuid(ruid); 2071590Srgrimes if (pwd == NULL) 2081590Srgrimes errx(1, "who are you?"); 20977220Smarkm 2101590Srgrimes username = strdup(pwd->pw_name); 2111590Srgrimes if (username == NULL) 21277220Smarkm err(1, "strdup failure"); 21377220Smarkm 21421646Sdavidn if (asme) { 21521646Sdavidn if (pwd->pw_shell != NULL && *pwd->pw_shell != '\0') { 21677220Smarkm /* must copy - pwd memory is recycled */ 21777220Smarkm shell = strncpy(shellbuf, pwd->pw_shell, 21877220Smarkm sizeof(shellbuf)); 21977220Smarkm shellbuf[sizeof(shellbuf) - 1] = '\0'; 22077220Smarkm } 22177220Smarkm else { 2221590Srgrimes shell = _PATH_BSHELL; 2231590Srgrimes iscsh = NO; 2241590Srgrimes } 22521646Sdavidn } 2261590Srgrimes 22777220Smarkm /* Do the whole PAM startup thing */ 22874874Smarkm retcode = pam_start("su", user, &conv, &pamh); 22974874Smarkm if (retcode != PAM_SUCCESS) { 23074874Smarkm syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, retcode)); 23174874Smarkm errx(1, "pam_start: %s", pam_strerror(pamh, retcode)); 23274874Smarkm } 23374874Smarkm 234110456Sdes PAM_SET_ITEM(PAM_RUSER, username); 23581529Smarkm 23674874Smarkm mytty = ttyname(STDERR_FILENO); 23774874Smarkm if (!mytty) 23874874Smarkm mytty = "tty"; 23977220Smarkm PAM_SET_ITEM(PAM_TTY, mytty); 24077220Smarkm 24177220Smarkm retcode = pam_authenticate(pamh, 0); 24274874Smarkm if (retcode != PAM_SUCCESS) { 243105386Smarkm#if 0 24477220Smarkm syslog(LOG_ERR, "pam_authenticate: %s", 24577220Smarkm pam_strerror(pamh, retcode)); 246105386Smarkm#endif 247105386Smarkm syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s on %s", 248105386Smarkm username, user, mytty); 24977220Smarkm errx(1, "Sorry"); 25074874Smarkm } 25177220Smarkm retcode = pam_get_item(pamh, PAM_USER, (const void **)&p); 25277220Smarkm if (retcode == PAM_SUCCESS) 25377220Smarkm user = p; 25477220Smarkm else 25577220Smarkm syslog(LOG_ERR, "pam_get_item(PAM_USER): %s", 25677220Smarkm pam_strerror(pamh, retcode)); 25774874Smarkm 25877220Smarkm retcode = pam_acct_mgmt(pamh, 0); 25977220Smarkm if (retcode == PAM_NEW_AUTHTOK_REQD) { 26077220Smarkm retcode = pam_chauthtok(pamh, 26177220Smarkm PAM_CHANGE_EXPIRED_AUTHTOK); 26274874Smarkm if (retcode != PAM_SUCCESS) { 26377220Smarkm syslog(LOG_ERR, "pam_chauthtok: %s", 26477220Smarkm pam_strerror(pamh, retcode)); 26574874Smarkm errx(1, "Sorry"); 26674874Smarkm } 26774874Smarkm } 26877220Smarkm if (retcode != PAM_SUCCESS) { 26977220Smarkm syslog(LOG_ERR, "pam_acct_mgmt: %s", 27077220Smarkm pam_strerror(pamh, retcode)); 27177220Smarkm errx(1, "Sorry"); 27277220Smarkm } 27374874Smarkm 2741590Srgrimes /* get target login information, default to root */ 27577220Smarkm pwd = getpwnam(user); 27677220Smarkm if (pwd == NULL) 2779502Swollman errx(1, "unknown login: %s", user); 27877220Smarkm if (class == NULL) 27930793Sguido lc = login_getpwclass(pwd); 28077220Smarkm else { 28177220Smarkm if (ruid != 0) 28230793Sguido errx(1, "only root may use -c"); 28330793Sguido lc = login_getclass(class); 28430793Sguido if (lc == NULL) 28530793Sguido errx(1, "unknown class: %s", class); 28630793Sguido } 2871590Srgrimes 28877220Smarkm /* if asme and non-standard target shell, must be root */ 2891590Srgrimes if (asme) { 29077220Smarkm if (ruid != 0 && !chshell(pwd->pw_shell)) 2911590Srgrimes errx(1, "permission denied (shell)."); 29277220Smarkm } 29377220Smarkm else if (pwd->pw_shell && *pwd->pw_shell) { 2941590Srgrimes shell = pwd->pw_shell; 2951590Srgrimes iscsh = UNSET; 29677220Smarkm } 29777220Smarkm else { 2981590Srgrimes shell = _PATH_BSHELL; 2991590Srgrimes iscsh = NO; 3001590Srgrimes } 3011590Srgrimes 3021590Srgrimes /* if we're forking a csh, we want to slightly muck the args */ 3031590Srgrimes if (iscsh == UNSET) { 30414440Smarkm p = strrchr(shell, '/'); 30514440Smarkm if (p) 3061590Srgrimes ++p; 3071590Srgrimes else 3081590Srgrimes p = shell; 30977220Smarkm iscsh = strcmp(p, "csh") ? (strcmp(p, "tcsh") ? NO : YES) : YES; 3101590Srgrimes } 31177220Smarkm setpriority(PRIO_PROCESS, 0, prio); 3121590Srgrimes 313113262Sdes /* Switch to home directory */ 314113262Sdes if (asthem) { 315113262Sdes if (chdir(pwd->pw_dir) < 0) 316113262Sdes errx(1, "no directory"); 317113262Sdes } 318113262Sdes 31921646Sdavidn /* 32077220Smarkm * PAM modules might add supplementary groups in pam_setcred(), so 32177220Smarkm * initialize them first. 32274874Smarkm */ 32374874Smarkm if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) < 0) 32474874Smarkm err(1, "setusercontext"); 32574874Smarkm 32674874Smarkm retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED); 327113262Sdes if (retcode != PAM_SUCCESS) { 328113262Sdes syslog(LOG_ERR, "pam_setcred: %s", 32977220Smarkm pam_strerror(pamh, retcode)); 330113262Sdes errx(1, "failed to establish credentials."); 331113262Sdes } 332113262Sdes if (asthem) { 333113262Sdes retcode = pam_open_session(pamh, 0); 334113262Sdes if (retcode != PAM_SUCCESS) { 335113262Sdes syslog(LOG_ERR, "pam_open_session: %s", 336113262Sdes pam_strerror(pamh, retcode)); 337113262Sdes errx(1, "failed to open session."); 338113262Sdes } 339113262Sdes } 34074874Smarkm 34174874Smarkm /* 34274874Smarkm * We must fork() before setuid() because we need to call 34374874Smarkm * pam_setcred(pamh, PAM_DELETE_CRED) as root. 34474874Smarkm */ 34598837Sdillon sa.sa_flags = SA_RESTART; 346105362Stjr sa.sa_handler = SIG_IGN; 34798837Sdillon sigemptyset(&sa.sa_mask); 34898837Sdillon sigaction(SIGINT, &sa, &sa_int); 34998837Sdillon sigaction(SIGQUIT, &sa, &sa_quit); 350112695Sdavidxu sigaction(SIGPIPE, &sa, &sa_pipe); 351112085Sdavidxu sa.sa_handler = SIG_DFL; 352112085Sdavidxu sigaction(SIGTSTP, &sa, NULL); 35374874Smarkm statusp = 1; 354112695Sdavidxu if (pipe(fds) == -1) { 355112695Sdavidxu err(1, "pipe"); 356112695Sdavidxu PAM_END(); 357112695Sdavidxu exit(1); 358112695Sdavidxu } 35977220Smarkm child_pid = fork(); 36077220Smarkm switch (child_pid) { 36174874Smarkm default: 362112695Sdavidxu close(fds[0]); 363112695Sdavidxu setpgid(child_pid, child_pid); 364112695Sdavidxu tcsetpgrp(1, child_pid); 365112695Sdavidxu close(fds[1]); 366112695Sdavidxu sigaction(SIGPIPE, &sa_pipe, NULL); 367113262Sdes while ((pid = waitpid(child_pid, &statusp, WUNTRACED)) != -1) { 36877220Smarkm if (WIFSTOPPED(statusp)) { 36977220Smarkm kill(getpid(), SIGSTOP); 370101722Sache child_pgrp = getpgid(child_pid); 371112695Sdavidxu tcsetpgrp(1, child_pgrp); 372112695Sdavidxu kill(child_pid, SIGCONT); 37377220Smarkm statusp = 1; 37477220Smarkm continue; 37577220Smarkm } 37677220Smarkm break; 37774874Smarkm } 378113262Sdes if (pid == -1) 37977220Smarkm err(1, "waitpid"); 38081528Smarkm PAM_END(); 38177220Smarkm exit(statusp); 38274874Smarkm case -1: 38377220Smarkm err(1, "fork"); 38481528Smarkm PAM_END(); 38577220Smarkm exit(1); 38674874Smarkm case 0: 387112695Sdavidxu close(fds[1]); 388112695Sdavidxu read(fds[0], &temp, 1); 389112695Sdavidxu close(fds[0]); 390112695Sdavidxu sigaction(SIGPIPE, &sa_pipe, NULL); 39198837Sdillon sigaction(SIGINT, &sa_int, NULL); 39298837Sdillon sigaction(SIGQUIT, &sa_quit, NULL); 393112695Sdavidxu 39477220Smarkm /* 39577220Smarkm * Set all user context except for: Environmental variables 39677220Smarkm * Umask Login records (wtmp, etc) Path 39777220Smarkm */ 39877220Smarkm setwhat = LOGIN_SETALL & ~(LOGIN_SETENV | LOGIN_SETUMASK | 399105758Srwatson LOGIN_SETLOGIN | LOGIN_SETPATH | LOGIN_SETGROUP | 400105758Srwatson LOGIN_SETMAC); 40177220Smarkm /* 402105758Srwatson * If -s is present, also set the MAC label. 403105758Srwatson */ 404105758Srwatson if (setmaclabel) 405105758Srwatson setwhat |= LOGIN_SETMAC; 406105758Srwatson /* 40777220Smarkm * Don't touch resource/priority settings if -m has been used 40877220Smarkm * or -l and -c hasn't, and we're not su'ing to root. 40977220Smarkm */ 41077220Smarkm if ((asme || (!asthem && class == NULL)) && pwd->pw_uid) 41177220Smarkm setwhat &= ~(LOGIN_SETPRIORITY | LOGIN_SETRESOURCES); 41277220Smarkm if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) < 0) 41377220Smarkm err(1, "setusercontext"); 41474874Smarkm 41577220Smarkm if (!asme) { 41677220Smarkm if (asthem) { 41777220Smarkm p = getenv("TERM"); 41877220Smarkm environ = &cleanenv; 419113262Sdes } 42069427Srwatson 421113262Sdes if (asthem || pwd->pw_uid) 422113262Sdes setenv("USER", pwd->pw_name, 1); 423113262Sdes setenv("HOME", pwd->pw_dir, 1); 424113262Sdes setenv("SHELL", shell, 1); 425113262Sdes 426113262Sdes if (asthem) { 42777220Smarkm /* 42877220Smarkm * Add any environmental variables that the 42977220Smarkm * PAM modules may have set. 43077220Smarkm */ 43177220Smarkm environ_pam = pam_getenvlist(pamh); 43277220Smarkm if (environ_pam) 43377220Smarkm export_pam_environment(); 4341590Srgrimes 43577220Smarkm /* set the su'd user's environment & umask */ 43677220Smarkm setusercontext(lc, pwd, pwd->pw_uid, 43777220Smarkm LOGIN_SETPATH | LOGIN_SETUMASK | 43877220Smarkm LOGIN_SETENV); 43977220Smarkm if (p) 44077220Smarkm setenv("TERM", p, 1); 44177220Smarkm } 44277220Smarkm } 44377220Smarkm login_close(lc); 44474874Smarkm 44577220Smarkm if (iscsh == YES) { 44677220Smarkm if (fastlogin) 44783373Smarkm *np.a-- = "-f"; 44877220Smarkm if (asme) 44983373Smarkm *np.a-- = "-m"; 4501590Srgrimes } 45177220Smarkm /* csh strips the first character... */ 45283373Smarkm *np.a = asthem ? "-su" : iscsh == YES ? "_su" : "su"; 45374874Smarkm 45477220Smarkm if (ruid != 0) 45577220Smarkm syslog(LOG_NOTICE, "%s to %s%s", username, user, 45677220Smarkm ontty()); 45774874Smarkm 45883373Smarkm execv(shell, np.b); 45977220Smarkm err(1, "%s", shell); 4601590Srgrimes } 4611590Srgrimes} 4621590Srgrimes 46374874Smarkmstatic int 46477220Smarkmexport_pam_environment(void) 46574874Smarkm{ 46674874Smarkm char **pp; 46774874Smarkm 46874874Smarkm for (pp = environ_pam; *pp != NULL; pp++) { 46974874Smarkm if (ok_to_export(*pp)) 47077220Smarkm putenv(*pp); 47174874Smarkm free(*pp); 47274874Smarkm } 47374874Smarkm return PAM_SUCCESS; 47474874Smarkm} 47574874Smarkm 47674874Smarkm/* 47774874Smarkm * Sanity checks on PAM environmental variables: 47874874Smarkm * - Make sure there is an '=' in the string. 47974874Smarkm * - Make sure the string doesn't run on too long. 48074874Smarkm * - Do not export certain variables. This list was taken from the 48174874Smarkm * Solaris pam_putenv(3) man page. 482113262Sdes * Note that if the user is chrooted, PAM may have a better idea than we 483113262Sdes * do of where her home directory is. 48474874Smarkm */ 48574874Smarkmstatic int 48677220Smarkmok_to_export(const char *s) 48774874Smarkm{ 48874874Smarkm static const char *noexport[] = { 489113262Sdes "SHELL", /* "HOME", */ "LOGNAME", "MAIL", "CDPATH", 49074874Smarkm "IFS", "PATH", NULL 49174874Smarkm }; 49274874Smarkm const char **pp; 49374874Smarkm size_t n; 49474874Smarkm 49574874Smarkm if (strlen(s) > 1024 || strchr(s, '=') == NULL) 49674874Smarkm return 0; 49774874Smarkm if (strncmp(s, "LD_", 3) == 0) 49874874Smarkm return 0; 49974874Smarkm for (pp = noexport; *pp != NULL; pp++) { 50074874Smarkm n = strlen(*pp); 50174874Smarkm if (s[n] == '=' && strncmp(s, *pp, n) == 0) 50274874Smarkm return 0; 50374874Smarkm } 50474874Smarkm return 1; 50574874Smarkm} 50674874Smarkm 50728099Scharnierstatic void 50877220Smarkmusage(void) 50928099Scharnier{ 51081702Sru 511105758Srwatson fprintf(stderr, "usage: su [-] [-flms] [-c class] [login [args]]\n"); 51281702Sru exit(1); 51328099Scharnier} 51428099Scharnier 51577220Smarkmstatic int 51677220Smarkmchshell(char *sh) 5171590Srgrimes{ 51877220Smarkm int r; 5191590Srgrimes char *cp; 5201590Srgrimes 52177220Smarkm r = 0; 52221646Sdavidn setusershell(); 52377220Smarkm do { 52477220Smarkm cp = getusershell(); 52577220Smarkm r = strcmp(cp, sh); 52677220Smarkm } while (!r && cp != NULL); 52721646Sdavidn endusershell(); 52821646Sdavidn return r; 5291590Srgrimes} 5301590Srgrimes 53177220Smarkmstatic char * 53277220Smarkmontty(void) 5331590Srgrimes{ 5341590Srgrimes char *p; 5351590Srgrimes static char buf[MAXPATHLEN + 4]; 5361590Srgrimes 5371590Srgrimes buf[0] = 0; 53814440Smarkm p = ttyname(STDERR_FILENO); 53914440Smarkm if (p) 5401590Srgrimes snprintf(buf, sizeof(buf), " on %s", p); 54177220Smarkm return buf; 5421590Srgrimes} 543