📄 slocal.c
字号:
/* slocal.c - MH style mailer to write to a local user's mailbox */#ifndef lintstatic char ident[] = "@(#)$Id: slocal.c,v 1.2 90/11/25 19:05:52 sharpe Exp $";#endif lint/* This program implements mail delivery in the MH/MMDF style. Under SendMail, users should add the line "| /usr/local/lib/mh/slocal" to their $HOME/.forward file. Under MMDF-I, users should (symbolically) link /usr/local/lib/mh/slocal to $HOME/bin/rcvmail. Under stand-alone MH, post will automatically run this during local delivery. This program should be used ONLY if you have "mts sendmail" or "mts mh" or "mts mmdf1" set in your MH configuration. *//* */#include "../h/mh.h"#include "../h/dropsbr.h"#include "../h/rcvmail.h"#include "../zotnet/tws.h"#include "../zotnet/mts.h"#include <pwd.h>#include <signal.h>#ifndef V7#ifndef NOIOCTLH#include <sys/ioctl.h>#endif NOIOCTLH#endif not V7#include <sys/stat.h>#include <utmp.h>#define NVEC 100/* */static struct swit switches[] = {#define ADDRSW 0 "addr address", 0,#define USERSW 1 "user name", 0,#define FILESW 2 "file file", 0,#define SENDSW 3 "sender address", 0,#define MBOXSW 4 "mailbox file", 0,#define HOMESW 5 "home directory", 0,#define MAILSW 6 "maildelivery file", 0,#define VERBSW 7 "verbose", 0,#define NVERBSW 8 "noverbose", 0,#define DEBUGSW 9 "debug", 0,#define HELPSW 10 "help", 4, NULL, NULL};/* */static int debug = 0;static int globbed = 0;static int parsed = 0;static int utmped = 0;static int verbose = 0;static char *addr = NULLCP;static char *user = NULLCP;static char *info = NULLCP;static char *file = NULLCP;static char *sender = NULLCP;static char *unixfrom = NULLCP;static char *mbox = NULLCP;static char *home = NULLCP;static struct passwd *pw;static char ddate[BUFSIZ];struct tws *now;static jmp_buf myctx;/* */static struct pair { char *p_name; char *p_value; char p_flags;#define P_NIL 0x00#define P_ADR 0x01#define P_HID 0x02#define P_CHK 0x04};static struct pair *lookup ();static struct pair hdrs[NVEC + 1] = { "source", NULL, P_HID, "addr", NULL, P_HID, "Return-Path", NULL, P_ADR, "Reply-To", NULL, P_ADR, "From", NULL, P_ADR, "Sender", NULL, P_ADR, "To", NULL, P_ADR, "cc", NULL, P_ADR, "Resent-Reply-To", NULL, P_ADR, "Resent-From", NULL, P_ADR, "Resent-Sender", NULL, P_ADR, "Resent-To", NULL, P_ADR, "Resent-cc", NULL, P_ADR, NULL};static struct pair vars[] = { "sender", NULL, P_NIL, "address", NULL, P_NIL, "size", NULL, P_NIL, "reply-to", NULL, P_CHK, "info", NULL, P_NIL, NULL};/* */extern char **environ;static void adorn ();static int alrmser ();long lseek ();#ifdef SYS5struct passwd *getpwnam ();#endif SYS5static int localmail(), usr_delivery(), split(), parse(), logged_in();static int timely(), usr_file(), usr_pipe(), copyfile();static expand(), glob(), copyinfo();/* *//* ARGSUSED */main (argc, argv, envp)int argc;char **argv, **envp;{ int fd; FILE *fp = stdin; char *cp, *mdlvr = NULL, buf[100], from[BUFSIZ], mailbox[BUFSIZ], tmpfil[BUFSIZ], **argp = argv + 1; invo_name = r1bindex (*argv, '/'); m_foil (NULLCP); mts_init (invo_name);/* */ while (cp = *argp++) { if (*cp == '-') switch (smatch (++cp, switches)) { case AMBIGSW: ambigsw (cp, switches); done (1); case UNKWNSW: adios (NULLCP, "-%s unknown", cp); case HELPSW: (void) sprintf (buf, "%s [switches] [address info sender]", invo_name); help (buf, switches); done (1); case ADDRSW: if (!(addr = *argp++))/* allow -xyz arguments */ adios (NULLCP, "missing argument to %s", argp[-2]); continue; case USERSW: if (!(user = *argp++))/* allow -xyz arguments */ adios (NULLCP, "missing argument to %s", argp[-2]); continue; case FILESW: if (!(file = *argp++) || *file == '-') adios (NULLCP, "missing argument to %s", argp[-2]); continue; case SENDSW: if (!(sender = *argp++))/* allow -xyz arguments */ adios (NULLCP, "missing argument to %s", argp[-2]); continue; case MBOXSW: if (!(mbox = *argp++) || *mbox == '-') adios (NULLCP, "missing argument to %s", argp[-2]); continue; case HOMESW: if (!(home = *argp++) || *home == '-') adios (NULLCP, "missing argument to %s", argp[-2]); continue; case MAILSW: if (!(cp = *argp++) || *cp == '-') adios (NULLCP, "missing argument to %s", argp[-2]); if (mdlvr) adios (NULLCP, "only one maildelivery file at a time!"); mdlvr = cp; continue; case VERBSW: verbose++; continue; case NVERBSW: verbose = 0; continue; case DEBUGSW: debug++; continue; } switch (argp - (argv + 1)) { case 1: addr = cp; break; case 2: info = cp; break; case 3: sender = cp; break; } }/* */ if (addr == NULL) addr = getusr (); if (user == NULL) user = (cp = index (addr, '.')) ? ++cp : addr; if ((pw = getpwnam (user)) == NULL) adios (NULLCP, "no such local user as %s", user); if (chdir (pw -> pw_dir) == NOTOK) (void) chdir ("/"); (void) umask (0077); if (geteuid () == 0) {#ifdef BSD41A (void) inigrp (pw -> pw_name, pw -> pw_gid);#endif BSD41A (void) setgid (pw -> pw_gid);#ifdef BSD42 (void) initgroups (pw -> pw_name, pw -> pw_gid);#endif BSD42 (void) setuid (pw -> pw_uid); } if (info == NULL) info = ""; setbuf (stdin, NULLCP); if (file == NULL) { if ((fd = copyfile (fileno (stdin), file = tmpfil, 1)) == NOTOK) adios (NULLCP, "unable to create temporary file"); if (debug) fprintf (stderr, "temporary file \"%s\" selected\n", tmpfil); else (void) unlink (tmpfil); if ((fp = fdopen (fd, "r+")) == NULL) adios (NULLCP, "unable to access temporary file"); } else fd = fileno (stdin); from[0] = NULL; if (sender == NULL) copyinfo (fp, from); if (mbox == NULL) { (void) sprintf (mailbox, "%s/%s", mmdfldir[0] ? mmdfldir : pw -> pw_dir, mmdflfil[0] ? mmdflfil : pw -> pw_name); mbox = mailbox; } if (home == NULL) home = pw -> pw_dir; if ((now = dtwstime ()) == NULL) adios (NULLCP, "unable to ascertain local time"); (void) sprintf (ddate, "Delivery-Date: %s\n", dtimenow ()); if (debug) { fprintf (stderr, "addr=\"%s\" user=\"%s\" info=\"%s\" file=\"%s\"\n", addr, user, info, file); fprintf (stderr, "sender=\"%s\" mbox=\"%s\" home=\"%s\" from=\"%s\"\n", sender, mbox, home, from); fprintf (stderr, "ddate=\"%s\" now=%02d:%02d\n", ddate, now -> tw_hour, now -> tw_min); } done (localmail (fd, from, mdlvr) != NOTOK ? RCV_MOK : RCV_MBX);}/* */static int localmail (fd, from, mdlvr)int fd;char *from, *mdlvr;{ if (usr_delivery (fd, mdlvr ? mdlvr : ".maildelivery", 0, from) != NOTOK) return OK; if (usr_delivery (fd, maildelivery, 1, from) != NOTOK) return OK;#ifdef notdef if (verbose) printf ("(invoking hook)\n"); if (usr_hook (fd, mbox) != NOTOK) return OK;#endif notdef if (verbose) printf ("(trying normal delivery)\n"); return usr_file (fd, mbox, from);}/* */#define matches(a,b) (stringdex (b, a) >= 0)static int usr_delivery (fd, delivery, su, from)int fd, su;char *delivery, *from;{ int i, accept, status, won, vecp, next; register char *cp, *action, *field, *pattern, *string; char buffer[BUFSIZ], tmpbuf[BUFSIZ], *vec[NVEC]; struct stat st; register struct pair *p; register FILE *fp; if ((fp = fopen (delivery, "r")) == NULL) return NOTOK; if (fstat (fileno (fp), &st) == NOTOK || (st.st_uid != 0 && (su || st.st_uid != pw -> pw_uid)) || st.st_mode & 0022) { if (verbose) { printf ("%s: ownership/modes bad (%d, %d,%d,0%o)\n", delivery, su, pw -> pw_uid, st.st_uid, st.st_mode); (void) fflush (stdout); } return NOTOK; } won = 0; next = 1; while (fgets (buffer, sizeof buffer, fp) != NULL) { if (*buffer == '#') continue; if (cp = index (buffer, '\n')) *cp = NULL; if ((vecp = split (buffer, vec)) < 5) continue; if (debug) for (i = 0; vec[i]; i++) fprintf (stderr, "vec[%d]: \"%s\"\n", i, vec[i]); field = vec[0]; pattern = vec[1]; action = vec[2]; switch (vec[3][0]) { case 'N': case 'n': if (! next) continue; /* if previous condition failed, don't do this - else fall through */ case '?': if (won) continue; /* else fall */ case 'A': case 'a': accept = 1; break; case 'R': case 'r': default: accept = 0; break; } string = vec[4]; if (vecp > 5) { if (uleq (vec[5], "select")) { if (logged_in () != NOTOK) continue; if (vecp > 7 && timely (vec[6], vec[7]) == NOTOK) continue; } } switch (*field) { case '*': break; case 'd': if (uleq (field, "default")) { if (won) continue; break; } /* else fall */ default: if (!parsed && parse (fd) == NOTOK) { (void) fclose (fp); return NOTOK; } if ((p = lookup (hdrs, field)) == NULL || (p->p_value == NULL) /* XXX */ || !matches (p -> p_value, pattern)) { next = 0; continue; } else next = 1; break; } switch (*action) { case 'q': if (!uleq (action, "qpipe")) continue; /* else fall */ case '^': expand (tmpbuf, string, fd); if (split (tmpbuf, vec) < 1) continue; status = usr_pipe (fd, tmpbuf, vec[0], vec); break; case 'p': if (!uleq (action, "pipe")) continue; /* else fall */ case '|': vec[2] = "sh"; vec[3] = "-c"; expand (tmpbuf, string, fd); vec[4] = tmpbuf; vec[5] = NULL; status = usr_pipe (fd, tmpbuf, "/bin/sh", vec + 2); break; case 'f': if (!uleq (action, "file")) continue; /* else fall */ case '>': status = usr_file (fd, string, from); /* UUCP format? */ break; case 'd': if (!uleq (action, "destroy")) continue; status = OK; break; } if (accept) { if (status == NOTOK) { won = 0; break; } won++; } } (void) fclose (fp); return (won ? OK : NOTOK);}/* */#define QUOTE '\\'static int split (cp, vec)char *cp, **vec;{ register int i; register char *s; for (i = 0, s = cp; i <= NVEC;) { vec[i] = NULL; while (isspace (*s) || *s == ',') *s++ = NULL; if (*s == NULL) break; if (*s == '"') { for (vec[i++] = ++s; *s != NULL && *s != '"'; s++) if (*s == QUOTE) { if (*++s == '"') (void) strcpy (s - 1, s); s--; } if (*s == '"') *s++ = NULL; continue; } if (*s == QUOTE && *++s != '"') s--; vec[i++] = s++; while (*s != NULL && !isspace (*s) && *s != ',') s++; } vec[i] = NULL; return i;}/* */static int parse (fd)register int fd;{ register int i, state; int fd1; register char *cp, *dp, *lp; char name[NAMESZ], field[BUFSIZ]; register struct pair *p, *q; register FILE *in; if (parsed++) return OK; if ((fd1 = dup (fd)) == NOTOK) return NOTOK; if ((in = fdopen (fd1, "r")) == NULL) { (void) close (fd1); return NOTOK; } rewind (in); if (p = lookup (hdrs, "source")) p -> p_value = getcpy (sender); if (p = lookup (hdrs, "addr"))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -