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