recipient.c revision 125820
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 16125820SgshapiroSM_RCSID("@(#)$Id: recipient.c,v 8.330.2.4 2003/10/06 20:43:29 ca 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); 18690792Sgshapiro printaddr(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 "); 24890792Sgshapiro printaddr(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 "); 26190792Sgshapiro printaddr(b, false); 26238032Speter } 26390792Sgshapiro if (a != b) 26490792Sgshapiro { 26590792Sgshapiro if (tTd(27, 5)) 26690792Sgshapiro { 26790792Sgshapiro sm_dprintf("sendtolist: QS_DONTSEND "); 26890792Sgshapiro printaddr(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 "); 40690792Sgshapiro printaddr(&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); 47990792Sgshapiro printaddr(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); 73090792Sgshapiro printaddr(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: "); 80390792Sgshapiro printaddr(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]); 93390792Sgshapiro printaddr(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: "); 103190792Sgshapiro printaddr(new, false); 103238032Speter if (tTd(26, 10)) 103338032Speter { 103490792Sgshapiro sm_dprintf("SENDQ:\n"); 103590792Sgshapiro printaddr(*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 { 131238032Speter euid = FileMailer->m_uid; 131338032Speter egid = FileMailer->m_gid; 131464562Sgshapiro user = NULL; 131538032Speter } 131638032Speter else 131738032Speter { 131838032Speter euid = egid = 0; 131964562Sgshapiro user = NULL; 132038032Speter } 132138032Speter if (!bitset(SFF_ROOTOK, flags)) 132238032Speter { 132338032Speter if (euid == 0) 132438032Speter { 132538032Speter euid = DefUid; 132664562Sgshapiro user = DefUser; 132738032Speter } 132838032Speter if (egid == 0) 132938032Speter egid = DefGid; 133038032Speter } 133138032Speter if (geteuid() == 0 && 133238032Speter (ctladdr == NULL || !bitset(QGOODUID, ctladdr->q_flags))) 133338032Speter flags |= SFF_SETUIDOK; 133438032Speter 133564562Sgshapiro if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 133638032Speter flags |= SFF_NOSLINK; 133764562Sgshapiro if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) 133838032Speter flags |= SFF_NOHLINK; 133938032Speter 134064562Sgshapiro errno = safefile(filename, euid, egid, user, flags, S_IWRITE, NULL); 134138032Speter return errno == 0; 134238032Speter} 134390792Sgshapiro/* 134438032Speter** INCLUDE -- handle :include: specification. 134538032Speter** 134638032Speter** Parameters: 134738032Speter** fname -- filename to include. 134890792Sgshapiro** forwarding -- if true, we are reading a .forward file. 134990792Sgshapiro** if false, it's a :include: file. 135038032Speter** ctladdr -- address template to use to fill in these 135138032Speter** addresses -- effective user/group id are 135238032Speter** the important things. 135338032Speter** sendq -- a pointer to the head of the send queue 135438032Speter** to put these addresses in. 135538032Speter** aliaslevel -- the alias nesting depth. 135638032Speter** e -- the current envelope. 135738032Speter** 135838032Speter** Returns: 135938032Speter** open error status 136038032Speter** 136138032Speter** Side Effects: 136238032Speter** reads the :include: file and sends to everyone 136338032Speter** listed in that file. 136438032Speter** 136538032Speter** Security Note: 136638032Speter** If you have restricted chown (that is, you can't 136738032Speter** give a file away), it is reasonable to allow programs 136838032Speter** and files called from this :include: file to be to be 136938032Speter** run as the owner of the :include: file. This is bogus 137038032Speter** if there is any chance of someone giving away a file. 137138032Speter** We assume that pre-POSIX systems can give away files. 137238032Speter** 137338032Speter** There is an additional restriction that if you 137438032Speter** forward to a :include: file, it will not take on 137538032Speter** the ownership of the :include: file. This may not 137638032Speter** be necessary, but shouldn't hurt. 137738032Speter*/ 137838032Speter 137938032Speterstatic jmp_buf CtxIncludeTimeout; 138038032Speter 138138032Speterint 138238032Speterinclude(fname, forwarding, ctladdr, sendq, aliaslevel, e) 138338032Speter char *fname; 138438032Speter bool forwarding; 138538032Speter ADDRESS *ctladdr; 138638032Speter ADDRESS **sendq; 138738032Speter int aliaslevel; 138838032Speter ENVELOPE *e; 138938032Speter{ 139090792Sgshapiro SM_FILE_T *volatile fp = NULL; 139138032Speter char *oldto = e->e_to; 139238032Speter char *oldfilename = FileName; 139338032Speter int oldlinenumber = LineNumber; 139490792Sgshapiro register SM_EVENT *ev = NULL; 139538032Speter int nincludes; 139638032Speter int mode; 139790792Sgshapiro volatile bool maxreached = false; 139838032Speter register ADDRESS *ca; 139964562Sgshapiro volatile uid_t saveduid; 140064562Sgshapiro volatile gid_t savedgid; 140164562Sgshapiro volatile uid_t uid; 140264562Sgshapiro volatile gid_t gid; 140364562Sgshapiro char *volatile user; 140438032Speter int rval = 0; 140564562Sgshapiro volatile long sfflags = SFF_REGONLY; 140638032Speter register char *p; 140790792Sgshapiro bool safechown = false; 140890792Sgshapiro volatile bool safedir = false; 140938032Speter struct stat st; 141038032Speter char buf[MAXLINE]; 141138032Speter 141238032Speter if (tTd(27, 2)) 141390792Sgshapiro sm_dprintf("include(%s)\n", fname); 141438032Speter if (tTd(27, 4)) 141590792Sgshapiro sm_dprintf(" ruid=%d euid=%d\n", 141664562Sgshapiro (int) getuid(), (int) geteuid()); 141738032Speter if (tTd(27, 14)) 141838032Speter { 141990792Sgshapiro sm_dprintf("ctladdr "); 142090792Sgshapiro printaddr(ctladdr, false); 142138032Speter } 142238032Speter 142338032Speter if (tTd(27, 9)) 142490792Sgshapiro sm_dprintf("include: old uid = %d/%d\n", 142590792Sgshapiro (int) getuid(), (int) geteuid()); 142638032Speter 142738032Speter if (forwarding) 142866494Sgshapiro { 142998121Sgshapiro sfflags |= SFF_MUSTOWN|SFF_ROOTOK; 143066494Sgshapiro if (!bitnset(DBS_GROUPWRITABLEFORWARDFILE, DontBlameSendmail)) 143166494Sgshapiro sfflags |= SFF_NOGWFILES; 143266494Sgshapiro if (!bitnset(DBS_WORLDWRITABLEFORWARDFILE, DontBlameSendmail)) 143366494Sgshapiro sfflags |= SFF_NOWWFILES; 143466494Sgshapiro } 143566494Sgshapiro else 143666494Sgshapiro { 143766494Sgshapiro if (!bitnset(DBS_GROUPWRITABLEINCLUDEFILE, DontBlameSendmail)) 143866494Sgshapiro sfflags |= SFF_NOGWFILES; 143966494Sgshapiro if (!bitnset(DBS_WORLDWRITABLEINCLUDEFILE, DontBlameSendmail)) 144066494Sgshapiro sfflags |= SFF_NOWWFILES; 144166494Sgshapiro } 144266494Sgshapiro 144364562Sgshapiro /* 144464562Sgshapiro ** If RunAsUser set, won't be able to run programs as user 144564562Sgshapiro ** so mark them as unsafe unless the administrator knows better. 144664562Sgshapiro */ 144764562Sgshapiro 144864562Sgshapiro if ((geteuid() != 0 || RunAsUid != 0) && 144964562Sgshapiro !bitnset(DBS_NONROOTSAFEADDR, DontBlameSendmail)) 145064562Sgshapiro { 145164562Sgshapiro if (tTd(27, 4)) 145290792Sgshapiro sm_dprintf("include: not safe (euid=%d, RunAsUid=%d)\n", 145390792Sgshapiro (int) geteuid(), (int) RunAsUid); 145464562Sgshapiro ctladdr->q_flags |= QUNSAFEADDR; 145564562Sgshapiro } 145664562Sgshapiro 145738032Speter ca = getctladdr(ctladdr); 145864562Sgshapiro if (ca == NULL || 145964562Sgshapiro (ca->q_uid == DefUid && ca->q_gid == 0)) 146038032Speter { 146138032Speter uid = DefUid; 146238032Speter gid = DefGid; 146364562Sgshapiro user = DefUser; 146438032Speter } 146538032Speter else 146638032Speter { 146738032Speter uid = ca->q_uid; 146838032Speter gid = ca->q_gid; 146964562Sgshapiro user = ca->q_user; 147038032Speter } 147164562Sgshapiro#if MAILER_SETUID_METHOD != USE_SETUID 147238032Speter saveduid = geteuid(); 147338032Speter savedgid = getegid(); 147438032Speter if (saveduid == 0) 147538032Speter { 147638032Speter if (!DontInitGroups) 147738032Speter { 147864562Sgshapiro if (initgroups(user, gid) == -1) 147964562Sgshapiro { 148064562Sgshapiro rval = EAGAIN; 148138032Speter syserr("include: initgroups(%s, %d) failed", 148264562Sgshapiro user, gid); 148364562Sgshapiro goto resetuid; 148464562Sgshapiro } 148538032Speter } 148638032Speter else 148738032Speter { 148838032Speter GIDSET_T gidset[1]; 148938032Speter 149038032Speter gidset[0] = gid; 149138032Speter if (setgroups(1, gidset) == -1) 149264562Sgshapiro { 149364562Sgshapiro rval = EAGAIN; 149438032Speter syserr("include: setgroups() failed"); 149564562Sgshapiro goto resetuid; 149664562Sgshapiro } 149738032Speter } 149838032Speter 149938032Speter if (gid != 0 && setgid(gid) < -1) 150064562Sgshapiro { 150164562Sgshapiro rval = EAGAIN; 150238032Speter syserr("setgid(%d) failure", gid); 150364562Sgshapiro goto resetuid; 150464562Sgshapiro } 150538032Speter if (uid != 0) 150638032Speter { 150764562Sgshapiro# if MAILER_SETUID_METHOD == USE_SETEUID 150838032Speter if (seteuid(uid) < 0) 150964562Sgshapiro { 151064562Sgshapiro rval = EAGAIN; 151138032Speter syserr("seteuid(%d) failure (real=%d, eff=%d)", 151298121Sgshapiro uid, (int) getuid(), (int) geteuid()); 151364562Sgshapiro goto resetuid; 151464562Sgshapiro } 151564562Sgshapiro# endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 151664562Sgshapiro# if MAILER_SETUID_METHOD == USE_SETREUID 151738032Speter if (setreuid(0, uid) < 0) 151864562Sgshapiro { 151964562Sgshapiro rval = EAGAIN; 152038032Speter syserr("setreuid(0, %d) failure (real=%d, eff=%d)", 152198121Sgshapiro uid, (int) getuid(), (int) geteuid()); 152264562Sgshapiro goto resetuid; 152364562Sgshapiro } 152464562Sgshapiro# endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 152538032Speter } 152638032Speter } 152764562Sgshapiro#endif /* MAILER_SETUID_METHOD != USE_SETUID */ 152838032Speter 152938032Speter if (tTd(27, 9)) 153090792Sgshapiro sm_dprintf("include: new uid = %d/%d\n", 153190792Sgshapiro (int) getuid(), (int) geteuid()); 153238032Speter 153338032Speter /* 153438032Speter ** If home directory is remote mounted but server is down, 153538032Speter ** this can hang or give errors; use a timeout to avoid this 153638032Speter */ 153738032Speter 153838032Speter if (setjmp(CtxIncludeTimeout) != 0) 153938032Speter { 154064562Sgshapiro ctladdr->q_state = QS_QUEUEUP; 154138032Speter errno = 0; 154238032Speter 154338032Speter /* return pseudo-error code */ 154438032Speter rval = E_SM_OPENTIMEOUT; 154538032Speter goto resetuid; 154638032Speter } 154738032Speter if (TimeOuts.to_fileopen > 0) 154890792Sgshapiro ev = sm_setevent(TimeOuts.to_fileopen, includetimeout, 0); 154938032Speter else 155038032Speter ev = NULL; 155138032Speter 155264562Sgshapiro 155338032Speter /* check for writable parent directory */ 155438032Speter p = strrchr(fname, '/'); 155538032Speter if (p != NULL) 155638032Speter { 155738032Speter int ret; 155838032Speter 155938032Speter *p = '\0'; 156064562Sgshapiro ret = safedirpath(fname, uid, gid, user, 156164562Sgshapiro sfflags|SFF_SAFEDIRPATH, 0, 0); 156238032Speter if (ret == 0) 156338032Speter { 156438032Speter /* in safe directory: relax chown & link rules */ 156590792Sgshapiro safedir = true; 156638032Speter sfflags |= SFF_NOPATHCHECK; 156738032Speter } 156838032Speter else 156938032Speter { 157064562Sgshapiro if (bitnset((forwarding ? 157164562Sgshapiro DBS_FORWARDFILEINUNSAFEDIRPATH : 157264562Sgshapiro DBS_INCLUDEFILEINUNSAFEDIRPATH), 157364562Sgshapiro DontBlameSendmail)) 157438032Speter sfflags |= SFF_NOPATHCHECK; 157564562Sgshapiro else if (bitnset((forwarding ? 157664562Sgshapiro DBS_FORWARDFILEINGROUPWRITABLEDIRPATH : 157764562Sgshapiro DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH), 157864562Sgshapiro DontBlameSendmail) && 157938032Speter ret == E_SM_GWDIR) 158038032Speter { 158164562Sgshapiro setbitn(DBS_GROUPWRITABLEDIRPATHSAFE, 158264562Sgshapiro DontBlameSendmail); 158364562Sgshapiro ret = safedirpath(fname, uid, gid, user, 158464562Sgshapiro sfflags|SFF_SAFEDIRPATH, 158564562Sgshapiro 0, 0); 158664562Sgshapiro clrbitn(DBS_GROUPWRITABLEDIRPATHSAFE, 158764562Sgshapiro DontBlameSendmail); 158838032Speter if (ret == 0) 158938032Speter sfflags |= SFF_NOPATHCHECK; 159038032Speter else 159138032Speter sfflags |= SFF_SAFEDIRPATH; 159238032Speter } 159338032Speter else 159438032Speter sfflags |= SFF_SAFEDIRPATH; 159538032Speter if (ret > E_PSEUDOBASE && 159664562Sgshapiro !bitnset((forwarding ? 159764562Sgshapiro DBS_FORWARDFILEINUNSAFEDIRPATHSAFE : 159864562Sgshapiro DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE), 159964562Sgshapiro DontBlameSendmail)) 160038032Speter { 160190792Sgshapiro if (LogLevel > 11) 160238032Speter sm_syslog(LOG_INFO, e->e_id, 160338032Speter "%s: unsafe directory path, marked unsafe", 160438032Speter shortenstring(fname, MAXSHORTSTR)); 160538032Speter ctladdr->q_flags |= QUNSAFEADDR; 160638032Speter } 160738032Speter } 160838032Speter *p = '/'; 160938032Speter } 161038032Speter 161138032Speter /* allow links only in unwritable directories */ 161238032Speter if (!safedir && 161364562Sgshapiro !bitnset((forwarding ? 161464562Sgshapiro DBS_LINKEDFORWARDFILEINWRITABLEDIR : 161564562Sgshapiro DBS_LINKEDINCLUDEFILEINWRITABLEDIR), 161664562Sgshapiro DontBlameSendmail)) 161738032Speter sfflags |= SFF_NOLINK; 161838032Speter 161964562Sgshapiro rval = safefile(fname, uid, gid, user, sfflags, S_IREAD, &st); 162038032Speter if (rval != 0) 162138032Speter { 162238032Speter /* don't use this :include: file */ 162338032Speter if (tTd(27, 4)) 162490792Sgshapiro sm_dprintf("include: not safe (uid=%d): %s\n", 162590792Sgshapiro (int) uid, sm_errstring(rval)); 162638032Speter } 162790792Sgshapiro else if ((fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, fname, 162890792Sgshapiro SM_IO_RDONLY, NULL)) == NULL) 162938032Speter { 163038032Speter rval = errno; 163138032Speter if (tTd(27, 4)) 163290792Sgshapiro sm_dprintf("include: open: %s\n", sm_errstring(rval)); 163338032Speter } 163490792Sgshapiro else if (filechanged(fname, sm_io_getinfo(fp,SM_IO_WHAT_FD, NULL), &st)) 163538032Speter { 163638032Speter rval = E_SM_FILECHANGE; 163738032Speter if (tTd(27, 4)) 163890792Sgshapiro sm_dprintf("include: file changed after open\n"); 163938032Speter } 164038032Speter if (ev != NULL) 164190792Sgshapiro sm_clrevent(ev); 164238032Speter 164338032Speterresetuid: 164438032Speter 164538032Speter#if HASSETREUID || USESETEUID 164638032Speter if (saveduid == 0) 164738032Speter { 164838032Speter if (uid != 0) 164938032Speter { 165038032Speter# if USESETEUID 165138032Speter if (seteuid(0) < 0) 165264562Sgshapiro syserr("!seteuid(0) failure (real=%d, eff=%d)", 165390792Sgshapiro (int) getuid(), (int) geteuid()); 165464562Sgshapiro# else /* USESETEUID */ 165538032Speter if (setreuid(-1, 0) < 0) 165664562Sgshapiro syserr("!setreuid(-1, 0) failure (real=%d, eff=%d)", 165790792Sgshapiro (int) getuid(), (int) geteuid()); 165838032Speter if (setreuid(RealUid, 0) < 0) 165964562Sgshapiro syserr("!setreuid(%d, 0) failure (real=%d, eff=%d)", 166090792Sgshapiro (int) RealUid, (int) getuid(), 166190792Sgshapiro (int) geteuid()); 166264562Sgshapiro# endif /* USESETEUID */ 166338032Speter } 166464562Sgshapiro if (setgid(savedgid) < 0) 166564562Sgshapiro syserr("!setgid(%d) failure (real=%d eff=%d)", 166690792Sgshapiro (int) savedgid, (int) getgid(), 166790792Sgshapiro (int) getegid()); 166838032Speter } 166964562Sgshapiro#endif /* HASSETREUID || USESETEUID */ 167038032Speter 167138032Speter if (tTd(27, 9)) 167290792Sgshapiro sm_dprintf("include: reset uid = %d/%d\n", 167390792Sgshapiro (int) getuid(), (int) geteuid()); 167438032Speter 167538032Speter if (rval == E_SM_OPENTIMEOUT) 167664562Sgshapiro usrerr("451 4.4.1 open timeout on %s", fname); 167738032Speter 167838032Speter if (fp == NULL) 167938032Speter return rval; 168038032Speter 168190792Sgshapiro if (fstat(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), &st) < 0) 168238032Speter { 168338032Speter rval = errno; 168438032Speter syserr("Cannot fstat %s!", fname); 168590792Sgshapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 168638032Speter return rval; 168738032Speter } 168838032Speter 168938032Speter /* if path was writable, check to avoid file giveaway tricks */ 169090792Sgshapiro safechown = chownsafe(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), safedir); 169138032Speter if (tTd(27, 6)) 169290792Sgshapiro sm_dprintf("include: parent of %s is %s, chown is %ssafe\n", 169390792Sgshapiro fname, safedir ? "safe" : "dangerous", 169490792Sgshapiro safechown ? "" : "un"); 169538032Speter 169664562Sgshapiro /* if no controlling user or coming from an alias delivery */ 169764562Sgshapiro if (safechown && 169864562Sgshapiro (ca == NULL || 169964562Sgshapiro (ca->q_uid == DefUid && ca->q_gid == 0))) 170038032Speter { 170138032Speter ctladdr->q_uid = st.st_uid; 170238032Speter ctladdr->q_gid = st.st_gid; 170338032Speter ctladdr->q_flags |= QGOODUID; 170438032Speter } 170538032Speter if (ca != NULL && ca->q_uid == st.st_uid) 170638032Speter { 170738032Speter /* optimization -- avoid getpwuid if we already have info */ 170838032Speter ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 170938032Speter ctladdr->q_ruser = ca->q_ruser; 171038032Speter } 171138032Speter else if (!forwarding) 171238032Speter { 171338032Speter register struct passwd *pw; 171438032Speter 171538032Speter pw = sm_getpwuid(st.st_uid); 171638032Speter if (pw == NULL) 171764562Sgshapiro { 171864562Sgshapiro ctladdr->q_uid = st.st_uid; 171938032Speter ctladdr->q_flags |= QBOGUSSHELL; 172064562Sgshapiro } 172138032Speter else 172238032Speter { 172338032Speter char *sh; 172438032Speter 172590792Sgshapiro ctladdr->q_ruser = sm_rpool_strdup_x(e->e_rpool, 172690792Sgshapiro pw->pw_name); 172738032Speter if (safechown) 172838032Speter sh = pw->pw_shell; 172938032Speter else 173038032Speter sh = "/SENDMAIL/ANY/SHELL/"; 173138032Speter if (!usershellok(pw->pw_name, sh)) 173238032Speter { 173390792Sgshapiro if (LogLevel > 11) 173438032Speter sm_syslog(LOG_INFO, e->e_id, 173564562Sgshapiro "%s: user %s has bad shell %s, marked %s", 173690792Sgshapiro shortenstring(fname, 173790792Sgshapiro MAXSHORTSTR), 173864562Sgshapiro pw->pw_name, sh, 173964562Sgshapiro safechown ? "bogus" : "unsafe"); 174038032Speter if (safechown) 174138032Speter ctladdr->q_flags |= QBOGUSSHELL; 174238032Speter else 174338032Speter ctladdr->q_flags |= QUNSAFEADDR; 174438032Speter } 174538032Speter } 174638032Speter } 174738032Speter 174838032Speter if (bitset(EF_VRFYONLY, e->e_flags)) 174938032Speter { 175038032Speter /* don't do any more now */ 175164562Sgshapiro ctladdr->q_state = QS_VERIFIED; 175238032Speter e->e_nrcpts++; 175390792Sgshapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 175438032Speter return rval; 175538032Speter } 175638032Speter 175738032Speter /* 175842575Speter ** Check to see if some bad guy can write this file 175938032Speter ** 176038032Speter ** Group write checking could be more clever, e.g., 176138032Speter ** guessing as to which groups are actually safe ("sys" 176238032Speter ** may be; "user" probably is not). 176338032Speter */ 176438032Speter 176538032Speter mode = S_IWOTH; 176664562Sgshapiro if (!bitnset((forwarding ? 176764562Sgshapiro DBS_GROUPWRITABLEFORWARDFILESAFE : 176864562Sgshapiro DBS_GROUPWRITABLEINCLUDEFILESAFE), 176964562Sgshapiro DontBlameSendmail)) 177038032Speter mode |= S_IWGRP; 177138032Speter 177238032Speter if (bitset(mode, st.st_mode)) 177338032Speter { 177438032Speter if (tTd(27, 6)) 177590792Sgshapiro sm_dprintf("include: %s is %s writable, marked unsafe\n", 177690792Sgshapiro shortenstring(fname, MAXSHORTSTR), 177790792Sgshapiro bitset(S_IWOTH, st.st_mode) ? "world" 177890792Sgshapiro : "group"); 177990792Sgshapiro if (LogLevel > 11) 178038032Speter sm_syslog(LOG_INFO, e->e_id, 178164562Sgshapiro "%s: %s writable %s file, marked unsafe", 178264562Sgshapiro shortenstring(fname, MAXSHORTSTR), 178364562Sgshapiro bitset(S_IWOTH, st.st_mode) ? "world" : "group", 178464562Sgshapiro forwarding ? "forward" : ":include:"); 178538032Speter ctladdr->q_flags |= QUNSAFEADDR; 178638032Speter } 178738032Speter 178838032Speter /* read the file -- each line is a comma-separated list. */ 178938032Speter FileName = fname; 179038032Speter LineNumber = 0; 179138032Speter ctladdr->q_flags &= ~QSELFREF; 179238032Speter nincludes = 0; 179390792Sgshapiro while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL && 179490792Sgshapiro !maxreached) 179538032Speter { 179690792Sgshapiro fixcrlf(buf, true); 179738032Speter LineNumber++; 179838032Speter if (buf[0] == '#' || buf[0] == '\0') 179938032Speter continue; 180038032Speter 180138032Speter /* <sp>#@# introduces a comment anywhere */ 180238032Speter /* for Japanese character sets */ 180338032Speter for (p = buf; (p = strchr(++p, '#')) != NULL; ) 180438032Speter { 180538032Speter if (p[1] == '@' && p[2] == '#' && 180638032Speter isascii(p[-1]) && isspace(p[-1]) && 180738032Speter (p[3] == '\0' || (isascii(p[3]) && isspace(p[3])))) 180838032Speter { 180966494Sgshapiro --p; 181066494Sgshapiro while (p > buf && isascii(p[-1]) && 181166494Sgshapiro isspace(p[-1])) 181266494Sgshapiro --p; 181366494Sgshapiro p[0] = '\0'; 181438032Speter break; 181538032Speter } 181638032Speter } 181738032Speter if (buf[0] == '\0') 181838032Speter continue; 181938032Speter 182038032Speter e->e_to = NULL; 182138032Speter message("%s to %s", 182238032Speter forwarding ? "forwarding" : "sending", buf); 182364562Sgshapiro if (forwarding && LogLevel > 10) 182438032Speter sm_syslog(LOG_INFO, e->e_id, 182564562Sgshapiro "forward %.200s => %s", 182664562Sgshapiro oldto, shortenstring(buf, MAXSHORTSTR)); 182738032Speter 182838032Speter nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); 182964562Sgshapiro 183064562Sgshapiro if (forwarding && 183164562Sgshapiro MaxForwardEntries > 0 && 183264562Sgshapiro nincludes >= MaxForwardEntries) 183364562Sgshapiro { 183464562Sgshapiro /* just stop reading and processing further entries */ 183590792Sgshapiro#if 0 183690792Sgshapiro /* additional: (?) */ 183764562Sgshapiro ctladdr->q_state = QS_DONTSEND; 183890792Sgshapiro#endif /* 0 */ 183990792Sgshapiro 184090792Sgshapiro syserr("Attempt to forward to more than %d addresses (in %s)!", 184198121Sgshapiro MaxForwardEntries, fname); 184290792Sgshapiro maxreached = true; 184364562Sgshapiro } 184438032Speter } 184538032Speter 184690792Sgshapiro if (sm_io_error(fp) && tTd(27, 3)) 184790792Sgshapiro sm_dprintf("include: read error: %s\n", sm_errstring(errno)); 184838032Speter if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 184938032Speter { 185038032Speter if (tTd(27, 5)) 185138032Speter { 185290792Sgshapiro sm_dprintf("include: QS_DONTSEND "); 185390792Sgshapiro printaddr(ctladdr, false); 185438032Speter } 185564562Sgshapiro ctladdr->q_state = QS_DONTSEND; 185638032Speter } 185738032Speter 185890792Sgshapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 185938032Speter FileName = oldfilename; 186038032Speter LineNumber = oldlinenumber; 186138032Speter e->e_to = oldto; 186238032Speter return rval; 186338032Speter} 186438032Speter 186538032Speterstatic void 186638032Speterincludetimeout() 186738032Speter{ 186877349Sgshapiro /* 186977349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 187077349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 187177349Sgshapiro ** DOING. 187277349Sgshapiro */ 187377349Sgshapiro 187477349Sgshapiro errno = ETIMEDOUT; 187538032Speter longjmp(CtxIncludeTimeout, 1); 187638032Speter} 187790792Sgshapiro/* 187838032Speter** SENDTOARGV -- send to an argument vector. 187938032Speter** 188038032Speter** Parameters: 188138032Speter** argv -- argument vector to send to. 188238032Speter** e -- the current envelope. 188338032Speter** 188438032Speter** Returns: 188538032Speter** none. 188638032Speter** 188738032Speter** Side Effects: 188838032Speter** puts all addresses on the argument vector onto the 188938032Speter** send queue. 189038032Speter*/ 189138032Speter 189238032Spetervoid 189338032Spetersendtoargv(argv, e) 189438032Speter register char **argv; 189538032Speter register ENVELOPE *e; 189638032Speter{ 189738032Speter register char *p; 189838032Speter 189938032Speter while ((p = *argv++) != NULL) 190038032Speter (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e); 190138032Speter} 190290792Sgshapiro/* 190338032Speter** GETCTLADDR -- get controlling address from an address header. 190438032Speter** 190538032Speter** If none, get one corresponding to the effective userid. 190638032Speter** 190738032Speter** Parameters: 190838032Speter** a -- the address to find the controller of. 190938032Speter** 191038032Speter** Returns: 191138032Speter** the controlling address. 191238032Speter*/ 191338032Speter 191438032SpeterADDRESS * 191538032Spetergetctladdr(a) 191638032Speter register ADDRESS *a; 191738032Speter{ 191838032Speter while (a != NULL && !bitset(QGOODUID, a->q_flags)) 191938032Speter a = a->q_alias; 192064562Sgshapiro return a; 192138032Speter} 192290792Sgshapiro/* 192338032Speter** SELF_REFERENCE -- check to see if an address references itself 192438032Speter** 192538032Speter** The check is done through a chain of aliases. If it is part of 192638032Speter** a loop, break the loop at the "best" address, that is, the one 192738032Speter** that exists as a real user. 192838032Speter** 192938032Speter** This is to handle the case of: 193038032Speter** awc: Andrew.Chang 193138032Speter** Andrew.Chang: awc@mail.server 193238032Speter** which is a problem only on mail.server. 193338032Speter** 193438032Speter** Parameters: 193538032Speter** a -- the address to check. 193638032Speter** 193738032Speter** Returns: 193838032Speter** The address that should be retained. 193938032Speter*/ 194038032Speter 194164562Sgshapirostatic ADDRESS * 194264562Sgshapiroself_reference(a) 194338032Speter ADDRESS *a; 194438032Speter{ 194538032Speter ADDRESS *b; /* top entry in self ref loop */ 194638032Speter ADDRESS *c; /* entry that point to a real mail box */ 194738032Speter 194838032Speter if (tTd(27, 1)) 194990792Sgshapiro sm_dprintf("self_reference(%s)\n", a->q_paddr); 195038032Speter 195138032Speter for (b = a->q_alias; b != NULL; b = b->q_alias) 195238032Speter { 195338032Speter if (sameaddr(a, b)) 195438032Speter break; 195538032Speter } 195638032Speter 195738032Speter if (b == NULL) 195838032Speter { 195938032Speter if (tTd(27, 1)) 196090792Sgshapiro sm_dprintf("\t... no self ref\n"); 196138032Speter return NULL; 196238032Speter } 196338032Speter 196438032Speter /* 196538032Speter ** Pick the first address that resolved to a real mail box 196690792Sgshapiro ** i.e has a mbdb entry. The returned value will be marked 196738032Speter ** QSELFREF in recipient(), which in turn will disable alias() 196864562Sgshapiro ** from marking it as QS_IS_DEAD(), which mean it will be used 196938032Speter ** as a deliverable address. 197038032Speter ** 197138032Speter ** The 2 key thing to note here are: 197238032Speter ** 1) we are in a recursive call sequence: 197390792Sgshapiro ** alias->sendtolist->recipient->alias 197438032Speter ** 2) normally, when we return back to alias(), the address 197564562Sgshapiro ** will be marked QS_EXPANDED, since alias() assumes the 197638032Speter ** expanded form will be used instead of the current address. 197738032Speter ** This behaviour is turned off if the address is marked 197890792Sgshapiro ** QSELFREF. We set QSELFREF when we return to recipient(). 197938032Speter */ 198038032Speter 198138032Speter c = a; 198238032Speter while (c != NULL) 198338032Speter { 198443730Speter if (tTd(27, 10)) 198590792Sgshapiro sm_dprintf(" %s", c->q_user); 198638032Speter if (bitnset(M_HASPWENT, c->q_mailer->m_flags)) 198738032Speter { 198890792Sgshapiro SM_MBDB_T user; 198990792Sgshapiro 199038032Speter if (tTd(27, 2)) 199190792Sgshapiro sm_dprintf("\t... getpwnam(%s)... ", c->q_user); 199290792Sgshapiro if (sm_mbdb_lookup(c->q_user, &user) == EX_OK) 199338032Speter { 199438032Speter if (tTd(27, 2)) 199590792Sgshapiro sm_dprintf("found\n"); 199638032Speter 199738032Speter /* ought to cache results here */ 199838032Speter if (sameaddr(b, c)) 199938032Speter return b; 200038032Speter else 200138032Speter return c; 200238032Speter } 200338032Speter if (tTd(27, 2)) 200490792Sgshapiro sm_dprintf("failed\n"); 200538032Speter } 200643730Speter else 200743730Speter { 200843730Speter /* if local delivery, compare usernames */ 200943730Speter if (bitnset(M_LOCALMAILER, c->q_mailer->m_flags) && 201043730Speter b->q_mailer == c->q_mailer) 201143730Speter { 201243730Speter if (tTd(27, 2)) 201390792Sgshapiro sm_dprintf("\t... local match (%s)\n", 201464562Sgshapiro c->q_user); 201543730Speter if (sameaddr(b, c)) 201643730Speter return b; 201743730Speter else 201843730Speter return c; 201943730Speter } 202043730Speter } 202143730Speter if (tTd(27, 10)) 202290792Sgshapiro sm_dprintf("\n"); 202338032Speter c = c->q_alias; 202438032Speter } 202538032Speter 202638032Speter if (tTd(27, 1)) 202790792Sgshapiro sm_dprintf("\t... cannot break loop for \"%s\"\n", a->q_paddr); 202838032Speter 202938032Speter return NULL; 203038032Speter} 2031