Commit | Line | Data |
---|---|---|
f5c46f90 | 1 | #ifndef lint |
0f4556f1 | 2 | static 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) {\ | |
15 | char *p;\ | |
16 | for (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 | |
26 | char *Cmds[NCMDS]; | |
27 | ||
28 | int notiok = 1; | |
29 | int nonzero = 0; | |
30 | ||
31 | char 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 | ||
40 | main(argc, argv) | |
41 | char *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 | ||
122 | doprocess: | |
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 | ||
290 | cleanup(code) | |
291 | int 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 | ||
309 | gtxfile(file) | |
310 | register 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; | |
319 | retry: | |
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 | ||
347 | gotfiles(file) | |
348 | register 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 | ||
382 | rmxfiles(xfile) | |
383 | register 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 | ||
412 | mvxfiles(xfile) | |
413 | char *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 | ||
449 | argok(xc, cmd) | |
450 | register 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 | ||
495 | notify(user, rmt, cmd, str) | |
496 | char *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 | ||
516 | retosndr(user, rmt, file) | |
517 | char *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 | } |