138032Speter/* 2261194Sgshapiro * Copyright (c) 1998-2003, 2006 Proofpoint, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1464562Sgshapiro#include <sendmail.h> 1538032Speter 16266527SgshapiroSM_RCSID("@(#)$Id: recipient.c,v 8.351 2013-11-22 20:51:56 ca Exp $") 1764562Sgshapiro 18141858Sgshapirostatic void includetimeout __P((int)); 1964562Sgshapirostatic ADDRESS *self_reference __P((ADDRESS *)); 2090792Sgshapirostatic int sortexpensive __P((ADDRESS *, ADDRESS *)); 2190792Sgshapirostatic int sortbysignature __P((ADDRESS *, ADDRESS *)); 2290792Sgshapirostatic int sorthost __P((ADDRESS *, ADDRESS *)); 2364562Sgshapiro 2490792Sgshapirotypedef int sortfn_t __P((ADDRESS *, ADDRESS *)); 2590792Sgshapiro 2638032Speter/* 2790792Sgshapiro** SORTHOST -- strcmp()-like func for host portion of an ADDRESS 2890792Sgshapiro** 2990792Sgshapiro** Parameters: 3090792Sgshapiro** xx -- first ADDRESS 3190792Sgshapiro** yy -- second ADDRESS 3290792Sgshapiro** 3390792Sgshapiro** Returns: 3490792Sgshapiro** <0 when xx->q_host is less than yy->q_host 3590792Sgshapiro** >0 when xx->q_host is greater than yy->q_host 3690792Sgshapiro** 0 when equal 3790792Sgshapiro*/ 3890792Sgshapiro 3990792Sgshapirostatic int 4090792Sgshapirosorthost(xx, yy) 4190792Sgshapiro register ADDRESS *xx; 4290792Sgshapiro register ADDRESS *yy; 4390792Sgshapiro{ 4490792Sgshapiro#if _FFR_HOST_SORT_REVERSE 4590792Sgshapiro /* XXX maybe compare hostnames from the end? */ 4690792Sgshapiro return sm_strrevcasecmp(xx->q_host, yy->q_host); 47363466Sgshapiro#else 4890792Sgshapiro return sm_strcasecmp(xx->q_host, yy->q_host); 49363466Sgshapiro#endif 5090792Sgshapiro} 5190792Sgshapiro 5290792Sgshapiro/* 5390792Sgshapiro** SORTEXPENSIVE -- strcmp()-like func for expensive mailers 5490792Sgshapiro** 5590792Sgshapiro** The mailer has been noted already as "expensive" for 'xx'. This 5690792Sgshapiro** will give a result relative to 'yy'. Expensive mailers get rated 5790792Sgshapiro** "greater than" non-expensive mailers because during the delivery phase 5890792Sgshapiro** it will get queued -- no use it getting in the way of less expensive 5990792Sgshapiro** recipients. We avoid an MX RR lookup when both 'xx' and 'yy' are 6090792Sgshapiro** expensive since an MX RR lookup happens when extracted from the queue 6190792Sgshapiro** later. 6290792Sgshapiro** 6390792Sgshapiro** Parameters: 6490792Sgshapiro** xx -- first ADDRESS 6590792Sgshapiro** yy -- second ADDRESS 6690792Sgshapiro** 6790792Sgshapiro** Returns: 6890792Sgshapiro** <0 when xx->q_host is less than yy->q_host and both are 6990792Sgshapiro** expensive 7090792Sgshapiro** >0 when xx->q_host is greater than yy->q_host, or when 7190792Sgshapiro** 'yy' is non-expensive 7290792Sgshapiro** 0 when equal (by expense and q_host) 7390792Sgshapiro*/ 7490792Sgshapiro 7590792Sgshapirostatic int 7690792Sgshapirosortexpensive(xx, yy) 7790792Sgshapiro ADDRESS *xx; 7890792Sgshapiro ADDRESS *yy; 7990792Sgshapiro{ 8090792Sgshapiro if (!bitnset(M_EXPENSIVE, yy->q_mailer->m_flags)) 8190792Sgshapiro return 1; /* xx should go later */ 8290792Sgshapiro#if _FFR_HOST_SORT_REVERSE 8390792Sgshapiro /* XXX maybe compare hostnames from the end? */ 8490792Sgshapiro return sm_strrevcasecmp(xx->q_host, yy->q_host); 85363466Sgshapiro#else 8690792Sgshapiro return sm_strcasecmp(xx->q_host, yy->q_host); 87363466Sgshapiro#endif 8890792Sgshapiro} 8990792Sgshapiro 9090792Sgshapiro/* 9190792Sgshapiro** SORTBYSIGNATURE -- a strcmp()-like func for q_mailer and q_host in ADDRESS 9290792Sgshapiro** 9390792Sgshapiro** Parameters: 9490792Sgshapiro** xx -- first ADDRESS 9590792Sgshapiro** yy -- second ADDRESS 9690792Sgshapiro** 9790792Sgshapiro** Returns: 9890792Sgshapiro** 0 when the "signature"'s are same 9990792Sgshapiro** <0 when xx->q_signature is less than yy->q_signature 10090792Sgshapiro** >0 when xx->q_signature is greater than yy->q_signature 10190792Sgshapiro** 10290792Sgshapiro** Side Effect: 10390792Sgshapiro** May set ADDRESS pointer for q_signature if not already set. 10490792Sgshapiro*/ 10590792Sgshapiro 10690792Sgshapirostatic int 10790792Sgshapirosortbysignature(xx, yy) 10890792Sgshapiro ADDRESS *xx; 10990792Sgshapiro ADDRESS *yy; 11090792Sgshapiro{ 11190792Sgshapiro register int ret; 11290792Sgshapiro 11390792Sgshapiro /* Let's avoid redoing the signature over and over again */ 11490792Sgshapiro if (xx->q_signature == NULL) 115363466Sgshapiro xx->q_signature = hostsignature(xx->q_mailer, xx->q_host, xx->q_flags & QSECURE); 11690792Sgshapiro if (yy->q_signature == NULL) 117363466Sgshapiro yy->q_signature = hostsignature(yy->q_mailer, yy->q_host, yy->q_flags & QSECURE); 11890792Sgshapiro ret = strcmp(xx->q_signature, yy->q_signature); 11990792Sgshapiro 12090792Sgshapiro /* 12190792Sgshapiro ** If the two signatures are the same then we will return a sort 12290792Sgshapiro ** value based on 'q_user'. But note that we have reversed xx and yy 12390792Sgshapiro ** on purpose. This additional compare helps reduce the number of 12490792Sgshapiro ** sameaddr() calls and loops in recipient() for the case when 12590792Sgshapiro ** the rcpt list has been provided already in-order. 12690792Sgshapiro */ 12790792Sgshapiro 12890792Sgshapiro if (ret == 0) 12990792Sgshapiro return strcmp(yy->q_user, xx->q_user); 13090792Sgshapiro else 13190792Sgshapiro return ret; 13290792Sgshapiro} 13390792Sgshapiro 13490792Sgshapiro/* 13538032Speter** SENDTOLIST -- Designate a send list. 13638032Speter** 13738032Speter** The parameter is a comma-separated list of people to send to. 13838032Speter** This routine arranges to send to all of them. 13938032Speter** 14038032Speter** Parameters: 14138032Speter** list -- the send list. 14238032Speter** ctladdr -- the address template for the person to 14338032Speter** send to -- effective uid/gid are important. 14438032Speter** This is typically the alias that caused this 14538032Speter** expansion. 14638032Speter** sendq -- a pointer to the head of a queue to put 14738032Speter** these people into. 14838032Speter** aliaslevel -- the current alias nesting depth -- to 14938032Speter** diagnose loops. 15038032Speter** e -- the envelope in which to add these recipients. 15138032Speter** 15238032Speter** Returns: 15338032Speter** The number of addresses actually on the list. 15438032Speter*/ 15538032Speter 15638032Speter/* q_flags bits inherited from ctladdr */ 15738032Speter#define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY) 15838032Speter 15938032Speterint 16038032Spetersendtolist(list, ctladdr, sendq, aliaslevel, e) 16138032Speter char *list; 16238032Speter ADDRESS *ctladdr; 16338032Speter ADDRESS **sendq; 16438032Speter int aliaslevel; 16538032Speter register ENVELOPE *e; 16638032Speter{ 16738032Speter register char *p; 16890792Sgshapiro register ADDRESS *SM_NONVOLATILE al; /* list of addresses to send to */ 16990792Sgshapiro SM_NONVOLATILE char delimiter; /* the address delimiter */ 17090792Sgshapiro SM_NONVOLATILE int naddrs; 17190792Sgshapiro SM_NONVOLATILE int i; 172120256Sgshapiro char *endp; 17338032Speter char *oldto = e->e_to; 17490792Sgshapiro char *SM_NONVOLATILE bufp; 17538032Speter char buf[MAXNAME + 1]; 17638032Speter 17738032Speter if (list == NULL) 17838032Speter { 17938032Speter syserr("sendtolist: null list"); 18038032Speter return 0; 18138032Speter } 18238032Speter 18338032Speter if (tTd(25, 1)) 18438032Speter { 18590792Sgshapiro sm_dprintf("sendto: %s\n ctladdr=", list); 186132943Sgshapiro printaddr(sm_debug_file(), ctladdr, false); 18738032Speter } 18838032Speter 18938032Speter /* heuristic to determine old versus new style addresses */ 19038032Speter if (ctladdr == NULL && 19138032Speter (strchr(list, ',') != NULL || strchr(list, ';') != NULL || 19238032Speter strchr(list, '<') != NULL || strchr(list, '(') != NULL)) 19338032Speter e->e_flags &= ~EF_OLDSTYLE; 19438032Speter delimiter = ' '; 19538032Speter if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) 19638032Speter delimiter = ','; 19738032Speter 19838032Speter al = NULL; 19938032Speter naddrs = 0; 20038032Speter 20138032Speter /* make sure we have enough space to copy the string */ 20238032Speter i = strlen(list) + 1; 203168515Sgshapiro if (i <= sizeof(buf)) 20464562Sgshapiro { 20538032Speter bufp = buf; 206168515Sgshapiro i = sizeof(buf); 20764562Sgshapiro } 20838032Speter else 20990792Sgshapiro bufp = sm_malloc_x(i); 210120256Sgshapiro endp = bufp + i; 21138032Speter 21290792Sgshapiro SM_TRY 21338032Speter { 21490792Sgshapiro (void) sm_strlcpy(bufp, denlstring(list, false, true), i); 21538032Speter 21690792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 21790792Sgshapiro for (p = bufp; *p != '\0'; ) 21838032Speter { 21990792Sgshapiro auto char *delimptr; 22090792Sgshapiro register ADDRESS *a; 22138032Speter 222120256Sgshapiro SM_ASSERT(p < endp); 223120256Sgshapiro 22490792Sgshapiro /* parse the address */ 225363466Sgshapiro while ((SM_ISSPACE(*p)) || *p == ',') 22690792Sgshapiro p++; 227120256Sgshapiro SM_ASSERT(p < endp); 22890792Sgshapiro a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, 22990792Sgshapiro &delimptr, e, true); 23090792Sgshapiro p = delimptr; 231120256Sgshapiro SM_ASSERT(p < endp); 23290792Sgshapiro if (a == NULL) 23390792Sgshapiro continue; 23490792Sgshapiro a->q_next = al; 23590792Sgshapiro a->q_alias = ctladdr; 23690792Sgshapiro 23790792Sgshapiro /* arrange to inherit attributes from parent */ 23890792Sgshapiro if (ctladdr != NULL) 23938032Speter { 24090792Sgshapiro ADDRESS *b; 24190792Sgshapiro 24290792Sgshapiro /* self reference test */ 24390792Sgshapiro if (sameaddr(ctladdr, a)) 24438032Speter { 24590792Sgshapiro if (tTd(27, 5)) 24690792Sgshapiro { 24790792Sgshapiro sm_dprintf("sendtolist: QSELFREF "); 248132943Sgshapiro printaddr(sm_debug_file(), ctladdr, false); 24990792Sgshapiro } 25090792Sgshapiro ctladdr->q_flags |= QSELFREF; 25138032Speter } 25238032Speter 25390792Sgshapiro /* check for address loops */ 25490792Sgshapiro b = self_reference(a); 25590792Sgshapiro if (b != NULL) 25638032Speter { 25790792Sgshapiro b->q_flags |= QSELFREF; 25838032Speter if (tTd(27, 5)) 25938032Speter { 26090792Sgshapiro sm_dprintf("sendtolist: QSELFREF "); 261132943Sgshapiro printaddr(sm_debug_file(), b, false); 26238032Speter } 26390792Sgshapiro if (a != b) 26490792Sgshapiro { 26590792Sgshapiro if (tTd(27, 5)) 26690792Sgshapiro { 26790792Sgshapiro sm_dprintf("sendtolist: QS_DONTSEND "); 268132943Sgshapiro printaddr(sm_debug_file(), a, false); 26990792Sgshapiro } 27090792Sgshapiro a->q_state = QS_DONTSEND; 27190792Sgshapiro b->q_flags |= a->q_flags & QNOTREMOTE; 27290792Sgshapiro continue; 27390792Sgshapiro } 27438032Speter } 27590792Sgshapiro 27690792Sgshapiro /* full name */ 27790792Sgshapiro if (a->q_fullname == NULL) 27890792Sgshapiro a->q_fullname = ctladdr->q_fullname; 27990792Sgshapiro 28090792Sgshapiro /* various flag bits */ 28190792Sgshapiro a->q_flags &= ~QINHERITEDBITS; 28290792Sgshapiro a->q_flags |= ctladdr->q_flags & QINHERITEDBITS; 28390792Sgshapiro 28490792Sgshapiro /* DSN recipient information */ 28590792Sgshapiro a->q_finalrcpt = ctladdr->q_finalrcpt; 28690792Sgshapiro a->q_orcpt = ctladdr->q_orcpt; 28738032Speter } 28838032Speter 28990792Sgshapiro al = a; 29090792Sgshapiro } 29138032Speter 29290792Sgshapiro /* arrange to send to everyone on the local send list */ 29390792Sgshapiro while (al != NULL) 29490792Sgshapiro { 29590792Sgshapiro register ADDRESS *a = al; 29638032Speter 29790792Sgshapiro al = a->q_next; 29890792Sgshapiro a = recipient(a, sendq, aliaslevel, e); 29990792Sgshapiro naddrs++; 30038032Speter } 30138032Speter } 30290792Sgshapiro SM_FINALLY 30338032Speter { 30490792Sgshapiro e->e_to = oldto; 30590792Sgshapiro if (bufp != buf) 30690792Sgshapiro sm_free(bufp); 30790792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL); 30838032Speter } 30990792Sgshapiro SM_END_TRY 31064562Sgshapiro return naddrs; 31138032Speter} 312168515Sgshapiro 31390792Sgshapiro#if MILTER 31490792Sgshapiro/* 31564562Sgshapiro** REMOVEFROMLIST -- Remove addresses from a send list. 31664562Sgshapiro** 31764562Sgshapiro** The parameter is a comma-separated list of recipients to remove. 31864562Sgshapiro** Note that it only deletes matching addresses. If those addresses 31990792Sgshapiro** have been expanded already in the sendq, it won't mark the 32064562Sgshapiro** expanded recipients as QS_REMOVED. 32164562Sgshapiro** 32264562Sgshapiro** Parameters: 32364562Sgshapiro** list -- the list to remove. 32464562Sgshapiro** sendq -- a pointer to the head of a queue to remove 32564562Sgshapiro** these addresses from. 32664562Sgshapiro** e -- the envelope in which to remove these recipients. 32764562Sgshapiro** 32864562Sgshapiro** Returns: 32964562Sgshapiro** The number of addresses removed from the list. 33064562Sgshapiro** 33164562Sgshapiro*/ 33264562Sgshapiro 33364562Sgshapiroint 33464562Sgshapiroremovefromlist(list, sendq, e) 33564562Sgshapiro char *list; 33664562Sgshapiro ADDRESS **sendq; 33764562Sgshapiro ENVELOPE *e; 33864562Sgshapiro{ 33990792Sgshapiro SM_NONVOLATILE char delimiter; /* the address delimiter */ 34090792Sgshapiro SM_NONVOLATILE int naddrs; 34190792Sgshapiro SM_NONVOLATILE int i; 34264562Sgshapiro char *p; 34364562Sgshapiro char *oldto = e->e_to; 34490792Sgshapiro char *SM_NONVOLATILE bufp; 34564562Sgshapiro char buf[MAXNAME + 1]; 34664562Sgshapiro 34764562Sgshapiro if (list == NULL) 34864562Sgshapiro { 34964562Sgshapiro syserr("removefromlist: null list"); 35064562Sgshapiro return 0; 35164562Sgshapiro } 35264562Sgshapiro 35364562Sgshapiro if (tTd(25, 1)) 35490792Sgshapiro sm_dprintf("removefromlist: %s\n", list); 35564562Sgshapiro 35664562Sgshapiro /* heuristic to determine old versus new style addresses */ 35764562Sgshapiro if (strchr(list, ',') != NULL || strchr(list, ';') != NULL || 35864562Sgshapiro strchr(list, '<') != NULL || strchr(list, '(') != NULL) 35964562Sgshapiro e->e_flags &= ~EF_OLDSTYLE; 36064562Sgshapiro delimiter = ' '; 36164562Sgshapiro if (!bitset(EF_OLDSTYLE, e->e_flags)) 36264562Sgshapiro delimiter = ','; 36364562Sgshapiro 36464562Sgshapiro naddrs = 0; 36564562Sgshapiro 36664562Sgshapiro /* make sure we have enough space to copy the string */ 36764562Sgshapiro i = strlen(list) + 1; 368168515Sgshapiro if (i <= sizeof(buf)) 36964562Sgshapiro { 37064562Sgshapiro bufp = buf; 371168515Sgshapiro i = sizeof(buf); 37264562Sgshapiro } 37364562Sgshapiro else 37490792Sgshapiro bufp = sm_malloc_x(i); 37564562Sgshapiro 37690792Sgshapiro SM_TRY 37764562Sgshapiro { 37890792Sgshapiro (void) sm_strlcpy(bufp, denlstring(list, false, true), i); 37964562Sgshapiro 380173340Sgshapiro#if _FFR_ADDR_TYPE_MODES 381173340Sgshapiro if (AddrTypeModes) 382173340Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), 383173340Sgshapiro "e r d"); 384173340Sgshapiro else 385173340Sgshapiro#endif /* _FFR_ADDR_TYPE_MODES */ 38690792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 38790792Sgshapiro for (p = bufp; *p != '\0'; ) 38864562Sgshapiro { 38990792Sgshapiro ADDRESS a; /* parsed address to be removed */ 39090792Sgshapiro ADDRESS *q; 39190792Sgshapiro ADDRESS **pq; 39290792Sgshapiro char *delimptr; 39390792Sgshapiro 39490792Sgshapiro /* parse the address */ 395363466Sgshapiro while ((SM_ISSPACE(*p)) || *p == ',') 39690792Sgshapiro p++; 397168515Sgshapiro if (parseaddr(p, &a, RF_COPYALL|RF_RM_ADDR, 39890792Sgshapiro delimiter, &delimptr, e, true) == NULL) 39990792Sgshapiro { 40090792Sgshapiro p = delimptr; 40190792Sgshapiro continue; 40290792Sgshapiro } 40364562Sgshapiro p = delimptr; 40490792Sgshapiro for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 40564562Sgshapiro { 40690792Sgshapiro if (!QS_IS_DEAD(q->q_state) && 407125820Sgshapiro (sameaddr(q, &a) || 408125820Sgshapiro strcmp(q->q_paddr, a.q_paddr) == 0)) 40964562Sgshapiro { 41090792Sgshapiro if (tTd(25, 5)) 41190792Sgshapiro { 41290792Sgshapiro sm_dprintf("removefromlist: QS_REMOVED "); 413132943Sgshapiro printaddr(sm_debug_file(), &a, false); 41490792Sgshapiro } 41590792Sgshapiro q->q_state = QS_REMOVED; 41690792Sgshapiro naddrs++; 41790792Sgshapiro break; 41864562Sgshapiro } 41964562Sgshapiro } 42064562Sgshapiro } 42164562Sgshapiro } 42290792Sgshapiro SM_FINALLY 42390792Sgshapiro { 42490792Sgshapiro e->e_to = oldto; 42590792Sgshapiro if (bufp != buf) 42690792Sgshapiro sm_free(bufp); 42790792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL); 42890792Sgshapiro } 42990792Sgshapiro SM_END_TRY 43064562Sgshapiro return naddrs; 43164562Sgshapiro} 43290792Sgshapiro#endif /* MILTER */ 433168515Sgshapiro 43490792Sgshapiro/* 43538032Speter** RECIPIENT -- Designate a message recipient 436168515Sgshapiro** Saves the named person for future mailing (after some checks). 43738032Speter** 43838032Speter** Parameters: 43990792Sgshapiro** new -- the (preparsed) address header for the recipient. 44038032Speter** sendq -- a pointer to the head of a queue to put the 44164562Sgshapiro** recipient in. Duplicate suppression is done 44238032Speter** in this queue. 44338032Speter** aliaslevel -- the current alias nesting depth. 44438032Speter** e -- the current envelope. 44538032Speter** 44638032Speter** Returns: 44738032Speter** The actual address in the queue. This will be "a" if 44838032Speter** the address is not a duplicate, else the original address. 44938032Speter** 45038032Speter*/ 45138032Speter 45238032SpeterADDRESS * 45390792Sgshapirorecipient(new, sendq, aliaslevel, e) 45490792Sgshapiro register ADDRESS *new; 45538032Speter register ADDRESS **sendq; 45638032Speter int aliaslevel; 45738032Speter register ENVELOPE *e; 45838032Speter{ 45938032Speter register ADDRESS *q; 46038032Speter ADDRESS **pq; 46190792Sgshapiro ADDRESS **prev; 46238032Speter register struct mailer *m; 46390792Sgshapiro register char *p; 46464562Sgshapiro int i, buflen; 46590792Sgshapiro bool quoted; /* set if the addr has a quote bit */ 46690792Sgshapiro bool insert; 46790792Sgshapiro int findusercount; 46890792Sgshapiro bool initialdontsend; 46938032Speter char *buf; 47038032Speter char buf0[MAXNAME + 1]; /* unquoted image of the user name */ 47190792Sgshapiro sortfn_t *sortfn; 47238032Speter 47390792Sgshapiro p = NULL; 47490792Sgshapiro quoted = false; 47590792Sgshapiro insert = false; 47690792Sgshapiro findusercount = 0; 47790792Sgshapiro initialdontsend = QS_IS_DEAD(new->q_state); 47890792Sgshapiro e->e_to = new->q_paddr; 47990792Sgshapiro m = new->q_mailer; 48038032Speter errno = 0; 48138032Speter if (aliaslevel == 0) 48290792Sgshapiro new->q_flags |= QPRIMARY; 48338032Speter if (tTd(26, 1)) 48438032Speter { 48590792Sgshapiro sm_dprintf("\nrecipient (%d): ", aliaslevel); 486132943Sgshapiro printaddr(sm_debug_file(), new, false); 48738032Speter } 48838032Speter 48990792Sgshapiro /* if this is primary, use it as original recipient */ 49090792Sgshapiro if (new->q_alias == NULL) 49138032Speter { 49238032Speter if (e->e_origrcpt == NULL) 49390792Sgshapiro e->e_origrcpt = new->q_paddr; 49490792Sgshapiro else if (e->e_origrcpt != new->q_paddr) 49538032Speter e->e_origrcpt = ""; 49638032Speter } 49738032Speter 49890792Sgshapiro /* find parent recipient for finalrcpt and orcpt */ 49990792Sgshapiro for (q = new; q->q_alias != NULL; q = q->q_alias) 50090792Sgshapiro continue; 50190792Sgshapiro 50290792Sgshapiro /* find final recipient DSN address */ 50390792Sgshapiro if (new->q_finalrcpt == NULL && 50490792Sgshapiro e->e_from.q_mailer != NULL) 50590792Sgshapiro { 50690792Sgshapiro char frbuf[MAXLINE]; 50790792Sgshapiro 50890792Sgshapiro p = e->e_from.q_mailer->m_addrtype; 50990792Sgshapiro if (p == NULL) 51090792Sgshapiro p = "rfc822"; 511363466Sgshapiro#if _FFR_EAI 512363466Sgshapiro if (sm_strcasecmp(p, "rfc822") == 0 && 513363466Sgshapiro !addr_is_ascii(q->q_user)) 514363466Sgshapiro p = "utf-8"; 515363466Sgshapiro#endif 51690792Sgshapiro if (sm_strcasecmp(p, "rfc822") != 0) 51790792Sgshapiro { 518168515Sgshapiro (void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s", 51990792Sgshapiro q->q_mailer->m_addrtype, 52090792Sgshapiro q->q_user); 52190792Sgshapiro } 52290792Sgshapiro else if (strchr(q->q_user, '@') != NULL) 52390792Sgshapiro { 524168515Sgshapiro (void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s", 52590792Sgshapiro p, q->q_user); 52690792Sgshapiro } 52790792Sgshapiro else if (strchr(q->q_paddr, '@') != NULL) 52890792Sgshapiro { 52990792Sgshapiro char *qp; 53090792Sgshapiro bool b; 53190792Sgshapiro 53290792Sgshapiro qp = q->q_paddr; 53390792Sgshapiro 53490792Sgshapiro /* strip brackets from address */ 53590792Sgshapiro b = false; 53690792Sgshapiro if (*qp == '<') 53790792Sgshapiro { 53890792Sgshapiro b = qp[strlen(qp) - 1] == '>'; 53990792Sgshapiro if (b) 54090792Sgshapiro qp[strlen(qp) - 1] = '\0'; 54190792Sgshapiro qp++; 54290792Sgshapiro } 543168515Sgshapiro (void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s", 54490792Sgshapiro p, qp); 54590792Sgshapiro 54690792Sgshapiro /* undo damage */ 54790792Sgshapiro if (b) 54890792Sgshapiro qp[strlen(qp)] = '>'; 54990792Sgshapiro } 55090792Sgshapiro else 55190792Sgshapiro { 552168515Sgshapiro (void) sm_snprintf(frbuf, sizeof(frbuf), 55390792Sgshapiro "%s; %.700s@%.100s", 55490792Sgshapiro p, q->q_user, MyHostName); 55590792Sgshapiro } 55690792Sgshapiro new->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool, frbuf); 55790792Sgshapiro } 55890792Sgshapiro 55964562Sgshapiro#if _FFR_GEN_ORCPT 56064562Sgshapiro /* set ORCPT DSN arg if not already set */ 56190792Sgshapiro if (new->q_orcpt == NULL) 56264562Sgshapiro { 56364562Sgshapiro /* check for an existing ORCPT */ 56464562Sgshapiro if (q->q_orcpt != NULL) 56590792Sgshapiro new->q_orcpt = q->q_orcpt; 56664562Sgshapiro else 56764562Sgshapiro { 56864562Sgshapiro /* make our own */ 56990792Sgshapiro bool b = false; 57064562Sgshapiro char *qp; 57164562Sgshapiro char obuf[MAXLINE]; 57264562Sgshapiro 57364562Sgshapiro if (e->e_from.q_mailer != NULL) 57464562Sgshapiro p = e->e_from.q_mailer->m_addrtype; 57564562Sgshapiro if (p == NULL) 57664562Sgshapiro p = "rfc822"; 577168515Sgshapiro (void) sm_strlcpyn(obuf, sizeof(obuf), 2, p, ";"); 57864562Sgshapiro 57964562Sgshapiro qp = q->q_paddr; 58064562Sgshapiro 58164562Sgshapiro /* FFR: Needs to strip comments from stdin addrs */ 58264562Sgshapiro 58364562Sgshapiro /* strip brackets from address */ 58464562Sgshapiro if (*qp == '<') 58564562Sgshapiro { 58664562Sgshapiro b = qp[strlen(qp) - 1] == '>'; 58764562Sgshapiro if (b) 58864562Sgshapiro qp[strlen(qp) - 1] = '\0'; 58964562Sgshapiro qp++; 59064562Sgshapiro } 59164562Sgshapiro 592168515Sgshapiro p = xtextify(denlstring(qp, true, false), "="); 59364562Sgshapiro 594168515Sgshapiro if (sm_strlcat(obuf, p, sizeof(obuf)) >= sizeof(obuf)) 59564562Sgshapiro { 59664562Sgshapiro /* if too big, don't use it */ 59764562Sgshapiro obuf[0] = '\0'; 59864562Sgshapiro } 59964562Sgshapiro 60064562Sgshapiro /* undo damage */ 60164562Sgshapiro if (b) 60264562Sgshapiro qp[strlen(qp)] = '>'; 60364562Sgshapiro 60464562Sgshapiro if (obuf[0] != '\0') 60590792Sgshapiro new->q_orcpt = 60690792Sgshapiro sm_rpool_strdup_x(e->e_rpool, obuf); 60764562Sgshapiro } 60864562Sgshapiro } 60964562Sgshapiro#endif /* _FFR_GEN_ORCPT */ 61064562Sgshapiro 61138032Speter /* break aliasing loops */ 61238032Speter if (aliaslevel > MaxAliasRecursion) 61338032Speter { 61490792Sgshapiro new->q_state = QS_BADADDR; 61590792Sgshapiro new->q_status = "5.4.6"; 616168515Sgshapiro if (new->q_alias != NULL) 617168515Sgshapiro { 618168515Sgshapiro new->q_alias->q_state = QS_BADADDR; 619168515Sgshapiro new->q_alias->q_status = "5.4.6"; 620168515Sgshapiro } 621168515Sgshapiro if ((SuprErrs || !LogUsrErrs) && LogLevel > 0) 622168515Sgshapiro { 623168515Sgshapiro sm_syslog(LOG_ERR, e->e_id, 624168515Sgshapiro "aliasing/forwarding loop broken: %s (%d aliases deep; %d max)", 625168515Sgshapiro FileName != NULL ? FileName : "", aliaslevel, 626168515Sgshapiro MaxAliasRecursion); 627168515Sgshapiro } 62890792Sgshapiro usrerrenh(new->q_status, 62964562Sgshapiro "554 aliasing/forwarding loop broken (%d aliases deep; %d max)", 63064562Sgshapiro aliaslevel, MaxAliasRecursion); 63190792Sgshapiro return new; 63238032Speter } 63338032Speter 63438032Speter /* 63538032Speter ** Finish setting up address structure. 63638032Speter */ 63738032Speter 63838032Speter /* get unquoted user for file, program or user.name check */ 63990792Sgshapiro i = strlen(new->q_user); 640168515Sgshapiro if (i >= sizeof(buf0)) 64164562Sgshapiro { 64264562Sgshapiro buflen = i + 1; 64364562Sgshapiro buf = xalloc(buflen); 64464562Sgshapiro } 64538032Speter else 64664562Sgshapiro { 64738032Speter buf = buf0; 648168515Sgshapiro buflen = sizeof(buf0); 64964562Sgshapiro } 65090792Sgshapiro (void) sm_strlcpy(buf, new->q_user, buflen); 65138032Speter for (p = buf; *p != '\0' && !quoted; p++) 65238032Speter { 65338032Speter if (*p == '\\') 65490792Sgshapiro quoted = true; 65538032Speter } 65638032Speter stripquotes(buf); 65738032Speter 65838032Speter /* check for direct mailing to restricted mailers */ 65938032Speter if (m == ProgMailer) 66038032Speter { 66190792Sgshapiro if (new->q_alias == NULL || UseMSP || 66290792Sgshapiro bitset(EF_UNSAFE, e->e_flags)) 66338032Speter { 66490792Sgshapiro new->q_state = QS_BADADDR; 66590792Sgshapiro new->q_status = "5.7.1"; 66690792Sgshapiro usrerrenh(new->q_status, 66764562Sgshapiro "550 Cannot mail directly to programs"); 66838032Speter } 66990792Sgshapiro else if (bitset(QBOGUSSHELL, new->q_alias->q_flags)) 67038032Speter { 67190792Sgshapiro new->q_state = QS_BADADDR; 67290792Sgshapiro new->q_status = "5.7.1"; 67390792Sgshapiro if (new->q_alias->q_ruser == NULL) 67490792Sgshapiro usrerrenh(new->q_status, 675285229Sgshapiro "550 UID %ld is an unknown user: cannot mail to programs", 676285229Sgshapiro (long) new->q_alias->q_uid); 67738032Speter else 67890792Sgshapiro usrerrenh(new->q_status, 67964562Sgshapiro "550 User %s@%s doesn't have a valid shell for mailing to programs", 68090792Sgshapiro new->q_alias->q_ruser, MyHostName); 68138032Speter } 68290792Sgshapiro else if (bitset(QUNSAFEADDR, new->q_alias->q_flags)) 68338032Speter { 68490792Sgshapiro new->q_state = QS_BADADDR; 68590792Sgshapiro new->q_status = "5.7.1"; 68690792Sgshapiro new->q_rstatus = "550 Unsafe for mailing to programs"; 68790792Sgshapiro usrerrenh(new->q_status, 68864562Sgshapiro "550 Address %s is unsafe for mailing to programs", 68990792Sgshapiro new->q_alias->q_paddr); 69038032Speter } 69138032Speter } 69238032Speter 69338032Speter /* 69438032Speter ** Look up this person in the recipient list. 69538032Speter ** If they are there already, return, otherwise continue. 69638032Speter ** If the list is empty, just add it. Notice the cute 69738032Speter ** hack to make from addresses suppress things correctly: 69864562Sgshapiro ** the QS_DUPLICATE state will be set in the send list. 69938032Speter ** [Please note: the emphasis is on "hack."] 70038032Speter */ 70138032Speter 70290792Sgshapiro prev = NULL; 70390792Sgshapiro 70490792Sgshapiro /* 70590792Sgshapiro ** If this message is going to the queue or FastSplit is set 70690792Sgshapiro ** and it is the first try and the envelope hasn't split, then we 70790792Sgshapiro ** avoid doing an MX RR lookup now because one will be done when the 70890792Sgshapiro ** message is extracted from the queue later. It can go to the queue 70990792Sgshapiro ** because all messages are going to the queue or this mailer of 71090792Sgshapiro ** the current recipient is marked expensive. 71190792Sgshapiro */ 71290792Sgshapiro 713110560Sgshapiro if (UseMSP || WILL_BE_QUEUED(e->e_sendmode) || 71490792Sgshapiro (!bitset(EF_SPLIT, e->e_flags) && e->e_ntries == 0 && 71590792Sgshapiro FastSplit > 0)) 71690792Sgshapiro sortfn = sorthost; 71790792Sgshapiro else if (NoConnect && bitnset(M_EXPENSIVE, new->q_mailer->m_flags)) 71890792Sgshapiro sortfn = sortexpensive; 71990792Sgshapiro else 72090792Sgshapiro sortfn = sortbysignature; 72190792Sgshapiro 72238032Speter for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 72338032Speter { 72490792Sgshapiro /* 72590792Sgshapiro ** If address is "less than" it should be inserted now. 72690792Sgshapiro ** If address is "greater than" current comparison it'll 72790792Sgshapiro ** insert later in the list; so loop again (if possible). 72890792Sgshapiro ** If address is "equal" (different equal than sameaddr() 72990792Sgshapiro ** call) then check if sameaddr() will be true. 73090792Sgshapiro ** Because this list is now sorted, it'll mean fewer 73190792Sgshapiro ** comparisons and fewer loops which is important for more 73290792Sgshapiro ** recipients. 73390792Sgshapiro */ 73490792Sgshapiro 73590792Sgshapiro i = (*sortfn)(new, q); 73690792Sgshapiro if (i == 0) /* equal */ 73738032Speter { 73890792Sgshapiro /* 73990792Sgshapiro ** Sortbysignature() has said that the two have 74090792Sgshapiro ** equal MX RR's and the same user. Calling sameaddr() 74190792Sgshapiro ** now checks if the two hosts are as identical as the 74290792Sgshapiro ** MX RR's are (which might not be the case) 74390792Sgshapiro ** before saying these are the identical addresses. 74490792Sgshapiro */ 74590792Sgshapiro 74690792Sgshapiro if (sameaddr(q, new) && 74790792Sgshapiro (bitset(QRCPTOK, q->q_flags) || 74890792Sgshapiro !bitset(QPRIMARY, q->q_flags))) 74938032Speter { 75090792Sgshapiro if (tTd(26, 1)) 75190792Sgshapiro { 75290792Sgshapiro sm_dprintf("%s in sendq: ", 75390792Sgshapiro new->q_paddr); 754132943Sgshapiro printaddr(sm_debug_file(), q, false); 75590792Sgshapiro } 75690792Sgshapiro if (!bitset(QPRIMARY, q->q_flags)) 75790792Sgshapiro { 75890792Sgshapiro if (!QS_IS_DEAD(new->q_state)) 75990792Sgshapiro message("duplicate suppressed"); 76090792Sgshapiro else 76190792Sgshapiro q->q_state = QS_DUPLICATE; 76290792Sgshapiro q->q_flags |= new->q_flags; 76390792Sgshapiro } 76490792Sgshapiro else if (bitset(QSELFREF, q->q_flags) 76590792Sgshapiro || q->q_state == QS_REMOVED) 76690792Sgshapiro { 76790792Sgshapiro /* 76890792Sgshapiro ** If an earlier milter removed the 76990792Sgshapiro ** address, a later one can still add 77090792Sgshapiro ** it back. 77190792Sgshapiro */ 77290792Sgshapiro 77390792Sgshapiro q->q_state = new->q_state; 77490792Sgshapiro q->q_flags |= new->q_flags; 77590792Sgshapiro } 77690792Sgshapiro new = q; 77790792Sgshapiro goto done; 77838032Speter } 77938032Speter } 78090792Sgshapiro else if (i < 0) /* less than */ 78190792Sgshapiro { 78290792Sgshapiro insert = true; 78390792Sgshapiro break; 78490792Sgshapiro } 78590792Sgshapiro prev = pq; 78638032Speter } 78738032Speter 78890792Sgshapiro /* pq should point to an address, never NULL */ 78990792Sgshapiro SM_ASSERT(pq != NULL); 79090792Sgshapiro 79138032Speter /* add address on list */ 79290792Sgshapiro if (insert) 79342575Speter { 79490792Sgshapiro /* 79590792Sgshapiro ** insert before 'pq'. Only possible when at least 1 79690792Sgshapiro ** ADDRESS is in the list already. 79790792Sgshapiro */ 79890792Sgshapiro 79990792Sgshapiro new->q_next = *pq; 80090792Sgshapiro if (prev == NULL) 80190792Sgshapiro *sendq = new; /* To be the first ADDRESS */ 80290792Sgshapiro else 80390792Sgshapiro (*prev)->q_next = new; 80442575Speter } 80590792Sgshapiro else 80690792Sgshapiro { 80790792Sgshapiro /* 80890792Sgshapiro ** Place in list at current 'pq' position. Possible 80990792Sgshapiro ** when there are 0 or more ADDRESS's in the list. 81090792Sgshapiro */ 81138032Speter 81290792Sgshapiro new->q_next = NULL; 81390792Sgshapiro *pq = new; 81490792Sgshapiro } 81590792Sgshapiro 81690792Sgshapiro /* added a new address: clear split flag */ 81790792Sgshapiro e->e_flags &= ~EF_SPLIT; 81890792Sgshapiro 81938032Speter /* 82038032Speter ** Alias the name and handle special mailer types. 82138032Speter */ 82238032Speter 82338032Speter trylocaluser: 82438032Speter if (tTd(29, 7)) 82542575Speter { 82690792Sgshapiro sm_dprintf("at trylocaluser: "); 827132943Sgshapiro printaddr(sm_debug_file(), new, false); 82842575Speter } 82938032Speter 83090792Sgshapiro if (!QS_IS_OK(new->q_state)) 83190792Sgshapiro { 83290792Sgshapiro if (QS_IS_UNDELIVERED(new->q_state)) 83390792Sgshapiro e->e_nrcpts++; 83438032Speter goto testselfdestruct; 83590792Sgshapiro } 83638032Speter 83738032Speter if (m == InclMailer) 83838032Speter { 83990792Sgshapiro new->q_state = QS_INCLUDED; 84090792Sgshapiro if (new->q_alias == NULL || UseMSP || 84190792Sgshapiro bitset(EF_UNSAFE, e->e_flags)) 84238032Speter { 84390792Sgshapiro new->q_state = QS_BADADDR; 84490792Sgshapiro new->q_status = "5.7.1"; 84590792Sgshapiro usrerrenh(new->q_status, 84664562Sgshapiro "550 Cannot mail directly to :include:s"); 84738032Speter } 84838032Speter else 84938032Speter { 85038032Speter int ret; 85138032Speter 85290792Sgshapiro message("including file %s", new->q_user); 85390792Sgshapiro ret = include(new->q_user, false, new, 85490792Sgshapiro sendq, aliaslevel, e); 85538032Speter if (transienterror(ret)) 85638032Speter { 85738032Speter if (LogLevel > 2) 85838032Speter sm_syslog(LOG_ERR, e->e_id, 85964562Sgshapiro "include %s: transient error: %s", 86090792Sgshapiro shortenstring(new->q_user, 86190792Sgshapiro MAXSHORTSTR), 86290792Sgshapiro sm_errstring(ret)); 86390792Sgshapiro new->q_state = QS_QUEUEUP; 86464562Sgshapiro usrerr("451 4.2.4 Cannot open %s: %s", 86590792Sgshapiro shortenstring(new->q_user, 86690792Sgshapiro MAXSHORTSTR), 86790792Sgshapiro sm_errstring(ret)); 86838032Speter } 86938032Speter else if (ret != 0) 87038032Speter { 87190792Sgshapiro new->q_state = QS_BADADDR; 87290792Sgshapiro new->q_status = "5.2.4"; 87390792Sgshapiro usrerrenh(new->q_status, 87464562Sgshapiro "550 Cannot open %s: %s", 87590792Sgshapiro shortenstring(new->q_user, 87690792Sgshapiro MAXSHORTSTR), 87790792Sgshapiro sm_errstring(ret)); 87838032Speter } 87938032Speter } 88038032Speter } 88138032Speter else if (m == FileMailer) 88238032Speter { 88390792Sgshapiro /* check if allowed */ 88490792Sgshapiro if (new->q_alias == NULL || UseMSP || 88590792Sgshapiro bitset(EF_UNSAFE, e->e_flags)) 88638032Speter { 88790792Sgshapiro new->q_state = QS_BADADDR; 88890792Sgshapiro new->q_status = "5.7.1"; 88990792Sgshapiro usrerrenh(new->q_status, 89064562Sgshapiro "550 Cannot mail directly to files"); 89138032Speter } 89290792Sgshapiro else if (bitset(QBOGUSSHELL, new->q_alias->q_flags)) 89338032Speter { 89490792Sgshapiro new->q_state = QS_BADADDR; 89590792Sgshapiro new->q_status = "5.7.1"; 89690792Sgshapiro if (new->q_alias->q_ruser == NULL) 89790792Sgshapiro usrerrenh(new->q_status, 898285229Sgshapiro "550 UID %ld is an unknown user: cannot mail to files", 899285229Sgshapiro (long) new->q_alias->q_uid); 90038032Speter else 90190792Sgshapiro usrerrenh(new->q_status, 90264562Sgshapiro "550 User %s@%s doesn't have a valid shell for mailing to files", 90390792Sgshapiro new->q_alias->q_ruser, MyHostName); 90438032Speter } 90590792Sgshapiro else if (bitset(QUNSAFEADDR, new->q_alias->q_flags)) 90638032Speter { 90790792Sgshapiro new->q_state = QS_BADADDR; 90890792Sgshapiro new->q_status = "5.7.1"; 90990792Sgshapiro new->q_rstatus = "550 Unsafe for mailing to files"; 91090792Sgshapiro usrerrenh(new->q_status, 91164562Sgshapiro "550 Address %s is unsafe for mailing to files", 91290792Sgshapiro new->q_alias->q_paddr); 91338032Speter } 91438032Speter } 91538032Speter 91638032Speter /* try aliasing */ 91790792Sgshapiro if (!quoted && QS_IS_OK(new->q_state) && 91838032Speter bitnset(M_ALIASABLE, m->m_flags)) 91990792Sgshapiro alias(new, sendq, aliaslevel, e); 92038032Speter 92164562Sgshapiro#if USERDB 92238032Speter /* if not aliased, look it up in the user database */ 92390792Sgshapiro if (!bitset(QNOTREMOTE, new->q_flags) && 92490792Sgshapiro QS_IS_SENDABLE(new->q_state) && 92538032Speter bitnset(M_CHECKUDB, m->m_flags)) 92638032Speter { 92790792Sgshapiro if (udbexpand(new, sendq, aliaslevel, e) == EX_TEMPFAIL) 92838032Speter { 92990792Sgshapiro new->q_state = QS_QUEUEUP; 93038032Speter if (e->e_message == NULL) 931168515Sgshapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, 932168515Sgshapiro "Deferred: user database error"); 93390792Sgshapiro if (new->q_message == NULL) 93490792Sgshapiro new->q_message = "Deferred: user database error"; 93538032Speter if (LogLevel > 8) 93638032Speter sm_syslog(LOG_INFO, e->e_id, 93764562Sgshapiro "deferred: udbexpand: %s", 93890792Sgshapiro sm_errstring(errno)); 93938032Speter message("queued (user database error): %s", 94090792Sgshapiro sm_errstring(errno)); 94138032Speter e->e_nrcpts++; 94238032Speter goto testselfdestruct; 94338032Speter } 94438032Speter } 94564562Sgshapiro#endif /* USERDB */ 94638032Speter 94738032Speter /* 94838032Speter ** If we have a level two config file, then pass the name through 94938032Speter ** Ruleset 5 before sending it off. Ruleset 5 has the right 95090792Sgshapiro ** to rewrite it to another mailer. This gives us a hook 95138032Speter ** after local aliasing has been done. 95238032Speter */ 95338032Speter 95438032Speter if (tTd(29, 5)) 95538032Speter { 95690792Sgshapiro sm_dprintf("recipient: testing local? cl=%d, rr5=%p\n\t", 957363466Sgshapiro ConfigLevel, (void *)RewriteRules[5]); 958132943Sgshapiro printaddr(sm_debug_file(), new, false); 95938032Speter } 96064562Sgshapiro if (ConfigLevel >= 2 && RewriteRules[5] != NULL && 96164562Sgshapiro bitnset(M_TRYRULESET5, m->m_flags) && 96290792Sgshapiro !bitset(QNOTREMOTE, new->q_flags) && 96390792Sgshapiro QS_IS_OK(new->q_state)) 96438032Speter { 96590792Sgshapiro maplocaluser(new, sendq, aliaslevel + 1, e); 96638032Speter } 96738032Speter 96838032Speter /* 96938032Speter ** If it didn't get rewritten to another mailer, go ahead 97038032Speter ** and deliver it. 97138032Speter */ 97238032Speter 97390792Sgshapiro if (QS_IS_OK(new->q_state) && 97438032Speter bitnset(M_HASPWENT, m->m_flags)) 97538032Speter { 97638032Speter auto bool fuzzy; 97790792Sgshapiro SM_MBDB_T user; 97890792Sgshapiro int status; 97938032Speter 98038032Speter /* warning -- finduser may trash buf */ 98190792Sgshapiro status = finduser(buf, &fuzzy, &user); 98290792Sgshapiro switch (status) 98338032Speter { 98490792Sgshapiro case EX_TEMPFAIL: 98590792Sgshapiro new->q_state = QS_QUEUEUP; 98690792Sgshapiro new->q_status = "4.5.2"; 98790792Sgshapiro giveresponse(EX_TEMPFAIL, new->q_status, m, NULL, 98890792Sgshapiro new->q_alias, (time_t) 0, e, new); 98990792Sgshapiro break; 99090792Sgshapiro default: 99190792Sgshapiro new->q_state = QS_BADADDR; 99290792Sgshapiro new->q_status = "5.1.1"; 99390792Sgshapiro new->q_rstatus = "550 5.1.1 User unknown"; 99490792Sgshapiro giveresponse(EX_NOUSER, new->q_status, m, NULL, 99590792Sgshapiro new->q_alias, (time_t) 0, e, new); 99690792Sgshapiro break; 99790792Sgshapiro case EX_OK: 99838032Speter if (fuzzy) 99938032Speter { 100038032Speter /* name was a fuzzy match */ 100190792Sgshapiro new->q_user = sm_rpool_strdup_x(e->e_rpool, 100290792Sgshapiro user.mbdb_name); 100338032Speter if (findusercount++ > 3) 100438032Speter { 100590792Sgshapiro new->q_state = QS_BADADDR; 100690792Sgshapiro new->q_status = "5.4.6"; 100790792Sgshapiro usrerrenh(new->q_status, 100864562Sgshapiro "554 aliasing/forwarding loop for %s broken", 100990792Sgshapiro user.mbdb_name); 101038032Speter goto done; 101138032Speter } 101238032Speter 101338032Speter /* see if it aliases */ 101490792Sgshapiro (void) sm_strlcpy(buf, user.mbdb_name, buflen); 101538032Speter goto trylocaluser; 101638032Speter } 101790792Sgshapiro if (*user.mbdb_homedir == '\0') 101890792Sgshapiro new->q_home = NULL; 101990792Sgshapiro else if (strcmp(user.mbdb_homedir, "/") == 0) 102090792Sgshapiro new->q_home = ""; 102138032Speter else 102290792Sgshapiro new->q_home = sm_rpool_strdup_x(e->e_rpool, 102390792Sgshapiro user.mbdb_homedir); 102490792Sgshapiro if (user.mbdb_uid != SM_NO_UID) 102538032Speter { 102690792Sgshapiro new->q_uid = user.mbdb_uid; 102790792Sgshapiro new->q_gid = user.mbdb_gid; 102890792Sgshapiro new->q_flags |= QGOODUID; 102938032Speter } 103090792Sgshapiro new->q_ruser = sm_rpool_strdup_x(e->e_rpool, 103190792Sgshapiro user.mbdb_name); 103290792Sgshapiro if (user.mbdb_fullname[0] != '\0') 103390792Sgshapiro new->q_fullname = sm_rpool_strdup_x(e->e_rpool, 103490792Sgshapiro user.mbdb_fullname); 103590792Sgshapiro if (!usershellok(user.mbdb_name, user.mbdb_shell)) 103690792Sgshapiro { 103790792Sgshapiro new->q_flags |= QBOGUSSHELL; 103890792Sgshapiro } 103938032Speter if (bitset(EF_VRFYONLY, e->e_flags)) 104038032Speter { 104138032Speter /* don't do any more now */ 104290792Sgshapiro new->q_state = QS_VERIFIED; 104338032Speter } 104438032Speter else if (!quoted) 104590792Sgshapiro forward(new, sendq, aliaslevel, e); 104638032Speter } 104738032Speter } 104890792Sgshapiro if (!QS_IS_DEAD(new->q_state)) 104938032Speter e->e_nrcpts++; 105038032Speter 105138032Speter testselfdestruct: 105290792Sgshapiro new->q_flags |= QTHISPASS; 105338032Speter if (tTd(26, 8)) 105438032Speter { 105590792Sgshapiro sm_dprintf("testselfdestruct: "); 1056132943Sgshapiro printaddr(sm_debug_file(), new, false); 105738032Speter if (tTd(26, 10)) 105838032Speter { 105990792Sgshapiro sm_dprintf("SENDQ:\n"); 1060132943Sgshapiro printaddr(sm_debug_file(), *sendq, true); 106190792Sgshapiro sm_dprintf("----\n"); 106238032Speter } 106338032Speter } 106490792Sgshapiro if (new->q_alias == NULL && new != &e->e_from && 106590792Sgshapiro QS_IS_DEAD(new->q_state)) 106638032Speter { 106738032Speter for (q = *sendq; q != NULL; q = q->q_next) 106838032Speter { 106964562Sgshapiro if (!QS_IS_DEAD(q->q_state)) 107038032Speter break; 107138032Speter } 107238032Speter if (q == NULL) 107338032Speter { 107490792Sgshapiro new->q_state = QS_BADADDR; 107590792Sgshapiro new->q_status = "5.4.6"; 107690792Sgshapiro usrerrenh(new->q_status, 107764562Sgshapiro "554 aliasing/forwarding loop broken"); 107838032Speter } 107938032Speter } 108038032Speter 108138032Speter done: 108290792Sgshapiro new->q_flags |= QTHISPASS; 108338032Speter if (buf != buf0) 108490792Sgshapiro sm_free(buf); /* XXX leak if above code raises exception */ 108538032Speter 108638032Speter /* 108738032Speter ** If we are at the top level, check to see if this has 108838032Speter ** expanded to exactly one address. If so, it can inherit 108938032Speter ** the primaryness of the address. 109038032Speter ** 109138032Speter ** While we're at it, clear the QTHISPASS bits. 109238032Speter */ 109338032Speter 109438032Speter if (aliaslevel == 0) 109538032Speter { 109638032Speter int nrcpts = 0; 109738032Speter ADDRESS *only = NULL; 109838032Speter 109938032Speter for (q = *sendq; q != NULL; q = q->q_next) 110038032Speter { 110138032Speter if (bitset(QTHISPASS, q->q_flags) && 110264562Sgshapiro QS_IS_SENDABLE(q->q_state)) 110338032Speter { 110438032Speter nrcpts++; 110538032Speter only = q; 110638032Speter } 110738032Speter q->q_flags &= ~QTHISPASS; 110838032Speter } 110938032Speter if (nrcpts == 1) 111038032Speter { 111138032Speter /* check to see if this actually got a new owner */ 111238032Speter q = only; 111338032Speter while ((q = q->q_alias) != NULL) 111438032Speter { 111538032Speter if (q->q_owner != NULL) 111638032Speter break; 111738032Speter } 111838032Speter if (q == NULL) 111938032Speter only->q_flags |= QPRIMARY; 112038032Speter } 112138032Speter else if (!initialdontsend && nrcpts > 0) 112238032Speter { 112338032Speter /* arrange for return receipt */ 112438032Speter e->e_flags |= EF_SENDRECEIPT; 112590792Sgshapiro new->q_flags |= QEXPANDED; 112664562Sgshapiro if (e->e_xfp != NULL && 112790792Sgshapiro bitset(QPINGONSUCCESS, new->q_flags)) 112890792Sgshapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 112990792Sgshapiro "%s... expanded to multiple addresses\n", 113090792Sgshapiro new->q_paddr); 113138032Speter } 113238032Speter } 113390792Sgshapiro new->q_flags |= QRCPTOK; 1134168515Sgshapiro (void) sm_snprintf(buf0, sizeof(buf0), "%d", e->e_nrcpts); 113590792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{nrcpts}"), buf0); 113690792Sgshapiro return new; 113738032Speter} 1138168515Sgshapiro 113990792Sgshapiro/* 114038032Speter** FINDUSER -- find the password entry for a user. 114138032Speter** 114238032Speter** This looks a lot like getpwnam, except that it may want to 114338032Speter** do some fancier pattern matching in /etc/passwd. 114438032Speter** 114538032Speter** This routine contains most of the time of many sendmail runs. 114638032Speter** It deserves to be optimized. 114738032Speter** 114838032Speter** Parameters: 114938032Speter** name -- the name to match against. 115090792Sgshapiro** fuzzyp -- an outarg that is set to true if this entry 115138032Speter** was found using the fuzzy matching algorithm; 115290792Sgshapiro** set to false otherwise. 115390792Sgshapiro** user -- structure to fill in if user is found 115438032Speter** 115538032Speter** Returns: 115690792Sgshapiro** On success, fill in *user, set *fuzzyp and return EX_OK. 115790792Sgshapiro** If the user was not found, return EX_NOUSER. 115890792Sgshapiro** On error, return EX_TEMPFAIL or EX_OSERR. 115938032Speter** 116038032Speter** Side Effects: 116138032Speter** may modify name. 116238032Speter*/ 116338032Speter 116490792Sgshapiroint 116590792Sgshapirofinduser(name, fuzzyp, user) 116638032Speter char *name; 116738032Speter bool *fuzzyp; 116890792Sgshapiro SM_MBDB_T *user; 116938032Speter{ 117090792Sgshapiro#if MATCHGECOS 117138032Speter register struct passwd *pw; 1172363466Sgshapiro#endif 117338032Speter register char *p; 117438032Speter bool tryagain; 117590792Sgshapiro int status; 117638032Speter 117738032Speter if (tTd(29, 4)) 117890792Sgshapiro sm_dprintf("finduser(%s): ", name); 117938032Speter 118090792Sgshapiro *fuzzyp = false; 118138032Speter 1182285229Sgshapiro#if HESIOD && !HESIOD_ALLOW_NUMERIC_LOGIN 118338032Speter /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 118438032Speter for (p = name; *p != '\0'; p++) 118538032Speter if (!isascii(*p) || !isdigit(*p)) 118638032Speter break; 118738032Speter if (*p == '\0') 118838032Speter { 118938032Speter if (tTd(29, 4)) 119090792Sgshapiro sm_dprintf("failed (numeric input)\n"); 119190792Sgshapiro return EX_NOUSER; 119238032Speter } 1193285229Sgshapiro#endif /* HESIOD && !HESIOD_ALLOW_NUMERIC_LOGIN */ 119438032Speter 119538032Speter /* look up this login name using fast path */ 119690792Sgshapiro status = sm_mbdb_lookup(name, user); 119790792Sgshapiro if (status != EX_NOUSER) 119838032Speter { 119938032Speter if (tTd(29, 4)) 120090792Sgshapiro sm_dprintf("%s (non-fuzzy)\n", sm_strexit(status)); 120190792Sgshapiro return status; 120238032Speter } 120338032Speter 120438032Speter /* try mapping it to lower case */ 120590792Sgshapiro tryagain = false; 120638032Speter for (p = name; *p != '\0'; p++) 120738032Speter { 120838032Speter if (isascii(*p) && isupper(*p)) 120938032Speter { 121038032Speter *p = tolower(*p); 121190792Sgshapiro tryagain = true; 121238032Speter } 121338032Speter } 121490792Sgshapiro if (tryagain && (status = sm_mbdb_lookup(name, user)) != EX_NOUSER) 121538032Speter { 121638032Speter if (tTd(29, 4)) 121790792Sgshapiro sm_dprintf("%s (lower case)\n", sm_strexit(status)); 121890792Sgshapiro *fuzzyp = true; 121990792Sgshapiro return status; 122038032Speter } 122138032Speter 122238032Speter#if MATCHGECOS 122338032Speter /* see if fuzzy matching allowed */ 122438032Speter if (!MatchGecos) 122538032Speter { 122638032Speter if (tTd(29, 4)) 122790792Sgshapiro sm_dprintf("not found (fuzzy disabled)\n"); 122890792Sgshapiro return EX_NOUSER; 122938032Speter } 123038032Speter 123138032Speter /* search for a matching full name instead */ 123238032Speter for (p = name; *p != '\0'; p++) 123338032Speter { 123438032Speter if (*p == (SpaceSub & 0177) || *p == '_') 123538032Speter *p = ' '; 123638032Speter } 123738032Speter (void) setpwent(); 123838032Speter while ((pw = getpwent()) != NULL) 123938032Speter { 124038032Speter char buf[MAXNAME + 1]; 124138032Speter 124238032Speter# if 0 124390792Sgshapiro if (sm_strcasecmp(pw->pw_name, name) == 0) 124438032Speter { 124538032Speter if (tTd(29, 4)) 124690792Sgshapiro sm_dprintf("found (case wrapped)\n"); 124738032Speter break; 124838032Speter } 124964562Sgshapiro# endif /* 0 */ 125038032Speter 1251168515Sgshapiro sm_pwfullname(pw->pw_gecos, pw->pw_name, buf, sizeof(buf)); 125290792Sgshapiro if (strchr(buf, ' ') != NULL && sm_strcasecmp(buf, name) == 0) 125338032Speter { 125438032Speter if (tTd(29, 4)) 125590792Sgshapiro sm_dprintf("fuzzy matches %s\n", pw->pw_name); 125638032Speter message("sending to login name %s", pw->pw_name); 125738032Speter break; 125838032Speter } 125938032Speter } 126038032Speter if (pw != NULL) 126190792Sgshapiro *fuzzyp = true; 126238032Speter else if (tTd(29, 4)) 126390792Sgshapiro sm_dprintf("no fuzzy match found\n"); 126438032Speter# if DEC_OSF_BROKEN_GETPWENT /* DEC OSF/1 3.2 or earlier */ 126538032Speter endpwent(); 1266363466Sgshapiro# endif 126790792Sgshapiro if (pw == NULL) 126890792Sgshapiro return EX_NOUSER; 126990792Sgshapiro sm_mbdb_frompw(user, pw); 127090792Sgshapiro return EX_OK; 127164562Sgshapiro#else /* MATCHGECOS */ 127238032Speter if (tTd(29, 4)) 127390792Sgshapiro sm_dprintf("not found (fuzzy disabled)\n"); 127490792Sgshapiro return EX_NOUSER; 127564562Sgshapiro#endif /* MATCHGECOS */ 127638032Speter} 1277168515Sgshapiro 127890792Sgshapiro/* 127938032Speter** WRITABLE -- predicate returning if the file is writable. 128038032Speter** 128138032Speter** This routine must duplicate the algorithm in sys/fio.c. 128238032Speter** Unfortunately, we cannot use the access call since we 128338032Speter** won't necessarily be the real uid when we try to 128438032Speter** actually open the file. 128538032Speter** 128638032Speter** Notice that ANY file with ANY execute bit is automatically 128738032Speter** not writable. This is also enforced by mailfile. 128838032Speter** 128938032Speter** Parameters: 129038032Speter** filename -- the file name to check. 129138032Speter** ctladdr -- the controlling address for this file. 129238032Speter** flags -- SFF_* flags to control the function. 129338032Speter** 129438032Speter** Returns: 129590792Sgshapiro** true -- if we will be able to write this file. 129690792Sgshapiro** false -- if we cannot write this file. 129738032Speter** 129838032Speter** Side Effects: 129938032Speter** none. 130038032Speter*/ 130138032Speter 130238032Speterbool 130338032Speterwritable(filename, ctladdr, flags) 130438032Speter char *filename; 130538032Speter ADDRESS *ctladdr; 130664562Sgshapiro long flags; 130738032Speter{ 130864562Sgshapiro uid_t euid = 0; 130964562Sgshapiro gid_t egid = 0; 131064562Sgshapiro char *user = NULL; 131138032Speter 131238032Speter if (tTd(44, 5)) 131390792Sgshapiro sm_dprintf("writable(%s, 0x%lx)\n", filename, flags); 131438032Speter 131538032Speter /* 131638032Speter ** File does exist -- check that it is writable. 131738032Speter */ 131838032Speter 131938032Speter if (geteuid() != 0) 132038032Speter { 132138032Speter euid = geteuid(); 132238032Speter egid = getegid(); 132364562Sgshapiro user = NULL; 132438032Speter } 132538032Speter else if (ctladdr != NULL) 132638032Speter { 132738032Speter euid = ctladdr->q_uid; 132838032Speter egid = ctladdr->q_gid; 132964562Sgshapiro user = ctladdr->q_user; 133038032Speter } 133138032Speter else if (bitset(SFF_RUNASREALUID, flags)) 133238032Speter { 133338032Speter euid = RealUid; 133438032Speter egid = RealGid; 133564562Sgshapiro user = RealUserName; 133638032Speter } 133738032Speter else if (FileMailer != NULL && !bitset(SFF_ROOTOK, flags)) 133838032Speter { 1339132943Sgshapiro if (FileMailer->m_uid == NO_UID) 1340132943Sgshapiro { 1341132943Sgshapiro euid = DefUid; 1342132943Sgshapiro user = DefUser; 1343132943Sgshapiro } 1344132943Sgshapiro else 1345132943Sgshapiro { 1346132943Sgshapiro euid = FileMailer->m_uid; 1347132943Sgshapiro user = NULL; 1348132943Sgshapiro } 1349132943Sgshapiro if (FileMailer->m_gid == NO_GID) 1350132943Sgshapiro egid = DefGid; 1351132943Sgshapiro else 1352132943Sgshapiro egid = FileMailer->m_gid; 135338032Speter } 135438032Speter else 135538032Speter { 135638032Speter euid = egid = 0; 135764562Sgshapiro user = NULL; 135838032Speter } 135938032Speter if (!bitset(SFF_ROOTOK, flags)) 136038032Speter { 136138032Speter if (euid == 0) 136238032Speter { 136338032Speter euid = DefUid; 136464562Sgshapiro user = DefUser; 136538032Speter } 136638032Speter if (egid == 0) 136738032Speter egid = DefGid; 136838032Speter } 136938032Speter if (geteuid() == 0 && 137038032Speter (ctladdr == NULL || !bitset(QGOODUID, ctladdr->q_flags))) 137138032Speter flags |= SFF_SETUIDOK; 137238032Speter 137364562Sgshapiro if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 137438032Speter flags |= SFF_NOSLINK; 137564562Sgshapiro if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) 137638032Speter flags |= SFF_NOHLINK; 137738032Speter 137864562Sgshapiro errno = safefile(filename, euid, egid, user, flags, S_IWRITE, NULL); 137938032Speter return errno == 0; 138038032Speter} 1381168515Sgshapiro 138290792Sgshapiro/* 138338032Speter** INCLUDE -- handle :include: specification. 138438032Speter** 138538032Speter** Parameters: 138638032Speter** fname -- filename to include. 138790792Sgshapiro** forwarding -- if true, we are reading a .forward file. 138890792Sgshapiro** if false, it's a :include: file. 138938032Speter** ctladdr -- address template to use to fill in these 139038032Speter** addresses -- effective user/group id are 139138032Speter** the important things. 139238032Speter** sendq -- a pointer to the head of the send queue 139338032Speter** to put these addresses in. 139438032Speter** aliaslevel -- the alias nesting depth. 139538032Speter** e -- the current envelope. 139638032Speter** 139738032Speter** Returns: 139838032Speter** open error status 139938032Speter** 140038032Speter** Side Effects: 140138032Speter** reads the :include: file and sends to everyone 140238032Speter** listed in that file. 140338032Speter** 140438032Speter** Security Note: 140538032Speter** If you have restricted chown (that is, you can't 140638032Speter** give a file away), it is reasonable to allow programs 140738032Speter** and files called from this :include: file to be to be 140838032Speter** run as the owner of the :include: file. This is bogus 140938032Speter** if there is any chance of someone giving away a file. 141038032Speter** We assume that pre-POSIX systems can give away files. 141138032Speter** 141238032Speter** There is an additional restriction that if you 141338032Speter** forward to a :include: file, it will not take on 141438032Speter** the ownership of the :include: file. This may not 141538032Speter** be necessary, but shouldn't hurt. 141638032Speter*/ 141738032Speter 141838032Speterstatic jmp_buf CtxIncludeTimeout; 141938032Speter 142038032Speterint 142138032Speterinclude(fname, forwarding, ctladdr, sendq, aliaslevel, e) 142238032Speter char *fname; 142338032Speter bool forwarding; 142438032Speter ADDRESS *ctladdr; 142538032Speter ADDRESS **sendq; 142638032Speter int aliaslevel; 142738032Speter ENVELOPE *e; 142838032Speter{ 142990792Sgshapiro SM_FILE_T *volatile fp = NULL; 143038032Speter char *oldto = e->e_to; 143138032Speter char *oldfilename = FileName; 143238032Speter int oldlinenumber = LineNumber; 143390792Sgshapiro register SM_EVENT *ev = NULL; 143438032Speter int nincludes; 143538032Speter int mode; 143690792Sgshapiro volatile bool maxreached = false; 143738032Speter register ADDRESS *ca; 143864562Sgshapiro volatile uid_t saveduid; 143964562Sgshapiro volatile gid_t savedgid; 144064562Sgshapiro volatile uid_t uid; 144164562Sgshapiro volatile gid_t gid; 144264562Sgshapiro char *volatile user; 144338032Speter int rval = 0; 144464562Sgshapiro volatile long sfflags = SFF_REGONLY; 144538032Speter register char *p; 144690792Sgshapiro bool safechown = false; 144790792Sgshapiro volatile bool safedir = false; 144838032Speter struct stat st; 144938032Speter char buf[MAXLINE]; 145038032Speter 145138032Speter if (tTd(27, 2)) 145290792Sgshapiro sm_dprintf("include(%s)\n", fname); 145338032Speter if (tTd(27, 4)) 1454285229Sgshapiro sm_dprintf(" ruid=%ld euid=%ld\n", 1455285229Sgshapiro (long) getuid(), (long) geteuid()); 145638032Speter if (tTd(27, 14)) 145738032Speter { 145890792Sgshapiro sm_dprintf("ctladdr "); 1459132943Sgshapiro printaddr(sm_debug_file(), ctladdr, false); 146038032Speter } 146138032Speter 146238032Speter if (tTd(27, 9)) 1463285229Sgshapiro sm_dprintf("include: old uid = %ld/%ld\n", 1464285229Sgshapiro (long) getuid(), (long) geteuid()); 146538032Speter 146638032Speter if (forwarding) 146766494Sgshapiro { 146898121Sgshapiro sfflags |= SFF_MUSTOWN|SFF_ROOTOK; 146966494Sgshapiro if (!bitnset(DBS_GROUPWRITABLEFORWARDFILE, DontBlameSendmail)) 147066494Sgshapiro sfflags |= SFF_NOGWFILES; 147166494Sgshapiro if (!bitnset(DBS_WORLDWRITABLEFORWARDFILE, DontBlameSendmail)) 147266494Sgshapiro sfflags |= SFF_NOWWFILES; 147366494Sgshapiro } 147466494Sgshapiro else 147566494Sgshapiro { 147666494Sgshapiro if (!bitnset(DBS_GROUPWRITABLEINCLUDEFILE, DontBlameSendmail)) 147766494Sgshapiro sfflags |= SFF_NOGWFILES; 147866494Sgshapiro if (!bitnset(DBS_WORLDWRITABLEINCLUDEFILE, DontBlameSendmail)) 147966494Sgshapiro sfflags |= SFF_NOWWFILES; 148066494Sgshapiro } 148166494Sgshapiro 148264562Sgshapiro /* 148364562Sgshapiro ** If RunAsUser set, won't be able to run programs as user 148464562Sgshapiro ** so mark them as unsafe unless the administrator knows better. 148564562Sgshapiro */ 148664562Sgshapiro 148764562Sgshapiro if ((geteuid() != 0 || RunAsUid != 0) && 148864562Sgshapiro !bitnset(DBS_NONROOTSAFEADDR, DontBlameSendmail)) 148964562Sgshapiro { 149064562Sgshapiro if (tTd(27, 4)) 1491285229Sgshapiro sm_dprintf("include: not safe (euid=%ld, RunAsUid=%ld)\n", 1492285229Sgshapiro (long) geteuid(), (long) RunAsUid); 149364562Sgshapiro ctladdr->q_flags |= QUNSAFEADDR; 149464562Sgshapiro } 149564562Sgshapiro 149638032Speter ca = getctladdr(ctladdr); 149764562Sgshapiro if (ca == NULL || 149864562Sgshapiro (ca->q_uid == DefUid && ca->q_gid == 0)) 149938032Speter { 150038032Speter uid = DefUid; 150138032Speter gid = DefGid; 150264562Sgshapiro user = DefUser; 150338032Speter } 150438032Speter else 150538032Speter { 150638032Speter uid = ca->q_uid; 150738032Speter gid = ca->q_gid; 150864562Sgshapiro user = ca->q_user; 150938032Speter } 151064562Sgshapiro#if MAILER_SETUID_METHOD != USE_SETUID 151138032Speter saveduid = geteuid(); 151238032Speter savedgid = getegid(); 151338032Speter if (saveduid == 0) 151438032Speter { 151538032Speter if (!DontInitGroups) 151638032Speter { 151764562Sgshapiro if (initgroups(user, gid) == -1) 151864562Sgshapiro { 151964562Sgshapiro rval = EAGAIN; 1520285229Sgshapiro syserr("include: initgroups(%s, %ld) failed", 1521285229Sgshapiro user, (long) gid); 152264562Sgshapiro goto resetuid; 152364562Sgshapiro } 152438032Speter } 152538032Speter else 152638032Speter { 152738032Speter GIDSET_T gidset[1]; 152838032Speter 152938032Speter gidset[0] = gid; 153038032Speter if (setgroups(1, gidset) == -1) 153164562Sgshapiro { 153264562Sgshapiro rval = EAGAIN; 153338032Speter syserr("include: setgroups() failed"); 153464562Sgshapiro goto resetuid; 153564562Sgshapiro } 153638032Speter } 153738032Speter 153838032Speter if (gid != 0 && setgid(gid) < -1) 153964562Sgshapiro { 154064562Sgshapiro rval = EAGAIN; 1541285229Sgshapiro syserr("setgid(%ld) failure", (long) gid); 154264562Sgshapiro goto resetuid; 154364562Sgshapiro } 154438032Speter if (uid != 0) 154538032Speter { 154664562Sgshapiro# if MAILER_SETUID_METHOD == USE_SETEUID 154738032Speter if (seteuid(uid) < 0) 154864562Sgshapiro { 154964562Sgshapiro rval = EAGAIN; 1550285229Sgshapiro syserr("seteuid(%ld) failure (real=%ld, eff=%ld)", 1551285229Sgshapiro (long) uid, (long) getuid(), (long) geteuid()); 155264562Sgshapiro goto resetuid; 155364562Sgshapiro } 155464562Sgshapiro# endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 155564562Sgshapiro# if MAILER_SETUID_METHOD == USE_SETREUID 155638032Speter if (setreuid(0, uid) < 0) 155764562Sgshapiro { 155864562Sgshapiro rval = EAGAIN; 1559285229Sgshapiro syserr("setreuid(0, %ld) failure (real=%ld, eff=%ld)", 1560285229Sgshapiro (long) uid, (long) getuid(), (long) geteuid()); 156164562Sgshapiro goto resetuid; 156264562Sgshapiro } 156364562Sgshapiro# endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 156438032Speter } 156538032Speter } 156664562Sgshapiro#endif /* MAILER_SETUID_METHOD != USE_SETUID */ 156738032Speter 156838032Speter if (tTd(27, 9)) 1569285229Sgshapiro sm_dprintf("include: new uid = %ld/%ld\n", 1570285229Sgshapiro (long) getuid(), (long) geteuid()); 157138032Speter 157238032Speter /* 157338032Speter ** If home directory is remote mounted but server is down, 157438032Speter ** this can hang or give errors; use a timeout to avoid this 157538032Speter */ 157638032Speter 157738032Speter if (setjmp(CtxIncludeTimeout) != 0) 157838032Speter { 157964562Sgshapiro ctladdr->q_state = QS_QUEUEUP; 158038032Speter errno = 0; 158138032Speter 158238032Speter /* return pseudo-error code */ 158338032Speter rval = E_SM_OPENTIMEOUT; 158438032Speter goto resetuid; 158538032Speter } 158638032Speter if (TimeOuts.to_fileopen > 0) 158790792Sgshapiro ev = sm_setevent(TimeOuts.to_fileopen, includetimeout, 0); 158838032Speter else 158938032Speter ev = NULL; 159038032Speter 159164562Sgshapiro 159238032Speter /* check for writable parent directory */ 159338032Speter p = strrchr(fname, '/'); 159438032Speter if (p != NULL) 159538032Speter { 159638032Speter int ret; 159738032Speter 159838032Speter *p = '\0'; 159964562Sgshapiro ret = safedirpath(fname, uid, gid, user, 160064562Sgshapiro sfflags|SFF_SAFEDIRPATH, 0, 0); 160138032Speter if (ret == 0) 160238032Speter { 160338032Speter /* in safe directory: relax chown & link rules */ 160490792Sgshapiro safedir = true; 160538032Speter sfflags |= SFF_NOPATHCHECK; 160638032Speter } 160738032Speter else 160838032Speter { 160964562Sgshapiro if (bitnset((forwarding ? 161064562Sgshapiro DBS_FORWARDFILEINUNSAFEDIRPATH : 161164562Sgshapiro DBS_INCLUDEFILEINUNSAFEDIRPATH), 161264562Sgshapiro DontBlameSendmail)) 161338032Speter sfflags |= SFF_NOPATHCHECK; 161464562Sgshapiro else if (bitnset((forwarding ? 161564562Sgshapiro DBS_FORWARDFILEINGROUPWRITABLEDIRPATH : 161664562Sgshapiro DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH), 161764562Sgshapiro DontBlameSendmail) && 161838032Speter ret == E_SM_GWDIR) 161938032Speter { 162064562Sgshapiro setbitn(DBS_GROUPWRITABLEDIRPATHSAFE, 162164562Sgshapiro DontBlameSendmail); 162264562Sgshapiro ret = safedirpath(fname, uid, gid, user, 162364562Sgshapiro sfflags|SFF_SAFEDIRPATH, 162464562Sgshapiro 0, 0); 162564562Sgshapiro clrbitn(DBS_GROUPWRITABLEDIRPATHSAFE, 162664562Sgshapiro DontBlameSendmail); 162738032Speter if (ret == 0) 162838032Speter sfflags |= SFF_NOPATHCHECK; 162938032Speter else 163038032Speter sfflags |= SFF_SAFEDIRPATH; 163138032Speter } 163238032Speter else 163338032Speter sfflags |= SFF_SAFEDIRPATH; 163438032Speter if (ret > E_PSEUDOBASE && 163564562Sgshapiro !bitnset((forwarding ? 163664562Sgshapiro DBS_FORWARDFILEINUNSAFEDIRPATHSAFE : 163764562Sgshapiro DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE), 163864562Sgshapiro DontBlameSendmail)) 163938032Speter { 164090792Sgshapiro if (LogLevel > 11) 164138032Speter sm_syslog(LOG_INFO, e->e_id, 164238032Speter "%s: unsafe directory path, marked unsafe", 164338032Speter shortenstring(fname, MAXSHORTSTR)); 164438032Speter ctladdr->q_flags |= QUNSAFEADDR; 164538032Speter } 164638032Speter } 164738032Speter *p = '/'; 164838032Speter } 164938032Speter 165038032Speter /* allow links only in unwritable directories */ 165138032Speter if (!safedir && 165264562Sgshapiro !bitnset((forwarding ? 165364562Sgshapiro DBS_LINKEDFORWARDFILEINWRITABLEDIR : 165464562Sgshapiro DBS_LINKEDINCLUDEFILEINWRITABLEDIR), 165564562Sgshapiro DontBlameSendmail)) 165638032Speter sfflags |= SFF_NOLINK; 165738032Speter 165864562Sgshapiro rval = safefile(fname, uid, gid, user, sfflags, S_IREAD, &st); 165938032Speter if (rval != 0) 166038032Speter { 166138032Speter /* don't use this :include: file */ 166238032Speter if (tTd(27, 4)) 1663285229Sgshapiro sm_dprintf("include: not safe (uid=%ld): %s\n", 1664285229Sgshapiro (long) uid, sm_errstring(rval)); 166538032Speter } 166690792Sgshapiro else if ((fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, fname, 166790792Sgshapiro SM_IO_RDONLY, NULL)) == NULL) 166838032Speter { 166938032Speter rval = errno; 167038032Speter if (tTd(27, 4)) 167190792Sgshapiro sm_dprintf("include: open: %s\n", sm_errstring(rval)); 167238032Speter } 167390792Sgshapiro else if (filechanged(fname, sm_io_getinfo(fp,SM_IO_WHAT_FD, NULL), &st)) 167438032Speter { 167538032Speter rval = E_SM_FILECHANGE; 167638032Speter if (tTd(27, 4)) 167790792Sgshapiro sm_dprintf("include: file changed after open\n"); 167838032Speter } 167938032Speter if (ev != NULL) 168090792Sgshapiro sm_clrevent(ev); 168138032Speter 168238032Speterresetuid: 168338032Speter 168438032Speter#if HASSETREUID || USESETEUID 168538032Speter if (saveduid == 0) 168638032Speter { 168738032Speter if (uid != 0) 168838032Speter { 168938032Speter# if USESETEUID 169038032Speter if (seteuid(0) < 0) 1691285229Sgshapiro syserr("!seteuid(0) failure (real=%ld, eff=%ld)", 1692285229Sgshapiro (long) getuid(), (long) geteuid()); 169364562Sgshapiro# else /* USESETEUID */ 169438032Speter if (setreuid(-1, 0) < 0) 1695285229Sgshapiro syserr("!setreuid(-1, 0) failure (real=%ld, eff=%ld)", 1696285229Sgshapiro (long) getuid(), (long) geteuid()); 169738032Speter if (setreuid(RealUid, 0) < 0) 1698285229Sgshapiro syserr("!setreuid(%ld, 0) failure (real=%ld, eff=%ld)", 1699285229Sgshapiro (long) RealUid, (long) getuid(), 1700285229Sgshapiro (long) geteuid()); 170164562Sgshapiro# endif /* USESETEUID */ 170238032Speter } 170364562Sgshapiro if (setgid(savedgid) < 0) 1704285229Sgshapiro syserr("!setgid(%ld) failure (real=%ld eff=%ld)", 1705285229Sgshapiro (long) savedgid, (long) getgid(), 1706285229Sgshapiro (long) getegid()); 170738032Speter } 170864562Sgshapiro#endif /* HASSETREUID || USESETEUID */ 170938032Speter 171038032Speter if (tTd(27, 9)) 1711285229Sgshapiro sm_dprintf("include: reset uid = %ld/%ld\n", 1712285229Sgshapiro (long) getuid(), (long) geteuid()); 171338032Speter 171438032Speter if (rval == E_SM_OPENTIMEOUT) 171564562Sgshapiro usrerr("451 4.4.1 open timeout on %s", fname); 171638032Speter 171738032Speter if (fp == NULL) 171838032Speter return rval; 171938032Speter 172090792Sgshapiro if (fstat(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), &st) < 0) 172138032Speter { 172238032Speter rval = errno; 172338032Speter syserr("Cannot fstat %s!", fname); 172490792Sgshapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 172538032Speter return rval; 172638032Speter } 172738032Speter 172838032Speter /* if path was writable, check to avoid file giveaway tricks */ 172990792Sgshapiro safechown = chownsafe(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), safedir); 173038032Speter if (tTd(27, 6)) 173190792Sgshapiro sm_dprintf("include: parent of %s is %s, chown is %ssafe\n", 173290792Sgshapiro fname, safedir ? "safe" : "dangerous", 173390792Sgshapiro safechown ? "" : "un"); 173438032Speter 173564562Sgshapiro /* if no controlling user or coming from an alias delivery */ 173664562Sgshapiro if (safechown && 173764562Sgshapiro (ca == NULL || 173864562Sgshapiro (ca->q_uid == DefUid && ca->q_gid == 0))) 173938032Speter { 174038032Speter ctladdr->q_uid = st.st_uid; 174138032Speter ctladdr->q_gid = st.st_gid; 174238032Speter ctladdr->q_flags |= QGOODUID; 174338032Speter } 174438032Speter if (ca != NULL && ca->q_uid == st.st_uid) 174538032Speter { 174638032Speter /* optimization -- avoid getpwuid if we already have info */ 174738032Speter ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 174838032Speter ctladdr->q_ruser = ca->q_ruser; 174938032Speter } 175038032Speter else if (!forwarding) 175138032Speter { 175238032Speter register struct passwd *pw; 175338032Speter 175438032Speter pw = sm_getpwuid(st.st_uid); 175538032Speter if (pw == NULL) 175664562Sgshapiro { 175764562Sgshapiro ctladdr->q_uid = st.st_uid; 175838032Speter ctladdr->q_flags |= QBOGUSSHELL; 175964562Sgshapiro } 176038032Speter else 176138032Speter { 176238032Speter char *sh; 176338032Speter 176490792Sgshapiro ctladdr->q_ruser = sm_rpool_strdup_x(e->e_rpool, 176590792Sgshapiro pw->pw_name); 176638032Speter if (safechown) 176738032Speter sh = pw->pw_shell; 176838032Speter else 176938032Speter sh = "/SENDMAIL/ANY/SHELL/"; 177038032Speter if (!usershellok(pw->pw_name, sh)) 177138032Speter { 177290792Sgshapiro if (LogLevel > 11) 177338032Speter sm_syslog(LOG_INFO, e->e_id, 177464562Sgshapiro "%s: user %s has bad shell %s, marked %s", 177590792Sgshapiro shortenstring(fname, 177690792Sgshapiro MAXSHORTSTR), 177764562Sgshapiro pw->pw_name, sh, 177864562Sgshapiro safechown ? "bogus" : "unsafe"); 177938032Speter if (safechown) 178038032Speter ctladdr->q_flags |= QBOGUSSHELL; 178138032Speter else 178238032Speter ctladdr->q_flags |= QUNSAFEADDR; 178338032Speter } 178438032Speter } 178538032Speter } 178638032Speter 178738032Speter if (bitset(EF_VRFYONLY, e->e_flags)) 178838032Speter { 178938032Speter /* don't do any more now */ 179064562Sgshapiro ctladdr->q_state = QS_VERIFIED; 179138032Speter e->e_nrcpts++; 179290792Sgshapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 179338032Speter return rval; 179438032Speter } 179538032Speter 179638032Speter /* 179742575Speter ** Check to see if some bad guy can write this file 179838032Speter ** 179938032Speter ** Group write checking could be more clever, e.g., 180038032Speter ** guessing as to which groups are actually safe ("sys" 180138032Speter ** may be; "user" probably is not). 180238032Speter */ 180338032Speter 180438032Speter mode = S_IWOTH; 180564562Sgshapiro if (!bitnset((forwarding ? 180664562Sgshapiro DBS_GROUPWRITABLEFORWARDFILESAFE : 180764562Sgshapiro DBS_GROUPWRITABLEINCLUDEFILESAFE), 180864562Sgshapiro DontBlameSendmail)) 180938032Speter mode |= S_IWGRP; 181038032Speter 181138032Speter if (bitset(mode, st.st_mode)) 181238032Speter { 181338032Speter if (tTd(27, 6)) 181490792Sgshapiro sm_dprintf("include: %s is %s writable, marked unsafe\n", 181590792Sgshapiro shortenstring(fname, MAXSHORTSTR), 181690792Sgshapiro bitset(S_IWOTH, st.st_mode) ? "world" 181790792Sgshapiro : "group"); 181890792Sgshapiro if (LogLevel > 11) 181938032Speter sm_syslog(LOG_INFO, e->e_id, 182064562Sgshapiro "%s: %s writable %s file, marked unsafe", 182164562Sgshapiro shortenstring(fname, MAXSHORTSTR), 182264562Sgshapiro bitset(S_IWOTH, st.st_mode) ? "world" : "group", 182364562Sgshapiro forwarding ? "forward" : ":include:"); 182438032Speter ctladdr->q_flags |= QUNSAFEADDR; 182538032Speter } 182638032Speter 182738032Speter /* read the file -- each line is a comma-separated list. */ 182838032Speter FileName = fname; 182938032Speter LineNumber = 0; 183038032Speter ctladdr->q_flags &= ~QSELFREF; 183138032Speter nincludes = 0; 1832249729Sgshapiro while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0 && 183390792Sgshapiro !maxreached) 183438032Speter { 183590792Sgshapiro fixcrlf(buf, true); 183638032Speter LineNumber++; 183738032Speter if (buf[0] == '#' || buf[0] == '\0') 183838032Speter continue; 183938032Speter 184038032Speter /* <sp>#@# introduces a comment anywhere */ 184138032Speter /* for Japanese character sets */ 184238032Speter for (p = buf; (p = strchr(++p, '#')) != NULL; ) 184338032Speter { 184438032Speter if (p[1] == '@' && p[2] == '#' && 184538032Speter isascii(p[-1]) && isspace(p[-1]) && 1846363466Sgshapiro (p[3] == '\0' || (SM_ISSPACE(p[3])))) 184738032Speter { 184866494Sgshapiro --p; 184966494Sgshapiro while (p > buf && isascii(p[-1]) && 185066494Sgshapiro isspace(p[-1])) 185166494Sgshapiro --p; 185266494Sgshapiro p[0] = '\0'; 185338032Speter break; 185438032Speter } 185538032Speter } 185638032Speter if (buf[0] == '\0') 185738032Speter continue; 185838032Speter 185938032Speter e->e_to = NULL; 186038032Speter message("%s to %s", 186138032Speter forwarding ? "forwarding" : "sending", buf); 186264562Sgshapiro if (forwarding && LogLevel > 10) 186338032Speter sm_syslog(LOG_INFO, e->e_id, 186464562Sgshapiro "forward %.200s => %s", 186564562Sgshapiro oldto, shortenstring(buf, MAXSHORTSTR)); 186638032Speter 186738032Speter nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); 186864562Sgshapiro 186964562Sgshapiro if (forwarding && 187064562Sgshapiro MaxForwardEntries > 0 && 187164562Sgshapiro nincludes >= MaxForwardEntries) 187264562Sgshapiro { 187364562Sgshapiro /* just stop reading and processing further entries */ 187490792Sgshapiro#if 0 187590792Sgshapiro /* additional: (?) */ 187664562Sgshapiro ctladdr->q_state = QS_DONTSEND; 187790792Sgshapiro#endif /* 0 */ 187890792Sgshapiro 187990792Sgshapiro syserr("Attempt to forward to more than %d addresses (in %s)!", 188098121Sgshapiro MaxForwardEntries, fname); 188190792Sgshapiro maxreached = true; 188264562Sgshapiro } 188338032Speter } 188438032Speter 188590792Sgshapiro if (sm_io_error(fp) && tTd(27, 3)) 188690792Sgshapiro sm_dprintf("include: read error: %s\n", sm_errstring(errno)); 188738032Speter if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 188838032Speter { 1889168515Sgshapiro if (aliaslevel <= MaxAliasRecursion || 1890168515Sgshapiro ctladdr->q_state != QS_BADADDR) 189138032Speter { 1892168515Sgshapiro ctladdr->q_state = QS_DONTSEND; 1893168515Sgshapiro if (tTd(27, 5)) 1894168515Sgshapiro { 1895168515Sgshapiro sm_dprintf("include: QS_DONTSEND "); 1896168515Sgshapiro printaddr(sm_debug_file(), ctladdr, false); 1897168515Sgshapiro } 189838032Speter } 189938032Speter } 190038032Speter 190190792Sgshapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 190238032Speter FileName = oldfilename; 190338032Speter LineNumber = oldlinenumber; 190438032Speter e->e_to = oldto; 190538032Speter return rval; 190638032Speter} 190738032Speter 190838032Speterstatic void 1909141858Sgshapiroincludetimeout(ignore) 1910141858Sgshapiro int ignore; 191138032Speter{ 191277349Sgshapiro /* 191377349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 191477349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 191577349Sgshapiro ** DOING. 191677349Sgshapiro */ 191777349Sgshapiro 191877349Sgshapiro errno = ETIMEDOUT; 191938032Speter longjmp(CtxIncludeTimeout, 1); 192038032Speter} 1921168515Sgshapiro 192290792Sgshapiro/* 192338032Speter** SENDTOARGV -- send to an argument vector. 192438032Speter** 192538032Speter** Parameters: 192638032Speter** argv -- argument vector to send to. 192738032Speter** e -- the current envelope. 192838032Speter** 192938032Speter** Returns: 193038032Speter** none. 193138032Speter** 193238032Speter** Side Effects: 193338032Speter** puts all addresses on the argument vector onto the 193438032Speter** send queue. 193538032Speter*/ 193638032Speter 193738032Spetervoid 193838032Spetersendtoargv(argv, e) 193938032Speter register char **argv; 194038032Speter register ENVELOPE *e; 194138032Speter{ 194238032Speter register char *p; 194338032Speter 194438032Speter while ((p = *argv++) != NULL) 194538032Speter (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e); 194638032Speter} 1947168515Sgshapiro 194890792Sgshapiro/* 194938032Speter** GETCTLADDR -- get controlling address from an address header. 195038032Speter** 195138032Speter** If none, get one corresponding to the effective userid. 195238032Speter** 195338032Speter** Parameters: 195438032Speter** a -- the address to find the controller of. 195538032Speter** 195638032Speter** Returns: 195738032Speter** the controlling address. 195838032Speter*/ 195938032Speter 196038032SpeterADDRESS * 196138032Spetergetctladdr(a) 196238032Speter register ADDRESS *a; 196338032Speter{ 196438032Speter while (a != NULL && !bitset(QGOODUID, a->q_flags)) 196538032Speter a = a->q_alias; 196664562Sgshapiro return a; 196738032Speter} 1968168515Sgshapiro 196990792Sgshapiro/* 197038032Speter** SELF_REFERENCE -- check to see if an address references itself 197138032Speter** 197238032Speter** The check is done through a chain of aliases. If it is part of 197338032Speter** a loop, break the loop at the "best" address, that is, the one 197438032Speter** that exists as a real user. 197538032Speter** 197638032Speter** This is to handle the case of: 197738032Speter** awc: Andrew.Chang 197838032Speter** Andrew.Chang: awc@mail.server 197938032Speter** which is a problem only on mail.server. 198038032Speter** 198138032Speter** Parameters: 198238032Speter** a -- the address to check. 198338032Speter** 198438032Speter** Returns: 198538032Speter** The address that should be retained. 198638032Speter*/ 198738032Speter 198864562Sgshapirostatic ADDRESS * 198964562Sgshapiroself_reference(a) 199038032Speter ADDRESS *a; 199138032Speter{ 199238032Speter ADDRESS *b; /* top entry in self ref loop */ 199338032Speter ADDRESS *c; /* entry that point to a real mail box */ 199438032Speter 199538032Speter if (tTd(27, 1)) 199690792Sgshapiro sm_dprintf("self_reference(%s)\n", a->q_paddr); 199738032Speter 199838032Speter for (b = a->q_alias; b != NULL; b = b->q_alias) 199938032Speter { 200038032Speter if (sameaddr(a, b)) 200138032Speter break; 200238032Speter } 200338032Speter 200438032Speter if (b == NULL) 200538032Speter { 200638032Speter if (tTd(27, 1)) 200790792Sgshapiro sm_dprintf("\t... no self ref\n"); 200838032Speter return NULL; 200938032Speter } 201038032Speter 201138032Speter /* 201238032Speter ** Pick the first address that resolved to a real mail box 201390792Sgshapiro ** i.e has a mbdb entry. The returned value will be marked 201438032Speter ** QSELFREF in recipient(), which in turn will disable alias() 201564562Sgshapiro ** from marking it as QS_IS_DEAD(), which mean it will be used 201638032Speter ** as a deliverable address. 201738032Speter ** 201838032Speter ** The 2 key thing to note here are: 201938032Speter ** 1) we are in a recursive call sequence: 202090792Sgshapiro ** alias->sendtolist->recipient->alias 202138032Speter ** 2) normally, when we return back to alias(), the address 202264562Sgshapiro ** will be marked QS_EXPANDED, since alias() assumes the 202338032Speter ** expanded form will be used instead of the current address. 202438032Speter ** This behaviour is turned off if the address is marked 202590792Sgshapiro ** QSELFREF. We set QSELFREF when we return to recipient(). 202638032Speter */ 202738032Speter 202838032Speter c = a; 202938032Speter while (c != NULL) 203038032Speter { 203143730Speter if (tTd(27, 10)) 203290792Sgshapiro sm_dprintf(" %s", c->q_user); 203338032Speter if (bitnset(M_HASPWENT, c->q_mailer->m_flags)) 203438032Speter { 203590792Sgshapiro SM_MBDB_T user; 203690792Sgshapiro 203738032Speter if (tTd(27, 2)) 203890792Sgshapiro sm_dprintf("\t... getpwnam(%s)... ", c->q_user); 203990792Sgshapiro if (sm_mbdb_lookup(c->q_user, &user) == EX_OK) 204038032Speter { 204138032Speter if (tTd(27, 2)) 204290792Sgshapiro sm_dprintf("found\n"); 204338032Speter 204438032Speter /* ought to cache results here */ 204538032Speter if (sameaddr(b, c)) 204638032Speter return b; 204738032Speter else 204838032Speter return c; 204938032Speter } 205038032Speter if (tTd(27, 2)) 205190792Sgshapiro sm_dprintf("failed\n"); 205238032Speter } 205343730Speter else 205443730Speter { 205543730Speter /* if local delivery, compare usernames */ 205643730Speter if (bitnset(M_LOCALMAILER, c->q_mailer->m_flags) && 205743730Speter b->q_mailer == c->q_mailer) 205843730Speter { 205943730Speter if (tTd(27, 2)) 206090792Sgshapiro sm_dprintf("\t... local match (%s)\n", 206164562Sgshapiro c->q_user); 206243730Speter if (sameaddr(b, c)) 206343730Speter return b; 206443730Speter else 206543730Speter return c; 206643730Speter } 206743730Speter } 206843730Speter if (tTd(27, 10)) 206990792Sgshapiro sm_dprintf("\n"); 207038032Speter c = c->q_alias; 207138032Speter } 207238032Speter 207338032Speter if (tTd(27, 1)) 207490792Sgshapiro sm_dprintf("\t... cannot break loop for \"%s\"\n", a->q_paddr); 207538032Speter 207638032Speter return NULL; 207738032Speter} 2078