X-Git-Url: http://git.marmaro.de/?a=blobdiff_plain;f=uip%2Fpost.c;h=3c4716100120e4a0d9c8d40a96e33c81c2b482d9;hb=374ece2e88368afd6e0a29c4ee4b75ffa9e28b39;hp=d91e003817c17b5cc46e915dd6b861a6ee137a55;hpb=8f4c5da8971926f7eccc912f7998c343aef3c33b;p=mmh diff --git a/uip/post.c b/uip/post.c index d91e003..3c47161 100644 --- a/uip/post.c +++ b/uip/post.c @@ -2,7 +2,9 @@ /* * post.c -- enter messages into the mail transport system * - * $Id$ + * This code is Copyright (c) 2002, by the authors of nmh. See the + * COPYRIGHT file in the root directory of the nmh distribution for + * complete copyright information. */ #include @@ -12,37 +14,20 @@ #include #include #include +#include #include -#include +#include #include -#include #include -#ifdef TIME_WITH_SYS_TIME +#ifdef HAVE_SYS_TIME_H # include -# include -#else -# ifdef TM_IN_SYS_TIME -# include -# else -# include -# endif #endif +#include -#ifdef MMDFMTS -# include -# include -#endif - -#ifdef SMTPMTS -# include -#endif - -#ifndef MMDFMTS -# define uptolow(c) ((isalpha(c) && isupper (c)) ? tolower (c) : (c)) -#endif +#include #ifndef CYRUS_SASL # define SASLminc(a) (a) @@ -50,6 +35,12 @@ # define SASLminc(a) 0 #endif /* CYRUS_SASL */ +#ifndef TLS_SUPPORT +# define TLSminc(a) (a) +#else /* TLS_SUPPORT */ +# define TLSminc(a) 0 +#endif /* TLS_SUPPORT */ + #define FCCS 10 /* max number of fccs allowed */ /* In the following array of structures, the numeric second field of the @@ -108,38 +99,40 @@ static struct swit switches[] = { { "dashstuffing", -12 }, /* should we dashstuff BCC messages? */ #define NBITSTUFFSW 23 { "nodashstuffing", -14 }, -#define MAILSW 24 - { "mail", -4 }, /* specify MAIL smtp mode */ -#define SAMLSW 25 - { "saml", -4 }, /* specify SAML smtp mode */ -#define SENDSW 26 - { "send", -4 }, /* specify SEND smtp mode */ -#define SOMLSW 27 - { "soml", -4 }, /* specify SOML smtp mode */ -#define ANNOSW 28 +#define ANNOSW 24 { "idanno number", -6 }, /* interface from send */ -#define DLVRSW 29 - { "deliver address-list", -7 }, -#define CLIESW 30 +#define CLIESW 25 { "client host", -6 }, -#define SERVSW 31 - { "server host", -6 }, /* specify alternate SMTP server */ -#define SNOOPSW 32 +#define SERVSW 26 + { "server host", 6 }, /* specify alternate SMTP server */ +#define SNOOPSW 27 { "snoop", -5 }, /* snoop the SMTP transaction */ -#define FILLSW 33 - { "fill-in file", -7 }, -#define FILLUSW 34 - { "fill-up", -7 }, -#define PARTSW 35 +#define PARTSW 28 { "partno", -6 }, -#define QUEUESW 36 +#define QUEUESW 29 { "queued", -6 }, -#define SASLSW 37 +#define SASLSW 30 { "sasl", SASLminc(-4) }, -#define SASLMECHSW 38 +#define NOSASLSW 31 + { "nosasl", SASLminc(-6) }, +#define SASLMXSSFSW 32 + { "saslmaxssf", SASLminc(-10) }, +#define SASLMECHSW 33 { "saslmech", SASLminc(-5) }, -#define USERSW 39 +#define USERSW 34 { "user", SASLminc(-4) }, +#define PORTSW 35 + { "port server port name/number", 4 }, +#define TLSSW 36 + { "tls", TLSminc(-3) }, +#define NTLSSW 37 + { "notls", TLSminc(-5) }, +#define FILEPROCSW 38 + { "fileproc", -4 }, +#define MHLPROCSW 39 + { "mhlproc", -3 }, +#define MTSSW 40 + { "mts smtp|sendmail/smtp|sendmail/pipe", 2 }, { NULL, 0 } }; @@ -153,50 +146,56 @@ struct headers { /* * flags for headers->flags */ -#define HNOP 0x0000 /* just used to keep .set around */ -#define HBAD 0x0001 /* bad header - don't let it through */ -#define HADR 0x0002 /* header has an address field */ -#define HSUB 0x0004 /* Subject: header */ -#define HTRY 0x0008 /* try to send to addrs on header */ -#define HBCC 0x0010 /* don't output this header */ -#define HMNG 0x0020 /* munge this header */ -#define HNGR 0x0040 /* no groups allowed in this header */ -#define HFCC 0x0080 /* FCC: type header */ -#define HNIL 0x0100 /* okay for this header not to have addrs */ -#define HIGN 0x0200 /* ignore this header */ -#define HDCC 0x0400 /* another undocumented feature */ +#define HNOP 0x0000 /* just used to keep .set around */ +#define HBAD 0x0001 /* bad header - don't let it through */ +#define HADR 0x0002 /* header has an address field */ +#define HSUB 0x0004 /* Subject: header */ +#define HTRY 0x0008 /* try to send to addrs on header */ +#define HBCC 0x0010 /* don't output this header, unless MTS_SENDMAIL_PIPE */ +#define HMNG 0x0020 /* munge this header */ +#define HNGR 0x0040 /* no groups allowed in this header */ +#define HFCC 0x0080 /* FCC: type header */ +#define HNIL 0x0100 /* okay for this header not to have addrs */ +#define HIGN 0x0200 /* ignore this header */ +#define HDCC 0x0400 /* another undocumented feature */ +#define HONE 0x0800 /* Only (zero or) one address allowed */ +#define HEFM 0x1000 /* Envelope-From: header */ /* * flags for headers->set */ -#define MFRM 0x0001 /* we've seen a From: */ -#define MDAT 0x0002 /* we've seen a Date: */ -#define MRFM 0x0004 /* we've seen a Resent-From: */ -#define MVIS 0x0008 /* we've seen sighted addrs */ -#define MINV 0x0010 /* we've seen blind addrs */ +#define MFRM 0x0001 /* we've seen a From: */ +#define MDAT 0x0002 /* we've seen a Date: */ +#define MRFM 0x0004 /* we've seen a Resent-From: */ +#define MVIS 0x0008 /* we've seen sighted addrs */ +#define MINV 0x0010 /* we've seen blind addrs */ +#define MSND 0x0020 /* we've seen a Sender: */ +#define MRSN 0x0040 /* We've seen a Resent-Sendr:*/ +#define MEFM 0x0080 /* We've seen Envelope-From: */ static struct headers NHeaders[] = { - { "Return-Path", HBAD, 0 }, - { "Received", HBAD, 0 }, - { "Reply-To", HADR|HNGR, 0 }, - { "From", HADR|HNGR, MFRM }, - { "Sender", HADR|HBAD, 0 }, - { "Date", HBAD, 0 }, - { "Subject", HSUB, 0 }, - { "To", HADR|HTRY, MVIS }, - { "cc", HADR|HTRY, MVIS }, - { "Bcc", HADR|HTRY|HBCC|HNIL, MINV }, - { "Dcc", HADR|HTRY|HDCC|HNIL, MVIS }, /* sorta cc & bcc combined */ - { "Message-ID", HBAD, 0 }, - { "Fcc", HFCC, 0 }, - { NULL, 0, 0 } + { "Return-Path", HBAD, 0 }, + { "Received", HBAD, 0 }, + { "Reply-To", HADR|HNGR, 0 }, + { "From", HADR|HNGR, MFRM }, + { "Sender", HADR|HNGR|HONE, MSND }, + { "Date", HBAD, 0 }, + { "Subject", HSUB, 0 }, + { "To", HADR|HTRY, MVIS }, + { "cc", HADR|HTRY, MVIS }, + { "Bcc", HADR|HTRY|HBCC|HNIL, MINV }, + { "Dcc", HADR|HTRY|HDCC|HNIL, MVIS }, /* sorta cc & bcc combined */ + { "Message-ID", HBAD, 0 }, + { "Fcc", HFCC, 0 }, + { "Envelope-From", HADR|HONE|HEFM, MEFM }, + { NULL, 0, 0 } }; static struct headers RHeaders[] = { { "Resent-Reply-To", HADR|HNGR, 0 }, { "Resent-From", HADR|HNGR, MRFM }, - { "Resent-Sender", HADR|HBAD, 0 }, + { "Resent-Sender", HADR|HNGR, MRSN }, { "Resent-Date", HBAD, 0 }, { "Resent-Subject", HSUB, 0 }, { "Resent-To", HADR|HTRY, MVIS }, @@ -206,16 +205,13 @@ static struct headers RHeaders[] = { { "Resent-Fcc", HFCC, 0 }, { "Reply-To", HADR, 0 }, { "From", HADR|HNGR, MFRM }, -#ifdef MMDFI - { "Sender", HADR|HNGR|HMNG, 0 }, -#else - { "Sender", HADR|HNGR, 0 }, -#endif + { "Sender", HADR|HNGR, MSND }, { "Date", HNOP, MDAT }, { "To", HADR|HNIL, 0 }, { "cc", HADR|HNIL, 0 }, { "Bcc", HADR|HTRY|HBCC|HNIL, 0 }, { "Fcc", HIGN, 0 }, + { "Envelope-From", HADR|HONE|HEFM, MEFM }, { NULL, 0, 0 } }; @@ -240,8 +236,13 @@ static int checksw = 0; /* whom -check */ static int linepos=0; /* putadr()'s position on the line */ static int nameoutput=0; /* putadr() has output header name */ static int sasl=0; /* Use SASL auth for SMTP */ +static int saslssf=-1; /* Our maximum SSF for SASL */ static char *saslmech=NULL; /* Force use of particular SASL mech */ static char *user=NULL; /* Authenticate as this user */ +static char *port="smtp"; /* Name of server port for SMTP */ +static int tls=0; /* Use TLS for encryption */ +static int fromcount=0; /* Count of addresses on From: header */ +static int seensender=0; /* Have we seen a Sender: header? */ static unsigned msgflags = 0; /* what we've seen */ @@ -257,6 +258,8 @@ static char tmpfil[BUFSIZ]; static char bccfil[BUFSIZ]; static char from[BUFSIZ]; /* my network address */ +static char sender[BUFSIZ]; /* my Sender: header */ +static char efrom[BUFSIZ]; /* my Envelope-From: header */ static char signature[BUFSIZ]; /* my signature */ static char *filter = NULL; /* the filter for BCC'ing */ static char *subject = NULL; /* the subject field for BCC'ing */ @@ -264,34 +267,22 @@ static char *fccfold[FCCS]; /* foldernames for FCC'ing */ static struct headers *hdrtab; /* table for the message we're doing */ -static struct mailname localaddrs={NULL}; /* local addrs */ -static struct mailname netaddrs={NULL}; /* network addrs */ -static struct mailname uuaddrs={NULL}; /* uucp addrs */ -static struct mailname tmpaddrs={NULL}; /* temporary queue */ - -#ifdef MMDFMTS -static char *submitmode = "m"; /* deliver to mailbox only */ -static char submitopts[6] = "vl"; /* initial options for submit */ -#endif /* MMDFMTS */ +static struct mailname localaddrs; /* local addrs */ +static struct mailname netaddrs; /* network addrs */ +static struct mailname uuaddrs; /* uucp addrs */ +static struct mailname tmpaddrs; /* temporary queue */ -#ifdef SMTPMTS static int snoop = 0; -static int smtpmode = S_MAIL; static char *clientsw = NULL; static char *serversw = NULL; extern struct smtp sm_reply; -#endif /* SMTPMTS */ static char prefix[] = "----- =_aaaaaaaaaa"; -static int fill_up = 0; -static char *fill_in = NULL; static char *partno = NULL; static int queued = 0; -extern boolean draft_from_masquerading; /* defined in mts.c */ - /* * static prototypes */ @@ -305,16 +296,16 @@ static int insert (struct mailname *); static void pl (void); static void anno (void); static int annoaux (struct mailname *); -static void insert_fcc (struct headers *, char *); +static void insert_fcc (struct headers *, unsigned char *); static void make_bcc_file (int); -static void verify_all_addresses (int); +static void verify_all_addresses (int, char *); static void chkadr (void); static void sigon (void); static void sigoff (void); static void p_refile (char *); static void fcc (char *, char *); static void die (char *, char *, ...); -static void post (char *, int, int); +static void post (char *, int, int, char *); static void do_text (char *file, int fd); static void do_an_address (struct mailname *, int); static void do_addresses (int, int); @@ -325,7 +316,7 @@ int main (int argc, char **argv) { int state, compnum, dashstuff = 0; - char *cp, *msg = NULL, **argp, **arguments; + char *cp, *msg = NULL, **argp, **arguments, *envelope; char buf[BUFSIZ], name[NAMESZ]; FILE *in, *out; @@ -342,10 +333,6 @@ main (int argc, char **argv) arguments = getarguments (invo_name, argc, argv, 0); argp = arguments; -#if defined(MMDFMTS) && defined(MMDFII) - mmdf_init (invo_name); -#endif /* MMDFMTS and MMDFII */ - while ((cp = *argp++)) { if (*cp == '-') { switch (smatch (++cp, switches)) { @@ -358,10 +345,10 @@ main (int argc, char **argv) case HELPSW: snprintf (buf, sizeof(buf), "%s [switches] file", invo_name); print_help (buf, switches, 0); - done (1); + done (0); case VERSIONSW: print_version(invo_name); - done (1); + done (0); case LIBSW: if (!(cp = *argp++) || *cp == '-') @@ -464,46 +451,6 @@ main (int argc, char **argv) adios (NULL, "bad argument %s %s", argp[-2], cp); continue; -#ifdef MMDFMTS - case MAILSW: - submitmode = "m"; - continue; - case SOMLSW: /* for right now, sigh... */ - case SAMLSW: - submitmode = "b"; - continue; - case SENDSW: - submitmode = "y"; - continue; -#endif /* MMDFMTS */ - - case DLVRSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - -#ifndef SMTPMTS - case CLIESW: - case SERVSW: - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - - case SNOOPSW: - continue; -#else /* SMTPMTS */ - case MAILSW: - smtpmode = S_MAIL; - continue; - case SAMLSW: - smtpmode = S_SAML; - continue; - case SOMLSW: - smtpmode = S_SOML; - continue; - case SENDSW: - smtpmode = S_SEND; - continue; case CLIESW: if (!(clientsw = *argp++) || *clientsw == '-') adios (NULL, "missing argument to %s", argp[-2]); @@ -515,15 +462,7 @@ main (int argc, char **argv) case SNOOPSW: snoop++; continue; -#endif /* SMTPMTS */ - case FILLSW: - if (!(fill_in = *argp++) || *fill_in == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case FILLUSW: - fill_up++; - continue; case PARTSW: if (!(partno = *argp++) || *partno == '-') adios (NULL, "missing argument to %s", argp[-2]); @@ -536,6 +475,16 @@ main (int argc, char **argv) case SASLSW: sasl++; continue; + + case NOSASLSW: + sasl = 0; + continue; + + case SASLMXSSFSW: + if (!(cp = *argp++) || *cp == '-') + adios (NULL, "missing argument to %s", argp[-2]); + saslssf = atoi(cp); + continue; case SASLMECHSW: if (!(saslmech = *argp++) || *saslmech == '-') @@ -546,6 +495,37 @@ main (int argc, char **argv) if (!(user = *argp++) || *user == '-') adios (NULL, "missing argument to %s", argp[-2]); continue; + + case PORTSW: + if (!(port = *argp++) || *port == '-') + adios (NULL, "missing argument to %s", argp[-2]); + continue; + + case TLSSW: + tls++; + continue; + + case NTLSSW: + tls = 0; + continue; + + case FILEPROCSW: + if (!(cp = *argp++) || *cp == '-') + adios (NULL, "missing argument to %s", argp[-2]); + fileproc = cp; + continue; + + case MHLPROCSW: + if (!(cp = *argp++) || *cp == '-') + adios (NULL, "missing argument to %s", argp[-2]); + mhlproc = cp; + continue; + + case MTSSW: + if (!(cp = *argp++) || *cp == '-') + adios (NULL, "missing argument to %s", argp[-2]); + save_mts_method (cp); + continue; } } if (msg) @@ -571,16 +551,17 @@ main (int argc, char **argv) discard (out = stdout); /* XXX: reference discard() to help loader */ } else { if (whomsw) { - if ((out = fopen (fill_in ? fill_in : "/dev/null", "w")) == NULL) + if ((out = fopen ("/dev/null", "w")) == NULL) adios ("/dev/null", "unable to open"); } else { - strncpy (tmpfil, m_scratch ("", m_maildir (invo_name)), - sizeof(tmpfil)); - if ((out = fopen (tmpfil, "w")) == NULL) { - strncpy (tmpfil, m_tmpfil (invo_name), sizeof(tmpfil)); - if ((out = fopen (tmpfil, "w")) == NULL) - adios (tmpfil, "unable to create"); - } + char *cp = m_mktemp(m_maildir(invo_name), NULL, &out); + if (cp == NULL) { + cp = m_mktemp2(NULL, invo_name, NULL, &out); + if (cp == NULL) { + adios ("post", "unable to create temporary file"); + } + } + strncpy(tmpfil, cp, sizeof(tmpfil)); chmod (tmpfil, 0600); } } @@ -608,7 +589,7 @@ main (int argc, char **argv) case BODY: case BODYEOF: finish_headers (out); - if (whomsw && !fill_in) + if (whomsw) break; fprintf (out, "\n%s", buf); while (state == BODY) { @@ -642,29 +623,46 @@ main (int argc, char **argv) fclose (out); } + /* + * Here's how we decide which address to use as the envelope-from + * address for SMTP. + * + * - If we were given an Envelope-From header, use that. + * - If we were given a Sender: address, use that. + * - Otherwise, use the address on the From: line + */ + + if (msgflags & MEFM) { + envelope = efrom; + } else if (seensender) { + envelope = sender; + } else { + envelope = from; + } + /* If we are doing a "whom" check */ if (whomsw) { - if (!fill_up) - verify_all_addresses (1); + /* This won't work with MTS_SENDMAIL_PIPE. */ + verify_all_addresses (1, envelope); done (0); } -#ifdef MMDFMTS - strcat (submitopts, submitmode); - if (watch) - strcat (submitopts, "nw"); -#endif /* MMDFMTS */ - if (msgflags & MINV) { make_bcc_file (dashstuff); if (msgflags & MVIS) { - verify_all_addresses (verbose); - post (tmpfil, 0, verbose); + if (sm_mts != MTS_SENDMAIL_PIPE) { + /* It would be nice to have support to call + verify_all_addresses with MTS_SENDMAIL_PIPE, but + that might require running sendmail as root. Note + that spost didn't verify addresses. */ + verify_all_addresses (verbose, envelope); + } + post (tmpfil, 0, verbose, envelope); } - post (bccfil, 1, verbose); + post (bccfil, 1, verbose, envelope); unlink (bccfil); } else { - post (tmpfil, 0, isatty (1)); + post (tmpfil, 0, isatty (1), envelope); } p_refile (tmpfil); @@ -673,7 +671,8 @@ main (int argc, char **argv) if (verbose) printf (partno ? "Partial Message #%s Processed\n" : "Message Processed\n", partno); - return done (0); + done (0); + return 1; } @@ -687,7 +686,7 @@ putfmt (char *name, char *str, FILE *out) int count, grp, i, keep; char *cp, *pp, *qp; char namep[BUFSIZ]; - struct mailname *mp, *np; + struct mailname *mp = NULL, *np = NULL; struct headers *hdr; while (*str == ' ' || *str == '\t') @@ -706,17 +705,11 @@ putfmt (char *name, char *str, FILE *out) hdr = &hdrtab[i]; if (hdr->flags & HIGN) { - if (fill_in) - fprintf (out, "%s: %s", name, str); return; } if (hdr->flags & HBAD) { - if (fill_in) - fprintf (out, "%s: %s", name, str); - else { - advise (NULL, "illegal header line -- %s:", name); - badmsg++; - } + advise (NULL, "illegal header line -- %s:", name); + badmsg++; return; } msgflags |= (hdr->set & ~(MVIS | MINV)); @@ -724,11 +717,6 @@ putfmt (char *name, char *str, FILE *out) if (hdr->flags & HSUB) subject = subject ? add (str, add ("\t", subject)) : getcpy (str); if (hdr->flags & HFCC) { - if (fill_in) { - fprintf (out, "%s: %s", name, str); - return; - } - if ((cp = strrchr(str, '\n'))) *cp = 0; for (cp = pp = str; (cp = strchr(pp, ',')); pp = cp) { @@ -763,6 +751,14 @@ putfmt (char *name, char *str, FILE *out) if (hdr->flags & HNIL) fprintf (out, "%s: %s", name, str); else { + /* + * Sender (or Resent-Sender) can have only one address + */ + if ((msgstate == RESENT) ? (hdr->set & MRSN) + : (hdr->set & MSND)) { + advise (NULL, "%s: field requires one address", name); + badmsg++; + } #ifdef notdef advise (NULL, "%s: field requires at least one address", name); badmsg++; @@ -771,9 +767,15 @@ putfmt (char *name, char *str, FILE *out) return; } + if (count > 1 && (hdr->flags & HONE)) { + advise (NULL, "%s: field only permits one address", name); + badmsg++; + return; + } + nameoutput = linepos = 0; snprintf (namep, sizeof(namep), "%s%s", - !fill_in && (hdr->flags & HMNG) ? "Original-" : "", name); + (hdr->flags & HMNG) ? "Original-" : "", name); for (grp = 0, mp = tmpaddrs.m_next; mp; mp = np) if (mp->m_nohost) { /* also used to test (hdr->flags & HTRY) */ @@ -789,17 +791,37 @@ putfmt (char *name, char *str, FILE *out) continue; } - if (draft_from_masquerading && ((msgstate == RESENT) - ? (hdr->set & MRFM) - : (hdr->set & MFRM))) - /* The user manually specified a [Resent-]From: address in - their draft and the "masquerade:" line in mts.conf - doesn't contain "draft_from", so we'll set things up to - use the actual email address embedded in the draft - [Resent-]From: (after alias substitution, and without the - GECOS full name or angle brackets) as the envelope - From:. */ + /* + * If it's a From: or Resent-From: header, save the address + * for later possible use (as the envelope address for SMTP) + */ + + if ((msgstate == RESENT) ? (hdr->set & MRFM) + : (hdr->set & MFRM)) { strncpy(from, auxformat(mp, 0), sizeof(from) - 1); + from[sizeof(from) - 1] = '\0'; + fromcount = count; + } + + /* + * Also save the Sender: or Resent-Sender: header as well + */ + + if ((msgstate == RESENT) ? (hdr->set & MRSN) + : (hdr->set & MSND)) { + strncpy(sender, auxformat(mp, 0), sizeof(sender) - 1); + sender[sizeof(sender) - 1] = '\0'; + seensender++; + } + + /* + * ALSO ... save Envelope-From + */ + + if (hdr->set & MEFM) { + strncpy(efrom, auxformat(mp, 0), sizeof(efrom) - 1); + efrom[sizeof(efrom) - 1] = '\0'; + } if (hdr->flags & HBCC) mp->m_bcc++; @@ -821,17 +843,37 @@ putfmt (char *name, char *str, FILE *out) } else { /* Address includes a host, so no alias substitution is needed. */ - if (draft_from_masquerading && ((msgstate == RESENT) - ? (hdr->set & MRFM) - : (hdr->set & MFRM))) - /* The user manually specified a [Resent-]From: address in - their draft and the "masquerade:" line in mts.conf - doesn't contain "draft_from", so we'll set things up to - use the actual email address embedded in the draft - [Resent-]From: (after alias substitution, and without the - GECOS full name or angle brackets) as the envelope - From:. */ + + /* + * If it's a From: or Resent-From header, save the address + * for later possible use (as the envelope address for SMTP) + */ + + if ((msgstate == RESENT) ? (hdr->set & MRFM) + : (hdr->set & MFRM)) { strncpy(from, auxformat(mp, 0), sizeof(from) - 1); + fromcount = count; + } + + /* + * Also save the Sender: header as well + */ + + if ((msgstate == RESENT) ? (hdr->set & MRSN) + : (hdr->set & MSND)) { + strncpy(sender, auxformat(mp, 0), sizeof(sender) - 1); + sender[sizeof(sender) - 1] = '\0'; + seensender++; + } + + /* + * ALSO ... save Envelope-From + */ + + if (hdr->set & MEFM) { + strncpy(efrom, auxformat(mp, 0), sizeof(efrom) - 1); + efrom[sizeof(efrom) - 1] = '\0'; + } if (hdr->flags & HBCC) mp->m_bcc++; @@ -854,8 +896,6 @@ putfmt (char *name, char *str, FILE *out) badmsg++; } if (linepos) { - if (fill_in && grp > 0) - putc (';', out); putc ('\n', out); } } @@ -864,24 +904,26 @@ putfmt (char *name, char *str, FILE *out) static void start_headers (void) { - char *cp; - char myhost[BUFSIZ], sigbuf[BUFSIZ]; + unsigned char *cp; + char sigbuf[BUFSIZ]; struct mailname *mp; myuid = getuid (); mygid = getgid (); time (&tclock); - strncpy (from, adrsprintf (NULL, NULL), sizeof(from)); - strncpy (myhost, LocalName (), sizeof(myhost)); + /* + * Probably not necessary, but just in case ... + */ - for (cp = myhost; *cp; cp++) - *cp = uptolow (*cp); + from[0] = '\0'; + efrom[0] = '\0'; + sender[0] = '\0'; if ((cp = getfullname ()) && *cp) { strncpy (sigbuf, cp, sizeof(sigbuf)); snprintf (signature, sizeof(signature), "%s <%s>", - sigbuf, adrsprintf (NULL, NULL)); + sigbuf, getlocaladdr()); if ((cp = getname (signature)) == NULL) adios (NULL, "getname () failed -- you lose extraordinarily big"); if ((mp = getm (cp, NULL, 0, AD_HOST, NULL)) == NULL) @@ -890,7 +932,7 @@ start_headers (void) while (getname ("")) continue; } else { - strncpy (signature, adrsprintf (NULL, NULL), sizeof(signature)); + strncpy (signature, getlocaladdr(), sizeof(signature)); } } @@ -906,27 +948,46 @@ finish_headers (FILE *out) { switch (msgstate) { case NORMAL: - if (whomsw && !fill_up) + if (!(msgflags & MFRM)) { + /* + * A From: header is now required in the draft. + */ + advise (NULL, "message has no From: header"); + advise (NULL, "See default components files for examples"); + badmsg++; + break; + } + + if (fromcount > 1 && (seensender == 0 && !(msgflags & MEFM))) { + advise (NULL, "A Sender: or Envelope-From: header is required " + "with multiple\nFrom: addresses"); + badmsg++; + break; + } + + if (whomsw) break; fprintf (out, "Date: %s\n", dtime (&tclock, 0)); if (msgid) fprintf (out, "Message-ID: <%d.%ld@%s>\n", - (int) getpid (), (long) tclock, LocalName ()); - if (msgflags & MFRM) { - /* There was already a From: in the draft. Don't add one. */ - if (!draft_from_masquerading) - /* mts.conf didn't contain "masquerade:[...]draft_from[...]" - so we'll reveal the user's actual account@thismachine - address in a Sender: header (and use it as the envelope - From: later). */ - fprintf (out, "Sender: %s\n", from); + (int) getpid (), (long) tclock, LocalName (1)); + /* + * If we have multiple From: addresses, make sure we have an + * Sender: header. If we don't have one, then generate one + * from Envelope-From: (which in this case, cannot be blank) + */ + + if (fromcount > 1 && seensender == 0) { + if (efrom[0] == '\0') { + advise (NULL, "Envelope-From cannot be blank when there " + "is multiple From: addresses\nand no Sender: " + "header"); + badmsg++; + } else { + fprintf (out, "Sender: %s\n", efrom); + } } - else - /* Construct a From: header. */ - fprintf (out, "From: %s\n", signature); - if (whomsw) - break; if (!(msgflags & MVIS)) fprintf (out, "Bcc: Blind Distribution List: ;\n"); @@ -941,31 +1002,43 @@ finish_headers (FILE *out) advise (NULL, "message has no From: header"); badmsg++; } - if (whomsw && !fill_up) + if (!(msgflags & MRFM)) { + advise (NULL, "message has no Resent-From: header"); + advise (NULL, "See default components files for examples"); + badmsg++; + break; + } + if (fromcount > 1 && (seensender == 0 && !(msgflags & MEFM))) { + advise (NULL, "A Resent-Sender: or Envelope-From: header is " + "required with multiple\nResent-From: addresses"); + badmsg++; break; + } -#ifdef MMDFI /* sigh */ - fprintf (out, "Sender: %s\n", from); -#endif /* MMDFI */ + if (whomsw) + break; fprintf (out, "Resent-Date: %s\n", dtime (&tclock, 0)); if (msgid) fprintf (out, "Resent-Message-ID: <%d.%ld@%s>\n", - (int) getpid (), (long) tclock, LocalName ()); - if (msgflags & MRFM) { - /* There was already a Resent-From: in draft. Don't add one. */ - if (!draft_from_masquerading) - /* mts.conf didn't contain "masquerade:[...]draft_from[...]" - so we'll reveal the user's actual account@thismachine - address in a Sender: header (and use it as the envelope - From: later). */ - fprintf (out, "Resent-Sender: %s\n", from); + (int) getpid (), (long) tclock, LocalName (1)); + /* + * If we have multiple Resent-From: addresses, make sure we have an + * Resent-Sender: header. If we don't have one, then generate one + * from Envelope-From (which in this case, cannot be blank) + */ + + if (fromcount > 1 && seensender == 0) { + if (efrom[0] == '\0') { + advise (NULL, "Envelope-From cannot be blank when there " + "is multiple Resent-From: addresses and no " + "Resent-Sender: header"); + badmsg++; + } else { + fprintf (out, "Resent-Sender: %s\n", efrom); + } } - else - /* Construct a Resent-From: header. */ - fprintf (out, "Resent-From: %s\n", signature); - if (whomsw) - break; + if (!(msgflags & MVIS)) fprintf (out, "Resent-Bcc: Blind Re-Distribution List: ;\n"); break; @@ -984,7 +1057,7 @@ get_header (char *header, struct headers *table) struct headers *h; for (h = table; h->value; h++) - if (!strcasecmp (header, h->value)) + if (!mh_strcasecmp (header, h->value)) return (h - table); return NOTOK; @@ -1000,7 +1073,8 @@ putadr (char *name, char *aka, struct mailname *mp, FILE *out, unsigned int flag if (mp->m_mbox == NULL || ((flags & HTRY) && !insert (mp))) return 0; - if ((!fill_in && (flags & (HBCC | HDCC))) || mp->m_ingrp) + if (sm_mts != MTS_SENDMAIL_PIPE && + ((flags & (HBCC | HDCC | HEFM)) || mp->m_ingrp)) return 1; if (!nameoutput) { @@ -1011,7 +1085,7 @@ putadr (char *name, char *aka, struct mailname *mp, FILE *out, unsigned int flag if (*aka && mp->m_type != UUCPHOST && !mp->m_pers) mp->m_pers = getcpy (aka); if (format) { - if (mp->m_gname && !fill_in) { + if (mp->m_gname) { snprintf (buffer, sizeof(buffer), "%s;", mp->m_gname); cp = buffer; } else { @@ -1044,17 +1118,15 @@ putgrp (char *name, char *group, FILE *out, unsigned int flags) int len; char *cp; - if (!fill_in && (flags & HBCC)) + if (sm_mts != MTS_SENDMAIL_PIPE && (flags & HBCC)) return; if (!nameoutput) { fprintf (out, "%s: ", name); linepos += (nameoutput = strlen (name) + 2); - if (fill_in) - linepos -= strlen (group); } - cp = fill_in ? group : concat (group, ";", NULL); + cp = concat (group, ";", NULL); len = strlen (cp); if (linepos > nameoutput) { @@ -1086,8 +1158,8 @@ insert (struct mailname *np) : &netaddrs; mp->m_next; mp = mp->m_next) - if (!strcasecmp (np->m_host, mp->m_next->m_host) - && !strcasecmp (np->m_mbox, mp->m_next->m_mbox) + if (!mh_strcasecmp (np->m_host, mp->m_next->m_host) + && !mh_strcasecmp (np->m_mbox, mp->m_next->m_mbox) && np->m_bcc == mp->m_next->m_bcc) return 0; @@ -1166,9 +1238,9 @@ annoaux (struct mailname *mp) static void -insert_fcc (struct headers *hdr, char *pp) +insert_fcc (struct headers *hdr, unsigned char *pp) { - char *cp; + unsigned char *cp; for (cp = pp; isspace (*cp); cp++) continue; @@ -1195,17 +1267,17 @@ make_bcc_file (int dashstuff) pid_t child_id; char *vec[6]; FILE *out; + char *tfile = NULL; - strncpy (bccfil, m_tmpfil ("bccs"), sizeof(bccfil)); - if ((out = fopen (bccfil, "w")) == NULL) - adios (bccfil, "unable to create"); + tfile = m_mktemp2(NULL, "bccs", NULL, &out); + if (tfile == NULL) adios("bcc", "unable to create temporary file"); chmod (bccfil, 0600); + strncpy (bccfil, tfile, sizeof(bccfil)); fprintf (out, "Date: %s\n", dtime (&tclock, 0)); if (msgid) fprintf (out, "Message-ID: <%d.%ld@%s>\n", - (int) getpid (), (long) tclock, LocalName ()); - fprintf (out, "From: %s\n", signature); + (int) getpid (), (long) tclock, LocalName (1)); if (subject) fprintf (out, "Subject: %s", subject); fprintf (out, "BCC:\n"); @@ -1314,19 +1386,16 @@ make_bcc_file (int dashstuff) static int find_prefix (void) { - int len, result; - char buffer[BUFSIZ]; + int result = OK; + unsigned char buffer[BUFSIZ]; FILE *in; if ((in = fopen (tmpfil, "r")) == NULL) adios (tmpfil, "unable to re-open"); - len = strlen (prefix); - - result = OK; while (fgets (buffer, sizeof(buffer) - 1, in)) if (buffer[0] == '-' && buffer[1] == '-') { - char *cp; + unsigned char *cp; for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--) if (!isspace (*cp)) @@ -1394,15 +1463,8 @@ do_addresses (int bccque, int talk) chkadr (); -#ifdef MMDFMTS - if (rp_isbad (retval = mm_waend ())) - die (NULL, "problem ending addresses [%s]\n", rp_valstr (retval)); -#endif /* MMDFMTS */ - -#ifdef SMTPMTS if (rp_isbad (retval = sm_waend ())) die (NULL, "problem ending addresses; %s", rp_string (retval)); -#endif /* SMTPMTS */ } @@ -1415,15 +1477,13 @@ do_addresses (int bccque, int talk) * SENDMAIL/SMTP routines */ -#ifdef SMTPMTS - static void -post (char *file, int bccque, int talk) +post (char *file, int bccque, int talk, char *envelope) { - int fd, onex; - int retval; + int fd; + int retval, i; + pid_t child_id; - onex = !(msgflags & MINV) || bccque; if (verbose) { if (msgflags & MINV) printf (" -- Posting for %s Recipients --\n", @@ -1434,38 +1494,71 @@ post (char *file, int bccque, int talk) sigon (); - if (rp_isbad (retval = sm_init (clientsw, serversw, watch, verbose, - snoop, onex, queued, sasl, saslmech, - user)) - || rp_isbad (retval = sm_winit (smtpmode, from))) - die (NULL, "problem initializing server; %s", rp_string (retval)); - - do_addresses (bccque, talk && verbose); - if ((fd = open (file, O_RDONLY)) == NOTOK) - die (file, "unable to re-open"); - do_text (file, fd); - close (fd); - fflush (stdout); + if (sm_mts == MTS_SENDMAIL_PIPE) { + char *sargv[16], **argp; - sm_end (onex ? OK : DONE); - sigoff (); + for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) + sleep (5); + switch (child_id) { + case NOTOK: + adios ("fork", "unable to"); - if (verbose) { - if (msgflags & MINV) - printf (" -- %s Recipient Copies Posted --\n", - bccque ? "Blind" : "Sighted"); - else - printf (" -- Recipient Copies Posted --\n"); - } + case OK: + if (freopen( file, "r", stdin) == NULL) { + adios (file, "can't reopen for sendmail"); + } - fflush (stdout); + argp = sargv; + *argp++ = "sendmail"; + *argp++ = "-t"; /* read msg for recipients */ + *argp++ = "-i"; /* don't stop on "." */ + if (whomsw) + *argp++ = "-bv"; + if (snoop) + *argp++ = "-v"; + *argp = NULL; + + execv (sendmail, sargv); + adios (sendmail, "can't exec"); + + default: + pidXwait (child_id, NULL); + break; + } + } else { + if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch, + verbose, snoop, queued, sasl, + saslssf, saslmech, user, tls)) || + rp_isbad (retval = sm_winit (envelope))) + die (NULL, "problem initializing server; %s", rp_string (retval)); + + do_addresses (bccque, talk && verbose); + if ((fd = open (file, O_RDONLY)) == NOTOK) + die (file, "unable to re-open"); + do_text (file, fd); + close (fd); + fflush (stdout); + + sm_end (!(msgflags & MINV) || bccque ? OK : DONE); + sigoff (); + + if (verbose) { + if (msgflags & MINV) + printf (" -- %s Recipient Copies Posted --\n", + bccque ? "Blind" : "Sighted"); + else + printf (" -- Recipient Copies Posted --\n"); + } + + fflush (stdout); + } } /* Address Verification */ static void -verify_all_addresses (int talk) +verify_all_addresses (int talk, char *envelope) { int retval; struct mailname *lp; @@ -1473,9 +1566,10 @@ verify_all_addresses (int talk) sigon (); if (!whomsw || checksw) - if (rp_isbad (retval = sm_init (clientsw, serversw, 0, 0, snoop, 0, - 0, 0, 0, 0)) - || rp_isbad (retval = sm_winit (smtpmode, from))) + if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch, + verbose, snoop, queued, sasl, + saslssf, saslmech, user, tls)) + || rp_isbad (retval = sm_winit (envelope))) die (NULL, "problem initializing server; %s", rp_string (retval)); if (talk && !whomsw) @@ -1600,303 +1694,22 @@ do_text (char *file, int fd) } } -#endif /* SMTPMTS */ - -/* - * MMDF routines - */ - -#ifdef MMDFMTS - -static void -post (char *file, int bccque, int talk) -{ - int fd, onex; - int retval; -#ifdef RP_NS - int len; - struct rp_bufstruct reply; -#endif /* RP_NS */ - - onex = !(msgflags & MINV) || bccque; - if (verbose) { - if (msgflags & MINV) - printf (" -- Posting for %s Recipients --\n", - bccque ? "Blind" : "Sighted"); - else - printf (" -- Posting for All Recipients --\n"); - } - - sigon (); - - if (rp_isbad (retval = mm_init ()) - || rp_isbad (retval = mm_sbinit ()) - || rp_isbad (retval = mm_winit (NULL, submitopts, from))) - die (NULL, "problem initializing MMDF system [%s]", - rp_valstr (retval)); -#ifdef RP_NS - if (rp_isbad (retval = mm_rrply (&reply, &len))) - die (NULL, "problem with sender address [%s]", - rp_valstr (retval)); -#endif /* RP_NS */ - - do_addresses (bccque, talk && verbose); - if ((fd = open (file, O_RDONLY)) == NOTOK) - die (file, "unable to re-open"); - do_text (file, fd); - close (fd); - fflush (stdout); - - mm_sbend (); - mm_end (OK); - sigoff (); - - if (verbose) - if (msgflags & MINV) - printf (" -- %s Recipient Copies Posted --\n", - bccque ? "Blind" : "Sighted"); - else - printf (" -- Recipient Copies Posted --\n"); - fflush (stdout); -} - - -/* Address Verification */ - -static void -verify_all_addresses (int talk) -{ - int retval; - struct mailname *lp; - -#ifdef RP_NS - int len; - struct rp_bufstruct reply; -#endif /* RP_NS */ - - sigon (); - - if (!whomsw || checksw) { - if (rp_isbad (retval = mm_init ()) - || rp_isbad (retval = mm_sbinit ()) - || rp_isbad (retval = mm_winit (NULL, submitopts, from))) - die (NULL, "problem initializing MMDF system [%s]", - rp_valstr (retval)); -#ifdef RP_NS - if (rp_isbad (retval = mm_rrply (&reply, &len))) - die (NULL, "problem with sender address [%s]", rp_valstr (retval)); -#endif /* RP_NS */ - } - - if (talk && !whomsw) - printf (" -- Address Verification --\n"); - if (talk && localaddrs.m_next) - printf (" -- Local Recipients --\n"); - for (lp = localaddrs.m_next; lp; lp = lp->m_next) - do_an_address (lp, talk); - - if (talk && uuaddrs.m_next) - printf (" -- UUCP Recipients --\n"); - for (lp = uuaddrs.m_next; lp; lp = lp->m_next) - do_an_address (lp, talk); - - if (talk && netaddrs.m_next) - printf (" -- Network Recipients --\n"); - for (lp = netaddrs.m_next; lp; lp = lp->m_next) - do_an_address (lp, talk); - - chkadr (); - if (talk && !whomsw) - printf (" -- Address Verification Successful --\n"); - - if (!whomsw || checksw) - mm_end (NOTOK); - - fflush (stdout); - sigoff (); -} - - -static void -do_an_address (struct mailname *lp, int talk) -{ - int len, retval; - char *mbox, *host, *text, *path; - char addr[BUFSIZ]; - struct rp_bufstruct reply; - - switch (lp->m_type) { - case LOCALHOST: - mbox = lp->m_mbox; - host = LocalName (); - strncpy (addr, mbox, sizeof(addr)); - break; - - case UUCPHOST: - fprintf (talk ? stdout : stderr, " %s!%s: %s\n", - lp->m_host, lp->m_mbox, "not supported; UUCP address"); - unkadr++; - fflush (stdout); - return; - - default: /* let MMDF decide if the host is bad */ - mbox = lp->m_mbox; - host = lp->m_host; - snprintf (addr, sizeof(addr), "%s at %s", mbox, host); - break; - } - - if (talk) - printf (" %s%s", addr, whomsw && lp->m_bcc ? "[BCC]" : ""); - - if (whomsw && !checksw) { - putchar ('\n'); - return; - } - if (talk) - printf (": "); - fflush (stdout); - -#ifdef MMDFII - if (lp->m_path) - path = concat (lp->m_path, mbox, "@", host, NULL); - else -#endif /* MMDFII */ - path = NULL; - if (rp_isbad (retval = mm_wadr (path ? NULL : host, path ? path : mbox)) - || rp_isbad (retval = mm_rrply (&reply, &len))) - die (NULL, "problem submitting address [%s]", rp_valstr (retval)); - - switch (rp_gval (reply.rp_val)) { - case RP_AOK: - if (talk) - printf ("address ok\n"); - fflush (stdout); - return; - -#ifdef RP_DOK - case RP_DOK: - if (talk) - printf ("nameserver timeout - queued for checking\n"); - fflush (stdout); - return; -#endif /* RP_DOK */ - - case RP_NO: - text = "you lose"; - break; - -#ifdef RP_NS - case RP_NS: - text = "temporary nameserver failure"; - break; - -#endif /* RP_NS */ - - case RP_USER: - case RP_NDEL: - text = "not deliverable"; - break; - - case RP_AGN: - text = "try again later"; - break; - - case RP_NOOP: - text = "nothing done"; - break; - - default: - if (!talk) - fprintf (stderr, " %s: ", addr); - text = "unexpected response"; - die (NULL, "%s;\n [%s] -- %s", text, - rp_valstr (reply.rp_val), reply.rp_line); - } - - if (!talk) - fprintf (stderr, " %s: ", addr); - fprintf (talk ? stdout : stderr, "%s;\n %s\n", text, reply.rp_line); - unkadr++; - - fflush (stdout); -} - - -static void -do_text (char *file, int fd) -{ - int retval, state; - char buf[BUFSIZ]; - struct rp_bufstruct reply; - - lseek (fd, (off_t) 0, SEEK_SET); - - while ((state = read (fd, buf, sizeof(buf))) > 0) { - if (rp_isbad (mm_wtxt (buf, state))) - die (NULL, "problem writing text [%s]\n", rp_valstr (retval)); - } - - if (state == NOTOK) - die (file, "problem reading from"); - - if (rp_isbad (retval = mm_wtend ())) - die (NULL, "problem ending text [%s]\n", rp_valstr (retval)); - - if (rp_isbad (retval = mm_rrply (&reply, &state))) - die (NULL, "problem getting submission status [%s]\n", - rp_valstr (retval)); - - switch (rp_gval (reply.rp_val)) { - case RP_OK: - case RP_MOK: - break; - - case RP_NO: - die (NULL, "you lose; %s", reply.rp_line); - - case RP_NDEL: - die (NULL, "no delivery occurred; %s", reply.rp_line); - - case RP_AGN: - die (NULL, "try again later; %s", reply.rp_line); - - case RP_NOOP: - die (NULL, "nothing done; %s", reply.rp_line); - - default: - die (NULL, "unexpected response;\n\t[%s] -- %s", - rp_valstr (reply.rp_val), reply.rp_line); - } -} - -#endif /* MMDFMTS */ - /* * SIGNAL HANDLING */ -static RETSIGTYPE +static void sigser (int i) { -#ifndef RELIABLE_SIGNALS - SIGNAL (i, SIG_IGN); -#endif + NMH_UNUSED (i); unlink (tmpfil); if (msgflags & MINV) unlink (bccfil); -#ifdef MMDFMTS - if (!whomsw || checksw) - mm_end (NOTOK); -#endif /* MMDFMTS */ - -#ifdef SMTPMTS if (!whomsw || checksw) sm_end (NOTOK); -#endif /* SMTPMTS */ done (1); } @@ -2012,42 +1825,11 @@ die (char *what, char *fmt, ...) if (msgflags & MINV) unlink (bccfil); -#ifdef MMDFMTS - if (!whomsw || checksw) - mm_end (NOTOK); -#endif /* MMDFMTS */ - -#ifdef SMTPMTS if (!whomsw || checksw) sm_end (NOTOK); -#endif /* SMTPMTS */ va_start(ap, fmt); advertise (what, NULL, fmt, ap); va_end(ap); done (1); } - - -#ifdef MMDFMTS -/* - * err_abrt() is used by the mm_ routines - * do not, under *ANY* circumstances, remove it from post, - * or you will lose *BIG* - */ - -void -err_abrt (int code, char *fmt, ...) -{ - char buffer[BUFSIZ]; - va_list ap; - - snprintf (buffer, sizeof(buffer), "[%s]", rp_valstr (code)); - - va_start(ap, fmt); - advertise (buffer, NULL, fmt, ap); - va_end(ap); - - done (1); -} -#endif /* MMDFMTS */