|
|
1.1 root 1: /* umhook.c - one attempt at a rcvmail hook for UUCP mail */
2:
3: /* I don't comment my code heavily, so read this...
4:
5: You run this program from your .login file. The invocation is simply
6: "umhook". The program "detaches" itself and runs unattended until you
7: logout. Whenever you get UUCP mail (or upto a minute afterwards),
8: umhook will filter your UUCP mail drop to a temporary file. The mail
9: drop is *NOT* touched beyond this (even the access time remains the
10: same). For each message that was new in the mail drop, umhook will
11: fork a process to interpret your .maildelivery file.
12:
13: The umhook program uses the -ljobs control facility to do two things:
14: - determine when the controlling tty has gone away
15: - kill a child that's run away (the child sets up a process group)
16: */
17:
18: #include "../h/mh.h"
19: #include "../zotnet/mf.h"
20: #include <stdio.h>
21: #include "../zotnet/mts.h"
22: #include <pwd.h>
23: #include <signal.h>
24: #include <sys/ioctl.h>
25: #include <sys/types.h>
26: #include <sys/stat.h>
27:
28: /* */
29:
30: static struct swit switches[] = {
31: #define SLEEPSW 0
32: "sleep seconds", 0,
33:
34: #define HELPSW 1
35: "help", 4,
36:
37: NULL, NULL
38: };
39:
40: /* */
41:
42: static int snooze = 60;
43:
44: static int uucp = NOTOK;
45:
46: extern char *environ;
47:
48: static char myhome[BUFSIZ] = "";
49: static char mymail[BUFSIZ] = "";
50: static char myaddr[BUFSIZ] = "";
51: static char mystat[BUFSIZ] = "";
52: static char myuser[BUFSIZ] = "";
53:
54: int sigser ();
55:
56: long lseek ();
57: #ifdef SYS5
58: struct passwd *getpwuid ();
59: #endif SYS5
60:
61: /* */
62:
63: /* ARGSUSED */
64:
65: main (argc, argv)
66: int argc;
67: char **argv;
68: {
69: char *cp,
70: **ap,
71: **argp,
72: buf[100],
73: *arguments[MAXARGS];
74: struct passwd *pw;
75:
76: invo_name = r1bindex (argv[0], '/');
77: mts_init (invo_name);
78: if ((cp = m_find (invo_name)) != NULL) {
79: ap = brkstring (cp = getcpy (cp), " ", "\n");
80: ap = copyip (ap, arguments);
81: }
82: else
83: ap = arguments;
84: (void) copyip (argv + 1, ap);
85: argp = arguments;
86:
87: /* */
88:
89: while (cp = *argp++) {
90: if (*cp == '-')
91: switch (smatch (++cp, switches)) {
92: case AMBIGSW:
93: ambigsw (cp, switches);
94: done (1);
95: case UNKWNSW:
96: adios (NULLCP, "-%s unknown", cp);
97: case HELPSW:
98: (void) sprintf (buf, "%s [switches]", invo_name);
99: help (buf, switches);
100: done (1);
101:
102: case SLEEPSW:
103: if (!(cp = *argp++) || *cp == '-')
104: adios (NULLCP, "missing argument to %s", argp[-2]);
105: if ((snooze = atoi (cp)) < 0)
106: adios (NULLCP, "bad argument %s %s", argp[-2], cp);
107: continue;
108: }
109: adios (NULLCP, "usage: %s [switches]", invo_name);
110: }
111:
112: /* */
113:
114: if ((pw = getpwuid (getuid ())) == NULL)
115: adios (NULLCP, "you lose big");
116:
117: *environ = NULL;
118: (void) putenv ("USER", pw -> pw_name);
119: (void) putenv ("HOME", pw -> pw_dir);
120: (void) putenv ("SHELL", pw -> pw_shell);
121: if (chdir (pw -> pw_dir) == NOTOK)
122: (void) chdir ("/");
123: (void) umask (0077);
124:
125: if (geteuid () == 0) {
126: #ifdef BSD41A
127: (void) inigrp (pw -> pw_name, pw -> pw_gid);
128: #endif BSD41A
129: (void) setgid (pw -> pw_gid);
130: #ifdef BSD42
131: (void) initgroups (pw -> pw_name, pw -> pw_gid);
132: #endif BSD42
133: (void) setuid (pw -> pw_uid);
134: }
135:
136: (void) sprintf (mymail, "%s/%s",
137: uucpldir[0] ? uucpldir : pw -> pw_dir,
138: uucplfil[0] ? uucplfil : pw -> pw_name);
139: (void) strcpy (myuser, pw -> pw_name);
140: (void) sprintf (myaddr, "%s@%s", pw -> pw_name, LocalName ());
141: (void) strcpy (myhome, pw -> pw_dir);
142: (void) sprintf (mystat, ".%s_%d", invo_name, pw -> pw_uid);
143:
144: if (access (slocalproc, 1) == NOTOK)
145: adios (slocalproc, "unable to execute");
146:
147: closefds (fileno (stderr) + 1);
148:
149: (void) signal (SIGINT, SIG_IGN);
150: (void) signal (SIGHUP, sigser);
151: (void) signal (SIGQUIT, SIG_IGN);
152: (void) signal (SIGTERM, sigser);
153:
154: switch (fork ()) {
155: case NOTOK:
156: case OK:
157: umhook ();
158: break;
159:
160: default:
161: break;
162: }
163:
164: exit (0);
165: }
166:
167: /* */
168:
169: #ifndef TIOCGPGRP
170: #define pgrp_ok(pg) 1
171: #else TIOCGPGRP
172: #define pgrp_ok(pg) (ioctl (2, TIOCGPGRP, (char *) &pg) != NOTOK)
173: #endif TIOCGPGRP
174:
175: static umhook () {
176: int pg;
177: struct stat st1,
178: st2;
179:
180: st_init (&st1);
181:
182: for (; pgrp_ok (pg);) {
183: if (stat (mymail, &st2) == NOTOK) {
184: st2.st_ino = (ino_t) 0;
185: st2.st_size = (off_t) 0;
186: st2.st_mtime = (time_t) 0;
187: }
188: else
189: if (st1.st_mtime != st2.st_mtime)
190: if (st1.st_ino != st2.st_ino)
191: process ((off_t) 0, &st2);
192: else
193: if (st1.st_size < st2.st_size)
194: process (st1.st_size, &st2);
195:
196: st1.st_ino = st2.st_ino;
197: st1.st_size = st2.st_size;
198: st1.st_mtime = st2.st_mtime;
199:
200: sleep ((unsigned) snooze);
201: }
202: }
203:
204: /* */
205:
206: static process (offset, st)
207: off_t offset;
208: struct stat *st;
209: {
210: int td1,
211: td2;
212: time_t timep[2];
213: char tmpfil[BUFSIZ];
214: register FILE *fp;
215:
216: if ((uucp = lkopen (mymail, 0)) == NOTOK)
217: adios (NULLCP, "unable to lock and open %s", mymail);
218: if (lseek (uucp, (long) offset, 0) == (long) NOTOK)
219: adios (mymail, "unable to position to %ld offset on", offset);
220:
221: (void) strcpy (tmpfil, m_tmpfil (invo_name));
222: if ((td1 = creat (tmpfil, TMPMODE)) == NOTOK)
223: adios (tmpfil, "unable to create");
224: (void) close (td1);
225:
226: if ((td1 = open (tmpfil, 2)) == NOTOK)
227: adios (tmpfil, "unable to open");
228: (void) unlink (tmpfil);
229: if ((td2 = dup (td1)) == NOTOK)
230: adios ("file descriptor", "unable to dup");
231:
232: switch (uucp2mmdf (uucp, td1, FALSE)) {
233: case MFPRM:
234: adios (NULLCP, "internal error while filtering UUCP mail");
235:
236: case MFSIO:
237: adios (NULLCP, "no free file pointers");
238:
239: case MFERR:
240: adios ("UUCP mail", "i/o error while filtering");
241:
242: case MFOK:
243: case MFROM:
244: case MFHDR:
245: case MFTXT:
246: timep[0] = st -> st_atime;
247: timep[1] = st -> st_mtime;
248: utime (mymail, timep);
249: st_update (st);
250: break;
251: }
252: (void) lkclose (uucp, mymail), uucp = NOTOK;
253:
254: /* */
255:
256: (void) close (td1);
257:
258: (void) lseek (td2, 0L, 0);
259: if ((fp = fdopen (td2, "r")) == NULL)
260: adios (NULLCP, "no free file pointers");
261:
262: while (hook (fp))
263: continue;
264: (void) fclose (fp);
265: }
266:
267: /* */
268:
269: static int hook (in)
270: register FILE *in;
271: {
272: int child_id,
273: done,
274: fd1,
275: fd2,
276: i;
277: char buffer[BUFSIZ],
278: mysndr[BUFSIZ],
279: myfile[BUFSIZ];
280: register FILE *out;
281:
282: if (fgets (buffer, sizeof buffer, in) == NULL)
283: return FALSE;
284:
285: /* should insist on isdlm1 (buffer) here... */
286:
287: (void) strcpy (myfile, m_tmpfil (invo_name));
288: if ((fd1 = creat (myfile, TMPMODE)) == NOTOK)
289: adios (myfile, "unable to create");
290: (void) close (fd1);
291:
292: if ((fd1 = open (myfile, 2)) == NOTOK)
293: adios (myfile, "unable to open");
294: (void) unlink (myfile);
295: if ((fd2 = dup (fd1)) == NOTOK)
296: adios ("file descriptor", "unable to dup");
297:
298: if ((out = fdopen (fd1, "w")) == NULL)
299: adios (NULLCP, "no free file pointers");
300:
301: for (done = TRUE;;) {
302: if (fgets (buffer, sizeof buffer, in) == NULL)
303: break; /* should be error */
304: if (done && isdlm2 (buffer))
305: break;
306: done = buffer[strlen (buffer) - 1] == '\n';
307: fputs (buffer, out);
308: }
309: (void) fclose (out);
310:
311: (void) lseek (fd2, 0L, 0);
312: seeksndr (fd2, mysndr);
313:
314: /* */
315:
316: switch (child_id = fork ()) {
317: case NOTOK:
318: adios ("fork", "unable to");/* NOTREACHED */
319:
320: case OK:
321: (void) lseek (fd2, 0L, 0);
322: if (fd2 != 0)
323: (void) dup2 (fd2, 0);
324: (void) freopen ("/dev/null", "w", stdout);
325: (void) freopen ("/dev/null", "w", stderr);
326: if (fd2 != 3)
327: (void) dup2 (fd2, 3);
328: closefds (4);
329: #ifdef TIOCNOTTY
330: if ((i = open ("/dev/tty", 2)) != NOTOK) {
331: (void) ioctl (i, TIOCNOTTY, NULLCP);
332: (void) close (i);
333: }
334: #endif TIOCNOTTY
335: #ifdef BSD42
336: (void) setpgrp (0, getpid ());
337: #endif BSD42
338:
339: execlp (slocalproc, r1bindex (slocalproc, '/'),
340: "-file", myfile, "-mailbox", mymail,
341: "-home", myhome, "-addr", myaddr,
342: "-user", myuser, "-sender", mysndr, NULLCP);
343: adios (slocalproc, "unable to exec");/* NOTREACHED */
344:
345: default:
346: (void) close (fd2);
347: (void) pidwait (child_id, OK);
348: return TRUE;
349: }
350: }
351:
352: /* */
353:
354: static seeksndr (fd1, mysndr)
355: int fd1;
356: char *mysndr;
357: {
358: int fd2;
359: char *bp,
360: *hp,
361: from[BUFSIZ],
362: sender[BUFSIZ];
363: register FILE *in;
364:
365: if ((fd2 = dup (fd1)) == NOTOK)
366: adios ("file descriptor", "unable to dup");
367: if ((in = fdopen (fd2, "r")) == NULL)
368: adios (NULLCP, "no free file pointers");
369:
370: for (from[0] = sender[0] = NULL; mfgets (in, &hp) != DONE;)
371: if ((bp = index (hp, ':')) != NULL) {
372: *bp++ = NULL;
373: if (lequal (hp, "From"))
374: seekaddr (from, bp);
375: else
376: if (lequal (hp, "Sender"))
377: seekaddr (sender, bp);
378: }
379: (void) fclose (in);
380:
381: (void) strcpy (mysndr, sender[0] ? sender : from[0] ? from : myaddr);
382: }
383:
384: /* */
385:
386: static seekaddr (addr, bp)
387: char *addr,
388: *bp;
389: {
390: struct adrx *adrxp;
391:
392: if ((adrxp = seekadrx (bp)) == NULL)
393: return;
394: if (adrxp -> err || !adrxp -> mbox)
395: return;
396:
397: if (adrxp -> host)
398: (void) sprintf (addr, "%s@%s", adrxp -> mbox, adrxp -> host);
399: else
400: (void) strcpy (addr, adrxp -> mbox);
401:
402: while (seekadrx (NULLCP))
403: continue;
404: }
405:
406: /* */
407:
408: static st_init(st)
409: struct stat *st;
410: {
411: int fd;
412:
413: if ((fd = open (mystat, 0)) == NOTOK
414: || read (fd, (char *) st, sizeof *st) != (sizeof *st)) {
415: st -> st_ino = (ino_t) 0;
416: st -> st_size = (off_t) 0;
417: st -> st_mtime = (time_t) 0;
418: }
419: if (fd != NOTOK)
420: (void) close (fd);
421: }
422:
423:
424: static st_update(st)
425: struct stat *st;
426: {
427: static int fd = NOTOK;
428:
429: if (fd == NOTOK
430: && (fd = creat (mystat, TMPMODE)) == NOTOK)
431: adios (mystat, "unable to write");
432:
433: (void) lseek (fd, 0L, 0);
434: if (write (fd, (char *) st, sizeof *st) != (sizeof *st))
435: adios (mystat, "error writing");
436: }
437:
438: /* */
439:
440: #ifdef BSD42
441: /* ARGSUSED */
442: #endif BSD42
443:
444: static int sigser (sig)
445: int sig;
446: {
447: #ifndef BSD42
448: (void) signal (sig, SIG_IGN);
449: #endif BSD42
450:
451: done (1);
452: }
453:
454: /* */
455:
456: void done (status)
457: int status;
458: {
459: (void) lkclose (uucp, mymail), uucp = NOTOK;
460: exit (status);
461: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.