1 /*-
2 * Copyright (c) 1985, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
6 */
7
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1985, 1988, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)uuxqt.c 8.1 (Berkeley) 06/06/93";
16 #endif /* not lint */
17
18 #include "uucp.h"
19 #include <sys/stat.h>
20 #ifdef NDIR
21 #include "ndir.h"
22 #else
23 #include <sys/dir.h>
24 #endif
25 #include <signal.h>
26
27 #define BADCHARS "&^|(`\\<>;\"{}\n'"
28 #define RECHECKTIME 60*10 /* 10 minutes */
29
30 #define APPCMD(d) {\
31 char *p;\
32 for (p = d; *p != '\0';) *cmdp++ = *p++; *cmdp++ = ' '; *cmdp = '\0';}
33
34 extern char Filent[LLEN][NAMESIZE];
35
36 /*
37 * uuxqt will execute commands set up by a uux command,
38 * usually from a remote machine - set by uucp.
39 */
40
41 #define NCMDS 50
42 char *Cmds[NCMDS+1];
43 int Notify[NCMDS+1];
44 #define NT_YES 0 /* if should notify on execution */
45 #define NT_ERR 1 /* if should notify if non-zero exit status (-z equivalent) */
46 #define NT_NO 2 /* if should not notify ever (-n equivalent) */
47
48 extern int Nfiles;
49
50 int TransferSucceeded = 1;
51 int notiok = 1;
52 int nonzero = 0;
53
54 struct timeb Now;
55
56 char PATH[MAXFULLNAME] = "PATH=/bin:/usr/bin";
57 char UU_MACHINE[MAXFULLNAME];
58 char Shell[MAXFULLNAME];
59 char HOME[MAXFULLNAME];
60
61 extern char **environ;
62 char *nenv[] = {
63 PATH,
64 Shell,
65 HOME,
66 UU_MACHINE,
67 0
68 };
69
70 /* to remove restrictions from uuxqt
71 * define ALLOK 1
72 *
73 * to add allowable commands, add to the file CMDFILE
74 * A line of form "PATH=..." changes the search path
75 */
main(argc,argv)76 main(argc, argv)
77 char *argv[];
78 {
79 char xcmd[BUFSIZ*2];
80 int argnok;
81 int notiflg;
82 char xfile[MAXFULLNAME], user[MAXFULLNAME], buf[BUFSIZ*2];
83 char lbuf[MAXFULLNAME];
84 char cfile[NAMESIZE], dfile[MAXFULLNAME];
85 char file[NAMESIZE];
86 char fin[MAXFULLNAME], sysout[NAMESIZE], fout[MAXFULLNAME];
87 register FILE *xfp, *fp;
88 FILE *dfp;
89 char path[MAXFULLNAME];
90 char cmd[BUFSIZ*2];
91 char *cmdp, prm[1000], *ptr;
92 char *getprm(), *lastpart();
93 int uid, ret, badfiles;
94 register int i;
95 int stcico = 0;
96 time_t xstart, xnow;
97 char retstat[30];
98 extern char *optarg;
99 extern int optind;
100
101 strcpy(Progname, "uuxqt");
102 uucpname(Myname);
103 strcpy(Rmtname, Myname);
104
105 umask(WFMASK);
106 Ofn = 1;
107 Ifn = 0;
108 while ((i = getopt(argc, argv, "x:S:")) != EOF)
109 switch(i) {
110 case 'x':
111 chkdebug();
112 Debug = atoi(optarg);
113 if (Debug <= 0)
114 Debug = 1;
115 break;
116 case 'S':
117 Spool = optarg;
118 DEBUG(1, "Spool set to %s", Spool);
119 break;
120 case '?':
121 default:
122 fprintf(stderr, "unknown flag %s\n", argv[optind-1]);
123 break;
124 }
125
126 DEBUG(4, "\n\n** START **\n", CNULL);
127 if (subchdir(Spool) < 0) {
128 syslog(LOG_WARNING, "chdir(%s) failed: %m", Spool);
129 cleanup(1);
130 }
131 strcpy(Wrkdir, Spool);
132 uid = getuid();
133 if (guinfo(uid, User, path) != SUCCESS) {
134 syslog(LOG_WARNING, "Can't find username for uid %d", uid);
135 DEBUG(1, "Using username", "uucp");
136 strcpy(User, "uucp");
137 }
138 setgid(getegid());
139 setuid(geteuid());
140
141 DEBUG(4, "User - %s\n", User);
142 if (ulockf(X_LOCK, X_LOCKTIME) != 0)
143 exit(0);
144
145 fp = fopen(CMDFILE, "r");
146 if (fp == NULL) {
147 logent(CANTOPEN, CMDFILE);
148 Cmds[0] = "rmail";
149 Cmds[1] = "rnews";
150 Cmds[2] = "ruusend";
151 Cmds[3] = NULL;
152 goto doprocess;
153 }
154 DEBUG(5, "%s opened\n", CMDFILE);
155 for (i=0; i<NCMDS && cfgets(xcmd, sizeof(xcmd), fp) != NULL; i++) {
156 int j;
157 /* strip trailing whitespace */
158 for (j = strlen(xcmd)-1; j >= 0; --j)
159 if (xcmd[j] == '\n' || xcmd[j] == ' ' || xcmd[j] == '\t')
160 xcmd[j] = '\0';
161 else
162 break;
163 /* look for imbedded whitespace */
164 for (; j >= 0; --j)
165 if (xcmd[j] == '\n' || xcmd[j] == ' ' || xcmd[j] == '\t')
166 break;
167 /* skip this entry if it has embedded whitespace */
168 /* This defends against a bad PATH=, for example */
169 if (j >= 0) {
170 logent(xcmd, "BAD WHITESPACE");
171 continue;
172 }
173 if (strncmp(xcmd, "PATH=", 5) == 0) {
174 strcpy(PATH, xcmd);
175 i--; /*kludge */
176 continue;
177 }
178 DEBUG(5, "xcmd = %s\n", xcmd);
179
180 if ((ptr = index(xcmd, ',')) != NULL) {
181 *ptr++ = '\0';
182 if (strncmp(ptr, "Err", 3) == SAME)
183 Notify[i] = NT_ERR;
184 else if (strcmp(ptr, "No") == SAME)
185 Notify[i] = NT_NO;
186 else
187 Notify[i] = NT_YES;
188 } else
189 Notify[i] = NT_YES;
190 if ((Cmds[i] = malloc((unsigned)(strlen(xcmd)+1))) == NULL) {
191 DEBUG(1, "MALLOC FAILED", CNULL);
192 break;
193 }
194 strcpy(Cmds[i], xcmd);
195 }
196 Cmds[i] = CNULL;
197 fclose(fp);
198
199 doprocess:
200
201 (void) sprintf(HOME, "HOME=%s", Spool);
202 (void) sprintf(Shell, "SHELL=%s", SHELL);
203 environ = nenv; /* force use if our environment */
204
205 DEBUG(11,"path = %s\n", getenv("PATH"));
206
207 DEBUG(4, "process %s\n", CNULL);
208
209 time(&xstart);
210 while (gtxfile(xfile) > 0) {
211 /* if /etc/nologin exists, exit cleanly */
212 #if defined(BSD4_2) || defined(USG)
213 if (access(NOLOGIN) == 0) {
214 #else !BSD4_2 && ! USG
215 ultouch();
216 if (nologinflag) {
217 #endif !BSD4_2 && !USG
218 logent(NOLOGIN, "UUXQT SHUTDOWN");
219 if (Debug)
220 logent("debugging", "continuing anyway");
221 else
222 break;
223 }
224 DEBUG(4, "xfile - %s\n", xfile);
225
226 xfp = fopen(subfile(xfile), "r");
227 if (xfp == NULL) {
228 syslog(LOG_ERR, "fopen(%s) failed: %m", subfile(xfile));
229 cleanup(1);
230 }
231
232 /* initialize to default */
233 strcpy(user, User);
234 strcpy(fin, DEVNULL);
235 strcpy(fout, DEVNULL);
236 strcpy(sysout, Myname);
237 badfiles = 0;
238 while (fgets(buf, BUFSIZ, xfp) != NULL) {
239 if(buf[0] != '\0' && buf[0] != '#' &&
240 buf[1] != ' ' && buf[1] != '\0' && buf[1] != '\n') {
241 char *bnp, cfilename[BUFSIZ];
242 DEBUG(4, "uuxqt: buf = %s\n", buf);
243 bnp = rindex(xfile, '/');
244 sprintf(cfilename, "%s/%s", CORRUPT,
245 bnp ? bnp + 1 : xfile);
246 DEBUG(4, "uuxqt: move %s to ", xfile);
247 DEBUG(4, "%s\n", cfilename);
248 xmv(xfile, cfilename);
249 syslog(LOG_WARNING, "%s: X. FILE CORRUPTED",
250 xfile);
251 fclose(xfp);
252 goto doprocess;
253 }
254 switch (buf[0]) {
255 case X_USER: {
256 char ORmtname[MAXFULLNAME];
257 strcpy(ORmtname, Rmtname);
258 sscanf(&buf[1], "%s %s", user, Rmtname);
259 sprintf(UU_MACHINE, "UU_MACHINE=%s", Rmtname);
260 if (strcmp(ORmtname, Rmtname) != 0)
261 logcls();
262 break;}
263 case X_RETURNTO:
264 sscanf(&buf[1], "%s", user);
265 break;
266 case X_STDIN:
267 sscanf(&buf[1], "%s", fin);
268 i = expfile(fin);
269 /* rti!trt: do not check permissions of
270 * vanilla spool file */
271 if (i != 0
272 && (chkpth("", "", fin) || anyread(fin) != 0))
273 badfiles = 1;
274 break;
275 case X_STDOUT:
276 sscanf(&buf[1], "%s%s", fout, sysout);
277 sysout[MAXBASENAME] = '\0';
278 /* rti!trt: do not check permissions of
279 * vanilla spool file. DO check permissions
280 * of writing on a non-vanilla file */
281 i = 1;
282 if (fout[0] != '~' || prefix(sysout, Myname))
283 i = expfile(fout);
284 if (i != 0
285 && (chkpth("", "", fout)
286 || chkperm(fout, (char *)1)))
287 badfiles = 1;
288 break;
289 case X_CMD:
290 strcpy(cmd, &buf[2]);
291 if (*(cmd + strlen(cmd) - 1) == '\n')
292 *(cmd + strlen(cmd) - 1) = '\0';
293 break;
294 case X_NONOTI:
295 notiok = 0;
296 break;
297 case X_NONZERO:
298 nonzero = 1;
299 break;
300 default:
301 break;
302 }
303 }
304
305 fclose(xfp);
306 DEBUG(4, "fin - %s, ", fin);
307 DEBUG(4, "fout - %s, ", fout);
308 DEBUG(4, "sysout - %s, ", sysout);
309 DEBUG(4, "user - %s\n", user);
310 DEBUG(4, "cmd - %s\n", cmd);
311
312 /* command execution */
313 if (strcmp(fout, DEVNULL) == SAME)
314 strcpy(dfile,DEVNULL);
315 else
316 gename(DATAPRE, sysout, 'O', dfile);
317
318 /* expand file names where necessary */
319 expfile(dfile);
320 cmdp = buf;
321 ptr = cmd;
322 xcmd[0] = '\0';
323 argnok = 0;
324 while ((ptr = getprm(ptr, prm)) != NULL) {
325 if (prm[0] == ';' || prm[0] == '^'
326 || prm[0] == '&' || prm[0] == '|') {
327 xcmd[0] = '\0';
328 APPCMD(prm);
329 continue;
330 }
331
332 if ((argnok = argok(xcmd, prm)) != SUCCESS)
333 /* command not valid */
334 break;
335
336 if (prm[0] == '~')
337 expfile(prm);
338 APPCMD(prm);
339 }
340 /*
341 * clean up trailing ' ' in command.
342 */
343 if (cmdp > buf && cmdp[0] == '\0' && cmdp[-1] == ' ')
344 *--cmdp = '\0';
345 if (argnok || badfiles) {
346 sprintf(lbuf, "%s XQT DENIED", user);
347 logent(cmd, lbuf);
348 DEBUG(4, "bad command %s\n", prm);
349 notify(user, Rmtname, cmd, "DENIED");
350 goto rmfiles;
351 }
352 sprintf(lbuf, "%s XQT", user);
353 logent(buf, lbuf);
354 DEBUG(4, "cmd %s\n", buf);
355
356 mvxfiles(xfile);
357 if (subchdir(XQTDIR) < 0) {
358 syslog(LOG_ERR, "chdir(%s) failed: %m", XQTDIR);
359 cleanup(1);
360 }
361 ret = shio(buf, fin, dfile);
362 sprintf(retstat, "signal %d, exit %d", ret & 0377,
363 (ret>>8) & 0377);
364 if (strcmp(xcmd, "rmail") == SAME)
365 notiok = 0;
366 if (strcmp(xcmd, "rnews") == SAME)
367 nonzero = 1;
368 notiflg = chknotify(xcmd);
369 if (notiok && notiflg != NT_NO &&
370 (ret != 0 || (!nonzero && notiflg == NT_YES)))
371 notify(user, Rmtname, cmd, retstat);
372 else if (ret != 0 && strcmp(xcmd, "rmail") == SAME) {
373 /* mail failed - return letter to sender */
374 #ifdef DANGEROUS
375 /* NOT GUARANTEED SAFE!!! */
376 if (!nonzero)
377 retosndr(user, Rmtname, fin);
378 #else
379 notify(user, Rmtname, cmd, retstat);
380 #endif
381 sprintf(buf, "%s (%s) from %s!%s", buf, retstat, Rmtname, user);
382 logent("MAIL FAIL", buf);
383 }
384 DEBUG(4, "exit cmd - %d\n", ret);
385 if (subchdir(Spool) < 0) {
386 syslog(LOG_ERR, "chdir(%s) failed: %m", Spool);
387 cleanup(1);
388 }
389 rmxfiles(xfile);
390 if (ret != 0) {
391 /* exit status not zero */
392 dfp = fopen(subfile(dfile), "a");
393 if (dfp == NULL) {
394 syslog(LOG_ERR, "fopen(%s) failed: %m",
395 subfile(dfile));
396 cleanup(1);
397 }
398 fprintf(dfp, "exit status %d", ret);
399 fclose(dfp);
400 }
401 if (strcmp(fout, DEVNULL) != SAME) {
402 if (prefix(sysout, Myname)) {
403 xmv(dfile, fout);
404 chmod(fout, BASEMODE);
405 } else {
406 char *cp = rindex(user, '!');
407 gename(CMDPRE, sysout, 'O', cfile);
408 fp = fopen(subfile(cfile), "w");
409 if (fp == NULL) {
410 syslog(LOG_ERR, "fopen(%s) failed: %m",
411 subfile(cfile));
412 cleanup(1);
413 }
414 fprintf(fp, "S %s %s %s - %s 0666\n", dfile,
415 fout, cp ? cp : user, lastpart(dfile));
416 fclose(fp);
417 }
418 }
419 rmfiles:
420 xfp = fopen(subfile(xfile), "r");
421 if (xfp == NULL) {
422 syslog(LOG_ERR, "fopen(%s) failed: %m",
423 subfile(xfile));
424 cleanup(1);
425 }
426 while (fgets(buf, BUFSIZ, xfp) != NULL) {
427 if (buf[0] != X_RQDFILE)
428 continue;
429 sscanf(&buf[1], "%s", file);
430 unlink(subfile(file));
431 }
432 unlink(subfile(xfile));
433 fclose(xfp);
434
435 /* rescan X. for new work every RECHECKTIME seconds */
436 time(&xnow);
437 if (xnow > (xstart + RECHECKTIME)) {
438 extern int Nfiles;
439 Nfiles = 0; /*force rescan for new work */
440 }
441 xstart = xnow;
442 }
443
444 if (stcico)
445 xuucico("");
446 cleanup(0);
447 }
448
449
cleanup(code)450 cleanup(code)
451 int code;
452 {
453 logcls();
454 rmlock(CNULL);
455 #ifdef VMS
456 /*
457 * Since we run as a BATCH job we must wait for all processes to
458 * to finish
459 */
460 while(wait(0) != -1)
461 ;
462 #endif VMS
463 exit(code);
464 }
465
466
467 /*
468 * get a file to execute
469 *
470 * return codes: 0 - no file | 1 - file to execute
471 */
472
gtxfile(file)473 gtxfile(file)
474 register char *file;
475 {
476 char pre[3];
477 register int rechecked, i;
478 time_t ystrdy; /* yesterday */
479 struct stat stbuf; /* for X file age */
480
481 pre[0] = XQTPRE;
482 pre[1] = '.';
483 pre[2] = '\0';
484 rechecked = 0;
485 retry:
486 if (Nfiles-- <= 0) {
487 Nfiles = 0;
488 if (rechecked)
489 return 0;
490 rechecked = 1;
491 DEBUG(4, "iswrk\n", CNULL);
492 return iswrk(file, "get", Spool, pre);
493 }
494 sprintf(file, "%s/%s", Spool, Filent[0]);
495 for (i=0; i<Nfiles;i++)
496 strcpy(Filent[i], Filent[i+1]);
497
498 DEBUG(4, "file - %s\n", file);
499 /* skip spurious subdirectories */
500 if (strcmp(pre, file) == SAME)
501 goto retry;
502 if (gotfiles(file))
503 return 1;
504 /* check for old X. file with no work files and remove them. */
505 if (Nfiles > LLEN/2) {
506 time(&ystrdy);
507 ystrdy -= (4 * 3600L); /* 4 hours ago */
508 DEBUG(4, "gtxfile: Nfiles > LLEN/2\n", CNULL);
509 while (Nfiles-- > 0) {
510 sprintf(file, "%s/%s", Spool, Filent[0]);
511 for (i=0; i<Nfiles; i++)
512 strcpy(Filent[i], Filent[i+1]);
513
514 if (gotfiles(file))
515 return 1;
516 if (stat(subfile(file), &stbuf) == 0)
517 if (stbuf.st_mtime <= ystrdy) {
518 char *bnp, cfilename[NAMESIZE];
519 DEBUG(4, "gtxfile: move %s to CORRUPT \n", file);
520 bnp = rindex(file, '/');
521 sprintf(cfilename, "%s/%s", CORRUPT,
522 bnp ? bnp + 1 : file);
523 xmv(file, cfilename);
524 syslog(LOG_WARNING, "%s: X. FILE MISSING FILES", file);
525 }
526 }
527 Nfiles = 0;
528 DEBUG(4, "iswrk\n", CNULL);
529 if (!iswrk(file, "get", Spool, pre))
530 return 0;
531 }
532 goto retry;
533 }
534
535 /*
536 * check for needed files
537 *
538 * return codes: 0 - not ready | 1 - all files ready
539 */
540
gotfiles(file)541 gotfiles(file)
542 register char *file;
543 {
544 struct stat stbuf;
545 register FILE *fp;
546 char buf[BUFSIZ], rqfile[MAXFULLNAME];
547
548 fp = fopen(subfile(file), "r");
549 if (fp == NULL)
550 return 0;
551
552 while (fgets(buf, BUFSIZ, fp) != NULL) {
553 DEBUG(4, "%s\n", buf);
554 if (buf[0] != X_RQDFILE)
555 continue;
556 sscanf(&buf[1], "%s", rqfile);
557 expfile(rqfile);
558 if (stat(subfile(rqfile), &stbuf) == -1) {
559 fclose(fp);
560 return 0;
561 }
562 }
563
564 fclose(fp);
565 return 1;
566 }
567
568
569 /*
570 * remove execute files to x-directory
571 */
572
rmxfiles(xfile)573 rmxfiles(xfile)
574 register char *xfile;
575 {
576 register FILE *fp;
577 char buf[BUFSIZ], file[NAMESIZE], tfile[NAMESIZE];
578 char tfull[MAXFULLNAME];
579
580 if((fp = fopen(subfile(xfile), "r")) == NULL)
581 return;
582
583 while (fgets(buf, BUFSIZ, fp) != NULL) {
584 if (buf[0] != X_RQDFILE)
585 continue;
586 if (sscanf(&buf[1], "%s%s", file, tfile) < 2)
587 continue;
588 sprintf(tfull, "%s/%s", XQTDIR, tfile);
589 unlink(subfile(tfull));
590 }
591 fclose(fp);
592 return;
593 }
594
595
596 /*
597 * move execute files to x-directory
598 */
599
mvxfiles(xfile)600 mvxfiles(xfile)
601 char *xfile;
602 {
603 register FILE *fp;
604 char buf[BUFSIZ], ffile[MAXFULLNAME], tfile[NAMESIZE];
605 char tfull[MAXFULLNAME];
606
607 if((fp = fopen(subfile(xfile), "r")) == NULL)
608 return;
609
610 while (fgets(buf, BUFSIZ, fp) != NULL) {
611 if (buf[0] != X_RQDFILE)
612 continue;
613 if (sscanf(&buf[1], "%s%s", ffile, tfile) < 2)
614 continue;
615 expfile(ffile);
616 sprintf(tfull, "%s/%s", XQTDIR, tfile);
617 unlink(subfile(tfull));
618 if (xmv(ffile, tfull) != 0) {
619 syslog(LOG_WARNING, "xmv(%s,%s) failed: %m",
620 ffile, tfull);
621 cleanup(1);
622 }
623 }
624 fclose(fp);
625 }
626
627 /*
628 * check for valid command/argument
629 * *NOTE - side effect is to set xc to the command to be executed.
630 *
631 * return 0 - ok | 1 nok
632 */
633
argok(xc,cmd)634 argok(xc, cmd)
635 register char *xc, *cmd;
636 {
637 register char **ptr;
638
639 #ifndef ALLOK
640 if (strpbrk(cmd, BADCHARS) != NULL) {
641 DEBUG(1,"MAGIC CHARACTER FOUND\n", CNULL);
642 logent(cmd, "NASTY MAGIC CHARACTER FOUND");
643 return FAIL;
644 }
645 #endif !ALLOK
646
647 if (xc[0] != '\0')
648 return SUCCESS;
649
650 #ifndef ALLOK
651 ptr = Cmds;
652 DEBUG(9, "Compare %s and\n", cmd);
653 while(*ptr != NULL) {
654 DEBUG(9, "\t%s\n", *ptr);
655 if (strcmp(cmd, *ptr) == SAME)
656 break;
657 ptr++;
658 }
659 if (*ptr == NULL) {
660 DEBUG(1,"COMMAND NOT FOUND\n", CNULL);
661 return FAIL;
662 }
663 #endif
664 strcpy(xc, cmd);
665 DEBUG(9, "MATCHED %s\n", xc);
666 return SUCCESS;
667 }
668
669
670 /*
671 * if notification should be sent for successful execution of cmd
672 *
673 * return NT_YES - do notification
674 * NT_ERR - do notification if exit status != 0
675 * NT_NO - don't do notification ever
676 */
677
chknotify(cmd)678 chknotify(cmd)
679 char *cmd;
680 {
681 register char **ptr;
682 register int *nptr;
683
684 ptr = Cmds;
685 nptr = Notify;
686 while (*ptr != NULL) {
687 if (strcmp(cmd, *ptr) == SAME)
688 return *nptr;
689 ptr++;
690 nptr++;
691 }
692 return NT_YES; /* "shouldn't happen" */
693 }
694
695
696
697 /*
698 * send mail to user giving execution results
699 */
700
notify(user,rmt,cmd,str)701 notify(user, rmt, cmd, str)
702 char *user, *rmt, *cmd, *str;
703 {
704 char text[BUFSIZ*2];
705 char ruser[MAXFULLNAME];
706
707 if (strpbrk(user, BADCHARS) != NULL) {
708 char lbuf[MAXFULLNAME];
709 sprintf(lbuf, "%s INVALID CHARACTER IN USERNAME", user);
710 logent(cmd, lbuf);
711 strcpy(user, "postmaster");
712 }
713 sprintf(text, "uuxqt cmd (%s) status (%s)", cmd, str);
714 if (prefix(rmt, Myname))
715 strcpy(ruser, user);
716 else
717 sprintf(ruser, "%s!%s", rmt, user);
718 mailst(ruser, text, CNULL);
719 }
720
721 /*
722 * return mail to sender
723 *
724 */
retosndr(user,rmt,file)725 retosndr(user, rmt, file)
726 char *user, *rmt, *file;
727 {
728 char ruser[MAXFULLNAME];
729
730 if (strpbrk(user, BADCHARS) != NULL) {
731 char lbuf[MAXFULLNAME];
732 sprintf(lbuf, "%s INVALID CHARACTER IN USERNAME", user);
733 logent(file, lbuf);
734 strcpy(user, "postmaster");
735 }
736 if (strcmp(rmt, Myname) == SAME)
737 strcpy(ruser, user);
738 else
739 sprintf(ruser, "%s!%s", rmt, user);
740
741 if (anyread(file) == 0)
742 mailst(ruser, "Mail failed. Letter returned to sender.\n", file);
743 else
744 mailst(ruser, "Mail failed. Letter returned to sender.\n", CNULL);
745 return;
746 }
747
748 /*
749 * execute shell of command with fi and fo as standard input/output
750 */
751
shio(cmd,fi,fo)752 shio(cmd, fi, fo)
753 char *cmd, *fi, *fo;
754 {
755 int status, f;
756 int pid, ret;
757 char *args[256];
758 extern int errno;
759
760 if (fi == NULL)
761 fi = DEVNULL;
762 if (fo == NULL)
763 fo = DEVNULL;
764
765 getargs(cmd, args, 256);
766 DEBUG(3, "shio - %s\n", cmd);
767 #ifdef SIGCHLD
768 signal(SIGCHLD, SIG_IGN);
769 #endif SIGCHLD
770 if ((pid = fork()) == 0) {
771 signal(SIGINT, SIG_IGN);
772 signal(SIGHUP, SIG_IGN);
773 signal(SIGQUIT, SIG_IGN);
774 close(Ifn);
775 close(Ofn);
776 close(0);
777 setuid(getuid());
778 f = open(subfile(fi), 0);
779 if (f != 0) {
780 logent(fi, "CAN'T READ");
781 exit(-errno);
782 }
783 close(1);
784 f = creat(subfile(fo), 0666);
785 if (f != 1) {
786 logent(fo, "CAN'T WRITE");
787 exit(-errno);
788 }
789 execvp(args[0], args);
790 exit(100+errno);
791 }
792 while ((ret = wait(&status)) != pid && ret != -1)
793 ;
794 DEBUG(3, "status %d\n", status);
795 return status;
796 }
797