#include "uucp.h"
#include "uudefs.h"
#include "sysdep.h"
#include <errno.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
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;
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);
}
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;
}
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 *) "/dev/null", 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)
{
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)
{
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)
{
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;
}
#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);
(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)
{
(void) setuid (getuid ());
(void) setgid (getgid ());
}
else
{
#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
__setostype (0);
#endif
#endif
(void) execve ((char *) zcmd, (char **) pazargs, pazenv);
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++)
{
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);
return -1;
}