diff options
Diffstat (limited to 'gnu/libexec/uucp/libunix/spawn.c')
-rw-r--r-- | gnu/libexec/uucp/libunix/spawn.c | 456 |
1 files changed, 0 insertions, 456 deletions
diff --git a/gnu/libexec/uucp/libunix/spawn.c b/gnu/libexec/uucp/libunix/spawn.c deleted file mode 100644 index 6a413c48a063..000000000000 --- a/gnu/libexec/uucp/libunix/spawn.c +++ /dev/null @@ -1,456 +0,0 @@ -/* spawn.c - Spawn a program securely. - - Copyright (C) 1992, 1993, 1994, 1995 Ian Lance Taylor - - This file is part of the Taylor UUCP package. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The author of the program may be contacted at ian@airs.com or - c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144. - */ - -/* $FreeBSD$ */ - -#include "uucp.h" - -#include "uudefs.h" -#include "sysdep.h" - -#include <errno.h> -#include <paths.h> - -#if HAVE_FCNTL_H -#include <fcntl.h> -#else -#if HAVE_SYS_FILE_H -#include <sys/file.h> -#endif -#endif - -#ifndef O_RDONLY -#define O_RDONLY 0 -#define O_WRONLY 1 -#define O_RDWR 2 -#endif - -#ifndef FD_CLOEXEC -#define FD_CLOEXEC 1 -#endif - -#ifndef environ -extern char **environ; -#endif - -/* Spawn a child in a fairly secure fashion. This returns the process - ID of the child or -1 on error. It takes far too many arguments: - - pazargs -- arguments (element 0 is command) - aidescs -- file descriptors for stdin, stdout and stderr - fkeepuid -- TRUE if euid should be left unchanged - fkeepenv -- TRUE if environment should be left unmodified - zchdir -- directory to chdir to - fnosigs -- TRUE if child should ignore SIGHUP, SIGINT and SIGQUIT - fshell -- TRUE if should try /bin/sh if execve gets ENOEXEC - zpath -- value for environment variable PATH - zuu_machine -- value for environment variable UU_MACHINE - zuu_user -- value for environment variable UU_USER - - The aidescs array is three elements long. 0 is stdin, 1 is stdout - and 2 is stderr. The array may contain either file descriptor - numbers to dup appropriately, or one of the following: - - SPAWN_NULL -- set descriptor to /dev/null - SPAWN_READ_PIPE -- set aidescs element to pipe for parent to read - SPAWN_WRITE_PIPE -- set aidescs element to pipe for parent to write - - If fkeepenv is FALSE, a standard environment is created. The - environment arguments (zpath, zuu_machine and zuu_user) are only - used if fkeepenv is FALSE; any of them may be NULL. - - This routine expects that all file descriptors have been set to - close-on-exec, so it doesn't have to worry about closing them - explicitly. It sets the close-on-exec flag for the new pipe - descriptors it returns. */ - -pid_t -ixsspawn (pazargs, aidescs, fkeepuid, fkeepenv, zchdir, fnosigs, fshell, - zpath, zuu_machine, zuu_user) - const char **pazargs; - int aidescs[3]; - boolean fkeepuid; - boolean fkeepenv; - const char *zchdir; - boolean fnosigs; - boolean fshell; - const char *zpath; - const char *zuu_machine; - const char *zuu_user; -{ - char *zshcmd; - int i; - char *azenv[9]; - char **pazenv; - boolean ferr; -#if HAVE_FULLDUPLEX_PIPES - boolean ffullduplex; -#endif - int ierr = 0; - int onull; - int aichild_descs[3]; - int cpar_close; - int aipar_close[4]; - int cchild_close; - int aichild_close[3]; - pid_t iret = 0; - const char *zcmd; - - /* If we might have to use the shell, allocate enough space for the - quoted command before forking. Otherwise the allocation would - modify the data segment and we could not safely use vfork. */ - zshcmd = NULL; - if (fshell) - { - size_t clen; - - clen = 0; - for (i = 0; pazargs[i] != NULL; i++) - clen += strlen (pazargs[i]); - zshcmd = zbufalc (2 * clen + i); - } - - /* Set up a standard environment. This is again done before forking - because it will modify the data segment. */ - if (fkeepenv) - pazenv = environ; - else - { - const char *zterm, *ztz; - char *zspace; - int ienv; - - if (zpath == NULL) - zpath = CMDPATH; - - azenv[0] = zbufalc (sizeof "PATH=" + strlen (zpath)); - sprintf (azenv[0], "PATH=%s", zpath); - zspace = azenv[0] + sizeof "PATH=" - 1; - while ((zspace = strchr (zspace, ' ')) != NULL) - *zspace = ':'; - - azenv[1] = zbufalc (sizeof "HOME=" + strlen (zSspooldir)); - sprintf (azenv[1], "HOME=%s", zSspooldir); - - zterm = getenv ("TERM"); - if (zterm == NULL) - zterm = "unknown"; - azenv[2] = zbufalc (sizeof "TERM=" + strlen (zterm)); - sprintf (azenv[2], "TERM=%s", zterm); - - azenv[3] = zbufcpy ("SHELL=/bin/sh"); - - azenv[4] = zbufalc (sizeof "USER=" + strlen (OWNER)); - sprintf (azenv[4], "USER=%s", OWNER); - - ienv = 5; - - ztz = getenv ("TZ"); - if (ztz != NULL) - { - azenv[ienv] = zbufalc (sizeof "TZ=" + strlen (ztz)); - sprintf (azenv[ienv], "TZ=%s", ztz); - ++ienv; - } - - if (zuu_machine != NULL) - { - azenv[ienv] = zbufalc (sizeof "UU_MACHINE=" - + strlen (zuu_machine)); - sprintf (azenv[ienv], "UU_MACHINE=%s", zuu_machine); - ++ienv; - } - - if (zuu_user != NULL) - { - azenv[ienv] = zbufalc (sizeof "UU_USER=" - + strlen (zuu_user)); - sprintf (azenv[ienv], "UU_USER=%s", zuu_user); - ++ienv; - } - - azenv[ienv] = NULL; - pazenv = azenv; - } - - /* Set up any needed pipes. */ - - ferr = FALSE; - onull = -1; - cpar_close = 0; - cchild_close = 0; - -#if HAVE_FULLDUPLEX_PIPES - ffullduplex = (aidescs[0] == SPAWN_WRITE_PIPE - && aidescs[1] == SPAWN_READ_PIPE); -#endif - - for (i = 0; i < 3; i++) - { - if (aidescs[i] == SPAWN_NULL) - { - if (onull < 0) - { - onull = open ((char *) _PATH_DEVNULL, O_RDWR); - if (onull < 0 - || fcntl (onull, F_SETFD, - fcntl (onull, F_GETFD, 0) | FD_CLOEXEC) < 0) - { - ierr = errno; - (void) close (onull); - ferr = TRUE; - break; - } - aipar_close[cpar_close] = onull; - ++cpar_close; - } - aichild_descs[i] = onull; - } - else if (aidescs[i] != SPAWN_READ_PIPE - && aidescs[i] != SPAWN_WRITE_PIPE) - aichild_descs[i] = aidescs[i]; - else - { - int aipipe[2]; - -#if HAVE_FULLDUPLEX_PIPES - if (ffullduplex && i == 1) - { - /* Just use the fullduplex pipe. */ - aidescs[i] = aidescs[0]; - aichild_descs[i] = aichild_descs[0]; - continue; - } -#endif - - if (pipe (aipipe) < 0) - { - ierr = errno; - ferr = TRUE; - break; - } - - if (aidescs[i] == SPAWN_READ_PIPE) - { - aidescs[i] = aipipe[0]; - aichild_close[cchild_close] = aipipe[0]; - aichild_descs[i] = aipipe[1]; - aipar_close[cpar_close] = aipipe[1]; - } - else - { - aidescs[i] = aipipe[1]; - aichild_close[cchild_close] = aipipe[1]; - aichild_descs[i] = aipipe[0]; - aipar_close[cpar_close] = aipipe[0]; - } - - ++cpar_close; - ++cchild_close; - - if (fcntl (aipipe[0], F_SETFD, - fcntl (aipipe[0], F_GETFD, 0) | FD_CLOEXEC) < 0 - || fcntl (aipipe[1], F_SETFD, - fcntl (aipipe[1], F_GETFD, 0) | FD_CLOEXEC) < 0) - { - ierr = errno; - ferr = TRUE; - break; - } - } - } - -#if DEBUG > 1 - if (! ferr && FDEBUGGING (DEBUG_EXECUTE)) - { - ulog (LOG_DEBUG_START, "Forking %s", pazargs[0]); - for (i = 1; pazargs[i] != NULL; i++) - ulog (LOG_DEBUG_CONTINUE, " %s", pazargs[i]); - ulog (LOG_DEBUG_END, "%s", ""); - } -#endif - - if (! ferr) - { - /* This should really be vfork if available. */ - iret = ixsfork (); - if (iret < 0) - { - ferr = TRUE; - ierr = errno; - } - } - - if (ferr) - { - for (i = 0; i < cchild_close; i++) - (void) close (aichild_close[i]); - iret = -1; - } - - if (iret != 0) - { - /* The parent. Close the child's ends of the pipes and return - the process ID, or an error. */ - for (i = 0; i < cpar_close; i++) - (void) close (aipar_close[i]); - ubuffree (zshcmd); - if (! fkeepenv) - { - char **pz; - - for (pz = azenv; *pz != NULL; pz++) - ubuffree (*pz); - } - errno = ierr; - return iret; - } - - /* The child. */ - -#ifdef STDIN_FILENO -#if STDIN_FILENO != 0 || STDOUT_FILENO != 1 || STDERR_FILENO != 2 - #error The following code makes invalid assumptions -#endif -#endif - - for (i = 0; i < 3; i++) - { - if (aichild_descs[i] != i) - (void) dup2 (aichild_descs[i], i); - /* This should only be necessary if aichild_descs[i] == i, but - some systems copy the close-on-exec flag for a dupped - descriptor, which is wrong according to POSIX. */ - (void) fcntl (i, F_SETFD, fcntl (i, F_GETFD, 0) &~ FD_CLOEXEC); - } - - zcmd = pazargs[0]; - pazargs[0] = strrchr (zcmd, '/'); - if (pazargs[0] == NULL) - pazargs[0] = zcmd; - else - ++pazargs[0]; - - if (! fkeepuid) - { - /* Return to the uid of the invoking user. */ - (void) setuid (getuid ()); - (void) setgid (getgid ()); - } - else - { - /* Try to force the UUCP uid to be both real and effective user - ID, in order to present a consistent environment regardless - of the invoking user. This won't work on older System V - based systems, where it can cause trouble if ordinary users - wind up executing uuxqt, perhaps via uucico; any program - which uuxqt executes will have an arbitrary real user ID, so - if the program is itself a setuid program, any security - checks it does based on the real user ID will be incorrect. - Fixing this problem would seem to require a special setuid - root program; I have not used this approach because - modern systems should not suffer from it. */ -#if HAVE_SETREUID - (void) setreuid (geteuid (), -1); - (void) setregid (getegid (), -1); -#else - (void) setuid (geteuid ()); - (void) setgid (getegid ()); -#endif - } - - if (zchdir != NULL) - (void) chdir (zchdir); - - if (fnosigs) - { -#ifdef SIGHUP - (void) signal (SIGHUP, SIG_IGN); -#endif -#ifdef SIGINT - (void) signal (SIGINT, SIG_IGN); -#endif -#ifdef SIGQUIT - (void) signal (SIGQUIT, SIG_IGN); -#endif - } - -#ifdef isc386 -#ifdef _POSIX_SOURCE - /* ISC has a remarkably stupid notion of environments. If a program - is compiled in the POSIX environment, it sets a process state. - If you then exec a program which expects the USG environment, the - process state is not reset, so the execed program fails. The - __setostype call is required to change back to the USG - environment. This ought to be a switch in policy.h, but it seems - too trivial, so I will leave this code here and wait for it to - break in some fashion in the next version of ISC. */ - __setostype (0); -#endif -#endif - - (void) execve ((char *) zcmd, (char **) pazargs, pazenv); - - /* The exec failed. If permitted, try using /bin/sh to execute a - shell script. */ - if (errno == ENOEXEC && fshell) - { - char *zto; - const char *azshargs[4]; - - pazargs[0] = zcmd; - zto = zshcmd; - for (i = 0; pazargs[i] != NULL; i++) - { - const char *zfrom; - - for (zfrom = pazargs[i]; *zfrom != '\0'; zfrom++) - { - /* Some versions of /bin/sh appear to have a bug such - that quoting a '/' sometimes causes an error. I - don't know exactly when this happens (I can recreate - it on Ultrix 4.0), but in any case it is harmless to - not quote a '/'. */ - if (*zfrom != '/') - *zto++ = '\\'; - *zto++ = *zfrom; - } - *zto++ = ' '; - } - *(zto - 1) = '\0'; - - azshargs[0] = "sh"; - azshargs[1] = "-c"; - azshargs[2] = zshcmd; - azshargs[3] = NULL; - - (void) execve ((char *) "/bin/sh", (char **) azshargs, pazenv); - } - - _exit (EXIT_FAILURE); - - /* Avoid compiler warning. */ - return -1; -} |