diff --git a/src/cmd/ksh93/DESIGN b/src/cmd/ksh93/DESIGN index 32aecbadd614..ae808d406308 100644 --- a/src/cmd/ksh93/DESIGN +++ b/src/cmd/ksh93/DESIGN @@ -146,17 +146,15 @@ sh directory: 25. subshell.c contains the code to save and restore environments so that subshells can run without creating a new process. - 26. suid_exec.c contains the program from running execute - only and/or setuid/setgid scripts. - 27. tdump.c contains the code to dump a parse tree into + 26. tdump.c contains the code to dump a parse tree into a file. - 28. timers.c contains code for multiple event timeouts. - 29. trestore contains the code for restoring the parse + 27. timers.c contains code for multiple event timeouts. + 28. trestore contains the code for restoring the parse tree from the file created by tdump. - 30. waitevent.c contains the sh_waitnotify function so + 29. waitevent.c contains the sh_waitnotify function so that builtins can handle processing events when the shell is waiting for input or for process completion. - 31. xec.c is the main shell execution loop. + 30. xec.c is the main shell execution loop. edit directory: 1. completion.c contains code for command and file generation and diff --git a/src/cmd/ksh93/Mamfile b/src/cmd/ksh93/Mamfile index 8ae6404cbaef..bc366ca1a254 100644 --- a/src/cmd/ksh93/Mamfile +++ b/src/cmd/ksh93/Mamfile @@ -1367,26 +1367,6 @@ make install prev ${mam_libnetwork} exec - ${CC} ${CCLDFLAGS} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS} ${mam_cc_L+-L.} ${mam_cc_L+-L${INSTALLROOT}/lib} -o shcomp shcomp.o ${mam_libshell} ${mam_libnsl} ${mam_libast} -lm done shcomp generated - make suid_exec - make suid_exec.o - make sh/suid_exec.c - prev include/version.h implicit - prev ${PACKAGE_ast_INCLUDE}/error.h implicit - prev ${PACKAGE_ast_INCLUDE}/sig.h implicit - prev ${PACKAGE_ast_INCLUDE}/ls.h implicit - prev FEATURE/externs implicit - prev ${PACKAGE_ast_INCLUDE}/ast.h implicit - done sh/suid_exec.c - prev sh/suid_exec.c - exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Iinclude -I${PACKAGE_ast_INCLUDE} -DERROR_CONTEXT_T=Error_context_t -D_API_ast=20100309 -D_PACKAGE_ast -c sh/suid_exec.c - done suid_exec.o generated - prev +ljobs - prev +li - prev ${mam_libsocket} - prev ${mam_libsecdb} - prev ${mam_libnetwork} - exec - ${CC} ${CCLDFLAGS} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS} ${mam_cc_L+-L.} ${mam_cc_L+-L${INSTALLROOT}/lib} -o suid_exec suid_exec.o ${mam_libast} ${mam_libnsl} ${mam_libast} -lm - done suid_exec generated make shell prev libshell.a archive done shell virtual @@ -1473,10 +1453,6 @@ make install exec - then ${STDCP} include/history.h ${PACKAGE_ast_INCLUDE}/history.h exec - fi done ${PACKAGE_ast_INCLUDE}/history.h generated - make ${INSTALLROOT}/bin/suid_exec - prev suid_exec - exec - ${STDCMP} 2>/dev/null -s suid_exec ${INSTALLROOT}/bin/suid_exec || { ${STDMV} ${INSTALLROOT}/bin/suid_exec ${INSTALLROOT}/bin/suid_exec.old 2>/dev/null || true; ${STDCP} suid_exec ${INSTALLROOT}/bin/suid_exec ;} - done ${INSTALLROOT}/bin/suid_exec generated make ${INSTALLROOT}/bin/shcomp prev shcomp exec - ${STDCMP} 2>/dev/null -s shcomp ${INSTALLROOT}/bin/shcomp || { ${STDMV} ${INSTALLROOT}/bin/shcomp ${INSTALLROOT}/bin/shcomp.old 2>/dev/null || true; ${STDCP} shcomp ${INSTALLROOT}/bin/shcomp ;} diff --git a/src/cmd/ksh93/README b/src/cmd/ksh93/README index 542ee0af100d..6dc5c3c65413 100644 --- a/src/cmd/ksh93/README +++ b/src/cmd/ksh93/README @@ -144,8 +144,6 @@ The options have the following defaults and meanings: STATS on Add .sh.stats compound variable. - SUID_EXEC on Execute /etc/suid_exec for setuid, setgid script. - SYSRC Source /etc/ksh.kshrc on initializing an interactive shell. This is on by default if /etc/ksh.kshrc or /etc/bash.bashrc exists at compile time. @@ -222,19 +220,6 @@ a script. ksh93 is able to recognize files in this format and process them as scripts. You can use shcomp to send out scripts when you don't want to give away the original script source. -To be able to run setuid/setgid shell scripts, or scripts without read -permission, the SUID_EXEC compile option must be on, and ksh must be installed -in the /bin directory, the /usr/bin directory, the /usr/lbin directory, -or the /usr/local/bin directory and the name must end in sh. The program -suid_exec must be installed in the /etc directory, must be owned by root, -and must be an SUID program. If you must install ksh in some other directory -and want to be able to run setuid/setgid and execute only scripts, then -you will have to change the source code file sh/suid_exec.c explicitly. -If you do not have ksh in one of these secure locations, /bin/sh will -be invoked with the -p options and will fail when you execute a setuid/setgid -and/or execute only script. Note that ksh does not read the .profile -or $ENV file when the real and effective user/group IDs are not equal. - #### TESTING KSH #### The tests subdirectory contains a number of regression tests for ksh. diff --git a/src/cmd/ksh93/SHOPT.sh b/src/cmd/ksh93/SHOPT.sh index 484b30f4001b..2b61901748e9 100644 --- a/src/cmd/ksh93/SHOPT.sh +++ b/src/cmd/ksh93/SHOPT.sh @@ -36,7 +36,6 @@ SHOPT REMOTE= # enable --rc if running as a remote shell SHOPT SCRIPTONLY=0 # build ksh for running scripts only; compile out the interactive shell SHOPT SPAWN= # use spawnveg for fork/exec SHOPT STATS=1 # add .sh.stats variable -SHOPT SUID_EXEC=1 # allow (safe) SUID/SGID shell scripts SHOPT SYSRC= # attempt . /etc/ksh.kshrc if interactive SHOPT TEST_L= # add 'test -l' as an alias for 'test -L' SHOPT TIMEOUT= # number of seconds for shell timeout diff --git a/src/cmd/ksh93/data/msg.c b/src/cmd/ksh93/data/msg.c index ac39ec39e68b..339016dc593e 100644 --- a/src/cmd/ksh93/data/msg.c +++ b/src/cmd/ksh93/data/msg.c @@ -182,13 +182,6 @@ const char e_suidprofile[] = "/etc/suid_profile"; #if SHOPT_SYSRC const char e_sysrc[] = "/etc/ksh.kshrc"; #endif -#ifdef BUILD_DTKSH - const char e_suidexec[] = SUIDEXECPATH; -#else -#if SHOPT_SUID_EXEC - const char e_suidexec[] = "/etc/suid_exec"; -#endif /* SHOPT_SUID_EXEC */ -#endif #if !SHOPT_SCRIPTONLY const char hist_fname[] = "/.sh_history"; #endif /* !SHOPT_SCRIPTONLY */ diff --git a/src/cmd/ksh93/include/path.h b/src/cmd/ksh93/include/path.h index 59fc71fea933..b1c8299f0a48 100644 --- a/src/cmd/ksh93/include/path.h +++ b/src/cmd/ksh93/include/path.h @@ -108,9 +108,6 @@ extern const char e_mailmsg[]; extern const char e_suidprofile[]; extern const char e_sysprofile[]; extern const char e_traceprompt[]; -#if SHOPT_SUID_EXEC - extern const char e_suidexec[]; -#endif /* SHOPT_SUID_EXEC */ extern const char is_alias[]; extern const char is_builtin[]; extern const char is_spcbuiltin[]; diff --git a/src/cmd/ksh93/sh/path.c b/src/cmd/ksh93/sh/path.c index 102237442283..65e6c8bc0c65 100644 --- a/src/cmd/ksh93/sh/path.c +++ b/src/cmd/ksh93/sh/path.c @@ -2,7 +2,7 @@ * * * This software is part of the ast package * * Copyright (c) 1982-2012 AT&T Intellectual Property * -* Copyright (c) 2020-2022 Contributors to ksh 93u+m * +* Copyright (c) 2020-2023 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * @@ -1214,10 +1214,6 @@ pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t case EISDIR: return -1; case ENOEXEC: -#if SHOPT_SUID_EXEC - case EPERM: - /* some systems return EPERM if setuid bit is on */ -#endif errno = ENOEXEC; if(spawn) { @@ -1253,10 +1249,8 @@ pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t /* FALLTHROUGH */ case ENAMETOOLONG: #endif /* ENAMETOOLONG */ -#if !SHOPT_SUID_EXEC /* FALLTHROUGH */ case EPERM: -#endif sh.path_err = errno; return(-1); case ENOTDIR: @@ -1316,64 +1310,11 @@ static noreturn void exscript(register char *path,register char *argv[],char **e sh_close(sh.infd); sh_setstate(sh_state(SH_FORKED)); sfsync(sfstderr); -#if SHOPT_SUID_EXEC - /* check if file cannot open for read or script is setuid/setgid */ - { - static char name[] = "/tmp/euidXXXXXXXXXX"; - register int n; - register uid_t euserid; - char *savet=0; - struct stat statb; - if((n=sh_open(path,O_RDONLY,0)) >= 0) - { - /* move if n=0,1,2 */ - n = sh_iomovefd(n); - if(fstat(n,&statb)>=0 && !(statb.st_mode&(S_ISUID|S_ISGID))) - goto openok; - sh_close(n); - } - if((euserid=geteuid()) != sh.userid) - { - strncpy(name+9,fmtbase((intmax_t)sh.current_pid,10,0),sizeof(name)-10); - /* create an SUID open file with owner equal to effective UID */ - if((n=open(name,O_CREAT|O_TRUNC|O_WRONLY,S_ISUID|S_IXUSR)) < 0) - goto fail; - unlink(name); - /* make sure that file has right owner */ - if(fstat(n,&statb)<0 || statb.st_uid != euserid) - goto fail; - if(n!=10) - { - sh_close(10); - fcntl(n, F_DUPFD, 10); - sh_close(n); - n=10; - } - } - savet = *--argv; - *argv = path; - execve(e_suidexec,argv,envp); - fail: - /* - * The following code is just for compatibility - */ - if((n=open(path,O_RDONLY,0)) < 0) - { - errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path); - UNREACHABLE(); - } - if(savet) - *argv++ = savet; - openok: - sh.infd = n; - } -#else if((sh.infd = sh_open(path,O_RDONLY,0)) < 0) { errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path); UNREACHABLE(); } -#endif sh.infd = sh_iomovefd(sh.infd); #if SHOPT_ACCT sh_accbegin(path) ; /* reset accounting */ diff --git a/src/cmd/ksh93/sh/suid_exec.c b/src/cmd/ksh93/sh/suid_exec.c deleted file mode 100644 index dbfb58c2c500..000000000000 --- a/src/cmd/ksh93/sh/suid_exec.c +++ /dev/null @@ -1,511 +0,0 @@ -/*********************************************************************** -* * -* This software is part of the ast package * -* Copyright (c) 1982-2011 AT&T Intellectual Property * -* Copyright (c) 2020-2022 Contributors to ksh 93u+m * -* and is licensed under the * -* Eclipse Public License, Version 2.0 * -* * -* A copy of the License is available at * -* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * -* (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * -* * -* David Korn * -* Martijn Dekker * -* Johnothan King * -* * -***********************************************************************/ -/* - * This is a program to execute 'execute only' and SUID/SGID shell scripts. - * This program must be owned by root and must have the setuid bit set. - * It must not have the set group ID bit set. This program must be installed - * where the define parameter THISPROG indicates to work correctly on System V. - * - * Written by David Korn - * AT&T Labs - * Enhanced by Rob Stampfli - */ - -/* The file name of the script to execute is argv[0] - * argv[1] is the program name - * The basic idea is to open the script as standard input, set the effective - * user and group ID correctly, and then exec the shell. - * The complicated part is getting the effective UID of the caller and - * setting the effective UID/GID. The program which execs this program - * may pass file descriptor FDIN as an open file with mode SPECIAL if - * the effective user ID is not the real user ID. The effective - * user ID for authentication purposes will be the owner of this - * open file. On systems without the setreuid() call, e[ug]id is set - * by copying this program to a /tmp/file, making it an SUID and/or SGID - * program, and then execing this program. - * A forked version of this program waits until it can unlink the /tmp - * file and then exits. Actually, we fork() twice so the parent can - * wait for the child to complete. A pipe is used to guarantee that we - * do not remove the /tmp file too soon. - */ - -#include -#include "FEATURE/externs" -#include -#include -#include -#include -#include "version.h" - -#define SPECIAL 04100 /* setuid execute only by owner */ -#define FDIN 10 /* must be same as /dev/fd below */ -#undef FDSYNC -#define FDSYNC 11 /* used on SysV to synchronize cleanup */ -#define FDVERIFY 12 /* used to validate /tmp process */ -#undef BLKSIZE -#define BLKSIZE sizeof(char*)*1024 -#if BUILD_DTKSH -#define THISPROG SUIDEXECPATH -#else -#define THISPROG "/etc/suid_exec" -#endif -#define DEFSHELL "/bin/sh" - -static void error_exit(const char*); -static int in_dir(const char*, const char*); -static int endsh(const char*); -#ifndef _lib_setregid -# undef _lib_setreuid -#endif -#ifndef _lib_setreuid - static void setids(int,uid_t,gid_t); - static int mycopy(int, int); - static void maketemp(char*); -#else - static void setids(int,int,int); -#endif /* _lib_setreuid */ - -static const char version[] = "\n@(#)$Id: suid_exec "SH_RELEASE" $\n"; -static const char badopen[] = "cannot open"; -static const char badexec[] = "cannot exec"; -static const char devfd[] = "/dev/fd/10"; /* must match FDIN above */ -#ifndef _lib_setreuid -static char tmpname[] = "/tmp/SUIDXXXXXX"; -#endif -static char **arglist; - -static char *shell; -static char *command; -static uid_t ruserid; -static uid_t euserid; -static gid_t rgroupid; -static gid_t egroupid; -static struct stat statb; - -int main(int argc,char *argv[]) -{ - register int m,n; - register char *p; - struct stat statx; - int mode; - uid_t effuid; - gid_t effgid; - NOT_USED(argc); - arglist = argv; - if((command = argv[1]) == 0) - error_exit(badexec); - ruserid = getuid(); - euserid = geteuid(); - rgroupid = getgid(); - egroupid = getegid(); - p = argv[0]; -#ifndef _lib_setreuid - maketemp(tmpname); - if(strcmp(p,tmpname)==0) - { - /* At this point, the presumption is that we are the - * version of THISPROG copied into /tmp, with the owner, - * group, and setuid/gid bits correctly set. This copy of - * the program is executable by anyone, so we must be careful - * not to allow just any invocation of it to succeed, since - * it is setuid/gid. Validate the proper execution by - * examining the FDVERIFY file descriptor -- if it is owned - * by root and is mode SPECIAL, then this is proof that it was - * passed by a program with superuser privileges -- hence we - * can presume legitimacy. Otherwise, bail out, as we suspect - * an impostor. - */ - if(fstat(FDVERIFY,&statb) < 0 || statb.st_uid != 0 || - (statb.st_mode & ~S_IFMT) != SPECIAL || close(FDVERIFY)<0) - error_exit(badexec); - /* This enables the grandchild to clean up /tmp file */ - close(FDSYNC); - /* Make sure that this is a valid invocation of the clone. - * Perhaps unnecessary, given FDVERIFY, but what the heck... - */ - if(stat(tmpname,&statb) < 0 || statb.st_nlink != 1 || - !S_ISREG(statb.st_mode)) - error_exit(badexec); - if(ruserid != euserid && - ((statb.st_mode & S_ISUID) == 0 || statb.st_uid != euserid)) - error_exit(badexec); - goto exec; - } - /* Make sure that this is the real setuid program, not the clone. - * It is possible by clever hacking to get past this point in the - * clone, but it doesn't do the hacker any good that I can see. - */ - if(euserid) - error_exit(badexec); -#endif /* _lib_setreuid */ - /* Open the script for reading first and then validate it. This - * prevents someone from pulling a switcheroo while we are validating. - */ - n = open(p,0); - if(n == FDIN) - { - n = dup(n); - close(FDIN); - } - if(n < 0) - error_exit(badopen); - /* validate execution rights to this script */ - if(fstat(FDIN,&statb) < 0 || (statb.st_mode & ~S_IFMT) != SPECIAL) - euserid = ruserid; - else - euserid = statb.st_uid; - /* do it the easy way if you can */ - if(euserid == ruserid && egroupid == rgroupid) - { - if(access(p,X_OK) < 0) - error_exit(badexec); - } - else - { - /* have to check access on each component */ - while(*p++) - { - if(*p == '/' || *p == 0) - { - m = *p; - *p = 0; - if(eaccess(argv[0],X_OK) < 0) - error_exit(badexec); - *p = m; - } - } - p = argv[0]; - } - if(fstat(n, &statb) < 0 || !S_ISREG(statb.st_mode)) - error_exit(badopen); - if(stat(p, &statx) < 0 || - statb.st_ino != statx.st_ino || statb.st_dev != statx.st_dev) - error_exit(badexec); - if(stat(THISPROG, &statx) < 0 || - (statb.st_ino == statx.st_ino && statb.st_dev == statx.st_dev)) - error_exit(badexec); - close(FDIN); - if(fcntl(n,F_DUPFD,FDIN) != FDIN) - error_exit(badexec); - close(n); - - /* compute the desired new effective user and group ID */ - effuid = euserid; - effgid = egroupid; - mode = 0; - if(statb.st_mode & S_ISUID) - effuid = statb.st_uid; - if(statb.st_mode & S_ISGID) - effgid = statb.st_gid; - - /* see if group needs setting */ - if(effgid != egroupid) - if(effgid != rgroupid || setgid(rgroupid) < 0) - mode = S_ISGID; - - /* now see if the UID needs setting */ - if(mode) - { - if(effuid != ruserid) - mode |= S_ISUID; - } - else if(effuid) - { - if(effuid != ruserid || setuid(ruserid) < 0) - mode = S_ISUID; - } - - if(mode) - setids(mode, effuid, effgid); -#ifndef _lib_setreuid -exec: -#endif /* _lib_setreuid */ - /* only use SHELL if file is in trusted directory and ends in sh */ - shell = getenv("SHELL"); - if(shell == 0 || !endsh(shell) || ( -#ifdef BUILD_DTKSH - !in_dir(CDE_INSTALLATION_TOP"/bin",shell) && -#endif - !in_dir("/bin",shell) && - !in_dir("/usr/bin",shell) && - !in_dir("/usr/lbin",shell) && - !in_dir("/usr/local/bin",shell))) - shell = DEFSHELL; - argv[0] = command; - argv[1] = (char*)devfd; - execv(shell,argv); - error_exit(badexec); -} - -/* - * return true if shell ends in sh or ksh - */ -static int endsh(register const char *shell) -{ - while(*shell) - shell++; - if(*--shell != 'h' || *--shell != 's') - return(0); - if(*--shell=='/') - return(1); - if(*shell=='k' && *--shell=='/') - return(1); - return(0); -} - - -/* - * return true if shell is in directory - */ -static int in_dir(register const char *dir,register const char *shell) -{ - while(*dir) - { - if(*dir++ != *shell++) - return(0); - } - /* return true if next character is a '/' */ - return(*shell=='/'); -} - -static void error_exit(const char *message) -{ - sfprintf(sfstdout,"%s: %s\n",command,message); - exit(126); -} - - -/* - * This version of access checks against effective UID and effective GID - */ -int eaccess(register const char *name, register int mode) -{ - struct stat statb; - if (stat(name, &statb) == 0) - { - if(euserid == 0) - { - if(!S_ISREG(statb.st_mode) || mode != 1) - return(0); - /* root needs execute permission for someone */ - mode = (S_IXUSR|S_IXGRP|S_IXOTH); - } - else if(euserid == statb.st_uid) - mode <<= 6; - else if(egroupid == statb.st_gid) - mode <<= 3; -#ifdef _lib_getgroups - /* on some systems you can be in several groups */ - else - { - static int maxgroups; - gid_t *groups=0; - register int n; - if(maxgroups==0) - { - /* first time */ - if((maxgroups=getgroups(0,groups)) < 0) - { - /* pre-POSIX system */ - maxgroups = (int)astconf_long(CONF_NGROUPS_MAX); - } - } - groups = (gid_t*)malloc((maxgroups+1)*sizeof(gid_t)); - if(!groups) - { - error(ERROR_SYSTEM|ERROR_PANIC,"out of memory"); - UNREACHABLE(); - } - n = getgroups(maxgroups,groups); - while(--n >= 0) - { - if(groups[n] == statb.st_gid) - { - mode <<= 3; - break; - } - } - } -#endif /* _lib_getgroups */ - if(statb.st_mode & mode) - return(0); - } - return(-1); -} - -#ifdef _lib_setreuid -static void setids(int mode,int owner,int group) -{ - if(mode & S_ISGID) - setregid(rgroupid,group); - - /* set effective UID even if S_ISUID is not set. This is because - * we are *really* executing EUID root at this point. Even if S_ISUID - * is not set, the value for owner that is passed should be correct. - */ - setreuid(ruserid,owner); -} - -#else -/* - * This version of setids creates a /tmp file and copies itself into it. - * The "clone" file is made executable with appropriate SUID/SGID bits. - * Finally, the clone is exec'd. This file is unlinked by a grandchild - * of this program, who waits around until the text is free. - */ -static void setids(int mode,uid_t owner,gid_t group) -{ - register int n,m; - int pv[2]; - - /* - * Create a token to pass to the new program for validation. - * This token can only be procured by someone running with an - * effective user ID of root, and hence gives the clone a way to - * certify that it was really invoked by THISPROG. Someone who - * is already root could spoof us, but why would they want to? - * - * Since we are root here, we must be careful: What if someone - * linked a valuable file to tmpname? - */ - unlink(tmpname); /* should normally fail */ -#ifdef O_EXCL - if((n = open(tmpname, O_WRONLY | O_CREAT | O_EXCL, SPECIAL)) < 0 || - unlink(tmpname) < 0) -#else - if((n = open(tmpname, O_WRONLY | O_CREAT ,SPECIAL)) < 0 || unlink(tmpname) < 0) -#endif - error_exit(badexec); - if(n != FDVERIFY) - { - close(FDVERIFY); - if(fcntl(n,F_DUPFD,FDVERIFY) != FDVERIFY) - error_exit(badexec); - } - mode |= S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6); - /* create a pipe for synchronization */ - if(pipe(pv) < 0) - error_exit(badexec); - if((n=fork()) == 0) - { /* child */ - close(FDVERIFY); - close(pv[1]); - if((n=fork()) == 0) - { /* grandchild -- cleans up clone file */ - signal(SIGHUP, SIG_IGN); - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - signal(SIGTERM, SIG_IGN); - read(pv[0],pv,1); /* wait for clone to close pipe */ - while(unlink(tmpname) < 0 && errno == ETXTBSY) - sleep(1); - exit(0); - } - else if(n == -1) - exit(1); - else - { - /* Create a set[ug]id file that will become the clone. - * To make this atomic, without need for chown(), the - * child takes on desired user and group. The only - * downsize of this that I can see is that it may - * screw up some per- * user accounting. - */ - if((m = open(THISPROG, O_RDONLY)) < 0) - exit(1); - if((mode & S_ISGID) && setgid(group) < 0) - exit(1); - if((mode & S_ISUID) && owner && setuid(owner) < 0) - exit(1); -#ifdef O_EXCL - if((n = open(tmpname,O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, mode)) < 0) -#else - unlink(tmpname); - if((n = open(tmpname,O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0) -#endif /* O_EXCL */ - exit(1); - /* populate the clone */ - m = mycopy(m,n); - if(chmod(tmpname,mode) <0) - exit(1); - exit(m); - } - } - else if(n == -1) - error_exit(badexec); - else - { - arglist[0] = (char*)tmpname; - close(pv[0]); - /* move write end of pipe into FDSYNC */ - if(pv[1] != FDSYNC) - { - close(FDSYNC); - if(fcntl(pv[1],F_DUPFD,FDSYNC) != FDSYNC) - error_exit(badexec); - } - /* wait for child to die */ - while((m = wait(0)) != n) - if(m == -1 && errno != EINTR) - break; - /* Kill any setuid status at this point. That way, if the - * clone is not setuid, we won't exec it as root. Also, don't - * neglect to consider that someone could have switched the - * clone file on us. - */ - if(setuid(ruserid) < 0) - error_exit(badexec); - execv(tmpname,arglist); - error_exit(badexec); - } -} - -/* - * create a unique name into the