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: }