xref: /csrg-svn/usr.bin/uucp/uuxqt/uuxqt.c (revision 33966)
113697Ssam #ifndef lint
2*33966Srick static char sccsid[] = "@(#)uuxqt.c	5.10	(Berkeley) 04/05/88";
313697Ssam #endif
413697Ssam 
513697Ssam #include "uucp.h"
613697Ssam #include <sys/stat.h>
713697Ssam #ifdef	NDIR
813697Ssam #include "ndir.h"
913697Ssam #else
1013702Ssam #include <sys/dir.h>
1113697Ssam #endif
1217846Sralph #include <signal.h>
1313697Ssam 
1418628Sralph #define BADCHARS	"&^|(`\\<>;\"{}\n'"
1518628Sralph #define RECHECKTIME	60*10	/* 10 minutes */
1617870Sralph 
1713697Ssam #define APPCMD(d) {\
1813697Ssam char *p;\
1917846Sralph for (p = d; *p != '\0';) *cmdp++ = *p++; *cmdp++ = ' '; *cmdp = '\0';}
2013697Ssam 
2133579Srick extern char Filent[LLEN][NAMESIZE];
2233579Srick 
2313697Ssam /*
2413697Ssam  *	uuxqt will execute commands set up by a uux command,
2513697Ssam  *	usually from a remote machine - set by uucp.
2613697Ssam  */
2713697Ssam 
2813697Ssam #define	NCMDS	50
2917846Sralph char *Cmds[NCMDS+1];
3017846Sralph int Notify[NCMDS+1];
3117846Sralph #define	NT_YES	0	/* if should notify on execution */
3217846Sralph #define	NT_ERR	1	/* if should notify if non-zero exit status (-z equivalent) */
3317846Sralph #define	NT_NO	2	/* if should not notify ever (-n equivalent) */
3413697Ssam 
3517846Sralph extern int Nfiles;
3617846Sralph 
3718628Sralph int TransferSucceeded = 1;
3813697Ssam int notiok = 1;
3913697Ssam int nonzero = 0;
4013697Ssam 
4125147Sbloom struct timeb Now;
4225147Sbloom 
4318628Sralph char PATH[MAXFULLNAME] = "PATH=/bin:/usr/bin:/usr/ucb";
44*33966Srick char UU_MACHINE[MAXFULLNAME];
4518628Sralph char Shell[MAXFULLNAME];
4618628Sralph char HOME[MAXFULLNAME];
4717846Sralph 
4818628Sralph extern char **environ;
4918628Sralph char *nenv[] = {
5018628Sralph 	PATH,
5118628Sralph 	Shell,
5218628Sralph 	HOME,
53*33966Srick 	UU_MACHINE,
5418628Sralph 	0
5518628Sralph };
5617846Sralph 
5713697Ssam /*  to remove restrictions from uuxqt
5813697Ssam  *  define ALLOK 1
5913697Ssam  *
6013697Ssam  *  to add allowable commands, add to the file CMDFILE
6113697Ssam  *  A line of form "PATH=..." changes the search path
6213697Ssam  */
6313697Ssam main(argc, argv)
6413697Ssam char *argv[];
6513697Ssam {
6633579Srick 	char xcmd[BUFSIZ*2];
6713697Ssam 	int argnok;
6817846Sralph 	int notiflg;
6933579Srick 	char xfile[MAXFULLNAME], user[MAXFULLNAME], buf[BUFSIZ*2];
7017846Sralph 	char lbuf[MAXFULLNAME];
7113697Ssam 	char cfile[NAMESIZE], dfile[MAXFULLNAME];
7213697Ssam 	char file[NAMESIZE];
7313697Ssam 	char fin[MAXFULLNAME], sysout[NAMESIZE], fout[MAXFULLNAME];
7413697Ssam 	register FILE *xfp, *fp;
7513697Ssam 	FILE *dfp;
7613697Ssam 	char path[MAXFULLNAME];
7733579Srick 	char cmd[BUFSIZ*2];
7813697Ssam 	char *cmdp, prm[1000], *ptr;
7913697Ssam 	char *getprm(), *lastpart();
80*33966Srick 	int uid, ret, badfiles;
8113697Ssam 	register int i;
8213697Ssam 	int stcico = 0;
8318628Sralph 	time_t xstart, xnow;
8413697Ssam 	char retstat[30];
85*33966Srick 	extern char *optarg;
86*33966Srick 	extern int optind;
8713697Ssam 
8813697Ssam 	strcpy(Progname, "uuxqt");
8913697Ssam 	uucpname(Myname);
9013697Ssam 
9113697Ssam 	umask(WFMASK);
9213697Ssam 	Ofn = 1;
9313697Ssam 	Ifn = 0;
94*33966Srick 	while ((i = getopt(argc, argv, "x:S:")) != EOF)
95*33966Srick 		switch(i) {
9613697Ssam 		case 'x':
9717846Sralph 			chkdebug();
98*33966Srick 			Debug = atoi(optarg);
9913697Ssam 			if (Debug <= 0)
10013697Ssam 				Debug = 1;
10113697Ssam 			break;
10233579Srick 		case 'S':
103*33966Srick 			Spool = optarg;
10433579Srick 			DEBUG(1, "Spool set to %s", Spool);
10533579Srick 			break;
106*33966Srick 		case '?':
10713697Ssam 		default:
108*33966Srick 			fprintf(stderr, "unknown flag %s\n", argv[optind-1]);
10913697Ssam 				break;
11013697Ssam 		}
11113697Ssam 
11218628Sralph 	DEBUG(4, "\n\n** START **\n", CNULL);
113*33966Srick 	if (subchdir(Spool) < 0) {
114*33966Srick 		syslog(LOG_WARNING, "chdir(%s) failed: %m", Spool);
115*33966Srick 		cleanup(1);
116*33966Srick 	}
11713697Ssam 	strcpy(Wrkdir, Spool);
11813697Ssam 	uid = getuid();
11933579Srick 	if (guinfo(uid, User, path) != SUCCESS) {
120*33966Srick 		syslog(LOG_WARNING, "Can't find username for uid %d", uid);
12133579Srick 		DEBUG(1, "Using username", "uucp");
12233579Srick 		strcpy(User, "uucp");
12333579Srick 	}
12417846Sralph 	setgid(getegid());
12517846Sralph 	setuid(geteuid());
12617846Sralph 
12713697Ssam 	DEBUG(4, "User - %s\n", User);
12823692Sbloom 	if (ulockf(X_LOCK, X_LOCKTIME) != 0)
12913697Ssam 		exit(0);
13013697Ssam 
13113697Ssam 	fp = fopen(CMDFILE, "r");
13213697Ssam 	if (fp == NULL) {
13317846Sralph 		logent(CANTOPEN, CMDFILE);
13413697Ssam 		Cmds[0] = "rmail";
13513697Ssam 		Cmds[1] = "rnews";
13613697Ssam 		Cmds[2] = "ruusend";
13713697Ssam 		Cmds[3] = NULL;
13813697Ssam 		goto doprocess;
13913697Ssam 	}
14013697Ssam 	DEBUG(5, "%s opened\n", CMDFILE);
14117846Sralph 	for (i=0; i<NCMDS && cfgets(xcmd, sizeof(xcmd), fp) != NULL; i++) {
14217846Sralph 		int j;
14317846Sralph 		/* strip trailing whitespace */
14417846Sralph 		for (j = strlen(xcmd)-1; j >= 0; --j)
14517846Sralph 			if (xcmd[j] == '\n' || xcmd[j] == ' ' || xcmd[j] == '\t')
14617846Sralph 				xcmd[j] = '\0';
14717846Sralph 			else
14817846Sralph 				break;
14917846Sralph 		/* look for imbedded whitespace */
15017846Sralph 		for (; j >= 0; --j)
15117846Sralph 			if (xcmd[j] == '\n' || xcmd[j] == ' ' || xcmd[j] == '\t')
15217846Sralph 				break;
15317846Sralph 		/* skip this entry if it has embedded whitespace */
15417846Sralph 		/* This defends against a bad PATH=, for example */
15517846Sralph 		if (j >= 0) {
15617846Sralph 			logent(xcmd, "BAD WHITESPACE");
15717846Sralph 			continue;
15817846Sralph 		}
15913697Ssam 		if (strncmp(xcmd, "PATH=", 5) == 0) {
16013697Ssam 			strcpy(PATH, xcmd);
16117846Sralph 			i--;	/*kludge */
16213697Ssam 			continue;
16313697Ssam 		}
16413697Ssam 		DEBUG(5, "xcmd = %s\n", xcmd);
16517846Sralph 
16617846Sralph 		if ((ptr = index(xcmd, ',')) != NULL) {
16717846Sralph 			*ptr++ = '\0';
16817846Sralph 			if (strncmp(ptr, "Err", 3) == SAME)
16917846Sralph 				Notify[i] = NT_ERR;
17017846Sralph 			else if (strcmp(ptr, "No") == SAME)
17117846Sralph 				Notify[i] = NT_NO;
17217846Sralph 			else
17317846Sralph 				Notify[i] = NT_YES;
17417846Sralph 		} else
17517846Sralph 			Notify[i] = NT_YES;
17617846Sralph 		if ((Cmds[i] = malloc((unsigned)(strlen(xcmd)+1))) == NULL) {
17717846Sralph 			DEBUG(1, "MALLOC FAILED", CNULL);
17817846Sralph 			break;
17917846Sralph 		}
18013697Ssam 		strcpy(Cmds[i], xcmd);
18113697Ssam 	}
18217846Sralph 	Cmds[i] = CNULL;
18313697Ssam 	fclose(fp);
18413697Ssam 
18513697Ssam doprocess:
18618628Sralph 
18718628Sralph 	(void) sprintf(HOME, "HOME=%s", Spool);
18818628Sralph 	(void) sprintf(Shell, "SHELL=%s", SHELL);
18918628Sralph 	environ = nenv; /* force use if our environment */
19018628Sralph 
19118628Sralph 	DEBUG(11,"path = %s\n", getenv("PATH"));
19218628Sralph 
19317846Sralph 	DEBUG(4, "process %s\n", CNULL);
19433579Srick 
19518628Sralph 	time(&xstart);
19613697Ssam 	while (gtxfile(xfile) > 0) {
19725147Sbloom 		/* if /etc/nologin exists, exit cleanly */
19825147Sbloom #if defined(BSD4_2) || defined(USG)
19925147Sbloom 		if (access(NOLOGIN) == 0) {
20025147Sbloom #else !BSD4_2 && ! USG
20117846Sralph 		ultouch();
20217846Sralph 		if (nologinflag) {
20325147Sbloom #endif !BSD4_2 && !USG
20417846Sralph 			logent(NOLOGIN, "UUXQT SHUTDOWN");
20517846Sralph 			if (Debug)
20617846Sralph 				logent("debugging", "continuing anyway");
20717846Sralph 			else
20817846Sralph 				break;
20917846Sralph 		}
21013697Ssam 		DEBUG(4, "xfile - %s\n", xfile);
21113697Ssam 
21213697Ssam 		xfp = fopen(subfile(xfile), "r");
213*33966Srick 		if (xfp == NULL) {
214*33966Srick 			syslog(LOG_ERR, "fopen(%s) failed: %m", subfile(xfile));
215*33966Srick 			cleanup(1);
216*33966Srick 		}
21713697Ssam 
21813697Ssam 		/*  initialize to default  */
21913697Ssam 		strcpy(user, User);
22017846Sralph 		strcpy(fin, DEVNULL);
22117846Sralph 		strcpy(fout, DEVNULL);
22223692Sbloom 		strcpy(sysout, Myname);
22317846Sralph 		badfiles = 0;
22413697Ssam 		while (fgets(buf, BUFSIZ, xfp) != NULL) {
22533579Srick 	if(buf[0] != '\0' && buf[0] != '#' &&
22633579Srick 		buf[1] != ' ' && buf[1] != '\0' && buf[1] != '\n') {
22733579Srick 		char *bnp, cfilename[BUFSIZ];
22833579Srick 		DEBUG(4, "uuxqt: buf = %s\n", buf);
22933579Srick 		bnp = rindex(xfile, '/');
23033579Srick 		sprintf(cfilename, "%s/%s", CORRUPT,
23133579Srick 			bnp ? bnp + 1 : xfile);
23233579Srick 		DEBUG(4, "uuxqt: move %s to ", xfile);
23333579Srick 		DEBUG(4, "%s\n", cfilename);
23433579Srick 		xmv(xfile, cfilename);
235*33966Srick 		syslog(LOG_WARNING, "%s: X. FILE CORRUPTED", xfile);
23633579Srick 		fclose(xfp);
23733579Srick 		goto doprocess;
23833579Srick 
23933579Srick 	}
24013697Ssam 			switch (buf[0]) {
24113697Ssam 			case X_USER:
24217846Sralph 				sscanf(&buf[1], "%s %s", user, Rmtname);
243*33966Srick 				sprintf(UU_MACHINE, "UU_MACHINE=%s", Rmtname);
24413697Ssam 				break;
24517846Sralph 			case X_RETURNTO:
24617846Sralph 				sscanf(&buf[1], "%s", user);
24717846Sralph 				break;
24813697Ssam 			case X_STDIN:
24913697Ssam 				sscanf(&buf[1], "%s", fin);
25013697Ssam 				i = expfile(fin);
25113697Ssam 				/* rti!trt: do not check permissions of
25213697Ssam 				 * vanilla spool file */
25313697Ssam 				if (i != 0
25413697Ssam 				 && (chkpth("", "", fin) || anyread(fin) != 0))
25513697Ssam 					badfiles = 1;
25613697Ssam 				break;
25713697Ssam 			case X_STDOUT:
25813697Ssam 				sscanf(&buf[1], "%s%s", fout, sysout);
25923692Sbloom 				sysout[MAXBASENAME] = '\0';
26013697Ssam 				/* rti!trt: do not check permissions of
26113697Ssam 				 * vanilla spool file.  DO check permissions
26213697Ssam 				 * of writing on a non-vanilla file */
26313697Ssam 				i = 1;
26413697Ssam 				if (fout[0] != '~' || prefix(sysout, Myname))
26513697Ssam 					i = expfile(fout);
26613697Ssam 				if (i != 0
26713697Ssam 				 && (chkpth("", "", fout)
26813697Ssam 					|| chkperm(fout, (char *)1)))
26913697Ssam 					badfiles = 1;
27013697Ssam 				break;
27113697Ssam 			case X_CMD:
27213697Ssam 				strcpy(cmd, &buf[2]);
27313697Ssam 				if (*(cmd + strlen(cmd) - 1) == '\n')
27413697Ssam 					*(cmd + strlen(cmd) - 1) = '\0';
27513697Ssam 				break;
27613697Ssam 			case X_NONOTI:
27713697Ssam 				notiok = 0;
27813697Ssam 				break;
27913697Ssam 			case X_NONZERO:
28013697Ssam 				nonzero = 1;
28113697Ssam 				break;
28213697Ssam 			default:
28313697Ssam 				break;
28413697Ssam 			}
28513697Ssam 		}
28613697Ssam 
28713697Ssam 		fclose(xfp);
28813697Ssam 		DEBUG(4, "fin - %s, ", fin);
28913697Ssam 		DEBUG(4, "fout - %s, ", fout);
29013697Ssam 		DEBUG(4, "sysout - %s, ", sysout);
29113697Ssam 		DEBUG(4, "user - %s\n", user);
29213697Ssam 		DEBUG(4, "cmd - %s\n", cmd);
29313697Ssam 
29413697Ssam 		/*  command execution  */
29517846Sralph 		if (strcmp(fout, DEVNULL) == SAME)
29617846Sralph 			strcpy(dfile,DEVNULL);
29713697Ssam 		else
29813697Ssam 			gename(DATAPRE, sysout, 'O', dfile);
29913697Ssam 
30013697Ssam 		/* expand file names where necessary */
30113697Ssam 		expfile(dfile);
30218628Sralph 		cmdp = buf;
30313697Ssam 		ptr = cmd;
30413697Ssam 		xcmd[0] = '\0';
30513697Ssam 		argnok = 0;
30613697Ssam 		while ((ptr = getprm(ptr, prm)) != NULL) {
30713697Ssam 			if (prm[0] == ';' || prm[0] == '^'
30813697Ssam 			  || prm[0] == '&'  || prm[0] == '|') {
30913697Ssam 				xcmd[0] = '\0';
31013697Ssam 				APPCMD(prm);
31113697Ssam 				continue;
31213697Ssam 			}
31313697Ssam 
31417846Sralph 			if ((argnok = argok(xcmd, prm)) != SUCCESS)
31513697Ssam 				/*  command not valid  */
31613697Ssam 				break;
31713697Ssam 
31813697Ssam 			if (prm[0] == '~')
31913697Ssam 				expfile(prm);
32013697Ssam 			APPCMD(prm);
32113697Ssam 		}
32217846Sralph 		/*
32317846Sralph 		 * clean up trailing ' ' in command.
32417846Sralph 		 */
32517846Sralph 		if (cmdp > buf && cmdp[0] == '\0' && cmdp[-1] == ' ')
32617846Sralph 			*--cmdp = '\0';
32713697Ssam 		if (argnok || badfiles) {
32813697Ssam 			sprintf(lbuf, "%s XQT DENIED", user);
32913697Ssam 			logent(cmd, lbuf);
33013697Ssam 			DEBUG(4, "bad command %s\n", prm);
33113697Ssam 			notify(user, Rmtname, cmd, "DENIED");
33213697Ssam 			goto rmfiles;
33313697Ssam 		}
33413697Ssam 		sprintf(lbuf, "%s XQT", user);
33513697Ssam 		logent(buf, lbuf);
33613697Ssam 		DEBUG(4, "cmd %s\n", buf);
33713697Ssam 
33813697Ssam 		mvxfiles(xfile);
339*33966Srick 		if (subchdir(XQTDIR) < 0) {
340*33966Srick 			syslog(LOG_ERR, "chdir(%s) failed: %m", XQTDIR);
341*33966Srick 			cleanup(1);
342*33966Srick 		}
34318628Sralph 		ret = shio(buf, fin, dfile);
34413697Ssam 		sprintf(retstat, "signal %d, exit %d", ret & 0377,
34513697Ssam 		  (ret>>8) & 0377);
34613697Ssam 		if (strcmp(xcmd, "rmail") == SAME)
34713697Ssam 			notiok = 0;
34813697Ssam 		if (strcmp(xcmd, "rnews") == SAME)
34913697Ssam 			nonzero = 1;
35017846Sralph 		notiflg = chknotify(xcmd);
35117846Sralph 		if (notiok && notiflg != NT_NO &&
35217846Sralph 		   (ret != 0 || (!nonzero && notiflg == NT_YES)))
35313697Ssam 			notify(user, Rmtname, cmd, retstat);
35413697Ssam 		else if (ret != 0 && strcmp(xcmd, "rmail") == SAME) {
35513697Ssam 			/* mail failed - return letter to sender  */
35617846Sralph #ifdef	DANGEROUS
35717846Sralph 			/* NOT GUARANTEED SAFE!!! */
35817846Sralph 			if (!nonzero)
35917846Sralph 				retosndr(user, Rmtname, fin);
36017846Sralph #else
36117846Sralph 			notify(user, Rmtname, cmd, retstat);
36217846Sralph #endif
36317846Sralph 			sprintf(buf, "%s (%s) from %s!%s", buf, retstat, Rmtname, user);
36413697Ssam 			logent("MAIL FAIL", buf);
36513697Ssam 		}
36613697Ssam 		DEBUG(4, "exit cmd - %d\n", ret);
367*33966Srick 		if (subchdir(Spool) < 0) {
368*33966Srick 			syslog(LOG_ERR, "chdir(%s) failed: %m", Spool);
369*33966Srick 			cleanup(1);
370*33966Srick 		}
37113697Ssam 		rmxfiles(xfile);
37213697Ssam 		if (ret != 0) {
37313697Ssam 			/*  exit status not zero */
37413697Ssam 			dfp = fopen(subfile(dfile), "a");
375*33966Srick 			if (dfp == NULL) {
376*33966Srick 				syslog(LOG_ERR, "fopen(%s) failed: %m",
377*33966Srick 					subfile(dfile));
378*33966Srick 				cleanup(1);
379*33966Srick 			}
38013697Ssam 			fprintf(dfp, "exit status %d", ret);
38113697Ssam 			fclose(dfp);
38213697Ssam 		}
38317846Sralph 		if (strcmp(fout, DEVNULL) != SAME) {
38413697Ssam 			if (prefix(sysout, Myname)) {
38513697Ssam 				xmv(dfile, fout);
38613697Ssam 				chmod(fout, BASEMODE);
38718628Sralph 			} else {
38817846Sralph 				char *cp = rindex(user, '!');
38913697Ssam 				gename(CMDPRE, sysout, 'O', cfile);
39013697Ssam 				fp = fopen(subfile(cfile), "w");
391*33966Srick 				if (fp == NULL) {
392*33966Srick 					syslog(LOG_ERR, "fopen(%s) failed: %m",
393*33966Srick 						subfile(cfile));
394*33966Srick 					cleanup(1);
395*33966Srick 				}
39617846Sralph 				fprintf(fp, "S %s %s %s - %s 0666\n", dfile,
39717846Sralph 					fout, cp ? cp : user, lastpart(dfile));
39813697Ssam 				fclose(fp);
39913697Ssam 			}
40013697Ssam 		}
40113697Ssam 	rmfiles:
40213697Ssam 		xfp = fopen(subfile(xfile), "r");
403*33966Srick 		if (xfp == NULL) {
404*33966Srick 			syslog(LOG_ERR, "fopen(%s) failed: %m",
405*33966Srick 				subfile(xfile));
406*33966Srick 			cleanup(1);
407*33966Srick 		}
40813697Ssam 		while (fgets(buf, BUFSIZ, xfp) != NULL) {
40913697Ssam 			if (buf[0] != X_RQDFILE)
41013697Ssam 				continue;
41113697Ssam 			sscanf(&buf[1], "%s", file);
41213697Ssam 			unlink(subfile(file));
41313697Ssam 		}
41413697Ssam 		unlink(subfile(xfile));
41513697Ssam 		fclose(xfp);
41618628Sralph 
41718628Sralph 		/* rescan X. for new work every RECHECKTIME seconds */
41818628Sralph 		time(&xnow);
41918628Sralph 		if (xnow > (xstart + RECHECKTIME)) {
42018628Sralph 			extern int Nfiles;
42118628Sralph 			Nfiles = 0; 	/*force rescan for new work */
42218628Sralph 		}
42318628Sralph 		xstart = xnow;
42413697Ssam 	}
42513697Ssam 
42613697Ssam 	if (stcico)
42713697Ssam 		xuucico("");
42813697Ssam 	cleanup(0);
42913697Ssam }
43013697Ssam 
43113697Ssam 
43213697Ssam cleanup(code)
43313697Ssam int code;
43413697Ssam {
43513697Ssam 	logcls();
43613697Ssam 	rmlock(CNULL);
43717846Sralph #ifdef	VMS
43817846Sralph 	/*
43917846Sralph 	 *	Since we run as a BATCH job we must wait for all processes to
44017846Sralph 	 *	to finish
44117846Sralph 	 */
44218628Sralph 	while(wait(0) != -1)
44318628Sralph 		;
44417846Sralph #endif VMS
44513697Ssam 	exit(code);
44613697Ssam }
44713697Ssam 
44813697Ssam 
44918628Sralph /*
45018628Sralph  *	get a file to execute
45113697Ssam  *
45213697Ssam  *	return codes:  0 - no file  |  1 - file to execute
45313697Ssam  */
45413697Ssam 
45513697Ssam gtxfile(file)
45613697Ssam register char *file;
45713697Ssam {
45813697Ssam 	char pre[3];
45933579Srick 	register int rechecked, i;
46017846Sralph 	time_t ystrdy;		/* yesterday */
46117846Sralph 	struct stat stbuf;	/* for X file age */
46213697Ssam 
46313697Ssam 	pre[0] = XQTPRE;
46413697Ssam 	pre[1] = '.';
46513697Ssam 	pre[2] = '\0';
46613697Ssam 	rechecked = 0;
46713697Ssam retry:
46833579Srick 	if (Nfiles-- <= 0) {
46933579Srick 		Nfiles = 0;
47013697Ssam 		if (rechecked)
47117846Sralph 			return 0;
47213697Ssam 		rechecked = 1;
47317846Sralph 		DEBUG(4, "iswrk\n", CNULL);
47433579Srick 		return iswrk(file, "get", Spool, pre);
47513697Ssam 	}
47633579Srick 	sprintf(file, "%s/%s", Spool, Filent[0]);
47733579Srick 	for (i=0; i<Nfiles;i++)
47833579Srick 		strcpy(Filent[i], Filent[i+1]);
47933579Srick 
48013697Ssam 	DEBUG(4, "file - %s\n", file);
48113697Ssam 	/* skip spurious subdirectories */
48213697Ssam 	if (strcmp(pre, file) == SAME)
48313697Ssam 		goto retry;
48413697Ssam 	if (gotfiles(file))
48517846Sralph 		return 1;
48617846Sralph 	/* check for old X. file with no work files and remove them. */
48717846Sralph 	if (Nfiles > LLEN/2) {
48817846Sralph 	    time(&ystrdy);
48917846Sralph 	    ystrdy -= (4 * 3600L);		/* 4 hours ago */
49017846Sralph 	    DEBUG(4, "gtxfile: Nfiles > LLEN/2\n", CNULL);
49133579Srick 	    while (Nfiles-- > 0) {
49233579Srick 		sprintf(file, "%s/%s", Spool, Filent[0]);
49333579Srick 		for (i=0; i<Nfiles; i++)
49433579Srick 			strcpy(Filent[i], Filent[i+1]);
49533579Srick 
49633579Srick 		if (gotfiles(file))
49733579Srick 			return 1;
49817846Sralph 		if (stat(subfile(file), &stbuf) == 0)
49917846Sralph 		    if (stbuf.st_mtime <= ystrdy) {
50017846Sralph 			char *bnp, cfilename[NAMESIZE];
50117846Sralph 			DEBUG(4, "gtxfile: move %s to CORRUPT \n", file);
50233579Srick 			bnp = rindex(file, '/');
50317846Sralph 			sprintf(cfilename, "%s/%s", CORRUPT,
50433579Srick 				bnp ? bnp + 1 : file);
50533579Srick 			xmv(file, cfilename);
506*33966Srick 			syslog(LOG_WARNING, "%s: X. FILE MISSING FILES", file);
50717846Sralph 		    }
50817846Sralph 	    }
50933579Srick  	    Nfiles = 0;
51017846Sralph 	    DEBUG(4, "iswrk\n", CNULL);
51117846Sralph 	    if (!iswrk(file, "get", Spool, pre))
51217846Sralph 		return 0;
51317846Sralph 	}
51413697Ssam 	goto retry;
51513697Ssam }
51613697Ssam 
51718628Sralph /*
51818628Sralph  *	check for needed files
51913697Ssam  *
52013697Ssam  *	return codes:  0 - not ready  |  1 - all files ready
52113697Ssam  */
52213697Ssam 
52313697Ssam gotfiles(file)
52413697Ssam register char *file;
52513697Ssam {
52613697Ssam 	struct stat stbuf;
52713697Ssam 	register FILE *fp;
52813697Ssam 	char buf[BUFSIZ], rqfile[MAXFULLNAME];
52913697Ssam 
53013697Ssam 	fp = fopen(subfile(file), "r");
53113697Ssam 	if (fp == NULL)
53217846Sralph 		return 0;
53313697Ssam 
53413697Ssam 	while (fgets(buf, BUFSIZ, fp) != NULL) {
53513697Ssam 		DEBUG(4, "%s\n", buf);
53613697Ssam 		if (buf[0] != X_RQDFILE)
53713697Ssam 			continue;
53813697Ssam 		sscanf(&buf[1], "%s", rqfile);
53913697Ssam 		expfile(rqfile);
54013697Ssam 		if (stat(subfile(rqfile), &stbuf) == -1) {
54113697Ssam 			fclose(fp);
54217846Sralph 			return 0;
54313697Ssam 		}
54413697Ssam 	}
54513697Ssam 
54613697Ssam 	fclose(fp);
54717846Sralph 	return 1;
54813697Ssam }
54913697Ssam 
55013697Ssam 
55118628Sralph /*
55218628Sralph  *	remove execute files to x-directory
55313697Ssam  */
55413697Ssam 
55513697Ssam rmxfiles(xfile)
55613697Ssam register char *xfile;
55713697Ssam {
55813697Ssam 	register FILE *fp;
55913697Ssam 	char buf[BUFSIZ], file[NAMESIZE], tfile[NAMESIZE];
56013697Ssam 	char tfull[MAXFULLNAME];
56113697Ssam 
56213697Ssam 	if((fp = fopen(subfile(xfile), "r")) == NULL)
56313697Ssam 		return;
56413697Ssam 
56513697Ssam 	while (fgets(buf, BUFSIZ, fp) != NULL) {
56613697Ssam 		if (buf[0] != X_RQDFILE)
56713697Ssam 			continue;
56813697Ssam 		if (sscanf(&buf[1], "%s%s", file, tfile) < 2)
56913697Ssam 			continue;
57013697Ssam 		sprintf(tfull, "%s/%s", XQTDIR, tfile);
57113697Ssam 		unlink(subfile(tfull));
57213697Ssam 	}
57313697Ssam 	fclose(fp);
57413697Ssam 	return;
57513697Ssam }
57613697Ssam 
57713697Ssam 
57818628Sralph /*
57918628Sralph  *	move execute files to x-directory
58013697Ssam  */
58113697Ssam 
58213697Ssam mvxfiles(xfile)
58313697Ssam char *xfile;
58413697Ssam {
58513697Ssam 	register FILE *fp;
58613697Ssam 	char buf[BUFSIZ], ffile[MAXFULLNAME], tfile[NAMESIZE];
58713697Ssam 	char tfull[MAXFULLNAME];
58813697Ssam 
58913697Ssam 	if((fp = fopen(subfile(xfile), "r")) == NULL)
59013697Ssam 		return;
59113697Ssam 
59213697Ssam 	while (fgets(buf, BUFSIZ, fp) != NULL) {
59313697Ssam 		if (buf[0] != X_RQDFILE)
59413697Ssam 			continue;
59513697Ssam 		if (sscanf(&buf[1], "%s%s", ffile, tfile) < 2)
59613697Ssam 			continue;
59713697Ssam 		expfile(ffile);
59813697Ssam 		sprintf(tfull, "%s/%s", XQTDIR, tfile);
59913697Ssam 		unlink(subfile(tfull));
600*33966Srick 		if (xmv(ffile, tfull) != 0) {
601*33966Srick 			syslog(LOG_WARNING, "xmv(%s,%s) failed: %m",
602*33966Srick 				ffile, tfull);
603*33966Srick 			cleanup(1);
604*33966Srick 		}
60513697Ssam 	}
60613697Ssam 	fclose(fp);
60713697Ssam }
60813697Ssam 
60918628Sralph /*
61018628Sralph  *	check for valid command/argument
61118628Sralph  *	*NOTE - side effect is to set xc to the	command to be executed.
61213697Ssam  *
61313697Ssam  *	return 0 - ok | 1 nok
61413697Ssam  */
61513697Ssam 
61613697Ssam argok(xc, cmd)
61713697Ssam register char *xc, *cmd;
61813697Ssam {
61913697Ssam 	register char **ptr;
62013697Ssam 
62113697Ssam #ifndef ALLOK
62218628Sralph 	if (strpbrk(cmd, BADCHARS) != NULL) {
62317846Sralph 		DEBUG(1,"MAGIC CHARACTER FOUND\n", CNULL);
62418628Sralph 		logent(cmd, "NASTY MAGIC CHARACTER FOUND");
62517846Sralph 		return FAIL;
62617846Sralph 	}
62717846Sralph #endif !ALLOK
62813697Ssam 
62913697Ssam 	if (xc[0] != '\0')
63017846Sralph 		return SUCCESS;
63113697Ssam 
63213697Ssam #ifndef ALLOK
63313697Ssam 	ptr = Cmds;
63417846Sralph 	DEBUG(9, "Compare %s and\n", cmd);
63513697Ssam 	while(*ptr != NULL) {
63617846Sralph 		DEBUG(9, "\t%s\n", *ptr);
63713697Ssam 		if (strcmp(cmd, *ptr) == SAME)
63813697Ssam 			break;
63917846Sralph 		ptr++;
64013697Ssam 	}
64117846Sralph 	if (*ptr == NULL) {
64217846Sralph 		DEBUG(1,"COMMAND NOT FOUND\n", CNULL);
64317846Sralph 		return FAIL;
64417846Sralph 	}
64513697Ssam #endif
64613697Ssam 	strcpy(xc, cmd);
64717846Sralph 	DEBUG(9, "MATCHED %s\n", xc);
64817846Sralph 	return SUCCESS;
64913697Ssam }
65013697Ssam 
65113697Ssam 
65218628Sralph /*
65318628Sralph  *	if notification should be sent for successful execution of cmd
65417846Sralph  *
65517846Sralph  *	return NT_YES - do notification
65617846Sralph  *	       NT_ERR - do notification if exit status != 0
65717846Sralph  *	       NT_NO  - don't do notification ever
65817846Sralph  */
65917846Sralph 
66017846Sralph chknotify(cmd)
66117846Sralph char *cmd;
66217846Sralph {
66317846Sralph 	register char **ptr;
66417846Sralph 	register int *nptr;
66517846Sralph 
66617846Sralph 	ptr = Cmds;
66717846Sralph 	nptr = Notify;
66817846Sralph 	while (*ptr != NULL) {
66917846Sralph 		if (strcmp(cmd, *ptr) == SAME)
67017846Sralph 			return *nptr;
67117846Sralph 		ptr++;
67217846Sralph 		nptr++;
67317846Sralph 	}
67417846Sralph 	return NT_YES;		/* "shouldn't happen" */
67517846Sralph }
67617846Sralph 
67717846Sralph 
67817846Sralph 
67918628Sralph /*
68018628Sralph  *	send mail to user giving execution results
68113697Ssam  */
68213697Ssam 
68313697Ssam notify(user, rmt, cmd, str)
68413697Ssam char *user, *rmt, *cmd, *str;
68513697Ssam {
68633579Srick 	char text[BUFSIZ*2];
68713697Ssam 	char ruser[MAXFULLNAME];
68813697Ssam 
68925968Sbloom 	if (strpbrk(user, BADCHARS) != NULL) {
69025968Sbloom 		char lbuf[MAXFULLNAME];
69125968Sbloom 		sprintf(lbuf, "%s INVALID CHARACTER IN USERNAME", user);
69225968Sbloom 		logent(cmd, lbuf);
69325968Sbloom 		strcpy(user, "postmaster");
69425968Sbloom 	}
69517846Sralph 	sprintf(text, "uuxqt cmd (%s) status (%s)", cmd, str);
69613697Ssam 	if (prefix(rmt, Myname))
69713697Ssam 		strcpy(ruser, user);
69813697Ssam 	else
69913697Ssam 		sprintf(ruser, "%s!%s", rmt, user);
70017846Sralph 	mailst(ruser, text, CNULL);
70113697Ssam }
70213697Ssam 
70318628Sralph /*
70418628Sralph  *	return mail to sender
70513697Ssam  *
70613697Ssam  */
70713697Ssam retosndr(user, rmt, file)
70813697Ssam char *user, *rmt, *file;
70913697Ssam {
71017846Sralph 	char ruser[MAXFULLNAME];
71113697Ssam 
71225968Sbloom 	if (strpbrk(user, BADCHARS) != NULL) {
71325968Sbloom 		char lbuf[MAXFULLNAME];
71425968Sbloom 		sprintf(lbuf, "%s INVALID CHARACTER IN USERNAME", user);
71525968Sbloom 		logent(file, lbuf);
71625968Sbloom 		strcpy(user, "postmaster");
71725968Sbloom 	}
71813697Ssam 	if (strcmp(rmt, Myname) == SAME)
71913697Ssam 		strcpy(ruser, user);
72013697Ssam 	else
72113697Ssam 		sprintf(ruser, "%s!%s", rmt, user);
72213697Ssam 
72313697Ssam 	if (anyread(file) == 0)
72413697Ssam 		mailst(ruser, "Mail failed.  Letter returned to sender.\n", file);
72513697Ssam 	else
72617846Sralph 		mailst(ruser, "Mail failed.  Letter returned to sender.\n", CNULL);
72713697Ssam 	return;
72813697Ssam }
72917870Sralph 
73017870Sralph /*
73118628Sralph  *	execute shell of command with fi and fo as standard input/output
73218628Sralph  */
73318628Sralph 
73418628Sralph shio(cmd, fi, fo)
73518628Sralph char *cmd, *fi, *fo;
73618628Sralph {
73718628Sralph 	int status, f;
738*33966Srick 	int pid, ret;
73933579Srick 	char *args[256];
74018628Sralph 	extern int errno;
74118628Sralph 
74218628Sralph 	if (fi == NULL)
74318628Sralph 		fi = DEVNULL;
74418628Sralph 	if (fo == NULL)
74518628Sralph 		fo = DEVNULL;
74618628Sralph 
74733579Srick 	getargs(cmd, args, 256);
74818628Sralph 	DEBUG(3, "shio - %s\n", cmd);
74918628Sralph #ifdef SIGCHLD
75018628Sralph 	signal(SIGCHLD, SIG_IGN);
75118628Sralph #endif SIGCHLD
75218628Sralph 	if ((pid = fork()) == 0) {
75318628Sralph 		signal(SIGINT, SIG_IGN);
75418628Sralph 		signal(SIGHUP, SIG_IGN);
75518628Sralph 		signal(SIGQUIT, SIG_IGN);
75618628Sralph 		close(Ifn);
75718628Sralph 		close(Ofn);
75818628Sralph 		close(0);
75918628Sralph 		setuid(getuid());
76018628Sralph 		f = open(subfile(fi), 0);
76118628Sralph 		if (f != 0) {
76218628Sralph 			logent(fi, "CAN'T READ");
76318628Sralph 			exit(-errno);
76418628Sralph 		}
76518628Sralph 		close(1);
76618628Sralph 		f = creat(subfile(fo), 0666);
76718628Sralph 		if (f != 1) {
76818628Sralph 			logent(fo, "CAN'T WRITE");
76918628Sralph 			exit(-errno);
77018628Sralph 		}
77118628Sralph 		execvp(args[0], args);
77218628Sralph 		exit(100+errno);
77318628Sralph 	}
77418628Sralph 	while ((ret = wait(&status)) != pid && ret != -1)
77518628Sralph 		;
77618628Sralph 	DEBUG(3, "status %d\n", status);
77718628Sralph 	return status;
77818628Sralph }
779