recipient.c revision 132943
138032Speter/* 2125820Sgshapiro * Copyright (c) 1998-2003 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 16132943SgshapiroSM_RCSID("@(#)$Id: recipient.c,v 8.336 2004/07/23 20:45:02 gshapiro Exp $") 1764562Sgshapiro 1864562Sgshapirostatic void includetimeout __P((void)); 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; 20338032Speter if (i <= sizeof buf) 20464562Sgshapiro { 20538032Speter bufp = buf; 20664562Sgshapiro 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} 31290792Sgshapiro#if MILTER 31390792Sgshapiro/* 31464562Sgshapiro** REMOVEFROMLIST -- Remove addresses from a send list. 31564562Sgshapiro** 31664562Sgshapiro** The parameter is a comma-separated list of recipients to remove. 31764562Sgshapiro** Note that it only deletes matching addresses. If those addresses 31890792Sgshapiro** have been expanded already in the sendq, it won't mark the 31964562Sgshapiro** expanded recipients as QS_REMOVED. 32064562Sgshapiro** 32164562Sgshapiro** Parameters: 32264562Sgshapiro** list -- the list to remove. 32364562Sgshapiro** sendq -- a pointer to the head of a queue to remove 32464562Sgshapiro** these addresses from. 32564562Sgshapiro** e -- the envelope in which to remove these recipients. 32664562Sgshapiro** 32764562Sgshapiro** Returns: 32864562Sgshapiro** The number of addresses removed from the list. 32964562Sgshapiro** 33064562Sgshapiro*/ 33164562Sgshapiro 33264562Sgshapiroint 33364562Sgshapiroremovefromlist(list, sendq, e) 33464562Sgshapiro char *list; 33564562Sgshapiro ADDRESS **sendq; 33664562Sgshapiro ENVELOPE *e; 33764562Sgshapiro{ 33890792Sgshapiro SM_NONVOLATILE char delimiter; /* the address delimiter */ 33990792Sgshapiro SM_NONVOLATILE int naddrs; 34090792Sgshapiro SM_NONVOLATILE int i; 34164562Sgshapiro char *p; 34264562Sgshapiro char *oldto = e->e_to; 34390792Sgshapiro char *SM_NONVOLATILE bufp; 34464562Sgshapiro char buf[MAXNAME + 1]; 34564562Sgshapiro 34664562Sgshapiro if (list == NULL) 34764562Sgshapiro { 34864562Sgshapiro syserr("removefromlist: null list"); 34964562Sgshapiro return 0; 35064562Sgshapiro } 35164562Sgshapiro 35264562Sgshapiro if (tTd(25, 1)) 35390792Sgshapiro sm_dprintf("removefromlist: %s\n", list); 35464562Sgshapiro 35564562Sgshapiro /* heuristic to determine old versus new style addresses */ 35664562Sgshapiro if (strchr(list, ',') != NULL || strchr(list, ';') != NULL || 35764562Sgshapiro strchr(list, '<') != NULL || strchr(list, '(') != NULL) 35864562Sgshapiro e->e_flags &= ~EF_OLDSTYLE; 35964562Sgshapiro delimiter = ' '; 36064562Sgshapiro if (!bitset(EF_OLDSTYLE, e->e_flags)) 36164562Sgshapiro delimiter = ','; 36264562Sgshapiro 36364562Sgshapiro naddrs = 0; 36464562Sgshapiro 36564562Sgshapiro /* make sure we have enough space to copy the string */ 36664562Sgshapiro i = strlen(list) + 1; 36764562Sgshapiro if (i <= sizeof buf) 36864562Sgshapiro { 36964562Sgshapiro bufp = buf; 37064562Sgshapiro i = sizeof buf; 37164562Sgshapiro } 37264562Sgshapiro else 37390792Sgshapiro bufp = sm_malloc_x(i); 37464562Sgshapiro 37590792Sgshapiro SM_TRY 37664562Sgshapiro { 37790792Sgshapiro (void) sm_strlcpy(bufp, denlstring(list, false, true), i); 37864562Sgshapiro 37990792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 38090792Sgshapiro for (p = bufp; *p != '\0'; ) 38164562Sgshapiro { 38290792Sgshapiro ADDRESS a; /* parsed address to be removed */ 38390792Sgshapiro ADDRESS *q; 38490792Sgshapiro ADDRESS **pq; 38590792Sgshapiro char *delimptr; 38690792Sgshapiro 38790792Sgshapiro /* parse the address */ 38890792Sgshapiro while ((isascii(*p) && isspace(*p)) || *p == ',') 38990792Sgshapiro p++; 39090792Sgshapiro if (parseaddr(p, &a, RF_COPYALL, 39190792Sgshapiro delimiter, &delimptr, e, true) == NULL) 39290792Sgshapiro { 39390792Sgshapiro p = delimptr; 39490792Sgshapiro continue; 39590792Sgshapiro } 39664562Sgshapiro p = delimptr; 39790792Sgshapiro for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 39864562Sgshapiro { 39990792Sgshapiro if (!QS_IS_DEAD(q->q_state) && 400125820Sgshapiro (sameaddr(q, &a) || 401125820Sgshapiro strcmp(q->q_paddr, a.q_paddr) == 0)) 40264562Sgshapiro { 40390792Sgshapiro if (tTd(25, 5)) 40490792Sgshapiro { 40590792Sgshapiro sm_dprintf("removefromlist: QS_REMOVED "); 406132943Sgshapiro printaddr(sm_debug_file(), &a, false); 40790792Sgshapiro } 40890792Sgshapiro q->q_state = QS_REMOVED; 40990792Sgshapiro naddrs++; 41090792Sgshapiro break; 41164562Sgshapiro } 41264562Sgshapiro } 41364562Sgshapiro } 41464562Sgshapiro } 41590792Sgshapiro SM_FINALLY 41690792Sgshapiro { 41790792Sgshapiro e->e_to = oldto; 41890792Sgshapiro if (bufp != buf) 41990792Sgshapiro sm_free(bufp); 42090792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL); 42190792Sgshapiro } 42290792Sgshapiro SM_END_TRY 42364562Sgshapiro return naddrs; 42464562Sgshapiro} 42590792Sgshapiro#endif /* MILTER */ 42690792Sgshapiro/* 42738032Speter** RECIPIENT -- Designate a message recipient 42838032Speter** 42938032Speter** Saves the named person for future mailing. 43038032Speter** 43138032Speter** Parameters: 43290792Sgshapiro** new -- the (preparsed) address header for the recipient. 43338032Speter** sendq -- a pointer to the head of a queue to put the 43464562Sgshapiro** recipient in. Duplicate suppression is done 43538032Speter** in this queue. 43638032Speter** aliaslevel -- the current alias nesting depth. 43738032Speter** e -- the current envelope. 43838032Speter** 43938032Speter** Returns: 44038032Speter** The actual address in the queue. This will be "a" if 44138032Speter** the address is not a duplicate, else the original address. 44238032Speter** 44338032Speter*/ 44438032Speter 44538032SpeterADDRESS * 44690792Sgshapirorecipient(new, sendq, aliaslevel, e) 44790792Sgshapiro register ADDRESS *new; 44838032Speter register ADDRESS **sendq; 44938032Speter int aliaslevel; 45038032Speter register ENVELOPE *e; 45138032Speter{ 45238032Speter register ADDRESS *q; 45338032Speter ADDRESS **pq; 45490792Sgshapiro ADDRESS **prev; 45538032Speter register struct mailer *m; 45690792Sgshapiro register char *p; 45764562Sgshapiro int i, buflen; 45890792Sgshapiro bool quoted; /* set if the addr has a quote bit */ 45990792Sgshapiro bool insert; 46090792Sgshapiro int findusercount; 46190792Sgshapiro bool initialdontsend; 46238032Speter char *buf; 46338032Speter char buf0[MAXNAME + 1]; /* unquoted image of the user name */ 46490792Sgshapiro sortfn_t *sortfn; 46538032Speter 46690792Sgshapiro p = NULL; 46790792Sgshapiro quoted = false; 46890792Sgshapiro insert = false; 46990792Sgshapiro findusercount = 0; 47090792Sgshapiro initialdontsend = QS_IS_DEAD(new->q_state); 47190792Sgshapiro e->e_to = new->q_paddr; 47290792Sgshapiro m = new->q_mailer; 47338032Speter errno = 0; 47438032Speter if (aliaslevel == 0) 47590792Sgshapiro new->q_flags |= QPRIMARY; 47638032Speter if (tTd(26, 1)) 47738032Speter { 47890792Sgshapiro sm_dprintf("\nrecipient (%d): ", aliaslevel); 479132943Sgshapiro printaddr(sm_debug_file(), new, false); 48038032Speter } 48138032Speter 48290792Sgshapiro /* if this is primary, use it as original recipient */ 48390792Sgshapiro if (new->q_alias == NULL) 48438032Speter { 48538032Speter if (e->e_origrcpt == NULL) 48690792Sgshapiro e->e_origrcpt = new->q_paddr; 48790792Sgshapiro else if (e->e_origrcpt != new->q_paddr) 48838032Speter e->e_origrcpt = ""; 48938032Speter } 49038032Speter 49190792Sgshapiro /* find parent recipient for finalrcpt and orcpt */ 49290792Sgshapiro for (q = new; q->q_alias != NULL; q = q->q_alias) 49390792Sgshapiro continue; 49490792Sgshapiro 49590792Sgshapiro /* find final recipient DSN address */ 49690792Sgshapiro if (new->q_finalrcpt == NULL && 49790792Sgshapiro e->e_from.q_mailer != NULL) 49890792Sgshapiro { 49990792Sgshapiro char frbuf[MAXLINE]; 50090792Sgshapiro 50190792Sgshapiro p = e->e_from.q_mailer->m_addrtype; 50290792Sgshapiro if (p == NULL) 50390792Sgshapiro p = "rfc822"; 50490792Sgshapiro if (sm_strcasecmp(p, "rfc822") != 0) 50590792Sgshapiro { 50690792Sgshapiro (void) sm_snprintf(frbuf, sizeof frbuf, "%s; %.800s", 50790792Sgshapiro q->q_mailer->m_addrtype, 50890792Sgshapiro q->q_user); 50990792Sgshapiro } 51090792Sgshapiro else if (strchr(q->q_user, '@') != NULL) 51190792Sgshapiro { 51290792Sgshapiro (void) sm_snprintf(frbuf, sizeof frbuf, "%s; %.800s", 51390792Sgshapiro p, q->q_user); 51490792Sgshapiro } 51590792Sgshapiro else if (strchr(q->q_paddr, '@') != NULL) 51690792Sgshapiro { 51790792Sgshapiro char *qp; 51890792Sgshapiro bool b; 51990792Sgshapiro 52090792Sgshapiro qp = q->q_paddr; 52190792Sgshapiro 52290792Sgshapiro /* strip brackets from address */ 52390792Sgshapiro b = false; 52490792Sgshapiro if (*qp == '<') 52590792Sgshapiro { 52690792Sgshapiro b = qp[strlen(qp) - 1] == '>'; 52790792Sgshapiro if (b) 52890792Sgshapiro qp[strlen(qp) - 1] = '\0'; 52990792Sgshapiro qp++; 53090792Sgshapiro } 53190792Sgshapiro (void) sm_snprintf(frbuf, sizeof frbuf, "%s; %.800s", 53290792Sgshapiro p, qp); 53390792Sgshapiro 53490792Sgshapiro /* undo damage */ 53590792Sgshapiro if (b) 53690792Sgshapiro qp[strlen(qp)] = '>'; 53790792Sgshapiro } 53890792Sgshapiro else 53990792Sgshapiro { 54090792Sgshapiro (void) sm_snprintf(frbuf, sizeof frbuf, 54190792Sgshapiro "%s; %.700s@%.100s", 54290792Sgshapiro p, q->q_user, MyHostName); 54390792Sgshapiro } 54490792Sgshapiro new->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool, frbuf); 54590792Sgshapiro } 54690792Sgshapiro 54764562Sgshapiro#if _FFR_GEN_ORCPT 54864562Sgshapiro /* set ORCPT DSN arg if not already set */ 54990792Sgshapiro if (new->q_orcpt == NULL) 55064562Sgshapiro { 55164562Sgshapiro /* check for an existing ORCPT */ 55264562Sgshapiro if (q->q_orcpt != NULL) 55390792Sgshapiro new->q_orcpt = q->q_orcpt; 55464562Sgshapiro else 55564562Sgshapiro { 55664562Sgshapiro /* make our own */ 55790792Sgshapiro bool b = false; 55864562Sgshapiro char *qp; 55964562Sgshapiro char obuf[MAXLINE]; 56064562Sgshapiro 56164562Sgshapiro if (e->e_from.q_mailer != NULL) 56264562Sgshapiro p = e->e_from.q_mailer->m_addrtype; 56364562Sgshapiro if (p == NULL) 56464562Sgshapiro p = "rfc822"; 56590792Sgshapiro (void) sm_strlcpyn(obuf, sizeof obuf, 2, p, ";"); 56664562Sgshapiro 56764562Sgshapiro qp = q->q_paddr; 56864562Sgshapiro 56964562Sgshapiro /* FFR: Needs to strip comments from stdin addrs */ 57064562Sgshapiro 57164562Sgshapiro /* strip brackets from address */ 57264562Sgshapiro if (*qp == '<') 57364562Sgshapiro { 57464562Sgshapiro b = qp[strlen(qp) - 1] == '>'; 57564562Sgshapiro if (b) 57664562Sgshapiro qp[strlen(qp) - 1] = '\0'; 57764562Sgshapiro qp++; 57864562Sgshapiro } 57964562Sgshapiro 58090792Sgshapiro p = xtextify(denlstring(qp, true, false), NULL); 58164562Sgshapiro 58290792Sgshapiro if (sm_strlcat(obuf, p, sizeof obuf) >= sizeof obuf) 58364562Sgshapiro { 58464562Sgshapiro /* if too big, don't use it */ 58564562Sgshapiro obuf[0] = '\0'; 58664562Sgshapiro } 58764562Sgshapiro 58864562Sgshapiro /* undo damage */ 58964562Sgshapiro if (b) 59064562Sgshapiro qp[strlen(qp)] = '>'; 59164562Sgshapiro 59264562Sgshapiro if (obuf[0] != '\0') 59390792Sgshapiro new->q_orcpt = 59490792Sgshapiro sm_rpool_strdup_x(e->e_rpool, obuf); 59564562Sgshapiro } 59664562Sgshapiro } 59764562Sgshapiro#endif /* _FFR_GEN_ORCPT */ 59864562Sgshapiro 59938032Speter /* break aliasing loops */ 60038032Speter if (aliaslevel > MaxAliasRecursion) 60138032Speter { 60290792Sgshapiro new->q_state = QS_BADADDR; 60390792Sgshapiro new->q_status = "5.4.6"; 60490792Sgshapiro usrerrenh(new->q_status, 60564562Sgshapiro "554 aliasing/forwarding loop broken (%d aliases deep; %d max)", 60664562Sgshapiro aliaslevel, MaxAliasRecursion); 60790792Sgshapiro return new; 60838032Speter } 60938032Speter 61038032Speter /* 61138032Speter ** Finish setting up address structure. 61238032Speter */ 61338032Speter 61438032Speter /* get unquoted user for file, program or user.name check */ 61590792Sgshapiro i = strlen(new->q_user); 61638032Speter if (i >= sizeof buf0) 61764562Sgshapiro { 61864562Sgshapiro buflen = i + 1; 61964562Sgshapiro buf = xalloc(buflen); 62064562Sgshapiro } 62138032Speter else 62264562Sgshapiro { 62338032Speter buf = buf0; 62464562Sgshapiro buflen = sizeof buf0; 62564562Sgshapiro } 62690792Sgshapiro (void) sm_strlcpy(buf, new->q_user, buflen); 62738032Speter for (p = buf; *p != '\0' && !quoted; p++) 62838032Speter { 62938032Speter if (*p == '\\') 63090792Sgshapiro quoted = true; 63138032Speter } 63238032Speter stripquotes(buf); 63338032Speter 63438032Speter /* check for direct mailing to restricted mailers */ 63538032Speter if (m == ProgMailer) 63638032Speter { 63790792Sgshapiro if (new->q_alias == NULL || UseMSP || 63890792Sgshapiro bitset(EF_UNSAFE, e->e_flags)) 63938032Speter { 64090792Sgshapiro new->q_state = QS_BADADDR; 64190792Sgshapiro new->q_status = "5.7.1"; 64290792Sgshapiro usrerrenh(new->q_status, 64364562Sgshapiro "550 Cannot mail directly to programs"); 64438032Speter } 64590792Sgshapiro else if (bitset(QBOGUSSHELL, new->q_alias->q_flags)) 64638032Speter { 64790792Sgshapiro new->q_state = QS_BADADDR; 64890792Sgshapiro new->q_status = "5.7.1"; 64990792Sgshapiro if (new->q_alias->q_ruser == NULL) 65090792Sgshapiro usrerrenh(new->q_status, 65164562Sgshapiro "550 UID %d is an unknown user: cannot mail to programs", 65290792Sgshapiro new->q_alias->q_uid); 65338032Speter else 65490792Sgshapiro usrerrenh(new->q_status, 65564562Sgshapiro "550 User %s@%s doesn't have a valid shell for mailing to programs", 65690792Sgshapiro new->q_alias->q_ruser, MyHostName); 65738032Speter } 65890792Sgshapiro else if (bitset(QUNSAFEADDR, new->q_alias->q_flags)) 65938032Speter { 66090792Sgshapiro new->q_state = QS_BADADDR; 66190792Sgshapiro new->q_status = "5.7.1"; 66290792Sgshapiro new->q_rstatus = "550 Unsafe for mailing to programs"; 66390792Sgshapiro usrerrenh(new->q_status, 66464562Sgshapiro "550 Address %s is unsafe for mailing to programs", 66590792Sgshapiro new->q_alias->q_paddr); 66638032Speter } 66738032Speter } 66838032Speter 66938032Speter /* 67038032Speter ** Look up this person in the recipient list. 67138032Speter ** If they are there already, return, otherwise continue. 67238032Speter ** If the list is empty, just add it. Notice the cute 67338032Speter ** hack to make from addresses suppress things correctly: 67464562Sgshapiro ** the QS_DUPLICATE state will be set in the send list. 67538032Speter ** [Please note: the emphasis is on "hack."] 67638032Speter */ 67738032Speter 67890792Sgshapiro prev = NULL; 67990792Sgshapiro 68090792Sgshapiro /* 68190792Sgshapiro ** If this message is going to the queue or FastSplit is set 68290792Sgshapiro ** and it is the first try and the envelope hasn't split, then we 68390792Sgshapiro ** avoid doing an MX RR lookup now because one will be done when the 68490792Sgshapiro ** message is extracted from the queue later. It can go to the queue 68590792Sgshapiro ** because all messages are going to the queue or this mailer of 68690792Sgshapiro ** the current recipient is marked expensive. 68790792Sgshapiro */ 68890792Sgshapiro 689110560Sgshapiro if (UseMSP || WILL_BE_QUEUED(e->e_sendmode) || 69090792Sgshapiro (!bitset(EF_SPLIT, e->e_flags) && e->e_ntries == 0 && 69190792Sgshapiro FastSplit > 0)) 69290792Sgshapiro sortfn = sorthost; 69390792Sgshapiro else if (NoConnect && bitnset(M_EXPENSIVE, new->q_mailer->m_flags)) 69490792Sgshapiro sortfn = sortexpensive; 69590792Sgshapiro else 69690792Sgshapiro sortfn = sortbysignature; 69790792Sgshapiro 69838032Speter for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 69938032Speter { 70090792Sgshapiro /* 70190792Sgshapiro ** If address is "less than" it should be inserted now. 70290792Sgshapiro ** If address is "greater than" current comparison it'll 70390792Sgshapiro ** insert later in the list; so loop again (if possible). 70490792Sgshapiro ** If address is "equal" (different equal than sameaddr() 70590792Sgshapiro ** call) then check if sameaddr() will be true. 70690792Sgshapiro ** Because this list is now sorted, it'll mean fewer 70790792Sgshapiro ** comparisons and fewer loops which is important for more 70890792Sgshapiro ** recipients. 70990792Sgshapiro */ 71090792Sgshapiro 71190792Sgshapiro i = (*sortfn)(new, q); 71290792Sgshapiro if (i == 0) /* equal */ 71338032Speter { 71490792Sgshapiro /* 71590792Sgshapiro ** Sortbysignature() has said that the two have 71690792Sgshapiro ** equal MX RR's and the same user. Calling sameaddr() 71790792Sgshapiro ** now checks if the two hosts are as identical as the 71890792Sgshapiro ** MX RR's are (which might not be the case) 71990792Sgshapiro ** before saying these are the identical addresses. 72090792Sgshapiro */ 72190792Sgshapiro 72290792Sgshapiro if (sameaddr(q, new) && 72390792Sgshapiro (bitset(QRCPTOK, q->q_flags) || 72490792Sgshapiro !bitset(QPRIMARY, q->q_flags))) 72538032Speter { 72690792Sgshapiro if (tTd(26, 1)) 72790792Sgshapiro { 72890792Sgshapiro sm_dprintf("%s in sendq: ", 72990792Sgshapiro new->q_paddr); 730132943Sgshapiro printaddr(sm_debug_file(), q, false); 73190792Sgshapiro } 73290792Sgshapiro if (!bitset(QPRIMARY, q->q_flags)) 73390792Sgshapiro { 73490792Sgshapiro if (!QS_IS_DEAD(new->q_state)) 73590792Sgshapiro message("duplicate suppressed"); 73690792Sgshapiro else 73790792Sgshapiro q->q_state = QS_DUPLICATE; 73890792Sgshapiro q->q_flags |= new->q_flags; 73990792Sgshapiro } 74090792Sgshapiro else if (bitset(QSELFREF, q->q_flags) 74190792Sgshapiro || q->q_state == QS_REMOVED) 74290792Sgshapiro { 74390792Sgshapiro /* 74490792Sgshapiro ** If an earlier milter removed the 74590792Sgshapiro ** address, a later one can still add 74690792Sgshapiro ** it back. 74790792Sgshapiro */ 74890792Sgshapiro 74990792Sgshapiro q->q_state = new->q_state; 75090792Sgshapiro q->q_flags |= new->q_flags; 75190792Sgshapiro } 75290792Sgshapiro new = q; 75390792Sgshapiro goto done; 75438032Speter } 75538032Speter } 75690792Sgshapiro else if (i < 0) /* less than */ 75790792Sgshapiro { 75890792Sgshapiro insert = true; 75990792Sgshapiro break; 76090792Sgshapiro } 76190792Sgshapiro prev = pq; 76238032Speter } 76338032Speter 76490792Sgshapiro /* pq should point to an address, never NULL */ 76590792Sgshapiro SM_ASSERT(pq != NULL); 76690792Sgshapiro 76738032Speter /* add address on list */ 76890792Sgshapiro if (insert) 76942575Speter { 77090792Sgshapiro /* 77190792Sgshapiro ** insert before 'pq'. Only possible when at least 1 77290792Sgshapiro ** ADDRESS is in the list already. 77390792Sgshapiro */ 77490792Sgshapiro 77590792Sgshapiro new->q_next = *pq; 77690792Sgshapiro if (prev == NULL) 77790792Sgshapiro *sendq = new; /* To be the first ADDRESS */ 77890792Sgshapiro else 77990792Sgshapiro (*prev)->q_next = new; 78042575Speter } 78190792Sgshapiro else 78290792Sgshapiro { 78390792Sgshapiro /* 78490792Sgshapiro ** Place in list at current 'pq' position. Possible 78590792Sgshapiro ** when there are 0 or more ADDRESS's in the list. 78690792Sgshapiro */ 78738032Speter 78890792Sgshapiro new->q_next = NULL; 78990792Sgshapiro *pq = new; 79090792Sgshapiro } 79190792Sgshapiro 79290792Sgshapiro /* added a new address: clear split flag */ 79390792Sgshapiro e->e_flags &= ~EF_SPLIT; 79490792Sgshapiro 79538032Speter /* 79638032Speter ** Alias the name and handle special mailer types. 79738032Speter */ 79838032Speter 79938032Speter trylocaluser: 80038032Speter if (tTd(29, 7)) 80142575Speter { 80290792Sgshapiro sm_dprintf("at trylocaluser: "); 803132943Sgshapiro printaddr(sm_debug_file(), new, false); 80442575Speter } 80538032Speter 80690792Sgshapiro if (!QS_IS_OK(new->q_state)) 80790792Sgshapiro { 80890792Sgshapiro if (QS_IS_UNDELIVERED(new->q_state)) 80990792Sgshapiro e->e_nrcpts++; 81038032Speter goto testselfdestruct; 81190792Sgshapiro } 81238032Speter 81338032Speter if (m == InclMailer) 81438032Speter { 81590792Sgshapiro new->q_state = QS_INCLUDED; 81690792Sgshapiro if (new->q_alias == NULL || UseMSP || 81790792Sgshapiro bitset(EF_UNSAFE, e->e_flags)) 81838032Speter { 81990792Sgshapiro new->q_state = QS_BADADDR; 82090792Sgshapiro new->q_status = "5.7.1"; 82190792Sgshapiro usrerrenh(new->q_status, 82264562Sgshapiro "550 Cannot mail directly to :include:s"); 82338032Speter } 82438032Speter else 82538032Speter { 82638032Speter int ret; 82738032Speter 82890792Sgshapiro message("including file %s", new->q_user); 82990792Sgshapiro ret = include(new->q_user, false, new, 83090792Sgshapiro sendq, aliaslevel, e); 83138032Speter if (transienterror(ret)) 83238032Speter { 83338032Speter if (LogLevel > 2) 83438032Speter sm_syslog(LOG_ERR, e->e_id, 83564562Sgshapiro "include %s: transient error: %s", 83690792Sgshapiro shortenstring(new->q_user, 83790792Sgshapiro MAXSHORTSTR), 83890792Sgshapiro sm_errstring(ret)); 83990792Sgshapiro new->q_state = QS_QUEUEUP; 84064562Sgshapiro usrerr("451 4.2.4 Cannot open %s: %s", 84190792Sgshapiro shortenstring(new->q_user, 84290792Sgshapiro MAXSHORTSTR), 84390792Sgshapiro sm_errstring(ret)); 84438032Speter } 84538032Speter else if (ret != 0) 84638032Speter { 84790792Sgshapiro new->q_state = QS_BADADDR; 84890792Sgshapiro new->q_status = "5.2.4"; 84990792Sgshapiro usrerrenh(new->q_status, 85064562Sgshapiro "550 Cannot open %s: %s", 85190792Sgshapiro shortenstring(new->q_user, 85290792Sgshapiro MAXSHORTSTR), 85390792Sgshapiro sm_errstring(ret)); 85438032Speter } 85538032Speter } 85638032Speter } 85738032Speter else if (m == FileMailer) 85838032Speter { 85990792Sgshapiro /* check if allowed */ 86090792Sgshapiro if (new->q_alias == NULL || UseMSP || 86190792Sgshapiro bitset(EF_UNSAFE, e->e_flags)) 86238032Speter { 86390792Sgshapiro new->q_state = QS_BADADDR; 86490792Sgshapiro new->q_status = "5.7.1"; 86590792Sgshapiro usrerrenh(new->q_status, 86664562Sgshapiro "550 Cannot mail directly to files"); 86738032Speter } 86890792Sgshapiro else if (bitset(QBOGUSSHELL, new->q_alias->q_flags)) 86938032Speter { 87090792Sgshapiro new->q_state = QS_BADADDR; 87190792Sgshapiro new->q_status = "5.7.1"; 87290792Sgshapiro if (new->q_alias->q_ruser == NULL) 87390792Sgshapiro usrerrenh(new->q_status, 87464562Sgshapiro "550 UID %d is an unknown user: cannot mail to files", 87590792Sgshapiro new->q_alias->q_uid); 87638032Speter else 87790792Sgshapiro usrerrenh(new->q_status, 87864562Sgshapiro "550 User %s@%s doesn't have a valid shell for mailing to files", 87990792Sgshapiro new->q_alias->q_ruser, MyHostName); 88038032Speter } 88190792Sgshapiro else if (bitset(QUNSAFEADDR, new->q_alias->q_flags)) 88238032Speter { 88390792Sgshapiro new->q_state = QS_BADADDR; 88490792Sgshapiro new->q_status = "5.7.1"; 88590792Sgshapiro new->q_rstatus = "550 Unsafe for mailing to files"; 88690792Sgshapiro usrerrenh(new->q_status, 88764562Sgshapiro "550 Address %s is unsafe for mailing to files", 88890792Sgshapiro new->q_alias->q_paddr); 88938032Speter } 89038032Speter } 89138032Speter 89238032Speter /* try aliasing */ 89390792Sgshapiro if (!quoted && QS_IS_OK(new->q_state) && 89438032Speter bitnset(M_ALIASABLE, m->m_flags)) 89590792Sgshapiro alias(new, sendq, aliaslevel, e); 89638032Speter 89764562Sgshapiro#if USERDB 89838032Speter /* if not aliased, look it up in the user database */ 89990792Sgshapiro if (!bitset(QNOTREMOTE, new->q_flags) && 90090792Sgshapiro QS_IS_SENDABLE(new->q_state) && 90138032Speter bitnset(M_CHECKUDB, m->m_flags)) 90238032Speter { 90390792Sgshapiro if (udbexpand(new, sendq, aliaslevel, e) == EX_TEMPFAIL) 90438032Speter { 90590792Sgshapiro new->q_state = QS_QUEUEUP; 90638032Speter if (e->e_message == NULL) 90790792Sgshapiro e->e_message = "Deferred: user database error"; 90890792Sgshapiro if (new->q_message == NULL) 90990792Sgshapiro new->q_message = "Deferred: user database error"; 91038032Speter if (LogLevel > 8) 91138032Speter sm_syslog(LOG_INFO, e->e_id, 91264562Sgshapiro "deferred: udbexpand: %s", 91390792Sgshapiro sm_errstring(errno)); 91438032Speter message("queued (user database error): %s", 91590792Sgshapiro sm_errstring(errno)); 91638032Speter e->e_nrcpts++; 91738032Speter goto testselfdestruct; 91838032Speter } 91938032Speter } 92064562Sgshapiro#endif /* USERDB */ 92138032Speter 92238032Speter /* 92338032Speter ** If we have a level two config file, then pass the name through 92438032Speter ** Ruleset 5 before sending it off. Ruleset 5 has the right 92590792Sgshapiro ** to rewrite it to another mailer. This gives us a hook 92638032Speter ** after local aliasing has been done. 92738032Speter */ 92838032Speter 92938032Speter if (tTd(29, 5)) 93038032Speter { 93190792Sgshapiro sm_dprintf("recipient: testing local? cl=%d, rr5=%p\n\t", 93290792Sgshapiro ConfigLevel, RewriteRules[5]); 933132943Sgshapiro printaddr(sm_debug_file(), new, false); 93438032Speter } 93564562Sgshapiro if (ConfigLevel >= 2 && RewriteRules[5] != NULL && 93664562Sgshapiro bitnset(M_TRYRULESET5, m->m_flags) && 93790792Sgshapiro !bitset(QNOTREMOTE, new->q_flags) && 93890792Sgshapiro QS_IS_OK(new->q_state)) 93938032Speter { 94090792Sgshapiro maplocaluser(new, sendq, aliaslevel + 1, e); 94138032Speter } 94238032Speter 94338032Speter /* 94438032Speter ** If it didn't get rewritten to another mailer, go ahead 94538032Speter ** and deliver it. 94638032Speter */ 94738032Speter 94890792Sgshapiro if (QS_IS_OK(new->q_state) && 94938032Speter bitnset(M_HASPWENT, m->m_flags)) 95038032Speter { 95138032Speter auto bool fuzzy; 95290792Sgshapiro SM_MBDB_T user; 95390792Sgshapiro int status; 95438032Speter 95538032Speter /* warning -- finduser may trash buf */ 95690792Sgshapiro status = finduser(buf, &fuzzy, &user); 95790792Sgshapiro switch (status) 95838032Speter { 95990792Sgshapiro case EX_TEMPFAIL: 96090792Sgshapiro new->q_state = QS_QUEUEUP; 96190792Sgshapiro new->q_status = "4.5.2"; 96290792Sgshapiro giveresponse(EX_TEMPFAIL, new->q_status, m, NULL, 96390792Sgshapiro new->q_alias, (time_t) 0, e, new); 96490792Sgshapiro break; 96590792Sgshapiro default: 96690792Sgshapiro new->q_state = QS_BADADDR; 96790792Sgshapiro new->q_status = "5.1.1"; 96890792Sgshapiro new->q_rstatus = "550 5.1.1 User unknown"; 96990792Sgshapiro giveresponse(EX_NOUSER, new->q_status, m, NULL, 97090792Sgshapiro new->q_alias, (time_t) 0, e, new); 97190792Sgshapiro break; 97290792Sgshapiro case EX_OK: 97338032Speter if (fuzzy) 97438032Speter { 97538032Speter /* name was a fuzzy match */ 97690792Sgshapiro new->q_user = sm_rpool_strdup_x(e->e_rpool, 97790792Sgshapiro user.mbdb_name); 97838032Speter if (findusercount++ > 3) 97938032Speter { 98090792Sgshapiro new->q_state = QS_BADADDR; 98190792Sgshapiro new->q_status = "5.4.6"; 98290792Sgshapiro usrerrenh(new->q_status, 98364562Sgshapiro "554 aliasing/forwarding loop for %s broken", 98490792Sgshapiro user.mbdb_name); 98538032Speter goto done; 98638032Speter } 98738032Speter 98838032Speter /* see if it aliases */ 98990792Sgshapiro (void) sm_strlcpy(buf, user.mbdb_name, buflen); 99038032Speter goto trylocaluser; 99138032Speter } 99290792Sgshapiro if (*user.mbdb_homedir == '\0') 99390792Sgshapiro new->q_home = NULL; 99490792Sgshapiro else if (strcmp(user.mbdb_homedir, "/") == 0) 99590792Sgshapiro new->q_home = ""; 99638032Speter else 99790792Sgshapiro new->q_home = sm_rpool_strdup_x(e->e_rpool, 99890792Sgshapiro user.mbdb_homedir); 99990792Sgshapiro if (user.mbdb_uid != SM_NO_UID) 100038032Speter { 100190792Sgshapiro new->q_uid = user.mbdb_uid; 100290792Sgshapiro new->q_gid = user.mbdb_gid; 100390792Sgshapiro new->q_flags |= QGOODUID; 100438032Speter } 100590792Sgshapiro new->q_ruser = sm_rpool_strdup_x(e->e_rpool, 100690792Sgshapiro user.mbdb_name); 100790792Sgshapiro if (user.mbdb_fullname[0] != '\0') 100890792Sgshapiro new->q_fullname = sm_rpool_strdup_x(e->e_rpool, 100990792Sgshapiro user.mbdb_fullname); 101090792Sgshapiro if (!usershellok(user.mbdb_name, user.mbdb_shell)) 101190792Sgshapiro { 101290792Sgshapiro new->q_flags |= QBOGUSSHELL; 101390792Sgshapiro } 101438032Speter if (bitset(EF_VRFYONLY, e->e_flags)) 101538032Speter { 101638032Speter /* don't do any more now */ 101790792Sgshapiro new->q_state = QS_VERIFIED; 101838032Speter } 101938032Speter else if (!quoted) 102090792Sgshapiro forward(new, sendq, aliaslevel, e); 102138032Speter } 102238032Speter } 102390792Sgshapiro if (!QS_IS_DEAD(new->q_state)) 102438032Speter e->e_nrcpts++; 102538032Speter 102638032Speter testselfdestruct: 102790792Sgshapiro new->q_flags |= QTHISPASS; 102838032Speter if (tTd(26, 8)) 102938032Speter { 103090792Sgshapiro sm_dprintf("testselfdestruct: "); 1031132943Sgshapiro printaddr(sm_debug_file(), new, false); 103238032Speter if (tTd(26, 10)) 103338032Speter { 103490792Sgshapiro sm_dprintf("SENDQ:\n"); 1035132943Sgshapiro printaddr(sm_debug_file(), *sendq, true); 103690792Sgshapiro sm_dprintf("----\n"); 103738032Speter } 103838032Speter } 103990792Sgshapiro if (new->q_alias == NULL && new != &e->e_from && 104090792Sgshapiro QS_IS_DEAD(new->q_state)) 104138032Speter { 104238032Speter for (q = *sendq; q != NULL; q = q->q_next) 104338032Speter { 104464562Sgshapiro if (!QS_IS_DEAD(q->q_state)) 104538032Speter break; 104638032Speter } 104738032Speter if (q == NULL) 104838032Speter { 104990792Sgshapiro new->q_state = QS_BADADDR; 105090792Sgshapiro new->q_status = "5.4.6"; 105190792Sgshapiro usrerrenh(new->q_status, 105264562Sgshapiro "554 aliasing/forwarding loop broken"); 105338032Speter } 105438032Speter } 105538032Speter 105638032Speter done: 105790792Sgshapiro new->q_flags |= QTHISPASS; 105838032Speter if (buf != buf0) 105990792Sgshapiro sm_free(buf); /* XXX leak if above code raises exception */ 106038032Speter 106138032Speter /* 106238032Speter ** If we are at the top level, check to see if this has 106338032Speter ** expanded to exactly one address. If so, it can inherit 106438032Speter ** the primaryness of the address. 106538032Speter ** 106638032Speter ** While we're at it, clear the QTHISPASS bits. 106738032Speter */ 106838032Speter 106938032Speter if (aliaslevel == 0) 107038032Speter { 107138032Speter int nrcpts = 0; 107238032Speter ADDRESS *only = NULL; 107338032Speter 107438032Speter for (q = *sendq; q != NULL; q = q->q_next) 107538032Speter { 107638032Speter if (bitset(QTHISPASS, q->q_flags) && 107764562Sgshapiro QS_IS_SENDABLE(q->q_state)) 107838032Speter { 107938032Speter nrcpts++; 108038032Speter only = q; 108138032Speter } 108238032Speter q->q_flags &= ~QTHISPASS; 108338032Speter } 108438032Speter if (nrcpts == 1) 108538032Speter { 108638032Speter /* check to see if this actually got a new owner */ 108738032Speter q = only; 108838032Speter while ((q = q->q_alias) != NULL) 108938032Speter { 109038032Speter if (q->q_owner != NULL) 109138032Speter break; 109238032Speter } 109338032Speter if (q == NULL) 109438032Speter only->q_flags |= QPRIMARY; 109538032Speter } 109638032Speter else if (!initialdontsend && nrcpts > 0) 109738032Speter { 109838032Speter /* arrange for return receipt */ 109938032Speter e->e_flags |= EF_SENDRECEIPT; 110090792Sgshapiro new->q_flags |= QEXPANDED; 110164562Sgshapiro if (e->e_xfp != NULL && 110290792Sgshapiro bitset(QPINGONSUCCESS, new->q_flags)) 110390792Sgshapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 110490792Sgshapiro "%s... expanded to multiple addresses\n", 110590792Sgshapiro new->q_paddr); 110638032Speter } 110738032Speter } 110890792Sgshapiro new->q_flags |= QRCPTOK; 110990792Sgshapiro (void) sm_snprintf(buf0, sizeof buf0, "%d", e->e_nrcpts); 111090792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{nrcpts}"), buf0); 111190792Sgshapiro return new; 111238032Speter} 111390792Sgshapiro/* 111438032Speter** FINDUSER -- find the password entry for a user. 111538032Speter** 111638032Speter** This looks a lot like getpwnam, except that it may want to 111738032Speter** do some fancier pattern matching in /etc/passwd. 111838032Speter** 111938032Speter** This routine contains most of the time of many sendmail runs. 112038032Speter** It deserves to be optimized. 112138032Speter** 112238032Speter** Parameters: 112338032Speter** name -- the name to match against. 112490792Sgshapiro** fuzzyp -- an outarg that is set to true if this entry 112538032Speter** was found using the fuzzy matching algorithm; 112690792Sgshapiro** set to false otherwise. 112790792Sgshapiro** user -- structure to fill in if user is found 112838032Speter** 112938032Speter** Returns: 113090792Sgshapiro** On success, fill in *user, set *fuzzyp and return EX_OK. 113190792Sgshapiro** If the user was not found, return EX_NOUSER. 113290792Sgshapiro** On error, return EX_TEMPFAIL or EX_OSERR. 113338032Speter** 113438032Speter** Side Effects: 113538032Speter** may modify name. 113638032Speter*/ 113738032Speter 113890792Sgshapiroint 113990792Sgshapirofinduser(name, fuzzyp, user) 114038032Speter char *name; 114138032Speter bool *fuzzyp; 114290792Sgshapiro SM_MBDB_T *user; 114338032Speter{ 114490792Sgshapiro#if MATCHGECOS 114538032Speter register struct passwd *pw; 114690792Sgshapiro#endif /* MATCHGECOS */ 114738032Speter register char *p; 114838032Speter bool tryagain; 114990792Sgshapiro int status; 115038032Speter 115138032Speter if (tTd(29, 4)) 115290792Sgshapiro sm_dprintf("finduser(%s): ", name); 115338032Speter 115490792Sgshapiro *fuzzyp = false; 115538032Speter 115690792Sgshapiro#if HESIOD 115738032Speter /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 115838032Speter for (p = name; *p != '\0'; p++) 115938032Speter if (!isascii(*p) || !isdigit(*p)) 116038032Speter break; 116138032Speter if (*p == '\0') 116238032Speter { 116338032Speter if (tTd(29, 4)) 116490792Sgshapiro sm_dprintf("failed (numeric input)\n"); 116590792Sgshapiro return EX_NOUSER; 116638032Speter } 116764562Sgshapiro#endif /* HESIOD */ 116838032Speter 116938032Speter /* look up this login name using fast path */ 117090792Sgshapiro status = sm_mbdb_lookup(name, user); 117190792Sgshapiro if (status != EX_NOUSER) 117238032Speter { 117338032Speter if (tTd(29, 4)) 117490792Sgshapiro sm_dprintf("%s (non-fuzzy)\n", sm_strexit(status)); 117590792Sgshapiro return status; 117638032Speter } 117738032Speter 117838032Speter /* try mapping it to lower case */ 117990792Sgshapiro tryagain = false; 118038032Speter for (p = name; *p != '\0'; p++) 118138032Speter { 118238032Speter if (isascii(*p) && isupper(*p)) 118338032Speter { 118438032Speter *p = tolower(*p); 118590792Sgshapiro tryagain = true; 118638032Speter } 118738032Speter } 118890792Sgshapiro if (tryagain && (status = sm_mbdb_lookup(name, user)) != EX_NOUSER) 118938032Speter { 119038032Speter if (tTd(29, 4)) 119190792Sgshapiro sm_dprintf("%s (lower case)\n", sm_strexit(status)); 119290792Sgshapiro *fuzzyp = true; 119390792Sgshapiro return status; 119438032Speter } 119538032Speter 119638032Speter#if MATCHGECOS 119738032Speter /* see if fuzzy matching allowed */ 119838032Speter if (!MatchGecos) 119938032Speter { 120038032Speter if (tTd(29, 4)) 120190792Sgshapiro sm_dprintf("not found (fuzzy disabled)\n"); 120290792Sgshapiro return EX_NOUSER; 120338032Speter } 120438032Speter 120538032Speter /* search for a matching full name instead */ 120638032Speter for (p = name; *p != '\0'; p++) 120738032Speter { 120838032Speter if (*p == (SpaceSub & 0177) || *p == '_') 120938032Speter *p = ' '; 121038032Speter } 121138032Speter (void) setpwent(); 121238032Speter while ((pw = getpwent()) != NULL) 121338032Speter { 121438032Speter char buf[MAXNAME + 1]; 121538032Speter 121638032Speter# if 0 121790792Sgshapiro if (sm_strcasecmp(pw->pw_name, name) == 0) 121838032Speter { 121938032Speter if (tTd(29, 4)) 122090792Sgshapiro sm_dprintf("found (case wrapped)\n"); 122138032Speter break; 122238032Speter } 122364562Sgshapiro# endif /* 0 */ 122438032Speter 122590792Sgshapiro sm_pwfullname(pw->pw_gecos, pw->pw_name, buf, sizeof buf); 122690792Sgshapiro if (strchr(buf, ' ') != NULL && sm_strcasecmp(buf, name) == 0) 122738032Speter { 122838032Speter if (tTd(29, 4)) 122990792Sgshapiro sm_dprintf("fuzzy matches %s\n", pw->pw_name); 123038032Speter message("sending to login name %s", pw->pw_name); 123138032Speter break; 123238032Speter } 123338032Speter } 123438032Speter if (pw != NULL) 123590792Sgshapiro *fuzzyp = true; 123638032Speter else if (tTd(29, 4)) 123790792Sgshapiro sm_dprintf("no fuzzy match found\n"); 123838032Speter# if DEC_OSF_BROKEN_GETPWENT /* DEC OSF/1 3.2 or earlier */ 123938032Speter endpwent(); 124064562Sgshapiro# endif /* DEC_OSF_BROKEN_GETPWENT */ 124190792Sgshapiro if (pw == NULL) 124290792Sgshapiro return EX_NOUSER; 124390792Sgshapiro sm_mbdb_frompw(user, pw); 124490792Sgshapiro return EX_OK; 124564562Sgshapiro#else /* MATCHGECOS */ 124638032Speter if (tTd(29, 4)) 124790792Sgshapiro sm_dprintf("not found (fuzzy disabled)\n"); 124890792Sgshapiro return EX_NOUSER; 124964562Sgshapiro#endif /* MATCHGECOS */ 125038032Speter} 125190792Sgshapiro/* 125238032Speter** WRITABLE -- predicate returning if the file is writable. 125338032Speter** 125438032Speter** This routine must duplicate the algorithm in sys/fio.c. 125538032Speter** Unfortunately, we cannot use the access call since we 125638032Speter** won't necessarily be the real uid when we try to 125738032Speter** actually open the file. 125838032Speter** 125938032Speter** Notice that ANY file with ANY execute bit is automatically 126038032Speter** not writable. This is also enforced by mailfile. 126138032Speter** 126238032Speter** Parameters: 126338032Speter** filename -- the file name to check. 126438032Speter** ctladdr -- the controlling address for this file. 126538032Speter** flags -- SFF_* flags to control the function. 126638032Speter** 126738032Speter** Returns: 126890792Sgshapiro** true -- if we will be able to write this file. 126990792Sgshapiro** false -- if we cannot write this file. 127038032Speter** 127138032Speter** Side Effects: 127238032Speter** none. 127338032Speter*/ 127438032Speter 127538032Speterbool 127638032Speterwritable(filename, ctladdr, flags) 127738032Speter char *filename; 127838032Speter ADDRESS *ctladdr; 127964562Sgshapiro long flags; 128038032Speter{ 128164562Sgshapiro uid_t euid = 0; 128264562Sgshapiro gid_t egid = 0; 128364562Sgshapiro char *user = NULL; 128438032Speter 128538032Speter if (tTd(44, 5)) 128690792Sgshapiro sm_dprintf("writable(%s, 0x%lx)\n", filename, flags); 128738032Speter 128838032Speter /* 128938032Speter ** File does exist -- check that it is writable. 129038032Speter */ 129138032Speter 129238032Speter if (geteuid() != 0) 129338032Speter { 129438032Speter euid = geteuid(); 129538032Speter egid = getegid(); 129664562Sgshapiro user = NULL; 129738032Speter } 129838032Speter else if (ctladdr != NULL) 129938032Speter { 130038032Speter euid = ctladdr->q_uid; 130138032Speter egid = ctladdr->q_gid; 130264562Sgshapiro user = ctladdr->q_user; 130338032Speter } 130438032Speter else if (bitset(SFF_RUNASREALUID, flags)) 130538032Speter { 130638032Speter euid = RealUid; 130738032Speter egid = RealGid; 130864562Sgshapiro user = RealUserName; 130938032Speter } 131038032Speter else if (FileMailer != NULL && !bitset(SFF_ROOTOK, flags)) 131138032Speter { 1312132943Sgshapiro if (FileMailer->m_uid == NO_UID) 1313132943Sgshapiro { 1314132943Sgshapiro euid = DefUid; 1315132943Sgshapiro user = DefUser; 1316132943Sgshapiro } 1317132943Sgshapiro else 1318132943Sgshapiro { 1319132943Sgshapiro euid = FileMailer->m_uid; 1320132943Sgshapiro user = NULL; 1321132943Sgshapiro } 1322132943Sgshapiro if (FileMailer->m_gid == NO_GID) 1323132943Sgshapiro egid = DefGid; 1324132943Sgshapiro else 1325132943Sgshapiro egid = FileMailer->m_gid; 132638032Speter } 132738032Speter else 132838032Speter { 132938032Speter euid = egid = 0; 133064562Sgshapiro user = NULL; 133138032Speter } 133238032Speter if (!bitset(SFF_ROOTOK, flags)) 133338032Speter { 133438032Speter if (euid == 0) 133538032Speter { 133638032Speter euid = DefUid; 133764562Sgshapiro user = DefUser; 133838032Speter } 133938032Speter if (egid == 0) 134038032Speter egid = DefGid; 134138032Speter } 134238032Speter if (geteuid() == 0 && 134338032Speter (ctladdr == NULL || !bitset(QGOODUID, ctladdr->q_flags))) 134438032Speter flags |= SFF_SETUIDOK; 134538032Speter 134664562Sgshapiro if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 134738032Speter flags |= SFF_NOSLINK; 134864562Sgshapiro if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) 134938032Speter flags |= SFF_NOHLINK; 135038032Speter 135164562Sgshapiro errno = safefile(filename, euid, egid, user, flags, S_IWRITE, NULL); 135238032Speter return errno == 0; 135338032Speter} 135490792Sgshapiro/* 135538032Speter** INCLUDE -- handle :include: specification. 135638032Speter** 135738032Speter** Parameters: 135838032Speter** fname -- filename to include. 135990792Sgshapiro** forwarding -- if true, we are reading a .forward file. 136090792Sgshapiro** if false, it's a :include: file. 136138032Speter** ctladdr -- address template to use to fill in these 136238032Speter** addresses -- effective user/group id are 136338032Speter** the important things. 136438032Speter** sendq -- a pointer to the head of the send queue 136538032Speter** to put these addresses in. 136638032Speter** aliaslevel -- the alias nesting depth. 136738032Speter** e -- the current envelope. 136838032Speter** 136938032Speter** Returns: 137038032Speter** open error status 137138032Speter** 137238032Speter** Side Effects: 137338032Speter** reads the :include: file and sends to everyone 137438032Speter** listed in that file. 137538032Speter** 137638032Speter** Security Note: 137738032Speter** If you have restricted chown (that is, you can't 137838032Speter** give a file away), it is reasonable to allow programs 137938032Speter** and files called from this :include: file to be to be 138038032Speter** run as the owner of the :include: file. This is bogus 138138032Speter** if there is any chance of someone giving away a file. 138238032Speter** We assume that pre-POSIX systems can give away files. 138338032Speter** 138438032Speter** There is an additional restriction that if you 138538032Speter** forward to a :include: file, it will not take on 138638032Speter** the ownership of the :include: file. This may not 138738032Speter** be necessary, but shouldn't hurt. 138838032Speter*/ 138938032Speter 139038032Speterstatic jmp_buf CtxIncludeTimeout; 139138032Speter 139238032Speterint 139338032Speterinclude(fname, forwarding, ctladdr, sendq, aliaslevel, e) 139438032Speter char *fname; 139538032Speter bool forwarding; 139638032Speter ADDRESS *ctladdr; 139738032Speter ADDRESS **sendq; 139838032Speter int aliaslevel; 139938032Speter ENVELOPE *e; 140038032Speter{ 140190792Sgshapiro SM_FILE_T *volatile fp = NULL; 140238032Speter char *oldto = e->e_to; 140338032Speter char *oldfilename = FileName; 140438032Speter int oldlinenumber = LineNumber; 140590792Sgshapiro register SM_EVENT *ev = NULL; 140638032Speter int nincludes; 140738032Speter int mode; 140890792Sgshapiro volatile bool maxreached = false; 140938032Speter register ADDRESS *ca; 141064562Sgshapiro volatile uid_t saveduid; 141164562Sgshapiro volatile gid_t savedgid; 141264562Sgshapiro volatile uid_t uid; 141364562Sgshapiro volatile gid_t gid; 141464562Sgshapiro char *volatile user; 141538032Speter int rval = 0; 141664562Sgshapiro volatile long sfflags = SFF_REGONLY; 141738032Speter register char *p; 141890792Sgshapiro bool safechown = false; 141990792Sgshapiro volatile bool safedir = false; 142038032Speter struct stat st; 142138032Speter char buf[MAXLINE]; 142238032Speter 142338032Speter if (tTd(27, 2)) 142490792Sgshapiro sm_dprintf("include(%s)\n", fname); 142538032Speter if (tTd(27, 4)) 142690792Sgshapiro sm_dprintf(" ruid=%d euid=%d\n", 142764562Sgshapiro (int) getuid(), (int) geteuid()); 142838032Speter if (tTd(27, 14)) 142938032Speter { 143090792Sgshapiro sm_dprintf("ctladdr "); 1431132943Sgshapiro printaddr(sm_debug_file(), ctladdr, false); 143238032Speter } 143338032Speter 143438032Speter if (tTd(27, 9)) 143590792Sgshapiro sm_dprintf("include: old uid = %d/%d\n", 143690792Sgshapiro (int) getuid(), (int) geteuid()); 143738032Speter 143838032Speter if (forwarding) 143966494Sgshapiro { 144098121Sgshapiro sfflags |= SFF_MUSTOWN|SFF_ROOTOK; 144166494Sgshapiro if (!bitnset(DBS_GROUPWRITABLEFORWARDFILE, DontBlameSendmail)) 144266494Sgshapiro sfflags |= SFF_NOGWFILES; 144366494Sgshapiro if (!bitnset(DBS_WORLDWRITABLEFORWARDFILE, DontBlameSendmail)) 144466494Sgshapiro sfflags |= SFF_NOWWFILES; 144566494Sgshapiro } 144666494Sgshapiro else 144766494Sgshapiro { 144866494Sgshapiro if (!bitnset(DBS_GROUPWRITABLEINCLUDEFILE, DontBlameSendmail)) 144966494Sgshapiro sfflags |= SFF_NOGWFILES; 145066494Sgshapiro if (!bitnset(DBS_WORLDWRITABLEINCLUDEFILE, DontBlameSendmail)) 145166494Sgshapiro sfflags |= SFF_NOWWFILES; 145266494Sgshapiro } 145366494Sgshapiro 145464562Sgshapiro /* 145564562Sgshapiro ** If RunAsUser set, won't be able to run programs as user 145664562Sgshapiro ** so mark them as unsafe unless the administrator knows better. 145764562Sgshapiro */ 145864562Sgshapiro 145964562Sgshapiro if ((geteuid() != 0 || RunAsUid != 0) && 146064562Sgshapiro !bitnset(DBS_NONROOTSAFEADDR, DontBlameSendmail)) 146164562Sgshapiro { 146264562Sgshapiro if (tTd(27, 4)) 146390792Sgshapiro sm_dprintf("include: not safe (euid=%d, RunAsUid=%d)\n", 146490792Sgshapiro (int) geteuid(), (int) RunAsUid); 146564562Sgshapiro ctladdr->q_flags |= QUNSAFEADDR; 146664562Sgshapiro } 146764562Sgshapiro 146838032Speter ca = getctladdr(ctladdr); 146964562Sgshapiro if (ca == NULL || 147064562Sgshapiro (ca->q_uid == DefUid && ca->q_gid == 0)) 147138032Speter { 147238032Speter uid = DefUid; 147338032Speter gid = DefGid; 147464562Sgshapiro user = DefUser; 147538032Speter } 147638032Speter else 147738032Speter { 147838032Speter uid = ca->q_uid; 147938032Speter gid = ca->q_gid; 148064562Sgshapiro user = ca->q_user; 148138032Speter } 148264562Sgshapiro#if MAILER_SETUID_METHOD != USE_SETUID 148338032Speter saveduid = geteuid(); 148438032Speter savedgid = getegid(); 148538032Speter if (saveduid == 0) 148638032Speter { 148738032Speter if (!DontInitGroups) 148838032Speter { 148964562Sgshapiro if (initgroups(user, gid) == -1) 149064562Sgshapiro { 149164562Sgshapiro rval = EAGAIN; 149238032Speter syserr("include: initgroups(%s, %d) failed", 149364562Sgshapiro user, gid); 149464562Sgshapiro goto resetuid; 149564562Sgshapiro } 149638032Speter } 149738032Speter else 149838032Speter { 149938032Speter GIDSET_T gidset[1]; 150038032Speter 150138032Speter gidset[0] = gid; 150238032Speter if (setgroups(1, gidset) == -1) 150364562Sgshapiro { 150464562Sgshapiro rval = EAGAIN; 150538032Speter syserr("include: setgroups() failed"); 150664562Sgshapiro goto resetuid; 150764562Sgshapiro } 150838032Speter } 150938032Speter 151038032Speter if (gid != 0 && setgid(gid) < -1) 151164562Sgshapiro { 151264562Sgshapiro rval = EAGAIN; 151338032Speter syserr("setgid(%d) failure", gid); 151464562Sgshapiro goto resetuid; 151564562Sgshapiro } 151638032Speter if (uid != 0) 151738032Speter { 151864562Sgshapiro# if MAILER_SETUID_METHOD == USE_SETEUID 151938032Speter if (seteuid(uid) < 0) 152064562Sgshapiro { 152164562Sgshapiro rval = EAGAIN; 152238032Speter syserr("seteuid(%d) failure (real=%d, eff=%d)", 152398121Sgshapiro uid, (int) getuid(), (int) geteuid()); 152464562Sgshapiro goto resetuid; 152564562Sgshapiro } 152664562Sgshapiro# endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 152764562Sgshapiro# if MAILER_SETUID_METHOD == USE_SETREUID 152838032Speter if (setreuid(0, uid) < 0) 152964562Sgshapiro { 153064562Sgshapiro rval = EAGAIN; 153138032Speter syserr("setreuid(0, %d) failure (real=%d, eff=%d)", 153298121Sgshapiro uid, (int) getuid(), (int) geteuid()); 153364562Sgshapiro goto resetuid; 153464562Sgshapiro } 153564562Sgshapiro# endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 153638032Speter } 153738032Speter } 153864562Sgshapiro#endif /* MAILER_SETUID_METHOD != USE_SETUID */ 153938032Speter 154038032Speter if (tTd(27, 9)) 154190792Sgshapiro sm_dprintf("include: new uid = %d/%d\n", 154290792Sgshapiro (int) getuid(), (int) geteuid()); 154338032Speter 154438032Speter /* 154538032Speter ** If home directory is remote mounted but server is down, 154638032Speter ** this can hang or give errors; use a timeout to avoid this 154738032Speter */ 154838032Speter 154938032Speter if (setjmp(CtxIncludeTimeout) != 0) 155038032Speter { 155164562Sgshapiro ctladdr->q_state = QS_QUEUEUP; 155238032Speter errno = 0; 155338032Speter 155438032Speter /* return pseudo-error code */ 155538032Speter rval = E_SM_OPENTIMEOUT; 155638032Speter goto resetuid; 155738032Speter } 155838032Speter if (TimeOuts.to_fileopen > 0) 155990792Sgshapiro ev = sm_setevent(TimeOuts.to_fileopen, includetimeout, 0); 156038032Speter else 156138032Speter ev = NULL; 156238032Speter 156364562Sgshapiro 156438032Speter /* check for writable parent directory */ 156538032Speter p = strrchr(fname, '/'); 156638032Speter if (p != NULL) 156738032Speter { 156838032Speter int ret; 156938032Speter 157038032Speter *p = '\0'; 157164562Sgshapiro ret = safedirpath(fname, uid, gid, user, 157264562Sgshapiro sfflags|SFF_SAFEDIRPATH, 0, 0); 157338032Speter if (ret == 0) 157438032Speter { 157538032Speter /* in safe directory: relax chown & link rules */ 157690792Sgshapiro safedir = true; 157738032Speter sfflags |= SFF_NOPATHCHECK; 157838032Speter } 157938032Speter else 158038032Speter { 158164562Sgshapiro if (bitnset((forwarding ? 158264562Sgshapiro DBS_FORWARDFILEINUNSAFEDIRPATH : 158364562Sgshapiro DBS_INCLUDEFILEINUNSAFEDIRPATH), 158464562Sgshapiro DontBlameSendmail)) 158538032Speter sfflags |= SFF_NOPATHCHECK; 158664562Sgshapiro else if (bitnset((forwarding ? 158764562Sgshapiro DBS_FORWARDFILEINGROUPWRITABLEDIRPATH : 158864562Sgshapiro DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH), 158964562Sgshapiro DontBlameSendmail) && 159038032Speter ret == E_SM_GWDIR) 159138032Speter { 159264562Sgshapiro setbitn(DBS_GROUPWRITABLEDIRPATHSAFE, 159364562Sgshapiro DontBlameSendmail); 159464562Sgshapiro ret = safedirpath(fname, uid, gid, user, 159564562Sgshapiro sfflags|SFF_SAFEDIRPATH, 159664562Sgshapiro 0, 0); 159764562Sgshapiro clrbitn(DBS_GROUPWRITABLEDIRPATHSAFE, 159864562Sgshapiro DontBlameSendmail); 159938032Speter if (ret == 0) 160038032Speter sfflags |= SFF_NOPATHCHECK; 160138032Speter else 160238032Speter sfflags |= SFF_SAFEDIRPATH; 160338032Speter } 160438032Speter else 160538032Speter sfflags |= SFF_SAFEDIRPATH; 160638032Speter if (ret > E_PSEUDOBASE && 160764562Sgshapiro !bitnset((forwarding ? 160864562Sgshapiro DBS_FORWARDFILEINUNSAFEDIRPATHSAFE : 160964562Sgshapiro DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE), 161064562Sgshapiro DontBlameSendmail)) 161138032Speter { 161290792Sgshapiro if (LogLevel > 11) 161338032Speter sm_syslog(LOG_INFO, e->e_id, 161438032Speter "%s: unsafe directory path, marked unsafe", 161538032Speter shortenstring(fname, MAXSHORTSTR)); 161638032Speter ctladdr->q_flags |= QUNSAFEADDR; 161738032Speter } 161838032Speter } 161938032Speter *p = '/'; 162038032Speter } 162138032Speter 162238032Speter /* allow links only in unwritable directories */ 162338032Speter if (!safedir && 162464562Sgshapiro !bitnset((forwarding ? 162564562Sgshapiro DBS_LINKEDFORWARDFILEINWRITABLEDIR : 162664562Sgshapiro DBS_LINKEDINCLUDEFILEINWRITABLEDIR), 162764562Sgshapiro DontBlameSendmail)) 162838032Speter sfflags |= SFF_NOLINK; 162938032Speter 163064562Sgshapiro rval = safefile(fname, uid, gid, user, sfflags, S_IREAD, &st); 163138032Speter if (rval != 0) 163238032Speter { 163338032Speter /* don't use this :include: file */ 163438032Speter if (tTd(27, 4)) 163590792Sgshapiro sm_dprintf("include: not safe (uid=%d): %s\n", 163690792Sgshapiro (int) uid, sm_errstring(rval)); 163738032Speter } 163890792Sgshapiro else if ((fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, fname, 163990792Sgshapiro SM_IO_RDONLY, NULL)) == NULL) 164038032Speter { 164138032Speter rval = errno; 164238032Speter if (tTd(27, 4)) 164390792Sgshapiro sm_dprintf("include: open: %s\n", sm_errstring(rval)); 164438032Speter } 164590792Sgshapiro else if (filechanged(fname, sm_io_getinfo(fp,SM_IO_WHAT_FD, NULL), &st)) 164638032Speter { 164738032Speter rval = E_SM_FILECHANGE; 164838032Speter if (tTd(27, 4)) 164990792Sgshapiro sm_dprintf("include: file changed after open\n"); 165038032Speter } 165138032Speter if (ev != NULL) 165290792Sgshapiro sm_clrevent(ev); 165338032Speter 165438032Speterresetuid: 165538032Speter 165638032Speter#if HASSETREUID || USESETEUID 165738032Speter if (saveduid == 0) 165838032Speter { 165938032Speter if (uid != 0) 166038032Speter { 166138032Speter# if USESETEUID 166238032Speter if (seteuid(0) < 0) 166364562Sgshapiro syserr("!seteuid(0) failure (real=%d, eff=%d)", 166490792Sgshapiro (int) getuid(), (int) geteuid()); 166564562Sgshapiro# else /* USESETEUID */ 166638032Speter if (setreuid(-1, 0) < 0) 166764562Sgshapiro syserr("!setreuid(-1, 0) failure (real=%d, eff=%d)", 166890792Sgshapiro (int) getuid(), (int) geteuid()); 166938032Speter if (setreuid(RealUid, 0) < 0) 167064562Sgshapiro syserr("!setreuid(%d, 0) failure (real=%d, eff=%d)", 167190792Sgshapiro (int) RealUid, (int) getuid(), 167290792Sgshapiro (int) geteuid()); 167364562Sgshapiro# endif /* USESETEUID */ 167438032Speter } 167564562Sgshapiro if (setgid(savedgid) < 0) 167664562Sgshapiro syserr("!setgid(%d) failure (real=%d eff=%d)", 167790792Sgshapiro (int) savedgid, (int) getgid(), 167890792Sgshapiro (int) getegid()); 167938032Speter } 168064562Sgshapiro#endif /* HASSETREUID || USESETEUID */ 168138032Speter 168238032Speter if (tTd(27, 9)) 168390792Sgshapiro sm_dprintf("include: reset uid = %d/%d\n", 168490792Sgshapiro (int) getuid(), (int) geteuid()); 168538032Speter 168638032Speter if (rval == E_SM_OPENTIMEOUT) 168764562Sgshapiro usrerr("451 4.4.1 open timeout on %s", fname); 168838032Speter 168938032Speter if (fp == NULL) 169038032Speter return rval; 169138032Speter 169290792Sgshapiro if (fstat(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), &st) < 0) 169338032Speter { 169438032Speter rval = errno; 169538032Speter syserr("Cannot fstat %s!", fname); 169690792Sgshapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 169738032Speter return rval; 169838032Speter } 169938032Speter 170038032Speter /* if path was writable, check to avoid file giveaway tricks */ 170190792Sgshapiro safechown = chownsafe(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), safedir); 170238032Speter if (tTd(27, 6)) 170390792Sgshapiro sm_dprintf("include: parent of %s is %s, chown is %ssafe\n", 170490792Sgshapiro fname, safedir ? "safe" : "dangerous", 170590792Sgshapiro safechown ? "" : "un"); 170638032Speter 170764562Sgshapiro /* if no controlling user or coming from an alias delivery */ 170864562Sgshapiro if (safechown && 170964562Sgshapiro (ca == NULL || 171064562Sgshapiro (ca->q_uid == DefUid && ca->q_gid == 0))) 171138032Speter { 171238032Speter ctladdr->q_uid = st.st_uid; 171338032Speter ctladdr->q_gid = st.st_gid; 171438032Speter ctladdr->q_flags |= QGOODUID; 171538032Speter } 171638032Speter if (ca != NULL && ca->q_uid == st.st_uid) 171738032Speter { 171838032Speter /* optimization -- avoid getpwuid if we already have info */ 171938032Speter ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 172038032Speter ctladdr->q_ruser = ca->q_ruser; 172138032Speter } 172238032Speter else if (!forwarding) 172338032Speter { 172438032Speter register struct passwd *pw; 172538032Speter 172638032Speter pw = sm_getpwuid(st.st_uid); 172738032Speter if (pw == NULL) 172864562Sgshapiro { 172964562Sgshapiro ctladdr->q_uid = st.st_uid; 173038032Speter ctladdr->q_flags |= QBOGUSSHELL; 173164562Sgshapiro } 173238032Speter else 173338032Speter { 173438032Speter char *sh; 173538032Speter 173690792Sgshapiro ctladdr->q_ruser = sm_rpool_strdup_x(e->e_rpool, 173790792Sgshapiro pw->pw_name); 173838032Speter if (safechown) 173938032Speter sh = pw->pw_shell; 174038032Speter else 174138032Speter sh = "/SENDMAIL/ANY/SHELL/"; 174238032Speter if (!usershellok(pw->pw_name, sh)) 174338032Speter { 174490792Sgshapiro if (LogLevel > 11) 174538032Speter sm_syslog(LOG_INFO, e->e_id, 174664562Sgshapiro "%s: user %s has bad shell %s, marked %s", 174790792Sgshapiro shortenstring(fname, 174890792Sgshapiro MAXSHORTSTR), 174964562Sgshapiro pw->pw_name, sh, 175064562Sgshapiro safechown ? "bogus" : "unsafe"); 175138032Speter if (safechown) 175238032Speter ctladdr->q_flags |= QBOGUSSHELL; 175338032Speter else 175438032Speter ctladdr->q_flags |= QUNSAFEADDR; 175538032Speter } 175638032Speter } 175738032Speter } 175838032Speter 175938032Speter if (bitset(EF_VRFYONLY, e->e_flags)) 176038032Speter { 176138032Speter /* don't do any more now */ 176264562Sgshapiro ctladdr->q_state = QS_VERIFIED; 176338032Speter e->e_nrcpts++; 176490792Sgshapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 176538032Speter return rval; 176638032Speter } 176738032Speter 176838032Speter /* 176942575Speter ** Check to see if some bad guy can write this file 177038032Speter ** 177138032Speter ** Group write checking could be more clever, e.g., 177238032Speter ** guessing as to which groups are actually safe ("sys" 177338032Speter ** may be; "user" probably is not). 177438032Speter */ 177538032Speter 177638032Speter mode = S_IWOTH; 177764562Sgshapiro if (!bitnset((forwarding ? 177864562Sgshapiro DBS_GROUPWRITABLEFORWARDFILESAFE : 177964562Sgshapiro DBS_GROUPWRITABLEINCLUDEFILESAFE), 178064562Sgshapiro DontBlameSendmail)) 178138032Speter mode |= S_IWGRP; 178238032Speter 178338032Speter if (bitset(mode, st.st_mode)) 178438032Speter { 178538032Speter if (tTd(27, 6)) 178690792Sgshapiro sm_dprintf("include: %s is %s writable, marked unsafe\n", 178790792Sgshapiro shortenstring(fname, MAXSHORTSTR), 178890792Sgshapiro bitset(S_IWOTH, st.st_mode) ? "world" 178990792Sgshapiro : "group"); 179090792Sgshapiro if (LogLevel > 11) 179138032Speter sm_syslog(LOG_INFO, e->e_id, 179264562Sgshapiro "%s: %s writable %s file, marked unsafe", 179364562Sgshapiro shortenstring(fname, MAXSHORTSTR), 179464562Sgshapiro bitset(S_IWOTH, st.st_mode) ? "world" : "group", 179564562Sgshapiro forwarding ? "forward" : ":include:"); 179638032Speter ctladdr->q_flags |= QUNSAFEADDR; 179738032Speter } 179838032Speter 179938032Speter /* read the file -- each line is a comma-separated list. */ 180038032Speter FileName = fname; 180138032Speter LineNumber = 0; 180238032Speter ctladdr->q_flags &= ~QSELFREF; 180338032Speter nincludes = 0; 180490792Sgshapiro while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL && 180590792Sgshapiro !maxreached) 180638032Speter { 180790792Sgshapiro fixcrlf(buf, true); 180838032Speter LineNumber++; 180938032Speter if (buf[0] == '#' || buf[0] == '\0') 181038032Speter continue; 181138032Speter 181238032Speter /* <sp>#@# introduces a comment anywhere */ 181338032Speter /* for Japanese character sets */ 181438032Speter for (p = buf; (p = strchr(++p, '#')) != NULL; ) 181538032Speter { 181638032Speter if (p[1] == '@' && p[2] == '#' && 181738032Speter isascii(p[-1]) && isspace(p[-1]) && 181838032Speter (p[3] == '\0' || (isascii(p[3]) && isspace(p[3])))) 181938032Speter { 182066494Sgshapiro --p; 182166494Sgshapiro while (p > buf && isascii(p[-1]) && 182266494Sgshapiro isspace(p[-1])) 182366494Sgshapiro --p; 182466494Sgshapiro p[0] = '\0'; 182538032Speter break; 182638032Speter } 182738032Speter } 182838032Speter if (buf[0] == '\0') 182938032Speter continue; 183038032Speter 183138032Speter e->e_to = NULL; 183238032Speter message("%s to %s", 183338032Speter forwarding ? "forwarding" : "sending", buf); 183464562Sgshapiro if (forwarding && LogLevel > 10) 183538032Speter sm_syslog(LOG_INFO, e->e_id, 183664562Sgshapiro "forward %.200s => %s", 183764562Sgshapiro oldto, shortenstring(buf, MAXSHORTSTR)); 183838032Speter 183938032Speter nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); 184064562Sgshapiro 184164562Sgshapiro if (forwarding && 184264562Sgshapiro MaxForwardEntries > 0 && 184364562Sgshapiro nincludes >= MaxForwardEntries) 184464562Sgshapiro { 184564562Sgshapiro /* just stop reading and processing further entries */ 184690792Sgshapiro#if 0 184790792Sgshapiro /* additional: (?) */ 184864562Sgshapiro ctladdr->q_state = QS_DONTSEND; 184990792Sgshapiro#endif /* 0 */ 185090792Sgshapiro 185190792Sgshapiro syserr("Attempt to forward to more than %d addresses (in %s)!", 185298121Sgshapiro MaxForwardEntries, fname); 185390792Sgshapiro maxreached = true; 185464562Sgshapiro } 185538032Speter } 185638032Speter 185790792Sgshapiro if (sm_io_error(fp) && tTd(27, 3)) 185890792Sgshapiro sm_dprintf("include: read error: %s\n", sm_errstring(errno)); 185938032Speter if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 186038032Speter { 186138032Speter if (tTd(27, 5)) 186238032Speter { 186390792Sgshapiro sm_dprintf("include: QS_DONTSEND "); 1864132943Sgshapiro printaddr(sm_debug_file(), ctladdr, false); 186538032Speter } 186664562Sgshapiro ctladdr->q_state = QS_DONTSEND; 186738032Speter } 186838032Speter 186990792Sgshapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 187038032Speter FileName = oldfilename; 187138032Speter LineNumber = oldlinenumber; 187238032Speter e->e_to = oldto; 187338032Speter return rval; 187438032Speter} 187538032Speter 187638032Speterstatic void 187738032Speterincludetimeout() 187838032Speter{ 187977349Sgshapiro /* 188077349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 188177349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 188277349Sgshapiro ** DOING. 188377349Sgshapiro */ 188477349Sgshapiro 188577349Sgshapiro errno = ETIMEDOUT; 188638032Speter longjmp(CtxIncludeTimeout, 1); 188738032Speter} 188890792Sgshapiro/* 188938032Speter** SENDTOARGV -- send to an argument vector. 189038032Speter** 189138032Speter** Parameters: 189238032Speter** argv -- argument vector to send to. 189338032Speter** e -- the current envelope. 189438032Speter** 189538032Speter** Returns: 189638032Speter** none. 189738032Speter** 189838032Speter** Side Effects: 189938032Speter** puts all addresses on the argument vector onto the 190038032Speter** send queue. 190138032Speter*/ 190238032Speter 190338032Spetervoid 190438032Spetersendtoargv(argv, e) 190538032Speter register char **argv; 190638032Speter register ENVELOPE *e; 190738032Speter{ 190838032Speter register char *p; 190938032Speter 191038032Speter while ((p = *argv++) != NULL) 191138032Speter (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e); 191238032Speter} 191390792Sgshapiro/* 191438032Speter** GETCTLADDR -- get controlling address from an address header. 191538032Speter** 191638032Speter** If none, get one corresponding to the effective userid. 191738032Speter** 191838032Speter** Parameters: 191938032Speter** a -- the address to find the controller of. 192038032Speter** 192138032Speter** Returns: 192238032Speter** the controlling address. 192338032Speter*/ 192438032Speter 192538032SpeterADDRESS * 192638032Spetergetctladdr(a) 192738032Speter register ADDRESS *a; 192838032Speter{ 192938032Speter while (a != NULL && !bitset(QGOODUID, a->q_flags)) 193038032Speter a = a->q_alias; 193164562Sgshapiro return a; 193238032Speter} 193390792Sgshapiro/* 193438032Speter** SELF_REFERENCE -- check to see if an address references itself 193538032Speter** 193638032Speter** The check is done through a chain of aliases. If it is part of 193738032Speter** a loop, break the loop at the "best" address, that is, the one 193838032Speter** that exists as a real user. 193938032Speter** 194038032Speter** This is to handle the case of: 194138032Speter** awc: Andrew.Chang 194238032Speter** Andrew.Chang: awc@mail.server 194338032Speter** which is a problem only on mail.server. 194438032Speter** 194538032Speter** Parameters: 194638032Speter** a -- the address to check. 194738032Speter** 194838032Speter** Returns: 194938032Speter** The address that should be retained. 195038032Speter*/ 195138032Speter 195264562Sgshapirostatic ADDRESS * 195364562Sgshapiroself_reference(a) 195438032Speter ADDRESS *a; 195538032Speter{ 195638032Speter ADDRESS *b; /* top entry in self ref loop */ 195738032Speter ADDRESS *c; /* entry that point to a real mail box */ 195838032Speter 195938032Speter if (tTd(27, 1)) 196090792Sgshapiro sm_dprintf("self_reference(%s)\n", a->q_paddr); 196138032Speter 196238032Speter for (b = a->q_alias; b != NULL; b = b->q_alias) 196338032Speter { 196438032Speter if (sameaddr(a, b)) 196538032Speter break; 196638032Speter } 196738032Speter 196838032Speter if (b == NULL) 196938032Speter { 197038032Speter if (tTd(27, 1)) 197190792Sgshapiro sm_dprintf("\t... no self ref\n"); 197238032Speter return NULL; 197338032Speter } 197438032Speter 197538032Speter /* 197638032Speter ** Pick the first address that resolved to a real mail box 197790792Sgshapiro ** i.e has a mbdb entry. The returned value will be marked 197838032Speter ** QSELFREF in recipient(), which in turn will disable alias() 197964562Sgshapiro ** from marking it as QS_IS_DEAD(), which mean it will be used 198038032Speter ** as a deliverable address. 198138032Speter ** 198238032Speter ** The 2 key thing to note here are: 198338032Speter ** 1) we are in a recursive call sequence: 198490792Sgshapiro ** alias->sendtolist->recipient->alias 198538032Speter ** 2) normally, when we return back to alias(), the address 198664562Sgshapiro ** will be marked QS_EXPANDED, since alias() assumes the 198738032Speter ** expanded form will be used instead of the current address. 198838032Speter ** This behaviour is turned off if the address is marked 198990792Sgshapiro ** QSELFREF. We set QSELFREF when we return to recipient(). 199038032Speter */ 199138032Speter 199238032Speter c = a; 199338032Speter while (c != NULL) 199438032Speter { 199543730Speter if (tTd(27, 10)) 199690792Sgshapiro sm_dprintf(" %s", c->q_user); 199738032Speter if (bitnset(M_HASPWENT, c->q_mailer->m_flags)) 199838032Speter { 199990792Sgshapiro SM_MBDB_T user; 200090792Sgshapiro 200138032Speter if (tTd(27, 2)) 200290792Sgshapiro sm_dprintf("\t... getpwnam(%s)... ", c->q_user); 200390792Sgshapiro if (sm_mbdb_lookup(c->q_user, &user) == EX_OK) 200438032Speter { 200538032Speter if (tTd(27, 2)) 200690792Sgshapiro sm_dprintf("found\n"); 200738032Speter 200838032Speter /* ought to cache results here */ 200938032Speter if (sameaddr(b, c)) 201038032Speter return b; 201138032Speter else 201238032Speter return c; 201338032Speter } 201438032Speter if (tTd(27, 2)) 201590792Sgshapiro sm_dprintf("failed\n"); 201638032Speter } 201743730Speter else 201843730Speter { 201943730Speter /* if local delivery, compare usernames */ 202043730Speter if (bitnset(M_LOCALMAILER, c->q_mailer->m_flags) && 202143730Speter b->q_mailer == c->q_mailer) 202243730Speter { 202343730Speter if (tTd(27, 2)) 202490792Sgshapiro sm_dprintf("\t... local match (%s)\n", 202564562Sgshapiro c->q_user); 202643730Speter if (sameaddr(b, c)) 202743730Speter return b; 202843730Speter else 202943730Speter return c; 203043730Speter } 203143730Speter } 203243730Speter if (tTd(27, 10)) 203390792Sgshapiro sm_dprintf("\n"); 203438032Speter c = c->q_alias; 203538032Speter } 203638032Speter 203738032Speter if (tTd(27, 1)) 203890792Sgshapiro sm_dprintf("\t... cannot break loop for \"%s\"\n", a->q_paddr); 203938032Speter 204038032Speter return NULL; 204138032Speter} 2042