xref: /csrg-svn/usr.bin/uucp/uuxqt/uuxqt.c (revision 62411)
148671Sbostic /*-
2*62411Sbostic  * Copyright (c) 1985, 1988, 1993
3*62411Sbostic  *	The Regents of the University of California.  All rights reserved.
448671Sbostic  *
548671Sbostic  * %sccs.include.proprietary.c%
648671Sbostic  */
748671Sbostic 
813697Ssam #ifndef lint
9*62411Sbostic static char copyright[] =
10*62411Sbostic "@(#) Copyright (c) 1985, 1988, 1993\n\
11*62411Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1248671Sbostic #endif /* not lint */
1313697Ssam 
1448671Sbostic #ifndef lint
15*62411Sbostic static char sccsid[] = "@(#)uuxqt.c	8.1 (Berkeley) 06/06/93";
1648671Sbostic #endif /* not lint */
1748671Sbostic 
1813697Ssam #include "uucp.h"
1913697Ssam #include <sys/stat.h>
2013697Ssam #ifdef	NDIR
2113697Ssam #include "ndir.h"
2213697Ssam #else
2313702Ssam #include <sys/dir.h>
2413697Ssam #endif
2517846Sralph #include <signal.h>
2613697Ssam 
2718628Sralph #define BADCHARS	"&^|(`\\<>;\"{}\n'"
2818628Sralph #define RECHECKTIME	60*10	/* 10 minutes */
2917870Sralph 
3013697Ssam #define APPCMD(d) {\
3113697Ssam char *p;\
3217846Sralph for (p = d; *p != '\0';) *cmdp++ = *p++; *cmdp++ = ' '; *cmdp = '\0';}
3313697Ssam 
3433579Srick extern char Filent[LLEN][NAMESIZE];
3533579Srick 
3613697Ssam /*
3713697Ssam  *	uuxqt will execute commands set up by a uux command,
3813697Ssam  *	usually from a remote machine - set by uucp.
3913697Ssam  */
4013697Ssam 
4113697Ssam #define	NCMDS	50
4217846Sralph char *Cmds[NCMDS+1];
4317846Sralph int Notify[NCMDS+1];
4417846Sralph #define	NT_YES	0	/* if should notify on execution */
4517846Sralph #define	NT_ERR	1	/* if should notify if non-zero exit status (-z equivalent) */
4617846Sralph #define	NT_NO	2	/* if should not notify ever (-n equivalent) */
4713697Ssam 
4817846Sralph extern int Nfiles;
4917846Sralph 
5018628Sralph int TransferSucceeded = 1;
5113697Ssam int notiok = 1;
5213697Ssam int nonzero = 0;
5313697Ssam 
5425147Sbloom struct timeb Now;
5525147Sbloom 
5644709Strent char PATH[MAXFULLNAME] = "PATH=/bin:/usr/bin";
5733966Srick char UU_MACHINE[MAXFULLNAME];
5818628Sralph char Shell[MAXFULLNAME];
5918628Sralph char HOME[MAXFULLNAME];
6017846Sralph 
6118628Sralph extern char **environ;
6218628Sralph char *nenv[] = {
6318628Sralph 	PATH,
6418628Sralph 	Shell,
6518628Sralph 	HOME,
6633966Srick 	UU_MACHINE,
6718628Sralph 	0
6818628Sralph };
6917846Sralph 
7013697Ssam /*  to remove restrictions from uuxqt
7113697Ssam  *  define ALLOK 1
7213697Ssam  *
7313697Ssam  *  to add allowable commands, add to the file CMDFILE
7413697Ssam  *  A line of form "PATH=..." changes the search path
7513697Ssam  */
main(argc,argv)7613697Ssam main(argc, argv)
7713697Ssam char *argv[];
7813697Ssam {
7933579Srick 	char xcmd[BUFSIZ*2];
8013697Ssam 	int argnok;
8117846Sralph 	int notiflg;
8233579Srick 	char xfile[MAXFULLNAME], user[MAXFULLNAME], buf[BUFSIZ*2];
8317846Sralph 	char lbuf[MAXFULLNAME];
8413697Ssam 	char cfile[NAMESIZE], dfile[MAXFULLNAME];
8513697Ssam 	char file[NAMESIZE];
8613697Ssam 	char fin[MAXFULLNAME], sysout[NAMESIZE], fout[MAXFULLNAME];
8713697Ssam 	register FILE *xfp, *fp;
8813697Ssam 	FILE *dfp;
8913697Ssam 	char path[MAXFULLNAME];
9033579Srick 	char cmd[BUFSIZ*2];
9113697Ssam 	char *cmdp, prm[1000], *ptr;
9213697Ssam 	char *getprm(), *lastpart();
9333966Srick 	int uid, ret, badfiles;
9413697Ssam 	register int i;
9513697Ssam 	int stcico = 0;
9618628Sralph 	time_t xstart, xnow;
9713697Ssam 	char retstat[30];
9833966Srick 	extern char *optarg;
9933966Srick 	extern int optind;
10013697Ssam 
10113697Ssam 	strcpy(Progname, "uuxqt");
10213697Ssam 	uucpname(Myname);
10334176Srick 	strcpy(Rmtname, Myname);
10413697Ssam 
10513697Ssam 	umask(WFMASK);
10613697Ssam 	Ofn = 1;
10713697Ssam 	Ifn = 0;
10833966Srick 	while ((i = getopt(argc, argv, "x:S:")) != EOF)
10933966Srick 		switch(i) {
11013697Ssam 		case 'x':
11117846Sralph 			chkdebug();
11233966Srick 			Debug = atoi(optarg);
11313697Ssam 			if (Debug <= 0)
11413697Ssam 				Debug = 1;
11513697Ssam 			break;
11633579Srick 		case 'S':
11733966Srick 			Spool = optarg;
11833579Srick 			DEBUG(1, "Spool set to %s", Spool);
11933579Srick 			break;
12033966Srick 		case '?':
12113697Ssam 		default:
12233966Srick 			fprintf(stderr, "unknown flag %s\n", argv[optind-1]);
12313697Ssam 				break;
12413697Ssam 		}
12513697Ssam 
12618628Sralph 	DEBUG(4, "\n\n** START **\n", CNULL);
12733966Srick 	if (subchdir(Spool) < 0) {
12833966Srick 		syslog(LOG_WARNING, "chdir(%s) failed: %m", Spool);
12933966Srick 		cleanup(1);
13033966Srick 	}
13113697Ssam 	strcpy(Wrkdir, Spool);
13213697Ssam 	uid = getuid();
13333579Srick 	if (guinfo(uid, User, path) != SUCCESS) {
13433966Srick 		syslog(LOG_WARNING, "Can't find username for uid %d", uid);
13533579Srick 		DEBUG(1, "Using username", "uucp");
13633579Srick 		strcpy(User, "uucp");
13733579Srick 	}
13817846Sralph 	setgid(getegid());
13917846Sralph 	setuid(geteuid());
14017846Sralph 
14113697Ssam 	DEBUG(4, "User - %s\n", User);
14223692Sbloom 	if (ulockf(X_LOCK, X_LOCKTIME) != 0)
14313697Ssam 		exit(0);
14413697Ssam 
14513697Ssam 	fp = fopen(CMDFILE, "r");
14613697Ssam 	if (fp == NULL) {
14717846Sralph 		logent(CANTOPEN, CMDFILE);
14813697Ssam 		Cmds[0] = "rmail";
14913697Ssam 		Cmds[1] = "rnews";
15013697Ssam 		Cmds[2] = "ruusend";
15113697Ssam 		Cmds[3] = NULL;
15213697Ssam 		goto doprocess;
15313697Ssam 	}
15413697Ssam 	DEBUG(5, "%s opened\n", CMDFILE);
15517846Sralph 	for (i=0; i<NCMDS && cfgets(xcmd, sizeof(xcmd), fp) != NULL; i++) {
15617846Sralph 		int j;
15717846Sralph 		/* strip trailing whitespace */
15817846Sralph 		for (j = strlen(xcmd)-1; j >= 0; --j)
15917846Sralph 			if (xcmd[j] == '\n' || xcmd[j] == ' ' || xcmd[j] == '\t')
16017846Sralph 				xcmd[j] = '\0';
16117846Sralph 			else
16217846Sralph 				break;
16317846Sralph 		/* look for imbedded whitespace */
16417846Sralph 		for (; j >= 0; --j)
16517846Sralph 			if (xcmd[j] == '\n' || xcmd[j] == ' ' || xcmd[j] == '\t')
16617846Sralph 				break;
16717846Sralph 		/* skip this entry if it has embedded whitespace */
16817846Sralph 		/* This defends against a bad PATH=, for example */
16917846Sralph 		if (j >= 0) {
17017846Sralph 			logent(xcmd, "BAD WHITESPACE");
17117846Sralph 			continue;
17217846Sralph 		}
17313697Ssam 		if (strncmp(xcmd, "PATH=", 5) == 0) {
17413697Ssam 			strcpy(PATH, xcmd);
17517846Sralph 			i--;	/*kludge */
17613697Ssam 			continue;
17713697Ssam 		}
17813697Ssam 		DEBUG(5, "xcmd = %s\n", xcmd);
17917846Sralph 
18017846Sralph 		if ((ptr = index(xcmd, ',')) != NULL) {
18117846Sralph 			*ptr++ = '\0';
18217846Sralph 			if (strncmp(ptr, "Err", 3) == SAME)
18317846Sralph 				Notify[i] = NT_ERR;
18417846Sralph 			else if (strcmp(ptr, "No") == SAME)
18517846Sralph 				Notify[i] = NT_NO;
18617846Sralph 			else
18717846Sralph 				Notify[i] = NT_YES;
18817846Sralph 		} else
18917846Sralph 			Notify[i] = NT_YES;
19017846Sralph 		if ((Cmds[i] = malloc((unsigned)(strlen(xcmd)+1))) == NULL) {
19117846Sralph 			DEBUG(1, "MALLOC FAILED", CNULL);
19217846Sralph 			break;
19317846Sralph 		}
19413697Ssam 		strcpy(Cmds[i], xcmd);
19513697Ssam 	}
19617846Sralph 	Cmds[i] = CNULL;
19713697Ssam 	fclose(fp);
19813697Ssam 
19913697Ssam doprocess:
20018628Sralph 
20118628Sralph 	(void) sprintf(HOME, "HOME=%s", Spool);
20218628Sralph 	(void) sprintf(Shell, "SHELL=%s", SHELL);
20318628Sralph 	environ = nenv; /* force use if our environment */
20418628Sralph 
20518628Sralph 	DEBUG(11,"path = %s\n", getenv("PATH"));
20618628Sralph 
20717846Sralph 	DEBUG(4, "process %s\n", CNULL);
20833579Srick 
20918628Sralph 	time(&xstart);
21013697Ssam 	while (gtxfile(xfile) > 0) {
21125147Sbloom 		/* if /etc/nologin exists, exit cleanly */
21225147Sbloom #if defined(BSD4_2) || defined(USG)
21325147Sbloom 		if (access(NOLOGIN) == 0) {
21425147Sbloom #else !BSD4_2 && ! USG
21517846Sralph 		ultouch();
21617846Sralph 		if (nologinflag) {
21725147Sbloom #endif !BSD4_2 && !USG
21817846Sralph 			logent(NOLOGIN, "UUXQT SHUTDOWN");
21917846Sralph 			if (Debug)
22017846Sralph 				logent("debugging", "continuing anyway");
22117846Sralph 			else
22217846Sralph 				break;
22317846Sralph 		}
22413697Ssam 		DEBUG(4, "xfile - %s\n", xfile);
22513697Ssam 
22613697Ssam 		xfp = fopen(subfile(xfile), "r");
22733966Srick 		if (xfp == NULL) {
22833966Srick 			syslog(LOG_ERR, "fopen(%s) failed: %m", subfile(xfile));
22933966Srick 			cleanup(1);
23033966Srick 		}
23113697Ssam 
23213697Ssam 		/*  initialize to default  */
23313697Ssam 		strcpy(user, User);
23417846Sralph 		strcpy(fin, DEVNULL);
23517846Sralph 		strcpy(fout, DEVNULL);
23623692Sbloom 		strcpy(sysout, Myname);
23717846Sralph 		badfiles = 0;
23813697Ssam 		while (fgets(buf, BUFSIZ, xfp) != NULL) {
23934267Srick 			if(buf[0] != '\0' && buf[0] != '#' &&
24034267Srick 			    buf[1] != ' ' && buf[1] != '\0' && buf[1] != '\n') {
24134267Srick 				char *bnp, cfilename[BUFSIZ];
24234267Srick 				DEBUG(4, "uuxqt: buf = %s\n", buf);
24334267Srick 				bnp = rindex(xfile, '/');
24434267Srick 				sprintf(cfilename, "%s/%s", CORRUPT,
24534267Srick 					bnp ? bnp + 1 : xfile);
24634267Srick 				DEBUG(4, "uuxqt: move %s to ", xfile);
24734267Srick 				DEBUG(4, "%s\n", cfilename);
24834267Srick 				xmv(xfile, cfilename);
24934267Srick 				syslog(LOG_WARNING, "%s: X. FILE CORRUPTED",
25034267Srick 					xfile);
25134267Srick 				fclose(xfp);
25234267Srick 				goto doprocess;
25334267Srick 			}
25413697Ssam 			switch (buf[0]) {
25534267Srick 			case X_USER: {
25634267Srick 				char ORmtname[MAXFULLNAME];
25734267Srick 				strcpy(ORmtname, Rmtname);
25817846Sralph 				sscanf(&buf[1], "%s %s", user, Rmtname);
25933966Srick 				sprintf(UU_MACHINE, "UU_MACHINE=%s", Rmtname);
26034267Srick 				if (strcmp(ORmtname, Rmtname) != 0)
26134267Srick 					logcls();
26234267Srick 				break;}
26317846Sralph 			case X_RETURNTO:
26417846Sralph 				sscanf(&buf[1], "%s", user);
26517846Sralph 				break;
26613697Ssam 			case X_STDIN:
26713697Ssam 				sscanf(&buf[1], "%s", fin);
26813697Ssam 				i = expfile(fin);
26913697Ssam 				/* rti!trt: do not check permissions of
27013697Ssam 				 * vanilla spool file */
27113697Ssam 				if (i != 0
27213697Ssam 				 && (chkpth("", "", fin) || anyread(fin) != 0))
27313697Ssam 					badfiles = 1;
27413697Ssam 				break;
27513697Ssam 			case X_STDOUT:
27613697Ssam 				sscanf(&buf[1], "%s%s", fout, sysout);
27723692Sbloom 				sysout[MAXBASENAME] = '\0';
27813697Ssam 				/* rti!trt: do not check permissions of
27913697Ssam 				 * vanilla spool file.  DO check permissions
28013697Ssam 				 * of writing on a non-vanilla file */
28113697Ssam 				i = 1;
28213697Ssam 				if (fout[0] != '~' || prefix(sysout, Myname))
28313697Ssam 					i = expfile(fout);
28413697Ssam 				if (i != 0
28513697Ssam 				 && (chkpth("", "", fout)
28613697Ssam 					|| chkperm(fout, (char *)1)))
28713697Ssam 					badfiles = 1;
28813697Ssam 				break;
28913697Ssam 			case X_CMD:
29013697Ssam 				strcpy(cmd, &buf[2]);
29113697Ssam 				if (*(cmd + strlen(cmd) - 1) == '\n')
29213697Ssam 					*(cmd + strlen(cmd) - 1) = '\0';
29313697Ssam 				break;
29413697Ssam 			case X_NONOTI:
29513697Ssam 				notiok = 0;
29613697Ssam 				break;
29713697Ssam 			case X_NONZERO:
29813697Ssam 				nonzero = 1;
29913697Ssam 				break;
30013697Ssam 			default:
30113697Ssam 				break;
30213697Ssam 			}
30313697Ssam 		}
30413697Ssam 
30513697Ssam 		fclose(xfp);
30613697Ssam 		DEBUG(4, "fin - %s, ", fin);
30713697Ssam 		DEBUG(4, "fout - %s, ", fout);
30813697Ssam 		DEBUG(4, "sysout - %s, ", sysout);
30913697Ssam 		DEBUG(4, "user - %s\n", user);
31013697Ssam 		DEBUG(4, "cmd - %s\n", cmd);
31113697Ssam 
31213697Ssam 		/*  command execution  */
31317846Sralph 		if (strcmp(fout, DEVNULL) == SAME)
31417846Sralph 			strcpy(dfile,DEVNULL);
31513697Ssam 		else
31613697Ssam 			gename(DATAPRE, sysout, 'O', dfile);
31713697Ssam 
31813697Ssam 		/* expand file names where necessary */
31913697Ssam 		expfile(dfile);
32018628Sralph 		cmdp = buf;
32113697Ssam 		ptr = cmd;
32213697Ssam 		xcmd[0] = '\0';
32313697Ssam 		argnok = 0;
32413697Ssam 		while ((ptr = getprm(ptr, prm)) != NULL) {
32513697Ssam 			if (prm[0] == ';' || prm[0] == '^'
32613697Ssam 			  || prm[0] == '&'  || prm[0] == '|') {
32713697Ssam 				xcmd[0] = '\0';
32813697Ssam 				APPCMD(prm);
32913697Ssam 				continue;
33013697Ssam 			}
33113697Ssam 
33217846Sralph 			if ((argnok = argok(xcmd, prm)) != SUCCESS)
33313697Ssam 				/*  command not valid  */
33413697Ssam 				break;
33513697Ssam 
33613697Ssam 			if (prm[0] == '~')
33713697Ssam 				expfile(prm);
33813697Ssam 			APPCMD(prm);
33913697Ssam 		}
34017846Sralph 		/*
34117846Sralph 		 * clean up trailing ' ' in command.
34217846Sralph 		 */
34317846Sralph 		if (cmdp > buf && cmdp[0] == '\0' && cmdp[-1] == ' ')
34417846Sralph 			*--cmdp = '\0';
34513697Ssam 		if (argnok || badfiles) {
34613697Ssam 			sprintf(lbuf, "%s XQT DENIED", user);
34713697Ssam 			logent(cmd, lbuf);
34813697Ssam 			DEBUG(4, "bad command %s\n", prm);
34913697Ssam 			notify(user, Rmtname, cmd, "DENIED");
35013697Ssam 			goto rmfiles;
35113697Ssam 		}
35213697Ssam 		sprintf(lbuf, "%s XQT", user);
35313697Ssam 		logent(buf, lbuf);
35413697Ssam 		DEBUG(4, "cmd %s\n", buf);
35513697Ssam 
35613697Ssam 		mvxfiles(xfile);
35733966Srick 		if (subchdir(XQTDIR) < 0) {
35833966Srick 			syslog(LOG_ERR, "chdir(%s) failed: %m", XQTDIR);
35933966Srick 			cleanup(1);
36033966Srick 		}
36118628Sralph 		ret = shio(buf, fin, dfile);
36213697Ssam 		sprintf(retstat, "signal %d, exit %d", ret & 0377,
36313697Ssam 		  (ret>>8) & 0377);
36413697Ssam 		if (strcmp(xcmd, "rmail") == SAME)
36513697Ssam 			notiok = 0;
36613697Ssam 		if (strcmp(xcmd, "rnews") == SAME)
36713697Ssam 			nonzero = 1;
36817846Sralph 		notiflg = chknotify(xcmd);
36917846Sralph 		if (notiok && notiflg != NT_NO &&
37017846Sralph 		   (ret != 0 || (!nonzero && notiflg == NT_YES)))
37113697Ssam 			notify(user, Rmtname, cmd, retstat);
37213697Ssam 		else if (ret != 0 && strcmp(xcmd, "rmail") == SAME) {
37313697Ssam 			/* mail failed - return letter to sender  */
37417846Sralph #ifdef	DANGEROUS
37517846Sralph 			/* NOT GUARANTEED SAFE!!! */
37617846Sralph 			if (!nonzero)
37717846Sralph 				retosndr(user, Rmtname, fin);
37817846Sralph #else
37917846Sralph 			notify(user, Rmtname, cmd, retstat);
38017846Sralph #endif
38117846Sralph 			sprintf(buf, "%s (%s) from %s!%s", buf, retstat, Rmtname, user);
38213697Ssam 			logent("MAIL FAIL", buf);
38313697Ssam 		}
38413697Ssam 		DEBUG(4, "exit cmd - %d\n", ret);
38533966Srick 		if (subchdir(Spool) < 0) {
38633966Srick 			syslog(LOG_ERR, "chdir(%s) failed: %m", Spool);
38733966Srick 			cleanup(1);
38833966Srick 		}
38913697Ssam 		rmxfiles(xfile);
39013697Ssam 		if (ret != 0) {
39113697Ssam 			/*  exit status not zero */
39213697Ssam 			dfp = fopen(subfile(dfile), "a");
39333966Srick 			if (dfp == NULL) {
39433966Srick 				syslog(LOG_ERR, "fopen(%s) failed: %m",
39533966Srick 					subfile(dfile));
39633966Srick 				cleanup(1);
39733966Srick 			}
39813697Ssam 			fprintf(dfp, "exit status %d", ret);
39913697Ssam 			fclose(dfp);
40013697Ssam 		}
40117846Sralph 		if (strcmp(fout, DEVNULL) != SAME) {
40213697Ssam 			if (prefix(sysout, Myname)) {
40313697Ssam 				xmv(dfile, fout);
40413697Ssam 				chmod(fout, BASEMODE);
40518628Sralph 			} else {
40617846Sralph 				char *cp = rindex(user, '!');
40713697Ssam 				gename(CMDPRE, sysout, 'O', cfile);
40813697Ssam 				fp = fopen(subfile(cfile), "w");
40933966Srick 				if (fp == NULL) {
41033966Srick 					syslog(LOG_ERR, "fopen(%s) failed: %m",
41133966Srick 						subfile(cfile));
41233966Srick 					cleanup(1);
41333966Srick 				}
41417846Sralph 				fprintf(fp, "S %s %s %s - %s 0666\n", dfile,
41517846Sralph 					fout, cp ? cp : user, lastpart(dfile));
41613697Ssam 				fclose(fp);
41713697Ssam 			}
41813697Ssam 		}
41913697Ssam 	rmfiles:
42013697Ssam 		xfp = fopen(subfile(xfile), "r");
42133966Srick 		if (xfp == NULL) {
42233966Srick 			syslog(LOG_ERR, "fopen(%s) failed: %m",
42333966Srick 				subfile(xfile));
42433966Srick 			cleanup(1);
42533966Srick 		}
42613697Ssam 		while (fgets(buf, BUFSIZ, xfp) != NULL) {
42713697Ssam 			if (buf[0] != X_RQDFILE)
42813697Ssam 				continue;
42913697Ssam 			sscanf(&buf[1], "%s", file);
43013697Ssam 			unlink(subfile(file));
43113697Ssam 		}
43213697Ssam 		unlink(subfile(xfile));
43313697Ssam 		fclose(xfp);
43418628Sralph 
43518628Sralph 		/* rescan X. for new work every RECHECKTIME seconds */
43618628Sralph 		time(&xnow);
43718628Sralph 		if (xnow > (xstart + RECHECKTIME)) {
43818628Sralph 			extern int Nfiles;
43918628Sralph 			Nfiles = 0; 	/*force rescan for new work */
44018628Sralph 		}
44118628Sralph 		xstart = xnow;
44213697Ssam 	}
44313697Ssam 
44413697Ssam 	if (stcico)
44513697Ssam 		xuucico("");
44613697Ssam 	cleanup(0);
44713697Ssam }
44813697Ssam 
44913697Ssam 
cleanup(code)45013697Ssam cleanup(code)
45113697Ssam int code;
45213697Ssam {
45313697Ssam 	logcls();
45413697Ssam 	rmlock(CNULL);
45517846Sralph #ifdef	VMS
45617846Sralph 	/*
45717846Sralph 	 *	Since we run as a BATCH job we must wait for all processes to
45817846Sralph 	 *	to finish
45917846Sralph 	 */
46018628Sralph 	while(wait(0) != -1)
46118628Sralph 		;
46217846Sralph #endif VMS
46313697Ssam 	exit(code);
46413697Ssam }
46513697Ssam 
46613697Ssam 
46718628Sralph /*
46818628Sralph  *	get a file to execute
46913697Ssam  *
47013697Ssam  *	return codes:  0 - no file  |  1 - file to execute
47113697Ssam  */
47213697Ssam 
gtxfile(file)47313697Ssam gtxfile(file)
47413697Ssam register char *file;
47513697Ssam {
47613697Ssam 	char pre[3];
47733579Srick 	register int rechecked, i;
47817846Sralph 	time_t ystrdy;		/* yesterday */
47917846Sralph 	struct stat stbuf;	/* for X file age */
48013697Ssam 
48113697Ssam 	pre[0] = XQTPRE;
48213697Ssam 	pre[1] = '.';
48313697Ssam 	pre[2] = '\0';
48413697Ssam 	rechecked = 0;
48513697Ssam retry:
48633579Srick 	if (Nfiles-- <= 0) {
48733579Srick 		Nfiles = 0;
48813697Ssam 		if (rechecked)
48917846Sralph 			return 0;
49013697Ssam 		rechecked = 1;
49117846Sralph 		DEBUG(4, "iswrk\n", CNULL);
49233579Srick 		return iswrk(file, "get", Spool, pre);
49313697Ssam 	}
49433579Srick 	sprintf(file, "%s/%s", Spool, Filent[0]);
49533579Srick 	for (i=0; i<Nfiles;i++)
49633579Srick 		strcpy(Filent[i], Filent[i+1]);
49733579Srick 
49813697Ssam 	DEBUG(4, "file - %s\n", file);
49913697Ssam 	/* skip spurious subdirectories */
50013697Ssam 	if (strcmp(pre, file) == SAME)
50113697Ssam 		goto retry;
50213697Ssam 	if (gotfiles(file))
50317846Sralph 		return 1;
50417846Sralph 	/* check for old X. file with no work files and remove them. */
50517846Sralph 	if (Nfiles > LLEN/2) {
50617846Sralph 	    time(&ystrdy);
50717846Sralph 	    ystrdy -= (4 * 3600L);		/* 4 hours ago */
50817846Sralph 	    DEBUG(4, "gtxfile: Nfiles > LLEN/2\n", CNULL);
50933579Srick 	    while (Nfiles-- > 0) {
51033579Srick 		sprintf(file, "%s/%s", Spool, Filent[0]);
51133579Srick 		for (i=0; i<Nfiles; i++)
51233579Srick 			strcpy(Filent[i], Filent[i+1]);
51333579Srick 
51433579Srick 		if (gotfiles(file))
51533579Srick 			return 1;
51617846Sralph 		if (stat(subfile(file), &stbuf) == 0)
51717846Sralph 		    if (stbuf.st_mtime <= ystrdy) {
51817846Sralph 			char *bnp, cfilename[NAMESIZE];
51917846Sralph 			DEBUG(4, "gtxfile: move %s to CORRUPT \n", file);
52033579Srick 			bnp = rindex(file, '/');
52117846Sralph 			sprintf(cfilename, "%s/%s", CORRUPT,
52233579Srick 				bnp ? bnp + 1 : file);
52333579Srick 			xmv(file, cfilename);
52433966Srick 			syslog(LOG_WARNING, "%s: X. FILE MISSING FILES", file);
52517846Sralph 		    }
52617846Sralph 	    }
52733579Srick  	    Nfiles = 0;
52817846Sralph 	    DEBUG(4, "iswrk\n", CNULL);
52917846Sralph 	    if (!iswrk(file, "get", Spool, pre))
53017846Sralph 		return 0;
53117846Sralph 	}
53213697Ssam 	goto retry;
53313697Ssam }
53413697Ssam 
53518628Sralph /*
53618628Sralph  *	check for needed files
53713697Ssam  *
53813697Ssam  *	return codes:  0 - not ready  |  1 - all files ready
53913697Ssam  */
54013697Ssam 
gotfiles(file)54113697Ssam gotfiles(file)
54213697Ssam register char *file;
54313697Ssam {
54413697Ssam 	struct stat stbuf;
54513697Ssam 	register FILE *fp;
54613697Ssam 	char buf[BUFSIZ], rqfile[MAXFULLNAME];
54713697Ssam 
54813697Ssam 	fp = fopen(subfile(file), "r");
54913697Ssam 	if (fp == NULL)
55017846Sralph 		return 0;
55113697Ssam 
55213697Ssam 	while (fgets(buf, BUFSIZ, fp) != NULL) {
55313697Ssam 		DEBUG(4, "%s\n", buf);
55413697Ssam 		if (buf[0] != X_RQDFILE)
55513697Ssam 			continue;
55613697Ssam 		sscanf(&buf[1], "%s", rqfile);
55713697Ssam 		expfile(rqfile);
55813697Ssam 		if (stat(subfile(rqfile), &stbuf) == -1) {
55913697Ssam 			fclose(fp);
56017846Sralph 			return 0;
56113697Ssam 		}
56213697Ssam 	}
56313697Ssam 
56413697Ssam 	fclose(fp);
56517846Sralph 	return 1;
56613697Ssam }
56713697Ssam 
56813697Ssam 
56918628Sralph /*
57018628Sralph  *	remove execute files to x-directory
57113697Ssam  */
57213697Ssam 
rmxfiles(xfile)57313697Ssam rmxfiles(xfile)
57413697Ssam register char *xfile;
57513697Ssam {
57613697Ssam 	register FILE *fp;
57713697Ssam 	char buf[BUFSIZ], file[NAMESIZE], tfile[NAMESIZE];
57813697Ssam 	char tfull[MAXFULLNAME];
57913697Ssam 
58013697Ssam 	if((fp = fopen(subfile(xfile), "r")) == NULL)
58113697Ssam 		return;
58213697Ssam 
58313697Ssam 	while (fgets(buf, BUFSIZ, fp) != NULL) {
58413697Ssam 		if (buf[0] != X_RQDFILE)
58513697Ssam 			continue;
58613697Ssam 		if (sscanf(&buf[1], "%s%s", file, tfile) < 2)
58713697Ssam 			continue;
58813697Ssam 		sprintf(tfull, "%s/%s", XQTDIR, tfile);
58913697Ssam 		unlink(subfile(tfull));
59013697Ssam 	}
59113697Ssam 	fclose(fp);
59213697Ssam 	return;
59313697Ssam }
59413697Ssam 
59513697Ssam 
59618628Sralph /*
59718628Sralph  *	move execute files to x-directory
59813697Ssam  */
59913697Ssam 
mvxfiles(xfile)60013697Ssam mvxfiles(xfile)
60113697Ssam char *xfile;
60213697Ssam {
60313697Ssam 	register FILE *fp;
60413697Ssam 	char buf[BUFSIZ], ffile[MAXFULLNAME], tfile[NAMESIZE];
60513697Ssam 	char tfull[MAXFULLNAME];
60613697Ssam 
60713697Ssam 	if((fp = fopen(subfile(xfile), "r")) == NULL)
60813697Ssam 		return;
60913697Ssam 
61013697Ssam 	while (fgets(buf, BUFSIZ, fp) != NULL) {
61113697Ssam 		if (buf[0] != X_RQDFILE)
61213697Ssam 			continue;
61313697Ssam 		if (sscanf(&buf[1], "%s%s", ffile, tfile) < 2)
61413697Ssam 			continue;
61513697Ssam 		expfile(ffile);
61613697Ssam 		sprintf(tfull, "%s/%s", XQTDIR, tfile);
61713697Ssam 		unlink(subfile(tfull));
61833966Srick 		if (xmv(ffile, tfull) != 0) {
61933966Srick 			syslog(LOG_WARNING, "xmv(%s,%s) failed: %m",
62033966Srick 				ffile, tfull);
62133966Srick 			cleanup(1);
62233966Srick 		}
62313697Ssam 	}
62413697Ssam 	fclose(fp);
62513697Ssam }
62613697Ssam 
62718628Sralph /*
62818628Sralph  *	check for valid command/argument
62918628Sralph  *	*NOTE - side effect is to set xc to the	command to be executed.
63013697Ssam  *
63113697Ssam  *	return 0 - ok | 1 nok
63213697Ssam  */
63313697Ssam 
argok(xc,cmd)63413697Ssam argok(xc, cmd)
63513697Ssam register char *xc, *cmd;
63613697Ssam {
63713697Ssam 	register char **ptr;
63813697Ssam 
63913697Ssam #ifndef ALLOK
64018628Sralph 	if (strpbrk(cmd, BADCHARS) != NULL) {
64117846Sralph 		DEBUG(1,"MAGIC CHARACTER FOUND\n", CNULL);
64218628Sralph 		logent(cmd, "NASTY MAGIC CHARACTER FOUND");
64317846Sralph 		return FAIL;
64417846Sralph 	}
64517846Sralph #endif !ALLOK
64613697Ssam 
64713697Ssam 	if (xc[0] != '\0')
64817846Sralph 		return SUCCESS;
64913697Ssam 
65013697Ssam #ifndef ALLOK
65113697Ssam 	ptr = Cmds;
65217846Sralph 	DEBUG(9, "Compare %s and\n", cmd);
65313697Ssam 	while(*ptr != NULL) {
65417846Sralph 		DEBUG(9, "\t%s\n", *ptr);
65513697Ssam 		if (strcmp(cmd, *ptr) == SAME)
65613697Ssam 			break;
65717846Sralph 		ptr++;
65813697Ssam 	}
65917846Sralph 	if (*ptr == NULL) {
66017846Sralph 		DEBUG(1,"COMMAND NOT FOUND\n", CNULL);
66117846Sralph 		return FAIL;
66217846Sralph 	}
66313697Ssam #endif
66413697Ssam 	strcpy(xc, cmd);
66517846Sralph 	DEBUG(9, "MATCHED %s\n", xc);
66617846Sralph 	return SUCCESS;
66713697Ssam }
66813697Ssam 
66913697Ssam 
67018628Sralph /*
67118628Sralph  *	if notification should be sent for successful execution of cmd
67217846Sralph  *
67317846Sralph  *	return NT_YES - do notification
67417846Sralph  *	       NT_ERR - do notification if exit status != 0
67517846Sralph  *	       NT_NO  - don't do notification ever
67617846Sralph  */
67717846Sralph 
chknotify(cmd)67817846Sralph chknotify(cmd)
67917846Sralph char *cmd;
68017846Sralph {
68117846Sralph 	register char **ptr;
68217846Sralph 	register int *nptr;
68317846Sralph 
68417846Sralph 	ptr = Cmds;
68517846Sralph 	nptr = Notify;
68617846Sralph 	while (*ptr != NULL) {
68717846Sralph 		if (strcmp(cmd, *ptr) == SAME)
68817846Sralph 			return *nptr;
68917846Sralph 		ptr++;
69017846Sralph 		nptr++;
69117846Sralph 	}
69217846Sralph 	return NT_YES;		/* "shouldn't happen" */
69317846Sralph }
69417846Sralph 
69517846Sralph 
69617846Sralph 
69718628Sralph /*
69818628Sralph  *	send mail to user giving execution results
69913697Ssam  */
70013697Ssam 
notify(user,rmt,cmd,str)70113697Ssam notify(user, rmt, cmd, str)
70213697Ssam char *user, *rmt, *cmd, *str;
70313697Ssam {
70433579Srick 	char text[BUFSIZ*2];
70513697Ssam 	char ruser[MAXFULLNAME];
70613697Ssam 
70725968Sbloom 	if (strpbrk(user, BADCHARS) != NULL) {
70825968Sbloom 		char lbuf[MAXFULLNAME];
70925968Sbloom 		sprintf(lbuf, "%s INVALID CHARACTER IN USERNAME", user);
71025968Sbloom 		logent(cmd, lbuf);
71125968Sbloom 		strcpy(user, "postmaster");
71225968Sbloom 	}
71317846Sralph 	sprintf(text, "uuxqt cmd (%s) status (%s)", cmd, str);
71413697Ssam 	if (prefix(rmt, Myname))
71513697Ssam 		strcpy(ruser, user);
71613697Ssam 	else
71713697Ssam 		sprintf(ruser, "%s!%s", rmt, user);
71817846Sralph 	mailst(ruser, text, CNULL);
71913697Ssam }
72013697Ssam 
72118628Sralph /*
72218628Sralph  *	return mail to sender
72313697Ssam  *
72413697Ssam  */
retosndr(user,rmt,file)72513697Ssam retosndr(user, rmt, file)
72613697Ssam char *user, *rmt, *file;
72713697Ssam {
72817846Sralph 	char ruser[MAXFULLNAME];
72913697Ssam 
73025968Sbloom 	if (strpbrk(user, BADCHARS) != NULL) {
73125968Sbloom 		char lbuf[MAXFULLNAME];
73225968Sbloom 		sprintf(lbuf, "%s INVALID CHARACTER IN USERNAME", user);
73325968Sbloom 		logent(file, lbuf);
73425968Sbloom 		strcpy(user, "postmaster");
73525968Sbloom 	}
73613697Ssam 	if (strcmp(rmt, Myname) == SAME)
73713697Ssam 		strcpy(ruser, user);
73813697Ssam 	else
73913697Ssam 		sprintf(ruser, "%s!%s", rmt, user);
74013697Ssam 
74113697Ssam 	if (anyread(file) == 0)
74213697Ssam 		mailst(ruser, "Mail failed.  Letter returned to sender.\n", file);
74313697Ssam 	else
74417846Sralph 		mailst(ruser, "Mail failed.  Letter returned to sender.\n", CNULL);
74513697Ssam 	return;
74613697Ssam }
74717870Sralph 
74817870Sralph /*
74918628Sralph  *	execute shell of command with fi and fo as standard input/output
75018628Sralph  */
75118628Sralph 
shio(cmd,fi,fo)75218628Sralph shio(cmd, fi, fo)
75318628Sralph char *cmd, *fi, *fo;
75418628Sralph {
75518628Sralph 	int status, f;
75633966Srick 	int pid, ret;
75733579Srick 	char *args[256];
75818628Sralph 	extern int errno;
75918628Sralph 
76018628Sralph 	if (fi == NULL)
76118628Sralph 		fi = DEVNULL;
76218628Sralph 	if (fo == NULL)
76318628Sralph 		fo = DEVNULL;
76418628Sralph 
76533579Srick 	getargs(cmd, args, 256);
76618628Sralph 	DEBUG(3, "shio - %s\n", cmd);
76718628Sralph #ifdef SIGCHLD
76818628Sralph 	signal(SIGCHLD, SIG_IGN);
76918628Sralph #endif SIGCHLD
77018628Sralph 	if ((pid = fork()) == 0) {
77118628Sralph 		signal(SIGINT, SIG_IGN);
77218628Sralph 		signal(SIGHUP, SIG_IGN);
77318628Sralph 		signal(SIGQUIT, SIG_IGN);
77418628Sralph 		close(Ifn);
77518628Sralph 		close(Ofn);
77618628Sralph 		close(0);
77718628Sralph 		setuid(getuid());
77818628Sralph 		f = open(subfile(fi), 0);
77918628Sralph 		if (f != 0) {
78018628Sralph 			logent(fi, "CAN'T READ");
78118628Sralph 			exit(-errno);
78218628Sralph 		}
78318628Sralph 		close(1);
78418628Sralph 		f = creat(subfile(fo), 0666);
78518628Sralph 		if (f != 1) {
78618628Sralph 			logent(fo, "CAN'T WRITE");
78718628Sralph 			exit(-errno);
78818628Sralph 		}
78918628Sralph 		execvp(args[0], args);
79018628Sralph 		exit(100+errno);
79118628Sralph 	}
79218628Sralph 	while ((ret = wait(&status)) != pid && ret != -1)
79318628Sralph 		;
79418628Sralph 	DEBUG(3, "status %d\n", status);
79518628Sralph 	return status;
79618628Sralph }
797