home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Source / GNU / uucp / uuxqt / uuxqt.c < prev   
Encoding:
C/C++ Source or Header  |  1995-08-20  |  42.2 KB  |  1,767 lines

  1. /* uuxqt.c
  2.    Run uux commands.
  3.  
  4.    Copyright (C) 1991, 1992, 1993, 1994, 1995 Ian Lance Taylor
  5.  
  6.    This file is part of the Taylor UUCP package.
  7.  
  8.    This program is free software; you can redistribute it and/or
  9.    modify it under the terms of the GNU General Public License as
  10.    published by the Free Software Foundation; either version 2 of the
  11.    License, or (at your option) any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful, but
  14.    WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.    General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  21.  
  22.    The author of the program may be contacted at ian@airs.com or
  23.    c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144.
  24.    */
  25.  
  26. #include "uucp.h"
  27.  
  28. #if USE_RCS_ID
  29. const char uuxqt_rcsid[] = "$Id: uuxqt.c,v 1.82 1995/07/19 04:22:26 ian Rel $";
  30. #endif
  31.  
  32. #include <errno.h>
  33. #include <ctype.h>
  34.  
  35. #include "getopt.h"
  36.  
  37. #include "uudefs.h"
  38. #include "uuconf.h"
  39. #include "system.h"
  40.  
  41. /* Static variables used to unlock things if we get a fatal error.  */
  42. static int iQlock_seq = -1;
  43. static const char *zQunlock_cmd;
  44. static const char *zQunlock_file;
  45. static boolean fQunlock_directory;
  46. int cQmaxuuxqts;
  47.  
  48. /* Static variables to free in uqcleanup.  */
  49. static char *zQoutput;
  50. static char *zQmail;
  51.  
  52. /* Local functions.  */
  53. static void uqusage P((void));
  54. static void uqhelp P((void));
  55. static void uqabort P((void));
  56. static void uqdo_xqt_file P((pointer puuconf, const char *zfile,
  57.                  const char *zbase,
  58.                  const struct uuconf_system *qsys,
  59.                  const char *zlocalname,
  60.                  const char *zcmd, boolean *pfprocessed));
  61. static void uqcleanup P((const char *zfile, int iflags));
  62. static int isave_files P((const struct uuconf_system *, const char *zmail,
  63.               const char *zfile, int iclean));
  64. static boolean fqforward P((const char *zfile, char **pzallowed,
  65.                 const char *zlog, const char *zmail));
  66.  
  67. /* Long getopt options.  */
  68. static const struct option asQlongopts[] =
  69. {
  70.   { "command", required_argument, 0, 'c' },
  71.   { "system", required_argument, 0, 's' },
  72.   { "config", required_argument, NULL, 'I' },
  73.   { "debug", required_argument, NULL, 'x' },
  74.   { "version", no_argument, NULL, 'v' },
  75.   { "help", no_argument, NULL, 1 },
  76.   { NULL, 0, NULL, 0 }
  77. };
  78.  
  79. int
  80. main (argc, argv)
  81.      int argc;
  82.      char **argv;
  83. {
  84.   /* The type of command to execute (NULL for any type).  */
  85.   const char *zcmd = NULL;
  86.   /* The configuration file name.  */
  87.   const char *zconfig = NULL;
  88.   /* The system to execute commands for.  */
  89.   const char *zdosys = NULL;
  90.   int iopt;
  91.   pointer puuconf;
  92.   int iuuconf;
  93.   const char *zlocalname;
  94.   boolean fany;
  95.   char *z, *zgetsys;
  96.   boolean ferr;
  97.   boolean fsys;
  98.   struct uuconf_system ssys;
  99.  
  100.   zProgram = argv[0];
  101.  
  102.   while ((iopt = getopt_long (argc, argv, "c:I:s:vx:", asQlongopts,
  103.                   (int *) NULL)) != EOF)
  104.     {
  105.       switch (iopt)
  106.     {
  107.     case 'c':
  108.       /* Set the type of command to execute.  */
  109.       zcmd = optarg;
  110.       break;
  111.  
  112.     case 'I':
  113.       /* Set the configuration file name.  */
  114.       if (fsysdep_other_config (optarg))
  115.         zconfig = optarg;
  116.       break;
  117.  
  118.     case 's':
  119.       zdosys = optarg;
  120.       break;
  121.  
  122.     case 'x':
  123. #if DEBUG > 1
  124.       /* Set the debugging level.  */
  125.       iDebug |= idebug_parse (optarg);
  126. #endif
  127.       break;
  128.  
  129.     case 'v':
  130.       /* Print version and exit.  */
  131.       printf ("%s: Taylor UUCP %s, copyright (C) 1991, 92, 93, 94, 1995 Ian Lance Taylor\n",
  132.           zProgram, VERSION);
  133.       exit (EXIT_SUCCESS);
  134.       /*NOTREACHED*/
  135.  
  136.     case 1:
  137.       /* --help.  */
  138.       uqhelp ();
  139.       exit (EXIT_SUCCESS);
  140.       /*NOTREACHED*/
  141.  
  142.     case 0:
  143.       /* Long option found and flag set.  */
  144.       break;
  145.  
  146.     default:
  147.       uqusage ();
  148.       break;
  149.     }
  150.     }
  151.  
  152.   if (optind != argc)
  153.     uqusage ();
  154.  
  155.   iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig);
  156.   if (iuuconf != UUCONF_SUCCESS)
  157.     ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  158.  
  159. #if DEBUG > 1
  160.   {
  161.     const char *zdebug;
  162.  
  163.     iuuconf = uuconf_debuglevel (puuconf, &zdebug);
  164.     if (iuuconf != UUCONF_SUCCESS)
  165.       ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  166.     if (zdebug != NULL)
  167.       iDebug |= idebug_parse (zdebug);
  168.   }
  169. #endif
  170.  
  171.   iuuconf = uuconf_maxuuxqts (puuconf, &cQmaxuuxqts);
  172.   if (iuuconf != UUCONF_SUCCESS)
  173.     ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  174.  
  175. #ifdef SIGINT
  176.   usysdep_signal (SIGINT);
  177. #endif
  178. #ifdef SIGHUP
  179.   usysdep_signal (SIGHUP);
  180. #endif
  181. #ifdef SIGQUIT
  182.   usysdep_signal (SIGQUIT);
  183. #endif
  184. #ifdef SIGTERM
  185.   usysdep_signal (SIGTERM);
  186. #endif
  187. #ifdef SIGPIPE
  188.   usysdep_signal (SIGPIPE);
  189. #endif
  190.  
  191.   usysdep_initialize (puuconf, INIT_SUID);
  192.  
  193.   ulog_to_file (puuconf, TRUE);
  194.   ulog_fatal_fn (uqabort);
  195.  
  196.   iuuconf = uuconf_localname (puuconf, &zlocalname);
  197.   if (iuuconf == UUCONF_NOT_FOUND)
  198.     {
  199.       zlocalname = zsysdep_localname ();
  200.       if (zlocalname == NULL)
  201.     exit (EXIT_FAILURE);
  202.     }
  203.   else if (iuuconf != UUCONF_SUCCESS)
  204.     ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  205.  
  206.   fsys = FALSE;
  207.  
  208.   /* If we were given a system name, canonicalize it.  */
  209.   if (zdosys != NULL)
  210.     {
  211.       iuuconf = uuconf_system_info (puuconf, zdosys, &ssys);
  212.       if (iuuconf != UUCONF_SUCCESS)
  213.     {
  214.       if (iuuconf != UUCONF_NOT_FOUND)
  215.         ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  216.  
  217.       if (strcmp (zdosys, zlocalname) == 0)
  218.         {
  219.           iuuconf = uuconf_system_local (puuconf, &ssys);
  220.           if (iuuconf != UUCONF_SUCCESS)
  221.         ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  222.           ssys.uuconf_zname = (char *) zlocalname;
  223.         }
  224.       else
  225.         {
  226.           if (! funknown_system (puuconf, zdosys, &ssys))
  227.         ulog (LOG_FATAL, "%s: system not found", zdosys);
  228.         }
  229.     }
  230.  
  231.       zdosys = zbufcpy (ssys.uuconf_zname);
  232.       fsys = TRUE;
  233.     }
  234.  
  235.   /* Limit the number of uuxqt processes, and make sure we're the only
  236.      uuxqt daemon running for this command.  */
  237.   iQlock_seq = ixsysdep_lock_uuxqt (zcmd, cQmaxuuxqts);
  238.   if (iQlock_seq < 0)
  239.     {
  240.       ulog_close ();
  241.       usysdep_exit (TRUE);
  242.     }
  243.   zQunlock_cmd = zcmd;
  244.  
  245.   /* Keep scanning the execute files until we don't process any of
  246.      them.  */
  247.   do
  248.     {
  249.       fany = FALSE;
  250.  
  251.       /* Look for each execute file, and run it.  */
  252.  
  253.       if (! fsysdep_get_xqt_init (zdosys))
  254.     {
  255.       ulog_close ();
  256.       usysdep_exit (FALSE);
  257.     }
  258.  
  259.       while ((z = zsysdep_get_xqt (zdosys, &zgetsys, &ferr)) != NULL)
  260.     {
  261.       const char *zloc;
  262.       boolean fprocessed;
  263.       char *zbase;
  264.  
  265.       /* Get the system information for the system returned by
  266.          zsysdep_get_xqt.  */
  267.       if (! fsys || strcmp (ssys.uuconf_zname, zgetsys) != 0)
  268.         {
  269.           if (fsys)
  270.         (void) uuconf_system_free (puuconf, &ssys);
  271.  
  272.           iuuconf = uuconf_system_info (puuconf, zgetsys,
  273.                         &ssys);
  274.           if (iuuconf != UUCONF_SUCCESS)
  275.         {
  276.           if (iuuconf != UUCONF_NOT_FOUND)
  277.             {
  278.               ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  279.               ubuffree (z);
  280.               ubuffree (zgetsys);
  281.               continue;
  282.             }
  283.           else if (strcmp (zgetsys, zlocalname) == 0)
  284.             {
  285.               iuuconf = uuconf_system_local (puuconf, &ssys);
  286.               if (iuuconf != UUCONF_SUCCESS)
  287.             {
  288.               ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  289.               ubuffree (z);
  290.               ubuffree (zgetsys);
  291.               continue;
  292.             }
  293.               ssys.uuconf_zname = (char *) zlocalname;
  294.             }
  295.           else
  296.             {
  297.               if (! funknown_system (puuconf, zgetsys, &ssys))
  298.             {
  299.               ulog (LOG_ERROR,
  300.                 "%s: Execute file for unknown system %s",
  301.                 z, zgetsys);
  302.               (void) remove (z);
  303.               ubuffree (z);
  304.               ubuffree (zgetsys);
  305.               continue;
  306.             }
  307.             }
  308.         }
  309.  
  310.           fsys = TRUE;
  311.         }
  312.  
  313.       /* If we've received a signal, get out of the loop.  */
  314.       if (FGOT_SIGNAL ())
  315.         {
  316.           ubuffree (z);
  317.           ubuffree (zgetsys);
  318.           break;
  319.         }
  320.  
  321.       /* Make sure we are supposed to be executing jobs for this
  322.          system.  */
  323.       if (zdosys != NULL && strcmp (zdosys, ssys.uuconf_zname) != 0)
  324.         {
  325.           ubuffree (z);
  326.           ubuffree (zgetsys);
  327.           continue;
  328.         }
  329.  
  330.       zloc = ssys.uuconf_zlocalname;
  331.       if (zloc == NULL)
  332.         zloc = zlocalname;
  333.  
  334.       ulog_system (ssys.uuconf_zname);
  335.       zbase = zsysdep_base_name (z);
  336.       uqdo_xqt_file (puuconf, z, zbase, &ssys, zloc, zcmd, &fprocessed);
  337.       ubuffree (zbase);
  338.       ulog_system ((const char *) NULL);
  339.       ulog_user ((const char *) NULL);
  340.  
  341.       if (fprocessed)
  342.         fany = TRUE;
  343.       ubuffree (z);
  344.       ubuffree (zgetsys);
  345.     }
  346.  
  347.       usysdep_get_xqt_free (zdosys);
  348.     }
  349.   while (fany && ! FGOT_SIGNAL ());
  350.  
  351.   (void) fsysdep_unlock_uuxqt (iQlock_seq, zcmd, cQmaxuuxqts);
  352.   iQlock_seq = -1;
  353.  
  354.   ulog_close ();
  355.  
  356.   if (FGOT_SIGNAL ())
  357.     ferr = TRUE;
  358.  
  359.   usysdep_exit (! ferr);
  360.  
  361.   /* Avoid errors about not returning a value.  */
  362.   return 0;
  363. }
  364.  
  365. static void
  366. uqhelp ()
  367. {
  368.   printf ("Taylor UUCP %s, copyright (C) 1991, 92, 93, 94, 1995 Ian Lance Taylor\n",
  369.        VERSION);
  370.   printf ("Usage: %s [-c,--command cmd] [-s,--system system]\n", zProgram);
  371.   printf (" -c,--command cmd: Set type of command to execute\n");
  372.   printf (" -s,--system system: Execute commands only for named system\n");
  373.   printf (" -x,--debug debug: Set debugging level\n");
  374. #if HAVE_TAYLOR_CONFIG
  375.   printf (" -I,--config file: Set configuration file to use\n");
  376. #endif /* HAVE_TAYLOR_CONFIG */
  377.   printf (" -v,--version: Print version and exit\n");
  378.   printf (" --help: Print help and exit\n");
  379. }
  380.  
  381. static void
  382. uqusage ()
  383. {
  384.   fprintf (stderr,
  385.        "Usage: %s [-c,--command cmd] [-s,--system system]\n", zProgram);
  386.   fprintf (stderr, "Use %s --help for help\n", zProgram);
  387.   exit (EXIT_FAILURE);
  388. }
  389.  
  390. /* This is the abort function called when we get a fatal error.  */
  391.  
  392. static void
  393. uqabort ()
  394. {
  395. #if ! HAVE_HDB_LOGGING
  396.   /* When using HDB logging, it's a pain to have no system name.  */
  397.   ulog_system ((const char *) NULL);
  398. #endif
  399.  
  400.   ulog_user ((const char *) NULL);
  401.  
  402.   if (fQunlock_directory)
  403.     (void) fsysdep_unlock_uuxqt_dir (iQlock_seq);
  404.  
  405.   if (zQunlock_file != NULL)
  406.     (void) fsysdep_unlock_uuxqt_file (zQunlock_file);
  407.  
  408.   if (iQlock_seq >= 0)
  409.     (void) fsysdep_unlock_uuxqt (iQlock_seq, zQunlock_cmd, cQmaxuuxqts);
  410.  
  411.   ulog_close ();
  412.  
  413.   usysdep_exit (FALSE);
  414. }
  415.  
  416. /* An execute file is a series of lines.  The first character of each
  417.    line is a command.  The following commands are defined:
  418.  
  419.    C command-line
  420.    I standard-input
  421.    O standard-output [ system ]
  422.    F required-file filename-to-use
  423.    R requestor-address
  424.    U user system
  425.    Z (acknowledge if command failed; default)
  426.    N (no acknowledgement on failure)
  427.    n (acknowledge if command succeeded)
  428.    B (return command input on error)
  429.    e (process with sh)
  430.    E (process with exec)
  431.    M status-file
  432.    # comment
  433.  
  434.    Unrecognized commands are ignored.  We actually do not recognize
  435.    the Z command, since it requests default behaviour.  We always send
  436.    mail on failure, unless the N command appears.  We never send mail
  437.    on success, unless the n command appears.
  438.  
  439.    This code does not currently support the B or M commands.  */
  440.  
  441. /* Command arguments.  */
  442. static char **azQargs;
  443. /* Command as a complete string.  */
  444. static char *zQcmd;
  445. /* Standard input file name.  */
  446. static char *zQinput;
  447. /* Standard output file name.  */
  448. static char *zQoutfile;
  449. /* Standard output system.  */
  450. static char *zQoutsys;
  451. /* Number of required files.  */
  452. static int cQfiles;
  453. /* Names of required files.  */
  454. static char **azQfiles;
  455. /* Names required files should be renamed to (NULL if original is OK).  */
  456. static char **azQfiles_to;
  457. /* Requestor address (this is where mail should be sent).  */
  458. static char *zQrequestor;
  459. /* User name.  */
  460. static const char *zQuser;
  461. /* System name.  */
  462. static const char *zQsystem;
  463. /* This is set by the N flag, meaning that no acknowledgement should
  464.    be mailed on failure.  */
  465. static boolean fQno_ack;
  466. /* This is set by the n flag, meaning that acknowledgement should be
  467.    mailed if the command succeeded.  */
  468. static boolean fQsuccess_ack;
  469. /* This is set by the B flag, meaning that command input should be
  470.    mailed to the requestor if an error occurred.  */
  471. static boolean fQsend_input;
  472. /* This is set by the E flag, meaning that exec should be used to
  473.    execute the command.  */
  474. static boolean fQuse_exec;
  475. /* The status should be copied to this file on the requesting host.  */
  476. static const char *zQstatus_file;
  477. #if ALLOW_SH_EXECUTION
  478. /* This is set by the e flag, meaning that sh should be used to
  479.    execute the command.  */
  480. static boolean fQuse_sh;
  481. #endif /* ALLOW_SH_EXECUTION */
  482.  
  483. static int iqcmd P((pointer puuconf, int argc, char **argv, pointer pvar,
  484.             pointer pinfo));
  485. static int iqout P((pointer puuconf, int argc, char **argv, pointer pvar,
  486.             pointer pinfo));
  487. static int iqfile P((pointer puuconf, int argc, char **argv, pointer pvar,
  488.              pointer pinfo));
  489. static int iqrequestor P((pointer puuconf, int argc, char **argv,
  490.               pointer pvar, pointer pinfo));
  491. static int iquser P((pointer puuconf, int argc, char **argv, pointer pvar,
  492.              pointer pinfo));
  493. static int iqset P((pointer puuconf, int argc, char **argv, pointer pvar,
  494.             pointer pinfo));
  495.  
  496. /* We are lax about the number of arguments the functions accept,
  497.    because there is a lot of variation in what other (buggy) UUCP
  498.    packages generate.  Unused arguments are ignored.  */
  499.  
  500. static const struct uuconf_cmdtab asQcmds[] =
  501. {
  502.   { "C", UUCONF_CMDTABTYPE_FN | 0, NULL, iqcmd },
  503.   { "I", UUCONF_CMDTABTYPE_STRING, (pointer) &zQinput, NULL },
  504.   { "O", UUCONF_CMDTABTYPE_FN | 0, NULL, iqout },
  505.   { "F", UUCONF_CMDTABTYPE_FN | 0, NULL, iqfile },
  506.   { "R", UUCONF_CMDTABTYPE_FN | 0, NULL, iqrequestor },
  507.   { "U", UUCONF_CMDTABTYPE_FN | 0, NULL, iquser },
  508.   { "N", UUCONF_CMDTABTYPE_FN | 0, (pointer) &fQno_ack, iqset },
  509.   { "n", UUCONF_CMDTABTYPE_FN | 0, (pointer) &fQsuccess_ack, iqset },
  510.   { "B", UUCONF_CMDTABTYPE_FN | 0, (pointer) &fQsend_input, iqset },
  511. #if ALLOW_SH_EXECUTION
  512.   { "e", UUCONF_CMDTABTYPE_FN | 0, (pointer) &fQuse_sh, iqset },
  513. #endif
  514.   { "E", UUCONF_CMDTABTYPE_FN | 0, (pointer) &fQuse_exec, iqset },
  515.   { "M", UUCONF_CMDTABTYPE_STRING, (pointer) &zQstatus_file, NULL },
  516.   { NULL, 0, NULL, NULL }
  517. };
  518.  
  519. /* Handle the C command: store off the arguments.  */
  520.  
  521. /*ARGSUSED*/
  522. static int
  523. iqcmd (puuconf, argc, argv, pvar, pinfo)
  524.      pointer puuconf;
  525.      int argc;
  526.      char **argv;
  527.      pointer pvar;
  528.      pointer pinfo;
  529. {
  530.   int i;
  531.   size_t clen;
  532.  
  533.   if (argc <= 1)
  534.     return UUCONF_CMDTABRET_CONTINUE;
  535.  
  536.   azQargs = (char **) xmalloc (argc * sizeof (char *));
  537.   clen = 0;
  538.   for (i = 1; i < argc; i++)
  539.     {
  540.       azQargs[i - 1] = zbufcpy (argv[i]);
  541.       clen += strlen (argv[i]) + 1;
  542.     }
  543.   azQargs[i - 1] = NULL;
  544.  
  545.   zQcmd = (char *) xmalloc (clen);
  546.   zQcmd[0] = '\0';
  547.   for (i = 1; i < argc - 1; i++)
  548.     {
  549.       strcat (zQcmd, argv[i]);
  550.       strcat (zQcmd, " ");
  551.     }
  552.   strcat (zQcmd, argv[i]);
  553.  
  554.   return UUCONF_CMDTABRET_CONTINUE;
  555. }
  556.  
  557. /* Handle the O command, which may have one or two arguments.  */
  558.  
  559. /*ARGSUSED*/
  560. static int
  561. iqout (puuconf, argc, argv, pvar, pinfo)
  562.      pointer puuconf;
  563.      int argc;
  564.      char **argv;
  565.      pointer pvar;
  566.      pointer pinfo;
  567. {
  568.   if (argc > 1)
  569.     zQoutfile = zbufcpy (argv[1]);
  570.   if (argc > 2)
  571.     zQoutsys = zbufcpy (argv[2]);
  572.  
  573.   return UUCONF_CMDTABRET_CONTINUE;
  574. }
  575.  
  576. /* Handle the F command, which may have one or two arguments.  */
  577.  
  578. /*ARGSUSED*/
  579. static int
  580. iqfile (puuconf, argc, argv, pvar, pinfo)
  581.      pointer puuconf;
  582.      int argc;
  583.      char **argv;
  584.      pointer pvar;
  585.      pointer pinfo;
  586. {
  587.   if (argc < 2)
  588.     return UUCONF_CMDTABRET_CONTINUE;
  589.  
  590.   /* If this file is not in the spool directory, just ignore it.  */
  591.   if (! fspool_file (argv[1]))
  592.     return UUCONF_CMDTABRET_CONTINUE;
  593.  
  594.   ++cQfiles;
  595.   azQfiles = (char **) xrealloc ((pointer) azQfiles,
  596.                  cQfiles * sizeof (char *));
  597.   azQfiles_to = (char **) xrealloc ((pointer) azQfiles_to,
  598.                     cQfiles * sizeof (char *));
  599.  
  600.   azQfiles[cQfiles - 1] = zbufcpy (argv[1]);
  601.   if (argc > 2)
  602.     azQfiles_to[cQfiles - 1] = zbufcpy (argv[2]);
  603.   else
  604.     azQfiles_to[cQfiles - 1] = NULL;
  605.  
  606.   return UUCONF_CMDTABRET_CONTINUE;
  607. }
  608.  
  609. /* Handle the R command, which may have one or two arguments.  */
  610.  
  611. /*ARGSUSED*/
  612. static int
  613. iqrequestor (puuconf, argc, argv, pvar, pinfo)
  614.      pointer puuconf;
  615.      int argc;
  616.      char **argv;
  617.      pointer pvar;
  618.      pointer pinfo;
  619. {
  620.   /* We normally have a single argument, which is the ``requestor''
  621.      address, to which we should send any success or error messages.
  622.      Apparently the DOS program UUPC sends two arguments, which are
  623.      the username and the host.  */
  624.   if (argc == 2)
  625.     zQrequestor = zbufcpy (argv[1]);
  626.   else if (argc > 2)
  627.     {
  628.       zQrequestor = zbufalc (strlen (argv[1]) + strlen (argv[2])
  629.                  + sizeof "!");
  630.       sprintf (zQrequestor, "%s!%s", argv[2], argv[1]);
  631.     }
  632.  
  633.   return UUCONF_CMDTABRET_CONTINUE;
  634. }
  635.  
  636. /* Handle the U command, which takes two arguments.  */
  637.  
  638. /*ARGSUSED*/
  639. static int
  640. iquser (puuconf, argc, argv, pvar, pinfo)
  641.      pointer puuconf;
  642.      int argc;
  643.      char **argv;
  644.      pointer pvar;
  645.      pointer pinfo;
  646. {
  647.   if (argc > 1)
  648.     zQuser = argv[1];
  649.   if (argc > 2)
  650.     zQsystem = argv[2];
  651.   return UUCONF_CMDTABRET_KEEP;
  652. }
  653.  
  654. /* Handle various commands which just set boolean variables.  */
  655.  
  656. /*ARGSUSED*/
  657. static int
  658. iqset (puuconf, argc, argv, pvar, pinfo)
  659.      pointer puuconf;
  660.      int argc;
  661.      char **argv;
  662.      pointer pvar;
  663.      pointer pinfo;     
  664. {
  665.   boolean *pf = (boolean *) pvar;
  666.  
  667.   *pf = TRUE;
  668.   return UUCONF_CMDTABRET_CONTINUE;
  669. }
  670.  
  671. /* The execution processing does a lot of things that have to be
  672.    cleaned up.  Rather than try to add the appropriate statements
  673.    to each return point, we keep a set of flags indicating what
  674.    has to be cleaned up.  The actual clean up is done by the
  675.    function uqcleanup.  */
  676. #define REMOVE_FILE (01)
  677. #define REMOVE_NEEDED (02)
  678. #define FREE_QINPUT (04)
  679. #define REMOVE_QINPUT (010)
  680. #define FREE_OUTPUT (020)
  681. #define FREE_MAIL (040)
  682.  
  683. /* Process an execute file.  The zfile argument is the name of the
  684.    execute file.  The zbase argument is the base name of zfile.  The
  685.    qsys argument describes the system it came from.  The zcmd argument
  686.    is the name of the command we are executing (from the -c option) or
  687.    NULL if any command is OK.  This sets *pfprocessed to TRUE if the
  688.    file is ready to be executed.  */
  689.  
  690. static void
  691. uqdo_xqt_file (puuconf, zfile, zbase, qsys, zlocalname, zcmd, pfprocessed)
  692.      pointer puuconf;
  693.      const char *zfile;
  694.      const char *zbase;
  695.      const struct uuconf_system *qsys;
  696.      const char *zlocalname;
  697.      const char *zcmd;
  698.      boolean *pfprocessed;
  699. {
  700.   char *zabsolute;
  701.   boolean ferr;
  702.   FILE *e;
  703.   int iuuconf;
  704.   int i;
  705.   int iclean;
  706.   const char *zmail;
  707.   char *zoutput;
  708.   char *zinput;
  709.   boolean fbadname;
  710.   char abtemp[CFILE_NAME_LEN];
  711.   char abdata[CFILE_NAME_LEN];
  712.   char *zerror;
  713.   struct uuconf_system soutsys;
  714.   const struct uuconf_system *qoutsys;
  715.   boolean fshell;
  716.   size_t clen;
  717.   char *zfullcmd;
  718.   boolean ftemp;
  719.  
  720.   *pfprocessed = FALSE;
  721.  
  722.   e = fopen (zfile, "r");
  723.   if (e == NULL)
  724.     return;
  725.  
  726.   azQargs = NULL;
  727.   zQcmd = NULL;
  728.   zQinput = NULL;
  729.   zQoutfile = NULL;
  730.   zQoutsys = NULL;
  731.   cQfiles = 0;
  732.   azQfiles = NULL;
  733.   azQfiles_to = NULL;
  734.   zQrequestor = NULL;
  735.   zQuser = NULL;
  736.   zQsystem = NULL;
  737.   fQno_ack = FALSE;
  738.   fQsuccess_ack = FALSE;
  739.   fQsend_input = FALSE;
  740.   fQuse_exec = FALSE;
  741.   zQstatus_file = NULL;
  742. #if ALLOW_SH_EXECUTION
  743.   fQuse_sh = FALSE;
  744. #endif
  745.  
  746.   iuuconf = uuconf_cmd_file (puuconf, e, asQcmds, (pointer) zbase,
  747.                  (uuconf_cmdtabfn) NULL,
  748.                  (UUCONF_CMDTABFLAG_CASE
  749.                   | UUCONF_CMDTABFLAG_NOCOMMENTS),
  750.                  (pointer) NULL);
  751.   (void) fclose (e);
  752.  
  753.   if (iuuconf != UUCONF_SUCCESS)
  754.     {
  755.       ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  756.  
  757.       /* If we got a non-transient error, we notify the administrator.
  758.      We can't bounce it back to the original requestor, because we
  759.      don't know how to read the file to figure out who it is (it
  760.      would probably be possible to read the file and work it out,
  761.      but it doesn't seem worth it for such an unlikely error).  */
  762.       if (UUCONF_ERROR_VALUE (iuuconf) == UUCONF_SYNTAX_ERROR
  763.       || UUCONF_ERROR_VALUE (iuuconf) == UUCONF_UNKNOWN_COMMAND)
  764.     {
  765.       const char *az[20];
  766.       char *znew;
  767.  
  768.       i = 0;
  769.       az[i++] = "The execution file\n\t";
  770.       az[i++] = zfile;
  771.       az[i++] = "\nfor system\n\t";
  772.       az[i++] = qsys->uuconf_zname;
  773.       az[i++] = "\nwas corrupt.  ";
  774.       znew = zsysdep_save_corrupt_file (zfile);
  775.       if (znew == NULL)
  776.         {
  777.           az[i++] = "The file could not be preserved.\n";
  778.           (void) remove (zfile);
  779.         }
  780.       else
  781.         {
  782.           az[i++] = "It has been moved to\n\t";
  783.           az[i++] = znew;
  784.           az[i++] = "\n";
  785.         }
  786.       (void) fsysdep_mail (OWNER, "Corrupt execution file", i, az);
  787.       ubuffree (znew);
  788.     }
  789.  
  790.       return;
  791.     }
  792.  
  793.   iclean = 0;
  794.  
  795.   if (azQargs == NULL)
  796.     {
  797.       ulog (LOG_ERROR, "%s: No command given", zbase);
  798.       uqcleanup (zfile, iclean | REMOVE_FILE);
  799.       return;
  800.     }
  801.  
  802.   if (zcmd != NULL)
  803.     {
  804.       if (strcmp (zcmd, azQargs[0]) != 0)
  805.     {
  806.       uqcleanup (zfile, iclean);
  807.       return;
  808.     }
  809.     }
  810.   else
  811.     {
  812.       /* If there is a lock file for this particular command already,
  813.      it means that some other uuxqt is supposed to handle it.  */
  814.       if (fsysdep_uuxqt_locked (azQargs[0]))
  815.     {
  816.       uqcleanup (zfile, iclean);
  817.       return;
  818.     }
  819.     }
  820.  
  821.   /* Lock this particular file.  */
  822.   if (! fsysdep_lock_uuxqt_file (zfile))
  823.     {
  824.       uqcleanup (zfile, iclean);
  825.       return;
  826.     }
  827.  
  828.   zQunlock_file = zfile;
  829.  
  830.   /* Now that we have the file locked, make sure it still exists.
  831.      Otherwise another uuxqt could have just finished processing it
  832.      and removed the lock file.  */
  833.   if (! fsysdep_file_exists (zfile))
  834.     {
  835.       uqcleanup (zfile, iclean);
  836.       return;
  837.     }
  838.  
  839.   if (zQuser != NULL)
  840.     ulog_user (zQuser);
  841.   else if (zQrequestor != NULL)
  842.     ulog_user (zQrequestor);
  843.   else
  844.     ulog_user ("unknown");
  845.  
  846.   /* zQsystem, if it is set, comes from the execution file, which
  847.      means that we do not trust it.  We only retain it if
  848.      qsys->uuconf_zname is a prefix of it, since that can happen with
  849.      a job from an anonymous system on certain spool directory types,
  850.      and is unlikely to cause any trouble anyhow.  */
  851.   if (zQsystem == NULL
  852.       || strncmp (zQsystem, qsys->uuconf_zname,
  853.           strlen (qsys->uuconf_zname)) != 0)
  854.     zQsystem = qsys->uuconf_zname;
  855.  
  856.   /* Make sure that all the required files exist, and get their
  857.      full names in the spool directory.  */
  858.   for (i = 0; i < cQfiles; i++)
  859.     {
  860.       char *zreal;
  861.  
  862.       zreal = zsysdep_spool_file_name (qsys, azQfiles[i], (pointer) NULL);
  863.       if (zreal == NULL)
  864.     {
  865.       uqcleanup (zfile, iclean);
  866.       return;
  867.     }
  868.       if (! fsysdep_file_exists (zreal))
  869.     {
  870.       uqcleanup (zfile, iclean);
  871.       return;
  872.     }
  873.       ubuffree (azQfiles[i]);
  874.       azQfiles[i] = zbufcpy (zreal);
  875.       ubuffree (zreal);
  876.     }
  877.  
  878.   /* Lock the execution directory.  */
  879.   if (! fsysdep_lock_uuxqt_dir (iQlock_seq))
  880.     {
  881.       ulog (LOG_ERROR, "Could not lock execute directory");
  882.       uqcleanup (zfile, iclean);
  883.       return;
  884.     }
  885.   fQunlock_directory = TRUE;
  886.  
  887.   iclean |= REMOVE_FILE | REMOVE_NEEDED;
  888.   *pfprocessed = TRUE;
  889.  
  890.   /* Get the address to mail results to.  Prepend the system from
  891.      which the execute file originated, since mail addresses are
  892.      relative to it.  */
  893.   zmail = NULL;
  894.   if (zQrequestor != NULL)
  895.     zmail = zQrequestor;
  896.   else if (zQuser != NULL)
  897.     zmail = zQuser;
  898.   if (zmail != NULL
  899. #if HAVE_INTERNET_MAIL
  900.       && strchr (zmail, '@') == NULL
  901. #endif
  902.       && strcmp (zQsystem, zlocalname) != 0)
  903.     {
  904.       char *zset;
  905.  
  906.       zset = zbufalc (strlen (zQsystem) + strlen (zmail) + 2);
  907.       sprintf (zset, "%s!%s", zQsystem, zmail);
  908.       zmail = zset;
  909.       zQmail = zset;
  910.       iclean |= FREE_MAIL;
  911.     }
  912.  
  913.   /* The command "uucp" is handled specially.  We make sure that the
  914.      appropriate forwarding is permitted, and we add a -u argument to
  915.      specify the user.  */
  916.   if (strcmp (azQargs[0], "uucp") == 0)
  917.     {
  918.       char *zfrom, *zto;
  919.       boolean fmany;
  920.       char **azargs;
  921.       const char *zuser;
  922.  
  923.       zfrom = NULL;
  924.       zto = NULL;
  925.       fmany = FALSE;
  926.  
  927.       /* Skip all the options, and get the from and to specs.  We
  928.      don't permit multiple arguments.  */
  929.       for (i = 1; azQargs[i] != NULL; i++)
  930.     {
  931.       if (azQargs[i][0] == '-')
  932.         {
  933.           char *zopts;
  934.  
  935.           for (zopts = azQargs[i] + 1; *zopts != '\0'; zopts++)
  936.         {
  937.           /* The -g, -n, and -s options take an argument.  */
  938.           if (*zopts == 'g' || *zopts == 'n' || *zopts == 's')
  939.             {
  940.               if (zopts[1] == '\0')
  941.             ++i;
  942.               break;
  943.             }
  944.           /* The -I, -u and -x options are not permitted.  */
  945.           if (*zopts == 'I' || *zopts == 'u' || *zopts == 'x')
  946.             {
  947.               *zopts = 'r';
  948.               if (zopts[1] != '\0')
  949.             zopts[1] = '\0';
  950.               else
  951.             {
  952.               ++i;
  953.               azQargs[i] = zbufcpy ("-r");
  954.             }
  955.               break;
  956.             }
  957.         }
  958.         }
  959.       else if (zfrom == NULL)
  960.         zfrom = azQargs[i];
  961.       else if (zto == NULL)
  962.         zto = azQargs[i];
  963.       else
  964.         {
  965.           fmany = TRUE;
  966.           break;
  967.         }
  968.     }
  969.  
  970.       /* Add the -u argument.  This is required to let uucp do the
  971.      correct permissions checking on the file transfer.  */
  972.       for (i = 0; azQargs[i] != NULL; i++)
  973.     ;
  974.       azargs = (char **) xmalloc ((i + 2) * sizeof (char *));
  975.       azargs[0] = azQargs[0];
  976.       zuser = zQuser;
  977.       if (zuser == NULL)
  978.     zuser = "uucp";
  979.       azargs[1] = zbufalc (strlen (zQsystem) + strlen (zuser)
  980.                + sizeof "-u!");
  981.       sprintf (azargs[1], "-u%s!%s", zQsystem, zuser);
  982.       memcpy (azargs + 2, azQargs + 1, i * sizeof (char *));
  983.       xfree ((pointer) azQargs);
  984.       azQargs = azargs;
  985.  
  986.       /* Find the uucp binary.  */
  987.       zabsolute = zsysdep_find_command ("uucp", qsys->uuconf_pzcmds,
  988.                     qsys->uuconf_pzpath, &ferr);
  989.       if (zabsolute == NULL && ! ferr)
  990.     {
  991.       const char *azcmds[2];
  992.  
  993.       /* If "uucp" is not a permitted command, then the forwarding
  994.          entries must be set.  */
  995.       if (! fqforward (zfrom, qsys->uuconf_pzforward_from, "from", zmail)
  996.           || ! fqforward (zto, qsys->uuconf_pzforward_to, "to", zmail))
  997.         {
  998.           uqcleanup (zfile, iclean);
  999.           return;
  1000.         }
  1001.  
  1002.       /* If "uucp" is not a permitted command, then only uucp
  1003.          requests with a single source are permitted, since that
  1004.          is all that will be generated by uucp or uux.  */
  1005.       if (fmany)
  1006.         {
  1007.           ulog (LOG_ERROR, "Bad uucp request %s", zQcmd);
  1008.  
  1009.           if (zmail != NULL && ! fQno_ack)
  1010.         {
  1011.           const char *az[20];
  1012.  
  1013.           i = 0;
  1014.           az[i++] = "Your execution request failed because it was an";
  1015.           az[i++] = " unsupported uucp request.\n";
  1016.           az[i++] = "Execution requested was:\n\t";
  1017.           az[i++] = zQcmd;
  1018.           az[i++] = "\n";
  1019.  
  1020.           (void) fsysdep_mail (zmail, "Execution failed", i, az);
  1021.         }
  1022.  
  1023.           uqcleanup (zfile, iclean);
  1024.           return;
  1025.         }
  1026.  
  1027.       azcmds[0] = "uucp";
  1028.       azcmds[1] = NULL;
  1029.       zabsolute = zsysdep_find_command ("uucp", (char **) azcmds,
  1030.                         qsys->uuconf_pzpath, &ferr);
  1031.     }
  1032.       if (zabsolute == NULL)
  1033.     {
  1034.       if (! ferr)
  1035.         ulog (LOG_ERROR, "Can't find uucp executable");
  1036.  
  1037.       uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
  1038.       *pfprocessed = FALSE;
  1039.       return;
  1040.     }
  1041.     }
  1042.   else
  1043.     {
  1044.       /* Get the pathname to execute.  */
  1045.       zabsolute = zsysdep_find_command (azQargs[0], qsys->uuconf_pzcmds,
  1046.                     qsys->uuconf_pzpath,
  1047.                     &ferr);
  1048.       if (zabsolute == NULL)
  1049.     {
  1050.       if (ferr)
  1051.         {
  1052.           /* If we get an error, try again later.  */
  1053.           uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
  1054.           *pfprocessed = FALSE;
  1055.           return;
  1056.         }
  1057.  
  1058.       /* Not permitted.  Send mail to requestor.  */
  1059.       ulog (LOG_ERROR, "Not permitted to execute %s",
  1060.         azQargs[0]);
  1061.  
  1062.       if (zmail != NULL && ! fQno_ack)
  1063.         {
  1064.           const char *az[20];
  1065.  
  1066.           i = 0;
  1067.           az[i++] = "Your execution request failed because you are not";
  1068.           az[i++] = " permitted to execute\n\t";
  1069.           az[i++] = azQargs[0];
  1070.           az[i++] = "\non this system.\n";
  1071.           az[i++] = "Execution requested was:\n\t";
  1072.           az[i++] = zQcmd;
  1073.           az[i++] = "\n";
  1074.  
  1075.           (void) fsysdep_mail (zmail, "Execution failed", i, az);
  1076.         }
  1077.  
  1078.       iclean = isave_files (qsys, zmail, zfile, iclean);
  1079.  
  1080.       uqcleanup (zfile, iclean);
  1081.       return;
  1082.     }
  1083.     }
  1084.  
  1085.   ubuffree (azQargs[0]);
  1086.   azQargs[0] = zabsolute;
  1087.  
  1088.   for (i = 1; azQargs[i] != NULL; i++)
  1089.     {
  1090.       char *zlocal;
  1091.  
  1092.       zlocal = zsysdep_xqt_local_file (qsys, azQargs[i]);
  1093.       if (zlocal != NULL)
  1094.     {
  1095.       ubuffree (azQargs[i]);
  1096.       azQargs[i] = zlocal;
  1097.     }
  1098.     }
  1099.  
  1100. #if ! ALLOW_FILENAME_ARGUMENTS
  1101.  
  1102.   /* Check all the arguments to make sure they don't try to specify
  1103.      files they are not permitted to access.  */
  1104.   for (i = 1; azQargs[i] != NULL; i++)
  1105.     {
  1106.       if (! fsysdep_xqt_check_file (qsys, azQargs[i]))
  1107.     {
  1108.       if (zmail != NULL && ! fQno_ack)
  1109.         {
  1110.           const char *az[20];
  1111.           const char *zfailed;
  1112.  
  1113.           zfailed = azQargs[i];
  1114.           i = 0;
  1115.           az[i++] = "Your execution request failed because you are not";
  1116.           az[i++] = " permitted to refer to file\n\t";
  1117.           az[i++] = zfailed;
  1118.           az[i++] = "\non this system.\n";
  1119.           az[i++] = "Execution requested was:\n\t";
  1120.           az[i++] = zQcmd;
  1121.           az[i++] = "\n";
  1122.  
  1123.           (void) fsysdep_mail (zmail, "Execution failed", i, az);
  1124.         }
  1125.  
  1126.       iclean = isave_files (qsys, zmail, zfile, iclean);
  1127.  
  1128.       uqcleanup (zfile, iclean);
  1129.       return;
  1130.     }
  1131.     }
  1132.  
  1133. #endif /* ! ALLOW_FILENAME_ARGUMENTS */
  1134.  
  1135.   ulog (LOG_NORMAL, "Executing %s (%s)", zbase, zQcmd);
  1136.  
  1137.   if (zQinput != NULL)
  1138.     {
  1139.       boolean fspool;
  1140.       char *zreal;
  1141.  
  1142.       fspool = fspool_file (zQinput);
  1143.       if (! fspool)
  1144.     zreal = zsysdep_local_file (zQinput, qsys->uuconf_zpubdir, &fbadname);
  1145.       else
  1146.     {
  1147.       zreal = zsysdep_spool_file_name (qsys, zQinput, (pointer) NULL);
  1148.       fbadname = FALSE;
  1149.     }
  1150.       if (zreal == NULL && ! fbadname)
  1151.     {
  1152.       /* If we get an error, try again later.  */
  1153.       uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
  1154.       *pfprocessed = FALSE;
  1155.       return;
  1156.     }
  1157.  
  1158.       if (zreal != NULL)
  1159.     {
  1160.       zQinput = zreal;
  1161.       iclean |= FREE_QINPUT;
  1162.       if (fspool)
  1163.         iclean |= REMOVE_QINPUT;
  1164.     }
  1165.  
  1166.       if (zreal == NULL
  1167.       || (! fspool
  1168.           && ! fin_directory_list (zQinput, qsys->uuconf_pzremote_send,
  1169.                        qsys->uuconf_zpubdir, TRUE, TRUE,
  1170.                        (const char *) NULL)))
  1171.     {
  1172.       ulog (LOG_ERROR, "Not permitted to read %s", zQinput);
  1173.           
  1174.       if (zmail != NULL && ! fQno_ack)
  1175.         {
  1176.           const char *az[20];
  1177.  
  1178.           i = 0;
  1179.           az[i++] = "Your execution request failed because you are";
  1180.           az[i++] = " not permitted to read\n\t";
  1181.           az[i++] = zQinput;
  1182.           az[i++] = "\non this system.\n";
  1183.           az[i++] = "Execution requested was:\n\t";
  1184.           az[i++] = zQcmd;
  1185.           az[i++] = "\n";
  1186.  
  1187.           (void) fsysdep_mail (zmail, "Execution failed", i, az);
  1188.         }
  1189.  
  1190.       uqcleanup (zfile, iclean);
  1191.       return;
  1192.     }
  1193.     }
  1194.  
  1195.   zoutput = NULL;
  1196.   if (zQoutfile == NULL)
  1197.     qoutsys = NULL;
  1198.   else if (zQoutsys != NULL
  1199.        && strcmp (zQoutsys, zlocalname) != 0)
  1200.     {
  1201.       char *zdata;
  1202.      
  1203.       /* The output file is destined for some other system, so we must
  1204.      use a temporary file to catch standard output.  */
  1205.       if (strcmp (zQoutsys, qsys->uuconf_zname) == 0)
  1206.     qoutsys = qsys;
  1207.       else
  1208.     {
  1209.       iuuconf = uuconf_system_info (puuconf, zQoutsys, &soutsys);
  1210.       if (iuuconf != UUCONF_SUCCESS)
  1211.         {
  1212.           if (iuuconf != UUCONF_NOT_FOUND)
  1213.         {
  1214.           ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  1215.           uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
  1216.           *pfprocessed = FALSE;
  1217.           return;
  1218.         }
  1219.  
  1220.           if (! funknown_system (puuconf, zQoutsys, &soutsys))
  1221.         {
  1222.           ulog (LOG_ERROR,
  1223.             "Can't send standard output to unknown system %s",
  1224.             zQoutsys);
  1225.           /* We don't send mail to unknown systems, either.
  1226.              Maybe we should.  */
  1227.           uqcleanup (zfile, iclean);
  1228.           return;
  1229.         }
  1230.         }
  1231.  
  1232.       qoutsys = &soutsys;
  1233.     }
  1234.  
  1235.       zdata = zsysdep_data_file_name (qoutsys, zlocalname,
  1236.                       BDEFAULT_UUX_GRADE, FALSE, abtemp,
  1237.                       abdata, (char *) NULL);
  1238.       if (zdata == NULL)
  1239.     {
  1240.       /* If we get an error, try again later.  */
  1241.       uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
  1242.       *pfprocessed = FALSE;
  1243.       return;
  1244.     }
  1245.       zoutput = zdata;
  1246.       zQoutput = zoutput;
  1247.       iclean |= FREE_OUTPUT;
  1248.     }
  1249.   else
  1250.     {
  1251.       boolean fok;
  1252.      
  1253.       qoutsys = NULL;
  1254.  
  1255.       /* If we permitted the standard output to be redirected into
  1256.      the spool directory, people could set up phony commands.  */
  1257.       if (fspool_file (zQoutfile))
  1258.     fok = FALSE;
  1259.       else
  1260.     {
  1261.       zoutput = zsysdep_local_file (zQoutfile, qsys->uuconf_zpubdir,
  1262.                     &fbadname);
  1263.       if (zoutput == NULL)
  1264.         {
  1265.           if (! fbadname)
  1266.         {
  1267.           /* If we get an error, try again later.  */
  1268.           uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
  1269.           *pfprocessed = FALSE;
  1270.           return;
  1271.         }
  1272.           fok = FALSE;
  1273.         }
  1274.       else
  1275.         {
  1276.           ubuffree (zQoutfile);
  1277.           zQoutfile = zoutput;
  1278.  
  1279.           /* Make sure it's OK to receive this file.  */
  1280.           fok = fin_directory_list (zQoutfile,
  1281.                     qsys->uuconf_pzremote_receive,
  1282.                     qsys->uuconf_zpubdir, TRUE, FALSE,
  1283.                     (const char *) NULL);
  1284.         }
  1285.     }
  1286.  
  1287.       if (! fok)
  1288.     {
  1289.       ulog (LOG_ERROR, "Not permitted to write to %s", zQoutfile);
  1290.           
  1291.       if (zmail != NULL && ! fQno_ack)
  1292.         {
  1293.           const char *az[20];
  1294.  
  1295.           i = 0;
  1296.           az[i++] = "Your execution request failed because you are";
  1297.           az[i++] = " not permitted to write to\n\t";
  1298.           az[i++] = zQoutfile;
  1299.           az[i++] = "\non this system.\n";
  1300.           az[i++] = "Execution requested was:\n\t";
  1301.           az[i++] = zQcmd;
  1302.           az[i++] = "\n";
  1303.  
  1304.           (void) fsysdep_mail (zmail, "Execution failed", i, az);
  1305.         }
  1306.  
  1307.       uqcleanup (zfile, iclean);
  1308.       return;
  1309.     }
  1310.     }
  1311.  
  1312.   /* Move the required files to the execution directory if necessary.  */
  1313.   zinput = zQinput;
  1314.   if (! fsysdep_move_uuxqt_files (cQfiles, (const char **) azQfiles,
  1315.                   (const char **) azQfiles_to,
  1316.                   TRUE, iQlock_seq, &zinput))
  1317.     {
  1318.       /* If we get an error, try again later.  */
  1319.       uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
  1320.       *pfprocessed = FALSE;
  1321.       return;
  1322.     }
  1323.   if (zQinput != NULL && strcmp (zQinput, zinput) != 0)
  1324.     {
  1325.       if ((iclean & FREE_QINPUT) != 0)
  1326.     ubuffree (zQinput);
  1327.       zQinput = zinput;
  1328.       iclean |= FREE_QINPUT;
  1329.     }
  1330.  
  1331. #if ALLOW_SH_EXECUTION
  1332.   fshell = fQuse_sh;
  1333. #else
  1334.   fshell = FALSE;
  1335. #endif
  1336.  
  1337.   /* Get a shell command which uses the full path of the command to
  1338.      execute.  */
  1339.   clen = 0;
  1340.   for (i = 0; azQargs[i] != NULL; i++)
  1341.     clen += strlen (azQargs[i]) + 1;
  1342.   zfullcmd = zbufalc (clen);
  1343.   strcpy (zfullcmd, azQargs[0]);
  1344.   for (i = 1; azQargs[i] != NULL; i++)
  1345.     {
  1346.       strcat (zfullcmd, " ");
  1347.       strcat (zfullcmd, azQargs[i]);
  1348.     }
  1349.  
  1350.   if (! fsysdep_execute (qsys,
  1351.              zQuser == NULL ? (const char *) "uucp" : zQuser,
  1352.              (const char **) azQargs, zfullcmd, zQinput,
  1353.              zoutput, fshell, iQlock_seq, &zerror, &ftemp))
  1354.     {
  1355.       ubuffree (zfullcmd);
  1356.  
  1357.       (void) fsysdep_move_uuxqt_files (cQfiles, (const char **) azQfiles,
  1358.                        (const char **) azQfiles_to,
  1359.                        FALSE, iQlock_seq,
  1360.                        (char **) NULL);
  1361.  
  1362.       if (ftemp)
  1363.     {
  1364.       ulog (LOG_NORMAL, "Will retry later (%s)", zbase);
  1365.       if (zoutput != NULL)
  1366.         (void) remove (zoutput);
  1367.       if (zerror != NULL)
  1368.         {
  1369.           (void) remove (zerror);
  1370.           ubuffree (zerror);
  1371.         }
  1372.       uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
  1373.       *pfprocessed = FALSE;
  1374.       return;
  1375.     }
  1376.  
  1377.       ulog (LOG_NORMAL, "Execution failed (%s)", zbase);
  1378.  
  1379.       if (zmail != NULL && ! fQno_ack)
  1380.     {
  1381.       const char **pz;
  1382.       int cgot;
  1383.       FILE *eerr;
  1384.       int istart;
  1385.  
  1386.       cgot = 20;
  1387.       pz = (const char **) xmalloc (cgot * sizeof (const char *));
  1388.       i = 0;
  1389.       pz[i++] = "Execution request failed:\n\t";
  1390.       pz[i++] = zQcmd;
  1391.       pz[i++] = "\n";
  1392.  
  1393.       if (zerror == NULL)
  1394.         eerr = NULL;
  1395.       else
  1396.         eerr = fopen (zerror, "r");
  1397.       if (eerr == NULL)
  1398.         {
  1399.           pz[i++] = "There was no output on standard error\n";
  1400.           istart = i;
  1401.         }
  1402.       else
  1403.         {
  1404.           char *zline;
  1405.           size_t cline;
  1406.  
  1407.           pz[i++] = "Standard error output was:\n";
  1408.           istart = i;
  1409.  
  1410.           zline = NULL;
  1411.           cline = 0;
  1412.           while (getline (&zline, &cline, eerr) > 0)
  1413.         {
  1414.           if (i >= cgot)
  1415.             {
  1416.               cgot += 20;
  1417.               pz = ((const char **)
  1418.                 xrealloc ((pointer) pz,
  1419.                       cgot * sizeof (const char *)));
  1420.             }
  1421.           pz[i++] = zbufcpy (zline);
  1422.         }
  1423.  
  1424.           (void) fclose (eerr);
  1425.           xfree ((pointer) zline);
  1426.         }
  1427.  
  1428.       (void) fsysdep_mail (zmail, "Execution failed", i, pz);
  1429.  
  1430.       for (; istart < i; istart++)
  1431.         ubuffree ((char *) pz[istart]);
  1432.       xfree ((pointer) pz);
  1433.     }
  1434.  
  1435.       if (qoutsys != NULL)
  1436.     (void) remove (zoutput);
  1437.  
  1438.       iclean = isave_files (qsys, zmail, zfile, iclean);
  1439.     }
  1440.   else
  1441.     {
  1442.       ubuffree (zfullcmd);
  1443.  
  1444.       if (zmail != NULL && fQsuccess_ack)
  1445.     {
  1446.       const char *az[20];
  1447.  
  1448.       i = 0;
  1449.       az[i++] = "\nExecution request succeeded:\n\t";
  1450.       az[i++] = zQcmd;
  1451.       az[i++] = "\n";
  1452.  
  1453.       (void) fsysdep_mail (zmail, "Execution succeded", i, az);
  1454.     }
  1455.  
  1456.       /* Now we may have to uucp the output to some other machine.  */
  1457.  
  1458.       if (qoutsys != NULL)
  1459.     {
  1460.       struct scmd s;
  1461.  
  1462.       /* Fill in the command structure.  */
  1463.  
  1464.       s.bcmd = 'S';
  1465.       s.bgrade = BDEFAULT_UUX_GRADE;
  1466.       s.pseq = NULL;
  1467.       s.zfrom = abtemp;
  1468.       s.zto = zQoutfile;
  1469.       if (zQuser != NULL)
  1470.         s.zuser = zQuser;
  1471.       else
  1472.         s.zuser = "uucp";
  1473.       if (zmail != NULL && fQsuccess_ack)
  1474.         s.zoptions = "Cn";
  1475.       else
  1476.         s.zoptions = "C";
  1477.       s.ztemp = abtemp;
  1478.       s.imode = 0666;
  1479.       if (zmail != NULL && fQsuccess_ack)
  1480.         s.znotify = zmail;
  1481.       else
  1482.         s.znotify = "";
  1483.       s.cbytes = -1;
  1484.       s.zcmd = NULL;
  1485.       s.ipos = 0;
  1486.  
  1487.       ubuffree (zsysdep_spool_commands (qoutsys, BDEFAULT_UUX_GRADE,
  1488.                         1, &s));
  1489.     }
  1490.     }
  1491.  
  1492.   if (zerror != NULL)
  1493.     {
  1494.       (void) remove (zerror);
  1495.       ubuffree (zerror);
  1496.     }
  1497.  
  1498.   uqcleanup (zfile, iclean);
  1499. }
  1500.  
  1501. /* If we have enough disk space, save the data files so that the UUCP
  1502.    administrator can examine them.  Send a mail message listing the
  1503.    saved files.  */
  1504.  
  1505. static int
  1506. isave_files (qsys, zmail, zfile, iclean)
  1507.      const struct uuconf_system *qsys;
  1508.      const char *zmail;
  1509.      const char *zfile;
  1510.      int iclean;
  1511. {
  1512.   long cspace;
  1513.   char *zsavecmd;
  1514.   char **pzsave;
  1515.   int c;
  1516.   int ifile;
  1517.   char *zsaveinput;
  1518.   const char **pz;
  1519.   int i;
  1520.  
  1521.   /* Save the files if there is 1.5 times the amount of required free
  1522.      space.  */
  1523.   cspace = csysdep_bytes_free (zfile);
  1524.   if (cspace == -1)
  1525.     cspace = FREE_SPACE_DELTA;
  1526.   cspace -= qsys->uuconf_cfree_space + qsys->uuconf_cfree_space / 2;
  1527.   if (cspace < 0)
  1528.     return iclean;
  1529.  
  1530.   zsavecmd = zsysdep_save_failed_file (zfile);
  1531.   if (zsavecmd == NULL)
  1532.     return iclean;
  1533.  
  1534.   c = 1;
  1535.  
  1536.   pzsave = (char **) xmalloc (cQfiles * sizeof (char *));
  1537.   for (ifile = 0; ifile < cQfiles; ifile++)
  1538.     {
  1539.       if (azQfiles[ifile] != NULL)
  1540.     {
  1541.       ++c;
  1542.       pzsave[ifile] = zsysdep_save_failed_file (azQfiles[ifile]);
  1543.       if (pzsave[ifile] == NULL)
  1544.         {
  1545.           ubuffree (zsavecmd);
  1546.           for (i = 0; i < ifile; i++)
  1547.         if (azQfiles[i] != NULL)
  1548.           ubuffree (pzsave[i]);
  1549.           xfree ((pointer) pzsave);
  1550.           return iclean;
  1551.         }
  1552.     }
  1553.     }
  1554.  
  1555.   zsaveinput = NULL;
  1556.   if ((iclean & REMOVE_QINPUT) != 0
  1557.       && fsysdep_file_exists (zQinput))
  1558.     {
  1559.       zsaveinput = zsysdep_save_failed_file (zQinput);
  1560.       if (zsaveinput == NULL)
  1561.     {
  1562.       ubuffree (zsavecmd);
  1563.       for (i = 0; i < cQfiles; i++)
  1564.         if (azQfiles[i] != NULL)
  1565.           ubuffree  (pzsave[i]);
  1566.       xfree ((pointer) pzsave);
  1567.       return iclean;
  1568.     }
  1569.     }
  1570.  
  1571.   pz = (const char **) xmalloc ((20 + 2 * cQfiles) * sizeof (char *));
  1572.   i = 0;
  1573.  
  1574.   pz[i++] = "A UUCP execution request failed:\n\t";
  1575.   pz[i++] = zQcmd;
  1576.   if (zmail != NULL)
  1577.     {
  1578.       pz[i++] = "\nThe request was made by\n\t";
  1579.       pz[i++] = zmail;
  1580.     }
  1581.   else
  1582.     {
  1583.       pz[i++] = "\nThe request came from system\n\t";
  1584.       pz[i++] = qsys->uuconf_zname;
  1585.     }
  1586.   if (c == 1 && zsaveinput == NULL)
  1587.     pz[i++] = "\nThe following file has been saved:\n\t";
  1588.   else
  1589.     pz[i++] = "\nThe following files have been saved:\n\t";
  1590.   pz[i++] = zsavecmd;
  1591.   for (ifile = 0; ifile < cQfiles; ifile++)
  1592.     {
  1593.       if (azQfiles[ifile] != NULL)
  1594.     {
  1595.       pz[i++] = "\n\t";
  1596.       pz[i++] = pzsave[ifile];
  1597.     }
  1598.     }
  1599.   if (zsaveinput != NULL)
  1600.     {
  1601.       pz[i++] = "\n\t";
  1602.       pz[i++] = zsaveinput;
  1603.     }
  1604.   pz[i++] = "\n";
  1605.  
  1606.   (void) fsysdep_mail (OWNER,
  1607.                "UUCP execution files saved after failure",
  1608.                i, pz);
  1609.  
  1610.   xfree ((pointer) pz);
  1611.  
  1612.   ubuffree (zsavecmd);
  1613.   for (ifile = 0; ifile < cQfiles; ifile++)
  1614.     if (azQfiles[ifile] != NULL)
  1615.       ubuffree (pzsave[ifile]);
  1616.   xfree ((pointer) pzsave);
  1617.   ubuffree (zsaveinput);
  1618.  
  1619.   return iclean &~ (REMOVE_FILE | REMOVE_NEEDED);
  1620. }
  1621.  
  1622. /* Clean up the results of uqdo_xqt_file.  */
  1623.  
  1624. static void
  1625. uqcleanup (zfile, iflags)
  1626.      const char *zfile;
  1627.      int iflags;
  1628. {
  1629.   int i;
  1630.  
  1631.   DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
  1632.           "uqcleanup: %s, %d", zfile, iflags);
  1633.  
  1634.   if (zQunlock_file != NULL)
  1635.     {
  1636.       (void) fsysdep_unlock_uuxqt_file (zQunlock_file);
  1637.       zQunlock_file = NULL;
  1638.     }
  1639.  
  1640.   if ((iflags & REMOVE_FILE) != 0)
  1641.     (void) remove (zfile);
  1642.  
  1643.   if ((iflags & REMOVE_NEEDED) != 0)
  1644.     {
  1645.       for (i = 0; i < cQfiles; i++)
  1646.     {
  1647.       if (azQfiles[i] != NULL)
  1648.         (void) remove (azQfiles[i]);
  1649.     }
  1650.       if ((iflags & REMOVE_QINPUT) != 0)
  1651.     (void) remove (zQinput);
  1652.     }
  1653.  
  1654.   if ((iflags & FREE_QINPUT) != 0)
  1655.     ubuffree (zQinput);
  1656.  
  1657.   if ((iflags & FREE_OUTPUT) != 0)
  1658.     ubuffree (zQoutput);
  1659.   if ((iflags & FREE_MAIL) != 0)
  1660.     ubuffree (zQmail);
  1661.  
  1662.   if (fQunlock_directory)
  1663.     {
  1664.       (void) fsysdep_unlock_uuxqt_dir (iQlock_seq);
  1665.       fQunlock_directory = FALSE;
  1666.     }
  1667.  
  1668.   for (i = 0; i < cQfiles; i++)
  1669.     {
  1670.       ubuffree (azQfiles[i]);
  1671.       ubuffree (azQfiles_to[i]);
  1672.     }
  1673.  
  1674.   ubuffree (zQoutfile);
  1675.   ubuffree (zQoutsys);
  1676.   ubuffree (zQrequestor);
  1677.  
  1678.   if (azQargs != NULL)
  1679.     {
  1680.       for (i = 0; azQargs[i] != NULL; i++)
  1681.     ubuffree (azQargs[i]);
  1682.       xfree ((pointer) azQargs);
  1683.       azQargs = NULL;
  1684.     }
  1685.  
  1686.   xfree ((pointer) zQcmd);
  1687.   zQcmd = NULL;
  1688.  
  1689.   xfree ((pointer) azQfiles);
  1690.   azQfiles = NULL;
  1691.  
  1692.   xfree ((pointer) azQfiles_to);
  1693.   azQfiles_to = NULL;
  1694. }
  1695.  
  1696. /* Check whether forwarding is permitted.  */
  1697.  
  1698. static boolean
  1699. fqforward (zfile, pzallowed, zlog, zmail)
  1700.      const char *zfile;
  1701.      char **pzallowed;
  1702.      const char *zlog;
  1703.      const char *zmail;
  1704. {
  1705.   const char *zexclam;
  1706.  
  1707.   zexclam = strchr (zfile, '!');
  1708.   if (zexclam != NULL)
  1709.     {
  1710.       size_t clen;
  1711.       char *zsys;
  1712.       boolean fret;
  1713.  
  1714.       clen = zexclam - zfile;
  1715.       zsys = zbufalc (clen + 1);
  1716.       memcpy (zsys, zfile, clen);
  1717.       zsys[clen] = '\0';
  1718.  
  1719.       fret = FALSE;
  1720.       if (pzallowed != NULL)
  1721.     {
  1722.       char **pz;
  1723.  
  1724.       for (pz = pzallowed; *pz != NULL; pz++)
  1725.         {
  1726.           if (strcmp (*pz, "ANY") == 0
  1727.           || strcmp (*pz, zsys) == 0)
  1728.         {
  1729.           fret = TRUE;
  1730.           break;
  1731.         }
  1732.         }
  1733.     }
  1734.  
  1735.       if (! fret)
  1736.     {
  1737.       ulog (LOG_ERROR, "Not permitted to forward %s %s (%s)",
  1738.         zlog, zsys, zQcmd);
  1739.  
  1740.       if (zmail != NULL && ! fQno_ack)
  1741.         {
  1742.           int i;
  1743.           const char *az[20];
  1744.  
  1745.           i = 0;
  1746.           az[i++] = "Your execution request failed because you are";
  1747.           az[i++] = " not permitted to forward files\n";
  1748.           az[i++] = zlog;
  1749.           az[i++] = " the system\n\t";
  1750.           az[i++] = zsys;
  1751.           az[i++] = "\n";
  1752.           az[i++] = "Execution requested was:\n\t";
  1753.           az[i++] = zQcmd;
  1754.           az[i++] = "\n";
  1755.  
  1756.           (void) fsysdep_mail (zmail, "Execution failed", i, az);
  1757.         }
  1758.     }
  1759.  
  1760.       ubuffree (zsys);
  1761.  
  1762.       return fret;
  1763.     }
  1764.  
  1765.   return TRUE;
  1766. }
  1767.