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

  1. /* $Header: dfile.c,v 1.2 88/08/25 15:23:56 network Exp $
  2.  *
  3.  * Filter destination(s) through delivery file(s).
  4.  *
  5.  * $Log:    dfile.c,v $
  6.  * Revision 1.2  88/08/25  15:23:56  network
  7.  * Add third parameter to do_dfile(), so that if the delivery file cannot
  8.  * be executed, the given destination can be recorded as an error.
  9.  * 
  10.  * Revision 1.1  88/06/06  09:38:38  chip
  11.  * Initial revision
  12.  * 
  13.  */
  14.  
  15. #include "deliver.h"
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18.  
  19. /*----------------------------------------------------------------------
  20.  * Filter all valid destinations through the global delivery file.
  21.  */
  22.  
  23. sys_dfile(dac, dav)
  24. int     dac;
  25. char    **dav;
  26. {
  27.     char    **fav;
  28.     int     fac, a, goodnames;
  29.     struct stat st;
  30.  
  31.     /*
  32.      * If there is no global delivery file, then take all the named
  33.      * addresses verbatim and return.
  34.      */
  35.  
  36.     if (stat(sys_deliver, &st) == -1)
  37.     {
  38.         if (verbose)
  39.             message("%s: no system delivery file\n",
  40.                 progname);
  41.  
  42.         for (a = 0; a < dac; ++a)
  43.             (void) dest(dav[a], (char *) NULL);
  44.         return;
  45.     }
  46.  
  47.     /*
  48.      * Collect the arguments for the delivery file.
  49.      */
  50.  
  51.     fav = (char **) zalloc((dac + 3) * sizeof(char **));
  52.     fav[0] = shell;
  53.     fav[1] = sys_deliver;
  54.     fac = 2;
  55.  
  56.     goodnames = 0;
  57.     for (a = 0; a < dac; ++a)
  58.     {
  59.         char    *p;
  60.  
  61.         for (p = dav[a]; *p; ++p)
  62.         {
  63.             if (!isalpha(*p)
  64.              && !isdigit(*p)
  65.              && !strchr("#%-+._", *p))
  66.                 break;
  67.         }
  68.  
  69.         if (*p)
  70.         {
  71.             /* Invalid name -- note it and go on. */
  72.  
  73.             (void) dest(dav[a], (char *) NULL);
  74.         }
  75.         else
  76.         {
  77.             /* Valid name -- let the delivery file handle it. */
  78.  
  79.             fav[fac++] = dav[a];
  80.             ++goodnames;
  81.         }
  82.     }
  83.  
  84.     fav[fac] = NULL;
  85.  
  86.     /*
  87.      * If there were any good names found, let loose the delivery
  88.      * file.  Note the meaning of "good" is "well-formed", not "valid".
  89.      * Thus the system delivery file has control over the handling of
  90.      * all local deliveries, not just those to valid users.
  91.      */
  92.  
  93.     if (goodnames)
  94.         (void) do_dfile(eff_ct, fav, (DEST *)NULL);
  95.  
  96.     free((char *) fav);
  97. }
  98.  
  99. /*----------------------------------------------------------------------
  100.  * Filter all user destinations through their local delivery files.
  101.  */
  102.  
  103. user_dfiles()
  104. {
  105.     DEST    *d;
  106.     int     nfound;
  107.  
  108.     /*
  109.      * Continue to loop through all addresses until no destination
  110.      * that needs expanding can be found.
  111.      */
  112.  
  113.     do {
  114.         nfound = 0;
  115.         for (d = first_dest(); d; d = next_dest(d))
  116.         {
  117.             if (d->class == CL_USER
  118.              && d->state == ST_WORKING
  119.              && !d->dfdone)
  120.             {
  121.                 one_dfile(d);
  122.                 d->dfdone = TRUE;
  123.             }
  124.         }
  125.     } while (nfound > 0);
  126. }
  127.  
  128. /*----------------------------------------------------------------------
  129.  * Run the delivery file (if any) for the specified destination.
  130.  */
  131.  
  132. one_dfile(d)
  133. DEST    *d;
  134. {
  135.     CONTEXT *ct;
  136.     char    *fav[4];
  137.     char    udel_path[100];
  138.     struct stat st;
  139.  
  140.     if ((ct = name_context(d->name)) == NULL)
  141.     {
  142.         d->state = ST_ERROR;
  143.         d->error = "Missing context in user_dfile_one()";
  144.         return;
  145.     }
  146.  
  147.     /*
  148.      * If user's home directory is missing, forget it.
  149.      * If user's home directory is writable to the world,
  150.      * executing the delivery file would allow a security breach!
  151.      * Thanks to Jon Zeeff for this hint...
  152.      */
  153.  
  154.     if (stat(ct->home, &st) == -1
  155.      || (st.st_mode & S_IFMT) != S_IFDIR)
  156.     {
  157.         if (verbose)
  158.             message("%s: home directory %s is missing!\n",
  159.                 ct->name, ct->home);
  160.         return;
  161.     }
  162.  
  163.     if (st.st_mode & 02)
  164.     {
  165.         if (verbose)
  166.             message("%s: home directory is writable to the world!\n",
  167.                 ct->name);
  168.         return;
  169.     }
  170.  
  171.     /*
  172.      * If there is no delivery file to execute, just return.
  173.      */
  174.  
  175.     (void) sprintf(udel_path, "%s/%s", ct->home, user_deliver);
  176.     if (stat(udel_path, &st) == -1)
  177.     {
  178.         if (verbose)
  179.             message("%s has no delivery file\n", d->name);
  180.         return;
  181.     }
  182.  
  183.     /*
  184.      * Time to run the file!
  185.      * We put this dest on hold, so that it will be ignored unless
  186.      * the delivery file names it.
  187.      */
  188.  
  189.     d->state = ST_HOLD;
  190.  
  191.     fav[0] = "sh";
  192.     fav[1] = udel_path;
  193.     fav[2] = d->name;
  194.     fav[3] = NULL;
  195.     (void) do_dfile(ct, fav, d);
  196. }
  197.  
  198. /*----------------------------------------------------------------------
  199.  * Process a delivery file.
  200.  */
  201.  
  202. int
  203. do_dfile(ct, av, d)
  204. CONTEXT *ct;
  205. char    **av;
  206. DEST    *d;
  207. {
  208.     FILE    *fp;
  209.     char    *name, *mailbox;
  210.  
  211.     if (!ct)
  212.         return -1;
  213.  
  214.     if (! ok_context(ct))
  215.     {
  216.         if (d)
  217.         {
  218.             d->state = ST_ERROR;
  219.             d->error = "No permissions for that context";
  220.         }
  221.         else
  222.             message("No permissions to run as %s\n", ct);
  223.  
  224.         return -1;
  225.     }
  226.  
  227.     /* Make sure that the temp files are readable to the new process. */
  228.  
  229.     give_temps(ct);
  230.  
  231.     /* Here we go! */
  232.  
  233.     if (verbose)
  234.         message("Processing delivery file as %s\n", ct->name);
  235.  
  236.     if ((fp = ct_popenv(ct, "/bin/sh", av, "r")) == NULL)
  237.     {
  238.         error("can't execute delivery file as %s\n", ct->name);
  239.         leave(1);
  240.     }
  241.  
  242.     /*
  243.      * Read the standard output of the delivery file.
  244.      */
  245.  
  246.     while (dfile_gets(fp, &name, &mailbox) >= 0)
  247.     {
  248.         DEST    *nd;
  249.  
  250.         nd = dest(name, mailbox);
  251.         if (nd->state == ST_HOLD)
  252.             nd->state = ST_WORKING;
  253.  
  254.         /*
  255.          * If the delivery file specified a mailbox, verify
  256.          * that the user whose delivery file is running has
  257.          * permissions for the requested context.
  258.          */
  259.  
  260.         if ((nd->state == ST_WORKING) && (mailbox != NULL))
  261.         {
  262.             CONTEXT *nct;
  263.  
  264.             if ((nct = name_context(name)) == NULL)
  265.             {
  266.                 nd->state = ST_ERROR;
  267.                 nd->error = "Lost context in do_dfile()";
  268.             }
  269.             else if (! ok_context(nct))
  270.             {
  271.                 nd->state = ST_ERROR;
  272.                 nd->error = "No permissions for that context";
  273.             }
  274.         }
  275.     }
  276.  
  277.     return ct_pclose(fp);
  278. }
  279.  
  280. /*----------------------------------------------------------------------
  281.  * Get and parse a single delivery file output line.
  282.  */
  283.  
  284. int
  285. dfile_gets(fp, namep, mailboxp)
  286. FILE    *fp;
  287. char    **namep;
  288. char    **mailboxp;
  289. {
  290.     char    *p, *q;
  291.     static  char    buf[BUFSIZ];
  292.  
  293.     if (fgets(buf, GETSIZE(buf), fp) == NULL)
  294.         return -1;
  295.  
  296.     if ((p = strchr(buf, '\n')) != NULL)
  297.         *p = 0;
  298.     else
  299.     {
  300.         int c;
  301.  
  302.         while ((c = fgetc(fp)) != '\n' && c != EOF)
  303.             ; /* keep reading */
  304.  
  305.         error("invalid line from delivery file: '%s'\n", buf);
  306.         return -1;
  307.     }
  308.  
  309.     /* Strip out all whitespace and eliminate duplicated slashes */
  310.  
  311.     p = q = buf;
  312.     while (*p)
  313.     {
  314.         if (! isspace(*p))
  315.         {
  316.             if ((*q++ = *p++) == '/')
  317.             {
  318.                 while (*p == '/')
  319.                     ++p;
  320.             }
  321.         }
  322.     }
  323.     *q = 0;
  324.  
  325.     /* Debugging message: display input line */
  326.  
  327.     if (verbose)
  328.         message("\t'%s'\n", buf);
  329.  
  330.     if ((p = strchr(buf, ':')) != NULL)
  331.     {
  332.         *p++ = 0;
  333.         if ((q = strchr(p, ':')) != NULL)
  334.             *q = 0;
  335.     }
  336.  
  337.     *namep = buf;
  338.     *mailboxp = p;
  339.     return 0;
  340. }
  341.  
  342. /*----------------------------------------------------------------------
  343.  * Make the temp files readable in the given context.
  344.  * This is needed because the temps are readable by owner only.
  345.  */
  346.  
  347. give_temps(ct)
  348. CONTEXT *ct;
  349. {
  350.     int     t;
  351.  
  352.     if (!ct)
  353.         return;
  354.  
  355.     for (t = 0; t < T_MAX; ++t)
  356.     {
  357.         if (chown(tfile[t], ct->uid, ct->gid) == -1)
  358.             syserr("can't chown %s", tfile[t]);
  359.     }
  360. }
  361.