|
|
1.1 ! root 1: /* @(#)uuxqt.c 1.13 */ ! 2: ! 3: #include "uucp.h" ! 4: VERSION(@(#)uuxqt.c 1.13); ! 5: ! 6: /* ! 7: * execute commands set up by a uux command, ! 8: * usually from a remote machine - set by uucp. ! 9: */ ! 10: ! 11: #ifndef V7 ! 12: #define LOGNAME "LOGNAME=uucp" ! 13: #else ! 14: #define LOGNAME "USER=uucp" ! 15: #endif ! 16: ! 17: #define C_COMMAND 1 ! 18: #define C_FILE 2 ! 19: #define BAD_COMMAND 1 ! 20: #define BAD_FILE 2 ! 21: #define USAGE "[-xDEGUG] [-sSYSTEM]" ! 22: #define APPCMD(p) {(void) strcat(_Cmd, p); (void) strcat(_Cmd, " ");} ! 23: #define APPCMDNS(p) {(void) strcat(_Cmd, p);} ! 24: ! 25: char _Xfile[MAXFULLNAME]; ! 26: char _Cmd[2 * BUFSIZ]; /* build up command buffer */ ! 27: int _CargType; /* argument type of next C argument */ ! 28: ! 29: static void retosndr(), uucpst(); ! 30: static int chkFile(); ! 31: static int doFileChk(); ! 32: ! 33: main(argc, argv, envp) ! 34: char *argv[], *envp[]; ! 35: { ! 36: DIR *fp1; ! 37: int ret, maxnumb; ! 38: char dirname[MAXFULLNAME], lockname[MAXFULLNAME]; ! 39: extern onintr(); ! 40: FILE *fp; ! 41: ! 42: (void) signal(SIGILL, onintr); ! 43: (void) signal(SIGTRAP, onintr); ! 44: (void) signal(SIGIOT, onintr); ! 45: (void) signal(SIGEMT, onintr); ! 46: (void) signal(SIGFPE, onintr); ! 47: (void) signal(SIGBUS, onintr); ! 48: (void) signal(SIGSEGV, onintr); ! 49: (void) signal(SIGSYS, onintr); ! 50: (void) signal(SIGPIPE, onintr); ! 51: (void) signal(SIGTERM, SIG_IGN); ! 52: ! 53: /* choose LOGFILE */ ! 54: (void) strcpy(Logfile, LOGUUXQT); ! 55: ! 56: /* ! 57: * get local system name ! 58: */ ! 59: Env = envp; ! 60: Nstat.t_qtime = time((time_t *)0); ! 61: (void) strcpy(Progname, "uuxqt"); ! 62: Pchar = 'Q'; ! 63: uucpname(Myname); ! 64: Ofn = 1; ! 65: Ifn = 0; ! 66: dirname[0] = NULLCHAR; ! 67: while ((ret = getopt(argc, argv, "s:x:")) != EOF) { ! 68: switch(ret){ ! 69: ! 70: /* ! 71: * debugging level ! 72: */ ! 73: case 'x': ! 74: Debug = atoi(optarg); ! 75: if (Debug <= 0) ! 76: Debug = 1; ! 77: break; ! 78: ! 79: case 's': ! 80: /* fake out uuxqt and use the argument as if ! 81: * it were the spool directory for the purpose ! 82: * of determining what subdirectories to search ! 83: * EX: mkdir /tmp/foo; touch /tmp/foo/{baz,gorp} ! 84: * uuxqt -s/tmp/foo ! 85: * this will cause uuxqt to only run on the sub ! 86: * baz and gorp in the Spool directory. Trust me. ! 87: */ ! 88: (void) strncpy(dirname, optarg, MAXFULLNAME); ! 89: break; ! 90: ! 91: default: ! 92: (void) fprintf(stderr, "\tusage: %s %s\n", ! 93: Progname, USAGE); ! 94: exit(1); ! 95: } ! 96: } ! 97: if (argc != optind) { ! 98: (void) fprintf(stderr, "\tusage: %s %s\n", Progname, USAGE); ! 99: exit(1); ! 100: } ! 101: ! 102: DEBUG(4, "\n\n** START **\n", ""); ! 103: fp = fopen(LMTUUXQT, "r"); ! 104: if (fp == NULL) { ! 105: DEBUG(1, "No limitfile - %s\n", LMTUUXQT); ! 106: } else { ! 107: (void) fscanf(fp, "%d", &maxnumb); ! 108: (void) fclose(fp); ! 109: DEBUG(4, "Uuxqt limit %d -- ", maxnumb); ! 110: ret = cuantos(X_LOCKPRE, X_LOCKDIR); ! 111: DEBUG(4, "found %d -- ", ret); ! 112: if (maxnumb >= 0 && ret >= maxnumb) { ! 113: DEBUG(4, "exiting\n", maxnumb); ! 114: exit(0); ! 115: } ! 116: DEBUG(4, "continuing\n", maxnumb); ! 117: } ! 118: ! 119: /* ! 120: * determine user who started uuxqt (in principle) ! 121: */ ! 122: strcpy(User, "uucp"); /* in case all else fails (can't happen) */ ! 123: Uid = getuid(); ! 124: Euid = geteuid(); /* this should be UUCPUID */ ! 125: guinfo(Euid, User); ! 126: setuucp(User); ! 127: DEBUG(4, "User - %s\n", User); ! 128: guinfo(Uid, Loginuser); ! 129: ! 130: DEBUG(4, "process %s\n", ""); ! 131: ! 132: fp1 = opendir(Spool); ! 133: ASSERT(fp1 != NULL, Ct_OPEN, Spool, errno); ! 134: ! 135: if (dirname[0] != NULLCHAR) { ! 136: (void) sprintf(lockname, "%s.%s", X_LOCK, dirname); ! 137: if (ulockf(lockname, (time_t) X_LOCKTIME) == 0) { ! 138: xprocess(dirname); ! 139: rmlock(CNULL); ! 140: } ! 141: } ! 142: else { ! 143: while (gdirf(fp1, dirname, Spool) == TRUE) { ! 144: (void) sprintf(lockname, "%s.%s", X_LOCK, dirname); ! 145: if (ulockf(lockname, (time_t) X_LOCKTIME) != 0) ! 146: continue; ! 147: xprocess(dirname); ! 148: rmlock(CNULL); ! 149: } ! 150: } ! 151: ! 152: closedir(fp1); ! 153: cleanup(0); ! 154: } ! 155: ! 156: cleanup(code) ! 157: int code; ! 158: { ! 159: rmlock(CNULL); ! 160: exit(code); ! 161: } ! 162: ! 163: /* ! 164: * catch signal then cleanup and exit ! 165: */ ! 166: onintr(inter) ! 167: register int inter; ! 168: { ! 169: char str[30]; ! 170: (void) signal(inter, SIG_IGN); ! 171: (void) sprintf(str, "QSIGNAL %d", inter); ! 172: logent(str, "QCAUGHT"); ! 173: cleanup(-inter); ! 174: } ! 175: ! 176: #define XCACHESIZE (4096 / (MAXBASENAME + 1)) ! 177: static char xcache[XCACHESIZE][MAXBASENAME + 1]; /* cache for X. files */ ! 178: static int xcachesize = 0; /* how many left? */ ! 179: ! 180: /* ! 181: * stash an X. file so we can process them sorted first by grade, then by ! 182: * sequence number ! 183: */ ! 184: static int ! 185: xstash(file) ! 186: char *file; ! 187: { ! 188: DEBUG(4, "stashing %s\n", file); ! 189: strcpy(xcache[xcachesize++], file); ! 190: } ! 191: ! 192: /* ! 193: * xcompare ! 194: * comparison routine for for qsort() ! 195: */ ! 196: static int ! 197: xcompare(f1, f2) ! 198: register char *f1, *f2; ! 199: { ! 200: /* assumes file name is X.siteG1234 */ ! 201: /* use -strcmp() so that xstash is sorted largest first */ ! 202: /* pull files out of the stash from largest index to smallest */ ! 203: ! 204: return(-strcmp(f1 + strlen(f1) - 5, f2 + strlen(f2) - 5)); ! 205: } ! 206: ! 207: /* ! 208: * xsort ! 209: * sort the cached X. files, ! 210: * largest (last) to smallest (next to be processed) ! 211: */ ! 212: static int ! 213: xsort() ! 214: { ! 215: DEBUG(4, "xsort: first was %s\n", xcache[0]); ! 216: qsort(xcache, xcachesize, MAXBASENAME + 1, xcompare); ! 217: DEBUG(4, "xsort: first is %s\n", xcache[0]); ! 218: } ! 219: ! 220: /* ! 221: * xget ! 222: * return smallest X. file in cache ! 223: * (hint: it's the last one in the array) ! 224: */ ! 225: static int ! 226: xget(file) ! 227: char *file; ! 228: { ! 229: if (xcachesize > 0) { ! 230: strcpy(file, xcache[--xcachesize]); ! 231: DEBUG(4, "xget: returning %s\n", file); ! 232: return(1); ! 233: } else { ! 234: /* avoid horror of xcachesize < 0 (impossible, you say?)! */ ! 235: xcachesize = 0; ! 236: return(0); ! 237: } ! 238: } ! 239: ! 240: ! 241: /* ! 242: * get a file to execute ! 243: * file -> a read to return filename in ! 244: * returns: ! 245: * 0 -> no file ! 246: * 1 -> file to execute ! 247: */ ! 248: gt_Xfile(file, dir) ! 249: register char *file, *dir; ! 250: { ! 251: DIR *pdir; ! 252: ! 253: if (xcachesize == 0) { ! 254: /* open spool directory */ ! 255: pdir = opendir(dir); ! 256: /* this was an ASSERT, but it's not so bad as all that */ ! 257: if (pdir == NULL) ! 258: return(0); ! 259: ! 260: /* scan spool directory looking for X. files to stash */ ! 261: while (gnamef(pdir, file) == TRUE) { ! 262: DEBUG(4, "gt_Xfile got %s\n", file); ! 263: /* look for x prefix */ ! 264: if (file[0] != XQTPRE) ! 265: continue; ! 266: ! 267: /* check to see if required files have arrived */ ! 268: if (gotfiles(file)) ! 269: xstash(file); ! 270: if (xcachesize >= XCACHESIZE) ! 271: break; ! 272: } ! 273: closedir(pdir); ! 274: xsort(); ! 275: } ! 276: ! 277: return(xget(file)); ! 278: } ! 279: ! 280: /* ! 281: * check for needed files ! 282: * file -> name of file to check ! 283: * return: ! 284: * 0 -> not ready ! 285: * 1 -> all files ready ! 286: */ ! 287: gotfiles(file) ! 288: register char *file; ! 289: { ! 290: register FILE *fp; ! 291: struct stat stbuf; ! 292: char buf[BUFSIZ], rqfile[MAXFULLNAME]; ! 293: ! 294: fp = fopen(file, "r"); ! 295: if (fp == NULL) ! 296: return(FALSE); ! 297: ! 298: while (fgets(buf, BUFSIZ, fp) != NULL) { ! 299: DEBUG(4, "%s\n", buf); ! 300: ! 301: /* ! 302: * look at required files ! 303: */ ! 304: if (buf[0] != X_RQDFILE) ! 305: continue; ! 306: (void) sscanf(&buf[1], "%s", rqfile); ! 307: ! 308: /* ! 309: * expand file name ! 310: */ ! 311: expfile(rqfile); ! 312: ! 313: /* ! 314: * see if file exists ! 315: */ ! 316: if (stat(rqfile, &stbuf) == -1) { ! 317: fclose(fp); ! 318: return(FALSE); ! 319: } ! 320: } ! 321: ! 322: fclose(fp); ! 323: return(TRUE); ! 324: } ! 325: ! 326: /* ! 327: * remove execute files to x-directory ! 328: * ! 329: * _Xfile is a global ! 330: * return: ! 331: * none ! 332: */ ! 333: rm_Xfiles() ! 334: { ! 335: register FILE *fp; ! 336: char buf[BUFSIZ], file[NAMESIZE], tfile[NAMESIZE]; ! 337: char tfull[MAXFULLNAME]; ! 338: ! 339: if ((fp = fopen(_Xfile, "r")) == NULL) { ! 340: DEBUG(4, "rm_Xfiles: can't read %s\n", _Xfile); ! 341: return; ! 342: } ! 343: ! 344: /* ! 345: * (void) unlink each file belonging to job ! 346: */ ! 347: while (fgets(buf, BUFSIZ, fp) != NULL) { ! 348: if (buf[0] != X_RQDFILE) ! 349: continue; ! 350: if (sscanf(&buf[1], "%s%s", file, tfile) < 2) ! 351: continue; ! 352: (void) sprintf(tfull, "%s/%s", XQTDIR, tfile); ! 353: (void) unlink(tfull); ! 354: } ! 355: fclose(fp); ! 356: return; ! 357: } ! 358: ! 359: /* ! 360: * move execute files to x-directory ! 361: * _Xfile is a global ! 362: * return: ! 363: * none ! 364: */ ! 365: mv_Xfiles() ! 366: { ! 367: register FILE *fp; ! 368: char buf[BUFSIZ], ffile[MAXNAMESIZE], tfile[MAXNAMESIZE]; ! 369: char tfull[MAXNAMESIZE]; ! 370: ! 371: if ((fp = fopen(_Xfile, "r")) == NULL) { ! 372: DEBUG(4, "mv_Xfiles: can't read %s\n", _Xfile); ! 373: return; ! 374: } ! 375: ! 376: while (fgets(buf, BUFSIZ, fp) != NULL) { ! 377: if (buf[0] != X_RQDFILE) ! 378: continue; ! 379: if (sscanf(&buf[1], "%s%s", ffile, tfile) < 2) ! 380: continue; ! 381: ! 382: /* ! 383: * expand file names and move to ! 384: * execute directory ! 385: * Make files readable by anyone ! 386: */ ! 387: expfile(ffile); ! 388: (void) sprintf(tfull, "%s/%s", XQTDIR, tfile); ! 389: ! 390: ASSERT(xmv(ffile, tfull) == 0, "XMV ERROR", tfull, errno); ! 391: chmod(tfull, 0666); ! 392: } ! 393: fclose(fp); ! 394: return; ! 395: } ! 396: ! 397: /* ! 398: * undo what mv_Xfiles did ! 399: * _Xfile is a global ! 400: * return: ! 401: * none ! 402: */ ! 403: unmv_Xfiles() ! 404: { ! 405: FILE *fp; ! 406: char buf[BUFSIZ], ffile[MAXNAMESIZE], tfile[MAXNAMESIZE]; ! 407: char tfull[MAXNAMESIZE], ffull[MAXNAMESIZE], xfull[MAXNAMESIZE]; ! 408: ! 409: (void) sprintf(xfull, "%s/%s", RemSpool, _Xfile); ! 410: if ((fp = fopen(xfull, "r")) == NULL) { ! 411: DEBUG(4, "unmv_Xfiles: can't read %s\n", xfull); ! 412: return; ! 413: } ! 414: ! 415: while (fgets(buf, BUFSIZ, fp) != NULL) { ! 416: if (buf[0] != X_RQDFILE) ! 417: continue; ! 418: if (sscanf(&buf[1], "%s%s", ffile, tfile) < 2) ! 419: continue; ! 420: ! 421: /* ! 422: * expand file names and move back to ! 423: * spool directory ! 424: * Make files readable by uucp ! 425: */ ! 426: (void) sprintf(ffull, "%s/%s", RemSpool, ffile); ! 427: /* i know we're in .Xqtdir, but what the hell ... */ ! 428: (void) sprintf(tfull, "%s/%s", XQTDIR, tfile); ! 429: ! 430: ASSERT(xmv(tfull, ffull) == 0, "XMV ERROR", ffull, errno); ! 431: (void) chmod(ffull, 0600); ! 432: } ! 433: fclose(fp); ! 434: return; ! 435: } ! 436: ! 437: /* chkpart - checks the string (ptr points to it) for illegal command or ! 438: * file permission restriction - called recursively ! 439: * to check lines that have `string` or (string) form. ! 440: * _Cmd is the buffer where the command is built up. ! 441: * _CargType is the type of the next C line argument ! 442: * ! 443: * Return: ! 444: * BAD_FILE if a non permitted file is found ! 445: * BAD_COMMAND if non permitted command is found ! 446: * 0 - ok ! 447: */ ! 448: ! 449: static ! 450: int ! 451: chkpart(ptr) ! 452: char *ptr; ! 453: { ! 454: char prm[BUFSIZ], xcmd[BUFSIZ]; ! 455: char savechar[2]; /* one character string with NULL */ ! 456: int ret; ! 457: ! 458: /* _CargType is the arg type for this iteration (cmd or file) */ ! 459: while ((ptr = getprm(ptr, prm)) != NULL) { ! 460: DEBUG(4, "prm='%s'\n", prm); ! 461: switch(*prm) { ! 462: ! 463: /* End of command delimiter */ ! 464: case ';': ! 465: case '^': ! 466: case '&': ! 467: case '|': ! 468: APPCMDNS(prm); ! 469: _CargType = C_COMMAND; ! 470: continue; ! 471: ! 472: /* Other delimiter */ ! 473: case '>': ! 474: case '<': ! 475: APPCMDNS(prm); ! 476: continue; ! 477: ! 478: case '`': /* don't allow any ` commands */ ! 479: case '\\': ! 480: return(BAD_COMMAND); ! 481: ! 482: /* Some allowable quoted string */ ! 483: case '(': ! 484: case '"': ! 485: case '\'': ! 486: /* must recurse */ ! 487: savechar[0] = *prm; ! 488: savechar[1] = NULLCHAR; ! 489: APPCMD(savechar); /* put first char into command */ ! 490: savechar[0] = prm[strlen(prm)-1]; ! 491: prm[strlen(prm)-1] = NULLCHAR; /* delete last character */ ! 492: ! 493: /* recurse */ ! 494: if (ret = chkpart(prm+1)) { /* failed */ ! 495: return(ret); ! 496: } ! 497: APPCMD(savechar); /* put last char into command */ ! 498: continue; ! 499: ! 500: default: /* check for command or file */ ! 501: break; ! 502: } ! 503: ! 504: if (_CargType == C_COMMAND) { ! 505: if ( (cmdOK(prm, xcmd)) == FALSE) ! 506: return(BAD_COMMAND); ! 507: APPCMD(xcmd); ! 508: _CargType = C_FILE; ! 509: continue; ! 510: } ! 511: ! 512: #if NOTDEF ! 513: if (chkFile(prm)) ! 514: return(BAD_FILE); ! 515: else ! 516: #endif ! 517: APPCMD(prm); ! 518: } ! 519: return(0); /* all ok */ ! 520: } ! 521: ! 522: /* chkFile - try to find a path name in the prm. ! 523: * if found, check it for access permission. ! 524: * ! 525: * check file access permissions ! 526: * if ! in name assume that access on local machine is required ! 527: * ! 528: * Return: ! 529: * BAD_FILE - not permitted ! 530: * 0 - ok ! 531: */ ! 532: ! 533: static ! 534: int ! 535: chkFile(prm) ! 536: char *prm; ! 537: { ! 538: char *p, buf[BUFSIZ]; ! 539: ! 540: (void) strcpy(buf, prm); ! 541: switch(*prm) { ! 542: case '~': ! 543: case '/': ! 544: if (doFileChk(buf)) ! 545: return(BAD_FILE); ! 546: else ! 547: return(0); ! 548: /*NOTREACHED*/ ! 549: ! 550: case '!': ! 551: return(chkFile(buf+1)); ! 552: /*NOTREACHED*/ ! 553: ! 554: default: ! 555: break; ! 556: } ! 557: ! 558: if ( (p =strchr(buf, '!')) == NULL) { /* no "!", look for "/" */ ! 559: if ( (p = strchr(buf, '/')) == NULL) { /* ok */ ! 560: return(0); ! 561: } ! 562: if (doFileChk(p)) ! 563: return(BAD_FILE); ! 564: else ! 565: return(0); ! 566: } ! 567: ! 568: /* there is at least one '!' - see if it refers to my system */ ! 569: if (PREFIX(Myname, buf)) /* my system so far, check further */ ! 570: return(chkFile(p+1)); /* recurse with thing after '!' */ ! 571: else /* not my system - not my worry */ ! 572: return(0); ! 573: } ! 574: ! 575: /* doFileChk - check file path permission ! 576: * NOTE: file is assumed to be a buffer that expfile an ! 577: * write into. ! 578: * Return ! 579: * BAD_FILE - not allowed ! 580: * 0 - ok ! 581: */ ! 582: ! 583: static ! 584: int ! 585: doFileChk(file) ! 586: char *file; ! 587: { ! 588: expfile(file); ! 589: DEBUG(7, "fullname: %s\n", file); ! 590: if (chkpth(file, CK_READ) == FAIL ! 591: || chkpth(file, CK_WRITE) == FAIL ) ! 592: return(BAD_FILE); ! 593: else ! 594: return(0); ! 595: } ! 596: ! 597: ! 598: /* ! 599: * return stuff to user ! 600: * user -> user to notify ! 601: * rmt -> system name where user resides ! 602: * file -> file to return (generally contains input) ! 603: * cmd -> command that was to be executed ! 604: * buf -> user friendly face saving uplifting edifying missive ! 605: * errfile -> stderr output from cmd xeqn ! 606: * return: ! 607: * none ! 608: */ ! 609: static void ! 610: retosndr(user, rmt, file, cmd, buf, errfile) ! 611: char *user, *rmt, *file, *cmd, *buf, *errfile; ! 612: { ! 613: char ruser[BUFSIZ], msg[BUFSIZ]; ! 614: ! 615: (void) sprintf(msg, ! 616: "remote execution\t[uucp job %s (%s)]\n\t%s\n%s\n", ! 617: &_Xfile[2], timeStamp(), cmd, buf); ! 618: ! 619: DEBUG(5, "retosndr %s, ", msg); ! 620: ! 621: if (EQUALS(rmt, Myname)) ! 622: (void) strcpy(ruser, user); ! 623: else ! 624: (void) sprintf(ruser, "%s!%s", rmt, user); ! 625: ! 626: mailst(ruser, msg, file, errfile); ! 627: } ! 628: ! 629: ! 630: /* ! 631: * uucpst - send the status message back using a uucp command ! 632: * NOTE - this would be better if the file could be appended. ! 633: * - suggestion for the future - if rmail would take a file name ! 634: * instead of just person, then that facility would be correct, ! 635: * and this routine would not be needed. ! 636: */ ! 637: ! 638: static ! 639: void ! 640: uucpst(rmt, tofile, errfile, cmd, buf) ! 641: char *rmt, *tofile, *errfile, *cmd, *buf; ! 642: { ! 643: char arg[MAXFULLNAME], tmp[MAXBASENAME], msg[BUFSIZ]; ! 644: int ret; ! 645: FILE *fp, *fi; ! 646: ! 647: (void) sprintf(msg, ! 648: "uucp job %s (%s) remote execution\n\t%s\n%s\n", ! 649: &_Xfile[2], timeStamp(), cmd, buf); ! 650: ! 651: (void) sprintf(tmp, "%s.%d", rmt, getpid()); ! 652: if ((fp = fopen(tmp, "w")) == NULL) ! 653: return; ! 654: (void) fprintf(fp, "%s\n", msg); ! 655: ! 656: /* copy back stderr */ ! 657: if (*errfile != '\0' && NOTEMPTY(errfile) ! 658: && (fi = fopen(errfile, "r")) != NULL) { ! 659: fputs("\n\t===== stderr was =====\n", fp); ! 660: if (xfappend(fi, fp) != SUCCESS) ! 661: fputs("\n\t===== well, i tried =====\n", fp); ! 662: (void) fclose(fi); ! 663: fputc('\n', fp); ! 664: } ! 665: ! 666: ! 667: (void) fclose(fp); ! 668: (void) sprintf(arg, "%s!%s", rmt, tofile); ! 669: ! 670: /* start uucp */ ! 671: ! 672: if (vfork() == 0) { ! 673: (void) close(0); ! 674: (void) close(1); ! 675: (void) close(2); ! 676: (void) open("/dev/null", 2); ! 677: (void) open("/dev/null", 2); ! 678: (void) open("/dev/null", 2); ! 679: (void) signal(SIGINT, SIG_IGN); ! 680: (void) signal(SIGHUP, SIG_IGN); ! 681: (void) signal(SIGQUIT, SIG_IGN); ! 682: closelog(); ! 683: ! 684: (void) execle("/usr/bin/uucp", "UUCP", ! 685: "-C", tmp, arg, 0, Env); ! 686: (void) _exit(100); ! 687: } ! 688: ! 689: (void) wait(&ret); ! 690: (void) unlink(tmp); ! 691: return; ! 692: } ! 693: ! 694: static ! 695: xprocess(dirname) ! 696: char *dirname; ! 697: { ! 698: int return_stdin; /* return stdin for failed commands */ ! 699: int cmdok, mask, ret, badfiles; ! 700: int send_zero; /* return successful completion status */ ! 701: int send_nonzero; /* return unsuccessful completion status */ ! 702: int send_nothing; /* request for no exit status */ ! 703: int store_status; /* store status of command in local file */ ! 704: char lbuf[BUFSIZ]; ! 705: char *p; ! 706: char dfile[MAXFULLNAME], cfile[MAXFULLNAME], incmd[BUFSIZ]; ! 707: char errDfile[BUFSIZ]; ! 708: char fin[MAXFULLNAME], sysout[NAMESIZE], fout[MAXFULLNAME]; ! 709: char file[MAXNAMESIZE], tempname[NAMESIZE]; ! 710: char _Sfile[MAXFULLNAME]; /* name of local file for status */ ! 711: FILE *xfp, *dfp, *fp, *errdfp; ! 712: struct stat sb; ! 713: char buf[BUFSIZ], user[BUFSIZ], retaddr[BUFSIZ], msgbuf[BUFSIZ]; ! 714: ! 715: (void) strcpy(Rmtname, dirname); ! 716: chremdir(Rmtname); ! 717: (void) mchFind(Rmtname); ! 718: while (gt_Xfile(_Xfile, RemSpool) > 0) { ! 719: DEBUG(4, "_Xfile - %s\n", _Xfile); ! 720: ! 721: if ( (xfp = fopen(_Xfile, "r")) == NULL) { ! 722: toCorrupt(_Xfile); ! 723: continue; ! 724: } ! 725: ASSERT(xfp != NULL, Ct_OPEN, _Xfile, errno); ! 726: ! 727: if (stat(_Xfile, &sb) != -1) ! 728: Nstat.t_qtime = sb.st_mtime; ! 729: /* ! 730: * initialize to defaults ! 731: */ ! 732: (void) strcpy(user, User); ! 733: (void) strcpy(fin, "/dev/null"); ! 734: (void) strcpy(fout, "/dev/null"); ! 735: (void) sprintf(sysout, "%.*s", MAXBASENAME, Myname); ! 736: badfiles = 0; ! 737: *incmd = *retaddr = NULLCHAR; ! 738: (void) initSeq(); ! 739: send_zero = send_nonzero = send_nothing = store_status = return_stdin = 0; ! 740: ! 741: while (fgets(buf, BUFSIZ, xfp) != NULL) { ! 742: /* ! 743: * interpret JCL card ! 744: */ ! 745: switch (buf[0]) { ! 746: case X_USER: /* user name */ ! 747: /* ignore Rmtname -- i don't believe it */ ! 748: (void) sscanf(&buf[1], "%s", user); ! 749: break; ! 750: ! 751: case X_STDIN: /* standard input */ ! 752: (void) sscanf(&buf[1], "%s", fin); ! 753: expfile(fin); ! 754: if (chkpth(fin, CK_READ)) { ! 755: DEBUG(4, "badfile - in: %s\n", fin); ! 756: badfiles = 1; ! 757: } ! 758: break; ! 759: ! 760: case X_STDOUT: /* standard output */ ! 761: (void) sscanf(&buf[1], "%s%s", fout, sysout); ! 762: if ((p = strpbrk(sysout, "!/")) != NULL) ! 763: *p = NULLCHAR; /* these can hurt! */ ! 764: if (*sysout != NULLCHAR && !EQUALS(sysout, Myname)) ! 765: break; ! 766: ! 767: expfile(fout); ! 768: if (chkpth(fout, CK_WRITE)) { ! 769: badfiles = 1; ! 770: DEBUG(4, "badfile - out: %s\n", fout); ! 771: } ! 772: break; ! 773: ! 774: ! 775: case X_CMD: /* command to execute */ ! 776: (void) strcpy(incmd, &buf[2]); ! 777: if (*(incmd + strlen(incmd) - 1) == '\n') ! 778: *(incmd + strlen(incmd) - 1) = NULLCHAR; ! 779: break; ! 780: ! 781: case X_MAILF: /* put status in _Sfile */ ! 782: store_status = 1; ! 783: (void) sscanf(&buf[1], "%s", _Sfile); ! 784: break; ! 785: ! 786: case X_SENDNOTHING: /* no failure notification */ ! 787: send_nothing++; ! 788: break; ! 789: ! 790: case X_SENDZERO: /* success notification */ ! 791: send_zero++; ! 792: break; ! 793: ! 794: case X_NONZERO: /* failure notification */ ! 795: send_nonzero++; ! 796: break; ! 797: ! 798: case X_BRINGBACK: /* return stdin on command failure */ ! 799: return_stdin = 1; ! 800: break; ! 801: ! 802: ! 803: case X_RETADDR: /* return address */ ! 804: (void) sscanf(&buf[1], "%s", retaddr); ! 805: break; ! 806: ! 807: default: ! 808: break; ! 809: } ! 810: } ! 811: ! 812: fclose(xfp); ! 813: DEBUG(4, "fin - %s, ", fin); ! 814: DEBUG(4, "fout - %s, ", fout); ! 815: DEBUG(4, "sysout - %s, ", sysout); ! 816: DEBUG(4, "user - %s\n", user); ! 817: DEBUG(4, "incmd - %s\n", incmd); ! 818: ! 819: if (retaddr[0] != NULLCHAR) ! 820: (void) strcpy(user, retaddr); /* pick on this guy */ ! 821: ! 822: /* get rid of stuff that can hurt */ ! 823: if ( (p = strpbrk(user, ";&|<>^`\\('\"")) != NULL) { ! 824: *p = NULLCHAR; ! 825: } ! 826: ! 827: if (incmd[0] == NULLCHAR) { ! 828: /* this is a bad X. file - just get rid of it */ ! 829: toCorrupt(_Xfile); ! 830: continue; ! 831: } ! 832: ! 833: /* ! 834: * send_nothing must be explicitly requested to avert failure status ! 835: * send_zero must be explicitly requested for success notification ! 836: */ ! 837: if (!send_nothing) ! 838: send_nonzero++; ! 839: ! 840: /* ! 841: * command execution ! 842: * generate a temporary file (if necessary) ! 843: * to hold output to be shipped back ! 844: */ ! 845: if (EQUALS(fout, "/dev/null")) ! 846: (void) strcpy(dfile, "/dev/null"); ! 847: else { ! 848: gename(DATAPRE, sysout, 'O', tempname); ! 849: (void) sprintf(dfile, "%s/%s", WORKSPACE, tempname); ! 850: } ! 851: ! 852: /* initialize command line */ ! 853: /* set up two environment variables, remote machine name */ ! 854: /* and remote user name if available from R line */ ! 855: (void) sprintf(_Cmd, ! 856: "%s %s UU_MACHINE=%s UU_USER=%s export UU_MACHINE UU_USER PATH; ", ! 857: PATH, LOGNAME, Rmtname, user); ! 858: ! 859: /* ! 860: * check to see if command can be executed ! 861: */ ! 862: _CargType = C_COMMAND; /* the first thing is a command */ ! 863: cmdok = chkpart(incmd); ! 864: ! 865: if (badfiles || (cmdok == BAD_COMMAND) || cmdok == BAD_FILE) { ! 866: if (cmdok == BAD_COMMAND) { ! 867: (void) sprintf(lbuf, "%s XQT DENIED", user); ! 868: (void) sprintf(msgbuf, "execution permission denied to %s", user); ! 869: } else { ! 870: (void) sprintf(lbuf, ! 871: "%s XQT- STDIN/STDOUT/FILE ACCESS DENIED", user); ! 872: (void) sprintf(msgbuf, "file access denied to %s", user); ! 873: } ! 874: logent(incmd, lbuf); ! 875: DEBUG(4, "bad command %s\n", incmd); ! 876: ! 877: if (send_nonzero) ! 878: retosndr(user, Rmtname, return_stdin ? fin : "", incmd, msgbuf, ""); ! 879: if (store_status) ! 880: uucpst(Rmtname, _Sfile, "", incmd, msgbuf); ! 881: goto rmfiles; ! 882: } ! 883: ! 884: (void) sprintf(lbuf, "%s XQT", user); ! 885: logent(_Cmd, lbuf); ! 886: DEBUG(4, "cmd %s\n", _Cmd); ! 887: ! 888: /* move files to execute directory and change to that directory */ ! 889: ! 890: mv_Xfiles(); ! 891: ! 892: ASSERT(chdir(XQTDIR) == 0, Ct_CHDIR, XQTDIR, errno); ! 893: ! 894: /* invoke shell to execute command */ ! 895: ! 896: mask = umask(0); ! 897: DEBUG(7, "full cmd: %s\n", _Cmd); ! 898: ! 899: /* temp file to capture error output */ ! 900: gename(DATAPRE, sysout, 'E', tempname); ! 901: (void) sprintf(errDfile, "%s/%s", WORKSPACE, tempname); ! 902: ret = shio(_Cmd, fin, dfile, errDfile); ! 903: umask(mask); ! 904: if (ret == -1) { /* -1 means the fork() failed */ ! 905: unmv_Xfiles(); /* put things back */ ! 906: errent(Ct_FORK, buf, errno, sccsid, __FILE__, __LINE__); ! 907: cleanup(1); /* g'nite! */ ! 908: } ! 909: ! 910: if (ret == 0) { /* exit == signal == 0 */ ! 911: (void) strcpy(msgbuf, "exited normally"); ! 912: if (send_zero) ! 913: retosndr(user, Rmtname, "", incmd, msgbuf, ""); ! 914: if (store_status) ! 915: uucpst(Rmtname, _Sfile, "", incmd, msgbuf); ! 916: } else { /* exit != 0 */ ! 917: int exitcode = (ret >> 8) & 0377; ! 918: ! 919: if (exitcode) /* exit != 0 */ ! 920: (void) sprintf(msgbuf, "exited with status %d", exitcode); ! 921: else /* signal != 0 */ ! 922: (void) sprintf(msgbuf, "terminated by signal %d", ret & 0177); ! 923: DEBUG(5, "%s\n", msgbuf); ! 924: ! 925: if (send_nonzero) ! 926: retosndr(user, Rmtname, return_stdin ? fin : "", incmd, msgbuf, errDfile); ! 927: if (store_status) ! 928: uucpst(Rmtname, _Sfile, errDfile, incmd, msgbuf); ! 929: ! 930: (void) sprintf(lbuf, "%s - %s", incmd, msgbuf); ! 931: logent(lbuf, "COMMAND FAIL"); ! 932: } ! 933: ! 934: /* change back to spool directory */ ! 935: ! 936: chremdir(Rmtname); ! 937: ! 938: /* remove file */ ! 939: ! 940: rm_Xfiles(); ! 941: ! 942: if (ret != 0) { ! 943: /* ! 944: * exit status not zero, ! 945: * so append bad news message and stderr to returned data ! 946: */ ! 947: if (access(dfile, 0) != 0) ! 948: close(creat(dfile, DFILEMODE)); ! 949: dfp = fopen(dfile, "a"); ! 950: ASSERT(dfp != NULL, Ct_OPEN, dfile, errno); ! 951: if (NOTEMPTY(errDfile) && (errdfp = fopen(errDfile, "r")) != NULL) { ! 952: (void) fprintf(dfp, "%s\n\t===== error output =====\n", msgbuf); ! 953: (void) xfappend(errdfp, dfp); /* who cares if it fails? */ ! 954: (void) fclose(errdfp); ! 955: } ! 956: (void) fclose(dfp); ! 957: } ! 958: ! 959: if (!EQUALS(fout, "/dev/null")) { ! 960: /* ! 961: * if output is on this machine copy output ! 962: * there, otherwise spawn job to send to send ! 963: * output elsewhere. ! 964: */ ! 965: ! 966: if (EQUALS(sysout, Myname)) { ! 967: xmv(dfile, fout); ! 968: } ! 969: else { ! 970: gename(CMDPRE, sysout, 'O', tempname); ! 971: (void) sprintf(cfile, "%s/%s", WORKSPACE, tempname); ! 972: fp = fdopen(ret = creat(cfile, CFILEMODE), "w"); ! 973: ASSERT(ret >= 0 && fp != NULL, Ct_OPEN, cfile, errno); ! 974: (void) fprintf(fp, "S %s %s %s -d %s 0666\n", ! 975: BASENAME(dfile, '/'), fout, user, BASENAME(dfile, '/')); ! 976: fclose(fp); ! 977: wfcommit(dfile, BASENAME(dfile, '/'), sysout); ! 978: wfcommit(cfile, BASENAME(cfile, '/'), sysout); ! 979: } ! 980: } ! 981: rmfiles: ! 982: ! 983: /* delete job files in spool directory */ ! 984: xfp = fopen(_Xfile, "r"); ! 985: ASSERT(xfp != NULL, Ct_OPEN, _Xfile, errno); ! 986: while (fgets(buf, BUFSIZ, xfp) != NULL) { ! 987: if (buf[0] != X_RQDFILE) ! 988: continue; ! 989: (void) sscanf(&buf[1], "%s", file); ! 990: (void) unlink(file); ! 991: } ! 992: (void) unlink(_Xfile); ! 993: fclose(xfp); ! 994: unlink(errDfile); ! 995: } ! 996: } ! 997: ! 998: ! 999: /* ! 1000: * return the number of files in directory <dir> who's names ! 1001: * begin with <prefix> ! 1002: * This is used to count the number of uuxqts currently running. ! 1003: * ! 1004: */ ! 1005: ! 1006: cuantos(prefix, dir) ! 1007: char *prefix, *dir; ! 1008: { ! 1009: int i = 0; ! 1010: DIR *pdir; ! 1011: char fullname[MAXNAMESIZE], file[MAXNAMESIZE]; ! 1012: ! 1013: pdir = opendir(dir); ! 1014: ASSERT(pdir != NULL, Ct_OPEN, dir, errno); ! 1015: ! 1016: while (gnamef(pdir, file) == TRUE) ! 1017: if (PREFIX(prefix, file)) { ! 1018: (void) sprintf(fullname, "%s/%s", dir, file); ! 1019: if (checkLock(fullname)) ! 1020: i++; ! 1021: } ! 1022: closedir(pdir); ! 1023: return(i); ! 1024: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.