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