1: #ifndef lint 2: static char sccsid[] = "@(#)uuxqt.c 5.2 (Berkeley) 7/2/83"; 3: #endif 4: 5: #include "uucp.h" 6: #include <sys/types.h> 7: #include <sys/stat.h> 8: #ifdef NDIR 9: #include "ndir.h" 10: #else 11: #include <sys/dir.h> 12: #endif 13: 14: #define APPCMD(d) {\ 15: char *p;\ 16: for (p = d; *p != '\0';) *cmdp++ = *p++;\ 17: *cmdp++ = ' ';\ 18: *cmdp = '\0';} 19: 20: /* 21: * uuxqt will execute commands set up by a uux command, 22: * usually from a remote machine - set by uucp. 23: */ 24: 25: #define NCMDS 50 26: char *Cmds[NCMDS]; 27: 28: int notiok = 1; 29: int nonzero = 0; 30: 31: char PATH[MAXFULLNAME] = "PATH=/bin:/usr/bin"; 32: /* to remove restrictions from uuxqt 33: * define ALLOK 1 34: * 35: * to add allowable commands, add to the file CMDFILE 36: * A line of form "PATH=..." changes the search path 37: */ 38: 39: 40: main(argc, argv) 41: char *argv[]; 42: { 43: char xcmd[MAXFULLNAME]; 44: int argnok; 45: char xfile[MAXFULLNAME], user[32], buf[BUFSIZ]; 46: char lbuf[30]; 47: char cfile[NAMESIZE], dfile[MAXFULLNAME]; 48: char file[NAMESIZE]; 49: char fin[MAXFULLNAME], sysout[NAMESIZE], fout[MAXFULLNAME]; 50: register FILE *xfp, *fp; 51: FILE *dfp; 52: char path[MAXFULLNAME]; 53: char cmd[BUFSIZ]; 54: /* set size of prm to something large -- cmcl2!salkind */ 55: char *cmdp, prm[1000], *ptr; 56: char *getprm(), *lastpart(); 57: int uid, ret, badfiles; 58: register int i; 59: int stcico = 0; 60: char retstat[30]; 61: int orig_uid = getuid(); 62: 63: strcpy(Progname, "uuxqt"); 64: uucpname(Myname); 65: 66: /* Try to run as uucp -- rti!trt */ 67: setgid(getegid()); 68: setuid(geteuid()); 69: 70: umask(WFMASK); 71: Ofn = 1; 72: Ifn = 0; 73: while (argc>1 && argv[1][0] == '-') { 74: switch(argv[1][1]){ 75: case 'x': 76: chkdebug(orig_uid); 77: Debug = atoi(&argv[1][2]); 78: if (Debug <= 0) 79: Debug = 1; 80: break; 81: default: 82: fprintf(stderr, "unknown flag %s\n", argv[1]); 83: break; 84: } 85: --argc; argv++; 86: } 87: 88: DEBUG(4, "\n\n** %s **\n", "START"); 89: subchdir(Spool); 90: strcpy(Wrkdir, Spool); 91: uid = getuid(); 92: guinfo(uid, User, path); 93: DEBUG(4, "User - %s\n", User); 94: if (ulockf(X_LOCK, (time_t) X_LOCKTIME) != 0) 95: exit(0); 96: 97: fp = fopen(CMDFILE, "r"); 98: if (fp == NULL) { 99: /* Fall-back if CMDFILE missing. Sept 1982, rti!trt */ 100: logent("CAN'T OPEN", CMDFILE); 101: Cmds[0] = "rmail"; 102: Cmds[1] = "rnews"; 103: Cmds[2] = "ruusend"; 104: Cmds[3] = NULL; 105: goto doprocess; 106: } 107: DEBUG(5, "%s opened\n", CMDFILE); 108: for (i=0; i<NCMDS-1 && cfgets(xcmd, sizeof(xcmd), fp) != NULL; i++) { 109: xcmd[strlen(xcmd)-1] = '\0'; 110: if (strncmp(xcmd, "PATH=", 5) == 0) { 111: strcpy(PATH, xcmd); 112: i--; /* kludge */ 113: continue; 114: } 115: DEBUG(5, "xcmd = %s\n", xcmd); 116: Cmds[i] = malloc((unsigned)(strlen(xcmd)+1)); 117: strcpy(Cmds[i], xcmd); 118: } 119: Cmds[i] = 0; 120: fclose(fp); 121: 122: doprocess: 123: DEBUG(4, "process %s\n", ""); 124: while (gtxfile(xfile) > 0) { 125: ultouch(); /* rti!trt */ 126: DEBUG(4, "xfile - %s\n", xfile); 127: 128: xfp = fopen(subfile(xfile), "r"); 129: ASSERT(xfp != NULL, "CAN'T OPEN", xfile, 0); 130: 131: /* initialize to default */ 132: strcpy(user, User); 133: strcpy(fin, "/dev/null"); 134: strcpy(fout, "/dev/null"); 135: sprintf(sysout, "%.7s", Myname); 136: badfiles = 0; /* this was missing -- rti!trt */ 137: while (fgets(buf, BUFSIZ, xfp) != NULL) { 138: switch (buf[0]) { 139: case X_USER: 140: sscanf(&buf[1], "%s%s", user, Rmtname); 141: break; 142: case X_STDIN: 143: sscanf(&buf[1], "%s", fin); 144: i = expfile(fin); 145: /* rti!trt: do not check permissions of 146: * vanilla spool file */ 147: if (i != 0 148: && (chkpth("", "", fin) || anyread(fin) != 0)) 149: badfiles = 1; 150: break; 151: case X_STDOUT: 152: sscanf(&buf[1], "%s%s", fout, sysout); 153: sysout[7] = '\0'; 154: /* rti!trt: do not check permissions of 155: * vanilla spool file. DO check permissions 156: * of writing on a non-vanilla file */ 157: i = 1; 158: if (fout[0] != '~' || prefix(sysout, Myname)) 159: i = expfile(fout); 160: if (i != 0 161: && (chkpth("", "", fout) 162: || chkperm(fout, (char *)1))) 163: badfiles = 1; 164: break; 165: case X_CMD: 166: strcpy(cmd, &buf[2]); 167: if (*(cmd + strlen(cmd) - 1) == '\n') 168: *(cmd + strlen(cmd) - 1) = '\0'; 169: break; 170: case X_NONOTI: 171: notiok = 0; 172: break; 173: case X_NONZERO: 174: nonzero = 1; 175: break; 176: default: 177: break; 178: } 179: } 180: 181: fclose(xfp); 182: DEBUG(4, "fin - %s, ", fin); 183: DEBUG(4, "fout - %s, ", fout); 184: DEBUG(4, "sysout - %s, ", sysout); 185: DEBUG(4, "user - %s\n", user); 186: DEBUG(4, "cmd - %s\n", cmd); 187: 188: /* command execution */ 189: if (strcmp(fout, "/dev/null") == SAME) 190: strcpy(dfile,"/dev/null"); 191: else 192: gename(DATAPRE, sysout, 'O', dfile); 193: 194: /* expand file names where necessary */ 195: expfile(dfile); 196: strcpy(buf, PATH); 197: strcat(buf, ";export PATH;"); 198: cmdp = buf + strlen(buf); 199: ptr = cmd; 200: xcmd[0] = '\0'; 201: argnok = 0; 202: while ((ptr = getprm(ptr, prm)) != NULL) { 203: if (prm[0] == ';' || prm[0] == '^' 204: || prm[0] == '&' || prm[0] == '|') { 205: xcmd[0] = '\0'; 206: APPCMD(prm); 207: continue; 208: } 209: 210: if ((argnok = argok(xcmd, prm)) != 0) 211: /* command not valid */ 212: break; 213: 214: if (prm[0] == '~') 215: expfile(prm); 216: APPCMD(prm); 217: } 218: if (argnok || badfiles) { 219: sprintf(lbuf, "%s XQT DENIED", user); 220: logent(cmd, lbuf); 221: DEBUG(4, "bad command %s\n", prm); 222: notify(user, Rmtname, cmd, "DENIED"); 223: goto rmfiles; 224: } 225: sprintf(lbuf, "%s XQT", user); 226: logent(buf, lbuf); 227: DEBUG(4, "cmd %s\n", buf); 228: 229: mvxfiles(xfile); 230: subchdir(XQTDIR); 231: ret = shio(buf, fin, dfile, (char *)NULL); 232: /* watcgl.11, dmmartindale, signal and exit values were reversed */ 233: sprintf(retstat, "signal %d, exit %d", ret & 0377, 234: (ret>>8) & 0377); 235: if (strcmp(xcmd, "rmail") == SAME) 236: notiok = 0; 237: if (strcmp(xcmd, "rnews") == SAME) 238: nonzero = 1; 239: if (notiok && (!nonzero || (nonzero && ret != 0))) 240: notify(user, Rmtname, cmd, retstat); 241: else if (ret != 0 && strcmp(xcmd, "rmail") == SAME) { 242: /* mail failed - return letter to sender */ 243: retosndr(user, Rmtname, fin); 244: sprintf(buf, "ret (%o) from %s!%s", ret, Rmtname, user); 245: logent("MAIL FAIL", buf); 246: } 247: DEBUG(4, "exit cmd - %d\n", ret); 248: subchdir(Spool); 249: rmxfiles(xfile); 250: if (ret != 0) { 251: /* exit status not zero */ 252: dfp = fopen(subfile(dfile), "a"); 253: ASSERT(dfp != NULL, "CAN'T OPEN", dfile, 0); 254: fprintf(dfp, "exit status %d", ret); 255: fclose(dfp); 256: } 257: if (strcmp(fout, "/dev/null") != SAME) { 258: if (prefix(sysout, Myname)) { 259: xmv(dfile, fout); 260: chmod(fout, BASEMODE); 261: } 262: else { 263: gename(CMDPRE, sysout, 'O', cfile); 264: fp = fopen(subfile(cfile), "w"); 265: ASSERT(fp != NULL, "OPEN", cfile, 0); 266: fprintf(fp, "S %s %s %s - %s 0666\n", 267: dfile, fout, user, lastpart(dfile)); 268: fclose(fp); 269: } 270: } 271: rmfiles: 272: xfp = fopen(subfile(xfile), "r"); 273: ASSERT(xfp != NULL, "CAN'T OPEN", xfile, 0); 274: while (fgets(buf, BUFSIZ, xfp) != NULL) { 275: if (buf[0] != X_RQDFILE) 276: continue; 277: sscanf(&buf[1], "%s", file); 278: unlink(subfile(file)); 279: } 280: unlink(subfile(xfile)); 281: fclose(xfp); 282: } 283: 284: if (stcico) 285: xuucico(""); 286: cleanup(0); 287: } 288: 289: 290: cleanup(code) 291: int code; 292: { 293: logcls(); 294: rmlock(CNULL); 295: exit(code); 296: } 297: 298: 299: /******* 300: * gtxfile(file) get a file to execute 301: * char *file; 302: * 303: * return codes: 0 - no file | 1 - file to execute 304: * Mod to recheck for X-able files. Sept 1982, rti!trt. 305: * Suggested by utzoo.2458 (utzoo!henry) 306: * Uses iswrk/gtwrkf to keep files in sequence, May 1983. 307: */ 308: 309: gtxfile(file) 310: register char *file; 311: { 312: char pre[3]; 313: register int rechecked; 314: 315: pre[0] = XQTPRE; 316: pre[1] = '.'; 317: pre[2] = '\0'; 318: rechecked = 0; 319: retry: 320: if (!gtwrkf(Spool, file)) { 321: if (rechecked) 322: return(0); 323: rechecked = 1; 324: DEBUG(4, "iswrk\n", ""); 325: if (!iswrk(file, "get", Spool, pre)) 326: return(0); 327: } 328: DEBUG(4, "file - %s\n", file); 329: #ifndef UUDIR 330: /* skip spurious subdirectories */ 331: if (strcmp(pre, file) == SAME) 332: goto retry; 333: #endif 334: if (gotfiles(file)) 335: return(1); 336: goto retry; 337: } 338: 339: 340: /*** 341: * gotfiles(file) check for needed files 342: * char *file; 343: * 344: * return codes: 0 - not ready | 1 - all files ready 345: */ 346: 347: gotfiles(file) 348: register char *file; 349: { 350: struct stat stbuf; 351: register FILE *fp; 352: char buf[BUFSIZ], rqfile[MAXFULLNAME]; 353: 354: fp = fopen(subfile(file), "r"); 355: if (fp == NULL) 356: return(0); 357: 358: while (fgets(buf, BUFSIZ, fp) != NULL) { 359: DEBUG(4, "%s\n", buf); 360: if (buf[0] != X_RQDFILE) 361: continue; 362: sscanf(&buf[1], "%s", rqfile); 363: expfile(rqfile); 364: if (stat(subfile(rqfile), &stbuf) == -1) { 365: fclose(fp); 366: return(0); 367: } 368: } 369: 370: fclose(fp); 371: return(1); 372: } 373: 374: 375: /*** 376: * rmxfiles(xfile) remove execute files to x-directory 377: * char *xfile; 378: * 379: * return codes - none 380: */ 381: 382: rmxfiles(xfile) 383: register char *xfile; 384: { 385: register FILE *fp; 386: char buf[BUFSIZ], file[NAMESIZE], tfile[NAMESIZE]; 387: char tfull[MAXFULLNAME]; 388: 389: if((fp = fopen(subfile(xfile), "r")) == NULL) 390: return; 391: 392: while (fgets(buf, BUFSIZ, fp) != NULL) { 393: if (buf[0] != X_RQDFILE) 394: continue; 395: if (sscanf(&buf[1], "%s%s", file, tfile) < 2) 396: continue; 397: sprintf(tfull, "%s/%s", XQTDIR, tfile); 398: unlink(subfile(tfull)); 399: } 400: fclose(fp); 401: return; 402: } 403: 404: 405: /*** 406: * mvxfiles(xfile) move execute files to x-directory 407: * char *xfile; 408: * 409: * return codes - none 410: */ 411: 412: mvxfiles(xfile) 413: char *xfile; 414: { 415: register FILE *fp; 416: char buf[BUFSIZ], ffile[MAXFULLNAME], tfile[NAMESIZE]; 417: char tfull[MAXFULLNAME]; 418: int ret; 419: 420: if((fp = fopen(subfile(xfile), "r")) == NULL) 421: return; 422: 423: while (fgets(buf, BUFSIZ, fp) != NULL) { 424: if (buf[0] != X_RQDFILE) 425: continue; 426: if (sscanf(&buf[1], "%s%s", ffile, tfile) < 2) 427: continue; 428: expfile(ffile); 429: sprintf(tfull, "%s/%s", XQTDIR, tfile); 430: /* duke!rti, ncsu!mcm: use xmv, not link(II) */ 431: unlink(subfile(tfull)); 432: ret = xmv(ffile, tfull); 433: ASSERT(ret == 0, "XQTDIR ERROR", "", ret); 434: } 435: fclose(fp); 436: return; 437: } 438: 439: 440: /*** 441: * argok(xc, cmd) check for valid command/argumanet 442: * *NOTE - side effect is to set xc to the 443: * command to be executed. 444: * char *xc, *cmd; 445: * 446: * return 0 - ok | 1 nok 447: */ 448: 449: argok(xc, cmd) 450: register char *xc, *cmd; 451: { 452: register char **ptr; 453: 454: #ifndef ALLOK 455: /* don't allow sh command strings `....` */ 456: /* don't allow redirection of standard in or out */ 457: /* don't allow other funny stuff */ 458: /* but there are probably total holes here */ 459: /* post-script. ittvax!swatt has a uuxqt that solves this. */ 460: /* This version of uuxqt will shortly disappear */ 461: if (index(cmd, '`') != NULL 462: || index(cmd, '>') != NULL 463: || index(cmd, ';') != NULL 464: || index(cmd, '^') != NULL 465: || index(cmd, '&') != NULL 466: || index(cmd, '|') != NULL 467: || index(cmd, '<') != NULL) 468: return(1); 469: #endif 470: 471: if (xc[0] != '\0') 472: return(0); 473: 474: #ifndef ALLOK 475: ptr = Cmds; 476: while(*ptr != NULL) { 477: if (strcmp(cmd, *ptr) == SAME) 478: break; 479: ptr++; 480: } 481: if (*ptr == NULL) 482: return(1); 483: #endif 484: strcpy(xc, cmd); 485: return(0); 486: } 487: 488: 489: /*** 490: * notify send mail to user giving execution results 491: * return code - none 492: * This program assumes new mail command - send remote mail 493: */ 494: 495: notify(user, rmt, cmd, str) 496: char *user, *rmt, *cmd, *str; 497: { 498: char text[MAXFULLNAME]; 499: char ruser[MAXFULLNAME]; 500: 501: sprintf(text, "uuxqt cmd (%.50s) status (%s)", cmd, str); 502: if (prefix(rmt, Myname)) 503: strcpy(ruser, user); 504: else 505: sprintf(ruser, "%s!%s", rmt, user); 506: mailst(ruser, text, ""); 507: return; 508: } 509: 510: /*** 511: * retosndr - return mail to sender 512: * 513: * return code - none 514: */ 515: 516: retosndr(user, rmt, file) 517: char *user, *rmt, *file; 518: { 519: char ruser[100]; 520: 521: if (strcmp(rmt, Myname) == SAME) 522: strcpy(ruser, user); 523: else 524: sprintf(ruser, "%s!%s", rmt, user); 525: 526: if (anyread(file) == 0) 527: mailst(ruser, "Mail failed. Letter returned to sender.\n", file); 528: else 529: mailst(ruser, "Mail failed. Letter returned to sender.\n", ""); 530: return; 531: }