recipient.c revision 173340
138032Speter/* 2168515Sgshapiro * Copyright (c) 1998-2003, 2006 Sendmail, 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 16173340SgshapiroSM_RCSID("@(#)$Id: recipient.c,v 8.349 2007/07/10 17:01:22 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); 4790792Sgshapiro#else /* _FFR_HOST_SORT_REVERSE */ 4890792Sgshapiro return sm_strcasecmp(xx->q_host, yy->q_host); 4990792Sgshapiro#endif /* _FFR_HOST_SORT_REVERSE */ 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); 8590792Sgshapiro#else /* _FFR_HOST_SORT_REVERSE */ 8690792Sgshapiro return sm_strcasecmp(xx->q_host, yy->q_host); 8790792Sgshapiro#endif /* _FFR_HOST_SORT_REVERSE */ 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) 11590792Sgshapiro xx->q_signature = hostsignature(xx->q_mailer, xx->q_host); 11690792Sgshapiro if (yy->q_signature == NULL) 11790792Sgshapiro yy->q_signature = hostsignature(yy->q_mailer, yy->q_host); 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 */ 22590792Sgshapiro while ((isascii(*p) && 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 */ 39590792Sgshapiro while ((isascii(*p) && 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"; 51190792Sgshapiro if (sm_strcasecmp(p, "rfc822") != 0) 51290792Sgshapiro { 513168515Sgshapiro (void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s", 51490792Sgshapiro q->q_mailer->m_addrtype, 51590792Sgshapiro q->q_user); 51690792Sgshapiro } 51790792Sgshapiro else if (strchr(q->q_user, '@') != NULL) 51890792Sgshapiro { 519168515Sgshapiro (void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s", 52090792Sgshapiro p, q->q_user); 52190792Sgshapiro } 52290792Sgshapiro else if (strchr(q->q_paddr, '@') != NULL) 52390792Sgshapiro { 52490792Sgshapiro char *qp; 52590792Sgshapiro bool b; 52690792Sgshapiro 52790792Sgshapiro qp = q->q_paddr; 52890792Sgshapiro 52990792Sgshapiro /* strip brackets from address */ 53090792Sgshapiro b = false; 53190792Sgshapiro if (*qp == '<') 53290792Sgshapiro { 53390792Sgshapiro b = qp[strlen(qp) - 1] == '>'; 53490792Sgshapiro if (b) 53590792Sgshapiro qp[strlen(qp) - 1] = '\0'; 53690792Sgshapiro qp++; 53790792Sgshapiro } 538168515Sgshapiro (void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s", 53990792Sgshapiro p, qp); 54090792Sgshapiro 54190792Sgshapiro /* undo damage */ 54290792Sgshapiro if (b) 54390792Sgshapiro qp[strlen(qp)] = '>'; 54490792Sgshapiro } 54590792Sgshapiro else 54690792Sgshapiro { 547168515Sgshapiro (void) sm_snprintf(frbuf, sizeof(frbuf), 54890792Sgshapiro "%s; %.700s@%.100s", 54990792Sgshapiro p, q->q_user, MyHostName); 55090792Sgshapiro } 55190792Sgshapiro new->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool, frbuf); 55290792Sgshapiro } 55390792Sgshapiro 55464562Sgshapiro#if _FFR_GEN_ORCPT 55564562Sgshapiro /* set ORCPT DSN arg if not already set */ 55690792Sgshapiro if (new->q_orcpt == NULL) 55764562Sgshapiro { 55864562Sgshapiro /* check for an existing ORCPT */ 55964562Sgshapiro if (q->q_orcpt != NULL) 56090792Sgshapiro new->q_orcpt = q->q_orcpt; 56164562Sgshapiro else 56264562Sgshapiro { 56364562Sgshapiro /* make our own */ 56490792Sgshapiro bool b = false; 56564562Sgshapiro char *qp; 56664562Sgshapiro char obuf[MAXLINE]; 56764562Sgshapiro 56864562Sgshapiro if (e->e_from.q_mailer != NULL) 56964562Sgshapiro p = e->e_from.q_mailer->m_addrtype; 57064562Sgshapiro if (p == NULL) 57164562Sgshapiro p = "rfc822"; 572168515Sgshapiro (void) sm_strlcpyn(obuf, sizeof(obuf), 2, p, ";"); 57364562Sgshapiro 57464562Sgshapiro qp = q->q_paddr; 57564562Sgshapiro 57664562Sgshapiro /* FFR: Needs to strip comments from stdin addrs */ 57764562Sgshapiro 57864562Sgshapiro /* strip brackets from address */ 57964562Sgshapiro if (*qp == '<') 58064562Sgshapiro { 58164562Sgshapiro b = qp[strlen(qp) - 1] == '>'; 58264562Sgshapiro if (b) 58364562Sgshapiro qp[strlen(qp) - 1] = '\0'; 58464562Sgshapiro qp++; 58564562Sgshapiro } 58664562Sgshapiro 587168515Sgshapiro p = xtextify(denlstring(qp, true, false), "="); 58864562Sgshapiro 589168515Sgshapiro if (sm_strlcat(obuf, p, sizeof(obuf)) >= sizeof(obuf)) 59064562Sgshapiro { 59164562Sgshapiro /* if too big, don't use it */ 59264562Sgshapiro obuf[0] = '\0'; 59364562Sgshapiro } 59464562Sgshapiro 59564562Sgshapiro /* undo damage */ 59664562Sgshapiro if (b) 59764562Sgshapiro qp[strlen(qp)] = '>'; 59864562Sgshapiro 59964562Sgshapiro if (obuf[0] != '\0') 60090792Sgshapiro new->q_orcpt = 60190792Sgshapiro sm_rpool_strdup_x(e->e_rpool, obuf); 60264562Sgshapiro } 60364562Sgshapiro } 60464562Sgshapiro#endif /* _FFR_GEN_ORCPT */ 60564562Sgshapiro 60638032Speter /* break aliasing loops */ 60738032Speter if (aliaslevel > MaxAliasRecursion) 60838032Speter { 60990792Sgshapiro new->q_state = QS_BADADDR; 61090792Sgshapiro new->q_status = "5.4.6"; 611168515Sgshapiro if (new->q_alias != NULL) 612168515Sgshapiro { 613168515Sgshapiro new->q_alias->q_state = QS_BADADDR; 614168515Sgshapiro new->q_alias->q_status = "5.4.6"; 615168515Sgshapiro } 616168515Sgshapiro if ((SuprErrs || !LogUsrErrs) && LogLevel > 0) 617168515Sgshapiro { 618168515Sgshapiro sm_syslog(LOG_ERR, e->e_id, 619168515Sgshapiro "aliasing/forwarding loop broken: %s (%d aliases deep; %d max)", 620168515Sgshapiro FileName != NULL ? FileName : "", aliaslevel, 621168515Sgshapiro MaxAliasRecursion); 622168515Sgshapiro } 62390792Sgshapiro usrerrenh(new->q_status, 62464562Sgshapiro "554 aliasing/forwarding loop broken (%d aliases deep; %d max)", 62564562Sgshapiro aliaslevel, MaxAliasRecursion); 62690792Sgshapiro return new; 62738032Speter } 62838032Speter 62938032Speter /* 63038032Speter ** Finish setting up address structure. 63138032Speter */ 63238032Speter 63338032Speter /* get unquoted user for file, program or user.name check */ 63490792Sgshapiro i = strlen(new->q_user); 635168515Sgshapiro if (i >= sizeof(buf0)) 63664562Sgshapiro { 63764562Sgshapiro buflen = i + 1; 63864562Sgshapiro buf = xalloc(buflen); 63964562Sgshapiro } 64038032Speter else 64164562Sgshapiro { 64238032Speter buf = buf0; 643168515Sgshapiro buflen = sizeof(buf0); 64464562Sgshapiro } 64590792Sgshapiro (void) sm_strlcpy(buf, new->q_user, buflen); 64638032Speter for (p = buf; *p != '\0' && !quoted; p++) 64738032Speter { 64838032Speter if (*p == '\\') 64990792Sgshapiro quoted = true; 65038032Speter } 65138032Speter stripquotes(buf); 65238032Speter 65338032Speter /* check for direct mailing to restricted mailers */ 65438032Speter if (m == ProgMailer) 65538032Speter { 65690792Sgshapiro if (new->q_alias == NULL || UseMSP || 65790792Sgshapiro bitset(EF_UNSAFE, e->e_flags)) 65838032Speter { 65990792Sgshapiro new->q_state = QS_BADADDR; 66090792Sgshapiro new->q_status = "5.7.1"; 66190792Sgshapiro usrerrenh(new->q_status, 66264562Sgshapiro "550 Cannot mail directly to programs"); 66338032Speter } 66490792Sgshapiro else if (bitset(QBOGUSSHELL, new->q_alias->q_flags)) 66538032Speter { 66690792Sgshapiro new->q_state = QS_BADADDR; 66790792Sgshapiro new->q_status = "5.7.1"; 66890792Sgshapiro if (new->q_alias->q_ruser == NULL) 66990792Sgshapiro usrerrenh(new->q_status, 67064562Sgshapiro "550 UID %d is an unknown user: cannot mail to programs", 67190792Sgshapiro new->q_alias->q_uid); 67238032Speter else 67390792Sgshapiro usrerrenh(new->q_status, 67464562Sgshapiro "550 User %s@%s doesn't have a valid shell for mailing to programs", 67590792Sgshapiro new->q_alias->q_ruser, MyHostName); 67638032Speter } 67790792Sgshapiro else if (bitset(QUNSAFEADDR, new->q_alias->q_flags)) 67838032Speter { 67990792Sgshapiro new->q_state = QS_BADADDR; 68090792Sgshapiro new->q_status = "5.7.1"; 68190792Sgshapiro new->q_rstatus = "550 Unsafe for mailing to programs"; 68290792Sgshapiro usrerrenh(new->q_status, 68364562Sgshapiro "550 Address %s is unsafe for mailing to programs", 68490792Sgshapiro new->q_alias->q_paddr); 68538032Speter } 68638032Speter } 68738032Speter 68838032Speter /* 68938032Speter ** Look up this person in the recipient list. 69038032Speter ** If they are there already, return, otherwise continue. 69138032Speter ** If the list is empty, just add it. Notice the cute 69238032Speter ** hack to make from addresses suppress things correctly: 69364562Sgshapiro ** the QS_DUPLICATE state will be set in the send list. 69438032Speter ** [Please note: the emphasis is on "hack."] 69538032Speter */ 69638032Speter 69790792Sgshapiro prev = NULL; 69890792Sgshapiro 69990792Sgshapiro /* 70090792Sgshapiro ** If this message is going to the queue or FastSplit is set 70190792Sgshapiro ** and it is the first try and the envelope hasn't split, then we 70290792Sgshapiro ** avoid doing an MX RR lookup now because one will be done when the 70390792Sgshapiro ** message is extracted from the queue later. It can go to the queue 70490792Sgshapiro ** because all messages are going to the queue or this mailer of 70590792Sgshapiro ** the current recipient is marked expensive. 70690792Sgshapiro */ 70790792Sgshapiro 708110560Sgshapiro if (UseMSP || WILL_BE_QUEUED(e->e_sendmode) || 70990792Sgshapiro (!bitset(EF_SPLIT, e->e_flags) && e->e_ntries == 0 && 71090792Sgshapiro FastSplit > 0)) 71190792Sgshapiro sortfn = sorthost; 71290792Sgshapiro else if (NoConnect && bitnset(M_EXPENSIVE, new->q_mailer->m_flags)) 71390792Sgshapiro sortfn = sortexpensive; 71490792Sgshapiro else 71590792Sgshapiro sortfn = sortbysignature; 71690792Sgshapiro 71738032Speter for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 71838032Speter { 71990792Sgshapiro /* 72090792Sgshapiro ** If address is "less than" it should be inserted now. 72190792Sgshapiro ** If address is "greater than" current comparison it'll 72290792Sgshapiro ** insert later in the list; so loop again (if possible). 72390792Sgshapiro ** If address is "equal" (different equal than sameaddr() 72490792Sgshapiro ** call) then check if sameaddr() will be true. 72590792Sgshapiro ** Because this list is now sorted, it'll mean fewer 72690792Sgshapiro ** comparisons and fewer loops which is important for more 72790792Sgshapiro ** recipients. 72890792Sgshapiro */ 72990792Sgshapiro 73090792Sgshapiro i = (*sortfn)(new, q); 73190792Sgshapiro if (i == 0) /* equal */ 73238032Speter { 73390792Sgshapiro /* 73490792Sgshapiro ** Sortbysignature() has said that the two have 73590792Sgshapiro ** equal MX RR's and the same user. Calling sameaddr() 73690792Sgshapiro ** now checks if the two hosts are as identical as the 73790792Sgshapiro ** MX RR's are (which might not be the case) 73890792Sgshapiro ** before saying these are the identical addresses. 73990792Sgshapiro */ 74090792Sgshapiro 74190792Sgshapiro if (sameaddr(q, new) && 74290792Sgshapiro (bitset(QRCPTOK, q->q_flags) || 74390792Sgshapiro !bitset(QPRIMARY, q->q_flags))) 74438032Speter { 74590792Sgshapiro if (tTd(26, 1)) 74690792Sgshapiro { 74790792Sgshapiro sm_dprintf("%s in sendq: ", 74890792Sgshapiro new->q_paddr); 749132943Sgshapiro printaddr(sm_debug_file(), q, false); 75090792Sgshapiro } 75190792Sgshapiro if (!bitset(QPRIMARY, q->q_flags)) 75290792Sgshapiro { 75390792Sgshapiro if (!QS_IS_DEAD(new->q_state)) 75490792Sgshapiro message("duplicate suppressed"); 75590792Sgshapiro else 75690792Sgshapiro q->q_state = QS_DUPLICATE; 75790792Sgshapiro q->q_flags |= new->q_flags; 75890792Sgshapiro } 75990792Sgshapiro else if (bitset(QSELFREF, q->q_flags) 76090792Sgshapiro || q->q_state == QS_REMOVED) 76190792Sgshapiro { 76290792Sgshapiro /* 76390792Sgshapiro ** If an earlier milter removed the 76490792Sgshapiro ** address, a later one can still add 76590792Sgshapiro ** it back. 76690792Sgshapiro */ 76790792Sgshapiro 76890792Sgshapiro q->q_state = new->q_state; 76990792Sgshapiro q->q_flags |= new->q_flags; 77090792Sgshapiro } 77190792Sgshapiro new = q; 77290792Sgshapiro goto done; 77338032Speter } 77438032Speter } 77590792Sgshapiro else if (i < 0) /* less than */ 77690792Sgshapiro { 77790792Sgshapiro insert = true; 77890792Sgshapiro break; 77990792Sgshapiro } 78090792Sgshapiro prev = pq; 78138032Speter } 78238032Speter 78390792Sgshapiro /* pq should point to an address, never NULL */ 78490792Sgshapiro SM_ASSERT(pq != NULL); 78590792Sgshapiro 78638032Speter /* add address on list */ 78790792Sgshapiro if (insert) 78842575Speter { 78990792Sgshapiro /* 79090792Sgshapiro ** insert before 'pq'. Only possible when at least 1 79190792Sgshapiro ** ADDRESS is in the list already. 79290792Sgshapiro */ 79390792Sgshapiro 79490792Sgshapiro new->q_next = *pq; 79590792Sgshapiro if (prev == NULL) 79690792Sgshapiro *sendq = new; /* To be the first ADDRESS */ 79790792Sgshapiro else 79890792Sgshapiro (*prev)->q_next = new; 79942575Speter } 80090792Sgshapiro else 80190792Sgshapiro { 80290792Sgshapiro /* 80390792Sgshapiro ** Place in list at current 'pq' position. Possible 80490792Sgshapiro ** when there are 0 or more ADDRESS's in the list. 80590792Sgshapiro */ 80638032Speter 80790792Sgshapiro new->q_next = NULL; 80890792Sgshapiro *pq = new; 80990792Sgshapiro } 81090792Sgshapiro 81190792Sgshapiro /* added a new address: clear split flag */ 81290792Sgshapiro e->e_flags &= ~EF_SPLIT; 81390792Sgshapiro 81438032Speter /* 81538032Speter ** Alias the name and handle special mailer types. 81638032Speter */ 81738032Speter 81838032Speter trylocaluser: 81938032Speter if (tTd(29, 7)) 82042575Speter { 82190792Sgshapiro sm_dprintf("at trylocaluser: "); 822132943Sgshapiro printaddr(sm_debug_file(), new, false); 82342575Speter } 82438032Speter 82590792Sgshapiro if (!QS_IS_OK(new->q_state)) 82690792Sgshapiro { 82790792Sgshapiro if (QS_IS_UNDELIVERED(new->q_state)) 82890792Sgshapiro e->e_nrcpts++; 82938032Speter goto testselfdestruct; 83090792Sgshapiro } 83138032Speter 83238032Speter if (m == InclMailer) 83338032Speter { 83490792Sgshapiro new->q_state = QS_INCLUDED; 83590792Sgshapiro if (new->q_alias == NULL || UseMSP || 83690792Sgshapiro bitset(EF_UNSAFE, e->e_flags)) 83738032Speter { 83890792Sgshapiro new->q_state = QS_BADADDR; 83990792Sgshapiro new->q_status = "5.7.1"; 84090792Sgshapiro usrerrenh(new->q_status, 84164562Sgshapiro "550 Cannot mail directly to :include:s"); 84238032Speter } 84338032Speter else 84438032Speter { 84538032Speter int ret; 84638032Speter 84790792Sgshapiro message("including file %s", new->q_user); 84890792Sgshapiro ret = include(new->q_user, false, new, 84990792Sgshapiro sendq, aliaslevel, e); 85038032Speter if (transienterror(ret)) 85138032Speter { 85238032Speter if (LogLevel > 2) 85338032Speter sm_syslog(LOG_ERR, e->e_id, 85464562Sgshapiro "include %s: transient error: %s", 85590792Sgshapiro shortenstring(new->q_user, 85690792Sgshapiro MAXSHORTSTR), 85790792Sgshapiro sm_errstring(ret)); 85890792Sgshapiro new->q_state = QS_QUEUEUP; 85964562Sgshapiro usrerr("451 4.2.4 Cannot open %s: %s", 86090792Sgshapiro shortenstring(new->q_user, 86190792Sgshapiro MAXSHORTSTR), 86290792Sgshapiro sm_errstring(ret)); 86338032Speter } 86438032Speter else if (ret != 0) 86538032Speter { 86690792Sgshapiro new->q_state = QS_BADADDR; 86790792Sgshapiro new->q_status = "5.2.4"; 86890792Sgshapiro usrerrenh(new->q_status, 86964562Sgshapiro "550 Cannot open %s: %s", 87090792Sgshapiro shortenstring(new->q_user, 87190792Sgshapiro MAXSHORTSTR), 87290792Sgshapiro sm_errstring(ret)); 87338032Speter } 87438032Speter } 87538032Speter } 87638032Speter else if (m == FileMailer) 87738032Speter { 87890792Sgshapiro /* check if allowed */ 87990792Sgshapiro if (new->q_alias == NULL || UseMSP || 88090792Sgshapiro bitset(EF_UNSAFE, e->e_flags)) 88138032Speter { 88290792Sgshapiro new->q_state = QS_BADADDR; 88390792Sgshapiro new->q_status = "5.7.1"; 88490792Sgshapiro usrerrenh(new->q_status, 88564562Sgshapiro "550 Cannot mail directly to files"); 88638032Speter } 88790792Sgshapiro else if (bitset(QBOGUSSHELL, new->q_alias->q_flags)) 88838032Speter { 88990792Sgshapiro new->q_state = QS_BADADDR; 89090792Sgshapiro new->q_status = "5.7.1"; 89190792Sgshapiro if (new->q_alias->q_ruser == NULL) 89290792Sgshapiro usrerrenh(new->q_status, 89364562Sgshapiro "550 UID %d is an unknown user: cannot mail to files", 89490792Sgshapiro new->q_alias->q_uid); 89538032Speter else 89690792Sgshapiro usrerrenh(new->q_status, 89764562Sgshapiro "550 User %s@%s doesn't have a valid shell for mailing to files", 89890792Sgshapiro new->q_alias->q_ruser, MyHostName); 89938032Speter } 90090792Sgshapiro else if (bitset(QUNSAFEADDR, new->q_alias->q_flags)) 90138032Speter { 90290792Sgshapiro new->q_state = QS_BADADDR; 90390792Sgshapiro new->q_status = "5.7.1"; 90490792Sgshapiro new->q_rstatus = "550 Unsafe for mailing to files"; 90590792Sgshapiro usrerrenh(new->q_status, 90664562Sgshapiro "550 Address %s is unsafe for mailing to files", 90790792Sgshapiro new->q_alias->q_paddr); 90838032Speter } 90938032Speter } 91038032Speter 91138032Speter /* try aliasing */ 91290792Sgshapiro if (!quoted && QS_IS_OK(new->q_state) && 91338032Speter bitnset(M_ALIASABLE, m->m_flags)) 91490792Sgshapiro alias(new, sendq, aliaslevel, e); 91538032Speter 91664562Sgshapiro#if USERDB 91738032Speter /* if not aliased, look it up in the user database */ 91890792Sgshapiro if (!bitset(QNOTREMOTE, new->q_flags) && 91990792Sgshapiro QS_IS_SENDABLE(new->q_state) && 92038032Speter bitnset(M_CHECKUDB, m->m_flags)) 92138032Speter { 92290792Sgshapiro if (udbexpand(new, sendq, aliaslevel, e) == EX_TEMPFAIL) 92338032Speter { 92490792Sgshapiro new->q_state = QS_QUEUEUP; 92538032Speter if (e->e_message == NULL) 926168515Sgshapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, 927168515Sgshapiro "Deferred: user database error"); 92890792Sgshapiro if (new->q_message == NULL) 92990792Sgshapiro new->q_message = "Deferred: user database error"; 93038032Speter if (LogLevel > 8) 93138032Speter sm_syslog(LOG_INFO, e->e_id, 93264562Sgshapiro "deferred: udbexpand: %s", 93390792Sgshapiro sm_errstring(errno)); 93438032Speter message("queued (user database error): %s", 93590792Sgshapiro sm_errstring(errno)); 93638032Speter e->e_nrcpts++; 93738032Speter goto testselfdestruct; 93838032Speter } 93938032Speter } 94064562Sgshapiro#endif /* USERDB */ 94138032Speter 94238032Speter /* 94338032Speter ** If we have a level two config file, then pass the name through 94438032Speter ** Ruleset 5 before sending it off. Ruleset 5 has the right 94590792Sgshapiro ** to rewrite it to another mailer. This gives us a hook 94638032Speter ** after local aliasing has been done. 94738032Speter */ 94838032Speter 94938032Speter if (tTd(29, 5)) 95038032Speter { 95190792Sgshapiro sm_dprintf("recipient: testing local? cl=%d, rr5=%p\n\t", 95290792Sgshapiro ConfigLevel, RewriteRules[5]); 953132943Sgshapiro printaddr(sm_debug_file(), new, false); 95438032Speter } 95564562Sgshapiro if (ConfigLevel >= 2 && RewriteRules[5] != NULL && 95664562Sgshapiro bitnset(M_TRYRULESET5, m->m_flags) && 95790792Sgshapiro !bitset(QNOTREMOTE, new->q_flags) && 95890792Sgshapiro QS_IS_OK(new->q_state)) 95938032Speter { 96090792Sgshapiro maplocaluser(new, sendq, aliaslevel + 1, e); 96138032Speter } 96238032Speter 96338032Speter /* 96438032Speter ** If it didn't get rewritten to another mailer, go ahead 96538032Speter ** and deliver it. 96638032Speter */ 96738032Speter 96890792Sgshapiro if (QS_IS_OK(new->q_state) && 96938032Speter bitnset(M_HASPWENT, m->m_flags)) 97038032Speter { 97138032Speter auto bool fuzzy; 97290792Sgshapiro SM_MBDB_T user; 97390792Sgshapiro int status; 97438032Speter 97538032Speter /* warning -- finduser may trash buf */ 97690792Sgshapiro status = finduser(buf, &fuzzy, &user); 97790792Sgshapiro switch (status) 97838032Speter { 97990792Sgshapiro case EX_TEMPFAIL: 98090792Sgshapiro new->q_state = QS_QUEUEUP; 98190792Sgshapiro new->q_status = "4.5.2"; 98290792Sgshapiro giveresponse(EX_TEMPFAIL, new->q_status, m, NULL, 98390792Sgshapiro new->q_alias, (time_t) 0, e, new); 98490792Sgshapiro break; 98590792Sgshapiro default: 98690792Sgshapiro new->q_state = QS_BADADDR; 98790792Sgshapiro new->q_status = "5.1.1"; 98890792Sgshapiro new->q_rstatus = "550 5.1.1 User unknown"; 98990792Sgshapiro giveresponse(EX_NOUSER, new->q_status, m, NULL, 99090792Sgshapiro new->q_alias, (time_t) 0, e, new); 99190792Sgshapiro break; 99290792Sgshapiro case EX_OK: 99338032Speter if (fuzzy) 99438032Speter { 99538032Speter /* name was a fuzzy match */ 99690792Sgshapiro new->q_user = sm_rpool_strdup_x(e->e_rpool, 99790792Sgshapiro user.mbdb_name); 99838032Speter if (findusercount++ > 3) 99938032Speter { 100090792Sgshapiro new->q_state = QS_BADADDR; 100190792Sgshapiro new->q_status = "5.4.6"; 100290792Sgshapiro usrerrenh(new->q_status, 100364562Sgshapiro "554 aliasing/forwarding loop for %s broken", 100490792Sgshapiro user.mbdb_name); 100538032Speter goto done; 100638032Speter } 100738032Speter 100838032Speter /* see if it aliases */ 100990792Sgshapiro (void) sm_strlcpy(buf, user.mbdb_name, buflen); 101038032Speter goto trylocaluser; 101138032Speter } 101290792Sgshapiro if (*user.mbdb_homedir == '\0') 101390792Sgshapiro new->q_home = NULL; 101490792Sgshapiro else if (strcmp(user.mbdb_homedir, "/") == 0) 101590792Sgshapiro new->q_home = ""; 101638032Speter else 101790792Sgshapiro new->q_home = sm_rpool_strdup_x(e->e_rpool, 101890792Sgshapiro user.mbdb_homedir); 101990792Sgshapiro if (user.mbdb_uid != SM_NO_UID) 102038032Speter { 102190792Sgshapiro new->q_uid = user.mbdb_uid; 102290792Sgshapiro new->q_gid = user.mbdb_gid; 102390792Sgshapiro new->q_flags |= QGOODUID; 102438032Speter } 102590792Sgshapiro new->q_ruser = sm_rpool_strdup_x(e->e_rpool, 102690792Sgshapiro user.mbdb_name); 102790792Sgshapiro if (user.mbdb_fullname[0] != '\0') 102890792Sgshapiro new->q_fullname = sm_rpool_strdup_x(e->e_rpool, 102990792Sgshapiro user.mbdb_fullname); 103090792Sgshapiro if (!usershellok(user.mbdb_name, user.mbdb_shell)) 103190792Sgshapiro { 103290792Sgshapiro new->q_flags |= QBOGUSSHELL; 103390792Sgshapiro } 103438032Speter if (bitset(EF_VRFYONLY, e->e_flags)) 103538032Speter { 103638032Speter /* don't do any more now */ 103790792Sgshapiro new->q_state = QS_VERIFIED; 103838032Speter } 103938032Speter else if (!quoted) 104090792Sgshapiro forward(new, sendq, aliaslevel, e); 104138032Speter } 104238032Speter } 104390792Sgshapiro if (!QS_IS_DEAD(new->q_state)) 104438032Speter e->e_nrcpts++; 104538032Speter 104638032Speter testselfdestruct: 104790792Sgshapiro new->q_flags |= QTHISPASS; 104838032Speter if (tTd(26, 8)) 104938032Speter { 105090792Sgshapiro sm_dprintf("testselfdestruct: "); 1051132943Sgshapiro printaddr(sm_debug_file(), new, false); 105238032Speter if (tTd(26, 10)) 105338032Speter { 105490792Sgshapiro sm_dprintf("SENDQ:\n"); 1055132943Sgshapiro printaddr(sm_debug_file(), *sendq, true); 105690792Sgshapiro sm_dprintf("----\n"); 105738032Speter } 105838032Speter } 105990792Sgshapiro if (new->q_alias == NULL && new != &e->e_from && 106090792Sgshapiro QS_IS_DEAD(new->q_state)) 106138032Speter { 106238032Speter for (q = *sendq; q != NULL; q = q->q_next) 106338032Speter { 106464562Sgshapiro if (!QS_IS_DEAD(q->q_state)) 106538032Speter break; 106638032Speter } 106738032Speter if (q == NULL) 106838032Speter { 106990792Sgshapiro new->q_state = QS_BADADDR; 107090792Sgshapiro new->q_status = "5.4.6"; 107190792Sgshapiro usrerrenh(new->q_status, 107264562Sgshapiro "554 aliasing/forwarding loop broken"); 107338032Speter } 107438032Speter } 107538032Speter 107638032Speter done: 107790792Sgshapiro new->q_flags |= QTHISPASS; 107838032Speter if (buf != buf0) 107990792Sgshapiro sm_free(buf); /* XXX leak if above code raises exception */ 108038032Speter 108138032Speter /* 108238032Speter ** If we are at the top level, check to see if this has 108338032Speter ** expanded to exactly one address. If so, it can inherit 108438032Speter ** the primaryness of the address. 108538032Speter ** 108638032Speter ** While we're at it, clear the QTHISPASS bits. 108738032Speter */ 108838032Speter 108938032Speter if (aliaslevel == 0) 109038032Speter { 109138032Speter int nrcpts = 0; 109238032Speter ADDRESS *only = NULL; 109338032Speter 109438032Speter for (q = *sendq; q != NULL; q = q->q_next) 109538032Speter { 109638032Speter if (bitset(QTHISPASS, q->q_flags) && 109764562Sgshapiro QS_IS_SENDABLE(q->q_state)) 109838032Speter { 109938032Speter nrcpts++; 110038032Speter only = q; 110138032Speter } 110238032Speter q->q_flags &= ~QTHISPASS; 110338032Speter } 110438032Speter if (nrcpts == 1) 110538032Speter { 110638032Speter /* check to see if this actually got a new owner */ 110738032Speter q = only; 110838032Speter while ((q = q->q_alias) != NULL) 110938032Speter { 111038032Speter if (q->q_owner != NULL) 111138032Speter break; 111238032Speter } 111338032Speter if (q == NULL) 111438032Speter only->q_flags |= QPRIMARY; 111538032Speter } 111638032Speter else if (!initialdontsend && nrcpts > 0) 111738032Speter { 111838032Speter /* arrange for return receipt */ 111938032Speter e->e_flags |= EF_SENDRECEIPT; 112090792Sgshapiro new->q_flags |= QEXPANDED; 112164562Sgshapiro if (e->e_xfp != NULL && 112290792Sgshapiro bitset(QPINGONSUCCESS, new->q_flags)) 112390792Sgshapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 112490792Sgshapiro "%s... expanded to multiple addresses\n", 112590792Sgshapiro new->q_paddr); 112638032Speter } 112738032Speter } 112890792Sgshapiro new->q_flags |= QRCPTOK; 1129168515Sgshapiro (void) sm_snprintf(buf0, sizeof(buf0), "%d", e->e_nrcpts); 113090792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{nrcpts}"), buf0); 113190792Sgshapiro return new; 113238032Speter} 1133168515Sgshapiro 113490792Sgshapiro/* 113538032Speter** FINDUSER -- find the password entry for a user. 113638032Speter** 113738032Speter** This looks a lot like getpwnam, except that it may want to 113838032Speter** do some fancier pattern matching in /etc/passwd. 113938032Speter** 114038032Speter** This routine contains most of the time of many sendmail runs. 114138032Speter** It deserves to be optimized. 114238032Speter** 114338032Speter** Parameters: 114438032Speter** name -- the name to match against. 114590792Sgshapiro** fuzzyp -- an outarg that is set to true if this entry 114638032Speter** was found using the fuzzy matching algorithm; 114790792Sgshapiro** set to false otherwise. 114890792Sgshapiro** user -- structure to fill in if user is found 114938032Speter** 115038032Speter** Returns: 115190792Sgshapiro** On success, fill in *user, set *fuzzyp and return EX_OK. 115290792Sgshapiro** If the user was not found, return EX_NOUSER. 115390792Sgshapiro** On error, return EX_TEMPFAIL or EX_OSERR. 115438032Speter** 115538032Speter** Side Effects: 115638032Speter** may modify name. 115738032Speter*/ 115838032Speter 115990792Sgshapiroint 116090792Sgshapirofinduser(name, fuzzyp, user) 116138032Speter char *name; 116238032Speter bool *fuzzyp; 116390792Sgshapiro SM_MBDB_T *user; 116438032Speter{ 116590792Sgshapiro#if MATCHGECOS 116638032Speter register struct passwd *pw; 116790792Sgshapiro#endif /* MATCHGECOS */ 116838032Speter register char *p; 116938032Speter bool tryagain; 117090792Sgshapiro int status; 117138032Speter 117238032Speter if (tTd(29, 4)) 117390792Sgshapiro sm_dprintf("finduser(%s): ", name); 117438032Speter 117590792Sgshapiro *fuzzyp = false; 117638032Speter 117790792Sgshapiro#if HESIOD 117838032Speter /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 117938032Speter for (p = name; *p != '\0'; p++) 118038032Speter if (!isascii(*p) || !isdigit(*p)) 118138032Speter break; 118238032Speter if (*p == '\0') 118338032Speter { 118438032Speter if (tTd(29, 4)) 118590792Sgshapiro sm_dprintf("failed (numeric input)\n"); 118690792Sgshapiro return EX_NOUSER; 118738032Speter } 118864562Sgshapiro#endif /* HESIOD */ 118938032Speter 119038032Speter /* look up this login name using fast path */ 119190792Sgshapiro status = sm_mbdb_lookup(name, user); 119290792Sgshapiro if (status != EX_NOUSER) 119338032Speter { 119438032Speter if (tTd(29, 4)) 119590792Sgshapiro sm_dprintf("%s (non-fuzzy)\n", sm_strexit(status)); 119690792Sgshapiro return status; 119738032Speter } 119838032Speter 119938032Speter /* try mapping it to lower case */ 120090792Sgshapiro tryagain = false; 120138032Speter for (p = name; *p != '\0'; p++) 120238032Speter { 120338032Speter if (isascii(*p) && isupper(*p)) 120438032Speter { 120538032Speter *p = tolower(*p); 120690792Sgshapiro tryagain = true; 120738032Speter } 120838032Speter } 120990792Sgshapiro if (tryagain && (status = sm_mbdb_lookup(name, user)) != EX_NOUSER) 121038032Speter { 121138032Speter if (tTd(29, 4)) 121290792Sgshapiro sm_dprintf("%s (lower case)\n", sm_strexit(status)); 121390792Sgshapiro *fuzzyp = true; 121490792Sgshapiro return status; 121538032Speter } 121638032Speter 121738032Speter#if MATCHGECOS 121838032Speter /* see if fuzzy matching allowed */ 121938032Speter if (!MatchGecos) 122038032Speter { 122138032Speter if (tTd(29, 4)) 122290792Sgshapiro sm_dprintf("not found (fuzzy disabled)\n"); 122390792Sgshapiro return EX_NOUSER; 122438032Speter } 122538032Speter 122638032Speter /* search for a matching full name instead */ 122738032Speter for (p = name; *p != '\0'; p++) 122838032Speter { 122938032Speter if (*p == (SpaceSub & 0177) || *p == '_') 123038032Speter *p = ' '; 123138032Speter } 123238032Speter (void) setpwent(); 123338032Speter while ((pw = getpwent()) != NULL) 123438032Speter { 123538032Speter char buf[MAXNAME + 1]; 123638032Speter 123738032Speter# if 0 123890792Sgshapiro if (sm_strcasecmp(pw->pw_name, name) == 0) 123938032Speter { 124038032Speter if (tTd(29, 4)) 124190792Sgshapiro sm_dprintf("found (case wrapped)\n"); 124238032Speter break; 124338032Speter } 124464562Sgshapiro# endif /* 0 */ 124538032Speter 1246168515Sgshapiro sm_pwfullname(pw->pw_gecos, pw->pw_name, buf, sizeof(buf)); 124790792Sgshapiro if (strchr(buf, ' ') != NULL && sm_strcasecmp(buf, name) == 0) 124838032Speter { 124938032Speter if (tTd(29, 4)) 125090792Sgshapiro sm_dprintf("fuzzy matches %s\n", pw->pw_name); 125138032Speter message("sending to login name %s", pw->pw_name); 125238032Speter break; 125338032Speter } 125438032Speter } 125538032Speter if (pw != NULL) 125690792Sgshapiro *fuzzyp = true; 125738032Speter else if (tTd(29, 4)) 125890792Sgshapiro sm_dprintf("no fuzzy match found\n"); 125938032Speter# if DEC_OSF_BROKEN_GETPWENT /* DEC OSF/1 3.2 or earlier */ 126038032Speter endpwent(); 126164562Sgshapiro# endif /* DEC_OSF_BROKEN_GETPWENT */ 126290792Sgshapiro if (pw == NULL) 126390792Sgshapiro return EX_NOUSER; 126490792Sgshapiro sm_mbdb_frompw(user, pw); 126590792Sgshapiro return EX_OK; 126664562Sgshapiro#else /* MATCHGECOS */ 126738032Speter if (tTd(29, 4)) 126890792Sgshapiro sm_dprintf("not found (fuzzy disabled)\n"); 126990792Sgshapiro return EX_NOUSER; 127064562Sgshapiro#endif /* MATCHGECOS */ 127138032Speter} 1272168515Sgshapiro 127390792Sgshapiro/* 127438032Speter** WRITABLE -- predicate returning if the file is writable. 127538032Speter** 127638032Speter** This routine must duplicate the algorithm in sys/fio.c. 127738032Speter** Unfortunately, we cannot use the access call since we 127838032Speter** won't necessarily be the real uid when we try to 127938032Speter** actually open the file. 128038032Speter** 128138032Speter** Notice that ANY file with ANY execute bit is automatically 128238032Speter** not writable. This is also enforced by mailfile. 128338032Speter** 128438032Speter** Parameters: 128538032Speter** filename -- the file name to check. 128638032Speter** ctladdr -- the controlling address for this file. 128738032Speter** flags -- SFF_* flags to control the function. 128838032Speter** 128938032Speter** Returns: 129090792Sgshapiro** true -- if we will be able to write this file. 129190792Sgshapiro** false -- if we cannot write this file. 129238032Speter** 129338032Speter** Side Effects: 129438032Speter** none. 129538032Speter*/ 129638032Speter 129738032Speterbool 129838032Speterwritable(filename, ctladdr, flags) 129938032Speter char *filename; 130038032Speter ADDRESS *ctladdr; 130164562Sgshapiro long flags; 130238032Speter{ 130364562Sgshapiro uid_t euid = 0; 130464562Sgshapiro gid_t egid = 0; 130564562Sgshapiro char *user = NULL; 130638032Speter 130738032Speter if (tTd(44, 5)) 130890792Sgshapiro sm_dprintf("writable(%s, 0x%lx)\n", filename, flags); 130938032Speter 131038032Speter /* 131138032Speter ** File does exist -- check that it is writable. 131238032Speter */ 131338032Speter 131438032Speter if (geteuid() != 0) 131538032Speter { 131638032Speter euid = geteuid(); 131738032Speter egid = getegid(); 131864562Sgshapiro user = NULL; 131938032Speter } 132038032Speter else if (ctladdr != NULL) 132138032Speter { 132238032Speter euid = ctladdr->q_uid; 132338032Speter egid = ctladdr->q_gid; 132464562Sgshapiro user = ctladdr->q_user; 132538032Speter } 132638032Speter else if (bitset(SFF_RUNASREALUID, flags)) 132738032Speter { 132838032Speter euid = RealUid; 132938032Speter egid = RealGid; 133064562Sgshapiro user = RealUserName; 133138032Speter } 133238032Speter else if (FileMailer != NULL && !bitset(SFF_ROOTOK, flags)) 133338032Speter { 1334132943Sgshapiro if (FileMailer->m_uid == NO_UID) 1335132943Sgshapiro { 1336132943Sgshapiro euid = DefUid; 1337132943Sgshapiro user = DefUser; 1338132943Sgshapiro } 1339132943Sgshapiro else 1340132943Sgshapiro { 1341132943Sgshapiro euid = FileMailer->m_uid; 1342132943Sgshapiro user = NULL; 1343132943Sgshapiro } 1344132943Sgshapiro if (FileMailer->m_gid == NO_GID) 1345132943Sgshapiro egid = DefGid; 1346132943Sgshapiro else 1347132943Sgshapiro egid = FileMailer->m_gid; 134838032Speter } 134938032Speter else 135038032Speter { 135138032Speter euid = egid = 0; 135264562Sgshapiro user = NULL; 135338032Speter } 135438032Speter if (!bitset(SFF_ROOTOK, flags)) 135538032Speter { 135638032Speter if (euid == 0) 135738032Speter { 135838032Speter euid = DefUid; 135964562Sgshapiro user = DefUser; 136038032Speter } 136138032Speter if (egid == 0) 136238032Speter egid = DefGid; 136338032Speter } 136438032Speter if (geteuid() == 0 && 136538032Speter (ctladdr == NULL || !bitset(QGOODUID, ctladdr->q_flags))) 136638032Speter flags |= SFF_SETUIDOK; 136738032Speter 136864562Sgshapiro if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 136938032Speter flags |= SFF_NOSLINK; 137064562Sgshapiro if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) 137138032Speter flags |= SFF_NOHLINK; 137238032Speter 137364562Sgshapiro errno = safefile(filename, euid, egid, user, flags, S_IWRITE, NULL); 137438032Speter return errno == 0; 137538032Speter} 1376168515Sgshapiro 137790792Sgshapiro/* 137838032Speter** INCLUDE -- handle :include: specification. 137938032Speter** 138038032Speter** Parameters: 138138032Speter** fname -- filename to include. 138290792Sgshapiro** forwarding -- if true, we are reading a .forward file. 138390792Sgshapiro** if false, it's a :include: file. 138438032Speter** ctladdr -- address template to use to fill in these 138538032Speter** addresses -- effective user/group id are 138638032Speter** the important things. 138738032Speter** sendq -- a pointer to the head of the send queue 138838032Speter** to put these addresses in. 138938032Speter** aliaslevel -- the alias nesting depth. 139038032Speter** e -- the current envelope. 139138032Speter** 139238032Speter** Returns: 139338032Speter** open error status 139438032Speter** 139538032Speter** Side Effects: 139638032Speter** reads the :include: file and sends to everyone 139738032Speter** listed in that file. 139838032Speter** 139938032Speter** Security Note: 140038032Speter** If you have restricted chown (that is, you can't 140138032Speter** give a file away), it is reasonable to allow programs 140238032Speter** and files called from this :include: file to be to be 140338032Speter** run as the owner of the :include: file. This is bogus 140438032Speter** if there is any chance of someone giving away a file. 140538032Speter** We assume that pre-POSIX systems can give away files. 140638032Speter** 140738032Speter** There is an additional restriction that if you 140838032Speter** forward to a :include: file, it will not take on 140938032Speter** the ownership of the :include: file. This may not 141038032Speter** be necessary, but shouldn't hurt. 141138032Speter*/ 141238032Speter 141338032Speterstatic jmp_buf CtxIncludeTimeout; 141438032Speter 141538032Speterint 141638032Speterinclude(fname, forwarding, ctladdr, sendq, aliaslevel, e) 141738032Speter char *fname; 141838032Speter bool forwarding; 141938032Speter ADDRESS *ctladdr; 142038032Speter ADDRESS **sendq; 142138032Speter int aliaslevel; 142238032Speter ENVELOPE *e; 142338032Speter{ 142490792Sgshapiro SM_FILE_T *volatile fp = NULL; 142538032Speter char *oldto = e->e_to; 142638032Speter char *oldfilename = FileName; 142738032Speter int oldlinenumber = LineNumber; 142890792Sgshapiro register SM_EVENT *ev = NULL; 142938032Speter int nincludes; 143038032Speter int mode; 143190792Sgshapiro volatile bool maxreached = false; 143238032Speter register ADDRESS *ca; 143364562Sgshapiro volatile uid_t saveduid; 143464562Sgshapiro volatile gid_t savedgid; 143564562Sgshapiro volatile uid_t uid; 143664562Sgshapiro volatile gid_t gid; 143764562Sgshapiro char *volatile user; 143838032Speter int rval = 0; 143964562Sgshapiro volatile long sfflags = SFF_REGONLY; 144038032Speter register char *p; 144190792Sgshapiro bool safechown = false; 144290792Sgshapiro volatile bool safedir = false; 144338032Speter struct stat st; 144438032Speter char buf[MAXLINE]; 144538032Speter 144638032Speter if (tTd(27, 2)) 144790792Sgshapiro sm_dprintf("include(%s)\n", fname); 144838032Speter if (tTd(27, 4)) 144990792Sgshapiro sm_dprintf(" ruid=%d euid=%d\n", 145064562Sgshapiro (int) getuid(), (int) geteuid()); 145138032Speter if (tTd(27, 14)) 145238032Speter { 145390792Sgshapiro sm_dprintf("ctladdr "); 1454132943Sgshapiro printaddr(sm_debug_file(), ctladdr, false); 145538032Speter } 145638032Speter 145738032Speter if (tTd(27, 9)) 145890792Sgshapiro sm_dprintf("include: old uid = %d/%d\n", 145990792Sgshapiro (int) getuid(), (int) geteuid()); 146038032Speter 146138032Speter if (forwarding) 146266494Sgshapiro { 146398121Sgshapiro sfflags |= SFF_MUSTOWN|SFF_ROOTOK; 146466494Sgshapiro if (!bitnset(DBS_GROUPWRITABLEFORWARDFILE, DontBlameSendmail)) 146566494Sgshapiro sfflags |= SFF_NOGWFILES; 146666494Sgshapiro if (!bitnset(DBS_WORLDWRITABLEFORWARDFILE, DontBlameSendmail)) 146766494Sgshapiro sfflags |= SFF_NOWWFILES; 146866494Sgshapiro } 146966494Sgshapiro else 147066494Sgshapiro { 147166494Sgshapiro if (!bitnset(DBS_GROUPWRITABLEINCLUDEFILE, DontBlameSendmail)) 147266494Sgshapiro sfflags |= SFF_NOGWFILES; 147366494Sgshapiro if (!bitnset(DBS_WORLDWRITABLEINCLUDEFILE, DontBlameSendmail)) 147466494Sgshapiro sfflags |= SFF_NOWWFILES; 147566494Sgshapiro } 147666494Sgshapiro 147764562Sgshapiro /* 147864562Sgshapiro ** If RunAsUser set, won't be able to run programs as user 147964562Sgshapiro ** so mark them as unsafe unless the administrator knows better. 148064562Sgshapiro */ 148164562Sgshapiro 148264562Sgshapiro if ((geteuid() != 0 || RunAsUid != 0) && 148364562Sgshapiro !bitnset(DBS_NONROOTSAFEADDR, DontBlameSendmail)) 148464562Sgshapiro { 148564562Sgshapiro if (tTd(27, 4)) 148690792Sgshapiro sm_dprintf("include: not safe (euid=%d, RunAsUid=%d)\n", 148790792Sgshapiro (int) geteuid(), (int) RunAsUid); 148864562Sgshapiro ctladdr->q_flags |= QUNSAFEADDR; 148964562Sgshapiro } 149064562Sgshapiro 149138032Speter ca = getctladdr(ctladdr); 149264562Sgshapiro if (ca == NULL || 149364562Sgshapiro (ca->q_uid == DefUid && ca->q_gid == 0)) 149438032Speter { 149538032Speter uid = DefUid; 149638032Speter gid = DefGid; 149764562Sgshapiro user = DefUser; 149838032Speter } 149938032Speter else 150038032Speter { 150138032Speter uid = ca->q_uid; 150238032Speter gid = ca->q_gid; 150364562Sgshapiro user = ca->q_user; 150438032Speter } 150564562Sgshapiro#if MAILER_SETUID_METHOD != USE_SETUID 150638032Speter saveduid = geteuid(); 150738032Speter savedgid = getegid(); 150838032Speter if (saveduid == 0) 150938032Speter { 151038032Speter if (!DontInitGroups) 151138032Speter { 151264562Sgshapiro if (initgroups(user, gid) == -1) 151364562Sgshapiro { 151464562Sgshapiro rval = EAGAIN; 151538032Speter syserr("include: initgroups(%s, %d) failed", 151664562Sgshapiro user, gid); 151764562Sgshapiro goto resetuid; 151864562Sgshapiro } 151938032Speter } 152038032Speter else 152138032Speter { 152238032Speter GIDSET_T gidset[1]; 152338032Speter 152438032Speter gidset[0] = gid; 152538032Speter if (setgroups(1, gidset) == -1) 152664562Sgshapiro { 152764562Sgshapiro rval = EAGAIN; 152838032Speter syserr("include: setgroups() failed"); 152964562Sgshapiro goto resetuid; 153064562Sgshapiro } 153138032Speter } 153238032Speter 153338032Speter if (gid != 0 && setgid(gid) < -1) 153464562Sgshapiro { 153564562Sgshapiro rval = EAGAIN; 153638032Speter syserr("setgid(%d) failure", gid); 153764562Sgshapiro goto resetuid; 153864562Sgshapiro } 153938032Speter if (uid != 0) 154038032Speter { 154164562Sgshapiro# if MAILER_SETUID_METHOD == USE_SETEUID 154238032Speter if (seteuid(uid) < 0) 154364562Sgshapiro { 154464562Sgshapiro rval = EAGAIN; 154538032Speter syserr("seteuid(%d) failure (real=%d, eff=%d)", 154698121Sgshapiro uid, (int) getuid(), (int) geteuid()); 154764562Sgshapiro goto resetuid; 154864562Sgshapiro } 154964562Sgshapiro# endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 155064562Sgshapiro# if MAILER_SETUID_METHOD == USE_SETREUID 155138032Speter if (setreuid(0, uid) < 0) 155264562Sgshapiro { 155364562Sgshapiro rval = EAGAIN; 155438032Speter syserr("setreuid(0, %d) failure (real=%d, eff=%d)", 155598121Sgshapiro uid, (int) getuid(), (int) geteuid()); 155664562Sgshapiro goto resetuid; 155764562Sgshapiro } 155864562Sgshapiro# endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 155938032Speter } 156038032Speter } 156164562Sgshapiro#endif /* MAILER_SETUID_METHOD != USE_SETUID */ 156238032Speter 156338032Speter if (tTd(27, 9)) 156490792Sgshapiro sm_dprintf("include: new uid = %d/%d\n", 156590792Sgshapiro (int) getuid(), (int) geteuid()); 156638032Speter 156738032Speter /* 156838032Speter ** If home directory is remote mounted but server is down, 156938032Speter ** this can hang or give errors; use a timeout to avoid this 157038032Speter */ 157138032Speter 157238032Speter if (setjmp(CtxIncludeTimeout) != 0) 157338032Speter { 157464562Sgshapiro ctladdr->q_state = QS_QUEUEUP; 157538032Speter errno = 0; 157638032Speter 157738032Speter /* return pseudo-error code */ 157838032Speter rval = E_SM_OPENTIMEOUT; 157938032Speter goto resetuid; 158038032Speter } 158138032Speter if (TimeOuts.to_fileopen > 0) 158290792Sgshapiro ev = sm_setevent(TimeOuts.to_fileopen, includetimeout, 0); 158338032Speter else 158438032Speter ev = NULL; 158538032Speter 158664562Sgshapiro 158738032Speter /* check for writable parent directory */ 158838032Speter p = strrchr(fname, '/'); 158938032Speter if (p != NULL) 159038032Speter { 159138032Speter int ret; 159238032Speter 159338032Speter *p = '\0'; 159464562Sgshapiro ret = safedirpath(fname, uid, gid, user, 159564562Sgshapiro sfflags|SFF_SAFEDIRPATH, 0, 0); 159638032Speter if (ret == 0) 159738032Speter { 159838032Speter /* in safe directory: relax chown & link rules */ 159990792Sgshapiro safedir = true; 160038032Speter sfflags |= SFF_NOPATHCHECK; 160138032Speter } 160238032Speter else 160338032Speter { 160464562Sgshapiro if (bitnset((forwarding ? 160564562Sgshapiro DBS_FORWARDFILEINUNSAFEDIRPATH : 160664562Sgshapiro DBS_INCLUDEFILEINUNSAFEDIRPATH), 160764562Sgshapiro DontBlameSendmail)) 160838032Speter sfflags |= SFF_NOPATHCHECK; 160964562Sgshapiro else if (bitnset((forwarding ? 161064562Sgshapiro DBS_FORWARDFILEINGROUPWRITABLEDIRPATH : 161164562Sgshapiro DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH), 161264562Sgshapiro DontBlameSendmail) && 161338032Speter ret == E_SM_GWDIR) 161438032Speter { 161564562Sgshapiro setbitn(DBS_GROUPWRITABLEDIRPATHSAFE, 161664562Sgshapiro DontBlameSendmail); 161764562Sgshapiro ret = safedirpath(fname, uid, gid, user, 161864562Sgshapiro sfflags|SFF_SAFEDIRPATH, 161964562Sgshapiro 0, 0); 162064562Sgshapiro clrbitn(DBS_GROUPWRITABLEDIRPATHSAFE, 162164562Sgshapiro DontBlameSendmail); 162238032Speter if (ret == 0) 162338032Speter sfflags |= SFF_NOPATHCHECK; 162438032Speter else 162538032Speter sfflags |= SFF_SAFEDIRPATH; 162638032Speter } 162738032Speter else 162838032Speter sfflags |= SFF_SAFEDIRPATH; 162938032Speter if (ret > E_PSEUDOBASE && 163064562Sgshapiro !bitnset((forwarding ? 163164562Sgshapiro DBS_FORWARDFILEINUNSAFEDIRPATHSAFE : 163264562Sgshapiro DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE), 163364562Sgshapiro DontBlameSendmail)) 163438032Speter { 163590792Sgshapiro if (LogLevel > 11) 163638032Speter sm_syslog(LOG_INFO, e->e_id, 163738032Speter "%s: unsafe directory path, marked unsafe", 163838032Speter shortenstring(fname, MAXSHORTSTR)); 163938032Speter ctladdr->q_flags |= QUNSAFEADDR; 164038032Speter } 164138032Speter } 164238032Speter *p = '/'; 164338032Speter } 164438032Speter 164538032Speter /* allow links only in unwritable directories */ 164638032Speter if (!safedir && 164764562Sgshapiro !bitnset((forwarding ? 164864562Sgshapiro DBS_LINKEDFORWARDFILEINWRITABLEDIR : 164964562Sgshapiro DBS_LINKEDINCLUDEFILEINWRITABLEDIR), 165064562Sgshapiro DontBlameSendmail)) 165138032Speter sfflags |= SFF_NOLINK; 165238032Speter 165364562Sgshapiro rval = safefile(fname, uid, gid, user, sfflags, S_IREAD, &st); 165438032Speter if (rval != 0) 165538032Speter { 165638032Speter /* don't use this :include: file */ 165738032Speter if (tTd(27, 4)) 165890792Sgshapiro sm_dprintf("include: not safe (uid=%d): %s\n", 165990792Sgshapiro (int) uid, sm_errstring(rval)); 166038032Speter } 166190792Sgshapiro else if ((fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, fname, 166290792Sgshapiro SM_IO_RDONLY, NULL)) == NULL) 166338032Speter { 166438032Speter rval = errno; 166538032Speter if (tTd(27, 4)) 166690792Sgshapiro sm_dprintf("include: open: %s\n", sm_errstring(rval)); 166738032Speter } 166890792Sgshapiro else if (filechanged(fname, sm_io_getinfo(fp,SM_IO_WHAT_FD, NULL), &st)) 166938032Speter { 167038032Speter rval = E_SM_FILECHANGE; 167138032Speter if (tTd(27, 4)) 167290792Sgshapiro sm_dprintf("include: file changed after open\n"); 167338032Speter } 167438032Speter if (ev != NULL) 167590792Sgshapiro sm_clrevent(ev); 167638032Speter 167738032Speterresetuid: 167838032Speter 167938032Speter#if HASSETREUID || USESETEUID 168038032Speter if (saveduid == 0) 168138032Speter { 168238032Speter if (uid != 0) 168338032Speter { 168438032Speter# if USESETEUID 168538032Speter if (seteuid(0) < 0) 168664562Sgshapiro syserr("!seteuid(0) failure (real=%d, eff=%d)", 168790792Sgshapiro (int) getuid(), (int) geteuid()); 168864562Sgshapiro# else /* USESETEUID */ 168938032Speter if (setreuid(-1, 0) < 0) 169064562Sgshapiro syserr("!setreuid(-1, 0) failure (real=%d, eff=%d)", 169190792Sgshapiro (int) getuid(), (int) geteuid()); 169238032Speter if (setreuid(RealUid, 0) < 0) 169364562Sgshapiro syserr("!setreuid(%d, 0) failure (real=%d, eff=%d)", 169490792Sgshapiro (int) RealUid, (int) getuid(), 169590792Sgshapiro (int) geteuid()); 169664562Sgshapiro# endif /* USESETEUID */ 169738032Speter } 169864562Sgshapiro if (setgid(savedgid) < 0) 169964562Sgshapiro syserr("!setgid(%d) failure (real=%d eff=%d)", 170090792Sgshapiro (int) savedgid, (int) getgid(), 170190792Sgshapiro (int) getegid()); 170238032Speter } 170364562Sgshapiro#endif /* HASSETREUID || USESETEUID */ 170438032Speter 170538032Speter if (tTd(27, 9)) 170690792Sgshapiro sm_dprintf("include: reset uid = %d/%d\n", 170790792Sgshapiro (int) getuid(), (int) geteuid()); 170838032Speter 170938032Speter if (rval == E_SM_OPENTIMEOUT) 171064562Sgshapiro usrerr("451 4.4.1 open timeout on %s", fname); 171138032Speter 171238032Speter if (fp == NULL) 171338032Speter return rval; 171438032Speter 171590792Sgshapiro if (fstat(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), &st) < 0) 171638032Speter { 171738032Speter rval = errno; 171838032Speter syserr("Cannot fstat %s!", fname); 171990792Sgshapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 172038032Speter return rval; 172138032Speter } 172238032Speter 172338032Speter /* if path was writable, check to avoid file giveaway tricks */ 172490792Sgshapiro safechown = chownsafe(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), safedir); 172538032Speter if (tTd(27, 6)) 172690792Sgshapiro sm_dprintf("include: parent of %s is %s, chown is %ssafe\n", 172790792Sgshapiro fname, safedir ? "safe" : "dangerous", 172890792Sgshapiro safechown ? "" : "un"); 172938032Speter 173064562Sgshapiro /* if no controlling user or coming from an alias delivery */ 173164562Sgshapiro if (safechown && 173264562Sgshapiro (ca == NULL || 173364562Sgshapiro (ca->q_uid == DefUid && ca->q_gid == 0))) 173438032Speter { 173538032Speter ctladdr->q_uid = st.st_uid; 173638032Speter ctladdr->q_gid = st.st_gid; 173738032Speter ctladdr->q_flags |= QGOODUID; 173838032Speter } 173938032Speter if (ca != NULL && ca->q_uid == st.st_uid) 174038032Speter { 174138032Speter /* optimization -- avoid getpwuid if we already have info */ 174238032Speter ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 174338032Speter ctladdr->q_ruser = ca->q_ruser; 174438032Speter } 174538032Speter else if (!forwarding) 174638032Speter { 174738032Speter register struct passwd *pw; 174838032Speter 174938032Speter pw = sm_getpwuid(st.st_uid); 175038032Speter if (pw == NULL) 175164562Sgshapiro { 175264562Sgshapiro ctladdr->q_uid = st.st_uid; 175338032Speter ctladdr->q_flags |= QBOGUSSHELL; 175464562Sgshapiro } 175538032Speter else 175638032Speter { 175738032Speter char *sh; 175838032Speter 175990792Sgshapiro ctladdr->q_ruser = sm_rpool_strdup_x(e->e_rpool, 176090792Sgshapiro pw->pw_name); 176138032Speter if (safechown) 176238032Speter sh = pw->pw_shell; 176338032Speter else 176438032Speter sh = "/SENDMAIL/ANY/SHELL/"; 176538032Speter if (!usershellok(pw->pw_name, sh)) 176638032Speter { 176790792Sgshapiro if (LogLevel > 11) 176838032Speter sm_syslog(LOG_INFO, e->e_id, 176964562Sgshapiro "%s: user %s has bad shell %s, marked %s", 177090792Sgshapiro shortenstring(fname, 177190792Sgshapiro MAXSHORTSTR), 177264562Sgshapiro pw->pw_name, sh, 177364562Sgshapiro safechown ? "bogus" : "unsafe"); 177438032Speter if (safechown) 177538032Speter ctladdr->q_flags |= QBOGUSSHELL; 177638032Speter else 177738032Speter ctladdr->q_flags |= QUNSAFEADDR; 177838032Speter } 177938032Speter } 178038032Speter } 178138032Speter 178238032Speter if (bitset(EF_VRFYONLY, e->e_flags)) 178338032Speter { 178438032Speter /* don't do any more now */ 178564562Sgshapiro ctladdr->q_state = QS_VERIFIED; 178638032Speter e->e_nrcpts++; 178790792Sgshapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 178838032Speter return rval; 178938032Speter } 179038032Speter 179138032Speter /* 179242575Speter ** Check to see if some bad guy can write this file 179338032Speter ** 179438032Speter ** Group write checking could be more clever, e.g., 179538032Speter ** guessing as to which groups are actually safe ("sys" 179638032Speter ** may be; "user" probably is not). 179738032Speter */ 179838032Speter 179938032Speter mode = S_IWOTH; 180064562Sgshapiro if (!bitnset((forwarding ? 180164562Sgshapiro DBS_GROUPWRITABLEFORWARDFILESAFE : 180264562Sgshapiro DBS_GROUPWRITABLEINCLUDEFILESAFE), 180364562Sgshapiro DontBlameSendmail)) 180438032Speter mode |= S_IWGRP; 180538032Speter 180638032Speter if (bitset(mode, st.st_mode)) 180738032Speter { 180838032Speter if (tTd(27, 6)) 180990792Sgshapiro sm_dprintf("include: %s is %s writable, marked unsafe\n", 181090792Sgshapiro shortenstring(fname, MAXSHORTSTR), 181190792Sgshapiro bitset(S_IWOTH, st.st_mode) ? "world" 181290792Sgshapiro : "group"); 181390792Sgshapiro if (LogLevel > 11) 181438032Speter sm_syslog(LOG_INFO, e->e_id, 181564562Sgshapiro "%s: %s writable %s file, marked unsafe", 181664562Sgshapiro shortenstring(fname, MAXSHORTSTR), 181764562Sgshapiro bitset(S_IWOTH, st.st_mode) ? "world" : "group", 181864562Sgshapiro forwarding ? "forward" : ":include:"); 181938032Speter ctladdr->q_flags |= QUNSAFEADDR; 182038032Speter } 182138032Speter 182238032Speter /* read the file -- each line is a comma-separated list. */ 182338032Speter FileName = fname; 182438032Speter LineNumber = 0; 182538032Speter ctladdr->q_flags &= ~QSELFREF; 182638032Speter nincludes = 0; 1827168515Sgshapiro while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL && 182890792Sgshapiro !maxreached) 182938032Speter { 183090792Sgshapiro fixcrlf(buf, true); 183138032Speter LineNumber++; 183238032Speter if (buf[0] == '#' || buf[0] == '\0') 183338032Speter continue; 183438032Speter 183538032Speter /* <sp>#@# introduces a comment anywhere */ 183638032Speter /* for Japanese character sets */ 183738032Speter for (p = buf; (p = strchr(++p, '#')) != NULL; ) 183838032Speter { 183938032Speter if (p[1] == '@' && p[2] == '#' && 184038032Speter isascii(p[-1]) && isspace(p[-1]) && 184138032Speter (p[3] == '\0' || (isascii(p[3]) && isspace(p[3])))) 184238032Speter { 184366494Sgshapiro --p; 184466494Sgshapiro while (p > buf && isascii(p[-1]) && 184566494Sgshapiro isspace(p[-1])) 184666494Sgshapiro --p; 184766494Sgshapiro p[0] = '\0'; 184838032Speter break; 184938032Speter } 185038032Speter } 185138032Speter if (buf[0] == '\0') 185238032Speter continue; 185338032Speter 185438032Speter e->e_to = NULL; 185538032Speter message("%s to %s", 185638032Speter forwarding ? "forwarding" : "sending", buf); 185764562Sgshapiro if (forwarding && LogLevel > 10) 185838032Speter sm_syslog(LOG_INFO, e->e_id, 185964562Sgshapiro "forward %.200s => %s", 186064562Sgshapiro oldto, shortenstring(buf, MAXSHORTSTR)); 186138032Speter 186238032Speter nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); 186364562Sgshapiro 186464562Sgshapiro if (forwarding && 186564562Sgshapiro MaxForwardEntries > 0 && 186664562Sgshapiro nincludes >= MaxForwardEntries) 186764562Sgshapiro { 186864562Sgshapiro /* just stop reading and processing further entries */ 186990792Sgshapiro#if 0 187090792Sgshapiro /* additional: (?) */ 187164562Sgshapiro ctladdr->q_state = QS_DONTSEND; 187290792Sgshapiro#endif /* 0 */ 187390792Sgshapiro 187490792Sgshapiro syserr("Attempt to forward to more than %d addresses (in %s)!", 187598121Sgshapiro MaxForwardEntries, fname); 187690792Sgshapiro maxreached = true; 187764562Sgshapiro } 187838032Speter } 187938032Speter 188090792Sgshapiro if (sm_io_error(fp) && tTd(27, 3)) 188190792Sgshapiro sm_dprintf("include: read error: %s\n", sm_errstring(errno)); 188238032Speter if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 188338032Speter { 1884168515Sgshapiro if (aliaslevel <= MaxAliasRecursion || 1885168515Sgshapiro ctladdr->q_state != QS_BADADDR) 188638032Speter { 1887168515Sgshapiro ctladdr->q_state = QS_DONTSEND; 1888168515Sgshapiro if (tTd(27, 5)) 1889168515Sgshapiro { 1890168515Sgshapiro sm_dprintf("include: QS_DONTSEND "); 1891168515Sgshapiro printaddr(sm_debug_file(), ctladdr, false); 1892168515Sgshapiro } 189338032Speter } 189438032Speter } 189538032Speter 189690792Sgshapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 189738032Speter FileName = oldfilename; 189838032Speter LineNumber = oldlinenumber; 189938032Speter e->e_to = oldto; 190038032Speter return rval; 190138032Speter} 190238032Speter 190338032Speterstatic void 1904141858Sgshapiroincludetimeout(ignore) 1905141858Sgshapiro int ignore; 190638032Speter{ 190777349Sgshapiro /* 190877349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 190977349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 191077349Sgshapiro ** DOING. 191177349Sgshapiro */ 191277349Sgshapiro 191377349Sgshapiro errno = ETIMEDOUT; 191438032Speter longjmp(CtxIncludeTimeout, 1); 191538032Speter} 1916168515Sgshapiro 191790792Sgshapiro/* 191838032Speter** SENDTOARGV -- send to an argument vector. 191938032Speter** 192038032Speter** Parameters: 192138032Speter** argv -- argument vector to send to. 192238032Speter** e -- the current envelope. 192338032Speter** 192438032Speter** Returns: 192538032Speter** none. 192638032Speter** 192738032Speter** Side Effects: 192838032Speter** puts all addresses on the argument vector onto the 192938032Speter** send queue. 193038032Speter*/ 193138032Speter 193238032Spetervoid 193338032Spetersendtoargv(argv, e) 193438032Speter register char **argv; 193538032Speter register ENVELOPE *e; 193638032Speter{ 193738032Speter register char *p; 193838032Speter 193938032Speter while ((p = *argv++) != NULL) 194038032Speter (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e); 194138032Speter} 1942168515Sgshapiro 194390792Sgshapiro/* 194438032Speter** GETCTLADDR -- get controlling address from an address header. 194538032Speter** 194638032Speter** If none, get one corresponding to the effective userid. 194738032Speter** 194838032Speter** Parameters: 194938032Speter** a -- the address to find the controller of. 195038032Speter** 195138032Speter** Returns: 195238032Speter** the controlling address. 195338032Speter*/ 195438032Speter 195538032SpeterADDRESS * 195638032Spetergetctladdr(a) 195738032Speter register ADDRESS *a; 195838032Speter{ 195938032Speter while (a != NULL && !bitset(QGOODUID, a->q_flags)) 196038032Speter a = a->q_alias; 196164562Sgshapiro return a; 196238032Speter} 1963168515Sgshapiro 196490792Sgshapiro/* 196538032Speter** SELF_REFERENCE -- check to see if an address references itself 196638032Speter** 196738032Speter** The check is done through a chain of aliases. If it is part of 196838032Speter** a loop, break the loop at the "best" address, that is, the one 196938032Speter** that exists as a real user. 197038032Speter** 197138032Speter** This is to handle the case of: 197238032Speter** awc: Andrew.Chang 197338032Speter** Andrew.Chang: awc@mail.server 197438032Speter** which is a problem only on mail.server. 197538032Speter** 197638032Speter** Parameters: 197738032Speter** a -- the address to check. 197838032Speter** 197938032Speter** Returns: 198038032Speter** The address that should be retained. 198138032Speter*/ 198238032Speter 198364562Sgshapirostatic ADDRESS * 198464562Sgshapiroself_reference(a) 198538032Speter ADDRESS *a; 198638032Speter{ 198738032Speter ADDRESS *b; /* top entry in self ref loop */ 198838032Speter ADDRESS *c; /* entry that point to a real mail box */ 198938032Speter 199038032Speter if (tTd(27, 1)) 199190792Sgshapiro sm_dprintf("self_reference(%s)\n", a->q_paddr); 199238032Speter 199338032Speter for (b = a->q_alias; b != NULL; b = b->q_alias) 199438032Speter { 199538032Speter if (sameaddr(a, b)) 199638032Speter break; 199738032Speter } 199838032Speter 199938032Speter if (b == NULL) 200038032Speter { 200138032Speter if (tTd(27, 1)) 200290792Sgshapiro sm_dprintf("\t... no self ref\n"); 200338032Speter return NULL; 200438032Speter } 200538032Speter 200638032Speter /* 200738032Speter ** Pick the first address that resolved to a real mail box 200890792Sgshapiro ** i.e has a mbdb entry. The returned value will be marked 200938032Speter ** QSELFREF in recipient(), which in turn will disable alias() 201064562Sgshapiro ** from marking it as QS_IS_DEAD(), which mean it will be used 201138032Speter ** as a deliverable address. 201238032Speter ** 201338032Speter ** The 2 key thing to note here are: 201438032Speter ** 1) we are in a recursive call sequence: 201590792Sgshapiro ** alias->sendtolist->recipient->alias 201638032Speter ** 2) normally, when we return back to alias(), the address 201764562Sgshapiro ** will be marked QS_EXPANDED, since alias() assumes the 201838032Speter ** expanded form will be used instead of the current address. 201938032Speter ** This behaviour is turned off if the address is marked 202090792Sgshapiro ** QSELFREF. We set QSELFREF when we return to recipient(). 202138032Speter */ 202238032Speter 202338032Speter c = a; 202438032Speter while (c != NULL) 202538032Speter { 202643730Speter if (tTd(27, 10)) 202790792Sgshapiro sm_dprintf(" %s", c->q_user); 202838032Speter if (bitnset(M_HASPWENT, c->q_mailer->m_flags)) 202938032Speter { 203090792Sgshapiro SM_MBDB_T user; 203190792Sgshapiro 203238032Speter if (tTd(27, 2)) 203390792Sgshapiro sm_dprintf("\t... getpwnam(%s)... ", c->q_user); 203490792Sgshapiro if (sm_mbdb_lookup(c->q_user, &user) == EX_OK) 203538032Speter { 203638032Speter if (tTd(27, 2)) 203790792Sgshapiro sm_dprintf("found\n"); 203838032Speter 203938032Speter /* ought to cache results here */ 204038032Speter if (sameaddr(b, c)) 204138032Speter return b; 204238032Speter else 204338032Speter return c; 204438032Speter } 204538032Speter if (tTd(27, 2)) 204690792Sgshapiro sm_dprintf("failed\n"); 204738032Speter } 204843730Speter else 204943730Speter { 205043730Speter /* if local delivery, compare usernames */ 205143730Speter if (bitnset(M_LOCALMAILER, c->q_mailer->m_flags) && 205243730Speter b->q_mailer == c->q_mailer) 205343730Speter { 205443730Speter if (tTd(27, 2)) 205590792Sgshapiro sm_dprintf("\t... local match (%s)\n", 205664562Sgshapiro c->q_user); 205743730Speter if (sameaddr(b, c)) 205843730Speter return b; 205943730Speter else 206043730Speter return c; 206143730Speter } 206243730Speter } 206343730Speter if (tTd(27, 10)) 206490792Sgshapiro sm_dprintf("\n"); 206538032Speter c = c->q_alias; 206638032Speter } 206738032Speter 206838032Speter if (tTd(27, 1)) 206990792Sgshapiro sm_dprintf("\t... cannot break loop for \"%s\"\n", a->q_paddr); 207038032Speter 207138032Speter return NULL; 207238032Speter} 2073