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