diff options
author | gshapiro <gshapiro@FreeBSD.org> | 2002-02-17 21:56:45 +0000 |
---|---|---|
committer | gshapiro <gshapiro@FreeBSD.org> | 2002-02-17 21:56:45 +0000 |
commit | 8449595fe97f4474b9b9a7e4edee1ef35dcff393 (patch) | |
tree | e7a33b132264d449a512ddf4a8685df097669c1d /contrib/sendmail/src/recipient.c | |
parent | 289b381b31415647269c7520d881017e2dcb27f1 (diff) | |
download | FreeBSD-src-8449595fe97f4474b9b9a7e4edee1ef35dcff393.zip FreeBSD-src-8449595fe97f4474b9b9a7e4edee1ef35dcff393.tar.gz |
Import sendmail 8.12.2
Diffstat (limited to 'contrib/sendmail/src/recipient.c')
-rw-r--r-- | contrib/sendmail/src/recipient.c | 1196 |
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; } |