home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume16 / deliver / part03 / procs.c < prev    next >
C/C++ Source or Header  |  1988-11-14  |  5KB  |  293 lines

  1. /* $Header: procs.c,v 1.2 88/09/14 19:42:28 network Exp $
  2.  *
  3.  * Process management and misc support.
  4.  *
  5.  * $Log:    procs.c,v $
  6.  * Revision 1.2  88/09/14  19:42:28  network
  7.  * Portability to System V and BSD.
  8.  * General fixup.
  9.  * 
  10.  * Revision 1.1  88/06/06  09:39:15  chip
  11.  * Initial revision
  12.  * 
  13.  */
  14.  
  15. #include "deliver.h"
  16. #include <errno.h>
  17. #include <signal.h>
  18.  
  19. /*
  20.  * External data.
  21.  */
  22.  
  23. extern  int     errno;
  24.  
  25. /*
  26.  * Local data.
  27.  */
  28.  
  29. static  int     child_pid = -1;
  30. static  int     (*saved_sigpipe)() = SIG_DFL;
  31.  
  32. /*----------------------------------------------------------------------
  33.  * Like popen(), but execute the child in a specific context.
  34.  * Also, the argument list is already a vector.
  35.  */
  36.  
  37. FILE *
  38. ct_popenv(ct, prog, av, mode)
  39. CONTEXT *ct;
  40. char    *prog;
  41. char    **av;
  42. char    *mode;
  43. {
  44.     char    ch;
  45.     int     child, parent;
  46.     int     pfd[2];
  47.  
  48.     if (!ct || !prog || !av || !mode)
  49.         return NULL;
  50.  
  51.     if (mode[0] == 'r' && mode[1] == 0)
  52.         child = 1, parent = 0;
  53.     else if (mode[0] == 'w' && mode[1] == 0)
  54.         child = 0, parent = 1;
  55.     else
  56.         return NULL;
  57.  
  58.     /* We can't have more than one child at a time. */
  59.  
  60.     if (child_pid >= 0)
  61.     {
  62.         error("in ct_popen: a process is already open\n");
  63.         return NULL;
  64.     }
  65.  
  66.     /* Make a stab at predicting uid-related failure. */
  67.  
  68.     if (! ok_context(ct))
  69.     {
  70.         error("in ct_popen: no permissions to become %s\n", ct->name);
  71.         return NULL;
  72.     }
  73.  
  74.     /* Pipes?  Like, tubular, fer shur! */
  75.  
  76.     if (pipe(pfd) == -1)
  77.     {
  78.         syserr("can't create a pipe");
  79.         return NULL;
  80.     }
  81.  
  82.     /* Generate a debugging message. */
  83.  
  84.     if (verbose)
  85.     {
  86.         int a;
  87.  
  88.         message("Spawning");
  89.         for (a = 0; av[a]; ++a)
  90.             message(" %s", av[a]);
  91.         message("\n");
  92.     }
  93.  
  94.     /* Handle the child case */
  95.  
  96.     if (sfork() == 0)
  97.     {
  98.         if (child == 0)
  99.         {
  100.             (void) close(0);
  101.             (void) dup(pfd[0]);     /* ass_u_me 0 */
  102.         }
  103.         else
  104.         {
  105.             (void) close(0);
  106.             if (open("/dev/null", O_RDONLY) != 0)
  107.             {
  108.                 /* This should _never_ happen, but... */
  109.                 syserr("can't open /dev/null");
  110.                 (void) dup(1);  /* ass_u_me 0 */
  111.             }
  112.  
  113.             (void) close(1);
  114.             (void) dup(pfd[1]);     /* ass_u_me 1 */
  115.         }
  116.  
  117.         if (become(ct, TRUE) < 0)
  118.             (void) write(pfd[1], "n", 1);
  119.         else
  120.         {
  121.             int     t;
  122.  
  123.             (void) write(pfd[1], "y", 1);
  124.  
  125.             (void) close(pfd[child]);
  126.             (void) close(pfd[parent]);
  127.             for (t = 0; t < T_MAX; ++t)
  128.                 (void) close(tfd[t]);
  129.  
  130.             (void) execv(prog, av);
  131.             syserr("can't execute %s", prog);
  132.         }
  133.  
  134.         exit(127);
  135.     }
  136.  
  137.     /* Make sure that a broken pipe won't kill us */
  138.  
  139.     saved_sigpipe = signal(SIGPIPE, SIG_IGN);
  140.  
  141.     /* The child must report "OK" before we continue. */
  142.  
  143.     if ((read(pfd[0], &ch, 1) < 1) || (ch != 'y'))
  144.     {
  145.         (void) close(pfd[0]);
  146.         (void) close(pfd[1]);
  147.         (void) await_child();
  148.         return NULL;
  149.     }
  150.  
  151.     (void) close(pfd[child]);
  152.     return fdopen(pfd[parent], mode);
  153. }
  154.  
  155. /*----------------------------------------------------------------------
  156.  * Close the stream opened by ct_popen().
  157.  */
  158.  
  159. ct_pclose(fp)
  160. FILE    *fp;
  161. {
  162.     if (fp)
  163.         (void) fclose(fp);
  164.     return await_child();
  165. }
  166.  
  167. /*----------------------------------------------------------------------
  168.  * Assume the identity of the given user.
  169.  */
  170.  
  171. int
  172. become(ct, chd)
  173. CONTEXT *ct;
  174. int     chd;
  175. {
  176.     char    env_path[32];
  177.  
  178.     /*
  179.      * Assume a new identity.
  180.      * Note the importance of doing the setgid() before the setuid().
  181.      */
  182.  
  183.     if (setgid(ct->gid) == -1)
  184.     {
  185.         syserr("can't setgid to %d", ct->gid);
  186.         return -1;
  187.     }
  188.     if (setuid(ct->uid) == -1)
  189.     {
  190.         syserr("can't setgid to %u", ct->uid);
  191.         return -1;
  192.     }
  193.     if (chd && chdir(ct->home) == -1)
  194.     {
  195.         syserr("can't chdir to %s", ct->home);
  196.         return -1;
  197.     }
  198.  
  199.     /* Set up the environment */
  200.  
  201.     (void) sprintf(env_path, "%s:/bin:/usr/bin",
  202.             ((ct->uid == 0) ? "/etc" : "."));
  203.     alloc_env("HOME", ct->home);
  204.     alloc_env("PATH", env_path);
  205.  
  206.     /* I guess it worked. */
  207.  
  208.     return 0;
  209. }
  210.  
  211. /*----------------------------------------------------------------------
  212.  * Safe fork.  If it doesn't work, it exits.
  213.  */
  214.  
  215. int
  216. sfork()
  217. {
  218.     int     tries;
  219.  
  220.     /*
  221.      * A few safety measures.
  222.      */
  223.  
  224.     (void) await_child();
  225.     (void) fflush(stdout);
  226.     (void) fflush(stderr);
  227.  
  228.     /*
  229.      * Be patient in waiting for a fork().
  230.      */
  231.  
  232.     for (tries = 0; tries < 10; ++tries)
  233.     {
  234.         if (tries)
  235.             snooze(3);
  236.         if ((child_pid = fork()) >= 0)
  237.             return child_pid;
  238.         if (errno != EAGAIN)
  239.             break;
  240.     }
  241.  
  242.     syserr("can't fork");
  243.     leave(1);
  244.     /* NOTREACHED */
  245. }
  246.  
  247. /*----------------------------------------------------------------------
  248.  * Wait for our child (if any) to exit.
  249.  * Returns child's exit status or -1 if there is a problem.
  250.  */
  251.  
  252. int
  253. await_child()
  254. {
  255.     int     wpid, st;
  256.  
  257.     if (child_pid < 0)
  258.         return -1;
  259.  
  260.     while ((wpid = wait(&st)) >= 0)
  261.     {
  262.         if (wpid == child_pid)
  263.             break;
  264.     }
  265.  
  266.     child_pid = -1;
  267.     if (wpid == -1)
  268.         syserr("waiting for child");
  269.  
  270.     (void) signal(SIGPIPE, saved_sigpipe);
  271.     saved_sigpipe = SIG_DFL;
  272.  
  273.     if (wpid == -1)
  274.         return -1;
  275.  
  276.     if (st & 0xFF)
  277.     {
  278.         error("child process died%s due to signal %d.\n",
  279.             ((st & 0x80) ? " and dumped core" : ""),
  280.             (st & 0x7F));
  281.  
  282.         return -1;
  283.     }
  284.  
  285.     if (verbose)
  286.     {
  287.         message("child process exited with status %d.\n",
  288.             (st >> 8) & 0xFF);
  289.     }
  290.  
  291.     return ((st >> 8) & 0xFF);
  292. }
  293.