su.c revision 112695
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 112695 2003-03-27 01:32:51Z davidxu $"; 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 7781528Smarkm#define PAM_END() do { \ 7877220Smarkm int local_ret; \ 7977220Smarkm if (pamh != NULL && creds_set) { \ 8077220Smarkm local_ret = pam_setcred(pamh, PAM_DELETE_CRED); \ 8177220Smarkm if (local_ret != PAM_SUCCESS) \ 8277220Smarkm syslog(LOG_ERR, "pam_setcred: %s", \ 8377220Smarkm pam_strerror(pamh, local_ret)); \ 8477220Smarkm local_ret = pam_end(pamh, local_ret); \ 8577220Smarkm if (local_ret != PAM_SUCCESS) \ 8677220Smarkm syslog(LOG_ERR, "pam_end: %s", \ 8777220Smarkm pam_strerror(pamh, local_ret)); \ 8877220Smarkm } \ 8977220Smarkm} while (0) 9074874Smarkm 9174874Smarkm 9277220Smarkm#define PAM_SET_ITEM(what, item) do { \ 9377220Smarkm int local_ret; \ 9477220Smarkm local_ret = pam_set_item(pamh, what, item); \ 9577220Smarkm if (local_ret != PAM_SUCCESS) { \ 9677220Smarkm syslog(LOG_ERR, "pam_set_item(" #what "): %s", \ 9777220Smarkm pam_strerror(pamh, local_ret)); \ 9877220Smarkm errx(1, "pam_set_item(" #what "): %s", \ 9977220Smarkm pam_strerror(pamh, local_ret)); \ 10077220Smarkm } \ 10177220Smarkm} while (0) 1023702Spst 10377220Smarkmenum tristate { UNSET, YES, NO }; 1041590Srgrimes 10577220Smarkmstatic pam_handle_t *pamh = NULL; 10677220Smarkmstatic int creds_set = 0; 10777220Smarkmstatic char **environ_pam; 10877220Smarkm 10977220Smarkmstatic char *ontty(void); 11077220Smarkmstatic int chshell(char *); 11177220Smarkmstatic void usage(void); 11277220Smarkmstatic int export_pam_environment(void); 11377220Smarkmstatic int ok_to_export(const char *); 11477220Smarkm 11577220Smarkmextern char **environ; 11677220Smarkm 1171590Srgrimesint 11877220Smarkmmain(int argc, char *argv[]) 1191590Srgrimes{ 12077220Smarkm struct passwd *pwd; 12191745Sdes struct pam_conv conv = { openpam_ttyconv, NULL }; 12277220Smarkm enum tristate iscsh; 12377220Smarkm login_cap_t *lc; 12483373Smarkm union { 12583373Smarkm const char **a; 12683373Smarkm char * const *b; 12797377Sdes } np; 12877220Smarkm uid_t ruid; 12977220Smarkm int asme, ch, asthem, fastlogin, prio, i, setwhat, retcode, 130105758Srwatson statusp, child_pid, child_pgrp, ret_pid, setmaclabel; 13189746Sdes char *username, *cleanenv, *class, shellbuf[MAXPATHLEN]; 13283373Smarkm const char *p, *user, *shell, *mytty, **nargv; 133112695Sdavidxu struct sigaction sa, sa_int, sa_quit, sa_pipe; 134112695Sdavidxu int temp, fds[2]; 13598837Sdillon 13677220Smarkm shell = class = cleanenv = NULL; 13777220Smarkm asme = asthem = fastlogin = statusp = 0; 13810586Sjoerg user = "root"; 13977220Smarkm iscsh = UNSET; 140105758Srwatson setmaclabel = 0; 14177220Smarkm 142105758Srwatson while ((ch = getopt(argc, argv, "-flmsc:")) != -1) 14377220Smarkm switch ((char)ch) { 1441590Srgrimes case 'f': 1451590Srgrimes fastlogin = 1; 1461590Srgrimes break; 1471590Srgrimes case '-': 1481590Srgrimes case 'l': 1491590Srgrimes asme = 0; 1501590Srgrimes asthem = 1; 1511590Srgrimes break; 1521590Srgrimes case 'm': 1531590Srgrimes asme = 1; 1541590Srgrimes asthem = 0; 1551590Srgrimes break; 156105758Srwatson case 's': 157105758Srwatson setmaclabel = 1; 158105758Srwatson break; 15930793Sguido case 'c': 16030793Sguido class = optarg; 16130793Sguido break; 1621590Srgrimes case '?': 1631590Srgrimes default: 16428099Scharnier usage(); 16528099Scharnier } 16639538Sroberto 16739538Sroberto if (optind < argc) 16810586Sjoerg user = argv[optind++]; 16910586Sjoerg 17028612Sjoerg if (user == NULL) 17128612Sjoerg usage(); 17228612Sjoerg 17377220Smarkm if (strlen(user) > MAXLOGNAME - 1) 17477220Smarkm errx(1, "username too long"); 17510586Sjoerg 17677220Smarkm nargv = malloc(sizeof(char *) * (argc + 4)); 17777220Smarkm if (nargv == NULL) 17877220Smarkm errx(1, "malloc failure"); 17977220Smarkm 18010586Sjoerg nargv[argc + 3] = NULL; 18110586Sjoerg for (i = argc; i >= optind; i--) 18277220Smarkm nargv[i + 3] = argv[i]; 18383373Smarkm np.a = &nargv[i + 3]; 18410586Sjoerg 1851590Srgrimes argv += optind; 1861590Srgrimes 1871590Srgrimes errno = 0; 1881590Srgrimes prio = getpriority(PRIO_PROCESS, 0); 1891590Srgrimes if (errno) 1901590Srgrimes prio = 0; 19177220Smarkm 19277220Smarkm setpriority(PRIO_PROCESS, 0, -2); 19374874Smarkm openlog("su", LOG_CONS, LOG_AUTH); 1941590Srgrimes 19577220Smarkm /* get current login name, real uid and shell */ 1961590Srgrimes ruid = getuid(); 1971590Srgrimes username = getlogin(); 19877220Smarkm pwd = getpwnam(username); 19977220Smarkm if (username == NULL || pwd == NULL || pwd->pw_uid != ruid) 2001590Srgrimes pwd = getpwuid(ruid); 2011590Srgrimes if (pwd == NULL) 2021590Srgrimes errx(1, "who are you?"); 20377220Smarkm 2041590Srgrimes username = strdup(pwd->pw_name); 2051590Srgrimes if (username == NULL) 20677220Smarkm err(1, "strdup failure"); 20777220Smarkm 20821646Sdavidn if (asme) { 20921646Sdavidn if (pwd->pw_shell != NULL && *pwd->pw_shell != '\0') { 21077220Smarkm /* must copy - pwd memory is recycled */ 21177220Smarkm shell = strncpy(shellbuf, pwd->pw_shell, 21277220Smarkm sizeof(shellbuf)); 21377220Smarkm shellbuf[sizeof(shellbuf) - 1] = '\0'; 21477220Smarkm } 21577220Smarkm else { 2161590Srgrimes shell = _PATH_BSHELL; 2171590Srgrimes iscsh = NO; 2181590Srgrimes } 21921646Sdavidn } 2201590Srgrimes 22177220Smarkm /* Do the whole PAM startup thing */ 22274874Smarkm retcode = pam_start("su", user, &conv, &pamh); 22374874Smarkm if (retcode != PAM_SUCCESS) { 22474874Smarkm syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, retcode)); 22574874Smarkm errx(1, "pam_start: %s", pam_strerror(pamh, retcode)); 22674874Smarkm } 22774874Smarkm 228110456Sdes PAM_SET_ITEM(PAM_RUSER, username); 22981529Smarkm 23074874Smarkm mytty = ttyname(STDERR_FILENO); 23174874Smarkm if (!mytty) 23274874Smarkm mytty = "tty"; 23377220Smarkm PAM_SET_ITEM(PAM_TTY, mytty); 23477220Smarkm 23577220Smarkm retcode = pam_authenticate(pamh, 0); 23674874Smarkm if (retcode != PAM_SUCCESS) { 237105386Smarkm#if 0 23877220Smarkm syslog(LOG_ERR, "pam_authenticate: %s", 23977220Smarkm pam_strerror(pamh, retcode)); 240105386Smarkm#endif 241105386Smarkm syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s on %s", 242105386Smarkm username, user, mytty); 24377220Smarkm errx(1, "Sorry"); 24474874Smarkm } 24577220Smarkm retcode = pam_get_item(pamh, PAM_USER, (const void **)&p); 24677220Smarkm if (retcode == PAM_SUCCESS) 24777220Smarkm user = p; 24877220Smarkm else 24977220Smarkm syslog(LOG_ERR, "pam_get_item(PAM_USER): %s", 25077220Smarkm pam_strerror(pamh, retcode)); 25174874Smarkm 25277220Smarkm retcode = pam_acct_mgmt(pamh, 0); 25377220Smarkm if (retcode == PAM_NEW_AUTHTOK_REQD) { 25477220Smarkm retcode = pam_chauthtok(pamh, 25577220Smarkm PAM_CHANGE_EXPIRED_AUTHTOK); 25674874Smarkm if (retcode != PAM_SUCCESS) { 25777220Smarkm syslog(LOG_ERR, "pam_chauthtok: %s", 25877220Smarkm pam_strerror(pamh, retcode)); 25974874Smarkm errx(1, "Sorry"); 26074874Smarkm } 26174874Smarkm } 26277220Smarkm if (retcode != PAM_SUCCESS) { 26377220Smarkm syslog(LOG_ERR, "pam_acct_mgmt: %s", 26477220Smarkm pam_strerror(pamh, retcode)); 26577220Smarkm errx(1, "Sorry"); 26677220Smarkm } 26774874Smarkm 2681590Srgrimes /* get target login information, default to root */ 26977220Smarkm pwd = getpwnam(user); 27077220Smarkm if (pwd == NULL) 2719502Swollman errx(1, "unknown login: %s", user); 27277220Smarkm if (class == NULL) 27330793Sguido lc = login_getpwclass(pwd); 27477220Smarkm else { 27577220Smarkm if (ruid != 0) 27630793Sguido errx(1, "only root may use -c"); 27730793Sguido lc = login_getclass(class); 27830793Sguido if (lc == NULL) 27930793Sguido errx(1, "unknown class: %s", class); 28030793Sguido } 2811590Srgrimes 28277220Smarkm /* if asme and non-standard target shell, must be root */ 2831590Srgrimes if (asme) { 28477220Smarkm if (ruid != 0 && !chshell(pwd->pw_shell)) 2851590Srgrimes errx(1, "permission denied (shell)."); 28677220Smarkm } 28777220Smarkm else if (pwd->pw_shell && *pwd->pw_shell) { 2881590Srgrimes shell = pwd->pw_shell; 2891590Srgrimes iscsh = UNSET; 29077220Smarkm } 29177220Smarkm else { 2921590Srgrimes shell = _PATH_BSHELL; 2931590Srgrimes iscsh = NO; 2941590Srgrimes } 2951590Srgrimes 2961590Srgrimes /* if we're forking a csh, we want to slightly muck the args */ 2971590Srgrimes if (iscsh == UNSET) { 29814440Smarkm p = strrchr(shell, '/'); 29914440Smarkm if (p) 3001590Srgrimes ++p; 3011590Srgrimes else 3021590Srgrimes p = shell; 30377220Smarkm iscsh = strcmp(p, "csh") ? (strcmp(p, "tcsh") ? NO : YES) : YES; 3041590Srgrimes } 30577220Smarkm setpriority(PRIO_PROCESS, 0, prio); 3061590Srgrimes 30721646Sdavidn /* 30877220Smarkm * PAM modules might add supplementary groups in pam_setcred(), so 30977220Smarkm * initialize them first. 31074874Smarkm */ 31174874Smarkm if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) < 0) 31274874Smarkm err(1, "setusercontext"); 31374874Smarkm 31474874Smarkm retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED); 31577220Smarkm if (retcode != PAM_SUCCESS) 31677220Smarkm syslog(LOG_ERR, "pam_setcred(pamh, PAM_ESTABLISH_CRED): %s", 31777220Smarkm pam_strerror(pamh, retcode)); 31877220Smarkm else 31977220Smarkm creds_set = 1; 32074874Smarkm 32174874Smarkm /* 32274874Smarkm * We must fork() before setuid() because we need to call 32374874Smarkm * pam_setcred(pamh, PAM_DELETE_CRED) as root. 32474874Smarkm */ 32598837Sdillon sa.sa_flags = SA_RESTART; 326105362Stjr sa.sa_handler = SIG_IGN; 32798837Sdillon sigemptyset(&sa.sa_mask); 32898837Sdillon sigaction(SIGINT, &sa, &sa_int); 32998837Sdillon sigaction(SIGQUIT, &sa, &sa_quit); 330112695Sdavidxu sigaction(SIGPIPE, &sa, &sa_pipe); 331112085Sdavidxu sa.sa_handler = SIG_DFL; 332112085Sdavidxu sigaction(SIGTSTP, &sa, NULL); 33374874Smarkm statusp = 1; 334112695Sdavidxu if (pipe(fds) == -1) { 335112695Sdavidxu err(1, "pipe"); 336112695Sdavidxu PAM_END(); 337112695Sdavidxu exit(1); 338112695Sdavidxu } 33977220Smarkm child_pid = fork(); 34077220Smarkm switch (child_pid) { 34174874Smarkm default: 342112695Sdavidxu close(fds[0]); 343112695Sdavidxu setpgid(child_pid, child_pid); 344112695Sdavidxu tcsetpgrp(1, child_pid); 345112695Sdavidxu close(fds[1]); 346112695Sdavidxu sigaction(SIGPIPE, &sa_pipe, NULL); 347112695Sdavidxu while ((ret_pid = waitpid(child_pid, &statusp, WUNTRACED)) != 348112695Sdavidxu -1) { 34977220Smarkm if (WIFSTOPPED(statusp)) { 35077220Smarkm kill(getpid(), SIGSTOP); 351101722Sache child_pgrp = getpgid(child_pid); 352112695Sdavidxu tcsetpgrp(1, child_pgrp); 353112695Sdavidxu kill(child_pid, SIGCONT); 35477220Smarkm statusp = 1; 35577220Smarkm continue; 35677220Smarkm } 35777220Smarkm break; 35874874Smarkm } 35977220Smarkm if (ret_pid == -1) 36077220Smarkm err(1, "waitpid"); 36181528Smarkm PAM_END(); 36277220Smarkm exit(statusp); 36374874Smarkm case -1: 36477220Smarkm err(1, "fork"); 36581528Smarkm PAM_END(); 36677220Smarkm exit(1); 36774874Smarkm case 0: 368112695Sdavidxu close(fds[1]); 369112695Sdavidxu read(fds[0], &temp, 1); 370112695Sdavidxu close(fds[0]); 371112695Sdavidxu sigaction(SIGPIPE, &sa_pipe, NULL); 37298837Sdillon sigaction(SIGINT, &sa_int, NULL); 37398837Sdillon sigaction(SIGQUIT, &sa_quit, NULL); 374112695Sdavidxu 37577220Smarkm /* 37677220Smarkm * Set all user context except for: Environmental variables 37777220Smarkm * Umask Login records (wtmp, etc) Path 37877220Smarkm */ 37977220Smarkm setwhat = LOGIN_SETALL & ~(LOGIN_SETENV | LOGIN_SETUMASK | 380105758Srwatson LOGIN_SETLOGIN | LOGIN_SETPATH | LOGIN_SETGROUP | 381105758Srwatson LOGIN_SETMAC); 38277220Smarkm /* 383105758Srwatson * If -s is present, also set the MAC label. 384105758Srwatson */ 385105758Srwatson if (setmaclabel) 386105758Srwatson setwhat |= LOGIN_SETMAC; 387105758Srwatson /* 38877220Smarkm * Don't touch resource/priority settings if -m has been used 38977220Smarkm * or -l and -c hasn't, and we're not su'ing to root. 39077220Smarkm */ 39177220Smarkm if ((asme || (!asthem && class == NULL)) && pwd->pw_uid) 39277220Smarkm setwhat &= ~(LOGIN_SETPRIORITY | LOGIN_SETRESOURCES); 39377220Smarkm if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) < 0) 39477220Smarkm err(1, "setusercontext"); 39574874Smarkm 39677220Smarkm if (!asme) { 39777220Smarkm if (asthem) { 39877220Smarkm p = getenv("TERM"); 39977220Smarkm environ = &cleanenv; 40069427Srwatson 40177220Smarkm /* 40277220Smarkm * Add any environmental variables that the 40377220Smarkm * PAM modules may have set. 40477220Smarkm */ 40577220Smarkm environ_pam = pam_getenvlist(pamh); 40677220Smarkm if (environ_pam) 40777220Smarkm export_pam_environment(); 4081590Srgrimes 40977220Smarkm /* set the su'd user's environment & umask */ 41077220Smarkm setusercontext(lc, pwd, pwd->pw_uid, 41177220Smarkm LOGIN_SETPATH | LOGIN_SETUMASK | 41277220Smarkm LOGIN_SETENV); 41377220Smarkm if (p) 41477220Smarkm setenv("TERM", p, 1); 41577220Smarkm if (chdir(pwd->pw_dir) < 0) 41677220Smarkm errx(1, "no directory"); 41777220Smarkm } 41877220Smarkm if (asthem || pwd->pw_uid) 41977220Smarkm setenv("USER", pwd->pw_name, 1); 42077220Smarkm setenv("HOME", pwd->pw_dir, 1); 42177220Smarkm setenv("SHELL", shell, 1); 42277220Smarkm } 42377220Smarkm login_close(lc); 42474874Smarkm 42577220Smarkm if (iscsh == YES) { 42677220Smarkm if (fastlogin) 42783373Smarkm *np.a-- = "-f"; 42877220Smarkm if (asme) 42983373Smarkm *np.a-- = "-m"; 4301590Srgrimes } 43177220Smarkm /* csh strips the first character... */ 43283373Smarkm *np.a = asthem ? "-su" : iscsh == YES ? "_su" : "su"; 43374874Smarkm 43477220Smarkm if (ruid != 0) 43577220Smarkm syslog(LOG_NOTICE, "%s to %s%s", username, user, 43677220Smarkm ontty()); 43774874Smarkm 43883373Smarkm execv(shell, np.b); 43977220Smarkm err(1, "%s", shell); 4401590Srgrimes } 4411590Srgrimes} 4421590Srgrimes 44374874Smarkmstatic int 44477220Smarkmexport_pam_environment(void) 44574874Smarkm{ 44674874Smarkm char **pp; 44774874Smarkm 44874874Smarkm for (pp = environ_pam; *pp != NULL; pp++) { 44974874Smarkm if (ok_to_export(*pp)) 45077220Smarkm putenv(*pp); 45174874Smarkm free(*pp); 45274874Smarkm } 45374874Smarkm return PAM_SUCCESS; 45474874Smarkm} 45574874Smarkm 45674874Smarkm/* 45774874Smarkm * Sanity checks on PAM environmental variables: 45874874Smarkm * - Make sure there is an '=' in the string. 45974874Smarkm * - Make sure the string doesn't run on too long. 46074874Smarkm * - Do not export certain variables. This list was taken from the 46174874Smarkm * Solaris pam_putenv(3) man page. 46274874Smarkm */ 46374874Smarkmstatic int 46477220Smarkmok_to_export(const char *s) 46574874Smarkm{ 46674874Smarkm static const char *noexport[] = { 46774874Smarkm "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH", 46874874Smarkm "IFS", "PATH", NULL 46974874Smarkm }; 47074874Smarkm const char **pp; 47174874Smarkm size_t n; 47274874Smarkm 47374874Smarkm if (strlen(s) > 1024 || strchr(s, '=') == NULL) 47474874Smarkm return 0; 47574874Smarkm if (strncmp(s, "LD_", 3) == 0) 47674874Smarkm return 0; 47774874Smarkm for (pp = noexport; *pp != NULL; pp++) { 47874874Smarkm n = strlen(*pp); 47974874Smarkm if (s[n] == '=' && strncmp(s, *pp, n) == 0) 48074874Smarkm return 0; 48174874Smarkm } 48274874Smarkm return 1; 48374874Smarkm} 48474874Smarkm 48528099Scharnierstatic void 48677220Smarkmusage(void) 48728099Scharnier{ 48881702Sru 489105758Srwatson fprintf(stderr, "usage: su [-] [-flms] [-c class] [login [args]]\n"); 49081702Sru exit(1); 49128099Scharnier} 49228099Scharnier 49377220Smarkmstatic int 49477220Smarkmchshell(char *sh) 4951590Srgrimes{ 49677220Smarkm int r; 4971590Srgrimes char *cp; 4981590Srgrimes 49977220Smarkm r = 0; 50021646Sdavidn setusershell(); 50177220Smarkm do { 50277220Smarkm cp = getusershell(); 50377220Smarkm r = strcmp(cp, sh); 50477220Smarkm } while (!r && cp != NULL); 50521646Sdavidn endusershell(); 50621646Sdavidn return r; 5071590Srgrimes} 5081590Srgrimes 50977220Smarkmstatic char * 51077220Smarkmontty(void) 5111590Srgrimes{ 5121590Srgrimes char *p; 5131590Srgrimes static char buf[MAXPATHLEN + 4]; 5141590Srgrimes 5151590Srgrimes buf[0] = 0; 51614440Smarkm p = ttyname(STDERR_FILENO); 51714440Smarkm if (p) 5181590Srgrimes snprintf(buf, sizeof(buf), " on %s", p); 51977220Smarkm return buf; 5201590Srgrimes} 521