|
|
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.