1c2aa98e2SPeter Wemm /*
25dd76dd0SGregory Neil Shapiro * Copyright (c) 1998-2003, 2006 Proofpoint, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro * All rights reserved.
4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved.
7c2aa98e2SPeter Wemm *
8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm * the sendmail distribution.
11c2aa98e2SPeter Wemm *
12c2aa98e2SPeter Wemm */
13c2aa98e2SPeter Wemm
1406f25ae9SGregory Neil Shapiro #include <sendmail.h>
1506f25ae9SGregory Neil Shapiro
164313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: recipient.c,v 8.351 2013-11-22 20:51:56 ca Exp $")
1706f25ae9SGregory Neil Shapiro
182fb4f839SGregory Neil Shapiro #include <sm/sendmail.h>
192fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
202fb4f839SGregory Neil Shapiro # include <sm/ixlen.h>
212fb4f839SGregory Neil Shapiro #endif
222fb4f839SGregory Neil Shapiro
23b6bacd31SGregory Neil Shapiro static void includetimeout __P((int));
2406f25ae9SGregory Neil Shapiro static ADDRESS *self_reference __P((ADDRESS *));
2540266059SGregory Neil Shapiro static int sortexpensive __P((ADDRESS *, ADDRESS *));
2640266059SGregory Neil Shapiro static int sortbysignature __P((ADDRESS *, ADDRESS *));
2740266059SGregory Neil Shapiro static int sorthost __P((ADDRESS *, ADDRESS *));
2840266059SGregory Neil Shapiro
2940266059SGregory Neil Shapiro typedef int sortfn_t __P((ADDRESS *, ADDRESS *));
3040266059SGregory Neil Shapiro
3140266059SGregory Neil Shapiro /*
3240266059SGregory Neil Shapiro ** SORTHOST -- strcmp()-like func for host portion of an ADDRESS
3340266059SGregory Neil Shapiro **
3440266059SGregory Neil Shapiro ** Parameters:
3540266059SGregory Neil Shapiro ** xx -- first ADDRESS
3640266059SGregory Neil Shapiro ** yy -- second ADDRESS
3740266059SGregory Neil Shapiro **
3840266059SGregory Neil Shapiro ** Returns:
3940266059SGregory Neil Shapiro ** <0 when xx->q_host is less than yy->q_host
4040266059SGregory Neil Shapiro ** >0 when xx->q_host is greater than yy->q_host
4140266059SGregory Neil Shapiro ** 0 when equal
4240266059SGregory Neil Shapiro */
4340266059SGregory Neil Shapiro
4440266059SGregory Neil Shapiro static int
sorthost(xx,yy)4540266059SGregory Neil Shapiro sorthost(xx, yy)
4640266059SGregory Neil Shapiro register ADDRESS *xx;
4740266059SGregory Neil Shapiro register ADDRESS *yy;
4840266059SGregory Neil Shapiro {
4940266059SGregory Neil Shapiro #if _FFR_HOST_SORT_REVERSE
5040266059SGregory Neil Shapiro /* XXX maybe compare hostnames from the end? */
5140266059SGregory Neil Shapiro return sm_strrevcasecmp(xx->q_host, yy->q_host);
525b0945b5SGregory Neil Shapiro #else
5340266059SGregory Neil Shapiro return sm_strcasecmp(xx->q_host, yy->q_host);
545b0945b5SGregory Neil Shapiro #endif
5540266059SGregory Neil Shapiro }
5640266059SGregory Neil Shapiro
5740266059SGregory Neil Shapiro /*
5840266059SGregory Neil Shapiro ** SORTEXPENSIVE -- strcmp()-like func for expensive mailers
5940266059SGregory Neil Shapiro **
6040266059SGregory Neil Shapiro ** The mailer has been noted already as "expensive" for 'xx'. This
6140266059SGregory Neil Shapiro ** will give a result relative to 'yy'. Expensive mailers get rated
6240266059SGregory Neil Shapiro ** "greater than" non-expensive mailers because during the delivery phase
6340266059SGregory Neil Shapiro ** it will get queued -- no use it getting in the way of less expensive
6440266059SGregory Neil Shapiro ** recipients. We avoid an MX RR lookup when both 'xx' and 'yy' are
6540266059SGregory Neil Shapiro ** expensive since an MX RR lookup happens when extracted from the queue
6640266059SGregory Neil Shapiro ** later.
6740266059SGregory Neil Shapiro **
6840266059SGregory Neil Shapiro ** Parameters:
6940266059SGregory Neil Shapiro ** xx -- first ADDRESS
7040266059SGregory Neil Shapiro ** yy -- second ADDRESS
7140266059SGregory Neil Shapiro **
7240266059SGregory Neil Shapiro ** Returns:
7340266059SGregory Neil Shapiro ** <0 when xx->q_host is less than yy->q_host and both are
7440266059SGregory Neil Shapiro ** expensive
7540266059SGregory Neil Shapiro ** >0 when xx->q_host is greater than yy->q_host, or when
7640266059SGregory Neil Shapiro ** 'yy' is non-expensive
7740266059SGregory Neil Shapiro ** 0 when equal (by expense and q_host)
7840266059SGregory Neil Shapiro */
7940266059SGregory Neil Shapiro
8040266059SGregory Neil Shapiro static int
sortexpensive(xx,yy)8140266059SGregory Neil Shapiro sortexpensive(xx, yy)
8240266059SGregory Neil Shapiro ADDRESS *xx;
8340266059SGregory Neil Shapiro ADDRESS *yy;
8440266059SGregory Neil Shapiro {
8540266059SGregory Neil Shapiro if (!bitnset(M_EXPENSIVE, yy->q_mailer->m_flags))
8640266059SGregory Neil Shapiro return 1; /* xx should go later */
8740266059SGregory Neil Shapiro #if _FFR_HOST_SORT_REVERSE
8840266059SGregory Neil Shapiro /* XXX maybe compare hostnames from the end? */
8940266059SGregory Neil Shapiro return sm_strrevcasecmp(xx->q_host, yy->q_host);
905b0945b5SGregory Neil Shapiro #else
9140266059SGregory Neil Shapiro return sm_strcasecmp(xx->q_host, yy->q_host);
925b0945b5SGregory Neil Shapiro #endif
9340266059SGregory Neil Shapiro }
9440266059SGregory Neil Shapiro
9540266059SGregory Neil Shapiro /*
9640266059SGregory Neil Shapiro ** SORTBYSIGNATURE -- a strcmp()-like func for q_mailer and q_host in ADDRESS
9740266059SGregory Neil Shapiro **
9840266059SGregory Neil Shapiro ** Parameters:
9940266059SGregory Neil Shapiro ** xx -- first ADDRESS
10040266059SGregory Neil Shapiro ** yy -- second ADDRESS
10140266059SGregory Neil Shapiro **
10240266059SGregory Neil Shapiro ** Returns:
10340266059SGregory Neil Shapiro ** 0 when the "signature"'s are same
10440266059SGregory Neil Shapiro ** <0 when xx->q_signature is less than yy->q_signature
10540266059SGregory Neil Shapiro ** >0 when xx->q_signature is greater than yy->q_signature
10640266059SGregory Neil Shapiro **
10740266059SGregory Neil Shapiro ** Side Effect:
10840266059SGregory Neil Shapiro ** May set ADDRESS pointer for q_signature if not already set.
10940266059SGregory Neil Shapiro */
11040266059SGregory Neil Shapiro
11140266059SGregory Neil Shapiro static int
sortbysignature(xx,yy)11240266059SGregory Neil Shapiro sortbysignature(xx, yy)
11340266059SGregory Neil Shapiro ADDRESS *xx;
11440266059SGregory Neil Shapiro ADDRESS *yy;
11540266059SGregory Neil Shapiro {
11640266059SGregory Neil Shapiro register int ret;
11740266059SGregory Neil Shapiro
11840266059SGregory Neil Shapiro /* Let's avoid redoing the signature over and over again */
11940266059SGregory Neil Shapiro if (xx->q_signature == NULL)
120*d39bd2c1SGregory Neil Shapiro xx->q_signature = hostsignature(xx->q_mailer, xx->q_host,
121*d39bd2c1SGregory Neil Shapiro QISSECURE(xx), NULL);
12240266059SGregory Neil Shapiro if (yy->q_signature == NULL)
123*d39bd2c1SGregory Neil Shapiro yy->q_signature = hostsignature(yy->q_mailer, yy->q_host,
124*d39bd2c1SGregory Neil Shapiro QISSECURE(yy), NULL);
12540266059SGregory Neil Shapiro ret = strcmp(xx->q_signature, yy->q_signature);
12640266059SGregory Neil Shapiro
12740266059SGregory Neil Shapiro /*
12840266059SGregory Neil Shapiro ** If the two signatures are the same then we will return a sort
12940266059SGregory Neil Shapiro ** value based on 'q_user'. But note that we have reversed xx and yy
13040266059SGregory Neil Shapiro ** on purpose. This additional compare helps reduce the number of
13140266059SGregory Neil Shapiro ** sameaddr() calls and loops in recipient() for the case when
13240266059SGregory Neil Shapiro ** the rcpt list has been provided already in-order.
13340266059SGregory Neil Shapiro */
13440266059SGregory Neil Shapiro
13540266059SGregory Neil Shapiro if (ret == 0)
13640266059SGregory Neil Shapiro return strcmp(yy->q_user, xx->q_user);
13740266059SGregory Neil Shapiro else
13840266059SGregory Neil Shapiro return ret;
13940266059SGregory Neil Shapiro }
140c2aa98e2SPeter Wemm
141c2aa98e2SPeter Wemm /*
142c2aa98e2SPeter Wemm ** SENDTOLIST -- Designate a send list.
143c2aa98e2SPeter Wemm **
144c2aa98e2SPeter Wemm ** The parameter is a comma-separated list of people to send to.
145c2aa98e2SPeter Wemm ** This routine arranges to send to all of them.
146c2aa98e2SPeter Wemm **
147c2aa98e2SPeter Wemm ** Parameters:
148c2aa98e2SPeter Wemm ** list -- the send list.
149c2aa98e2SPeter Wemm ** ctladdr -- the address template for the person to
150c2aa98e2SPeter Wemm ** send to -- effective uid/gid are important.
151c2aa98e2SPeter Wemm ** This is typically the alias that caused this
152c2aa98e2SPeter Wemm ** expansion.
153c2aa98e2SPeter Wemm ** sendq -- a pointer to the head of a queue to put
154c2aa98e2SPeter Wemm ** these people into.
155c2aa98e2SPeter Wemm ** aliaslevel -- the current alias nesting depth -- to
156c2aa98e2SPeter Wemm ** diagnose loops.
157c2aa98e2SPeter Wemm ** e -- the envelope in which to add these recipients.
158c2aa98e2SPeter Wemm **
159c2aa98e2SPeter Wemm ** Returns:
160c2aa98e2SPeter Wemm ** The number of addresses actually on the list.
161c2aa98e2SPeter Wemm */
162c2aa98e2SPeter Wemm
163c2aa98e2SPeter Wemm /* q_flags bits inherited from ctladdr */
164c2aa98e2SPeter Wemm #define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY)
165c2aa98e2SPeter Wemm
166c2aa98e2SPeter Wemm int
sendtolist(list,ctladdr,sendq,aliaslevel,e)167c2aa98e2SPeter Wemm sendtolist(list, ctladdr, sendq, aliaslevel, e)
168c2aa98e2SPeter Wemm char *list;
169c2aa98e2SPeter Wemm ADDRESS *ctladdr;
170c2aa98e2SPeter Wemm ADDRESS **sendq;
171c2aa98e2SPeter Wemm int aliaslevel;
172c2aa98e2SPeter Wemm register ENVELOPE *e;
173c2aa98e2SPeter Wemm {
174c2aa98e2SPeter Wemm register char *p;
17540266059SGregory Neil Shapiro register ADDRESS *SM_NONVOLATILE al; /* list of addresses to send to */
17640266059SGregory Neil Shapiro SM_NONVOLATILE char delimiter; /* the address delimiter */
17740266059SGregory Neil Shapiro SM_NONVOLATILE int naddrs;
17840266059SGregory Neil Shapiro SM_NONVOLATILE int i;
179a7ec597cSGregory Neil Shapiro char *endp;
180c2aa98e2SPeter Wemm char *oldto = e->e_to;
18140266059SGregory Neil Shapiro char *SM_NONVOLATILE bufp;
1822fb4f839SGregory Neil Shapiro char buf[MAXNAME + 1]; /* EAI: ok, uses bufp dynamically expanded */
183c2aa98e2SPeter Wemm
184c2aa98e2SPeter Wemm if (list == NULL)
185c2aa98e2SPeter Wemm {
186c2aa98e2SPeter Wemm syserr("sendtolist: null list");
187c2aa98e2SPeter Wemm return 0;
188c2aa98e2SPeter Wemm }
189c2aa98e2SPeter Wemm
190c2aa98e2SPeter Wemm if (tTd(25, 1))
191c2aa98e2SPeter Wemm {
19240266059SGregory Neil Shapiro sm_dprintf("sendto: %s\n ctladdr=", list);
193e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), ctladdr, false);
194c2aa98e2SPeter Wemm }
195c2aa98e2SPeter Wemm
196c2aa98e2SPeter Wemm /* heuristic to determine old versus new style addresses */
197c2aa98e2SPeter Wemm if (ctladdr == NULL &&
198c2aa98e2SPeter Wemm (strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
199c2aa98e2SPeter Wemm strchr(list, '<') != NULL || strchr(list, '(') != NULL))
200c2aa98e2SPeter Wemm e->e_flags &= ~EF_OLDSTYLE;
201c2aa98e2SPeter Wemm delimiter = ' ';
202c2aa98e2SPeter Wemm if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL)
203c2aa98e2SPeter Wemm delimiter = ',';
204c2aa98e2SPeter Wemm
205c2aa98e2SPeter Wemm al = NULL;
206c2aa98e2SPeter Wemm naddrs = 0;
207c2aa98e2SPeter Wemm
208c2aa98e2SPeter Wemm /* make sure we have enough space to copy the string */
209c2aa98e2SPeter Wemm i = strlen(list) + 1;
210d0cef73dSGregory Neil Shapiro if (i <= sizeof(buf))
21106f25ae9SGregory Neil Shapiro {
212c2aa98e2SPeter Wemm bufp = buf;
213d0cef73dSGregory Neil Shapiro i = sizeof(buf);
21406f25ae9SGregory Neil Shapiro }
215c2aa98e2SPeter Wemm else
21640266059SGregory Neil Shapiro bufp = sm_malloc_x(i);
217a7ec597cSGregory Neil Shapiro endp = bufp + i;
218c2aa98e2SPeter Wemm
21940266059SGregory Neil Shapiro SM_TRY
22040266059SGregory Neil Shapiro {
22140266059SGregory Neil Shapiro (void) sm_strlcpy(bufp, denlstring(list, false, true), i);
22240266059SGregory Neil Shapiro
22340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r");
224c2aa98e2SPeter Wemm for (p = bufp; *p != '\0'; )
225c2aa98e2SPeter Wemm {
226c2aa98e2SPeter Wemm auto char *delimptr;
227c2aa98e2SPeter Wemm register ADDRESS *a;
228c2aa98e2SPeter Wemm
229a7ec597cSGregory Neil Shapiro SM_ASSERT(p < endp);
230a7ec597cSGregory Neil Shapiro
231c2aa98e2SPeter Wemm /* parse the address */
2325b0945b5SGregory Neil Shapiro while ((SM_ISSPACE(*p)) || *p == ',')
233c2aa98e2SPeter Wemm p++;
234a7ec597cSGregory Neil Shapiro SM_ASSERT(p < endp);
2352fb4f839SGregory Neil Shapiro /* XXX p must be [i] */
23640266059SGregory Neil Shapiro a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter,
23740266059SGregory Neil Shapiro &delimptr, e, true);
238c2aa98e2SPeter Wemm p = delimptr;
239a7ec597cSGregory Neil Shapiro SM_ASSERT(p < endp);
240c2aa98e2SPeter Wemm if (a == NULL)
241c2aa98e2SPeter Wemm continue;
242c2aa98e2SPeter Wemm a->q_next = al;
243c2aa98e2SPeter Wemm a->q_alias = ctladdr;
244c2aa98e2SPeter Wemm
245c2aa98e2SPeter Wemm /* arrange to inherit attributes from parent */
246c2aa98e2SPeter Wemm if (ctladdr != NULL)
247c2aa98e2SPeter Wemm {
248c2aa98e2SPeter Wemm ADDRESS *b;
249c2aa98e2SPeter Wemm
250c2aa98e2SPeter Wemm /* self reference test */
251c2aa98e2SPeter Wemm if (sameaddr(ctladdr, a))
252c2aa98e2SPeter Wemm {
253c2aa98e2SPeter Wemm if (tTd(27, 5))
254c2aa98e2SPeter Wemm {
25540266059SGregory Neil Shapiro sm_dprintf("sendtolist: QSELFREF ");
256e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), ctladdr, false);
257c2aa98e2SPeter Wemm }
258c2aa98e2SPeter Wemm ctladdr->q_flags |= QSELFREF;
259c2aa98e2SPeter Wemm }
260c2aa98e2SPeter Wemm
261c2aa98e2SPeter Wemm /* check for address loops */
26206f25ae9SGregory Neil Shapiro b = self_reference(a);
263c2aa98e2SPeter Wemm if (b != NULL)
264c2aa98e2SPeter Wemm {
265c2aa98e2SPeter Wemm b->q_flags |= QSELFREF;
266c2aa98e2SPeter Wemm if (tTd(27, 5))
267c2aa98e2SPeter Wemm {
26840266059SGregory Neil Shapiro sm_dprintf("sendtolist: QSELFREF ");
269e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), b, false);
270c2aa98e2SPeter Wemm }
271c2aa98e2SPeter Wemm if (a != b)
272c2aa98e2SPeter Wemm {
273c2aa98e2SPeter Wemm if (tTd(27, 5))
274c2aa98e2SPeter Wemm {
27540266059SGregory Neil Shapiro sm_dprintf("sendtolist: QS_DONTSEND ");
276e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), a, false);
277c2aa98e2SPeter Wemm }
27806f25ae9SGregory Neil Shapiro a->q_state = QS_DONTSEND;
279c2aa98e2SPeter Wemm b->q_flags |= a->q_flags & QNOTREMOTE;
280c2aa98e2SPeter Wemm continue;
281c2aa98e2SPeter Wemm }
282c2aa98e2SPeter Wemm }
283c2aa98e2SPeter Wemm
284c2aa98e2SPeter Wemm /* full name */
285c2aa98e2SPeter Wemm if (a->q_fullname == NULL)
286c2aa98e2SPeter Wemm a->q_fullname = ctladdr->q_fullname;
287c2aa98e2SPeter Wemm
288c2aa98e2SPeter Wemm /* various flag bits */
289c2aa98e2SPeter Wemm a->q_flags &= ~QINHERITEDBITS;
290c2aa98e2SPeter Wemm a->q_flags |= ctladdr->q_flags & QINHERITEDBITS;
291c2aa98e2SPeter Wemm
29240266059SGregory Neil Shapiro /* DSN recipient information */
29340266059SGregory Neil Shapiro a->q_finalrcpt = ctladdr->q_finalrcpt;
294c2aa98e2SPeter Wemm a->q_orcpt = ctladdr->q_orcpt;
295c2aa98e2SPeter Wemm }
296c2aa98e2SPeter Wemm
297c2aa98e2SPeter Wemm al = a;
298c2aa98e2SPeter Wemm }
299c2aa98e2SPeter Wemm
300c2aa98e2SPeter Wemm /* arrange to send to everyone on the local send list */
301c2aa98e2SPeter Wemm while (al != NULL)
302c2aa98e2SPeter Wemm {
303c2aa98e2SPeter Wemm register ADDRESS *a = al;
304c2aa98e2SPeter Wemm
305c2aa98e2SPeter Wemm al = a->q_next;
306c2aa98e2SPeter Wemm a = recipient(a, sendq, aliaslevel, e);
307c2aa98e2SPeter Wemm naddrs++;
308c2aa98e2SPeter Wemm }
30940266059SGregory Neil Shapiro }
31040266059SGregory Neil Shapiro SM_FINALLY
31140266059SGregory Neil Shapiro {
312c2aa98e2SPeter Wemm e->e_to = oldto;
313c2aa98e2SPeter Wemm if (bufp != buf)
3148774250cSGregory Neil Shapiro sm_free(bufp);
31540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
31640266059SGregory Neil Shapiro }
31740266059SGregory Neil Shapiro SM_END_TRY
31806f25ae9SGregory Neil Shapiro return naddrs;
31906f25ae9SGregory Neil Shapiro }
320d0cef73dSGregory Neil Shapiro
32140266059SGregory Neil Shapiro #if MILTER
32240266059SGregory Neil Shapiro /*
32306f25ae9SGregory Neil Shapiro ** REMOVEFROMLIST -- Remove addresses from a send list.
32406f25ae9SGregory Neil Shapiro **
32506f25ae9SGregory Neil Shapiro ** The parameter is a comma-separated list of recipients to remove.
32606f25ae9SGregory Neil Shapiro ** Note that it only deletes matching addresses. If those addresses
32740266059SGregory Neil Shapiro ** have been expanded already in the sendq, it won't mark the
32806f25ae9SGregory Neil Shapiro ** expanded recipients as QS_REMOVED.
32906f25ae9SGregory Neil Shapiro **
33006f25ae9SGregory Neil Shapiro ** Parameters:
33106f25ae9SGregory Neil Shapiro ** list -- the list to remove.
33206f25ae9SGregory Neil Shapiro ** sendq -- a pointer to the head of a queue to remove
33306f25ae9SGregory Neil Shapiro ** these addresses from.
33406f25ae9SGregory Neil Shapiro ** e -- the envelope in which to remove these recipients.
33506f25ae9SGregory Neil Shapiro **
33606f25ae9SGregory Neil Shapiro ** Returns:
33706f25ae9SGregory Neil Shapiro ** The number of addresses removed from the list.
33806f25ae9SGregory Neil Shapiro **
33906f25ae9SGregory Neil Shapiro */
34006f25ae9SGregory Neil Shapiro
34106f25ae9SGregory Neil Shapiro int
removefromlist(list,sendq,e)34206f25ae9SGregory Neil Shapiro removefromlist(list, sendq, e)
34306f25ae9SGregory Neil Shapiro char *list;
34406f25ae9SGregory Neil Shapiro ADDRESS **sendq;
34506f25ae9SGregory Neil Shapiro ENVELOPE *e;
34606f25ae9SGregory Neil Shapiro {
34740266059SGregory Neil Shapiro SM_NONVOLATILE char delimiter; /* the address delimiter */
34840266059SGregory Neil Shapiro SM_NONVOLATILE int naddrs;
34940266059SGregory Neil Shapiro SM_NONVOLATILE int i;
35006f25ae9SGregory Neil Shapiro char *p;
35106f25ae9SGregory Neil Shapiro char *oldto = e->e_to;
35240266059SGregory Neil Shapiro char *SM_NONVOLATILE bufp;
3532fb4f839SGregory Neil Shapiro char buf[MAXNAME + 1]; /* EAI: ok, uses bufp dynamically expanded */
35406f25ae9SGregory Neil Shapiro
35506f25ae9SGregory Neil Shapiro if (list == NULL)
35606f25ae9SGregory Neil Shapiro {
35706f25ae9SGregory Neil Shapiro syserr("removefromlist: null list");
35806f25ae9SGregory Neil Shapiro return 0;
35906f25ae9SGregory Neil Shapiro }
36006f25ae9SGregory Neil Shapiro
36106f25ae9SGregory Neil Shapiro if (tTd(25, 1))
36240266059SGregory Neil Shapiro sm_dprintf("removefromlist: %s\n", list);
36306f25ae9SGregory Neil Shapiro
36406f25ae9SGregory Neil Shapiro /* heuristic to determine old versus new style addresses */
36506f25ae9SGregory Neil Shapiro if (strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
36606f25ae9SGregory Neil Shapiro strchr(list, '<') != NULL || strchr(list, '(') != NULL)
36706f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_OLDSTYLE;
36806f25ae9SGregory Neil Shapiro delimiter = ' ';
36906f25ae9SGregory Neil Shapiro if (!bitset(EF_OLDSTYLE, e->e_flags))
37006f25ae9SGregory Neil Shapiro delimiter = ',';
37106f25ae9SGregory Neil Shapiro
37206f25ae9SGregory Neil Shapiro naddrs = 0;
37306f25ae9SGregory Neil Shapiro
37406f25ae9SGregory Neil Shapiro /* make sure we have enough space to copy the string */
37506f25ae9SGregory Neil Shapiro i = strlen(list) + 1;
376d0cef73dSGregory Neil Shapiro if (i <= sizeof(buf))
37706f25ae9SGregory Neil Shapiro {
37806f25ae9SGregory Neil Shapiro bufp = buf;
379d0cef73dSGregory Neil Shapiro i = sizeof(buf);
38006f25ae9SGregory Neil Shapiro }
38106f25ae9SGregory Neil Shapiro else
38240266059SGregory Neil Shapiro bufp = sm_malloc_x(i);
38306f25ae9SGregory Neil Shapiro
38440266059SGregory Neil Shapiro SM_TRY
38540266059SGregory Neil Shapiro {
38640266059SGregory Neil Shapiro (void) sm_strlcpy(bufp, denlstring(list, false, true), i);
38740266059SGregory Neil Shapiro
388ffb83623SGregory Neil Shapiro # if _FFR_ADDR_TYPE_MODES
389ffb83623SGregory Neil Shapiro if (AddrTypeModes)
390ffb83623SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"),
391ffb83623SGregory Neil Shapiro "e r d");
392ffb83623SGregory Neil Shapiro else
393ffb83623SGregory Neil Shapiro # endif /* _FFR_ADDR_TYPE_MODES */
3942fb4f839SGregory Neil Shapiro /* "else" in #if code above */
3952fb4f839SGregory Neil Shapiro {
3962fb4f839SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"),
3972fb4f839SGregory Neil Shapiro "e r");
3982fb4f839SGregory Neil Shapiro }
39906f25ae9SGregory Neil Shapiro for (p = bufp; *p != '\0'; )
40006f25ae9SGregory Neil Shapiro {
40106f25ae9SGregory Neil Shapiro ADDRESS a; /* parsed address to be removed */
40206f25ae9SGregory Neil Shapiro ADDRESS *q;
40306f25ae9SGregory Neil Shapiro ADDRESS **pq;
40406f25ae9SGregory Neil Shapiro char *delimptr;
40506f25ae9SGregory Neil Shapiro
40606f25ae9SGregory Neil Shapiro /* parse the address */
4075b0945b5SGregory Neil Shapiro while ((SM_ISSPACE(*p)) || *p == ',')
40806f25ae9SGregory Neil Shapiro p++;
4092fb4f839SGregory Neil Shapiro /* XXX p must be [i] */
410d0cef73dSGregory Neil Shapiro if (parseaddr(p, &a, RF_COPYALL|RF_RM_ADDR,
41140266059SGregory Neil Shapiro delimiter, &delimptr, e, true) == NULL)
41206f25ae9SGregory Neil Shapiro {
41306f25ae9SGregory Neil Shapiro p = delimptr;
41406f25ae9SGregory Neil Shapiro continue;
41506f25ae9SGregory Neil Shapiro }
41606f25ae9SGregory Neil Shapiro p = delimptr;
41706f25ae9SGregory Neil Shapiro for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
41806f25ae9SGregory Neil Shapiro {
41906f25ae9SGregory Neil Shapiro if (!QS_IS_DEAD(q->q_state) &&
420323f6dcbSGregory Neil Shapiro (sameaddr(q, &a) ||
421323f6dcbSGregory Neil Shapiro strcmp(q->q_paddr, a.q_paddr) == 0))
42206f25ae9SGregory Neil Shapiro {
42306f25ae9SGregory Neil Shapiro if (tTd(25, 5))
42406f25ae9SGregory Neil Shapiro {
42540266059SGregory Neil Shapiro sm_dprintf("removefromlist: QS_REMOVED ");
426e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), &a, false);
42706f25ae9SGregory Neil Shapiro }
42806f25ae9SGregory Neil Shapiro q->q_state = QS_REMOVED;
42906f25ae9SGregory Neil Shapiro naddrs++;
43006f25ae9SGregory Neil Shapiro break;
43106f25ae9SGregory Neil Shapiro }
43206f25ae9SGregory Neil Shapiro }
43306f25ae9SGregory Neil Shapiro }
43440266059SGregory Neil Shapiro }
43540266059SGregory Neil Shapiro SM_FINALLY
43640266059SGregory Neil Shapiro {
43706f25ae9SGregory Neil Shapiro e->e_to = oldto;
43806f25ae9SGregory Neil Shapiro if (bufp != buf)
4398774250cSGregory Neil Shapiro sm_free(bufp);
44040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
44140266059SGregory Neil Shapiro }
44240266059SGregory Neil Shapiro SM_END_TRY
44306f25ae9SGregory Neil Shapiro return naddrs;
444c2aa98e2SPeter Wemm }
44540266059SGregory Neil Shapiro #endif /* MILTER */
446d0cef73dSGregory Neil Shapiro
44740266059SGregory Neil Shapiro /*
448c2aa98e2SPeter Wemm ** RECIPIENT -- Designate a message recipient
449d0cef73dSGregory Neil Shapiro ** Saves the named person for future mailing (after some checks).
450c2aa98e2SPeter Wemm **
451c2aa98e2SPeter Wemm ** Parameters:
45240266059SGregory Neil Shapiro ** new -- the (preparsed) address header for the recipient.
453c2aa98e2SPeter Wemm ** sendq -- a pointer to the head of a queue to put the
45406f25ae9SGregory Neil Shapiro ** recipient in. Duplicate suppression is done
455c2aa98e2SPeter Wemm ** in this queue.
456c2aa98e2SPeter Wemm ** aliaslevel -- the current alias nesting depth.
457c2aa98e2SPeter Wemm ** e -- the current envelope.
458c2aa98e2SPeter Wemm **
459c2aa98e2SPeter Wemm ** Returns:
460c2aa98e2SPeter Wemm ** The actual address in the queue. This will be "a" if
461c2aa98e2SPeter Wemm ** the address is not a duplicate, else the original address.
462c2aa98e2SPeter Wemm **
463c2aa98e2SPeter Wemm */
464c2aa98e2SPeter Wemm
465c2aa98e2SPeter Wemm ADDRESS *
recipient(new,sendq,aliaslevel,e)46640266059SGregory Neil Shapiro recipient(new, sendq, aliaslevel, e)
46740266059SGregory Neil Shapiro register ADDRESS *new;
468c2aa98e2SPeter Wemm register ADDRESS **sendq;
469c2aa98e2SPeter Wemm int aliaslevel;
470c2aa98e2SPeter Wemm register ENVELOPE *e;
471c2aa98e2SPeter Wemm {
472c2aa98e2SPeter Wemm register ADDRESS *q;
473c2aa98e2SPeter Wemm ADDRESS **pq;
47440266059SGregory Neil Shapiro ADDRESS **prev;
475c2aa98e2SPeter Wemm register struct mailer *m;
47640266059SGregory Neil Shapiro register char *p;
47706f25ae9SGregory Neil Shapiro int i, buflen;
47840266059SGregory Neil Shapiro bool quoted; /* set if the addr has a quote bit */
47940266059SGregory Neil Shapiro bool insert;
48040266059SGregory Neil Shapiro int findusercount;
48140266059SGregory Neil Shapiro bool initialdontsend;
482c2aa98e2SPeter Wemm char *buf;
4832fb4f839SGregory Neil Shapiro char buf0[MAXNAME + 1]; /* EAI: ok, uses bufp dynamically expanded */
4842fb4f839SGregory Neil Shapiro /* unquoted image of the user name */
48540266059SGregory Neil Shapiro sortfn_t *sortfn;
486c2aa98e2SPeter Wemm
48740266059SGregory Neil Shapiro p = NULL;
48840266059SGregory Neil Shapiro quoted = false;
48940266059SGregory Neil Shapiro insert = false;
49040266059SGregory Neil Shapiro findusercount = 0;
49140266059SGregory Neil Shapiro initialdontsend = QS_IS_DEAD(new->q_state);
49240266059SGregory Neil Shapiro e->e_to = new->q_paddr;
49340266059SGregory Neil Shapiro m = new->q_mailer;
494c2aa98e2SPeter Wemm errno = 0;
495c2aa98e2SPeter Wemm if (aliaslevel == 0)
49640266059SGregory Neil Shapiro new->q_flags |= QPRIMARY;
497c2aa98e2SPeter Wemm if (tTd(26, 1))
498c2aa98e2SPeter Wemm {
49940266059SGregory Neil Shapiro sm_dprintf("\nrecipient (%d): ", aliaslevel);
500e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), new, false);
501c2aa98e2SPeter Wemm }
502c2aa98e2SPeter Wemm
50340266059SGregory Neil Shapiro /* if this is primary, use it as original recipient */
50440266059SGregory Neil Shapiro if (new->q_alias == NULL)
505c2aa98e2SPeter Wemm {
506c2aa98e2SPeter Wemm if (e->e_origrcpt == NULL)
50740266059SGregory Neil Shapiro e->e_origrcpt = new->q_paddr;
50840266059SGregory Neil Shapiro else if (e->e_origrcpt != new->q_paddr)
509c2aa98e2SPeter Wemm e->e_origrcpt = "";
510c2aa98e2SPeter Wemm }
511c2aa98e2SPeter Wemm
51240266059SGregory Neil Shapiro /* find parent recipient for finalrcpt and orcpt */
51340266059SGregory Neil Shapiro for (q = new; q->q_alias != NULL; q = q->q_alias)
51440266059SGregory Neil Shapiro continue;
51540266059SGregory Neil Shapiro
51640266059SGregory Neil Shapiro /* find final recipient DSN address */
51740266059SGregory Neil Shapiro if (new->q_finalrcpt == NULL &&
51840266059SGregory Neil Shapiro e->e_from.q_mailer != NULL)
51940266059SGregory Neil Shapiro {
52040266059SGregory Neil Shapiro char frbuf[MAXLINE];
52140266059SGregory Neil Shapiro
52240266059SGregory Neil Shapiro p = e->e_from.q_mailer->m_addrtype;
52340266059SGregory Neil Shapiro if (p == NULL)
52440266059SGregory Neil Shapiro p = "rfc822";
5252fb4f839SGregory Neil Shapiro #if USE_EAI
5262fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(p, "rfc822") &&
5275b0945b5SGregory Neil Shapiro !addr_is_ascii(q->q_user))
5285b0945b5SGregory Neil Shapiro p = "utf-8";
5295b0945b5SGregory Neil Shapiro #endif
53040266059SGregory Neil Shapiro if (sm_strcasecmp(p, "rfc822") != 0)
53140266059SGregory Neil Shapiro {
532d0cef73dSGregory Neil Shapiro (void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s",
53340266059SGregory Neil Shapiro q->q_mailer->m_addrtype,
53440266059SGregory Neil Shapiro q->q_user);
53540266059SGregory Neil Shapiro }
53640266059SGregory Neil Shapiro else if (strchr(q->q_user, '@') != NULL)
53740266059SGregory Neil Shapiro {
538d0cef73dSGregory Neil Shapiro (void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s",
53940266059SGregory Neil Shapiro p, q->q_user);
54040266059SGregory Neil Shapiro }
54140266059SGregory Neil Shapiro else if (strchr(q->q_paddr, '@') != NULL)
54240266059SGregory Neil Shapiro {
54340266059SGregory Neil Shapiro char *qp;
54440266059SGregory Neil Shapiro bool b;
54540266059SGregory Neil Shapiro
54640266059SGregory Neil Shapiro qp = q->q_paddr;
54740266059SGregory Neil Shapiro
54840266059SGregory Neil Shapiro /* strip brackets from address */
54940266059SGregory Neil Shapiro b = false;
55040266059SGregory Neil Shapiro if (*qp == '<')
55140266059SGregory Neil Shapiro {
55240266059SGregory Neil Shapiro b = qp[strlen(qp) - 1] == '>';
55340266059SGregory Neil Shapiro if (b)
55440266059SGregory Neil Shapiro qp[strlen(qp) - 1] = '\0';
55540266059SGregory Neil Shapiro qp++;
55640266059SGregory Neil Shapiro }
557d0cef73dSGregory Neil Shapiro (void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s",
55840266059SGregory Neil Shapiro p, qp);
55940266059SGregory Neil Shapiro
56040266059SGregory Neil Shapiro /* undo damage */
56140266059SGregory Neil Shapiro if (b)
56240266059SGregory Neil Shapiro qp[strlen(qp)] = '>';
56340266059SGregory Neil Shapiro }
56440266059SGregory Neil Shapiro else
56540266059SGregory Neil Shapiro {
566d0cef73dSGregory Neil Shapiro (void) sm_snprintf(frbuf, sizeof(frbuf),
56740266059SGregory Neil Shapiro "%s; %.700s@%.100s",
56840266059SGregory Neil Shapiro p, q->q_user, MyHostName);
56940266059SGregory Neil Shapiro }
57040266059SGregory Neil Shapiro new->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool, frbuf);
57140266059SGregory Neil Shapiro }
57240266059SGregory Neil Shapiro
57306f25ae9SGregory Neil Shapiro #if _FFR_GEN_ORCPT
57406f25ae9SGregory Neil Shapiro /* set ORCPT DSN arg if not already set */
57540266059SGregory Neil Shapiro if (new->q_orcpt == NULL)
57606f25ae9SGregory Neil Shapiro {
57706f25ae9SGregory Neil Shapiro /* check for an existing ORCPT */
57806f25ae9SGregory Neil Shapiro if (q->q_orcpt != NULL)
57940266059SGregory Neil Shapiro new->q_orcpt = q->q_orcpt;
58006f25ae9SGregory Neil Shapiro else
58106f25ae9SGregory Neil Shapiro {
58206f25ae9SGregory Neil Shapiro /* make our own */
58340266059SGregory Neil Shapiro bool b = false;
58406f25ae9SGregory Neil Shapiro char *qp;
58506f25ae9SGregory Neil Shapiro char obuf[MAXLINE];
58606f25ae9SGregory Neil Shapiro
58706f25ae9SGregory Neil Shapiro if (e->e_from.q_mailer != NULL)
58806f25ae9SGregory Neil Shapiro p = e->e_from.q_mailer->m_addrtype;
58906f25ae9SGregory Neil Shapiro if (p == NULL)
59006f25ae9SGregory Neil Shapiro p = "rfc822";
591d0cef73dSGregory Neil Shapiro (void) sm_strlcpyn(obuf, sizeof(obuf), 2, p, ";");
59206f25ae9SGregory Neil Shapiro
59306f25ae9SGregory Neil Shapiro qp = q->q_paddr;
59406f25ae9SGregory Neil Shapiro
59506f25ae9SGregory Neil Shapiro /* FFR: Needs to strip comments from stdin addrs */
59606f25ae9SGregory Neil Shapiro
59706f25ae9SGregory Neil Shapiro /* strip brackets from address */
59806f25ae9SGregory Neil Shapiro if (*qp == '<')
59906f25ae9SGregory Neil Shapiro {
60006f25ae9SGregory Neil Shapiro b = qp[strlen(qp) - 1] == '>';
60106f25ae9SGregory Neil Shapiro if (b)
60206f25ae9SGregory Neil Shapiro qp[strlen(qp) - 1] = '\0';
60306f25ae9SGregory Neil Shapiro qp++;
60406f25ae9SGregory Neil Shapiro }
60506f25ae9SGregory Neil Shapiro
606d0cef73dSGregory Neil Shapiro p = xtextify(denlstring(qp, true, false), "=");
60706f25ae9SGregory Neil Shapiro
608d0cef73dSGregory Neil Shapiro if (sm_strlcat(obuf, p, sizeof(obuf)) >= sizeof(obuf))
60906f25ae9SGregory Neil Shapiro {
61006f25ae9SGregory Neil Shapiro /* if too big, don't use it */
61106f25ae9SGregory Neil Shapiro obuf[0] = '\0';
61206f25ae9SGregory Neil Shapiro }
61306f25ae9SGregory Neil Shapiro
61406f25ae9SGregory Neil Shapiro /* undo damage */
61506f25ae9SGregory Neil Shapiro if (b)
61606f25ae9SGregory Neil Shapiro qp[strlen(qp)] = '>';
61706f25ae9SGregory Neil Shapiro
61806f25ae9SGregory Neil Shapiro if (obuf[0] != '\0')
61940266059SGregory Neil Shapiro new->q_orcpt =
62040266059SGregory Neil Shapiro sm_rpool_strdup_x(e->e_rpool, obuf);
62106f25ae9SGregory Neil Shapiro }
62206f25ae9SGregory Neil Shapiro }
62306f25ae9SGregory Neil Shapiro #endif /* _FFR_GEN_ORCPT */
62406f25ae9SGregory Neil Shapiro
625c2aa98e2SPeter Wemm /* break aliasing loops */
626c2aa98e2SPeter Wemm if (aliaslevel > MaxAliasRecursion)
627c2aa98e2SPeter Wemm {
62840266059SGregory Neil Shapiro new->q_state = QS_BADADDR;
62940266059SGregory Neil Shapiro new->q_status = "5.4.6";
630d0cef73dSGregory Neil Shapiro if (new->q_alias != NULL)
631d0cef73dSGregory Neil Shapiro {
632d0cef73dSGregory Neil Shapiro new->q_alias->q_state = QS_BADADDR;
633d0cef73dSGregory Neil Shapiro new->q_alias->q_status = "5.4.6";
634d0cef73dSGregory Neil Shapiro }
635d0cef73dSGregory Neil Shapiro if ((SuprErrs || !LogUsrErrs) && LogLevel > 0)
636d0cef73dSGregory Neil Shapiro {
637d0cef73dSGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
638d0cef73dSGregory Neil Shapiro "aliasing/forwarding loop broken: %s (%d aliases deep; %d max)",
639d0cef73dSGregory Neil Shapiro FileName != NULL ? FileName : "", aliaslevel,
640d0cef73dSGregory Neil Shapiro MaxAliasRecursion);
641d0cef73dSGregory Neil Shapiro }
64240266059SGregory Neil Shapiro usrerrenh(new->q_status,
64306f25ae9SGregory Neil Shapiro "554 aliasing/forwarding loop broken (%d aliases deep; %d max)",
644c2aa98e2SPeter Wemm aliaslevel, MaxAliasRecursion);
64540266059SGregory Neil Shapiro return new;
646c2aa98e2SPeter Wemm }
647c2aa98e2SPeter Wemm
648c2aa98e2SPeter Wemm /*
649c2aa98e2SPeter Wemm ** Finish setting up address structure.
650c2aa98e2SPeter Wemm */
651c2aa98e2SPeter Wemm
652c2aa98e2SPeter Wemm /* get unquoted user for file, program or user.name check */
65340266059SGregory Neil Shapiro i = strlen(new->q_user);
654d0cef73dSGregory Neil Shapiro if (i >= sizeof(buf0))
65506f25ae9SGregory Neil Shapiro {
65606f25ae9SGregory Neil Shapiro buflen = i + 1;
65706f25ae9SGregory Neil Shapiro buf = xalloc(buflen);
65806f25ae9SGregory Neil Shapiro }
659c2aa98e2SPeter Wemm else
66006f25ae9SGregory Neil Shapiro {
661c2aa98e2SPeter Wemm buf = buf0;
662d0cef73dSGregory Neil Shapiro buflen = sizeof(buf0);
66306f25ae9SGregory Neil Shapiro }
66440266059SGregory Neil Shapiro (void) sm_strlcpy(buf, new->q_user, buflen);
665c2aa98e2SPeter Wemm for (p = buf; *p != '\0' && !quoted; p++)
666c2aa98e2SPeter Wemm {
667c2aa98e2SPeter Wemm if (*p == '\\')
66840266059SGregory Neil Shapiro quoted = true;
669c2aa98e2SPeter Wemm }
670c2aa98e2SPeter Wemm stripquotes(buf);
671c2aa98e2SPeter Wemm
672c2aa98e2SPeter Wemm /* check for direct mailing to restricted mailers */
673c2aa98e2SPeter Wemm if (m == ProgMailer)
674c2aa98e2SPeter Wemm {
67540266059SGregory Neil Shapiro if (new->q_alias == NULL || UseMSP ||
67640266059SGregory Neil Shapiro bitset(EF_UNSAFE, e->e_flags))
677c2aa98e2SPeter Wemm {
67840266059SGregory Neil Shapiro new->q_state = QS_BADADDR;
67940266059SGregory Neil Shapiro new->q_status = "5.7.1";
68040266059SGregory Neil Shapiro usrerrenh(new->q_status,
68106f25ae9SGregory Neil Shapiro "550 Cannot mail directly to programs");
682c2aa98e2SPeter Wemm }
68340266059SGregory Neil Shapiro else if (bitset(QBOGUSSHELL, new->q_alias->q_flags))
684c2aa98e2SPeter Wemm {
68540266059SGregory Neil Shapiro new->q_state = QS_BADADDR;
68640266059SGregory Neil Shapiro new->q_status = "5.7.1";
68740266059SGregory Neil Shapiro if (new->q_alias->q_ruser == NULL)
68840266059SGregory Neil Shapiro usrerrenh(new->q_status,
689da7d7b9cSGregory Neil Shapiro "550 UID %ld is an unknown user: cannot mail to programs",
690da7d7b9cSGregory Neil Shapiro (long) new->q_alias->q_uid);
691c2aa98e2SPeter Wemm else
69240266059SGregory Neil Shapiro usrerrenh(new->q_status,
69306f25ae9SGregory Neil Shapiro "550 User %s@%s doesn't have a valid shell for mailing to programs",
69440266059SGregory Neil Shapiro new->q_alias->q_ruser, MyHostName);
695c2aa98e2SPeter Wemm }
69640266059SGregory Neil Shapiro else if (bitset(QUNSAFEADDR, new->q_alias->q_flags))
697c2aa98e2SPeter Wemm {
69840266059SGregory Neil Shapiro new->q_state = QS_BADADDR;
69940266059SGregory Neil Shapiro new->q_status = "5.7.1";
70040266059SGregory Neil Shapiro new->q_rstatus = "550 Unsafe for mailing to programs";
70140266059SGregory Neil Shapiro usrerrenh(new->q_status,
70206f25ae9SGregory Neil Shapiro "550 Address %s is unsafe for mailing to programs",
70340266059SGregory Neil Shapiro new->q_alias->q_paddr);
704c2aa98e2SPeter Wemm }
705c2aa98e2SPeter Wemm }
706c2aa98e2SPeter Wemm
707c2aa98e2SPeter Wemm /*
708c2aa98e2SPeter Wemm ** Look up this person in the recipient list.
709c2aa98e2SPeter Wemm ** If they are there already, return, otherwise continue.
710c2aa98e2SPeter Wemm ** If the list is empty, just add it. Notice the cute
711c2aa98e2SPeter Wemm ** hack to make from addresses suppress things correctly:
71206f25ae9SGregory Neil Shapiro ** the QS_DUPLICATE state will be set in the send list.
713c2aa98e2SPeter Wemm ** [Please note: the emphasis is on "hack."]
714c2aa98e2SPeter Wemm */
715c2aa98e2SPeter Wemm
71640266059SGregory Neil Shapiro prev = NULL;
71740266059SGregory Neil Shapiro
71840266059SGregory Neil Shapiro /*
71940266059SGregory Neil Shapiro ** If this message is going to the queue or FastSplit is set
72040266059SGregory Neil Shapiro ** and it is the first try and the envelope hasn't split, then we
72140266059SGregory Neil Shapiro ** avoid doing an MX RR lookup now because one will be done when the
72240266059SGregory Neil Shapiro ** message is extracted from the queue later. It can go to the queue
72340266059SGregory Neil Shapiro ** because all messages are going to the queue or this mailer of
72440266059SGregory Neil Shapiro ** the current recipient is marked expensive.
72540266059SGregory Neil Shapiro */
72640266059SGregory Neil Shapiro
72713bd1963SGregory Neil Shapiro if (UseMSP || WILL_BE_QUEUED(e->e_sendmode) ||
72840266059SGregory Neil Shapiro (!bitset(EF_SPLIT, e->e_flags) && e->e_ntries == 0 &&
72940266059SGregory Neil Shapiro FastSplit > 0))
73040266059SGregory Neil Shapiro sortfn = sorthost;
73140266059SGregory Neil Shapiro else if (NoConnect && bitnset(M_EXPENSIVE, new->q_mailer->m_flags))
73240266059SGregory Neil Shapiro sortfn = sortexpensive;
73340266059SGregory Neil Shapiro else
73440266059SGregory Neil Shapiro sortfn = sortbysignature;
73540266059SGregory Neil Shapiro
736c2aa98e2SPeter Wemm for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
737c2aa98e2SPeter Wemm {
73840266059SGregory Neil Shapiro /*
73940266059SGregory Neil Shapiro ** If address is "less than" it should be inserted now.
74040266059SGregory Neil Shapiro ** If address is "greater than" current comparison it'll
74140266059SGregory Neil Shapiro ** insert later in the list; so loop again (if possible).
74240266059SGregory Neil Shapiro ** If address is "equal" (different equal than sameaddr()
74340266059SGregory Neil Shapiro ** call) then check if sameaddr() will be true.
74440266059SGregory Neil Shapiro ** Because this list is now sorted, it'll mean fewer
74540266059SGregory Neil Shapiro ** comparisons and fewer loops which is important for more
74640266059SGregory Neil Shapiro ** recipients.
74740266059SGregory Neil Shapiro */
74840266059SGregory Neil Shapiro
74940266059SGregory Neil Shapiro i = (*sortfn)(new, q);
75040266059SGregory Neil Shapiro if (i == 0) /* equal */
75140266059SGregory Neil Shapiro {
75240266059SGregory Neil Shapiro /*
753*d39bd2c1SGregory Neil Shapiro ** sortbysignature() has said that the two have
75440266059SGregory Neil Shapiro ** equal MX RR's and the same user. Calling sameaddr()
75540266059SGregory Neil Shapiro ** now checks if the two hosts are as identical as the
75640266059SGregory Neil Shapiro ** MX RR's are (which might not be the case)
75740266059SGregory Neil Shapiro ** before saying these are the identical addresses.
75840266059SGregory Neil Shapiro */
75940266059SGregory Neil Shapiro
76040266059SGregory Neil Shapiro if (sameaddr(q, new) &&
761c2aa98e2SPeter Wemm (bitset(QRCPTOK, q->q_flags) ||
762c2aa98e2SPeter Wemm !bitset(QPRIMARY, q->q_flags)))
763c2aa98e2SPeter Wemm {
764c2aa98e2SPeter Wemm if (tTd(26, 1))
765c2aa98e2SPeter Wemm {
76640266059SGregory Neil Shapiro sm_dprintf("%s in sendq: ",
76740266059SGregory Neil Shapiro new->q_paddr);
768e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), q, false);
769c2aa98e2SPeter Wemm }
770c2aa98e2SPeter Wemm if (!bitset(QPRIMARY, q->q_flags))
771c2aa98e2SPeter Wemm {
77240266059SGregory Neil Shapiro if (!QS_IS_DEAD(new->q_state))
773c2aa98e2SPeter Wemm message("duplicate suppressed");
77406f25ae9SGregory Neil Shapiro else
77506f25ae9SGregory Neil Shapiro q->q_state = QS_DUPLICATE;
77640266059SGregory Neil Shapiro q->q_flags |= new->q_flags;
777c2aa98e2SPeter Wemm }
77806f25ae9SGregory Neil Shapiro else if (bitset(QSELFREF, q->q_flags)
77940266059SGregory Neil Shapiro || q->q_state == QS_REMOVED)
78006f25ae9SGregory Neil Shapiro {
78106f25ae9SGregory Neil Shapiro /*
78240266059SGregory Neil Shapiro ** If an earlier milter removed the
78340266059SGregory Neil Shapiro ** address, a later one can still add
78440266059SGregory Neil Shapiro ** it back.
78506f25ae9SGregory Neil Shapiro */
78640266059SGregory Neil Shapiro
78740266059SGregory Neil Shapiro q->q_state = new->q_state;
78840266059SGregory Neil Shapiro q->q_flags |= new->q_flags;
78906f25ae9SGregory Neil Shapiro }
79040266059SGregory Neil Shapiro new = q;
791c2aa98e2SPeter Wemm goto done;
792c2aa98e2SPeter Wemm }
793c2aa98e2SPeter Wemm }
79440266059SGregory Neil Shapiro else if (i < 0) /* less than */
79540266059SGregory Neil Shapiro {
79640266059SGregory Neil Shapiro insert = true;
79740266059SGregory Neil Shapiro break;
79840266059SGregory Neil Shapiro }
79940266059SGregory Neil Shapiro prev = pq;
80040266059SGregory Neil Shapiro }
80140266059SGregory Neil Shapiro
80240266059SGregory Neil Shapiro /* pq should point to an address, never NULL */
80340266059SGregory Neil Shapiro SM_ASSERT(pq != NULL);
804c2aa98e2SPeter Wemm
805c2aa98e2SPeter Wemm /* add address on list */
80640266059SGregory Neil Shapiro if (insert)
807065a643dSPeter Wemm {
80840266059SGregory Neil Shapiro /*
80940266059SGregory Neil Shapiro ** insert before 'pq'. Only possible when at least 1
81040266059SGregory Neil Shapiro ** ADDRESS is in the list already.
81140266059SGregory Neil Shapiro */
81240266059SGregory Neil Shapiro
81340266059SGregory Neil Shapiro new->q_next = *pq;
81440266059SGregory Neil Shapiro if (prev == NULL)
81540266059SGregory Neil Shapiro *sendq = new; /* To be the first ADDRESS */
81640266059SGregory Neil Shapiro else
81740266059SGregory Neil Shapiro (*prev)->q_next = new;
818065a643dSPeter Wemm }
81940266059SGregory Neil Shapiro else
82040266059SGregory Neil Shapiro {
82140266059SGregory Neil Shapiro /*
82240266059SGregory Neil Shapiro ** Place in list at current 'pq' position. Possible
82340266059SGregory Neil Shapiro ** when there are 0 or more ADDRESS's in the list.
82440266059SGregory Neil Shapiro */
82540266059SGregory Neil Shapiro
82640266059SGregory Neil Shapiro new->q_next = NULL;
82740266059SGregory Neil Shapiro *pq = new;
82840266059SGregory Neil Shapiro }
82940266059SGregory Neil Shapiro
83040266059SGregory Neil Shapiro /* added a new address: clear split flag */
83140266059SGregory Neil Shapiro e->e_flags &= ~EF_SPLIT;
832c2aa98e2SPeter Wemm
833c2aa98e2SPeter Wemm /*
834c2aa98e2SPeter Wemm ** Alias the name and handle special mailer types.
835c2aa98e2SPeter Wemm */
836c2aa98e2SPeter Wemm
837c2aa98e2SPeter Wemm trylocaluser:
838c2aa98e2SPeter Wemm if (tTd(29, 7))
839065a643dSPeter Wemm {
84040266059SGregory Neil Shapiro sm_dprintf("at trylocaluser: ");
841e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), new, false);
842065a643dSPeter Wemm }
843c2aa98e2SPeter Wemm
84440266059SGregory Neil Shapiro if (!QS_IS_OK(new->q_state))
84540266059SGregory Neil Shapiro {
84640266059SGregory Neil Shapiro if (QS_IS_UNDELIVERED(new->q_state))
84740266059SGregory Neil Shapiro e->e_nrcpts++;
848c2aa98e2SPeter Wemm goto testselfdestruct;
84940266059SGregory Neil Shapiro }
850c2aa98e2SPeter Wemm
851c2aa98e2SPeter Wemm if (m == InclMailer)
852c2aa98e2SPeter Wemm {
85340266059SGregory Neil Shapiro new->q_state = QS_INCLUDED;
85440266059SGregory Neil Shapiro if (new->q_alias == NULL || UseMSP ||
85540266059SGregory Neil Shapiro bitset(EF_UNSAFE, e->e_flags))
856c2aa98e2SPeter Wemm {
85740266059SGregory Neil Shapiro new->q_state = QS_BADADDR;
85840266059SGregory Neil Shapiro new->q_status = "5.7.1";
85940266059SGregory Neil Shapiro usrerrenh(new->q_status,
86006f25ae9SGregory Neil Shapiro "550 Cannot mail directly to :include:s");
861c2aa98e2SPeter Wemm }
862c2aa98e2SPeter Wemm else
863c2aa98e2SPeter Wemm {
864c2aa98e2SPeter Wemm int ret;
865c2aa98e2SPeter Wemm
86640266059SGregory Neil Shapiro message("including file %s", new->q_user);
86740266059SGregory Neil Shapiro ret = include(new->q_user, false, new,
86840266059SGregory Neil Shapiro sendq, aliaslevel, e);
869c2aa98e2SPeter Wemm if (transienterror(ret))
870c2aa98e2SPeter Wemm {
871c2aa98e2SPeter Wemm if (LogLevel > 2)
872c2aa98e2SPeter Wemm sm_syslog(LOG_ERR, e->e_id,
873c2aa98e2SPeter Wemm "include %s: transient error: %s",
87440266059SGregory Neil Shapiro shortenstring(new->q_user,
87540266059SGregory Neil Shapiro MAXSHORTSTR),
87640266059SGregory Neil Shapiro sm_errstring(ret));
87740266059SGregory Neil Shapiro new->q_state = QS_QUEUEUP;
87806f25ae9SGregory Neil Shapiro usrerr("451 4.2.4 Cannot open %s: %s",
87940266059SGregory Neil Shapiro shortenstring(new->q_user,
88040266059SGregory Neil Shapiro MAXSHORTSTR),
88140266059SGregory Neil Shapiro sm_errstring(ret));
882c2aa98e2SPeter Wemm }
883c2aa98e2SPeter Wemm else if (ret != 0)
884c2aa98e2SPeter Wemm {
88540266059SGregory Neil Shapiro new->q_state = QS_BADADDR;
88640266059SGregory Neil Shapiro new->q_status = "5.2.4";
88740266059SGregory Neil Shapiro usrerrenh(new->q_status,
88806f25ae9SGregory Neil Shapiro "550 Cannot open %s: %s",
88940266059SGregory Neil Shapiro shortenstring(new->q_user,
89040266059SGregory Neil Shapiro MAXSHORTSTR),
89140266059SGregory Neil Shapiro sm_errstring(ret));
892c2aa98e2SPeter Wemm }
893c2aa98e2SPeter Wemm }
894c2aa98e2SPeter Wemm }
895c2aa98e2SPeter Wemm else if (m == FileMailer)
896c2aa98e2SPeter Wemm {
89740266059SGregory Neil Shapiro /* check if allowed */
89840266059SGregory Neil Shapiro if (new->q_alias == NULL || UseMSP ||
89940266059SGregory Neil Shapiro bitset(EF_UNSAFE, e->e_flags))
900c2aa98e2SPeter Wemm {
90140266059SGregory Neil Shapiro new->q_state = QS_BADADDR;
90240266059SGregory Neil Shapiro new->q_status = "5.7.1";
90340266059SGregory Neil Shapiro usrerrenh(new->q_status,
90406f25ae9SGregory Neil Shapiro "550 Cannot mail directly to files");
905c2aa98e2SPeter Wemm }
90640266059SGregory Neil Shapiro else if (bitset(QBOGUSSHELL, new->q_alias->q_flags))
907c2aa98e2SPeter Wemm {
90840266059SGregory Neil Shapiro new->q_state = QS_BADADDR;
90940266059SGregory Neil Shapiro new->q_status = "5.7.1";
91040266059SGregory Neil Shapiro if (new->q_alias->q_ruser == NULL)
91140266059SGregory Neil Shapiro usrerrenh(new->q_status,
912da7d7b9cSGregory Neil Shapiro "550 UID %ld is an unknown user: cannot mail to files",
913da7d7b9cSGregory Neil Shapiro (long) new->q_alias->q_uid);
914c2aa98e2SPeter Wemm else
91540266059SGregory Neil Shapiro usrerrenh(new->q_status,
91606f25ae9SGregory Neil Shapiro "550 User %s@%s doesn't have a valid shell for mailing to files",
91740266059SGregory Neil Shapiro new->q_alias->q_ruser, MyHostName);
918c2aa98e2SPeter Wemm }
91940266059SGregory Neil Shapiro else if (bitset(QUNSAFEADDR, new->q_alias->q_flags))
920c2aa98e2SPeter Wemm {
92140266059SGregory Neil Shapiro new->q_state = QS_BADADDR;
92240266059SGregory Neil Shapiro new->q_status = "5.7.1";
92340266059SGregory Neil Shapiro new->q_rstatus = "550 Unsafe for mailing to files";
92440266059SGregory Neil Shapiro usrerrenh(new->q_status,
92506f25ae9SGregory Neil Shapiro "550 Address %s is unsafe for mailing to files",
92640266059SGregory Neil Shapiro new->q_alias->q_paddr);
927c2aa98e2SPeter Wemm }
928c2aa98e2SPeter Wemm }
929c2aa98e2SPeter Wemm
930c2aa98e2SPeter Wemm /* try aliasing */
93140266059SGregory Neil Shapiro if (!quoted && QS_IS_OK(new->q_state) &&
932c2aa98e2SPeter Wemm bitnset(M_ALIASABLE, m->m_flags))
93340266059SGregory Neil Shapiro alias(new, sendq, aliaslevel, e);
934c2aa98e2SPeter Wemm
935c2aa98e2SPeter Wemm #if USERDB
936c2aa98e2SPeter Wemm /* if not aliased, look it up in the user database */
93740266059SGregory Neil Shapiro if (!bitset(QNOTREMOTE, new->q_flags) &&
93840266059SGregory Neil Shapiro QS_IS_SENDABLE(new->q_state) &&
939c2aa98e2SPeter Wemm bitnset(M_CHECKUDB, m->m_flags))
940c2aa98e2SPeter Wemm {
94140266059SGregory Neil Shapiro if (udbexpand(new, sendq, aliaslevel, e) == EX_TEMPFAIL)
942c2aa98e2SPeter Wemm {
94340266059SGregory Neil Shapiro new->q_state = QS_QUEUEUP;
944c2aa98e2SPeter Wemm if (e->e_message == NULL)
945d0cef73dSGregory Neil Shapiro e->e_message = sm_rpool_strdup_x(e->e_rpool,
946d0cef73dSGregory Neil Shapiro "Deferred: user database error");
94740266059SGregory Neil Shapiro if (new->q_message == NULL)
94840266059SGregory Neil Shapiro new->q_message = "Deferred: user database error";
949c2aa98e2SPeter Wemm if (LogLevel > 8)
950c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id,
951c2aa98e2SPeter Wemm "deferred: udbexpand: %s",
95240266059SGregory Neil Shapiro sm_errstring(errno));
953c2aa98e2SPeter Wemm message("queued (user database error): %s",
95440266059SGregory Neil Shapiro sm_errstring(errno));
955c2aa98e2SPeter Wemm e->e_nrcpts++;
956c2aa98e2SPeter Wemm goto testselfdestruct;
957c2aa98e2SPeter Wemm }
958c2aa98e2SPeter Wemm }
95906f25ae9SGregory Neil Shapiro #endif /* USERDB */
960c2aa98e2SPeter Wemm
961c2aa98e2SPeter Wemm /*
962c2aa98e2SPeter Wemm ** If we have a level two config file, then pass the name through
963c2aa98e2SPeter Wemm ** Ruleset 5 before sending it off. Ruleset 5 has the right
96440266059SGregory Neil Shapiro ** to rewrite it to another mailer. This gives us a hook
965c2aa98e2SPeter Wemm ** after local aliasing has been done.
966c2aa98e2SPeter Wemm */
967c2aa98e2SPeter Wemm
968c2aa98e2SPeter Wemm if (tTd(29, 5))
969c2aa98e2SPeter Wemm {
97040266059SGregory Neil Shapiro sm_dprintf("recipient: testing local? cl=%d, rr5=%p\n\t",
9715b0945b5SGregory Neil Shapiro ConfigLevel, (void *)RewriteRules[5]);
972e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), new, false);
973c2aa98e2SPeter Wemm }
97406f25ae9SGregory Neil Shapiro if (ConfigLevel >= 2 && RewriteRules[5] != NULL &&
97506f25ae9SGregory Neil Shapiro bitnset(M_TRYRULESET5, m->m_flags) &&
97640266059SGregory Neil Shapiro !bitset(QNOTREMOTE, new->q_flags) &&
97740266059SGregory Neil Shapiro QS_IS_OK(new->q_state))
978c2aa98e2SPeter Wemm {
97940266059SGregory Neil Shapiro maplocaluser(new, sendq, aliaslevel + 1, e);
980c2aa98e2SPeter Wemm }
981c2aa98e2SPeter Wemm
982c2aa98e2SPeter Wemm /*
983c2aa98e2SPeter Wemm ** If it didn't get rewritten to another mailer, go ahead
984c2aa98e2SPeter Wemm ** and deliver it.
985c2aa98e2SPeter Wemm */
986c2aa98e2SPeter Wemm
98740266059SGregory Neil Shapiro if (QS_IS_OK(new->q_state) &&
988c2aa98e2SPeter Wemm bitnset(M_HASPWENT, m->m_flags))
989c2aa98e2SPeter Wemm {
990c2aa98e2SPeter Wemm auto bool fuzzy;
99140266059SGregory Neil Shapiro SM_MBDB_T user;
99240266059SGregory Neil Shapiro int status;
993c2aa98e2SPeter Wemm
994c2aa98e2SPeter Wemm /* warning -- finduser may trash buf */
99540266059SGregory Neil Shapiro status = finduser(buf, &fuzzy, &user);
99640266059SGregory Neil Shapiro switch (status)
997c2aa98e2SPeter Wemm {
99840266059SGregory Neil Shapiro case EX_TEMPFAIL:
99940266059SGregory Neil Shapiro new->q_state = QS_QUEUEUP;
100040266059SGregory Neil Shapiro new->q_status = "4.5.2";
100140266059SGregory Neil Shapiro giveresponse(EX_TEMPFAIL, new->q_status, m, NULL,
100240266059SGregory Neil Shapiro new->q_alias, (time_t) 0, e, new);
100340266059SGregory Neil Shapiro break;
100440266059SGregory Neil Shapiro default:
100540266059SGregory Neil Shapiro new->q_state = QS_BADADDR;
100640266059SGregory Neil Shapiro new->q_status = "5.1.1";
100740266059SGregory Neil Shapiro new->q_rstatus = "550 5.1.1 User unknown";
100840266059SGregory Neil Shapiro giveresponse(EX_NOUSER, new->q_status, m, NULL,
100940266059SGregory Neil Shapiro new->q_alias, (time_t) 0, e, new);
101040266059SGregory Neil Shapiro break;
101140266059SGregory Neil Shapiro case EX_OK:
1012c2aa98e2SPeter Wemm if (fuzzy)
1013c2aa98e2SPeter Wemm {
1014c2aa98e2SPeter Wemm /* name was a fuzzy match */
101540266059SGregory Neil Shapiro new->q_user = sm_rpool_strdup_x(e->e_rpool,
101640266059SGregory Neil Shapiro user.mbdb_name);
1017c2aa98e2SPeter Wemm if (findusercount++ > 3)
1018c2aa98e2SPeter Wemm {
101940266059SGregory Neil Shapiro new->q_state = QS_BADADDR;
102040266059SGregory Neil Shapiro new->q_status = "5.4.6";
102140266059SGregory Neil Shapiro usrerrenh(new->q_status,
102206f25ae9SGregory Neil Shapiro "554 aliasing/forwarding loop for %s broken",
102340266059SGregory Neil Shapiro user.mbdb_name);
1024c2aa98e2SPeter Wemm goto done;
1025c2aa98e2SPeter Wemm }
1026c2aa98e2SPeter Wemm
1027c2aa98e2SPeter Wemm /* see if it aliases */
102840266059SGregory Neil Shapiro (void) sm_strlcpy(buf, user.mbdb_name, buflen);
1029c2aa98e2SPeter Wemm goto trylocaluser;
1030c2aa98e2SPeter Wemm }
103140266059SGregory Neil Shapiro if (*user.mbdb_homedir == '\0')
103240266059SGregory Neil Shapiro new->q_home = NULL;
103340266059SGregory Neil Shapiro else if (strcmp(user.mbdb_homedir, "/") == 0)
103440266059SGregory Neil Shapiro new->q_home = "";
1035c2aa98e2SPeter Wemm else
103640266059SGregory Neil Shapiro new->q_home = sm_rpool_strdup_x(e->e_rpool,
103740266059SGregory Neil Shapiro user.mbdb_homedir);
103840266059SGregory Neil Shapiro if (user.mbdb_uid != SM_NO_UID)
1039c2aa98e2SPeter Wemm {
104040266059SGregory Neil Shapiro new->q_uid = user.mbdb_uid;
104140266059SGregory Neil Shapiro new->q_gid = user.mbdb_gid;
104240266059SGregory Neil Shapiro new->q_flags |= QGOODUID;
104340266059SGregory Neil Shapiro }
104440266059SGregory Neil Shapiro new->q_ruser = sm_rpool_strdup_x(e->e_rpool,
104540266059SGregory Neil Shapiro user.mbdb_name);
104640266059SGregory Neil Shapiro if (user.mbdb_fullname[0] != '\0')
104740266059SGregory Neil Shapiro new->q_fullname = sm_rpool_strdup_x(e->e_rpool,
104840266059SGregory Neil Shapiro user.mbdb_fullname);
104940266059SGregory Neil Shapiro if (!usershellok(user.mbdb_name, user.mbdb_shell))
105040266059SGregory Neil Shapiro {
105140266059SGregory Neil Shapiro new->q_flags |= QBOGUSSHELL;
1052c2aa98e2SPeter Wemm }
1053c2aa98e2SPeter Wemm if (bitset(EF_VRFYONLY, e->e_flags))
1054c2aa98e2SPeter Wemm {
1055c2aa98e2SPeter Wemm /* don't do any more now */
105640266059SGregory Neil Shapiro new->q_state = QS_VERIFIED;
1057c2aa98e2SPeter Wemm }
1058c2aa98e2SPeter Wemm else if (!quoted)
105940266059SGregory Neil Shapiro forward(new, sendq, aliaslevel, e);
1060c2aa98e2SPeter Wemm }
1061c2aa98e2SPeter Wemm }
106240266059SGregory Neil Shapiro if (!QS_IS_DEAD(new->q_state))
1063c2aa98e2SPeter Wemm e->e_nrcpts++;
1064c2aa98e2SPeter Wemm
1065c2aa98e2SPeter Wemm testselfdestruct:
106640266059SGregory Neil Shapiro new->q_flags |= QTHISPASS;
1067c2aa98e2SPeter Wemm if (tTd(26, 8))
1068c2aa98e2SPeter Wemm {
106940266059SGregory Neil Shapiro sm_dprintf("testselfdestruct: ");
1070e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), new, false);
1071c2aa98e2SPeter Wemm if (tTd(26, 10))
1072c2aa98e2SPeter Wemm {
107340266059SGregory Neil Shapiro sm_dprintf("SENDQ:\n");
1074e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), *sendq, true);
107540266059SGregory Neil Shapiro sm_dprintf("----\n");
1076c2aa98e2SPeter Wemm }
1077c2aa98e2SPeter Wemm }
107840266059SGregory Neil Shapiro if (new->q_alias == NULL && new != &e->e_from &&
107940266059SGregory Neil Shapiro QS_IS_DEAD(new->q_state))
1080c2aa98e2SPeter Wemm {
1081c2aa98e2SPeter Wemm for (q = *sendq; q != NULL; q = q->q_next)
1082c2aa98e2SPeter Wemm {
108306f25ae9SGregory Neil Shapiro if (!QS_IS_DEAD(q->q_state))
1084c2aa98e2SPeter Wemm break;
1085c2aa98e2SPeter Wemm }
1086c2aa98e2SPeter Wemm if (q == NULL)
1087c2aa98e2SPeter Wemm {
108840266059SGregory Neil Shapiro new->q_state = QS_BADADDR;
108940266059SGregory Neil Shapiro new->q_status = "5.4.6";
109040266059SGregory Neil Shapiro usrerrenh(new->q_status,
109106f25ae9SGregory Neil Shapiro "554 aliasing/forwarding loop broken");
1092c2aa98e2SPeter Wemm }
1093c2aa98e2SPeter Wemm }
1094c2aa98e2SPeter Wemm
1095c2aa98e2SPeter Wemm done:
109640266059SGregory Neil Shapiro new->q_flags |= QTHISPASS;
1097c2aa98e2SPeter Wemm if (buf != buf0)
109840266059SGregory Neil Shapiro sm_free(buf); /* XXX leak if above code raises exception */
1099c2aa98e2SPeter Wemm
1100c2aa98e2SPeter Wemm /*
1101c2aa98e2SPeter Wemm ** If we are at the top level, check to see if this has
1102c2aa98e2SPeter Wemm ** expanded to exactly one address. If so, it can inherit
1103c2aa98e2SPeter Wemm ** the primaryness of the address.
1104c2aa98e2SPeter Wemm **
1105c2aa98e2SPeter Wemm ** While we're at it, clear the QTHISPASS bits.
1106c2aa98e2SPeter Wemm */
1107c2aa98e2SPeter Wemm
1108c2aa98e2SPeter Wemm if (aliaslevel == 0)
1109c2aa98e2SPeter Wemm {
1110c2aa98e2SPeter Wemm int nrcpts = 0;
1111c2aa98e2SPeter Wemm ADDRESS *only = NULL;
1112c2aa98e2SPeter Wemm
1113c2aa98e2SPeter Wemm for (q = *sendq; q != NULL; q = q->q_next)
1114c2aa98e2SPeter Wemm {
1115c2aa98e2SPeter Wemm if (bitset(QTHISPASS, q->q_flags) &&
111606f25ae9SGregory Neil Shapiro QS_IS_SENDABLE(q->q_state))
1117c2aa98e2SPeter Wemm {
1118c2aa98e2SPeter Wemm nrcpts++;
1119c2aa98e2SPeter Wemm only = q;
1120c2aa98e2SPeter Wemm }
1121c2aa98e2SPeter Wemm q->q_flags &= ~QTHISPASS;
1122c2aa98e2SPeter Wemm }
1123c2aa98e2SPeter Wemm if (nrcpts == 1)
1124c2aa98e2SPeter Wemm {
1125c2aa98e2SPeter Wemm /* check to see if this actually got a new owner */
1126c2aa98e2SPeter Wemm q = only;
1127c2aa98e2SPeter Wemm while ((q = q->q_alias) != NULL)
1128c2aa98e2SPeter Wemm {
1129c2aa98e2SPeter Wemm if (q->q_owner != NULL)
1130c2aa98e2SPeter Wemm break;
1131c2aa98e2SPeter Wemm }
1132c2aa98e2SPeter Wemm if (q == NULL)
1133c2aa98e2SPeter Wemm only->q_flags |= QPRIMARY;
1134c2aa98e2SPeter Wemm }
1135c2aa98e2SPeter Wemm else if (!initialdontsend && nrcpts > 0)
1136c2aa98e2SPeter Wemm {
1137c2aa98e2SPeter Wemm /* arrange for return receipt */
1138c2aa98e2SPeter Wemm e->e_flags |= EF_SENDRECEIPT;
113940266059SGregory Neil Shapiro new->q_flags |= QEXPANDED;
114006f25ae9SGregory Neil Shapiro if (e->e_xfp != NULL &&
114140266059SGregory Neil Shapiro bitset(QPINGONSUCCESS, new->q_flags))
114240266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
1143c2aa98e2SPeter Wemm "%s... expanded to multiple addresses\n",
114440266059SGregory Neil Shapiro new->q_paddr);
1145c2aa98e2SPeter Wemm }
1146c2aa98e2SPeter Wemm }
114740266059SGregory Neil Shapiro new->q_flags |= QRCPTOK;
1148d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf0, sizeof(buf0), "%d", e->e_nrcpts);
114940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{nrcpts}"), buf0);
115040266059SGregory Neil Shapiro return new;
1151c2aa98e2SPeter Wemm }
1152d0cef73dSGregory Neil Shapiro
115340266059SGregory Neil Shapiro /*
1154c2aa98e2SPeter Wemm ** FINDUSER -- find the password entry for a user.
1155c2aa98e2SPeter Wemm **
1156c2aa98e2SPeter Wemm ** This looks a lot like getpwnam, except that it may want to
1157c2aa98e2SPeter Wemm ** do some fancier pattern matching in /etc/passwd.
1158c2aa98e2SPeter Wemm **
1159c2aa98e2SPeter Wemm ** This routine contains most of the time of many sendmail runs.
1160c2aa98e2SPeter Wemm ** It deserves to be optimized.
1161c2aa98e2SPeter Wemm **
1162c2aa98e2SPeter Wemm ** Parameters:
1163c2aa98e2SPeter Wemm ** name -- the name to match against.
116440266059SGregory Neil Shapiro ** fuzzyp -- an outarg that is set to true if this entry
1165c2aa98e2SPeter Wemm ** was found using the fuzzy matching algorithm;
116640266059SGregory Neil Shapiro ** set to false otherwise.
116740266059SGregory Neil Shapiro ** user -- structure to fill in if user is found
1168c2aa98e2SPeter Wemm **
1169c2aa98e2SPeter Wemm ** Returns:
117040266059SGregory Neil Shapiro ** On success, fill in *user, set *fuzzyp and return EX_OK.
117140266059SGregory Neil Shapiro ** If the user was not found, return EX_NOUSER.
117240266059SGregory Neil Shapiro ** On error, return EX_TEMPFAIL or EX_OSERR.
1173c2aa98e2SPeter Wemm **
1174c2aa98e2SPeter Wemm ** Side Effects:
1175c2aa98e2SPeter Wemm ** may modify name.
1176c2aa98e2SPeter Wemm */
1177c2aa98e2SPeter Wemm
117840266059SGregory Neil Shapiro int
finduser(name,fuzzyp,user)117940266059SGregory Neil Shapiro finduser(name, fuzzyp, user)
1180c2aa98e2SPeter Wemm char *name;
1181c2aa98e2SPeter Wemm bool *fuzzyp;
118240266059SGregory Neil Shapiro SM_MBDB_T *user;
1183c2aa98e2SPeter Wemm {
118440266059SGregory Neil Shapiro #if MATCHGECOS
1185c2aa98e2SPeter Wemm register struct passwd *pw;
11865b0945b5SGregory Neil Shapiro #endif
1187c2aa98e2SPeter Wemm register char *p;
1188c2aa98e2SPeter Wemm bool tryagain;
118940266059SGregory Neil Shapiro int status;
1190c2aa98e2SPeter Wemm
1191c2aa98e2SPeter Wemm if (tTd(29, 4))
119240266059SGregory Neil Shapiro sm_dprintf("finduser(%s): ", name);
1193c2aa98e2SPeter Wemm
119440266059SGregory Neil Shapiro *fuzzyp = false;
1195c2aa98e2SPeter Wemm
1196da7d7b9cSGregory Neil Shapiro #if HESIOD && !HESIOD_ALLOW_NUMERIC_LOGIN
1197c2aa98e2SPeter Wemm /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
1198c2aa98e2SPeter Wemm for (p = name; *p != '\0'; p++)
1199c2aa98e2SPeter Wemm if (!isascii(*p) || !isdigit(*p))
1200c2aa98e2SPeter Wemm break;
1201c2aa98e2SPeter Wemm if (*p == '\0')
1202c2aa98e2SPeter Wemm {
1203c2aa98e2SPeter Wemm if (tTd(29, 4))
120440266059SGregory Neil Shapiro sm_dprintf("failed (numeric input)\n");
120540266059SGregory Neil Shapiro return EX_NOUSER;
1206c2aa98e2SPeter Wemm }
1207da7d7b9cSGregory Neil Shapiro #endif /* HESIOD && !HESIOD_ALLOW_NUMERIC_LOGIN */
1208c2aa98e2SPeter Wemm
1209c2aa98e2SPeter Wemm /* look up this login name using fast path */
121040266059SGregory Neil Shapiro status = sm_mbdb_lookup(name, user);
121140266059SGregory Neil Shapiro if (status != EX_NOUSER)
1212c2aa98e2SPeter Wemm {
1213c2aa98e2SPeter Wemm if (tTd(29, 4))
121440266059SGregory Neil Shapiro sm_dprintf("%s (non-fuzzy)\n", sm_strexit(status));
121540266059SGregory Neil Shapiro return status;
1216c2aa98e2SPeter Wemm }
1217c2aa98e2SPeter Wemm
1218c2aa98e2SPeter Wemm /* try mapping it to lower case */
121940266059SGregory Neil Shapiro tryagain = false;
1220c2aa98e2SPeter Wemm for (p = name; *p != '\0'; p++)
1221c2aa98e2SPeter Wemm {
1222c2aa98e2SPeter Wemm if (isascii(*p) && isupper(*p))
1223c2aa98e2SPeter Wemm {
1224c2aa98e2SPeter Wemm *p = tolower(*p);
122540266059SGregory Neil Shapiro tryagain = true;
1226c2aa98e2SPeter Wemm }
1227c2aa98e2SPeter Wemm }
122840266059SGregory Neil Shapiro if (tryagain && (status = sm_mbdb_lookup(name, user)) != EX_NOUSER)
1229c2aa98e2SPeter Wemm {
1230c2aa98e2SPeter Wemm if (tTd(29, 4))
123140266059SGregory Neil Shapiro sm_dprintf("%s (lower case)\n", sm_strexit(status));
123240266059SGregory Neil Shapiro *fuzzyp = true;
123340266059SGregory Neil Shapiro return status;
1234c2aa98e2SPeter Wemm }
1235c2aa98e2SPeter Wemm
1236c2aa98e2SPeter Wemm #if MATCHGECOS
1237c2aa98e2SPeter Wemm /* see if fuzzy matching allowed */
1238c2aa98e2SPeter Wemm if (!MatchGecos)
1239c2aa98e2SPeter Wemm {
1240c2aa98e2SPeter Wemm if (tTd(29, 4))
124140266059SGregory Neil Shapiro sm_dprintf("not found (fuzzy disabled)\n");
124240266059SGregory Neil Shapiro return EX_NOUSER;
1243c2aa98e2SPeter Wemm }
1244c2aa98e2SPeter Wemm
1245c2aa98e2SPeter Wemm /* search for a matching full name instead */
1246c2aa98e2SPeter Wemm for (p = name; *p != '\0'; p++)
1247c2aa98e2SPeter Wemm {
1248c2aa98e2SPeter Wemm if (*p == (SpaceSub & 0177) || *p == '_')
1249c2aa98e2SPeter Wemm *p = ' ';
1250c2aa98e2SPeter Wemm }
1251c2aa98e2SPeter Wemm (void) setpwent();
1252c2aa98e2SPeter Wemm while ((pw = getpwent()) != NULL)
1253c2aa98e2SPeter Wemm {
12542fb4f839SGregory Neil Shapiro char buf[MAXNAME + 1]; /* EAI: ok: for pw_gecos */
1255c2aa98e2SPeter Wemm
1256c2aa98e2SPeter Wemm # if 0
12572fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(pw->pw_name, name))
1258c2aa98e2SPeter Wemm {
1259c2aa98e2SPeter Wemm if (tTd(29, 4))
126040266059SGregory Neil Shapiro sm_dprintf("found (case wrapped)\n");
1261c2aa98e2SPeter Wemm break;
1262c2aa98e2SPeter Wemm }
126306f25ae9SGregory Neil Shapiro # endif /* 0 */
1264c2aa98e2SPeter Wemm
1265d0cef73dSGregory Neil Shapiro sm_pwfullname(pw->pw_gecos, pw->pw_name, buf, sizeof(buf));
12662fb4f839SGregory Neil Shapiro if (strchr(buf, ' ') != NULL && SM_STRCASEEQ(buf, name))
1267c2aa98e2SPeter Wemm {
1268c2aa98e2SPeter Wemm if (tTd(29, 4))
126940266059SGregory Neil Shapiro sm_dprintf("fuzzy matches %s\n", pw->pw_name);
1270c2aa98e2SPeter Wemm message("sending to login name %s", pw->pw_name);
1271c2aa98e2SPeter Wemm break;
1272c2aa98e2SPeter Wemm }
1273c2aa98e2SPeter Wemm }
1274c2aa98e2SPeter Wemm if (pw != NULL)
127540266059SGregory Neil Shapiro *fuzzyp = true;
1276c2aa98e2SPeter Wemm else if (tTd(29, 4))
127740266059SGregory Neil Shapiro sm_dprintf("no fuzzy match found\n");
1278c2aa98e2SPeter Wemm # if DEC_OSF_BROKEN_GETPWENT /* DEC OSF/1 3.2 or earlier */
1279c2aa98e2SPeter Wemm endpwent();
12805b0945b5SGregory Neil Shapiro # endif
128140266059SGregory Neil Shapiro if (pw == NULL)
128240266059SGregory Neil Shapiro return EX_NOUSER;
128340266059SGregory Neil Shapiro sm_mbdb_frompw(user, pw);
128440266059SGregory Neil Shapiro return EX_OK;
128506f25ae9SGregory Neil Shapiro #else /* MATCHGECOS */
1286c2aa98e2SPeter Wemm if (tTd(29, 4))
128740266059SGregory Neil Shapiro sm_dprintf("not found (fuzzy disabled)\n");
128840266059SGregory Neil Shapiro return EX_NOUSER;
128906f25ae9SGregory Neil Shapiro #endif /* MATCHGECOS */
1290c2aa98e2SPeter Wemm }
1291d0cef73dSGregory Neil Shapiro
129240266059SGregory Neil Shapiro /*
1293c2aa98e2SPeter Wemm ** WRITABLE -- predicate returning if the file is writable.
1294c2aa98e2SPeter Wemm **
1295c2aa98e2SPeter Wemm ** This routine must duplicate the algorithm in sys/fio.c.
1296c2aa98e2SPeter Wemm ** Unfortunately, we cannot use the access call since we
1297c2aa98e2SPeter Wemm ** won't necessarily be the real uid when we try to
1298c2aa98e2SPeter Wemm ** actually open the file.
1299c2aa98e2SPeter Wemm **
1300c2aa98e2SPeter Wemm ** Notice that ANY file with ANY execute bit is automatically
1301c2aa98e2SPeter Wemm ** not writable. This is also enforced by mailfile.
1302c2aa98e2SPeter Wemm **
1303c2aa98e2SPeter Wemm ** Parameters:
1304c2aa98e2SPeter Wemm ** filename -- the file name to check.
1305c2aa98e2SPeter Wemm ** ctladdr -- the controlling address for this file.
1306c2aa98e2SPeter Wemm ** flags -- SFF_* flags to control the function.
1307c2aa98e2SPeter Wemm **
1308c2aa98e2SPeter Wemm ** Returns:
130940266059SGregory Neil Shapiro ** true -- if we will be able to write this file.
131040266059SGregory Neil Shapiro ** false -- if we cannot write this file.
1311c2aa98e2SPeter Wemm **
1312c2aa98e2SPeter Wemm ** Side Effects:
1313c2aa98e2SPeter Wemm ** none.
1314c2aa98e2SPeter Wemm */
1315c2aa98e2SPeter Wemm
1316c2aa98e2SPeter Wemm bool
writable(filename,ctladdr,flags)1317c2aa98e2SPeter Wemm writable(filename, ctladdr, flags)
1318c2aa98e2SPeter Wemm char *filename;
1319c2aa98e2SPeter Wemm ADDRESS *ctladdr;
132006f25ae9SGregory Neil Shapiro long flags;
1321c2aa98e2SPeter Wemm {
132206f25ae9SGregory Neil Shapiro uid_t euid = 0;
132306f25ae9SGregory Neil Shapiro gid_t egid = 0;
132406f25ae9SGregory Neil Shapiro char *user = NULL;
1325c2aa98e2SPeter Wemm
1326c2aa98e2SPeter Wemm if (tTd(44, 5))
132740266059SGregory Neil Shapiro sm_dprintf("writable(%s, 0x%lx)\n", filename, flags);
1328c2aa98e2SPeter Wemm
1329c2aa98e2SPeter Wemm /*
1330c2aa98e2SPeter Wemm ** File does exist -- check that it is writable.
1331c2aa98e2SPeter Wemm */
1332c2aa98e2SPeter Wemm
1333c2aa98e2SPeter Wemm if (geteuid() != 0)
1334c2aa98e2SPeter Wemm {
1335c2aa98e2SPeter Wemm euid = geteuid();
1336c2aa98e2SPeter Wemm egid = getegid();
133706f25ae9SGregory Neil Shapiro user = NULL;
1338c2aa98e2SPeter Wemm }
1339c2aa98e2SPeter Wemm else if (ctladdr != NULL)
1340c2aa98e2SPeter Wemm {
1341c2aa98e2SPeter Wemm euid = ctladdr->q_uid;
1342c2aa98e2SPeter Wemm egid = ctladdr->q_gid;
134306f25ae9SGregory Neil Shapiro user = ctladdr->q_user;
1344c2aa98e2SPeter Wemm }
1345c2aa98e2SPeter Wemm else if (bitset(SFF_RUNASREALUID, flags))
1346c2aa98e2SPeter Wemm {
1347c2aa98e2SPeter Wemm euid = RealUid;
1348c2aa98e2SPeter Wemm egid = RealGid;
134906f25ae9SGregory Neil Shapiro user = RealUserName;
1350c2aa98e2SPeter Wemm }
1351c2aa98e2SPeter Wemm else if (FileMailer != NULL && !bitset(SFF_ROOTOK, flags))
1352c2aa98e2SPeter Wemm {
1353e92d3f3fSGregory Neil Shapiro if (FileMailer->m_uid == NO_UID)
1354e92d3f3fSGregory Neil Shapiro {
1355e92d3f3fSGregory Neil Shapiro euid = DefUid;
1356e92d3f3fSGregory Neil Shapiro user = DefUser;
1357e92d3f3fSGregory Neil Shapiro }
1358e92d3f3fSGregory Neil Shapiro else
1359e92d3f3fSGregory Neil Shapiro {
1360c2aa98e2SPeter Wemm euid = FileMailer->m_uid;
136106f25ae9SGregory Neil Shapiro user = NULL;
1362c2aa98e2SPeter Wemm }
1363e92d3f3fSGregory Neil Shapiro if (FileMailer->m_gid == NO_GID)
1364e92d3f3fSGregory Neil Shapiro egid = DefGid;
1365e92d3f3fSGregory Neil Shapiro else
1366e92d3f3fSGregory Neil Shapiro egid = FileMailer->m_gid;
1367e92d3f3fSGregory Neil Shapiro }
1368c2aa98e2SPeter Wemm else
1369c2aa98e2SPeter Wemm {
1370c2aa98e2SPeter Wemm euid = egid = 0;
137106f25ae9SGregory Neil Shapiro user = NULL;
1372c2aa98e2SPeter Wemm }
1373c2aa98e2SPeter Wemm if (!bitset(SFF_ROOTOK, flags))
1374c2aa98e2SPeter Wemm {
1375c2aa98e2SPeter Wemm if (euid == 0)
1376c2aa98e2SPeter Wemm {
1377c2aa98e2SPeter Wemm euid = DefUid;
137806f25ae9SGregory Neil Shapiro user = DefUser;
1379c2aa98e2SPeter Wemm }
1380c2aa98e2SPeter Wemm if (egid == 0)
1381c2aa98e2SPeter Wemm egid = DefGid;
1382c2aa98e2SPeter Wemm }
1383c2aa98e2SPeter Wemm if (geteuid() == 0 &&
1384c2aa98e2SPeter Wemm (ctladdr == NULL || !bitset(QGOODUID, ctladdr->q_flags)))
1385c2aa98e2SPeter Wemm flags |= SFF_SETUIDOK;
1386c2aa98e2SPeter Wemm
138706f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail))
1388c2aa98e2SPeter Wemm flags |= SFF_NOSLINK;
138906f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail))
1390c2aa98e2SPeter Wemm flags |= SFF_NOHLINK;
1391c2aa98e2SPeter Wemm
139206f25ae9SGregory Neil Shapiro errno = safefile(filename, euid, egid, user, flags, S_IWRITE, NULL);
1393c2aa98e2SPeter Wemm return errno == 0;
1394c2aa98e2SPeter Wemm }
1395d0cef73dSGregory Neil Shapiro
139640266059SGregory Neil Shapiro /*
1397c2aa98e2SPeter Wemm ** INCLUDE -- handle :include: specification.
1398c2aa98e2SPeter Wemm **
1399c2aa98e2SPeter Wemm ** Parameters:
1400c2aa98e2SPeter Wemm ** fname -- filename to include.
140140266059SGregory Neil Shapiro ** forwarding -- if true, we are reading a .forward file.
140240266059SGregory Neil Shapiro ** if false, it's a :include: file.
1403c2aa98e2SPeter Wemm ** ctladdr -- address template to use to fill in these
1404c2aa98e2SPeter Wemm ** addresses -- effective user/group id are
1405c2aa98e2SPeter Wemm ** the important things.
1406c2aa98e2SPeter Wemm ** sendq -- a pointer to the head of the send queue
1407c2aa98e2SPeter Wemm ** to put these addresses in.
1408c2aa98e2SPeter Wemm ** aliaslevel -- the alias nesting depth.
1409c2aa98e2SPeter Wemm ** e -- the current envelope.
1410c2aa98e2SPeter Wemm **
1411c2aa98e2SPeter Wemm ** Returns:
1412c2aa98e2SPeter Wemm ** open error status
1413c2aa98e2SPeter Wemm **
1414c2aa98e2SPeter Wemm ** Side Effects:
1415c2aa98e2SPeter Wemm ** reads the :include: file and sends to everyone
1416c2aa98e2SPeter Wemm ** listed in that file.
1417c2aa98e2SPeter Wemm **
1418c2aa98e2SPeter Wemm ** Security Note:
1419c2aa98e2SPeter Wemm ** If you have restricted chown (that is, you can't
1420c2aa98e2SPeter Wemm ** give a file away), it is reasonable to allow programs
1421c2aa98e2SPeter Wemm ** and files called from this :include: file to be to be
1422c2aa98e2SPeter Wemm ** run as the owner of the :include: file. This is bogus
1423c2aa98e2SPeter Wemm ** if there is any chance of someone giving away a file.
1424c2aa98e2SPeter Wemm ** We assume that pre-POSIX systems can give away files.
1425c2aa98e2SPeter Wemm **
1426c2aa98e2SPeter Wemm ** There is an additional restriction that if you
1427c2aa98e2SPeter Wemm ** forward to a :include: file, it will not take on
1428c2aa98e2SPeter Wemm ** the ownership of the :include: file. This may not
1429c2aa98e2SPeter Wemm ** be necessary, but shouldn't hurt.
1430c2aa98e2SPeter Wemm */
1431c2aa98e2SPeter Wemm
1432c2aa98e2SPeter Wemm static jmp_buf CtxIncludeTimeout;
1433c2aa98e2SPeter Wemm
1434c2aa98e2SPeter Wemm int
include(fname,forwarding,ctladdr,sendq,aliaslevel,e)1435c2aa98e2SPeter Wemm include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
1436c2aa98e2SPeter Wemm char *fname;
1437c2aa98e2SPeter Wemm bool forwarding;
1438c2aa98e2SPeter Wemm ADDRESS *ctladdr;
1439c2aa98e2SPeter Wemm ADDRESS **sendq;
1440c2aa98e2SPeter Wemm int aliaslevel;
1441c2aa98e2SPeter Wemm ENVELOPE *e;
1442c2aa98e2SPeter Wemm {
144340266059SGregory Neil Shapiro SM_FILE_T *volatile fp = NULL;
1444c2aa98e2SPeter Wemm char *oldto = e->e_to;
1445c2aa98e2SPeter Wemm char *oldfilename = FileName;
1446c2aa98e2SPeter Wemm int oldlinenumber = LineNumber;
144740266059SGregory Neil Shapiro register SM_EVENT *ev = NULL;
1448c2aa98e2SPeter Wemm int nincludes;
1449c2aa98e2SPeter Wemm int mode;
145040266059SGregory Neil Shapiro volatile bool maxreached = false;
1451c2aa98e2SPeter Wemm register ADDRESS *ca;
145206f25ae9SGregory Neil Shapiro volatile uid_t saveduid;
145306f25ae9SGregory Neil Shapiro volatile gid_t savedgid;
145406f25ae9SGregory Neil Shapiro volatile uid_t uid;
145506f25ae9SGregory Neil Shapiro volatile gid_t gid;
145606f25ae9SGregory Neil Shapiro char *volatile user;
1457c2aa98e2SPeter Wemm int rval = 0;
145806f25ae9SGregory Neil Shapiro volatile long sfflags = SFF_REGONLY;
1459c2aa98e2SPeter Wemm register char *p;
146040266059SGregory Neil Shapiro bool safechown = false;
146140266059SGregory Neil Shapiro volatile bool safedir = false;
1462c2aa98e2SPeter Wemm struct stat st;
1463c2aa98e2SPeter Wemm char buf[MAXLINE];
1464c2aa98e2SPeter Wemm
1465c2aa98e2SPeter Wemm if (tTd(27, 2))
146640266059SGregory Neil Shapiro sm_dprintf("include(%s)\n", fname);
1467c2aa98e2SPeter Wemm if (tTd(27, 4))
1468da7d7b9cSGregory Neil Shapiro sm_dprintf(" ruid=%ld euid=%ld\n",
1469da7d7b9cSGregory Neil Shapiro (long) getuid(), (long) geteuid());
1470c2aa98e2SPeter Wemm if (tTd(27, 14))
1471c2aa98e2SPeter Wemm {
147240266059SGregory Neil Shapiro sm_dprintf("ctladdr ");
1473e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), ctladdr, false);
1474c2aa98e2SPeter Wemm }
1475c2aa98e2SPeter Wemm
1476c2aa98e2SPeter Wemm if (tTd(27, 9))
1477da7d7b9cSGregory Neil Shapiro sm_dprintf("include: old uid = %ld/%ld\n",
1478da7d7b9cSGregory Neil Shapiro (long) getuid(), (long) geteuid());
1479c2aa98e2SPeter Wemm
148042e5d165SGregory Neil Shapiro if (forwarding)
148142e5d165SGregory Neil Shapiro {
148294c01205SGregory Neil Shapiro sfflags |= SFF_MUSTOWN|SFF_ROOTOK;
148342e5d165SGregory Neil Shapiro if (!bitnset(DBS_GROUPWRITABLEFORWARDFILE, DontBlameSendmail))
148442e5d165SGregory Neil Shapiro sfflags |= SFF_NOGWFILES;
148542e5d165SGregory Neil Shapiro if (!bitnset(DBS_WORLDWRITABLEFORWARDFILE, DontBlameSendmail))
148642e5d165SGregory Neil Shapiro sfflags |= SFF_NOWWFILES;
148742e5d165SGregory Neil Shapiro }
148842e5d165SGregory Neil Shapiro else
148942e5d165SGregory Neil Shapiro {
149042e5d165SGregory Neil Shapiro if (!bitnset(DBS_GROUPWRITABLEINCLUDEFILE, DontBlameSendmail))
149142e5d165SGregory Neil Shapiro sfflags |= SFF_NOGWFILES;
149242e5d165SGregory Neil Shapiro if (!bitnset(DBS_WORLDWRITABLEINCLUDEFILE, DontBlameSendmail))
149342e5d165SGregory Neil Shapiro sfflags |= SFF_NOWWFILES;
149442e5d165SGregory Neil Shapiro }
1495c2aa98e2SPeter Wemm
149606f25ae9SGregory Neil Shapiro /*
149706f25ae9SGregory Neil Shapiro ** If RunAsUser set, won't be able to run programs as user
149806f25ae9SGregory Neil Shapiro ** so mark them as unsafe unless the administrator knows better.
149906f25ae9SGregory Neil Shapiro */
150006f25ae9SGregory Neil Shapiro
150106f25ae9SGregory Neil Shapiro if ((geteuid() != 0 || RunAsUid != 0) &&
150206f25ae9SGregory Neil Shapiro !bitnset(DBS_NONROOTSAFEADDR, DontBlameSendmail))
150306f25ae9SGregory Neil Shapiro {
150406f25ae9SGregory Neil Shapiro if (tTd(27, 4))
1505da7d7b9cSGregory Neil Shapiro sm_dprintf("include: not safe (euid=%ld, RunAsUid=%ld)\n",
1506da7d7b9cSGregory Neil Shapiro (long) geteuid(), (long) RunAsUid);
150706f25ae9SGregory Neil Shapiro ctladdr->q_flags |= QUNSAFEADDR;
150806f25ae9SGregory Neil Shapiro }
150906f25ae9SGregory Neil Shapiro
1510c2aa98e2SPeter Wemm ca = getctladdr(ctladdr);
151106f25ae9SGregory Neil Shapiro if (ca == NULL ||
151206f25ae9SGregory Neil Shapiro (ca->q_uid == DefUid && ca->q_gid == 0))
1513c2aa98e2SPeter Wemm {
1514c2aa98e2SPeter Wemm uid = DefUid;
1515c2aa98e2SPeter Wemm gid = DefGid;
151606f25ae9SGregory Neil Shapiro user = DefUser;
1517c2aa98e2SPeter Wemm }
1518c2aa98e2SPeter Wemm else
1519c2aa98e2SPeter Wemm {
1520c2aa98e2SPeter Wemm uid = ca->q_uid;
1521c2aa98e2SPeter Wemm gid = ca->q_gid;
152206f25ae9SGregory Neil Shapiro user = ca->q_user;
1523c2aa98e2SPeter Wemm }
152406f25ae9SGregory Neil Shapiro #if MAILER_SETUID_METHOD != USE_SETUID
1525c2aa98e2SPeter Wemm saveduid = geteuid();
1526c2aa98e2SPeter Wemm savedgid = getegid();
1527c2aa98e2SPeter Wemm if (saveduid == 0)
1528c2aa98e2SPeter Wemm {
1529c2aa98e2SPeter Wemm if (!DontInitGroups)
1530c2aa98e2SPeter Wemm {
153106f25ae9SGregory Neil Shapiro if (initgroups(user, gid) == -1)
153206f25ae9SGregory Neil Shapiro {
153306f25ae9SGregory Neil Shapiro rval = EAGAIN;
1534da7d7b9cSGregory Neil Shapiro syserr("include: initgroups(%s, %ld) failed",
1535da7d7b9cSGregory Neil Shapiro user, (long) gid);
153606f25ae9SGregory Neil Shapiro goto resetuid;
153706f25ae9SGregory Neil Shapiro }
1538c2aa98e2SPeter Wemm }
1539c2aa98e2SPeter Wemm else
1540c2aa98e2SPeter Wemm {
1541c2aa98e2SPeter Wemm GIDSET_T gidset[1];
1542c2aa98e2SPeter Wemm
1543c2aa98e2SPeter Wemm gidset[0] = gid;
1544c2aa98e2SPeter Wemm if (setgroups(1, gidset) == -1)
154506f25ae9SGregory Neil Shapiro {
154606f25ae9SGregory Neil Shapiro rval = EAGAIN;
1547c2aa98e2SPeter Wemm syserr("include: setgroups() failed");
154806f25ae9SGregory Neil Shapiro goto resetuid;
154906f25ae9SGregory Neil Shapiro }
1550c2aa98e2SPeter Wemm }
1551c2aa98e2SPeter Wemm
1552c2aa98e2SPeter Wemm if (gid != 0 && setgid(gid) < -1)
155306f25ae9SGregory Neil Shapiro {
155406f25ae9SGregory Neil Shapiro rval = EAGAIN;
1555da7d7b9cSGregory Neil Shapiro syserr("setgid(%ld) failure", (long) gid);
155606f25ae9SGregory Neil Shapiro goto resetuid;
155706f25ae9SGregory Neil Shapiro }
1558c2aa98e2SPeter Wemm if (uid != 0)
1559c2aa98e2SPeter Wemm {
156006f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETEUID
1561c2aa98e2SPeter Wemm if (seteuid(uid) < 0)
156206f25ae9SGregory Neil Shapiro {
156306f25ae9SGregory Neil Shapiro rval = EAGAIN;
1564da7d7b9cSGregory Neil Shapiro syserr("seteuid(%ld) failure (real=%ld, eff=%ld)",
1565da7d7b9cSGregory Neil Shapiro (long) uid, (long) getuid(), (long) geteuid());
156606f25ae9SGregory Neil Shapiro goto resetuid;
156706f25ae9SGregory Neil Shapiro }
156806f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETEUID */
156906f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETREUID
1570c2aa98e2SPeter Wemm if (setreuid(0, uid) < 0)
157106f25ae9SGregory Neil Shapiro {
157206f25ae9SGregory Neil Shapiro rval = EAGAIN;
1573da7d7b9cSGregory Neil Shapiro syserr("setreuid(0, %ld) failure (real=%ld, eff=%ld)",
1574da7d7b9cSGregory Neil Shapiro (long) uid, (long) getuid(), (long) geteuid());
157506f25ae9SGregory Neil Shapiro goto resetuid;
157606f25ae9SGregory Neil Shapiro }
157706f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETREUID */
1578c2aa98e2SPeter Wemm }
1579c2aa98e2SPeter Wemm }
158006f25ae9SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD != USE_SETUID */
1581c2aa98e2SPeter Wemm
1582c2aa98e2SPeter Wemm if (tTd(27, 9))
1583da7d7b9cSGregory Neil Shapiro sm_dprintf("include: new uid = %ld/%ld\n",
1584da7d7b9cSGregory Neil Shapiro (long) getuid(), (long) geteuid());
1585c2aa98e2SPeter Wemm
1586c2aa98e2SPeter Wemm /*
1587c2aa98e2SPeter Wemm ** If home directory is remote mounted but server is down,
1588c2aa98e2SPeter Wemm ** this can hang or give errors; use a timeout to avoid this
1589c2aa98e2SPeter Wemm */
1590c2aa98e2SPeter Wemm
1591c2aa98e2SPeter Wemm if (setjmp(CtxIncludeTimeout) != 0)
1592c2aa98e2SPeter Wemm {
159306f25ae9SGregory Neil Shapiro ctladdr->q_state = QS_QUEUEUP;
1594c2aa98e2SPeter Wemm errno = 0;
1595c2aa98e2SPeter Wemm
1596c2aa98e2SPeter Wemm /* return pseudo-error code */
1597c2aa98e2SPeter Wemm rval = E_SM_OPENTIMEOUT;
1598c2aa98e2SPeter Wemm goto resetuid;
1599c2aa98e2SPeter Wemm }
1600c2aa98e2SPeter Wemm if (TimeOuts.to_fileopen > 0)
160140266059SGregory Neil Shapiro ev = sm_setevent(TimeOuts.to_fileopen, includetimeout, 0);
1602c2aa98e2SPeter Wemm else
1603c2aa98e2SPeter Wemm ev = NULL;
1604c2aa98e2SPeter Wemm
1605c2aa98e2SPeter Wemm /* check for writable parent directory */
1606c2aa98e2SPeter Wemm p = strrchr(fname, '/');
1607c2aa98e2SPeter Wemm if (p != NULL)
1608c2aa98e2SPeter Wemm {
1609c2aa98e2SPeter Wemm int ret;
1610c2aa98e2SPeter Wemm
1611c2aa98e2SPeter Wemm *p = '\0';
161206f25ae9SGregory Neil Shapiro ret = safedirpath(fname, uid, gid, user,
161306f25ae9SGregory Neil Shapiro sfflags|SFF_SAFEDIRPATH, 0, 0);
1614c2aa98e2SPeter Wemm if (ret == 0)
1615c2aa98e2SPeter Wemm {
1616c2aa98e2SPeter Wemm /* in safe directory: relax chown & link rules */
161740266059SGregory Neil Shapiro safedir = true;
1618c2aa98e2SPeter Wemm sfflags |= SFF_NOPATHCHECK;
1619c2aa98e2SPeter Wemm }
1620c2aa98e2SPeter Wemm else
1621c2aa98e2SPeter Wemm {
162206f25ae9SGregory Neil Shapiro if (bitnset((forwarding ?
1623c2aa98e2SPeter Wemm DBS_FORWARDFILEINUNSAFEDIRPATH :
1624c2aa98e2SPeter Wemm DBS_INCLUDEFILEINUNSAFEDIRPATH),
1625c2aa98e2SPeter Wemm DontBlameSendmail))
1626c2aa98e2SPeter Wemm sfflags |= SFF_NOPATHCHECK;
162706f25ae9SGregory Neil Shapiro else if (bitnset((forwarding ?
1628c2aa98e2SPeter Wemm DBS_FORWARDFILEINGROUPWRITABLEDIRPATH :
1629c2aa98e2SPeter Wemm DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH),
1630c2aa98e2SPeter Wemm DontBlameSendmail) &&
1631c2aa98e2SPeter Wemm ret == E_SM_GWDIR)
1632c2aa98e2SPeter Wemm {
163306f25ae9SGregory Neil Shapiro setbitn(DBS_GROUPWRITABLEDIRPATHSAFE,
163406f25ae9SGregory Neil Shapiro DontBlameSendmail);
163506f25ae9SGregory Neil Shapiro ret = safedirpath(fname, uid, gid, user,
163606f25ae9SGregory Neil Shapiro sfflags|SFF_SAFEDIRPATH,
163706f25ae9SGregory Neil Shapiro 0, 0);
163806f25ae9SGregory Neil Shapiro clrbitn(DBS_GROUPWRITABLEDIRPATHSAFE,
163906f25ae9SGregory Neil Shapiro DontBlameSendmail);
1640c2aa98e2SPeter Wemm if (ret == 0)
1641c2aa98e2SPeter Wemm sfflags |= SFF_NOPATHCHECK;
1642c2aa98e2SPeter Wemm else
1643c2aa98e2SPeter Wemm sfflags |= SFF_SAFEDIRPATH;
1644c2aa98e2SPeter Wemm }
1645c2aa98e2SPeter Wemm else
1646c2aa98e2SPeter Wemm sfflags |= SFF_SAFEDIRPATH;
1647c2aa98e2SPeter Wemm if (ret > E_PSEUDOBASE &&
164806f25ae9SGregory Neil Shapiro !bitnset((forwarding ?
1649c2aa98e2SPeter Wemm DBS_FORWARDFILEINUNSAFEDIRPATHSAFE :
1650c2aa98e2SPeter Wemm DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE),
1651c2aa98e2SPeter Wemm DontBlameSendmail))
1652c2aa98e2SPeter Wemm {
165340266059SGregory Neil Shapiro if (LogLevel > 11)
1654c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id,
1655c2aa98e2SPeter Wemm "%s: unsafe directory path, marked unsafe",
1656c2aa98e2SPeter Wemm shortenstring(fname, MAXSHORTSTR));
1657c2aa98e2SPeter Wemm ctladdr->q_flags |= QUNSAFEADDR;
1658c2aa98e2SPeter Wemm }
1659c2aa98e2SPeter Wemm }
1660c2aa98e2SPeter Wemm *p = '/';
1661c2aa98e2SPeter Wemm }
1662c2aa98e2SPeter Wemm
1663c2aa98e2SPeter Wemm /* allow links only in unwritable directories */
1664c2aa98e2SPeter Wemm if (!safedir &&
166506f25ae9SGregory Neil Shapiro !bitnset((forwarding ?
1666c2aa98e2SPeter Wemm DBS_LINKEDFORWARDFILEINWRITABLEDIR :
1667c2aa98e2SPeter Wemm DBS_LINKEDINCLUDEFILEINWRITABLEDIR),
1668c2aa98e2SPeter Wemm DontBlameSendmail))
1669c2aa98e2SPeter Wemm sfflags |= SFF_NOLINK;
1670c2aa98e2SPeter Wemm
167106f25ae9SGregory Neil Shapiro rval = safefile(fname, uid, gid, user, sfflags, S_IREAD, &st);
1672c2aa98e2SPeter Wemm if (rval != 0)
1673c2aa98e2SPeter Wemm {
1674c2aa98e2SPeter Wemm /* don't use this :include: file */
1675c2aa98e2SPeter Wemm if (tTd(27, 4))
1676da7d7b9cSGregory Neil Shapiro sm_dprintf("include: not safe (uid=%ld): %s\n",
1677da7d7b9cSGregory Neil Shapiro (long) uid, sm_errstring(rval));
1678c2aa98e2SPeter Wemm }
167940266059SGregory Neil Shapiro else if ((fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, fname,
168040266059SGregory Neil Shapiro SM_IO_RDONLY, NULL)) == NULL)
1681c2aa98e2SPeter Wemm {
1682c2aa98e2SPeter Wemm rval = errno;
1683c2aa98e2SPeter Wemm if (tTd(27, 4))
168440266059SGregory Neil Shapiro sm_dprintf("include: open: %s\n", sm_errstring(rval));
1685c2aa98e2SPeter Wemm }
168640266059SGregory Neil Shapiro else if (filechanged(fname, sm_io_getinfo(fp,SM_IO_WHAT_FD, NULL), &st))
1687c2aa98e2SPeter Wemm {
1688c2aa98e2SPeter Wemm rval = E_SM_FILECHANGE;
1689c2aa98e2SPeter Wemm if (tTd(27, 4))
169040266059SGregory Neil Shapiro sm_dprintf("include: file changed after open\n");
1691c2aa98e2SPeter Wemm }
1692c2aa98e2SPeter Wemm if (ev != NULL)
169340266059SGregory Neil Shapiro sm_clrevent(ev);
1694c2aa98e2SPeter Wemm
1695c2aa98e2SPeter Wemm resetuid:
1696c2aa98e2SPeter Wemm
1697c2aa98e2SPeter Wemm #if HASSETREUID || USESETEUID
1698c2aa98e2SPeter Wemm if (saveduid == 0)
1699c2aa98e2SPeter Wemm {
1700c2aa98e2SPeter Wemm if (uid != 0)
1701c2aa98e2SPeter Wemm {
1702c2aa98e2SPeter Wemm # if USESETEUID
1703c2aa98e2SPeter Wemm if (seteuid(0) < 0)
1704da7d7b9cSGregory Neil Shapiro syserr("!seteuid(0) failure (real=%ld, eff=%ld)",
1705da7d7b9cSGregory Neil Shapiro (long) getuid(), (long) geteuid());
170606f25ae9SGregory Neil Shapiro # else /* USESETEUID */
1707c2aa98e2SPeter Wemm if (setreuid(-1, 0) < 0)
1708da7d7b9cSGregory Neil Shapiro syserr("!setreuid(-1, 0) failure (real=%ld, eff=%ld)",
1709da7d7b9cSGregory Neil Shapiro (long) getuid(), (long) geteuid());
1710c2aa98e2SPeter Wemm if (setreuid(RealUid, 0) < 0)
1711da7d7b9cSGregory Neil Shapiro syserr("!setreuid(%ld, 0) failure (real=%ld, eff=%ld)",
1712da7d7b9cSGregory Neil Shapiro (long) RealUid, (long) getuid(),
1713da7d7b9cSGregory Neil Shapiro (long) geteuid());
171406f25ae9SGregory Neil Shapiro # endif /* USESETEUID */
1715c2aa98e2SPeter Wemm }
171606f25ae9SGregory Neil Shapiro if (setgid(savedgid) < 0)
1717da7d7b9cSGregory Neil Shapiro syserr("!setgid(%ld) failure (real=%ld eff=%ld)",
1718da7d7b9cSGregory Neil Shapiro (long) savedgid, (long) getgid(),
1719da7d7b9cSGregory Neil Shapiro (long) getegid());
1720c2aa98e2SPeter Wemm }
172106f25ae9SGregory Neil Shapiro #endif /* HASSETREUID || USESETEUID */
1722c2aa98e2SPeter Wemm
1723c2aa98e2SPeter Wemm if (tTd(27, 9))
1724da7d7b9cSGregory Neil Shapiro sm_dprintf("include: reset uid = %ld/%ld\n",
1725da7d7b9cSGregory Neil Shapiro (long) getuid(), (long) geteuid());
1726c2aa98e2SPeter Wemm
1727c2aa98e2SPeter Wemm if (rval == E_SM_OPENTIMEOUT)
172806f25ae9SGregory Neil Shapiro usrerr("451 4.4.1 open timeout on %s", fname);
1729c2aa98e2SPeter Wemm
1730c2aa98e2SPeter Wemm if (fp == NULL)
1731c2aa98e2SPeter Wemm return rval;
1732c2aa98e2SPeter Wemm
173340266059SGregory Neil Shapiro if (fstat(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), &st) < 0)
1734c2aa98e2SPeter Wemm {
1735c2aa98e2SPeter Wemm rval = errno;
1736c2aa98e2SPeter Wemm syserr("Cannot fstat %s!", fname);
173740266059SGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT);
1738c2aa98e2SPeter Wemm return rval;
1739c2aa98e2SPeter Wemm }
1740c2aa98e2SPeter Wemm
1741c2aa98e2SPeter Wemm /* if path was writable, check to avoid file giveaway tricks */
174240266059SGregory Neil Shapiro safechown = chownsafe(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), safedir);
1743c2aa98e2SPeter Wemm if (tTd(27, 6))
174440266059SGregory Neil Shapiro sm_dprintf("include: parent of %s is %s, chown is %ssafe\n",
174540266059SGregory Neil Shapiro fname, safedir ? "safe" : "dangerous",
1746c2aa98e2SPeter Wemm safechown ? "" : "un");
1747c2aa98e2SPeter Wemm
174806f25ae9SGregory Neil Shapiro /* if no controlling user or coming from an alias delivery */
174906f25ae9SGregory Neil Shapiro if (safechown &&
175006f25ae9SGregory Neil Shapiro (ca == NULL ||
175106f25ae9SGregory Neil Shapiro (ca->q_uid == DefUid && ca->q_gid == 0)))
1752c2aa98e2SPeter Wemm {
1753c2aa98e2SPeter Wemm ctladdr->q_uid = st.st_uid;
1754c2aa98e2SPeter Wemm ctladdr->q_gid = st.st_gid;
1755c2aa98e2SPeter Wemm ctladdr->q_flags |= QGOODUID;
1756c2aa98e2SPeter Wemm }
1757c2aa98e2SPeter Wemm if (ca != NULL && ca->q_uid == st.st_uid)
1758c2aa98e2SPeter Wemm {
1759c2aa98e2SPeter Wemm /* optimization -- avoid getpwuid if we already have info */
1760c2aa98e2SPeter Wemm ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL;
1761c2aa98e2SPeter Wemm ctladdr->q_ruser = ca->q_ruser;
1762c2aa98e2SPeter Wemm }
1763c2aa98e2SPeter Wemm else if (!forwarding)
1764c2aa98e2SPeter Wemm {
1765c2aa98e2SPeter Wemm register struct passwd *pw;
1766c2aa98e2SPeter Wemm
1767c2aa98e2SPeter Wemm pw = sm_getpwuid(st.st_uid);
1768c2aa98e2SPeter Wemm if (pw == NULL)
176906f25ae9SGregory Neil Shapiro {
177006f25ae9SGregory Neil Shapiro ctladdr->q_uid = st.st_uid;
1771c2aa98e2SPeter Wemm ctladdr->q_flags |= QBOGUSSHELL;
177206f25ae9SGregory Neil Shapiro }
1773c2aa98e2SPeter Wemm else
1774c2aa98e2SPeter Wemm {
1775c2aa98e2SPeter Wemm char *sh;
1776c2aa98e2SPeter Wemm
177740266059SGregory Neil Shapiro ctladdr->q_ruser = sm_rpool_strdup_x(e->e_rpool,
177840266059SGregory Neil Shapiro pw->pw_name);
1779c2aa98e2SPeter Wemm if (safechown)
1780c2aa98e2SPeter Wemm sh = pw->pw_shell;
1781c2aa98e2SPeter Wemm else
1782c2aa98e2SPeter Wemm sh = "/SENDMAIL/ANY/SHELL/";
1783c2aa98e2SPeter Wemm if (!usershellok(pw->pw_name, sh))
1784c2aa98e2SPeter Wemm {
178540266059SGregory Neil Shapiro if (LogLevel > 11)
1786c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id,
1787c2aa98e2SPeter Wemm "%s: user %s has bad shell %s, marked %s",
178840266059SGregory Neil Shapiro shortenstring(fname,
178940266059SGregory Neil Shapiro MAXSHORTSTR),
1790c2aa98e2SPeter Wemm pw->pw_name, sh,
1791c2aa98e2SPeter Wemm safechown ? "bogus" : "unsafe");
1792c2aa98e2SPeter Wemm if (safechown)
1793c2aa98e2SPeter Wemm ctladdr->q_flags |= QBOGUSSHELL;
1794c2aa98e2SPeter Wemm else
1795c2aa98e2SPeter Wemm ctladdr->q_flags |= QUNSAFEADDR;
1796c2aa98e2SPeter Wemm }
1797c2aa98e2SPeter Wemm }
1798c2aa98e2SPeter Wemm }
1799c2aa98e2SPeter Wemm
1800c2aa98e2SPeter Wemm if (bitset(EF_VRFYONLY, e->e_flags))
1801c2aa98e2SPeter Wemm {
1802c2aa98e2SPeter Wemm /* don't do any more now */
180306f25ae9SGregory Neil Shapiro ctladdr->q_state = QS_VERIFIED;
1804c2aa98e2SPeter Wemm e->e_nrcpts++;
180540266059SGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT);
1806c2aa98e2SPeter Wemm return rval;
1807c2aa98e2SPeter Wemm }
1808c2aa98e2SPeter Wemm
1809c2aa98e2SPeter Wemm /*
1810c2aa98e2SPeter Wemm ** Check to see if some bad guy can write this file
1811c2aa98e2SPeter Wemm **
1812c2aa98e2SPeter Wemm ** Group write checking could be more clever, e.g.,
1813c2aa98e2SPeter Wemm ** guessing as to which groups are actually safe ("sys"
1814c2aa98e2SPeter Wemm ** may be; "user" probably is not).
1815c2aa98e2SPeter Wemm */
1816c2aa98e2SPeter Wemm
1817c2aa98e2SPeter Wemm mode = S_IWOTH;
181806f25ae9SGregory Neil Shapiro if (!bitnset((forwarding ?
1819c2aa98e2SPeter Wemm DBS_GROUPWRITABLEFORWARDFILESAFE :
1820c2aa98e2SPeter Wemm DBS_GROUPWRITABLEINCLUDEFILESAFE),
1821c2aa98e2SPeter Wemm DontBlameSendmail))
1822c2aa98e2SPeter Wemm mode |= S_IWGRP;
1823c2aa98e2SPeter Wemm
1824c2aa98e2SPeter Wemm if (bitset(mode, st.st_mode))
1825c2aa98e2SPeter Wemm {
1826c2aa98e2SPeter Wemm if (tTd(27, 6))
182740266059SGregory Neil Shapiro sm_dprintf("include: %s is %s writable, marked unsafe\n",
1828c2aa98e2SPeter Wemm shortenstring(fname, MAXSHORTSTR),
182940266059SGregory Neil Shapiro bitset(S_IWOTH, st.st_mode) ? "world"
183040266059SGregory Neil Shapiro : "group");
183140266059SGregory Neil Shapiro if (LogLevel > 11)
1832c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id,
1833c2aa98e2SPeter Wemm "%s: %s writable %s file, marked unsafe",
1834c2aa98e2SPeter Wemm shortenstring(fname, MAXSHORTSTR),
1835c2aa98e2SPeter Wemm bitset(S_IWOTH, st.st_mode) ? "world" : "group",
1836c2aa98e2SPeter Wemm forwarding ? "forward" : ":include:");
1837c2aa98e2SPeter Wemm ctladdr->q_flags |= QUNSAFEADDR;
1838c2aa98e2SPeter Wemm }
1839c2aa98e2SPeter Wemm
1840c2aa98e2SPeter Wemm /* read the file -- each line is a comma-separated list. */
1841c2aa98e2SPeter Wemm FileName = fname;
1842c2aa98e2SPeter Wemm LineNumber = 0;
1843c2aa98e2SPeter Wemm ctladdr->q_flags &= ~QSELFREF;
1844c2aa98e2SPeter Wemm nincludes = 0;
1845552d4955SGregory Neil Shapiro while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0 &&
184640266059SGregory Neil Shapiro !maxreached)
1847c2aa98e2SPeter Wemm {
184840266059SGregory Neil Shapiro fixcrlf(buf, true);
1849c2aa98e2SPeter Wemm LineNumber++;
1850c2aa98e2SPeter Wemm if (buf[0] == '#' || buf[0] == '\0')
1851c2aa98e2SPeter Wemm continue;
1852c2aa98e2SPeter Wemm
1853c2aa98e2SPeter Wemm /* <sp>#@# introduces a comment anywhere */
1854c2aa98e2SPeter Wemm /* for Japanese character sets */
1855c2aa98e2SPeter Wemm for (p = buf; (p = strchr(++p, '#')) != NULL; )
1856c2aa98e2SPeter Wemm {
1857c2aa98e2SPeter Wemm if (p[1] == '@' && p[2] == '#' &&
1858c2aa98e2SPeter Wemm isascii(p[-1]) && isspace(p[-1]) &&
18595b0945b5SGregory Neil Shapiro (p[3] == '\0' || (SM_ISSPACE(p[3]))))
1860c2aa98e2SPeter Wemm {
186142e5d165SGregory Neil Shapiro --p;
186242e5d165SGregory Neil Shapiro while (p > buf && isascii(p[-1]) &&
186342e5d165SGregory Neil Shapiro isspace(p[-1]))
186442e5d165SGregory Neil Shapiro --p;
186542e5d165SGregory Neil Shapiro p[0] = '\0';
1866c2aa98e2SPeter Wemm break;
1867c2aa98e2SPeter Wemm }
1868c2aa98e2SPeter Wemm }
1869c2aa98e2SPeter Wemm if (buf[0] == '\0')
1870c2aa98e2SPeter Wemm continue;
1871c2aa98e2SPeter Wemm
1872c2aa98e2SPeter Wemm e->e_to = NULL;
1873c2aa98e2SPeter Wemm message("%s to %s",
1874c2aa98e2SPeter Wemm forwarding ? "forwarding" : "sending", buf);
187506f25ae9SGregory Neil Shapiro if (forwarding && LogLevel > 10)
1876c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id,
1877c2aa98e2SPeter Wemm "forward %.200s => %s",
1878c2aa98e2SPeter Wemm oldto, shortenstring(buf, MAXSHORTSTR));
1879c2aa98e2SPeter Wemm
1880c2aa98e2SPeter Wemm nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e);
188106f25ae9SGregory Neil Shapiro
188206f25ae9SGregory Neil Shapiro if (forwarding &&
188306f25ae9SGregory Neil Shapiro MaxForwardEntries > 0 &&
188406f25ae9SGregory Neil Shapiro nincludes >= MaxForwardEntries)
188506f25ae9SGregory Neil Shapiro {
188606f25ae9SGregory Neil Shapiro /* just stop reading and processing further entries */
188740266059SGregory Neil Shapiro #if 0
188840266059SGregory Neil Shapiro /* additional: (?) */
188906f25ae9SGregory Neil Shapiro ctladdr->q_state = QS_DONTSEND;
189040266059SGregory Neil Shapiro #endif /* 0 */
189140266059SGregory Neil Shapiro
189240266059SGregory Neil Shapiro syserr("Attempt to forward to more than %d addresses (in %s)!",
189306f25ae9SGregory Neil Shapiro MaxForwardEntries, fname);
189440266059SGregory Neil Shapiro maxreached = true;
189506f25ae9SGregory Neil Shapiro }
1896c2aa98e2SPeter Wemm }
1897c2aa98e2SPeter Wemm
189840266059SGregory Neil Shapiro if (sm_io_error(fp) && tTd(27, 3))
189940266059SGregory Neil Shapiro sm_dprintf("include: read error: %s\n", sm_errstring(errno));
1900c2aa98e2SPeter Wemm if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags))
1901c2aa98e2SPeter Wemm {
1902d0cef73dSGregory Neil Shapiro if (aliaslevel <= MaxAliasRecursion ||
1903d0cef73dSGregory Neil Shapiro ctladdr->q_state != QS_BADADDR)
1904d0cef73dSGregory Neil Shapiro {
1905d0cef73dSGregory Neil Shapiro ctladdr->q_state = QS_DONTSEND;
1906c2aa98e2SPeter Wemm if (tTd(27, 5))
1907c2aa98e2SPeter Wemm {
190840266059SGregory Neil Shapiro sm_dprintf("include: QS_DONTSEND ");
1909e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), ctladdr, false);
1910c2aa98e2SPeter Wemm }
1911d0cef73dSGregory Neil Shapiro }
1912c2aa98e2SPeter Wemm }
1913c2aa98e2SPeter Wemm
191440266059SGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT);
1915c2aa98e2SPeter Wemm FileName = oldfilename;
1916c2aa98e2SPeter Wemm LineNumber = oldlinenumber;
1917c2aa98e2SPeter Wemm e->e_to = oldto;
1918c2aa98e2SPeter Wemm return rval;
1919c2aa98e2SPeter Wemm }
1920c2aa98e2SPeter Wemm
1921c2aa98e2SPeter Wemm static void
includetimeout(ignore)1922b6bacd31SGregory Neil Shapiro includetimeout(ignore)
1923b6bacd31SGregory Neil Shapiro int ignore;
1924c2aa98e2SPeter Wemm {
19258774250cSGregory Neil Shapiro /*
19268774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
19278774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
19288774250cSGregory Neil Shapiro ** DOING.
19298774250cSGregory Neil Shapiro */
19308774250cSGregory Neil Shapiro
19318774250cSGregory Neil Shapiro errno = ETIMEDOUT;
1932c2aa98e2SPeter Wemm longjmp(CtxIncludeTimeout, 1);
1933c2aa98e2SPeter Wemm }
1934d0cef73dSGregory Neil Shapiro
193540266059SGregory Neil Shapiro /*
1936c2aa98e2SPeter Wemm ** SENDTOARGV -- send to an argument vector.
1937c2aa98e2SPeter Wemm **
1938c2aa98e2SPeter Wemm ** Parameters:
1939c2aa98e2SPeter Wemm ** argv -- argument vector to send to.
1940c2aa98e2SPeter Wemm ** e -- the current envelope.
1941c2aa98e2SPeter Wemm **
1942c2aa98e2SPeter Wemm ** Returns:
1943c2aa98e2SPeter Wemm ** none.
1944c2aa98e2SPeter Wemm **
1945c2aa98e2SPeter Wemm ** Side Effects:
1946c2aa98e2SPeter Wemm ** puts all addresses on the argument vector onto the
1947c2aa98e2SPeter Wemm ** send queue.
1948c2aa98e2SPeter Wemm */
1949c2aa98e2SPeter Wemm
1950c2aa98e2SPeter Wemm void
sendtoargv(argv,e)1951c2aa98e2SPeter Wemm sendtoargv(argv, e)
1952c2aa98e2SPeter Wemm register char **argv;
1953c2aa98e2SPeter Wemm register ENVELOPE *e;
1954c2aa98e2SPeter Wemm {
1955c2aa98e2SPeter Wemm register char *p;
1956c2aa98e2SPeter Wemm
19572fb4f839SGregory Neil Shapiro #if USE_EAI
19582fb4f839SGregory Neil Shapiro if (!e->e_smtputf8)
19592fb4f839SGregory Neil Shapiro {
19602fb4f839SGregory Neil Shapiro char **av;
19612fb4f839SGregory Neil Shapiro
19622fb4f839SGregory Neil Shapiro av = argv;
19632fb4f839SGregory Neil Shapiro while ((p = *av++) != NULL)
19642fb4f839SGregory Neil Shapiro {
19652fb4f839SGregory Neil Shapiro if (!addr_is_ascii(p))
19662fb4f839SGregory Neil Shapiro {
19672fb4f839SGregory Neil Shapiro e->e_smtputf8 = true;
19682fb4f839SGregory Neil Shapiro break;
19692fb4f839SGregory Neil Shapiro }
19702fb4f839SGregory Neil Shapiro }
19712fb4f839SGregory Neil Shapiro }
19722fb4f839SGregory Neil Shapiro #endif /* USE_EAI */
19732fb4f839SGregory Neil Shapiro
1974c2aa98e2SPeter Wemm while ((p = *argv++) != NULL)
19752fb4f839SGregory Neil Shapiro {
19762fb4f839SGregory Neil Shapiro #if USE_EAI
19772fb4f839SGregory Neil Shapiro if (e->e_smtputf8)
19782fb4f839SGregory Neil Shapiro {
19792fb4f839SGregory Neil Shapiro int len = 0;
19802fb4f839SGregory Neil Shapiro
1981*d39bd2c1SGregory Neil Shapiro if (!SMTP_UTF8 && !asciistr(p))
19822fb4f839SGregory Neil Shapiro {
19832fb4f839SGregory Neil Shapiro usrerr("non-ASCII recipient address %s requires SMTPUTF8",
19842fb4f839SGregory Neil Shapiro p);
19852fb4f839SGregory Neil Shapiro finis(false, true, EX_USAGE);
19862fb4f839SGregory Neil Shapiro }
19872fb4f839SGregory Neil Shapiro p = quote_internal_chars(p, NULL, &len, NULL);
19882fb4f839SGregory Neil Shapiro }
19892fb4f839SGregory Neil Shapiro #endif /* USE_EAI */
1990c2aa98e2SPeter Wemm (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e);
1991c2aa98e2SPeter Wemm }
19922fb4f839SGregory Neil Shapiro }
1993d0cef73dSGregory Neil Shapiro
199440266059SGregory Neil Shapiro /*
1995c2aa98e2SPeter Wemm ** GETCTLADDR -- get controlling address from an address header.
1996c2aa98e2SPeter Wemm **
1997c2aa98e2SPeter Wemm ** If none, get one corresponding to the effective userid.
1998c2aa98e2SPeter Wemm **
1999c2aa98e2SPeter Wemm ** Parameters:
2000c2aa98e2SPeter Wemm ** a -- the address to find the controller of.
2001c2aa98e2SPeter Wemm **
2002c2aa98e2SPeter Wemm ** Returns:
2003c2aa98e2SPeter Wemm ** the controlling address.
2004c2aa98e2SPeter Wemm */
2005c2aa98e2SPeter Wemm
2006c2aa98e2SPeter Wemm ADDRESS *
getctladdr(a)2007c2aa98e2SPeter Wemm getctladdr(a)
2008c2aa98e2SPeter Wemm register ADDRESS *a;
2009c2aa98e2SPeter Wemm {
2010c2aa98e2SPeter Wemm while (a != NULL && !bitset(QGOODUID, a->q_flags))
2011c2aa98e2SPeter Wemm a = a->q_alias;
201206f25ae9SGregory Neil Shapiro return a;
2013c2aa98e2SPeter Wemm }
2014d0cef73dSGregory Neil Shapiro
201540266059SGregory Neil Shapiro /*
2016c2aa98e2SPeter Wemm ** SELF_REFERENCE -- check to see if an address references itself
2017c2aa98e2SPeter Wemm **
2018c2aa98e2SPeter Wemm ** The check is done through a chain of aliases. If it is part of
2019c2aa98e2SPeter Wemm ** a loop, break the loop at the "best" address, that is, the one
2020c2aa98e2SPeter Wemm ** that exists as a real user.
2021c2aa98e2SPeter Wemm **
2022c2aa98e2SPeter Wemm ** This is to handle the case of:
2023c2aa98e2SPeter Wemm ** awc: Andrew.Chang
2024c2aa98e2SPeter Wemm ** Andrew.Chang: awc@mail.server
2025c2aa98e2SPeter Wemm ** which is a problem only on mail.server.
2026c2aa98e2SPeter Wemm **
2027c2aa98e2SPeter Wemm ** Parameters:
2028c2aa98e2SPeter Wemm ** a -- the address to check.
2029c2aa98e2SPeter Wemm **
2030c2aa98e2SPeter Wemm ** Returns:
2031c2aa98e2SPeter Wemm ** The address that should be retained.
2032c2aa98e2SPeter Wemm */
2033c2aa98e2SPeter Wemm
203406f25ae9SGregory Neil Shapiro static ADDRESS *
self_reference(a)203506f25ae9SGregory Neil Shapiro self_reference(a)
2036c2aa98e2SPeter Wemm ADDRESS *a;
2037c2aa98e2SPeter Wemm {
2038c2aa98e2SPeter Wemm ADDRESS *b; /* top entry in self ref loop */
2039c2aa98e2SPeter Wemm ADDRESS *c; /* entry that point to a real mail box */
2040c2aa98e2SPeter Wemm
2041c2aa98e2SPeter Wemm if (tTd(27, 1))
204240266059SGregory Neil Shapiro sm_dprintf("self_reference(%s)\n", a->q_paddr);
2043c2aa98e2SPeter Wemm
2044c2aa98e2SPeter Wemm for (b = a->q_alias; b != NULL; b = b->q_alias)
2045c2aa98e2SPeter Wemm {
2046c2aa98e2SPeter Wemm if (sameaddr(a, b))
2047c2aa98e2SPeter Wemm break;
2048c2aa98e2SPeter Wemm }
2049c2aa98e2SPeter Wemm
2050c2aa98e2SPeter Wemm if (b == NULL)
2051c2aa98e2SPeter Wemm {
2052c2aa98e2SPeter Wemm if (tTd(27, 1))
205340266059SGregory Neil Shapiro sm_dprintf("\t... no self ref\n");
2054c2aa98e2SPeter Wemm return NULL;
2055c2aa98e2SPeter Wemm }
2056c2aa98e2SPeter Wemm
2057c2aa98e2SPeter Wemm /*
2058c2aa98e2SPeter Wemm ** Pick the first address that resolved to a real mail box
205940266059SGregory Neil Shapiro ** i.e has a mbdb entry. The returned value will be marked
2060c2aa98e2SPeter Wemm ** QSELFREF in recipient(), which in turn will disable alias()
206106f25ae9SGregory Neil Shapiro ** from marking it as QS_IS_DEAD(), which mean it will be used
2062c2aa98e2SPeter Wemm ** as a deliverable address.
2063c2aa98e2SPeter Wemm **
2064c2aa98e2SPeter Wemm ** The 2 key thing to note here are:
2065c2aa98e2SPeter Wemm ** 1) we are in a recursive call sequence:
206640266059SGregory Neil Shapiro ** alias->sendtolist->recipient->alias
2067c2aa98e2SPeter Wemm ** 2) normally, when we return back to alias(), the address
206806f25ae9SGregory Neil Shapiro ** will be marked QS_EXPANDED, since alias() assumes the
2069c2aa98e2SPeter Wemm ** expanded form will be used instead of the current address.
2070c2aa98e2SPeter Wemm ** This behaviour is turned off if the address is marked
207140266059SGregory Neil Shapiro ** QSELFREF. We set QSELFREF when we return to recipient().
2072c2aa98e2SPeter Wemm */
2073c2aa98e2SPeter Wemm
2074c2aa98e2SPeter Wemm c = a;
2075c2aa98e2SPeter Wemm while (c != NULL)
2076c2aa98e2SPeter Wemm {
20772e43090eSPeter Wemm if (tTd(27, 10))
207840266059SGregory Neil Shapiro sm_dprintf(" %s", c->q_user);
2079c2aa98e2SPeter Wemm if (bitnset(M_HASPWENT, c->q_mailer->m_flags))
2080c2aa98e2SPeter Wemm {
208140266059SGregory Neil Shapiro SM_MBDB_T user;
208240266059SGregory Neil Shapiro
2083c2aa98e2SPeter Wemm if (tTd(27, 2))
208440266059SGregory Neil Shapiro sm_dprintf("\t... getpwnam(%s)... ", c->q_user);
208540266059SGregory Neil Shapiro if (sm_mbdb_lookup(c->q_user, &user) == EX_OK)
2086c2aa98e2SPeter Wemm {
2087c2aa98e2SPeter Wemm if (tTd(27, 2))
208840266059SGregory Neil Shapiro sm_dprintf("found\n");
2089c2aa98e2SPeter Wemm
2090c2aa98e2SPeter Wemm /* ought to cache results here */
2091c2aa98e2SPeter Wemm if (sameaddr(b, c))
2092c2aa98e2SPeter Wemm return b;
2093c2aa98e2SPeter Wemm else
2094c2aa98e2SPeter Wemm return c;
2095c2aa98e2SPeter Wemm }
2096c2aa98e2SPeter Wemm if (tTd(27, 2))
209740266059SGregory Neil Shapiro sm_dprintf("failed\n");
2098c2aa98e2SPeter Wemm }
20992e43090eSPeter Wemm else
21002e43090eSPeter Wemm {
21012e43090eSPeter Wemm /* if local delivery, compare usernames */
21022e43090eSPeter Wemm if (bitnset(M_LOCALMAILER, c->q_mailer->m_flags) &&
21032e43090eSPeter Wemm b->q_mailer == c->q_mailer)
21042e43090eSPeter Wemm {
21052e43090eSPeter Wemm if (tTd(27, 2))
210640266059SGregory Neil Shapiro sm_dprintf("\t... local match (%s)\n",
210706f25ae9SGregory Neil Shapiro c->q_user);
21082e43090eSPeter Wemm if (sameaddr(b, c))
21092e43090eSPeter Wemm return b;
21102e43090eSPeter Wemm else
21112e43090eSPeter Wemm return c;
21122e43090eSPeter Wemm }
21132e43090eSPeter Wemm }
21142e43090eSPeter Wemm if (tTd(27, 10))
211540266059SGregory Neil Shapiro sm_dprintf("\n");
2116c2aa98e2SPeter Wemm c = c->q_alias;
2117c2aa98e2SPeter Wemm }
2118c2aa98e2SPeter Wemm
2119c2aa98e2SPeter Wemm if (tTd(27, 1))
212040266059SGregory Neil Shapiro sm_dprintf("\t... cannot break loop for \"%s\"\n", a->q_paddr);
2121c2aa98e2SPeter Wemm
2122c2aa98e2SPeter Wemm return NULL;
2123c2aa98e2SPeter Wemm }
2124