xref: /original-bsd/usr.bin/uucp/uuxqt/uuxqt.c (revision ec71041f)
144e19819Sbostic /*-
2*ec71041fSbostic  * Copyright (c) 1985, 1988, 1993
3*ec71041fSbostic  *	The Regents of the University of California.  All rights reserved.
444e19819Sbostic  *
544e19819Sbostic  * %sccs.include.proprietary.c%
644e19819Sbostic  */
744e19819Sbostic 
852081424Ssam #ifndef lint
9*ec71041fSbostic static char copyright[] =
10*ec71041fSbostic "@(#) Copyright (c) 1985, 1988, 1993\n\
11*ec71041fSbostic 	The Regents of the University of California.  All rights reserved.\n";
1244e19819Sbostic #endif /* not lint */
1344e19819Sbostic 
1444e19819Sbostic #ifndef lint
15*ec71041fSbostic static char sccsid[] = "@(#)uuxqt.c	8.1 (Berkeley) 06/06/93";
1644e19819Sbostic #endif /* not lint */
1752081424Ssam 
1852081424Ssam #include "uucp.h"
1952081424Ssam #include <sys/stat.h>
2052081424Ssam #ifdef	NDIR
2152081424Ssam #include "ndir.h"
2252081424Ssam #else
23109b7051Ssam #include <sys/dir.h>
2452081424Ssam #endif
25e21537dbSralph #include <signal.h>
2652081424Ssam 
272f96a7e7Sralph #define BADCHARS	"&^|(`\\<>;\"{}\n'"
282f96a7e7Sralph #define RECHECKTIME	60*10	/* 10 minutes */
29dbb6249cSralph 
3052081424Ssam #define APPCMD(d) {\
3152081424Ssam char *p;\
32e21537dbSralph for (p = d; *p != '\0';) *cmdp++ = *p++; *cmdp++ = ' '; *cmdp = '\0';}
3352081424Ssam 
342bba3b8bSrick extern char Filent[LLEN][NAMESIZE];
352bba3b8bSrick 
3652081424Ssam /*
3752081424Ssam  *	uuxqt will execute commands set up by a uux command,
3852081424Ssam  *	usually from a remote machine - set by uucp.
3952081424Ssam  */
4052081424Ssam 
4152081424Ssam #define	NCMDS	50
42e21537dbSralph char *Cmds[NCMDS+1];
43e21537dbSralph int Notify[NCMDS+1];
44e21537dbSralph #define	NT_YES	0	/* if should notify on execution */
45e21537dbSralph #define	NT_ERR	1	/* if should notify if non-zero exit status (-z equivalent) */
46e21537dbSralph #define	NT_NO	2	/* if should not notify ever (-n equivalent) */
47e21537dbSralph 
48e21537dbSralph extern int Nfiles;
4952081424Ssam 
502f96a7e7Sralph int TransferSucceeded = 1;
5152081424Ssam int notiok = 1;
5252081424Ssam int nonzero = 0;
5352081424Ssam 
5498a5b756Sbloom struct timeb Now;
5598a5b756Sbloom 
56290a350eStrent char PATH[MAXFULLNAME] = "PATH=/bin:/usr/bin";
572cbba08fSrick char UU_MACHINE[MAXFULLNAME];
582f96a7e7Sralph char Shell[MAXFULLNAME];
592f96a7e7Sralph char HOME[MAXFULLNAME];
602f96a7e7Sralph 
612f96a7e7Sralph extern char **environ;
622f96a7e7Sralph char *nenv[] = {
632f96a7e7Sralph 	PATH,
642f96a7e7Sralph 	Shell,
652f96a7e7Sralph 	HOME,
662cbba08fSrick 	UU_MACHINE,
672f96a7e7Sralph 	0
682f96a7e7Sralph };
692f96a7e7Sralph 
7052081424Ssam /*  to remove restrictions from uuxqt
7152081424Ssam  *  define ALLOK 1
7252081424Ssam  *
7352081424Ssam  *  to add allowable commands, add to the file CMDFILE
7452081424Ssam  *  A line of form "PATH=..." changes the search path
7552081424Ssam  */
main(argc,argv)7652081424Ssam main(argc, argv)
7752081424Ssam char *argv[];
7852081424Ssam {
792bba3b8bSrick 	char xcmd[BUFSIZ*2];
8052081424Ssam 	int argnok;
81e21537dbSralph 	int notiflg;
822bba3b8bSrick 	char xfile[MAXFULLNAME], user[MAXFULLNAME], buf[BUFSIZ*2];
83e21537dbSralph 	char lbuf[MAXFULLNAME];
8452081424Ssam 	char cfile[NAMESIZE], dfile[MAXFULLNAME];
8552081424Ssam 	char file[NAMESIZE];
8652081424Ssam 	char fin[MAXFULLNAME], sysout[NAMESIZE], fout[MAXFULLNAME];
8752081424Ssam 	register FILE *xfp, *fp;
8852081424Ssam 	FILE *dfp;
8952081424Ssam 	char path[MAXFULLNAME];
902bba3b8bSrick 	char cmd[BUFSIZ*2];
9152081424Ssam 	char *cmdp, prm[1000], *ptr;
9252081424Ssam 	char *getprm(), *lastpart();
932cbba08fSrick 	int uid, ret, badfiles;
9452081424Ssam 	register int i;
9552081424Ssam 	int stcico = 0;
962f96a7e7Sralph 	time_t xstart, xnow;
9752081424Ssam 	char retstat[30];
982cbba08fSrick 	extern char *optarg;
992cbba08fSrick 	extern int optind;
10052081424Ssam 
10152081424Ssam 	strcpy(Progname, "uuxqt");
10252081424Ssam 	uucpname(Myname);
103f2386554Srick 	strcpy(Rmtname, Myname);
10452081424Ssam 
10552081424Ssam 	umask(WFMASK);
10652081424Ssam 	Ofn = 1;
10752081424Ssam 	Ifn = 0;
1082cbba08fSrick 	while ((i = getopt(argc, argv, "x:S:")) != EOF)
1092cbba08fSrick 		switch(i) {
11052081424Ssam 		case 'x':
111e21537dbSralph 			chkdebug();
1122cbba08fSrick 			Debug = atoi(optarg);
11352081424Ssam 			if (Debug <= 0)
11452081424Ssam 				Debug = 1;
11552081424Ssam 			break;
1162bba3b8bSrick 		case 'S':
1172cbba08fSrick 			Spool = optarg;
1182bba3b8bSrick 			DEBUG(1, "Spool set to %s", Spool);
1192bba3b8bSrick 			break;
1202cbba08fSrick 		case '?':
12152081424Ssam 		default:
1222cbba08fSrick 			fprintf(stderr, "unknown flag %s\n", argv[optind-1]);
12352081424Ssam 				break;
12452081424Ssam 		}
12552081424Ssam 
1262f96a7e7Sralph 	DEBUG(4, "\n\n** START **\n", CNULL);
1272cbba08fSrick 	if (subchdir(Spool) < 0) {
1282cbba08fSrick 		syslog(LOG_WARNING, "chdir(%s) failed: %m", Spool);
1292cbba08fSrick 		cleanup(1);
1302cbba08fSrick 	}
13152081424Ssam 	strcpy(Wrkdir, Spool);
13252081424Ssam 	uid = getuid();
1332bba3b8bSrick 	if (guinfo(uid, User, path) != SUCCESS) {
1342cbba08fSrick 		syslog(LOG_WARNING, "Can't find username for uid %d", uid);
1352bba3b8bSrick 		DEBUG(1, "Using username", "uucp");
1362bba3b8bSrick 		strcpy(User, "uucp");
1372bba3b8bSrick 	}
138e21537dbSralph 	setgid(getegid());
139e21537dbSralph 	setuid(geteuid());
140e21537dbSralph 
14152081424Ssam 	DEBUG(4, "User - %s\n", User);
1421a575e59Sbloom 	if (ulockf(X_LOCK, X_LOCKTIME) != 0)
14352081424Ssam 		exit(0);
14452081424Ssam 
14552081424Ssam 	fp = fopen(CMDFILE, "r");
14652081424Ssam 	if (fp == NULL) {
147e21537dbSralph 		logent(CANTOPEN, CMDFILE);
14852081424Ssam 		Cmds[0] = "rmail";
14952081424Ssam 		Cmds[1] = "rnews";
15052081424Ssam 		Cmds[2] = "ruusend";
15152081424Ssam 		Cmds[3] = NULL;
15252081424Ssam 		goto doprocess;
15352081424Ssam 	}
15452081424Ssam 	DEBUG(5, "%s opened\n", CMDFILE);
155e21537dbSralph 	for (i=0; i<NCMDS && cfgets(xcmd, sizeof(xcmd), fp) != NULL; i++) {
156e21537dbSralph 		int j;
157e21537dbSralph 		/* strip trailing whitespace */
158e21537dbSralph 		for (j = strlen(xcmd)-1; j >= 0; --j)
159e21537dbSralph 			if (xcmd[j] == '\n' || xcmd[j] == ' ' || xcmd[j] == '\t')
160e21537dbSralph 				xcmd[j] = '\0';
161e21537dbSralph 			else
162e21537dbSralph 				break;
163e21537dbSralph 		/* look for imbedded whitespace */
164e21537dbSralph 		for (; j >= 0; --j)
165e21537dbSralph 			if (xcmd[j] == '\n' || xcmd[j] == ' ' || xcmd[j] == '\t')
166e21537dbSralph 				break;
167e21537dbSralph 		/* skip this entry if it has embedded whitespace */
168e21537dbSralph 		/* This defends against a bad PATH=, for example */
169e21537dbSralph 		if (j >= 0) {
170e21537dbSralph 			logent(xcmd, "BAD WHITESPACE");
171e21537dbSralph 			continue;
172e21537dbSralph 		}
17352081424Ssam 		if (strncmp(xcmd, "PATH=", 5) == 0) {
17452081424Ssam 			strcpy(PATH, xcmd);
17552081424Ssam 			i--;	/*kludge */
17652081424Ssam 			continue;
17752081424Ssam 		}
17852081424Ssam 		DEBUG(5, "xcmd = %s\n", xcmd);
179e21537dbSralph 
180e21537dbSralph 		if ((ptr = index(xcmd, ',')) != NULL) {
181e21537dbSralph 			*ptr++ = '\0';
182e21537dbSralph 			if (strncmp(ptr, "Err", 3) == SAME)
183e21537dbSralph 				Notify[i] = NT_ERR;
184e21537dbSralph 			else if (strcmp(ptr, "No") == SAME)
185e21537dbSralph 				Notify[i] = NT_NO;
186e21537dbSralph 			else
187e21537dbSralph 				Notify[i] = NT_YES;
188e21537dbSralph 		} else
189e21537dbSralph 			Notify[i] = NT_YES;
190e21537dbSralph 		if ((Cmds[i] = malloc((unsigned)(strlen(xcmd)+1))) == NULL) {
191e21537dbSralph 			DEBUG(1, "MALLOC FAILED", CNULL);
192e21537dbSralph 			break;
193e21537dbSralph 		}
19452081424Ssam 		strcpy(Cmds[i], xcmd);
19552081424Ssam 	}
196e21537dbSralph 	Cmds[i] = CNULL;
19752081424Ssam 	fclose(fp);
19852081424Ssam 
19952081424Ssam doprocess:
2002f96a7e7Sralph 
2012f96a7e7Sralph 	(void) sprintf(HOME, "HOME=%s", Spool);
2022f96a7e7Sralph 	(void) sprintf(Shell, "SHELL=%s", SHELL);
2032f96a7e7Sralph 	environ = nenv; /* force use if our environment */
2042f96a7e7Sralph 
2052f96a7e7Sralph 	DEBUG(11,"path = %s\n", getenv("PATH"));
2062f96a7e7Sralph 
207e21537dbSralph 	DEBUG(4, "process %s\n", CNULL);
2082bba3b8bSrick 
2092f96a7e7Sralph 	time(&xstart);
21052081424Ssam 	while (gtxfile(xfile) > 0) {
211e21537dbSralph 		/* if /etc/nologin exists, exit cleanly */
21298a5b756Sbloom #if defined(BSD4_2) || defined(USG)
21398a5b756Sbloom 		if (access(NOLOGIN) == 0) {
21498a5b756Sbloom #else !BSD4_2 && ! USG
21598a5b756Sbloom 		ultouch();
216e21537dbSralph 		if (nologinflag) {
21798a5b756Sbloom #endif !BSD4_2 && !USG
218e21537dbSralph 			logent(NOLOGIN, "UUXQT SHUTDOWN");
219e21537dbSralph 			if (Debug)
220e21537dbSralph 				logent("debugging", "continuing anyway");
221e21537dbSralph 			else
222e21537dbSralph 				break;
223e21537dbSralph 		}
22452081424Ssam 		DEBUG(4, "xfile - %s\n", xfile);
22552081424Ssam 
22652081424Ssam 		xfp = fopen(subfile(xfile), "r");
2272cbba08fSrick 		if (xfp == NULL) {
2282cbba08fSrick 			syslog(LOG_ERR, "fopen(%s) failed: %m", subfile(xfile));
2292cbba08fSrick 			cleanup(1);
2302cbba08fSrick 		}
23152081424Ssam 
23252081424Ssam 		/*  initialize to default  */
23352081424Ssam 		strcpy(user, User);
234e21537dbSralph 		strcpy(fin, DEVNULL);
235e21537dbSralph 		strcpy(fout, DEVNULL);
2361a575e59Sbloom 		strcpy(sysout, Myname);
237e21537dbSralph 		badfiles = 0;
23852081424Ssam 		while (fgets(buf, BUFSIZ, xfp) != NULL) {
2392bba3b8bSrick 			if(buf[0] != '\0' && buf[0] != '#' &&
2402bba3b8bSrick 			    buf[1] != ' ' && buf[1] != '\0' && buf[1] != '\n') {
2412bba3b8bSrick 				char *bnp, cfilename[BUFSIZ];
2422bba3b8bSrick 				DEBUG(4, "uuxqt: buf = %s\n", buf);
2432bba3b8bSrick 				bnp = rindex(xfile, '/');
2442bba3b8bSrick 				sprintf(cfilename, "%s/%s", CORRUPT,
2452bba3b8bSrick 					bnp ? bnp + 1 : xfile);
2462bba3b8bSrick 				DEBUG(4, "uuxqt: move %s to ", xfile);
2472bba3b8bSrick 				DEBUG(4, "%s\n", cfilename);
2482bba3b8bSrick 				xmv(xfile, cfilename);
249a92c1dbeSrick 				syslog(LOG_WARNING, "%s: X. FILE CORRUPTED",
250a92c1dbeSrick 					xfile);
2512bba3b8bSrick 				fclose(xfp);
2522bba3b8bSrick 				goto doprocess;
2532bba3b8bSrick 			}
25452081424Ssam 			switch (buf[0]) {
255a92c1dbeSrick 			case X_USER: {
256a92c1dbeSrick 				char ORmtname[MAXFULLNAME];
257a92c1dbeSrick 				strcpy(ORmtname, Rmtname);
25852081424Ssam 				sscanf(&buf[1], "%s %s", user, Rmtname);
2592cbba08fSrick 				sprintf(UU_MACHINE, "UU_MACHINE=%s", Rmtname);
260a92c1dbeSrick 				if (strcmp(ORmtname, Rmtname) != 0)
261a92c1dbeSrick 					logcls();
262a92c1dbeSrick 				break;}
263e21537dbSralph 			case X_RETURNTO:
264e21537dbSralph 				sscanf(&buf[1], "%s", user);
265e21537dbSralph 				break;
26652081424Ssam 			case X_STDIN:
26752081424Ssam 				sscanf(&buf[1], "%s", fin);
26852081424Ssam 				i = expfile(fin);
26952081424Ssam 				/* rti!trt: do not check permissions of
27052081424Ssam 				 * vanilla spool file */
27152081424Ssam 				if (i != 0
27252081424Ssam 				 && (chkpth("", "", fin) || anyread(fin) != 0))
27352081424Ssam 					badfiles = 1;
27452081424Ssam 				break;
27552081424Ssam 			case X_STDOUT:
27652081424Ssam 				sscanf(&buf[1], "%s%s", fout, sysout);
2771a575e59Sbloom 				sysout[MAXBASENAME] = '\0';
27852081424Ssam 				/* rti!trt: do not check permissions of
27952081424Ssam 				 * vanilla spool file.  DO check permissions
28052081424Ssam 				 * of writing on a non-vanilla file */
28152081424Ssam 				i = 1;
28252081424Ssam 				if (fout[0] != '~' || prefix(sysout, Myname))
28352081424Ssam 					i = expfile(fout);
28452081424Ssam 				if (i != 0
28552081424Ssam 				 && (chkpth("", "", fout)
28652081424Ssam 					|| chkperm(fout, (char *)1)))
28752081424Ssam 					badfiles = 1;
28852081424Ssam 				break;
28952081424Ssam 			case X_CMD:
29052081424Ssam 				strcpy(cmd, &buf[2]);
29152081424Ssam 				if (*(cmd + strlen(cmd) - 1) == '\n')
29252081424Ssam 					*(cmd + strlen(cmd) - 1) = '\0';
29352081424Ssam 				break;
29452081424Ssam 			case X_NONOTI:
29552081424Ssam 				notiok = 0;
29652081424Ssam 				break;
29752081424Ssam 			case X_NONZERO:
29852081424Ssam 				nonzero = 1;
29952081424Ssam 				break;
30052081424Ssam 			default:
30152081424Ssam 				break;
30252081424Ssam 			}
30352081424Ssam 		}
30452081424Ssam 
30552081424Ssam 		fclose(xfp);
30652081424Ssam 		DEBUG(4, "fin - %s, ", fin);
30752081424Ssam 		DEBUG(4, "fout - %s, ", fout);
30852081424Ssam 		DEBUG(4, "sysout - %s, ", sysout);
30952081424Ssam 		DEBUG(4, "user - %s\n", user);
31052081424Ssam 		DEBUG(4, "cmd - %s\n", cmd);
31152081424Ssam 
31252081424Ssam 		/*  command execution  */
313e21537dbSralph 		if (strcmp(fout, DEVNULL) == SAME)
314e21537dbSralph 			strcpy(dfile,DEVNULL);
31552081424Ssam 		else
31652081424Ssam 			gename(DATAPRE, sysout, 'O', dfile);
31752081424Ssam 
31852081424Ssam 		/* expand file names where necessary */
31952081424Ssam 		expfile(dfile);
3202f96a7e7Sralph 		cmdp = buf;
32152081424Ssam 		ptr = cmd;
32252081424Ssam 		xcmd[0] = '\0';
32352081424Ssam 		argnok = 0;
32452081424Ssam 		while ((ptr = getprm(ptr, prm)) != NULL) {
32552081424Ssam 			if (prm[0] == ';' || prm[0] == '^'
32652081424Ssam 			  || prm[0] == '&'  || prm[0] == '|') {
32752081424Ssam 				xcmd[0] = '\0';
32852081424Ssam 				APPCMD(prm);
32952081424Ssam 				continue;
33052081424Ssam 			}
33152081424Ssam 
332e21537dbSralph 			if ((argnok = argok(xcmd, prm)) != SUCCESS)
33352081424Ssam 				/*  command not valid  */
33452081424Ssam 				break;
33552081424Ssam 
33652081424Ssam 			if (prm[0] == '~')
33752081424Ssam 				expfile(prm);
33852081424Ssam 			APPCMD(prm);
33952081424Ssam 		}
340e21537dbSralph 		/*
341e21537dbSralph 		 * clean up trailing ' ' in command.
342e21537dbSralph 		 */
343e21537dbSralph 		if (cmdp > buf && cmdp[0] == '\0' && cmdp[-1] == ' ')
344e21537dbSralph 			*--cmdp = '\0';
34552081424Ssam 		if (argnok || badfiles) {
34652081424Ssam 			sprintf(lbuf, "%s XQT DENIED", user);
34752081424Ssam 			logent(cmd, lbuf);
34852081424Ssam 			DEBUG(4, "bad command %s\n", prm);
34952081424Ssam 			notify(user, Rmtname, cmd, "DENIED");
35052081424Ssam 			goto rmfiles;
35152081424Ssam 		}
35252081424Ssam 		sprintf(lbuf, "%s XQT", user);
35352081424Ssam 		logent(buf, lbuf);
35452081424Ssam 		DEBUG(4, "cmd %s\n", buf);
35552081424Ssam 
35652081424Ssam 		mvxfiles(xfile);
3572cbba08fSrick 		if (subchdir(XQTDIR) < 0) {
3582cbba08fSrick 			syslog(LOG_ERR, "chdir(%s) failed: %m", XQTDIR);
3592cbba08fSrick 			cleanup(1);
3602cbba08fSrick 		}
3612f96a7e7Sralph 		ret = shio(buf, fin, dfile);
36252081424Ssam 		sprintf(retstat, "signal %d, exit %d", ret & 0377,
36352081424Ssam 		  (ret>>8) & 0377);
36452081424Ssam 		if (strcmp(xcmd, "rmail") == SAME)
36552081424Ssam 			notiok = 0;
36652081424Ssam 		if (strcmp(xcmd, "rnews") == SAME)
36752081424Ssam 			nonzero = 1;
368e21537dbSralph 		notiflg = chknotify(xcmd);
369e21537dbSralph 		if (notiok && notiflg != NT_NO &&
370e21537dbSralph 		   (ret != 0 || (!nonzero && notiflg == NT_YES)))
37152081424Ssam 			notify(user, Rmtname, cmd, retstat);
37252081424Ssam 		else if (ret != 0 && strcmp(xcmd, "rmail") == SAME) {
37352081424Ssam 			/* mail failed - return letter to sender  */
374e21537dbSralph #ifdef	DANGEROUS
375e21537dbSralph 			/* NOT GUARANTEED SAFE!!! */
376e21537dbSralph 			if (!nonzero)
37752081424Ssam 				retosndr(user, Rmtname, fin);
378e21537dbSralph #else
379e21537dbSralph 			notify(user, Rmtname, cmd, retstat);
380e21537dbSralph #endif
381e21537dbSralph 			sprintf(buf, "%s (%s) from %s!%s", buf, retstat, Rmtname, user);
38252081424Ssam 			logent("MAIL FAIL", buf);
38352081424Ssam 		}
38452081424Ssam 		DEBUG(4, "exit cmd - %d\n", ret);
3852cbba08fSrick 		if (subchdir(Spool) < 0) {
3862cbba08fSrick 			syslog(LOG_ERR, "chdir(%s) failed: %m", Spool);
3872cbba08fSrick 			cleanup(1);
3882cbba08fSrick 		}
38952081424Ssam 		rmxfiles(xfile);
39052081424Ssam 		if (ret != 0) {
39152081424Ssam 			/*  exit status not zero */
39252081424Ssam 			dfp = fopen(subfile(dfile), "a");
3932cbba08fSrick 			if (dfp == NULL) {
3942cbba08fSrick 				syslog(LOG_ERR, "fopen(%s) failed: %m",
3952cbba08fSrick 					subfile(dfile));
3962cbba08fSrick 				cleanup(1);
3972cbba08fSrick 			}
39852081424Ssam 			fprintf(dfp, "exit status %d", ret);
39952081424Ssam 			fclose(dfp);
40052081424Ssam 		}
401e21537dbSralph 		if (strcmp(fout, DEVNULL) != SAME) {
40252081424Ssam 			if (prefix(sysout, Myname)) {
40352081424Ssam 				xmv(dfile, fout);
40452081424Ssam 				chmod(fout, BASEMODE);
4052f96a7e7Sralph 			} else {
406e21537dbSralph 				char *cp = rindex(user, '!');
40752081424Ssam 				gename(CMDPRE, sysout, 'O', cfile);
40852081424Ssam 				fp = fopen(subfile(cfile), "w");
4092cbba08fSrick 				if (fp == NULL) {
4102cbba08fSrick 					syslog(LOG_ERR, "fopen(%s) failed: %m",
4112cbba08fSrick 						subfile(cfile));
4122cbba08fSrick 					cleanup(1);
4132cbba08fSrick 				}
414e21537dbSralph 				fprintf(fp, "S %s %s %s - %s 0666\n", dfile,
415e21537dbSralph 					fout, cp ? cp : user, lastpart(dfile));
41652081424Ssam 				fclose(fp);
41752081424Ssam 			}
41852081424Ssam 		}
41952081424Ssam 	rmfiles:
42052081424Ssam 		xfp = fopen(subfile(xfile), "r");
4212cbba08fSrick 		if (xfp == NULL) {
4222cbba08fSrick 			syslog(LOG_ERR, "fopen(%s) failed: %m",
4232cbba08fSrick 				subfile(xfile));
4242cbba08fSrick 			cleanup(1);
4252cbba08fSrick 		}
42652081424Ssam 		while (fgets(buf, BUFSIZ, xfp) != NULL) {
42752081424Ssam 			if (buf[0] != X_RQDFILE)
42852081424Ssam 				continue;
42952081424Ssam 			sscanf(&buf[1], "%s", file);
43052081424Ssam 			unlink(subfile(file));
43152081424Ssam 		}
43252081424Ssam 		unlink(subfile(xfile));
43352081424Ssam 		fclose(xfp);
4342f96a7e7Sralph 
4352f96a7e7Sralph 		/* rescan X. for new work every RECHECKTIME seconds */
4362f96a7e7Sralph 		time(&xnow);
4372f96a7e7Sralph 		if (xnow > (xstart + RECHECKTIME)) {
4382f96a7e7Sralph 			extern int Nfiles;
4392f96a7e7Sralph 			Nfiles = 0; 	/*force rescan for new work */
4402f96a7e7Sralph 		}
4412f96a7e7Sralph 		xstart = xnow;
44252081424Ssam 	}
44352081424Ssam 
44452081424Ssam 	if (stcico)
44552081424Ssam 		xuucico("");
44652081424Ssam 	cleanup(0);
44752081424Ssam }
44852081424Ssam 
44952081424Ssam 
cleanup(code)45052081424Ssam cleanup(code)
45152081424Ssam int code;
45252081424Ssam {
45352081424Ssam 	logcls();
45452081424Ssam 	rmlock(CNULL);
455e21537dbSralph #ifdef	VMS
456e21537dbSralph 	/*
457e21537dbSralph 	 *	Since we run as a BATCH job we must wait for all processes to
458e21537dbSralph 	 *	to finish
459e21537dbSralph 	 */
4602f96a7e7Sralph 	while(wait(0) != -1)
4612f96a7e7Sralph 		;
462e21537dbSralph #endif VMS
46352081424Ssam 	exit(code);
46452081424Ssam }
46552081424Ssam 
46652081424Ssam 
4672f96a7e7Sralph /*
4682f96a7e7Sralph  *	get a file to execute
46952081424Ssam  *
47052081424Ssam  *	return codes:  0 - no file  |  1 - file to execute
47152081424Ssam  */
47252081424Ssam 
gtxfile(file)47352081424Ssam gtxfile(file)
47452081424Ssam register char *file;
47552081424Ssam {
47652081424Ssam 	char pre[3];
4772bba3b8bSrick 	register int rechecked, i;
478e21537dbSralph 	time_t ystrdy;		/* yesterday */
479e21537dbSralph 	struct stat stbuf;	/* for X file age */
48052081424Ssam 
48152081424Ssam 	pre[0] = XQTPRE;
48252081424Ssam 	pre[1] = '.';
48352081424Ssam 	pre[2] = '\0';
48452081424Ssam 	rechecked = 0;
48552081424Ssam retry:
4862bba3b8bSrick 	if (Nfiles-- <= 0) {
4872bba3b8bSrick 		Nfiles = 0;
48852081424Ssam 		if (rechecked)
489e21537dbSralph 			return 0;
49052081424Ssam 		rechecked = 1;
491e21537dbSralph 		DEBUG(4, "iswrk\n", CNULL);
4922bba3b8bSrick 		return iswrk(file, "get", Spool, pre);
49352081424Ssam 	}
4942bba3b8bSrick 	sprintf(file, "%s/%s", Spool, Filent[0]);
4952bba3b8bSrick 	for (i=0; i<Nfiles;i++)
4962bba3b8bSrick 		strcpy(Filent[i], Filent[i+1]);
4972bba3b8bSrick 
49852081424Ssam 	DEBUG(4, "file - %s\n", file);
49952081424Ssam 	/* skip spurious subdirectories */
50052081424Ssam 	if (strcmp(pre, file) == SAME)
50152081424Ssam 		goto retry;
50252081424Ssam 	if (gotfiles(file))
503e21537dbSralph 		return 1;
504e21537dbSralph 	/* check for old X. file with no work files and remove them. */
505e21537dbSralph 	if (Nfiles > LLEN/2) {
506e21537dbSralph 	    time(&ystrdy);
507e21537dbSralph 	    ystrdy -= (4 * 3600L);		/* 4 hours ago */
508e21537dbSralph 	    DEBUG(4, "gtxfile: Nfiles > LLEN/2\n", CNULL);
5092bba3b8bSrick 	    while (Nfiles-- > 0) {
5102bba3b8bSrick 		sprintf(file, "%s/%s", Spool, Filent[0]);
5112bba3b8bSrick 		for (i=0; i<Nfiles; i++)
5122bba3b8bSrick 			strcpy(Filent[i], Filent[i+1]);
5132bba3b8bSrick 
5142bba3b8bSrick 		if (gotfiles(file))
5152bba3b8bSrick 			return 1;
516e21537dbSralph 		if (stat(subfile(file), &stbuf) == 0)
517e21537dbSralph 		    if (stbuf.st_mtime <= ystrdy) {
518e21537dbSralph 			char *bnp, cfilename[NAMESIZE];
519e21537dbSralph 			DEBUG(4, "gtxfile: move %s to CORRUPT \n", file);
5202bba3b8bSrick 			bnp = rindex(file, '/');
521e21537dbSralph 			sprintf(cfilename, "%s/%s", CORRUPT,
5222bba3b8bSrick 				bnp ? bnp + 1 : file);
5232bba3b8bSrick 			xmv(file, cfilename);
5242cbba08fSrick 			syslog(LOG_WARNING, "%s: X. FILE MISSING FILES", file);
525e21537dbSralph 		    }
526e21537dbSralph 	    }
5272bba3b8bSrick  	    Nfiles = 0;
528e21537dbSralph 	    DEBUG(4, "iswrk\n", CNULL);
529e21537dbSralph 	    if (!iswrk(file, "get", Spool, pre))
530e21537dbSralph 		return 0;
531e21537dbSralph 	}
53252081424Ssam 	goto retry;
53352081424Ssam }
53452081424Ssam 
5352f96a7e7Sralph /*
5362f96a7e7Sralph  *	check for needed files
53752081424Ssam  *
53852081424Ssam  *	return codes:  0 - not ready  |  1 - all files ready
53952081424Ssam  */
54052081424Ssam 
gotfiles(file)54152081424Ssam gotfiles(file)
54252081424Ssam register char *file;
54352081424Ssam {
54452081424Ssam 	struct stat stbuf;
54552081424Ssam 	register FILE *fp;
54652081424Ssam 	char buf[BUFSIZ], rqfile[MAXFULLNAME];
54752081424Ssam 
54852081424Ssam 	fp = fopen(subfile(file), "r");
54952081424Ssam 	if (fp == NULL)
550e21537dbSralph 		return 0;
55152081424Ssam 
55252081424Ssam 	while (fgets(buf, BUFSIZ, fp) != NULL) {
55352081424Ssam 		DEBUG(4, "%s\n", buf);
55452081424Ssam 		if (buf[0] != X_RQDFILE)
55552081424Ssam 			continue;
55652081424Ssam 		sscanf(&buf[1], "%s", rqfile);
55752081424Ssam 		expfile(rqfile);
55852081424Ssam 		if (stat(subfile(rqfile), &stbuf) == -1) {
55952081424Ssam 			fclose(fp);
560e21537dbSralph 			return 0;
56152081424Ssam 		}
56252081424Ssam 	}
56352081424Ssam 
56452081424Ssam 	fclose(fp);
565e21537dbSralph 	return 1;
56652081424Ssam }
56752081424Ssam 
56852081424Ssam 
5692f96a7e7Sralph /*
5702f96a7e7Sralph  *	remove execute files to x-directory
57152081424Ssam  */
57252081424Ssam 
rmxfiles(xfile)57352081424Ssam rmxfiles(xfile)
57452081424Ssam register char *xfile;
57552081424Ssam {
57652081424Ssam 	register FILE *fp;
57752081424Ssam 	char buf[BUFSIZ], file[NAMESIZE], tfile[NAMESIZE];
57852081424Ssam 	char tfull[MAXFULLNAME];
57952081424Ssam 
58052081424Ssam 	if((fp = fopen(subfile(xfile), "r")) == NULL)
58152081424Ssam 		return;
58252081424Ssam 
58352081424Ssam 	while (fgets(buf, BUFSIZ, fp) != NULL) {
58452081424Ssam 		if (buf[0] != X_RQDFILE)
58552081424Ssam 			continue;
58652081424Ssam 		if (sscanf(&buf[1], "%s%s", file, tfile) < 2)
58752081424Ssam 			continue;
58852081424Ssam 		sprintf(tfull, "%s/%s", XQTDIR, tfile);
58952081424Ssam 		unlink(subfile(tfull));
59052081424Ssam 	}
59152081424Ssam 	fclose(fp);
59252081424Ssam 	return;
59352081424Ssam }
59452081424Ssam 
59552081424Ssam 
5962f96a7e7Sralph /*
5972f96a7e7Sralph  *	move execute files to x-directory
59852081424Ssam  */
59952081424Ssam 
mvxfiles(xfile)60052081424Ssam mvxfiles(xfile)
60152081424Ssam char *xfile;
60252081424Ssam {
60352081424Ssam 	register FILE *fp;
60452081424Ssam 	char buf[BUFSIZ], ffile[MAXFULLNAME], tfile[NAMESIZE];
60552081424Ssam 	char tfull[MAXFULLNAME];
60652081424Ssam 
60752081424Ssam 	if((fp = fopen(subfile(xfile), "r")) == NULL)
60852081424Ssam 		return;
60952081424Ssam 
61052081424Ssam 	while (fgets(buf, BUFSIZ, fp) != NULL) {
61152081424Ssam 		if (buf[0] != X_RQDFILE)
61252081424Ssam 			continue;
61352081424Ssam 		if (sscanf(&buf[1], "%s%s", ffile, tfile) < 2)
61452081424Ssam 			continue;
61552081424Ssam 		expfile(ffile);
61652081424Ssam 		sprintf(tfull, "%s/%s", XQTDIR, tfile);
61752081424Ssam 		unlink(subfile(tfull));
6182cbba08fSrick 		if (xmv(ffile, tfull) != 0) {
6192cbba08fSrick 			syslog(LOG_WARNING, "xmv(%s,%s) failed: %m",
6202cbba08fSrick 				ffile, tfull);
6212cbba08fSrick 			cleanup(1);
6222cbba08fSrick 		}
62352081424Ssam 	}
62452081424Ssam 	fclose(fp);
62552081424Ssam }
62652081424Ssam 
6272f96a7e7Sralph /*
6282f96a7e7Sralph  *	check for valid command/argument
6292f96a7e7Sralph  *	*NOTE - side effect is to set xc to the	command to be executed.
63052081424Ssam  *
63152081424Ssam  *	return 0 - ok | 1 nok
63252081424Ssam  */
63352081424Ssam 
argok(xc,cmd)63452081424Ssam argok(xc, cmd)
63552081424Ssam register char *xc, *cmd;
63652081424Ssam {
63752081424Ssam 	register char **ptr;
63852081424Ssam 
63952081424Ssam #ifndef ALLOK
6402f96a7e7Sralph 	if (strpbrk(cmd, BADCHARS) != NULL) {
641e21537dbSralph 		DEBUG(1,"MAGIC CHARACTER FOUND\n", CNULL);
6422f96a7e7Sralph 		logent(cmd, "NASTY MAGIC CHARACTER FOUND");
643e21537dbSralph 		return FAIL;
644e21537dbSralph 	}
645e21537dbSralph #endif !ALLOK
64652081424Ssam 
64752081424Ssam 	if (xc[0] != '\0')
648e21537dbSralph 		return SUCCESS;
64952081424Ssam 
65052081424Ssam #ifndef ALLOK
65152081424Ssam 	ptr = Cmds;
652e21537dbSralph 	DEBUG(9, "Compare %s and\n", cmd);
65352081424Ssam 	while(*ptr != NULL) {
654e21537dbSralph 		DEBUG(9, "\t%s\n", *ptr);
65552081424Ssam 		if (strcmp(cmd, *ptr) == SAME)
65652081424Ssam 			break;
65752081424Ssam 		ptr++;
65852081424Ssam 	}
659e21537dbSralph 	if (*ptr == NULL) {
660e21537dbSralph 		DEBUG(1,"COMMAND NOT FOUND\n", CNULL);
661e21537dbSralph 		return FAIL;
662e21537dbSralph 	}
66352081424Ssam #endif
66452081424Ssam 	strcpy(xc, cmd);
665e21537dbSralph 	DEBUG(9, "MATCHED %s\n", xc);
666e21537dbSralph 	return SUCCESS;
66752081424Ssam }
66852081424Ssam 
66952081424Ssam 
6702f96a7e7Sralph /*
6712f96a7e7Sralph  *	if notification should be sent for successful execution of cmd
672e21537dbSralph  *
673e21537dbSralph  *	return NT_YES - do notification
674e21537dbSralph  *	       NT_ERR - do notification if exit status != 0
675e21537dbSralph  *	       NT_NO  - don't do notification ever
676e21537dbSralph  */
677e21537dbSralph 
chknotify(cmd)678e21537dbSralph chknotify(cmd)
679e21537dbSralph char *cmd;
680e21537dbSralph {
681e21537dbSralph 	register char **ptr;
682e21537dbSralph 	register int *nptr;
683e21537dbSralph 
684e21537dbSralph 	ptr = Cmds;
685e21537dbSralph 	nptr = Notify;
686e21537dbSralph 	while (*ptr != NULL) {
687e21537dbSralph 		if (strcmp(cmd, *ptr) == SAME)
688e21537dbSralph 			return *nptr;
689e21537dbSralph 		ptr++;
690e21537dbSralph 		nptr++;
691e21537dbSralph 	}
692e21537dbSralph 	return NT_YES;		/* "shouldn't happen" */
693e21537dbSralph }
694e21537dbSralph 
695e21537dbSralph 
696e21537dbSralph 
6972f96a7e7Sralph /*
6982f96a7e7Sralph  *	send mail to user giving execution results
69952081424Ssam  */
70052081424Ssam 
notify(user,rmt,cmd,str)70152081424Ssam notify(user, rmt, cmd, str)
70252081424Ssam char *user, *rmt, *cmd, *str;
70352081424Ssam {
7042bba3b8bSrick 	char text[BUFSIZ*2];
70552081424Ssam 	char ruser[MAXFULLNAME];
70652081424Ssam 
707bd1b9349Sbloom 	if (strpbrk(user, BADCHARS) != NULL) {
708bd1b9349Sbloom 		char lbuf[MAXFULLNAME];
709bd1b9349Sbloom 		sprintf(lbuf, "%s INVALID CHARACTER IN USERNAME", user);
710bd1b9349Sbloom 		logent(cmd, lbuf);
711bd1b9349Sbloom 		strcpy(user, "postmaster");
712bd1b9349Sbloom 	}
713e21537dbSralph 	sprintf(text, "uuxqt cmd (%s) status (%s)", cmd, str);
71452081424Ssam 	if (prefix(rmt, Myname))
71552081424Ssam 		strcpy(ruser, user);
71652081424Ssam 	else
71752081424Ssam 		sprintf(ruser, "%s!%s", rmt, user);
718e21537dbSralph 	mailst(ruser, text, CNULL);
71952081424Ssam }
72052081424Ssam 
7212f96a7e7Sralph /*
7222f96a7e7Sralph  *	return mail to sender
72352081424Ssam  *
72452081424Ssam  */
retosndr(user,rmt,file)72552081424Ssam retosndr(user, rmt, file)
72652081424Ssam char *user, *rmt, *file;
72752081424Ssam {
728e21537dbSralph 	char ruser[MAXFULLNAME];
72952081424Ssam 
730bd1b9349Sbloom 	if (strpbrk(user, BADCHARS) != NULL) {
731bd1b9349Sbloom 		char lbuf[MAXFULLNAME];
732bd1b9349Sbloom 		sprintf(lbuf, "%s INVALID CHARACTER IN USERNAME", user);
733bd1b9349Sbloom 		logent(file, lbuf);
734bd1b9349Sbloom 		strcpy(user, "postmaster");
735bd1b9349Sbloom 	}
73652081424Ssam 	if (strcmp(rmt, Myname) == SAME)
73752081424Ssam 		strcpy(ruser, user);
73852081424Ssam 	else
73952081424Ssam 		sprintf(ruser, "%s!%s", rmt, user);
74052081424Ssam 
74152081424Ssam 	if (anyread(file) == 0)
74252081424Ssam 		mailst(ruser, "Mail failed.  Letter returned to sender.\n", file);
74352081424Ssam 	else
744e21537dbSralph 		mailst(ruser, "Mail failed.  Letter returned to sender.\n", CNULL);
74552081424Ssam 	return;
74652081424Ssam }
747dbb6249cSralph 
748dbb6249cSralph /*
7492f96a7e7Sralph  *	execute shell of command with fi and fo as standard input/output
7502f96a7e7Sralph  */
7512f96a7e7Sralph 
shio(cmd,fi,fo)7522f96a7e7Sralph shio(cmd, fi, fo)
7532f96a7e7Sralph char *cmd, *fi, *fo;
7542f96a7e7Sralph {
7552f96a7e7Sralph 	int status, f;
7562cbba08fSrick 	int pid, ret;
7572bba3b8bSrick 	char *args[256];
7582f96a7e7Sralph 	extern int errno;
7592f96a7e7Sralph 
7602f96a7e7Sralph 	if (fi == NULL)
7612f96a7e7Sralph 		fi = DEVNULL;
7622f96a7e7Sralph 	if (fo == NULL)
7632f96a7e7Sralph 		fo = DEVNULL;
7642f96a7e7Sralph 
7652bba3b8bSrick 	getargs(cmd, args, 256);
7662f96a7e7Sralph 	DEBUG(3, "shio - %s\n", cmd);
7672f96a7e7Sralph #ifdef SIGCHLD
7682f96a7e7Sralph 	signal(SIGCHLD, SIG_IGN);
7692f96a7e7Sralph #endif SIGCHLD
7702f96a7e7Sralph 	if ((pid = fork()) == 0) {
7712f96a7e7Sralph 		signal(SIGINT, SIG_IGN);
7722f96a7e7Sralph 		signal(SIGHUP, SIG_IGN);
7732f96a7e7Sralph 		signal(SIGQUIT, SIG_IGN);
7742f96a7e7Sralph 		close(Ifn);
7752f96a7e7Sralph 		close(Ofn);
7762f96a7e7Sralph 		close(0);
7772f96a7e7Sralph 		setuid(getuid());
7782f96a7e7Sralph 		f = open(subfile(fi), 0);
7792f96a7e7Sralph 		if (f != 0) {
7802f96a7e7Sralph 			logent(fi, "CAN'T READ");
7812f96a7e7Sralph 			exit(-errno);
7822f96a7e7Sralph 		}
7832f96a7e7Sralph 		close(1);
7842f96a7e7Sralph 		f = creat(subfile(fo), 0666);
7852f96a7e7Sralph 		if (f != 1) {
7862f96a7e7Sralph 			logent(fo, "CAN'T WRITE");
7872f96a7e7Sralph 			exit(-errno);
7882f96a7e7Sralph 		}
7892f96a7e7Sralph 		execvp(args[0], args);
7902f96a7e7Sralph 		exit(100+errno);
7912f96a7e7Sralph 	}
7922f96a7e7Sralph 	while ((ret = wait(&status)) != pid && ret != -1)
7932f96a7e7Sralph 		;
7942f96a7e7Sralph 	DEBUG(3, "status %d\n", status);
7952f96a7e7Sralph 	return status;
7962f96a7e7Sralph }
797