BSD 4_2 release
[unix-history] / usr / src / usr.bin / uucp / uuxqt.c
CommitLineData
f5c46f90 1#ifndef lint
0f4556f1 2static char sccsid[] = "@(#)uuxqt.c 5.2 (Berkeley) 7/2/83";
f5c46f90
SL
3#endif
4
5#include "uucp.h"
6#include <sys/types.h>
7#include <sys/stat.h>
8#ifdef NDIR
9#include "ndir.h"
10#else
ed412ce0 11#include <sys/dir.h>
f5c46f90
SL
12#endif
13
14#define APPCMD(d) {\
15char *p;\
16for (p = d; *p != '\0';) *cmdp++ = *p++;\
17*cmdp++ = ' ';\
18*cmdp = '\0';}
19
20/*
21 * uuxqt will execute commands set up by a uux command,
22 * usually from a remote machine - set by uucp.
23 */
24
25#define NCMDS 50
26char *Cmds[NCMDS];
27
28int notiok = 1;
29int nonzero = 0;
30
31char PATH[MAXFULLNAME] = "PATH=/bin:/usr/bin";
32/* to remove restrictions from uuxqt
33 * define ALLOK 1
34 *
35 * to add allowable commands, add to the file CMDFILE
36 * A line of form "PATH=..." changes the search path
37 */
38
39
40main(argc, argv)
41char *argv[];
42{
43 char xcmd[MAXFULLNAME];
44 int argnok;
45 char xfile[MAXFULLNAME], user[32], buf[BUFSIZ];
46 char lbuf[30];
47 char cfile[NAMESIZE], dfile[MAXFULLNAME];
48 char file[NAMESIZE];
49 char fin[MAXFULLNAME], sysout[NAMESIZE], fout[MAXFULLNAME];
50 register FILE *xfp, *fp;
51 FILE *dfp;
52 char path[MAXFULLNAME];
53 char cmd[BUFSIZ];
54 /* set size of prm to something large -- cmcl2!salkind */
55 char *cmdp, prm[1000], *ptr;
56 char *getprm(), *lastpart();
57 int uid, ret, badfiles;
58 register int i;
59 int stcico = 0;
60 char retstat[30];
61 int orig_uid = getuid();
62
63 strcpy(Progname, "uuxqt");
64 uucpname(Myname);
65
66 /* Try to run as uucp -- rti!trt */
67 setgid(getegid());
68 setuid(geteuid());
69
70 umask(WFMASK);
71 Ofn = 1;
72 Ifn = 0;
73 while (argc>1 && argv[1][0] == '-') {
74 switch(argv[1][1]){
75 case 'x':
76 chkdebug(orig_uid);
77 Debug = atoi(&argv[1][2]);
78 if (Debug <= 0)
79 Debug = 1;
80 break;
81 default:
82 fprintf(stderr, "unknown flag %s\n", argv[1]);
83 break;
84 }
85 --argc; argv++;
86 }
87
88 DEBUG(4, "\n\n** %s **\n", "START");
89 subchdir(Spool);
90 strcpy(Wrkdir, Spool);
91 uid = getuid();
92 guinfo(uid, User, path);
93 DEBUG(4, "User - %s\n", User);
94 if (ulockf(X_LOCK, (time_t) X_LOCKTIME) != 0)
95 exit(0);
96
97 fp = fopen(CMDFILE, "r");
98 if (fp == NULL) {
99 /* Fall-back if CMDFILE missing. Sept 1982, rti!trt */
100 logent("CAN'T OPEN", CMDFILE);
101 Cmds[0] = "rmail";
102 Cmds[1] = "rnews";
103 Cmds[2] = "ruusend";
104 Cmds[3] = NULL;
105 goto doprocess;
106 }
107 DEBUG(5, "%s opened\n", CMDFILE);
108 for (i=0; i<NCMDS-1 && cfgets(xcmd, sizeof(xcmd), fp) != NULL; i++) {
109 xcmd[strlen(xcmd)-1] = '\0';
110 if (strncmp(xcmd, "PATH=", 5) == 0) {
111 strcpy(PATH, xcmd);
112 i--; /* kludge */
113 continue;
114 }
115 DEBUG(5, "xcmd = %s\n", xcmd);
116 Cmds[i] = malloc((unsigned)(strlen(xcmd)+1));
117 strcpy(Cmds[i], xcmd);
118 }
119 Cmds[i] = 0;
120 fclose(fp);
121
122doprocess:
123 DEBUG(4, "process %s\n", "");
124 while (gtxfile(xfile) > 0) {
125 ultouch(); /* rti!trt */
126 DEBUG(4, "xfile - %s\n", xfile);
127
128 xfp = fopen(subfile(xfile), "r");
129 ASSERT(xfp != NULL, "CAN'T OPEN", xfile, 0);
130
131 /* initialize to default */
132 strcpy(user, User);
133 strcpy(fin, "/dev/null");
134 strcpy(fout, "/dev/null");
135 sprintf(sysout, "%.7s", Myname);
136 badfiles = 0; /* this was missing -- rti!trt */
137 while (fgets(buf, BUFSIZ, xfp) != NULL) {
138 switch (buf[0]) {
139 case X_USER:
140 sscanf(&buf[1], "%s%s", user, Rmtname);
141 break;
142 case X_STDIN:
143 sscanf(&buf[1], "%s", fin);
144 i = expfile(fin);
145 /* rti!trt: do not check permissions of
146 * vanilla spool file */
147 if (i != 0
148 && (chkpth("", "", fin) || anyread(fin) != 0))
149 badfiles = 1;
150 break;
151 case X_STDOUT:
152 sscanf(&buf[1], "%s%s", fout, sysout);
153 sysout[7] = '\0';
154 /* rti!trt: do not check permissions of
155 * vanilla spool file. DO check permissions
156 * of writing on a non-vanilla file */
157 i = 1;
158 if (fout[0] != '~' || prefix(sysout, Myname))
159 i = expfile(fout);
160 if (i != 0
161 && (chkpth("", "", fout)
162 || chkperm(fout, (char *)1)))
163 badfiles = 1;
164 break;
165 case X_CMD:
166 strcpy(cmd, &buf[2]);
167 if (*(cmd + strlen(cmd) - 1) == '\n')
168 *(cmd + strlen(cmd) - 1) = '\0';
169 break;
170 case X_NONOTI:
171 notiok = 0;
172 break;
173 case X_NONZERO:
174 nonzero = 1;
175 break;
176 default:
177 break;
178 }
179 }
180
181 fclose(xfp);
182 DEBUG(4, "fin - %s, ", fin);
183 DEBUG(4, "fout - %s, ", fout);
184 DEBUG(4, "sysout - %s, ", sysout);
185 DEBUG(4, "user - %s\n", user);
186 DEBUG(4, "cmd - %s\n", cmd);
187
188 /* command execution */
189 if (strcmp(fout, "/dev/null") == SAME)
190 strcpy(dfile,"/dev/null");
191 else
192 gename(DATAPRE, sysout, 'O', dfile);
193
194 /* expand file names where necessary */
195 expfile(dfile);
196 strcpy(buf, PATH);
197 strcat(buf, ";export PATH;");
198 cmdp = buf + strlen(buf);
199 ptr = cmd;
200 xcmd[0] = '\0';
201 argnok = 0;
202 while ((ptr = getprm(ptr, prm)) != NULL) {
203 if (prm[0] == ';' || prm[0] == '^'
204 || prm[0] == '&' || prm[0] == '|') {
205 xcmd[0] = '\0';
206 APPCMD(prm);
207 continue;
208 }
209
210 if ((argnok = argok(xcmd, prm)) != 0)
211 /* command not valid */
212 break;
213
214 if (prm[0] == '~')
215 expfile(prm);
216 APPCMD(prm);
217 }
218 if (argnok || badfiles) {
219 sprintf(lbuf, "%s XQT DENIED", user);
220 logent(cmd, lbuf);
221 DEBUG(4, "bad command %s\n", prm);
222 notify(user, Rmtname, cmd, "DENIED");
223 goto rmfiles;
224 }
225 sprintf(lbuf, "%s XQT", user);
226 logent(buf, lbuf);
227 DEBUG(4, "cmd %s\n", buf);
228
229 mvxfiles(xfile);
230 subchdir(XQTDIR);
231 ret = shio(buf, fin, dfile, (char *)NULL);
232/* watcgl.11, dmmartindale, signal and exit values were reversed */
233 sprintf(retstat, "signal %d, exit %d", ret & 0377,
234 (ret>>8) & 0377);
235 if (strcmp(xcmd, "rmail") == SAME)
236 notiok = 0;
237 if (strcmp(xcmd, "rnews") == SAME)
238 nonzero = 1;
239 if (notiok && (!nonzero || (nonzero && ret != 0)))
240 notify(user, Rmtname, cmd, retstat);
241 else if (ret != 0 && strcmp(xcmd, "rmail") == SAME) {
242 /* mail failed - return letter to sender */
243 retosndr(user, Rmtname, fin);
244 sprintf(buf, "ret (%o) from %s!%s", ret, Rmtname, user);
245 logent("MAIL FAIL", buf);
246 }
247 DEBUG(4, "exit cmd - %d\n", ret);
248 subchdir(Spool);
249 rmxfiles(xfile);
250 if (ret != 0) {
251 /* exit status not zero */
252 dfp = fopen(subfile(dfile), "a");
253 ASSERT(dfp != NULL, "CAN'T OPEN", dfile, 0);
254 fprintf(dfp, "exit status %d", ret);
255 fclose(dfp);
256 }
257 if (strcmp(fout, "/dev/null") != SAME) {
258 if (prefix(sysout, Myname)) {
259 xmv(dfile, fout);
260 chmod(fout, BASEMODE);
261 }
262 else {
263 gename(CMDPRE, sysout, 'O', cfile);
264 fp = fopen(subfile(cfile), "w");
265 ASSERT(fp != NULL, "OPEN", cfile, 0);
266 fprintf(fp, "S %s %s %s - %s 0666\n",
267 dfile, fout, user, lastpart(dfile));
268 fclose(fp);
269 }
270 }
271 rmfiles:
272 xfp = fopen(subfile(xfile), "r");
273 ASSERT(xfp != NULL, "CAN'T OPEN", xfile, 0);
274 while (fgets(buf, BUFSIZ, xfp) != NULL) {
275 if (buf[0] != X_RQDFILE)
276 continue;
277 sscanf(&buf[1], "%s", file);
278 unlink(subfile(file));
279 }
280 unlink(subfile(xfile));
281 fclose(xfp);
282 }
283
284 if (stcico)
285 xuucico("");
286 cleanup(0);
287}
288
289
290cleanup(code)
291int code;
292{
293 logcls();
294 rmlock(CNULL);
295 exit(code);
296}
297
298
299/*******
300 * gtxfile(file) get a file to execute
301 * char *file;
302 *
303 * return codes: 0 - no file | 1 - file to execute
304 * Mod to recheck for X-able files. Sept 1982, rti!trt.
305 * Suggested by utzoo.2458 (utzoo!henry)
306 * Uses iswrk/gtwrkf to keep files in sequence, May 1983.
307 */
308
309gtxfile(file)
310register char *file;
311{
312 char pre[3];
313 register int rechecked;
314
315 pre[0] = XQTPRE;
316 pre[1] = '.';
317 pre[2] = '\0';
318 rechecked = 0;
319retry:
320 if (!gtwrkf(Spool, file)) {
321 if (rechecked)
322 return(0);
323 rechecked = 1;
324 DEBUG(4, "iswrk\n", "");
325 if (!iswrk(file, "get", Spool, pre))
326 return(0);
327 }
328 DEBUG(4, "file - %s\n", file);
329#ifndef UUDIR
330 /* skip spurious subdirectories */
331 if (strcmp(pre, file) == SAME)
332 goto retry;
333#endif
334 if (gotfiles(file))
335 return(1);
336 goto retry;
337}
338
339
340/***
341 * gotfiles(file) check for needed files
342 * char *file;
343 *
344 * return codes: 0 - not ready | 1 - all files ready
345 */
346
347gotfiles(file)
348register char *file;
349{
350 struct stat stbuf;
351 register FILE *fp;
352 char buf[BUFSIZ], rqfile[MAXFULLNAME];
353
354 fp = fopen(subfile(file), "r");
355 if (fp == NULL)
356 return(0);
357
358 while (fgets(buf, BUFSIZ, fp) != NULL) {
359 DEBUG(4, "%s\n", buf);
360 if (buf[0] != X_RQDFILE)
361 continue;
362 sscanf(&buf[1], "%s", rqfile);
363 expfile(rqfile);
364 if (stat(subfile(rqfile), &stbuf) == -1) {
365 fclose(fp);
366 return(0);
367 }
368 }
369
370 fclose(fp);
371 return(1);
372}
373
374
375/***
376 * rmxfiles(xfile) remove execute files to x-directory
377 * char *xfile;
378 *
379 * return codes - none
380 */
381
382rmxfiles(xfile)
383register char *xfile;
384{
385 register FILE *fp;
386 char buf[BUFSIZ], file[NAMESIZE], tfile[NAMESIZE];
387 char tfull[MAXFULLNAME];
388
389 if((fp = fopen(subfile(xfile), "r")) == NULL)
390 return;
391
392 while (fgets(buf, BUFSIZ, fp) != NULL) {
393 if (buf[0] != X_RQDFILE)
394 continue;
395 if (sscanf(&buf[1], "%s%s", file, tfile) < 2)
396 continue;
397 sprintf(tfull, "%s/%s", XQTDIR, tfile);
398 unlink(subfile(tfull));
399 }
400 fclose(fp);
401 return;
402}
403
404
405/***
406 * mvxfiles(xfile) move execute files to x-directory
407 * char *xfile;
408 *
409 * return codes - none
410 */
411
412mvxfiles(xfile)
413char *xfile;
414{
415 register FILE *fp;
416 char buf[BUFSIZ], ffile[MAXFULLNAME], tfile[NAMESIZE];
417 char tfull[MAXFULLNAME];
418 int ret;
419
420 if((fp = fopen(subfile(xfile), "r")) == NULL)
421 return;
422
423 while (fgets(buf, BUFSIZ, fp) != NULL) {
424 if (buf[0] != X_RQDFILE)
425 continue;
426 if (sscanf(&buf[1], "%s%s", ffile, tfile) < 2)
427 continue;
428 expfile(ffile);
429 sprintf(tfull, "%s/%s", XQTDIR, tfile);
430 /* duke!rti, ncsu!mcm: use xmv, not link(II) */
431 unlink(subfile(tfull));
432 ret = xmv(ffile, tfull);
433 ASSERT(ret == 0, "XQTDIR ERROR", "", ret);
434 }
435 fclose(fp);
436 return;
437}
438
439
440/***
441 * argok(xc, cmd) check for valid command/argumanet
442 * *NOTE - side effect is to set xc to the
443 * command to be executed.
444 * char *xc, *cmd;
445 *
446 * return 0 - ok | 1 nok
447 */
448
449argok(xc, cmd)
450register char *xc, *cmd;
451{
452 register char **ptr;
453
454#ifndef ALLOK
455 /* don't allow sh command strings `....` */
456 /* don't allow redirection of standard in or out */
457 /* don't allow other funny stuff */
458 /* but there are probably total holes here */
459 /* post-script. ittvax!swatt has a uuxqt that solves this. */
460 /* This version of uuxqt will shortly disappear */
461 if (index(cmd, '`') != NULL
462 || index(cmd, '>') != NULL
463 || index(cmd, ';') != NULL
464 || index(cmd, '^') != NULL
465 || index(cmd, '&') != NULL
466 || index(cmd, '|') != NULL
467 || index(cmd, '<') != NULL)
468 return(1);
469#endif
470
471 if (xc[0] != '\0')
472 return(0);
473
474#ifndef ALLOK
475 ptr = Cmds;
476 while(*ptr != NULL) {
477 if (strcmp(cmd, *ptr) == SAME)
478 break;
479 ptr++;
480 }
481 if (*ptr == NULL)
482 return(1);
483#endif
484 strcpy(xc, cmd);
485 return(0);
486}
487
488
489/***
490 * notify send mail to user giving execution results
491 * return code - none
492 * This program assumes new mail command - send remote mail
493 */
494
495notify(user, rmt, cmd, str)
496char *user, *rmt, *cmd, *str;
497{
498 char text[MAXFULLNAME];
499 char ruser[MAXFULLNAME];
500
501 sprintf(text, "uuxqt cmd (%.50s) status (%s)", cmd, str);
502 if (prefix(rmt, Myname))
503 strcpy(ruser, user);
504 else
505 sprintf(ruser, "%s!%s", rmt, user);
506 mailst(ruser, text, "");
507 return;
508}
509
510/***
511 * retosndr - return mail to sender
512 *
513 * return code - none
514 */
515
516retosndr(user, rmt, file)
517char *user, *rmt, *file;
518{
519 char ruser[100];
520
521 if (strcmp(rmt, Myname) == SAME)
522 strcpy(ruser, user);
523 else
524 sprintf(ruser, "%s!%s", rmt, user);
525
526 if (anyread(file) == 0)
527 mailst(ruser, "Mail failed. Letter returned to sender.\n", file);
528 else
529 mailst(ruser, "Mail failed. Letter returned to sender.\n", "");
530 return;
531}