1 #ifndef lint 2 static char sccsid[] = "@(#)uuxqt.c 5.13 (Berkeley) 06/29/90"; 3 #endif 4 5 #include "uucp.h" 6 #include <sys/stat.h> 7 #ifdef NDIR 8 #include "ndir.h" 9 #else 10 #include <sys/dir.h> 11 #endif 12 #include <signal.h> 13 14 #define BADCHARS "&^|(`\\<>;\"{}\n'" 15 #define RECHECKTIME 60*10 /* 10 minutes */ 16 17 #define APPCMD(d) {\ 18 char *p;\ 19 for (p = d; *p != '\0';) *cmdp++ = *p++; *cmdp++ = ' '; *cmdp = '\0';} 20 21 extern char Filent[LLEN][NAMESIZE]; 22 23 /* 24 * uuxqt will execute commands set up by a uux command, 25 * usually from a remote machine - set by uucp. 26 */ 27 28 #define NCMDS 50 29 char *Cmds[NCMDS+1]; 30 int Notify[NCMDS+1]; 31 #define NT_YES 0 /* if should notify on execution */ 32 #define NT_ERR 1 /* if should notify if non-zero exit status (-z equivalent) */ 33 #define NT_NO 2 /* if should not notify ever (-n equivalent) */ 34 35 extern int Nfiles; 36 37 int TransferSucceeded = 1; 38 int notiok = 1; 39 int nonzero = 0; 40 41 struct timeb Now; 42 43 char PATH[MAXFULLNAME] = "PATH=/bin:/usr/bin"; 44 char UU_MACHINE[MAXFULLNAME]; 45 char Shell[MAXFULLNAME]; 46 char HOME[MAXFULLNAME]; 47 48 extern char **environ; 49 char *nenv[] = { 50 PATH, 51 Shell, 52 HOME, 53 UU_MACHINE, 54 0 55 }; 56 57 /* to remove restrictions from uuxqt 58 * define ALLOK 1 59 * 60 * to add allowable commands, add to the file CMDFILE 61 * A line of form "PATH=..." changes the search path 62 */ 63 main(argc, argv) 64 char *argv[]; 65 { 66 char xcmd[BUFSIZ*2]; 67 int argnok; 68 int notiflg; 69 char xfile[MAXFULLNAME], user[MAXFULLNAME], buf[BUFSIZ*2]; 70 char lbuf[MAXFULLNAME]; 71 char cfile[NAMESIZE], dfile[MAXFULLNAME]; 72 char file[NAMESIZE]; 73 char fin[MAXFULLNAME], sysout[NAMESIZE], fout[MAXFULLNAME]; 74 register FILE *xfp, *fp; 75 FILE *dfp; 76 char path[MAXFULLNAME]; 77 char cmd[BUFSIZ*2]; 78 char *cmdp, prm[1000], *ptr; 79 char *getprm(), *lastpart(); 80 int uid, ret, badfiles; 81 register int i; 82 int stcico = 0; 83 time_t xstart, xnow; 84 char retstat[30]; 85 extern char *optarg; 86 extern int optind; 87 88 strcpy(Progname, "uuxqt"); 89 uucpname(Myname); 90 strcpy(Rmtname, Myname); 91 92 umask(WFMASK); 93 Ofn = 1; 94 Ifn = 0; 95 while ((i = getopt(argc, argv, "x:S:")) != EOF) 96 switch(i) { 97 case 'x': 98 chkdebug(); 99 Debug = atoi(optarg); 100 if (Debug <= 0) 101 Debug = 1; 102 break; 103 case 'S': 104 Spool = optarg; 105 DEBUG(1, "Spool set to %s", Spool); 106 break; 107 case '?': 108 default: 109 fprintf(stderr, "unknown flag %s\n", argv[optind-1]); 110 break; 111 } 112 113 DEBUG(4, "\n\n** START **\n", CNULL); 114 if (subchdir(Spool) < 0) { 115 syslog(LOG_WARNING, "chdir(%s) failed: %m", Spool); 116 cleanup(1); 117 } 118 strcpy(Wrkdir, Spool); 119 uid = getuid(); 120 if (guinfo(uid, User, path) != SUCCESS) { 121 syslog(LOG_WARNING, "Can't find username for uid %d", uid); 122 DEBUG(1, "Using username", "uucp"); 123 strcpy(User, "uucp"); 124 } 125 setgid(getegid()); 126 setuid(geteuid()); 127 128 DEBUG(4, "User - %s\n", User); 129 if (ulockf(X_LOCK, X_LOCKTIME) != 0) 130 exit(0); 131 132 fp = fopen(CMDFILE, "r"); 133 if (fp == NULL) { 134 logent(CANTOPEN, CMDFILE); 135 Cmds[0] = "rmail"; 136 Cmds[1] = "rnews"; 137 Cmds[2] = "ruusend"; 138 Cmds[3] = NULL; 139 goto doprocess; 140 } 141 DEBUG(5, "%s opened\n", CMDFILE); 142 for (i=0; i<NCMDS && cfgets(xcmd, sizeof(xcmd), fp) != NULL; i++) { 143 int j; 144 /* strip trailing whitespace */ 145 for (j = strlen(xcmd)-1; j >= 0; --j) 146 if (xcmd[j] == '\n' || xcmd[j] == ' ' || xcmd[j] == '\t') 147 xcmd[j] = '\0'; 148 else 149 break; 150 /* look for imbedded whitespace */ 151 for (; j >= 0; --j) 152 if (xcmd[j] == '\n' || xcmd[j] == ' ' || xcmd[j] == '\t') 153 break; 154 /* skip this entry if it has embedded whitespace */ 155 /* This defends against a bad PATH=, for example */ 156 if (j >= 0) { 157 logent(xcmd, "BAD WHITESPACE"); 158 continue; 159 } 160 if (strncmp(xcmd, "PATH=", 5) == 0) { 161 strcpy(PATH, xcmd); 162 i--; /*kludge */ 163 continue; 164 } 165 DEBUG(5, "xcmd = %s\n", xcmd); 166 167 if ((ptr = index(xcmd, ',')) != NULL) { 168 *ptr++ = '\0'; 169 if (strncmp(ptr, "Err", 3) == SAME) 170 Notify[i] = NT_ERR; 171 else if (strcmp(ptr, "No") == SAME) 172 Notify[i] = NT_NO; 173 else 174 Notify[i] = NT_YES; 175 } else 176 Notify[i] = NT_YES; 177 if ((Cmds[i] = malloc((unsigned)(strlen(xcmd)+1))) == NULL) { 178 DEBUG(1, "MALLOC FAILED", CNULL); 179 break; 180 } 181 strcpy(Cmds[i], xcmd); 182 } 183 Cmds[i] = CNULL; 184 fclose(fp); 185 186 doprocess: 187 188 (void) sprintf(HOME, "HOME=%s", Spool); 189 (void) sprintf(Shell, "SHELL=%s", SHELL); 190 environ = nenv; /* force use if our environment */ 191 192 DEBUG(11,"path = %s\n", getenv("PATH")); 193 194 DEBUG(4, "process %s\n", CNULL); 195 196 time(&xstart); 197 while (gtxfile(xfile) > 0) { 198 /* if /etc/nologin exists, exit cleanly */ 199 #if defined(BSD4_2) || defined(USG) 200 if (access(NOLOGIN) == 0) { 201 #else !BSD4_2 && ! USG 202 ultouch(); 203 if (nologinflag) { 204 #endif !BSD4_2 && !USG 205 logent(NOLOGIN, "UUXQT SHUTDOWN"); 206 if (Debug) 207 logent("debugging", "continuing anyway"); 208 else 209 break; 210 } 211 DEBUG(4, "xfile - %s\n", xfile); 212 213 xfp = fopen(subfile(xfile), "r"); 214 if (xfp == NULL) { 215 syslog(LOG_ERR, "fopen(%s) failed: %m", subfile(xfile)); 216 cleanup(1); 217 } 218 219 /* initialize to default */ 220 strcpy(user, User); 221 strcpy(fin, DEVNULL); 222 strcpy(fout, DEVNULL); 223 strcpy(sysout, Myname); 224 badfiles = 0; 225 while (fgets(buf, BUFSIZ, xfp) != NULL) { 226 if(buf[0] != '\0' && buf[0] != '#' && 227 buf[1] != ' ' && buf[1] != '\0' && buf[1] != '\n') { 228 char *bnp, cfilename[BUFSIZ]; 229 DEBUG(4, "uuxqt: buf = %s\n", buf); 230 bnp = rindex(xfile, '/'); 231 sprintf(cfilename, "%s/%s", CORRUPT, 232 bnp ? bnp + 1 : xfile); 233 DEBUG(4, "uuxqt: move %s to ", xfile); 234 DEBUG(4, "%s\n", cfilename); 235 xmv(xfile, cfilename); 236 syslog(LOG_WARNING, "%s: X. FILE CORRUPTED", 237 xfile); 238 fclose(xfp); 239 goto doprocess; 240 } 241 switch (buf[0]) { 242 case X_USER: { 243 char ORmtname[MAXFULLNAME]; 244 strcpy(ORmtname, Rmtname); 245 sscanf(&buf[1], "%s %s", user, Rmtname); 246 sprintf(UU_MACHINE, "UU_MACHINE=%s", Rmtname); 247 if (strcmp(ORmtname, Rmtname) != 0) 248 logcls(); 249 break;} 250 case X_RETURNTO: 251 sscanf(&buf[1], "%s", user); 252 break; 253 case X_STDIN: 254 sscanf(&buf[1], "%s", fin); 255 i = expfile(fin); 256 /* rti!trt: do not check permissions of 257 * vanilla spool file */ 258 if (i != 0 259 && (chkpth("", "", fin) || anyread(fin) != 0)) 260 badfiles = 1; 261 break; 262 case X_STDOUT: 263 sscanf(&buf[1], "%s%s", fout, sysout); 264 sysout[MAXBASENAME] = '\0'; 265 /* rti!trt: do not check permissions of 266 * vanilla spool file. DO check permissions 267 * of writing on a non-vanilla file */ 268 i = 1; 269 if (fout[0] != '~' || prefix(sysout, Myname)) 270 i = expfile(fout); 271 if (i != 0 272 && (chkpth("", "", fout) 273 || chkperm(fout, (char *)1))) 274 badfiles = 1; 275 break; 276 case X_CMD: 277 strcpy(cmd, &buf[2]); 278 if (*(cmd + strlen(cmd) - 1) == '\n') 279 *(cmd + strlen(cmd) - 1) = '\0'; 280 break; 281 case X_NONOTI: 282 notiok = 0; 283 break; 284 case X_NONZERO: 285 nonzero = 1; 286 break; 287 default: 288 break; 289 } 290 } 291 292 fclose(xfp); 293 DEBUG(4, "fin - %s, ", fin); 294 DEBUG(4, "fout - %s, ", fout); 295 DEBUG(4, "sysout - %s, ", sysout); 296 DEBUG(4, "user - %s\n", user); 297 DEBUG(4, "cmd - %s\n", cmd); 298 299 /* command execution */ 300 if (strcmp(fout, DEVNULL) == SAME) 301 strcpy(dfile,DEVNULL); 302 else 303 gename(DATAPRE, sysout, 'O', dfile); 304 305 /* expand file names where necessary */ 306 expfile(dfile); 307 cmdp = buf; 308 ptr = cmd; 309 xcmd[0] = '\0'; 310 argnok = 0; 311 while ((ptr = getprm(ptr, prm)) != NULL) { 312 if (prm[0] == ';' || prm[0] == '^' 313 || prm[0] == '&' || prm[0] == '|') { 314 xcmd[0] = '\0'; 315 APPCMD(prm); 316 continue; 317 } 318 319 if ((argnok = argok(xcmd, prm)) != SUCCESS) 320 /* command not valid */ 321 break; 322 323 if (prm[0] == '~') 324 expfile(prm); 325 APPCMD(prm); 326 } 327 /* 328 * clean up trailing ' ' in command. 329 */ 330 if (cmdp > buf && cmdp[0] == '\0' && cmdp[-1] == ' ') 331 *--cmdp = '\0'; 332 if (argnok || badfiles) { 333 sprintf(lbuf, "%s XQT DENIED", user); 334 logent(cmd, lbuf); 335 DEBUG(4, "bad command %s\n", prm); 336 notify(user, Rmtname, cmd, "DENIED"); 337 goto rmfiles; 338 } 339 sprintf(lbuf, "%s XQT", user); 340 logent(buf, lbuf); 341 DEBUG(4, "cmd %s\n", buf); 342 343 mvxfiles(xfile); 344 if (subchdir(XQTDIR) < 0) { 345 syslog(LOG_ERR, "chdir(%s) failed: %m", XQTDIR); 346 cleanup(1); 347 } 348 ret = shio(buf, fin, dfile); 349 sprintf(retstat, "signal %d, exit %d", ret & 0377, 350 (ret>>8) & 0377); 351 if (strcmp(xcmd, "rmail") == SAME) 352 notiok = 0; 353 if (strcmp(xcmd, "rnews") == SAME) 354 nonzero = 1; 355 notiflg = chknotify(xcmd); 356 if (notiok && notiflg != NT_NO && 357 (ret != 0 || (!nonzero && notiflg == NT_YES))) 358 notify(user, Rmtname, cmd, retstat); 359 else if (ret != 0 && strcmp(xcmd, "rmail") == SAME) { 360 /* mail failed - return letter to sender */ 361 #ifdef DANGEROUS 362 /* NOT GUARANTEED SAFE!!! */ 363 if (!nonzero) 364 retosndr(user, Rmtname, fin); 365 #else 366 notify(user, Rmtname, cmd, retstat); 367 #endif 368 sprintf(buf, "%s (%s) from %s!%s", buf, retstat, Rmtname, user); 369 logent("MAIL FAIL", buf); 370 } 371 DEBUG(4, "exit cmd - %d\n", ret); 372 if (subchdir(Spool) < 0) { 373 syslog(LOG_ERR, "chdir(%s) failed: %m", Spool); 374 cleanup(1); 375 } 376 rmxfiles(xfile); 377 if (ret != 0) { 378 /* exit status not zero */ 379 dfp = fopen(subfile(dfile), "a"); 380 if (dfp == NULL) { 381 syslog(LOG_ERR, "fopen(%s) failed: %m", 382 subfile(dfile)); 383 cleanup(1); 384 } 385 fprintf(dfp, "exit status %d", ret); 386 fclose(dfp); 387 } 388 if (strcmp(fout, DEVNULL) != SAME) { 389 if (prefix(sysout, Myname)) { 390 xmv(dfile, fout); 391 chmod(fout, BASEMODE); 392 } else { 393 char *cp = rindex(user, '!'); 394 gename(CMDPRE, sysout, 'O', cfile); 395 fp = fopen(subfile(cfile), "w"); 396 if (fp == NULL) { 397 syslog(LOG_ERR, "fopen(%s) failed: %m", 398 subfile(cfile)); 399 cleanup(1); 400 } 401 fprintf(fp, "S %s %s %s - %s 0666\n", dfile, 402 fout, cp ? cp : user, lastpart(dfile)); 403 fclose(fp); 404 } 405 } 406 rmfiles: 407 xfp = fopen(subfile(xfile), "r"); 408 if (xfp == NULL) { 409 syslog(LOG_ERR, "fopen(%s) failed: %m", 410 subfile(xfile)); 411 cleanup(1); 412 } 413 while (fgets(buf, BUFSIZ, xfp) != NULL) { 414 if (buf[0] != X_RQDFILE) 415 continue; 416 sscanf(&buf[1], "%s", file); 417 unlink(subfile(file)); 418 } 419 unlink(subfile(xfile)); 420 fclose(xfp); 421 422 /* rescan X. for new work every RECHECKTIME seconds */ 423 time(&xnow); 424 if (xnow > (xstart + RECHECKTIME)) { 425 extern int Nfiles; 426 Nfiles = 0; /*force rescan for new work */ 427 } 428 xstart = xnow; 429 } 430 431 if (stcico) 432 xuucico(""); 433 cleanup(0); 434 } 435 436 437 cleanup(code) 438 int code; 439 { 440 logcls(); 441 rmlock(CNULL); 442 #ifdef VMS 443 /* 444 * Since we run as a BATCH job we must wait for all processes to 445 * to finish 446 */ 447 while(wait(0) != -1) 448 ; 449 #endif VMS 450 exit(code); 451 } 452 453 454 /* 455 * get a file to execute 456 * 457 * return codes: 0 - no file | 1 - file to execute 458 */ 459 460 gtxfile(file) 461 register char *file; 462 { 463 char pre[3]; 464 register int rechecked, i; 465 time_t ystrdy; /* yesterday */ 466 struct stat stbuf; /* for X file age */ 467 468 pre[0] = XQTPRE; 469 pre[1] = '.'; 470 pre[2] = '\0'; 471 rechecked = 0; 472 retry: 473 if (Nfiles-- <= 0) { 474 Nfiles = 0; 475 if (rechecked) 476 return 0; 477 rechecked = 1; 478 DEBUG(4, "iswrk\n", CNULL); 479 return iswrk(file, "get", Spool, pre); 480 } 481 sprintf(file, "%s/%s", Spool, Filent[0]); 482 for (i=0; i<Nfiles;i++) 483 strcpy(Filent[i], Filent[i+1]); 484 485 DEBUG(4, "file - %s\n", file); 486 /* skip spurious subdirectories */ 487 if (strcmp(pre, file) == SAME) 488 goto retry; 489 if (gotfiles(file)) 490 return 1; 491 /* check for old X. file with no work files and remove them. */ 492 if (Nfiles > LLEN/2) { 493 time(&ystrdy); 494 ystrdy -= (4 * 3600L); /* 4 hours ago */ 495 DEBUG(4, "gtxfile: Nfiles > LLEN/2\n", CNULL); 496 while (Nfiles-- > 0) { 497 sprintf(file, "%s/%s", Spool, Filent[0]); 498 for (i=0; i<Nfiles; i++) 499 strcpy(Filent[i], Filent[i+1]); 500 501 if (gotfiles(file)) 502 return 1; 503 if (stat(subfile(file), &stbuf) == 0) 504 if (stbuf.st_mtime <= ystrdy) { 505 char *bnp, cfilename[NAMESIZE]; 506 DEBUG(4, "gtxfile: move %s to CORRUPT \n", file); 507 bnp = rindex(file, '/'); 508 sprintf(cfilename, "%s/%s", CORRUPT, 509 bnp ? bnp + 1 : file); 510 xmv(file, cfilename); 511 syslog(LOG_WARNING, "%s: X. FILE MISSING FILES", file); 512 } 513 } 514 Nfiles = 0; 515 DEBUG(4, "iswrk\n", CNULL); 516 if (!iswrk(file, "get", Spool, pre)) 517 return 0; 518 } 519 goto retry; 520 } 521 522 /* 523 * check for needed files 524 * 525 * return codes: 0 - not ready | 1 - all files ready 526 */ 527 528 gotfiles(file) 529 register char *file; 530 { 531 struct stat stbuf; 532 register FILE *fp; 533 char buf[BUFSIZ], rqfile[MAXFULLNAME]; 534 535 fp = fopen(subfile(file), "r"); 536 if (fp == NULL) 537 return 0; 538 539 while (fgets(buf, BUFSIZ, fp) != NULL) { 540 DEBUG(4, "%s\n", buf); 541 if (buf[0] != X_RQDFILE) 542 continue; 543 sscanf(&buf[1], "%s", rqfile); 544 expfile(rqfile); 545 if (stat(subfile(rqfile), &stbuf) == -1) { 546 fclose(fp); 547 return 0; 548 } 549 } 550 551 fclose(fp); 552 return 1; 553 } 554 555 556 /* 557 * remove execute files to x-directory 558 */ 559 560 rmxfiles(xfile) 561 register char *xfile; 562 { 563 register FILE *fp; 564 char buf[BUFSIZ], file[NAMESIZE], tfile[NAMESIZE]; 565 char tfull[MAXFULLNAME]; 566 567 if((fp = fopen(subfile(xfile), "r")) == NULL) 568 return; 569 570 while (fgets(buf, BUFSIZ, fp) != NULL) { 571 if (buf[0] != X_RQDFILE) 572 continue; 573 if (sscanf(&buf[1], "%s%s", file, tfile) < 2) 574 continue; 575 sprintf(tfull, "%s/%s", XQTDIR, tfile); 576 unlink(subfile(tfull)); 577 } 578 fclose(fp); 579 return; 580 } 581 582 583 /* 584 * move execute files to x-directory 585 */ 586 587 mvxfiles(xfile) 588 char *xfile; 589 { 590 register FILE *fp; 591 char buf[BUFSIZ], ffile[MAXFULLNAME], tfile[NAMESIZE]; 592 char tfull[MAXFULLNAME]; 593 594 if((fp = fopen(subfile(xfile), "r")) == NULL) 595 return; 596 597 while (fgets(buf, BUFSIZ, fp) != NULL) { 598 if (buf[0] != X_RQDFILE) 599 continue; 600 if (sscanf(&buf[1], "%s%s", ffile, tfile) < 2) 601 continue; 602 expfile(ffile); 603 sprintf(tfull, "%s/%s", XQTDIR, tfile); 604 unlink(subfile(tfull)); 605 if (xmv(ffile, tfull) != 0) { 606 syslog(LOG_WARNING, "xmv(%s,%s) failed: %m", 607 ffile, tfull); 608 cleanup(1); 609 } 610 } 611 fclose(fp); 612 } 613 614 /* 615 * check for valid command/argument 616 * *NOTE - side effect is to set xc to the command to be executed. 617 * 618 * return 0 - ok | 1 nok 619 */ 620 621 argok(xc, cmd) 622 register char *xc, *cmd; 623 { 624 register char **ptr; 625 626 #ifndef ALLOK 627 if (strpbrk(cmd, BADCHARS) != NULL) { 628 DEBUG(1,"MAGIC CHARACTER FOUND\n", CNULL); 629 logent(cmd, "NASTY MAGIC CHARACTER FOUND"); 630 return FAIL; 631 } 632 #endif !ALLOK 633 634 if (xc[0] != '\0') 635 return SUCCESS; 636 637 #ifndef ALLOK 638 ptr = Cmds; 639 DEBUG(9, "Compare %s and\n", cmd); 640 while(*ptr != NULL) { 641 DEBUG(9, "\t%s\n", *ptr); 642 if (strcmp(cmd, *ptr) == SAME) 643 break; 644 ptr++; 645 } 646 if (*ptr == NULL) { 647 DEBUG(1,"COMMAND NOT FOUND\n", CNULL); 648 return FAIL; 649 } 650 #endif 651 strcpy(xc, cmd); 652 DEBUG(9, "MATCHED %s\n", xc); 653 return SUCCESS; 654 } 655 656 657 /* 658 * if notification should be sent for successful execution of cmd 659 * 660 * return NT_YES - do notification 661 * NT_ERR - do notification if exit status != 0 662 * NT_NO - don't do notification ever 663 */ 664 665 chknotify(cmd) 666 char *cmd; 667 { 668 register char **ptr; 669 register int *nptr; 670 671 ptr = Cmds; 672 nptr = Notify; 673 while (*ptr != NULL) { 674 if (strcmp(cmd, *ptr) == SAME) 675 return *nptr; 676 ptr++; 677 nptr++; 678 } 679 return NT_YES; /* "shouldn't happen" */ 680 } 681 682 683 684 /* 685 * send mail to user giving execution results 686 */ 687 688 notify(user, rmt, cmd, str) 689 char *user, *rmt, *cmd, *str; 690 { 691 char text[BUFSIZ*2]; 692 char ruser[MAXFULLNAME]; 693 694 if (strpbrk(user, BADCHARS) != NULL) { 695 char lbuf[MAXFULLNAME]; 696 sprintf(lbuf, "%s INVALID CHARACTER IN USERNAME", user); 697 logent(cmd, lbuf); 698 strcpy(user, "postmaster"); 699 } 700 sprintf(text, "uuxqt cmd (%s) status (%s)", cmd, str); 701 if (prefix(rmt, Myname)) 702 strcpy(ruser, user); 703 else 704 sprintf(ruser, "%s!%s", rmt, user); 705 mailst(ruser, text, CNULL); 706 } 707 708 /* 709 * return mail to sender 710 * 711 */ 712 retosndr(user, rmt, file) 713 char *user, *rmt, *file; 714 { 715 char ruser[MAXFULLNAME]; 716 717 if (strpbrk(user, BADCHARS) != NULL) { 718 char lbuf[MAXFULLNAME]; 719 sprintf(lbuf, "%s INVALID CHARACTER IN USERNAME", user); 720 logent(file, lbuf); 721 strcpy(user, "postmaster"); 722 } 723 if (strcmp(rmt, Myname) == SAME) 724 strcpy(ruser, user); 725 else 726 sprintf(ruser, "%s!%s", rmt, user); 727 728 if (anyread(file) == 0) 729 mailst(ruser, "Mail failed. Letter returned to sender.\n", file); 730 else 731 mailst(ruser, "Mail failed. Letter returned to sender.\n", CNULL); 732 return; 733 } 734 735 /* 736 * execute shell of command with fi and fo as standard input/output 737 */ 738 739 shio(cmd, fi, fo) 740 char *cmd, *fi, *fo; 741 { 742 int status, f; 743 int pid, ret; 744 char *args[256]; 745 extern int errno; 746 747 if (fi == NULL) 748 fi = DEVNULL; 749 if (fo == NULL) 750 fo = DEVNULL; 751 752 getargs(cmd, args, 256); 753 DEBUG(3, "shio - %s\n", cmd); 754 #ifdef SIGCHLD 755 signal(SIGCHLD, SIG_IGN); 756 #endif SIGCHLD 757 if ((pid = fork()) == 0) { 758 signal(SIGINT, SIG_IGN); 759 signal(SIGHUP, SIG_IGN); 760 signal(SIGQUIT, SIG_IGN); 761 close(Ifn); 762 close(Ofn); 763 close(0); 764 setuid(getuid()); 765 f = open(subfile(fi), 0); 766 if (f != 0) { 767 logent(fi, "CAN'T READ"); 768 exit(-errno); 769 } 770 close(1); 771 f = creat(subfile(fo), 0666); 772 if (f != 1) { 773 logent(fo, "CAN'T WRITE"); 774 exit(-errno); 775 } 776 execvp(args[0], args); 777 exit(100+errno); 778 } 779 while ((ret = wait(&status)) != pid && ret != -1) 780 ; 781 DEBUG(3, "status %d\n", status); 782 return status; 783 } 784