summaryrefslogtreecommitdiffstats
path: root/contrib/sendmail/src/recipient.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/sendmail/src/recipient.c')
-rw-r--r--contrib/sendmail/src/recipient.c1196
1 files changed, 739 insertions, 457 deletions
diff --git a/contrib/sendmail/src/recipient.c b/contrib/sendmail/src/recipient.c
index bfed632..378088a 100644
--- a/contrib/sendmail/src/recipient.c
+++ b/contrib/sendmail/src/recipient.c
@@ -11,15 +11,125 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: recipient.c,v 8.231.14.11 2001/05/03 17:24:14 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: recipient.c,v 8.327 2001/11/20 13:59:53 ca Exp $")
static void includetimeout __P((void));
static ADDRESS *self_reference __P((ADDRESS *));
+static int sortexpensive __P((ADDRESS *, ADDRESS *));
+static int sortbysignature __P((ADDRESS *, ADDRESS *));
+static int sorthost __P((ADDRESS *, ADDRESS *));
+
+typedef int sortfn_t __P((ADDRESS *, ADDRESS *));
+
+/*
+** SORTHOST -- strcmp()-like func for host portion of an ADDRESS
+**
+** Parameters:
+** xx -- first ADDRESS
+** yy -- second ADDRESS
+**
+** Returns:
+** <0 when xx->q_host is less than yy->q_host
+** >0 when xx->q_host is greater than yy->q_host
+** 0 when equal
+*/
+
+static int
+sorthost(xx, yy)
+ register ADDRESS *xx;
+ register ADDRESS *yy;
+{
+#if _FFR_HOST_SORT_REVERSE
+ /* XXX maybe compare hostnames from the end? */
+ return sm_strrevcasecmp(xx->q_host, yy->q_host);
+#else /* _FFR_HOST_SORT_REVERSE */
+ return sm_strcasecmp(xx->q_host, yy->q_host);
+#endif /* _FFR_HOST_SORT_REVERSE */
+}
+
+/*
+** SORTEXPENSIVE -- strcmp()-like func for expensive mailers
+**
+** The mailer has been noted already as "expensive" for 'xx'. This
+** will give a result relative to 'yy'. Expensive mailers get rated
+** "greater than" non-expensive mailers because during the delivery phase
+** it will get queued -- no use it getting in the way of less expensive
+** recipients. We avoid an MX RR lookup when both 'xx' and 'yy' are
+** expensive since an MX RR lookup happens when extracted from the queue
+** later.
+**
+** Parameters:
+** xx -- first ADDRESS
+** yy -- second ADDRESS
+**
+** Returns:
+** <0 when xx->q_host is less than yy->q_host and both are
+** expensive
+** >0 when xx->q_host is greater than yy->q_host, or when
+** 'yy' is non-expensive
+** 0 when equal (by expense and q_host)
+*/
+
+static int
+sortexpensive(xx, yy)
+ ADDRESS *xx;
+ ADDRESS *yy;
+{
+ if (!bitnset(M_EXPENSIVE, yy->q_mailer->m_flags))
+ return 1; /* xx should go later */
+#if _FFR_HOST_SORT_REVERSE
+ /* XXX maybe compare hostnames from the end? */
+ return sm_strrevcasecmp(xx->q_host, yy->q_host);
+#else /* _FFR_HOST_SORT_REVERSE */
+ return sm_strcasecmp(xx->q_host, yy->q_host);
+#endif /* _FFR_HOST_SORT_REVERSE */
+}
+
+/*
+** SORTBYSIGNATURE -- a strcmp()-like func for q_mailer and q_host in ADDRESS
+**
+** Parameters:
+** xx -- first ADDRESS
+** yy -- second ADDRESS
+**
+** Returns:
+** 0 when the "signature"'s are same
+** <0 when xx->q_signature is less than yy->q_signature
+** >0 when xx->q_signature is greater than yy->q_signature
+**
+** Side Effect:
+** May set ADDRESS pointer for q_signature if not already set.
+*/
+
+static int
+sortbysignature(xx, yy)
+ ADDRESS *xx;
+ ADDRESS *yy;
+{
+ register int ret;
+
+ /* Let's avoid redoing the signature over and over again */
+ if (xx->q_signature == NULL)
+ xx->q_signature = hostsignature(xx->q_mailer, xx->q_host);
+ if (yy->q_signature == NULL)
+ yy->q_signature = hostsignature(yy->q_mailer, yy->q_host);
+ ret = strcmp(xx->q_signature, yy->q_signature);
+
+ /*
+ ** If the two signatures are the same then we will return a sort
+ ** value based on 'q_user'. But note that we have reversed xx and yy
+ ** on purpose. This additional compare helps reduce the number of
+ ** sameaddr() calls and loops in recipient() for the case when
+ ** the rcpt list has been provided already in-order.
+ */
+
+ if (ret == 0)
+ return strcmp(yy->q_user, xx->q_user);
+ else
+ return ret;
+}
/*
** SENDTOLIST -- Designate a send list.
@@ -41,9 +151,6 @@ static ADDRESS *self_reference __P((ADDRESS *));
**
** Returns:
** The number of addresses actually on the list.
-**
-** Side Effects:
-** none.
*/
/* q_flags bits inherited from ctladdr */
@@ -58,12 +165,12 @@ sendtolist(list, ctladdr, sendq, aliaslevel, e)
register ENVELOPE *e;
{
register char *p;
- register ADDRESS *al; /* list of addresses to send to */
- char delimiter; /* the address delimiter */
- int naddrs;
- int i;
+ register ADDRESS *SM_NONVOLATILE al; /* list of addresses to send to */
+ SM_NONVOLATILE char delimiter; /* the address delimiter */
+ SM_NONVOLATILE int naddrs;
+ SM_NONVOLATILE int i;
char *oldto = e->e_to;
- char *bufp;
+ char *SM_NONVOLATILE bufp;
char buf[MAXNAME + 1];
if (list == NULL)
@@ -74,8 +181,8 @@ sendtolist(list, ctladdr, sendq, aliaslevel, e)
if (tTd(25, 1))
{
- dprintf("sendto: %s\n ctladdr=", list);
- printaddr(ctladdr, FALSE);
+ sm_dprintf("sendto: %s\n ctladdr=", list);
+ printaddr(ctladdr, false);
}
/* heuristic to determine old versus new style addresses */
@@ -98,105 +205,111 @@ sendtolist(list, ctladdr, sendq, aliaslevel, e)
i = sizeof buf;
}
else
- bufp = xalloc(i);
- (void) strlcpy(bufp, denlstring(list, FALSE, TRUE), i);
-
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), "e r", e);
-#endif /* _FFR_ADDR_TYPE */
- for (p = bufp; *p != '\0'; )
- {
- auto char *delimptr;
- register ADDRESS *a;
-
- /* parse the address */
- while ((isascii(*p) && isspace(*p)) || *p == ',')
- p++;
- a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e);
- p = delimptr;
- if (a == NULL)
- continue;
- a->q_next = al;
- a->q_alias = ctladdr;
+ bufp = sm_malloc_x(i);
+
+ SM_TRY
+ {
+ (void) sm_strlcpy(bufp, denlstring(list, false, true), i);
- /* arrange to inherit attributes from parent */
- if (ctladdr != NULL)
+ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r");
+ for (p = bufp; *p != '\0'; )
{
- ADDRESS *b;
+ auto char *delimptr;
+ register ADDRESS *a;
+
+ /* parse the address */
+ while ((isascii(*p) && isspace(*p)) || *p == ',')
+ p++;
+ a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter,
+ &delimptr, e, true);
+ p = delimptr;
+ if (a == NULL)
+ continue;
+ a->q_next = al;
+ a->q_alias = ctladdr;
- /* self reference test */
- if (sameaddr(ctladdr, a))
+ /* arrange to inherit attributes from parent */
+ if (ctladdr != NULL)
{
- if (tTd(27, 5))
- {
- dprintf("sendtolist: QSELFREF ");
- printaddr(ctladdr, FALSE);
- }
- ctladdr->q_flags |= QSELFREF;
- }
+ ADDRESS *b;
- /* check for address loops */
- b = self_reference(a);
- if (b != NULL)
- {
- b->q_flags |= QSELFREF;
- if (tTd(27, 5))
+ /* self reference test */
+ if (sameaddr(ctladdr, a))
{
- dprintf("sendtolist: QSELFREF ");
- printaddr(b, FALSE);
+ if (tTd(27, 5))
+ {
+ sm_dprintf("sendtolist: QSELFREF ");
+ printaddr(ctladdr, false);
+ }
+ ctladdr->q_flags |= QSELFREF;
}
- if (a != b)
+
+ /* check for address loops */
+ b = self_reference(a);
+ if (b != NULL)
{
+ b->q_flags |= QSELFREF;
if (tTd(27, 5))
{
- dprintf("sendtolist: QS_DONTSEND ");
- printaddr(a, FALSE);
+ sm_dprintf("sendtolist: QSELFREF ");
+ printaddr(b, false);
+ }
+ if (a != b)
+ {
+ if (tTd(27, 5))
+ {
+ sm_dprintf("sendtolist: QS_DONTSEND ");
+ printaddr(a, false);
+ }
+ a->q_state = QS_DONTSEND;
+ b->q_flags |= a->q_flags & QNOTREMOTE;
+ continue;
}
- a->q_state = QS_DONTSEND;
- b->q_flags |= a->q_flags & QNOTREMOTE;
- continue;
}
- }
- /* full name */
- if (a->q_fullname == NULL)
- a->q_fullname = ctladdr->q_fullname;
+ /* full name */
+ if (a->q_fullname == NULL)
+ a->q_fullname = ctladdr->q_fullname;
+
+ /* various flag bits */
+ a->q_flags &= ~QINHERITEDBITS;
+ a->q_flags |= ctladdr->q_flags & QINHERITEDBITS;
- /* various flag bits */
- a->q_flags &= ~QINHERITEDBITS;
- a->q_flags |= ctladdr->q_flags & QINHERITEDBITS;
+ /* DSN recipient information */
+ a->q_finalrcpt = ctladdr->q_finalrcpt;
+ a->q_orcpt = ctladdr->q_orcpt;
+ }
- /* original recipient information */
- a->q_orcpt = ctladdr->q_orcpt;
+ al = a;
}
- al = a;
- }
+ /* arrange to send to everyone on the local send list */
+ while (al != NULL)
+ {
+ register ADDRESS *a = al;
- /* arrange to send to everyone on the local send list */
- while (al != NULL)
+ al = a->q_next;
+ a = recipient(a, sendq, aliaslevel, e);
+ naddrs++;
+ }
+ }
+ SM_FINALLY
{
- register ADDRESS *a = al;
-
- al = a->q_next;
- a = recipient(a, sendq, aliaslevel, e);
- naddrs++;
+ e->e_to = oldto;
+ if (bufp != buf)
+ sm_free(bufp);
+ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
}
-
- e->e_to = oldto;
- if (bufp != buf)
- sm_free(bufp);
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), NULL, e);
-#endif /* _FFR_ADDR_TYPE */
+ SM_END_TRY
return naddrs;
}
- /*
+#if MILTER
+/*
** REMOVEFROMLIST -- Remove addresses from a send list.
**
** The parameter is a comma-separated list of recipients to remove.
** Note that it only deletes matching addresses. If those addresses
-** have been expended already in the sendq, it won't mark the
+** have been expanded already in the sendq, it won't mark the
** expanded recipients as QS_REMOVED.
**
** Parameters:
@@ -216,12 +329,12 @@ removefromlist(list, sendq, e)
ADDRESS **sendq;
ENVELOPE *e;
{
- char delimiter; /* the address delimiter */
- int naddrs;
- int i;
+ SM_NONVOLATILE char delimiter; /* the address delimiter */
+ SM_NONVOLATILE int naddrs;
+ SM_NONVOLATILE int i;
char *p;
char *oldto = e->e_to;
- char *bufp;
+ char *SM_NONVOLATILE bufp;
char buf[MAXNAME + 1];
if (list == NULL)
@@ -231,7 +344,7 @@ removefromlist(list, sendq, e)
}
if (tTd(25, 1))
- dprintf("removefromlist: %s\n", list);
+ sm_dprintf("removefromlist: %s\n", list);
/* heuristic to determine old versus new style addresses */
if (strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
@@ -251,61 +364,65 @@ removefromlist(list, sendq, e)
i = sizeof buf;
}
else
- bufp = xalloc(i);
- (void) strlcpy(bufp, denlstring(list, FALSE, TRUE), i);
-
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), "e r", e);
-#endif /* _FFR_ADDR_TYPE */
- for (p = bufp; *p != '\0'; )
- {
- ADDRESS a; /* parsed address to be removed */
- ADDRESS *q;
- ADDRESS **pq;
- char *delimptr;
-
- /* parse the address */
- while ((isascii(*p) && isspace(*p)) || *p == ',')
- p++;
- if (parseaddr(p, &a, RF_COPYALL,
- delimiter, &delimptr, e) == NULL)
+ bufp = sm_malloc_x(i);
+
+ SM_TRY
+ {
+ (void) sm_strlcpy(bufp, denlstring(list, false, true), i);
+
+ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r");
+ for (p = bufp; *p != '\0'; )
{
+ ADDRESS a; /* parsed address to be removed */
+ ADDRESS *q;
+ ADDRESS **pq;
+ char *delimptr;
+
+ /* parse the address */
+ while ((isascii(*p) && isspace(*p)) || *p == ',')
+ p++;
+ if (parseaddr(p, &a, RF_COPYALL,
+ delimiter, &delimptr, e, true) == NULL)
+ {
+ p = delimptr;
+ continue;
+ }
p = delimptr;
- continue;
- }
- p = delimptr;
- for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
- {
- if (!QS_IS_DEAD(q->q_state) &&
- sameaddr(q, &a))
+ for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
{
- if (tTd(25, 5))
+ if (!QS_IS_DEAD(q->q_state) &&
+ sameaddr(q, &a))
{
- dprintf("removefromlist: QS_REMOVED ");
- printaddr(&a, FALSE);
+ if (tTd(25, 5))
+ {
+ sm_dprintf("removefromlist: QS_REMOVED ");
+ printaddr(&a, false);
+ }
+ q->q_state = QS_REMOVED;
+ naddrs++;
+ break;
}
- q->q_state = QS_REMOVED;
- naddrs++;
- break;
}
}
}
-
- e->e_to = oldto;
- if (bufp != buf)
- sm_free(bufp);
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), NULL, e);
-#endif /* _FFR_ADDR_TYPE */
+ SM_FINALLY
+ {
+ e->e_to = oldto;
+ if (bufp != buf)
+ sm_free(bufp);
+ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
+ }
+ SM_END_TRY
return naddrs;
}
- /*
+#endif /* MILTER */
+/*
** RECIPIENT -- Designate a message recipient
**
** Saves the named person for future mailing.
**
** Parameters:
-** a -- the (preparsed) address header for the recipient.
+** new -- the (preparsed) address header for the recipient.
** sendq -- a pointer to the head of a queue to put the
** recipient in. Duplicate suppression is done
** in this queue.
@@ -316,62 +433,121 @@ removefromlist(list, sendq, e)
** The actual address in the queue. This will be "a" if
** the address is not a duplicate, else the original address.
**
-** Side Effects:
-** none.
*/
ADDRESS *
-recipient(a, sendq, aliaslevel, e)
- register ADDRESS *a;
+recipient(new, sendq, aliaslevel, e)
+ register ADDRESS *new;
register ADDRESS **sendq;
int aliaslevel;
register ENVELOPE *e;
{
register ADDRESS *q;
ADDRESS **pq;
+ ADDRESS **prev;
register struct mailer *m;
- register char *p = NULL;
- bool quoted = FALSE; /* set if the addr has a quote bit */
- int findusercount = 0;
- bool initialdontsend = QS_IS_DEAD(a->q_state);
+ register char *p;
int i, buflen;
+ bool quoted; /* set if the addr has a quote bit */
+ bool insert;
+ int findusercount;
+ bool initialdontsend;
char *buf;
char buf0[MAXNAME + 1]; /* unquoted image of the user name */
-
- e->e_to = a->q_paddr;
- m = a->q_mailer;
+ sortfn_t *sortfn;
+
+ p = NULL;
+ quoted = false;
+ insert = false;
+ findusercount = 0;
+ initialdontsend = QS_IS_DEAD(new->q_state);
+ e->e_to = new->q_paddr;
+ m = new->q_mailer;
errno = 0;
if (aliaslevel == 0)
- a->q_flags |= QPRIMARY;
+ new->q_flags |= QPRIMARY;
if (tTd(26, 1))
{
- dprintf("\nrecipient (%d): ", aliaslevel);
- printaddr(a, FALSE);
+ sm_dprintf("\nrecipient (%d): ", aliaslevel);
+ printaddr(new, false);
}
- /* if this is primary, add it to the original recipient list */
- if (a->q_alias == NULL)
+ /* if this is primary, use it as original recipient */
+ if (new->q_alias == NULL)
{
if (e->e_origrcpt == NULL)
- e->e_origrcpt = a->q_paddr;
- else if (e->e_origrcpt != a->q_paddr)
+ e->e_origrcpt = new->q_paddr;
+ else if (e->e_origrcpt != new->q_paddr)
e->e_origrcpt = "";
}
+ /* find parent recipient for finalrcpt and orcpt */
+ for (q = new; q->q_alias != NULL; q = q->q_alias)
+ continue;
+
+ /* find final recipient DSN address */
+ if (new->q_finalrcpt == NULL &&
+ e->e_from.q_mailer != NULL)
+ {
+ char frbuf[MAXLINE];
+
+ p = e->e_from.q_mailer->m_addrtype;
+ if (p == NULL)
+ p = "rfc822";
+ if (sm_strcasecmp(p, "rfc822") != 0)
+ {
+ (void) sm_snprintf(frbuf, sizeof frbuf, "%s; %.800s",
+ q->q_mailer->m_addrtype,
+ q->q_user);
+ }
+ else if (strchr(q->q_user, '@') != NULL)
+ {
+ (void) sm_snprintf(frbuf, sizeof frbuf, "%s; %.800s",
+ p, q->q_user);
+ }
+ else if (strchr(q->q_paddr, '@') != NULL)
+ {
+ char *qp;
+ bool b;
+
+ qp = q->q_paddr;
+
+ /* strip brackets from address */
+ b = false;
+ if (*qp == '<')
+ {
+ b = qp[strlen(qp) - 1] == '>';
+ if (b)
+ qp[strlen(qp) - 1] = '\0';
+ qp++;
+ }
+ (void) sm_snprintf(frbuf, sizeof frbuf, "%s; %.800s",
+ p, qp);
+
+ /* undo damage */
+ if (b)
+ qp[strlen(qp)] = '>';
+ }
+ else
+ {
+ (void) sm_snprintf(frbuf, sizeof frbuf,
+ "%s; %.700s@%.100s",
+ p, q->q_user, MyHostName);
+ }
+ new->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool, frbuf);
+ }
+
#if _FFR_GEN_ORCPT
/* set ORCPT DSN arg if not already set */
- if (a->q_orcpt == NULL)
+ if (new->q_orcpt == NULL)
{
- for (q = a; q->q_alias != NULL; q = q->q_alias)
- continue;
-
/* check for an existing ORCPT */
if (q->q_orcpt != NULL)
- a->q_orcpt = q->q_orcpt;
+ new->q_orcpt = q->q_orcpt;
else
{
/* make our own */
- bool b = FALSE;
+ bool b = false;
char *qp;
char obuf[MAXLINE];
@@ -379,8 +555,7 @@ recipient(a, sendq, aliaslevel, e)
p = e->e_from.q_mailer->m_addrtype;
if (p == NULL)
p = "rfc822";
- (void) strlcpy(obuf, p, sizeof obuf);
- (void) strlcat(obuf, ";", sizeof obuf);
+ (void) sm_strlcpyn(obuf, sizeof obuf, 2, p, ";");
qp = q->q_paddr;
@@ -395,9 +570,9 @@ recipient(a, sendq, aliaslevel, e)
qp++;
}
- p = xtextify(denlstring(qp, TRUE, FALSE), NULL);
+ p = xtextify(denlstring(qp, true, false), NULL);
- if (strlcat(obuf, p, sizeof obuf) >= sizeof obuf)
+ if (sm_strlcat(obuf, p, sizeof obuf) >= sizeof obuf)
{
/* if too big, don't use it */
obuf[0] = '\0';
@@ -408,7 +583,8 @@ recipient(a, sendq, aliaslevel, e)
qp[strlen(qp)] = '>';
if (obuf[0] != '\0')
- a->q_orcpt = newstr(obuf);
+ new->q_orcpt =
+ sm_rpool_strdup_x(e->e_rpool, obuf);
}
}
#endif /* _FFR_GEN_ORCPT */
@@ -416,12 +592,12 @@ recipient(a, sendq, aliaslevel, e)
/* break aliasing loops */
if (aliaslevel > MaxAliasRecursion)
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.4.6";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.4.6";
+ usrerrenh(new->q_status,
"554 aliasing/forwarding loop broken (%d aliases deep; %d max)",
aliaslevel, MaxAliasRecursion);
- return a;
+ return new;
}
/*
@@ -429,7 +605,7 @@ recipient(a, sendq, aliaslevel, e)
*/
/* get unquoted user for file, program or user.name check */
- i = strlen(a->q_user);
+ i = strlen(new->q_user);
if (i >= sizeof buf0)
{
buflen = i + 1;
@@ -440,45 +616,46 @@ recipient(a, sendq, aliaslevel, e)
buf = buf0;
buflen = sizeof buf0;
}
- (void) strlcpy(buf, a->q_user, buflen);
+ (void) sm_strlcpy(buf, new->q_user, buflen);
for (p = buf; *p != '\0' && !quoted; p++)
{
if (*p == '\\')
- quoted = TRUE;
+ quoted = true;
}
stripquotes(buf);
/* check for direct mailing to restricted mailers */
if (m == ProgMailer)
{
- if (a->q_alias == NULL)
+ if (new->q_alias == NULL || UseMSP ||
+ bitset(EF_UNSAFE, e->e_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ usrerrenh(new->q_status,
"550 Cannot mail directly to programs");
}
- else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
+ else if (bitset(QBOGUSSHELL, new->q_alias->q_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- if (a->q_alias->q_ruser == NULL)
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ if (new->q_alias->q_ruser == NULL)
+ usrerrenh(new->q_status,
"550 UID %d is an unknown user: cannot mail to programs",
- a->q_alias->q_uid);
+ new->q_alias->q_uid);
else
- usrerrenh(a->q_status,
+ usrerrenh(new->q_status,
"550 User %s@%s doesn't have a valid shell for mailing to programs",
- a->q_alias->q_ruser, MyHostName);
+ new->q_alias->q_ruser, MyHostName);
}
- else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
+ else if (bitset(QUNSAFEADDR, new->q_alias->q_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- a->q_rstatus = newstr("550 Unsafe for mailing to programs");
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ new->q_rstatus = "550 Unsafe for mailing to programs";
+ usrerrenh(new->q_status,
"550 Address %s is unsafe for mailing to programs",
- a->q_alias->q_paddr);
+ new->q_alias->q_paddr);
}
}
@@ -491,52 +668,123 @@ recipient(a, sendq, aliaslevel, e)
** [Please note: the emphasis is on "hack."]
*/
+ prev = NULL;
+
+ /*
+ ** If this message is going to the queue or FastSplit is set
+ ** and it is the first try and the envelope hasn't split, then we
+ ** avoid doing an MX RR lookup now because one will be done when the
+ ** message is extracted from the queue later. It can go to the queue
+ ** because all messages are going to the queue or this mailer of
+ ** the current recipient is marked expensive.
+ */
+
+ if (WILL_BE_QUEUED(e->e_sendmode) ||
+ (!bitset(EF_SPLIT, e->e_flags) && e->e_ntries == 0 &&
+ FastSplit > 0))
+ sortfn = sorthost;
+ else if (NoConnect && bitnset(M_EXPENSIVE, new->q_mailer->m_flags))
+ sortfn = sortexpensive;
+ else
+ sortfn = sortbysignature;
+
for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
{
- if (sameaddr(q, a) &&
- (bitset(QRCPTOK, q->q_flags) ||
- !bitset(QPRIMARY, q->q_flags)))
+ /*
+ ** If address is "less than" it should be inserted now.
+ ** If address is "greater than" current comparison it'll
+ ** insert later in the list; so loop again (if possible).
+ ** If address is "equal" (different equal than sameaddr()
+ ** call) then check if sameaddr() will be true.
+ ** Because this list is now sorted, it'll mean fewer
+ ** comparisons and fewer loops which is important for more
+ ** recipients.
+ */
+
+ i = (*sortfn)(new, q);
+ if (i == 0) /* equal */
{
- if (tTd(26, 1))
- {
- dprintf("%s in sendq: ", a->q_paddr);
- printaddr(q, FALSE);
- }
- if (!bitset(QPRIMARY, q->q_flags))
- {
- if (!QS_IS_DEAD(a->q_state))
- message("duplicate suppressed");
- else
- q->q_state = QS_DUPLICATE;
- q->q_flags |= a->q_flags;
- }
- else if (bitset(QSELFREF, q->q_flags)
-#if _FFR_MILTER
- || q->q_state == QS_REMOVED
-#endif /* _FFR_MILTER */
- )
+ /*
+ ** Sortbysignature() has said that the two have
+ ** equal MX RR's and the same user. Calling sameaddr()
+ ** now checks if the two hosts are as identical as the
+ ** MX RR's are (which might not be the case)
+ ** before saying these are the identical addresses.
+ */
+
+ if (sameaddr(q, new) &&
+ (bitset(QRCPTOK, q->q_flags) ||
+ !bitset(QPRIMARY, q->q_flags)))
{
-#if _FFR_MILTER
- /*
- ** If an earlier milter removed the address,
- ** a later one can still add it back.
- */
-#endif /* _FFR_MILTER */
- q->q_state = a->q_state;
- q->q_flags |= a->q_flags;
+ if (tTd(26, 1))
+ {
+ sm_dprintf("%s in sendq: ",
+ new->q_paddr);
+ printaddr(q, false);
+ }
+ if (!bitset(QPRIMARY, q->q_flags))
+ {
+ if (!QS_IS_DEAD(new->q_state))
+ message("duplicate suppressed");
+ else
+ q->q_state = QS_DUPLICATE;
+ q->q_flags |= new->q_flags;
+ }
+ else if (bitset(QSELFREF, q->q_flags)
+ || q->q_state == QS_REMOVED)
+ {
+ /*
+ ** If an earlier milter removed the
+ ** address, a later one can still add
+ ** it back.
+ */
+
+ q->q_state = new->q_state;
+ q->q_flags |= new->q_flags;
+ }
+ new = q;
+ goto done;
}
- a = q;
- goto done;
}
+ else if (i < 0) /* less than */
+ {
+ insert = true;
+ break;
+ }
+ prev = pq;
}
+ /* pq should point to an address, never NULL */
+ SM_ASSERT(pq != NULL);
+
/* add address on list */
- if (pq != NULL)
+ if (insert)
{
- *pq = a;
- a->q_next = NULL;
+ /*
+ ** insert before 'pq'. Only possible when at least 1
+ ** ADDRESS is in the list already.
+ */
+
+ new->q_next = *pq;
+ if (prev == NULL)
+ *sendq = new; /* To be the first ADDRESS */
+ else
+ (*prev)->q_next = new;
+ }
+ else
+ {
+ /*
+ ** Place in list at current 'pq' position. Possible
+ ** when there are 0 or more ADDRESS's in the list.
+ */
+
+ new->q_next = NULL;
+ *pq = new;
}
+ /* added a new address: clear split flag */
+ e->e_flags &= ~EF_SPLIT;
+
/*
** Alias the name and handle special mailer types.
*/
@@ -544,108 +792,120 @@ recipient(a, sendq, aliaslevel, e)
trylocaluser:
if (tTd(29, 7))
{
- dprintf("at trylocaluser: ");
- printaddr(a, FALSE);
+ sm_dprintf("at trylocaluser: ");
+ printaddr(new, false);
}
- if (!QS_IS_OK(a->q_state))
+ if (!QS_IS_OK(new->q_state))
+ {
+ if (QS_IS_UNDELIVERED(new->q_state))
+ e->e_nrcpts++;
goto testselfdestruct;
+ }
if (m == InclMailer)
{
- a->q_state = QS_INCLUDED;
- if (a->q_alias == NULL)
+ new->q_state = QS_INCLUDED;
+ if (new->q_alias == NULL || UseMSP ||
+ bitset(EF_UNSAFE, e->e_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ usrerrenh(new->q_status,
"550 Cannot mail directly to :include:s");
}
else
{
int ret;
- message("including file %s", a->q_user);
- ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e);
+ message("including file %s", new->q_user);
+ ret = include(new->q_user, false, new,
+ sendq, aliaslevel, e);
if (transienterror(ret))
{
if (LogLevel > 2)
sm_syslog(LOG_ERR, e->e_id,
"include %s: transient error: %s",
- shortenstring(a->q_user, MAXSHORTSTR),
- errstring(ret));
- a->q_state = QS_QUEUEUP;
+ shortenstring(new->q_user,
+ MAXSHORTSTR),
+ sm_errstring(ret));
+ new->q_state = QS_QUEUEUP;
usrerr("451 4.2.4 Cannot open %s: %s",
- shortenstring(a->q_user, MAXSHORTSTR),
- errstring(ret));
+ shortenstring(new->q_user,
+ MAXSHORTSTR),
+ sm_errstring(ret));
}
else if (ret != 0)
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.2.4";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.2.4";
+ usrerrenh(new->q_status,
"550 Cannot open %s: %s",
- shortenstring(a->q_user, MAXSHORTSTR),
- errstring(ret));
+ shortenstring(new->q_user,
+ MAXSHORTSTR),
+ sm_errstring(ret));
}
}
}
else if (m == FileMailer)
{
- /* check if writable or creatable */
- if (a->q_alias == NULL)
+ /* check if allowed */
+ if (new->q_alias == NULL || UseMSP ||
+ bitset(EF_UNSAFE, e->e_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ usrerrenh(new->q_status,
"550 Cannot mail directly to files");
}
- else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
+ else if (bitset(QBOGUSSHELL, new->q_alias->q_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- if (a->q_alias->q_ruser == NULL)
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ if (new->q_alias->q_ruser == NULL)
+ usrerrenh(new->q_status,
"550 UID %d is an unknown user: cannot mail to files",
- a->q_alias->q_uid);
+ new->q_alias->q_uid);
else
- usrerrenh(a->q_status,
+ usrerrenh(new->q_status,
"550 User %s@%s doesn't have a valid shell for mailing to files",
- a->q_alias->q_ruser, MyHostName);
+ new->q_alias->q_ruser, MyHostName);
}
- else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
+ else if (bitset(QUNSAFEADDR, new->q_alias->q_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- a->q_rstatus = newstr("550 Unsafe for mailing to files");
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ new->q_rstatus = "550 Unsafe for mailing to files";
+ usrerrenh(new->q_status,
"550 Address %s is unsafe for mailing to files",
- a->q_alias->q_paddr);
+ new->q_alias->q_paddr);
}
}
/* try aliasing */
- if (!quoted && QS_IS_OK(a->q_state) &&
+ if (!quoted && QS_IS_OK(new->q_state) &&
bitnset(M_ALIASABLE, m->m_flags))
- alias(a, sendq, aliaslevel, e);
+ alias(new, sendq, aliaslevel, e);
#if USERDB
/* if not aliased, look it up in the user database */
- if (!bitset(QNOTREMOTE, a->q_flags) &&
- QS_IS_SENDABLE(a->q_state) &&
+ if (!bitset(QNOTREMOTE, new->q_flags) &&
+ QS_IS_SENDABLE(new->q_state) &&
bitnset(M_CHECKUDB, m->m_flags))
{
- if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL)
+ if (udbexpand(new, sendq, aliaslevel, e) == EX_TEMPFAIL)
{
- a->q_state = QS_QUEUEUP;
+ new->q_state = QS_QUEUEUP;
if (e->e_message == NULL)
- e->e_message = newstr("Deferred: user database error");
+ e->e_message = "Deferred: user database error";
+ if (new->q_message == NULL)
+ new->q_message = "Deferred: user database error";
if (LogLevel > 8)
sm_syslog(LOG_INFO, e->e_id,
"deferred: udbexpand: %s",
- errstring(errno));
+ sm_errstring(errno));
message("queued (user database error): %s",
- errstring(errno));
+ sm_errstring(errno));
e->e_nrcpts++;
goto testselfdestruct;
}
@@ -655,22 +915,22 @@ recipient(a, sendq, aliaslevel, e)
/*
** If we have a level two config file, then pass the name through
** Ruleset 5 before sending it off. Ruleset 5 has the right
- ** to send rewrite it to another mailer. This gives us a hook
+ ** to rewrite it to another mailer. This gives us a hook
** after local aliasing has been done.
*/
if (tTd(29, 5))
{
- dprintf("recipient: testing local? cl=%d, rr5=%lx\n\t",
- ConfigLevel, (u_long) RewriteRules[5]);
- printaddr(a, FALSE);
+ sm_dprintf("recipient: testing local? cl=%d, rr5=%p\n\t",
+ ConfigLevel, RewriteRules[5]);
+ printaddr(new, false);
}
if (ConfigLevel >= 2 && RewriteRules[5] != NULL &&
bitnset(M_TRYRULESET5, m->m_flags) &&
- !bitset(QNOTREMOTE, a->q_flags) &&
- QS_IS_OK(a->q_state))
+ !bitset(QNOTREMOTE, new->q_flags) &&
+ QS_IS_OK(new->q_state))
{
- maplocaluser(a, sendq, aliaslevel + 1, e);
+ maplocaluser(new, sendq, aliaslevel + 1, e);
}
/*
@@ -678,90 +938,99 @@ recipient(a, sendq, aliaslevel, e)
** and deliver it.
*/
- if (QS_IS_OK(a->q_state) &&
+ if (QS_IS_OK(new->q_state) &&
bitnset(M_HASPWENT, m->m_flags))
{
auto bool fuzzy;
- register struct passwd *pw;
+ SM_MBDB_T user;
+ int status;
/* warning -- finduser may trash buf */
- pw = finduser(buf, &fuzzy);
- if (pw == NULL || strlen(pw->pw_name) > MAXNAME)
- {
- {
- a->q_state = QS_BADADDR;
- a->q_status = "5.1.1";
- a->q_rstatus = newstr("550 5.1.1 User unknown");
- giveresponse(EX_NOUSER, a->q_status, m, NULL,
- a->q_alias, (time_t) 0, e);
- }
- }
- else
+ status = finduser(buf, &fuzzy, &user);
+ switch (status)
{
- char nbuf[MAXNAME + 1];
-
+ case EX_TEMPFAIL:
+ new->q_state = QS_QUEUEUP;
+ new->q_status = "4.5.2";
+ giveresponse(EX_TEMPFAIL, new->q_status, m, NULL,
+ new->q_alias, (time_t) 0, e, new);
+ break;
+ default:
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.1.1";
+ new->q_rstatus = "550 5.1.1 User unknown";
+ giveresponse(EX_NOUSER, new->q_status, m, NULL,
+ new->q_alias, (time_t) 0, e, new);
+ break;
+ case EX_OK:
if (fuzzy)
{
/* name was a fuzzy match */
- a->q_user = newstr(pw->pw_name);
+ new->q_user = sm_rpool_strdup_x(e->e_rpool,
+ user.mbdb_name);
if (findusercount++ > 3)
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.4.6";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.4.6";
+ usrerrenh(new->q_status,
"554 aliasing/forwarding loop for %s broken",
- pw->pw_name);
+ user.mbdb_name);
goto done;
}
/* see if it aliases */
- (void) strlcpy(buf, pw->pw_name, buflen);
+ (void) sm_strlcpy(buf, user.mbdb_name, buflen);
goto trylocaluser;
}
- if (*pw->pw_dir == '\0')
- a->q_home = NULL;
- else if (strcmp(pw->pw_dir, "/") == 0)
- a->q_home = "";
+ if (*user.mbdb_homedir == '\0')
+ new->q_home = NULL;
+ else if (strcmp(user.mbdb_homedir, "/") == 0)
+ new->q_home = "";
else
- a->q_home = newstr(pw->pw_dir);
- a->q_uid = pw->pw_uid;
- a->q_gid = pw->pw_gid;
- a->q_ruser = newstr(pw->pw_name);
- a->q_flags |= QGOODUID;
- buildfname(pw->pw_gecos, pw->pw_name, nbuf, sizeof nbuf);
- if (nbuf[0] != '\0')
- a->q_fullname = newstr(nbuf);
- if (!usershellok(pw->pw_name, pw->pw_shell))
+ new->q_home = sm_rpool_strdup_x(e->e_rpool,
+ user.mbdb_homedir);
+ if (user.mbdb_uid != SM_NO_UID)
{
- a->q_flags |= QBOGUSSHELL;
+ new->q_uid = user.mbdb_uid;
+ new->q_gid = user.mbdb_gid;
+ new->q_flags |= QGOODUID;
+ }
+ new->q_ruser = sm_rpool_strdup_x(e->e_rpool,
+ user.mbdb_name);
+ if (user.mbdb_fullname[0] != '\0')
+ new->q_fullname = sm_rpool_strdup_x(e->e_rpool,
+ user.mbdb_fullname);
+ if (!usershellok(user.mbdb_name, user.mbdb_shell))
+ {
+ new->q_flags |= QBOGUSSHELL;
}
if (bitset(EF_VRFYONLY, e->e_flags))
{
/* don't do any more now */
- a->q_state = QS_VERIFIED;
+ new->q_state = QS_VERIFIED;
}
else if (!quoted)
- forward(a, sendq, aliaslevel, e);
+ forward(new, sendq, aliaslevel, e);
}
}
- if (!QS_IS_DEAD(a->q_state))
+ if (!QS_IS_DEAD(new->q_state))
e->e_nrcpts++;
testselfdestruct:
- a->q_flags |= QTHISPASS;
+ new->q_flags |= QTHISPASS;
if (tTd(26, 8))
{
- dprintf("testselfdestruct: ");
- printaddr(a, FALSE);
+ sm_dprintf("testselfdestruct: ");
+ printaddr(new, false);
if (tTd(26, 10))
{
- dprintf("SENDQ:\n");
- printaddr(*sendq, TRUE);
- dprintf("----\n");
+ sm_dprintf("SENDQ:\n");
+ printaddr(*sendq, true);
+ sm_dprintf("----\n");
}
}
- if (a->q_alias == NULL && a != &e->e_from &&
- QS_IS_DEAD(a->q_state))
+ if (new->q_alias == NULL && new != &e->e_from &&
+ QS_IS_DEAD(new->q_state))
{
for (q = *sendq; q != NULL; q = q->q_next)
{
@@ -770,17 +1039,17 @@ recipient(a, sendq, aliaslevel, e)
}
if (q == NULL)
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.4.6";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.4.6";
+ usrerrenh(new->q_status,
"554 aliasing/forwarding loop broken");
}
}
done:
- a->q_flags |= QTHISPASS;
+ new->q_flags |= QTHISPASS;
if (buf != buf0)
- sm_free(buf);
+ sm_free(buf); /* XXX leak if above code raises exception */
/*
** If we are at the top level, check to see if this has
@@ -821,18 +1090,20 @@ recipient(a, sendq, aliaslevel, e)
{
/* arrange for return receipt */
e->e_flags |= EF_SENDRECEIPT;
- a->q_flags |= QEXPANDED;
+ new->q_flags |= QEXPANDED;
if (e->e_xfp != NULL &&
- bitset(QPINGONSUCCESS, a->q_flags))
- fprintf(e->e_xfp,
- "%s... expanded to multiple addresses\n",
- a->q_paddr);
+ bitset(QPINGONSUCCESS, new->q_flags))
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "%s... expanded to multiple addresses\n",
+ new->q_paddr);
}
}
- a->q_flags |= QRCPTOK;
- return a;
+ new->q_flags |= QRCPTOK;
+ (void) sm_snprintf(buf0, sizeof buf0, "%d", e->e_nrcpts);
+ macdefine(&e->e_macro, A_TEMP, macid("{nrcpts}"), buf0);
+ return new;
}
- /*
+/*
** FINDUSER -- find the password entry for a user.
**
** This looks a lot like getpwnam, except that it may want to
@@ -843,33 +1114,39 @@ recipient(a, sendq, aliaslevel, e)
**
** Parameters:
** name -- the name to match against.
-** fuzzyp -- an outarg that is set to TRUE if this entry
+** fuzzyp -- an outarg that is set to true if this entry
** was found using the fuzzy matching algorithm;
-** set to FALSE otherwise.
+** set to false otherwise.
+** user -- structure to fill in if user is found
**
** Returns:
-** A pointer to a pw struct.
-** NULL if name is unknown or ambiguous.
+** On success, fill in *user, set *fuzzyp and return EX_OK.
+** If the user was not found, return EX_NOUSER.
+** On error, return EX_TEMPFAIL or EX_OSERR.
**
** Side Effects:
** may modify name.
*/
-struct passwd *
-finduser(name, fuzzyp)
+int
+finduser(name, fuzzyp, user)
char *name;
bool *fuzzyp;
+ SM_MBDB_T *user;
{
+#if MATCHGECOS
register struct passwd *pw;
+#endif /* MATCHGECOS */
register char *p;
bool tryagain;
+ int status;
if (tTd(29, 4))
- dprintf("finduser(%s): ", name);
+ sm_dprintf("finduser(%s): ", name);
- *fuzzyp = FALSE;
+ *fuzzyp = false;
-#ifdef HESIOD
+#if HESIOD
/* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
for (p = name; *p != '\0'; p++)
if (!isascii(*p) || !isdigit(*p))
@@ -877,35 +1154,36 @@ finduser(name, fuzzyp)
if (*p == '\0')
{
if (tTd(29, 4))
- dprintf("failed (numeric input)\n");
- return NULL;
+ sm_dprintf("failed (numeric input)\n");
+ return EX_NOUSER;
}
#endif /* HESIOD */
/* look up this login name using fast path */
- if ((pw = sm_getpwnam(name)) != NULL)
+ status = sm_mbdb_lookup(name, user);
+ if (status != EX_NOUSER)
{
if (tTd(29, 4))
- dprintf("found (non-fuzzy)\n");
- return pw;
+ sm_dprintf("%s (non-fuzzy)\n", sm_strexit(status));
+ return status;
}
/* try mapping it to lower case */
- tryagain = FALSE;
+ tryagain = false;
for (p = name; *p != '\0'; p++)
{
if (isascii(*p) && isupper(*p))
{
*p = tolower(*p);
- tryagain = TRUE;
+ tryagain = true;
}
}
- if (tryagain && (pw = sm_getpwnam(name)) != NULL)
+ if (tryagain && (status = sm_mbdb_lookup(name, user)) != EX_NOUSER)
{
if (tTd(29, 4))
- dprintf("found (lower case)\n");
- *fuzzyp = TRUE;
- return pw;
+ sm_dprintf("%s (lower case)\n", sm_strexit(status));
+ *fuzzyp = true;
+ return status;
}
#if MATCHGECOS
@@ -913,8 +1191,8 @@ finduser(name, fuzzyp)
if (!MatchGecos)
{
if (tTd(29, 4))
- dprintf("not found (fuzzy disabled)\n");
- return NULL;
+ sm_dprintf("not found (fuzzy disabled)\n");
+ return EX_NOUSER;
}
/* search for a matching full name instead */
@@ -929,38 +1207,41 @@ finduser(name, fuzzyp)
char buf[MAXNAME + 1];
# if 0
- if (strcasecmp(pw->pw_name, name) == 0)
+ if (sm_strcasecmp(pw->pw_name, name) == 0)
{
if (tTd(29, 4))
- dprintf("found (case wrapped)\n");
+ sm_dprintf("found (case wrapped)\n");
break;
}
# endif /* 0 */
- buildfname(pw->pw_gecos, pw->pw_name, buf, sizeof buf);
- if (strchr(buf, ' ') != NULL && strcasecmp(buf, name) == 0)
+ sm_pwfullname(pw->pw_gecos, pw->pw_name, buf, sizeof buf);
+ if (strchr(buf, ' ') != NULL && sm_strcasecmp(buf, name) == 0)
{
if (tTd(29, 4))
- dprintf("fuzzy matches %s\n", pw->pw_name);
+ sm_dprintf("fuzzy matches %s\n", pw->pw_name);
message("sending to login name %s", pw->pw_name);
break;
}
}
if (pw != NULL)
- *fuzzyp = TRUE;
+ *fuzzyp = true;
else if (tTd(29, 4))
- dprintf("no fuzzy match found\n");
+ sm_dprintf("no fuzzy match found\n");
# if DEC_OSF_BROKEN_GETPWENT /* DEC OSF/1 3.2 or earlier */
endpwent();
# endif /* DEC_OSF_BROKEN_GETPWENT */
- return pw;
+ if (pw == NULL)
+ return EX_NOUSER;
+ sm_mbdb_frompw(user, pw);
+ return EX_OK;
#else /* MATCHGECOS */
if (tTd(29, 4))
- dprintf("not found (fuzzy disabled)\n");
- return NULL;
+ sm_dprintf("not found (fuzzy disabled)\n");
+ return EX_NOUSER;
#endif /* MATCHGECOS */
}
- /*
+/*
** WRITABLE -- predicate returning if the file is writable.
**
** This routine must duplicate the algorithm in sys/fio.c.
@@ -977,8 +1258,8 @@ finduser(name, fuzzyp)
** flags -- SFF_* flags to control the function.
**
** Returns:
-** TRUE -- if we will be able to write this file.
-** FALSE -- if we cannot write this file.
+** true -- if we will be able to write this file.
+** false -- if we cannot write this file.
**
** Side Effects:
** none.
@@ -995,7 +1276,7 @@ writable(filename, ctladdr, flags)
char *user = NULL;
if (tTd(44, 5))
- dprintf("writable(%s, 0x%lx)\n", filename, flags);
+ sm_dprintf("writable(%s, 0x%lx)\n", filename, flags);
/*
** File does exist -- check that it is writable.
@@ -1052,13 +1333,13 @@ writable(filename, ctladdr, flags)
errno = safefile(filename, euid, egid, user, flags, S_IWRITE, NULL);
return errno == 0;
}
- /*
+/*
** INCLUDE -- handle :include: specification.
**
** Parameters:
** fname -- filename to include.
-** forwarding -- if TRUE, we are reading a .forward file.
-** if FALSE, it's a :include: file.
+** forwarding -- if true, we are reading a .forward file.
+** if false, it's a :include: file.
** ctladdr -- address template to use to fill in these
** addresses -- effective user/group id are
** the important things.
@@ -1099,14 +1380,14 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
int aliaslevel;
ENVELOPE *e;
{
- FILE *volatile fp = NULL;
+ SM_FILE_T *volatile fp = NULL;
char *oldto = e->e_to;
char *oldfilename = FileName;
int oldlinenumber = LineNumber;
- register EVENT *ev = NULL;
+ register SM_EVENT *ev = NULL;
int nincludes;
int mode;
- volatile bool maxreached = FALSE;
+ volatile bool maxreached = false;
register ADDRESS *ca;
volatile uid_t saveduid;
volatile gid_t savedgid;
@@ -1116,29 +1397,29 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
int rval = 0;
volatile long sfflags = SFF_REGONLY;
register char *p;
- bool safechown = FALSE;
- volatile bool safedir = FALSE;
+ bool safechown = false;
+ volatile bool safedir = false;
struct stat st;
char buf[MAXLINE];
if (tTd(27, 2))
- dprintf("include(%s)\n", fname);
+ sm_dprintf("include(%s)\n", fname);
if (tTd(27, 4))
- dprintf(" ruid=%d euid=%d\n",
+ sm_dprintf(" ruid=%d euid=%d\n",
(int) getuid(), (int) geteuid());
if (tTd(27, 14))
{
- dprintf("ctladdr ");
- printaddr(ctladdr, FALSE);
+ sm_dprintf("ctladdr ");
+ printaddr(ctladdr, false);
}
if (tTd(27, 9))
- dprintf("include: old uid = %d/%d\n",
- (int) getuid(), (int) geteuid());
+ sm_dprintf("include: old uid = %d/%d\n",
+ (int) getuid(), (int) geteuid());
-#if _FFR_UNSAFE_WRITABLE_INCLUDE
if (forwarding)
{
+ sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOWLINK;
if (!bitnset(DBS_GROUPWRITABLEFORWARDFILE, DontBlameSendmail))
sfflags |= SFF_NOGWFILES;
if (!bitnset(DBS_WORLDWRITABLEFORWARDFILE, DontBlameSendmail))
@@ -1151,10 +1432,6 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
if (!bitnset(DBS_WORLDWRITABLEINCLUDEFILE, DontBlameSendmail))
sfflags |= SFF_NOWWFILES;
}
-#endif /* _FFR_UNSAFE_WRITABLE_INCLUDE */
-
- if (forwarding)
- sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOWLINK;
/*
** If RunAsUser set, won't be able to run programs as user
@@ -1165,8 +1442,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
!bitnset(DBS_NONROOTSAFEADDR, DontBlameSendmail))
{
if (tTd(27, 4))
- dprintf("include: not safe (euid=%d, RunAsUid=%d)\n",
- (int) geteuid(), (int) RunAsUid);
+ sm_dprintf("include: not safe (euid=%d, RunAsUid=%d)\n",
+ (int) geteuid(), (int) RunAsUid);
ctladdr->q_flags |= QUNSAFEADDR;
}
@@ -1243,8 +1520,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
#endif /* MAILER_SETUID_METHOD != USE_SETUID */
if (tTd(27, 9))
- dprintf("include: new uid = %d/%d\n",
- (int) getuid(), (int) geteuid());
+ sm_dprintf("include: new uid = %d/%d\n",
+ (int) getuid(), (int) geteuid());
/*
** If home directory is remote mounted but server is down,
@@ -1261,7 +1538,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
goto resetuid;
}
if (TimeOuts.to_fileopen > 0)
- ev = setevent(TimeOuts.to_fileopen, includetimeout, 0);
+ ev = sm_setevent(TimeOuts.to_fileopen, includetimeout, 0);
else
ev = NULL;
@@ -1278,7 +1555,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
if (ret == 0)
{
/* in safe directory: relax chown & link rules */
- safedir = TRUE;
+ safedir = true;
sfflags |= SFF_NOPATHCHECK;
}
else
@@ -1314,7 +1591,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE),
DontBlameSendmail))
{
- if (LogLevel >= 12)
+ if (LogLevel > 11)
sm_syslog(LOG_INFO, e->e_id,
"%s: unsafe directory path, marked unsafe",
shortenstring(fname, MAXSHORTSTR));
@@ -1337,23 +1614,24 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
{
/* don't use this :include: file */
if (tTd(27, 4))
- dprintf("include: not safe (uid=%d): %s\n",
- (int) uid, errstring(rval));
+ sm_dprintf("include: not safe (uid=%d): %s\n",
+ (int) uid, sm_errstring(rval));
}
- else if ((fp = fopen(fname, "r")) == NULL)
+ else if ((fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, fname,
+ SM_IO_RDONLY, NULL)) == NULL)
{
rval = errno;
if (tTd(27, 4))
- dprintf("include: open: %s\n", errstring(rval));
+ sm_dprintf("include: open: %s\n", sm_errstring(rval));
}
- else if (filechanged(fname, fileno(fp), &st))
+ else if (filechanged(fname, sm_io_getinfo(fp,SM_IO_WHAT_FD, NULL), &st))
{
rval = E_SM_FILECHANGE;
if (tTd(27, 4))
- dprintf("include: file changed after open\n");
+ sm_dprintf("include: file changed after open\n");
}
if (ev != NULL)
- clrevent(ev);
+ sm_clrevent(ev);
resetuid:
@@ -1365,25 +1643,27 @@ resetuid:
# if USESETEUID
if (seteuid(0) < 0)
syserr("!seteuid(0) failure (real=%d, eff=%d)",
- getuid(), geteuid());
+ (int) getuid(), (int) geteuid());
# else /* USESETEUID */
if (setreuid(-1, 0) < 0)
syserr("!setreuid(-1, 0) failure (real=%d, eff=%d)",
- getuid(), geteuid());
+ (int) getuid(), (int) geteuid());
if (setreuid(RealUid, 0) < 0)
syserr("!setreuid(%d, 0) failure (real=%d, eff=%d)",
- RealUid, getuid(), geteuid());
+ (int) RealUid, (int) getuid(),
+ (int) geteuid());
# endif /* USESETEUID */
}
if (setgid(savedgid) < 0)
syserr("!setgid(%d) failure (real=%d eff=%d)",
- savedgid, getgid(), getegid());
+ (int) savedgid, (int) getgid(),
+ (int) getegid());
}
#endif /* HASSETREUID || USESETEUID */
if (tTd(27, 9))
- dprintf("include: reset uid = %d/%d\n",
- (int) getuid(), (int) geteuid());
+ sm_dprintf("include: reset uid = %d/%d\n",
+ (int) getuid(), (int) geteuid());
if (rval == E_SM_OPENTIMEOUT)
usrerr("451 4.4.1 open timeout on %s", fname);
@@ -1391,21 +1671,20 @@ resetuid:
if (fp == NULL)
return rval;
- if (fstat(fileno(fp), &st) < 0)
+ if (fstat(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), &st) < 0)
{
rval = errno;
syserr("Cannot fstat %s!", fname);
- (void) fclose(fp);
+ (void) sm_io_close(fp, SM_TIME_DEFAULT);
return rval;
}
/* if path was writable, check to avoid file giveaway tricks */
- safechown = chownsafe(fileno(fp), safedir);
+ safechown = chownsafe(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), safedir);
if (tTd(27, 6))
- dprintf("include: parent of %s is %s, chown is %ssafe\n",
- fname,
- safedir ? "safe" : "dangerous",
- safechown ? "" : "un");
+ sm_dprintf("include: parent of %s is %s, chown is %ssafe\n",
+ fname, safedir ? "safe" : "dangerous",
+ safechown ? "" : "un");
/* if no controlling user or coming from an alias delivery */
if (safechown &&
@@ -1436,17 +1715,19 @@ resetuid:
{
char *sh;
- ctladdr->q_ruser = newstr(pw->pw_name);
+ ctladdr->q_ruser = sm_rpool_strdup_x(e->e_rpool,
+ pw->pw_name);
if (safechown)
sh = pw->pw_shell;
else
sh = "/SENDMAIL/ANY/SHELL/";
if (!usershellok(pw->pw_name, sh))
{
- if (LogLevel >= 12)
+ if (LogLevel > 11)
sm_syslog(LOG_INFO, e->e_id,
"%s: user %s has bad shell %s, marked %s",
- shortenstring(fname, MAXSHORTSTR),
+ shortenstring(fname,
+ MAXSHORTSTR),
pw->pw_name, sh,
safechown ? "bogus" : "unsafe");
if (safechown)
@@ -1462,7 +1743,7 @@ resetuid:
/* don't do any more now */
ctladdr->q_state = QS_VERIFIED;
e->e_nrcpts++;
- (void) fclose(fp);
+ (void) sm_io_close(fp, SM_TIME_DEFAULT);
return rval;
}
@@ -1484,10 +1765,11 @@ resetuid:
if (bitset(mode, st.st_mode))
{
if (tTd(27, 6))
- dprintf("include: %s is %s writable, marked unsafe\n",
- shortenstring(fname, MAXSHORTSTR),
- bitset(S_IWOTH, st.st_mode) ? "world" : "group");
- if (LogLevel >= 12)
+ sm_dprintf("include: %s is %s writable, marked unsafe\n",
+ shortenstring(fname, MAXSHORTSTR),
+ bitset(S_IWOTH, st.st_mode) ? "world"
+ : "group");
+ if (LogLevel > 11)
sm_syslog(LOG_INFO, e->e_id,
"%s: %s writable %s file, marked unsafe",
shortenstring(fname, MAXSHORTSTR),
@@ -1501,9 +1783,10 @@ resetuid:
LineNumber = 0;
ctladdr->q_flags &= ~QSELFREF;
nincludes = 0;
- while (fgets(buf, sizeof buf, fp) != NULL && !maxreached)
+ while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL &&
+ !maxreached)
{
- fixcrlf(buf, TRUE);
+ fixcrlf(buf, true);
LineNumber++;
if (buf[0] == '#' || buf[0] == '\0')
continue;
@@ -1542,28 +1825,30 @@ resetuid:
nincludes >= MaxForwardEntries)
{
/* just stop reading and processing further entries */
- /* additional: (?)
+#if 0
+ /* additional: (?) */
ctladdr->q_state = QS_DONTSEND;
- **/
- syserr("Attempt to forward to more then %d addresses (in %s)!",
+#endif /* 0 */
+
+ syserr("Attempt to forward to more than %d addresses (in %s)!",
MaxForwardEntries,fname);
- maxreached = TRUE;
+ maxreached = true;
}
}
- if (ferror(fp) && tTd(27, 3))
- dprintf("include: read error: %s\n", errstring(errno));
+ if (sm_io_error(fp) && tTd(27, 3))
+ sm_dprintf("include: read error: %s\n", sm_errstring(errno));
if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags))
{
if (tTd(27, 5))
{
- dprintf("include: QS_DONTSEND ");
- printaddr(ctladdr, FALSE);
+ sm_dprintf("include: QS_DONTSEND ");
+ printaddr(ctladdr, false);
}
ctladdr->q_state = QS_DONTSEND;
}
- (void) fclose(fp);
+ (void) sm_io_close(fp, SM_TIME_DEFAULT);
FileName = oldfilename;
LineNumber = oldlinenumber;
e->e_to = oldto;
@@ -1582,7 +1867,7 @@ includetimeout()
errno = ETIMEDOUT;
longjmp(CtxIncludeTimeout, 1);
}
- /*
+/*
** SENDTOARGV -- send to an argument vector.
**
** Parameters:
@@ -1605,11 +1890,9 @@ sendtoargv(argv, e)
register char *p;
while ((p = *argv++) != NULL)
- {
(void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e);
- }
}
- /*
+/*
** GETCTLADDR -- get controlling address from an address header.
**
** If none, get one corresponding to the effective userid.
@@ -1619,9 +1902,6 @@ sendtoargv(argv, e)
**
** Returns:
** the controlling address.
-**
-** Side Effects:
-** none.
*/
ADDRESS *
@@ -1632,7 +1912,7 @@ getctladdr(a)
a = a->q_alias;
return a;
}
- /*
+/*
** SELF_REFERENCE -- check to see if an address references itself
**
** The check is done through a chain of aliases. If it is part of
@@ -1659,7 +1939,7 @@ self_reference(a)
ADDRESS *c; /* entry that point to a real mail box */
if (tTd(27, 1))
- dprintf("self_reference(%s)\n", a->q_paddr);
+ sm_dprintf("self_reference(%s)\n", a->q_paddr);
for (b = a->q_alias; b != NULL; b = b->q_alias)
{
@@ -1670,40 +1950,42 @@ self_reference(a)
if (b == NULL)
{
if (tTd(27, 1))
- dprintf("\t... no self ref\n");
+ sm_dprintf("\t... no self ref\n");
return NULL;
}
/*
** Pick the first address that resolved to a real mail box
- ** i.e has a pw entry. The returned value will be marked
+ ** i.e has a mbdb entry. The returned value will be marked
** QSELFREF in recipient(), which in turn will disable alias()
** from marking it as QS_IS_DEAD(), which mean it will be used
** as a deliverable address.
**
** The 2 key thing to note here are:
** 1) we are in a recursive call sequence:
- ** alias->sentolist->recipient->alias
+ ** alias->sendtolist->recipient->alias
** 2) normally, when we return back to alias(), the address
** will be marked QS_EXPANDED, since alias() assumes the
** expanded form will be used instead of the current address.
** This behaviour is turned off if the address is marked
- ** QSELFREF We set QSELFREF when we return to recipient().
+ ** QSELFREF. We set QSELFREF when we return to recipient().
*/
c = a;
while (c != NULL)
{
if (tTd(27, 10))
- dprintf(" %s", c->q_user);
+ sm_dprintf(" %s", c->q_user);
if (bitnset(M_HASPWENT, c->q_mailer->m_flags))
{
+ SM_MBDB_T user;
+
if (tTd(27, 2))
- dprintf("\t... getpwnam(%s)... ", c->q_user);
- if (sm_getpwnam(c->q_user) != NULL)
+ sm_dprintf("\t... getpwnam(%s)... ", c->q_user);
+ if (sm_mbdb_lookup(c->q_user, &user) == EX_OK)
{
if (tTd(27, 2))
- dprintf("found\n");
+ sm_dprintf("found\n");
/* ought to cache results here */
if (sameaddr(b, c))
@@ -1712,7 +1994,7 @@ self_reference(a)
return c;
}
if (tTd(27, 2))
- dprintf("failed\n");
+ sm_dprintf("failed\n");
}
else
{
@@ -1721,7 +2003,7 @@ self_reference(a)
b->q_mailer == c->q_mailer)
{
if (tTd(27, 2))
- dprintf("\t... local match (%s)\n",
+ sm_dprintf("\t... local match (%s)\n",
c->q_user);
if (sameaddr(b, c))
return b;
@@ -1730,12 +2012,12 @@ self_reference(a)
}
}
if (tTd(27, 10))
- dprintf("\n");
+ sm_dprintf("\n");
c = c->q_alias;
}
if (tTd(27, 1))
- dprintf("\t... cannot break loop for \"%s\"\n", a->q_paddr);
+ sm_dprintf("\t... cannot break loop for \"%s\"\n", a->q_paddr);
return NULL;
}
OpenPOWER on IntegriCloud