aboutsummaryrefslogtreecommitdiff
path: root/gnu/libexec/uucp/libunix/spawn.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/libexec/uucp/libunix/spawn.c')
-rw-r--r--gnu/libexec/uucp/libunix/spawn.c456
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;
-}