1c2aa98e2SPeter Wemm /*
2*d39bd2c1SGregory Neil Shapiro * Copyright (c) 1998-2010, 2012, 2020-2023 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>
154e4196cbSGregory Neil Shapiro #include <sm/time.h>
1606f25ae9SGregory Neil Shapiro
174313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: deliver.c,v 8.1030 2013-11-22 20:51:55 ca Exp $")
18c2aa98e2SPeter Wemm
192fb4f839SGregory Neil Shapiro #include <sm/sendmail.h>
202fb4f839SGregory Neil Shapiro
21c2aa98e2SPeter Wemm #if HASSETUSERCONTEXT
22c2aa98e2SPeter Wemm # include <login_cap.h>
235b0945b5SGregory Neil Shapiro #endif
2406f25ae9SGregory Neil Shapiro
25605302a5SGregory Neil Shapiro #if NETINET || NETINET6
26605302a5SGregory Neil Shapiro # include <arpa/inet.h>
275b0945b5SGregory Neil Shapiro #endif
28605302a5SGregory Neil Shapiro
2940266059SGregory Neil Shapiro #if STARTTLS || SASL
3006f25ae9SGregory Neil Shapiro # include "sfsasl.h"
315b0945b5SGregory Neil Shapiro # include "tls.h"
325b0945b5SGregory Neil Shapiro #endif
3306f25ae9SGregory Neil Shapiro
34*d39bd2c1SGregory Neil Shapiro #if !_FFR_DMTRIGGER
3506f25ae9SGregory Neil Shapiro static int deliver __P((ENVELOPE *, ADDRESS *));
36*d39bd2c1SGregory Neil Shapiro #endif
3706f25ae9SGregory Neil Shapiro static void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int));
38b6bacd31SGregory Neil Shapiro static void mailfiletimeout __P((int));
39b6bacd31SGregory Neil Shapiro static void endwaittimeout __P((int));
40*d39bd2c1SGregory Neil Shapiro static int parse_hostsignature __P((char *, char **, MAILER *
41*d39bd2c1SGregory Neil Shapiro #if DANE
42*d39bd2c1SGregory Neil Shapiro , BITMAP256
43*d39bd2c1SGregory Neil Shapiro #endif
44*d39bd2c1SGregory Neil Shapiro ));
4506f25ae9SGregory Neil Shapiro static void sendenvelope __P((ENVELOPE *, int));
4640266059SGregory Neil Shapiro static int coloncmp __P((const char *, const char *));
47c2aa98e2SPeter Wemm
48*d39bd2c1SGregory Neil Shapiro
4906f25ae9SGregory Neil Shapiro #if STARTTLS
50ba00ec3dSGregory Neil Shapiro # include <openssl/err.h>
515b0945b5SGregory Neil Shapiro # if DANE
52*d39bd2c1SGregory Neil Shapiro static int starttls __P((MAILER *, MCI *, ENVELOPE *, bool, dane_vrfy_ctx_P));
53*d39bd2c1SGregory Neil Shapiro
54*d39bd2c1SGregory Neil Shapiro # define MXADS_ISSET(mxads, i) (0 != bitnset(bitidx(i), mxads))
55*d39bd2c1SGregory Neil Shapiro # define MXADS_SET(mxads, i) setbitn(bitidx(i), mxads)
56*d39bd2c1SGregory Neil Shapiro
57*d39bd2c1SGregory Neil Shapiro /* use "marks" in hostsignature for "had ad"? (WIP) */
58*d39bd2c1SGregory Neil Shapiro # ifndef HSMARKS
59*d39bd2c1SGregory Neil Shapiro # define HSMARKS 1
605b0945b5SGregory Neil Shapiro # endif
61*d39bd2c1SGregory Neil Shapiro # if HSMARKS
62*d39bd2c1SGregory Neil Shapiro # define HSM_AD '+' /* mark for hostsignature: ad flag */
63*d39bd2c1SGregory Neil Shapiro # define DANE_SEC(dane) (DANE_SECURE == DANEMODE((dane)))
64*d39bd2c1SGregory Neil Shapiro # endif
65*d39bd2c1SGregory Neil Shapiro # else /* DANE */
66*d39bd2c1SGregory Neil Shapiro static int starttls __P((MAILER *, MCI *, ENVELOPE *, bool));
67*d39bd2c1SGregory Neil Shapiro # define MXADS_ISSET(mxads, i) 0
68*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
6940266059SGregory Neil Shapiro static int endtlsclt __P((MCI *));
7006f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
7140266059SGregory Neil Shapiro #if STARTTLS || SASL
7240266059SGregory Neil Shapiro static bool iscltflgset __P((ENVELOPE *, int));
735b0945b5SGregory Neil Shapiro #endif
745b0945b5SGregory Neil Shapiro
75*d39bd2c1SGregory Neil Shapiro #define SEP_MXHOSTS(endp, sep) \
76*d39bd2c1SGregory Neil Shapiro if (endp != NULL) \
77*d39bd2c1SGregory Neil Shapiro { \
78*d39bd2c1SGregory Neil Shapiro sep = *endp; \
79*d39bd2c1SGregory Neil Shapiro *endp = '\0'; \
80*d39bd2c1SGregory Neil Shapiro }
81*d39bd2c1SGregory Neil Shapiro
82*d39bd2c1SGregory Neil Shapiro #if NETINET6
83*d39bd2c1SGregory Neil Shapiro # define FIX_MXHOSTS(hp, endp, sep) \
84*d39bd2c1SGregory Neil Shapiro do { \
85*d39bd2c1SGregory Neil Shapiro if (*hp == '[') \
86*d39bd2c1SGregory Neil Shapiro { \
87*d39bd2c1SGregory Neil Shapiro endp = strchr(hp + 1, ']'); \
88*d39bd2c1SGregory Neil Shapiro if (endp != NULL) \
89*d39bd2c1SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); \
90*d39bd2c1SGregory Neil Shapiro } \
91*d39bd2c1SGregory Neil Shapiro else \
92*d39bd2c1SGregory Neil Shapiro endp = strpbrk(hp, ":,"); \
93*d39bd2c1SGregory Neil Shapiro SEP_MXHOSTS(endp, sep); \
94*d39bd2c1SGregory Neil Shapiro } while (0)
95*d39bd2c1SGregory Neil Shapiro #else /* NETINET6 */
96*d39bd2c1SGregory Neil Shapiro # define FIX_MXHOSTS(hp, endp, sep) \
97*d39bd2c1SGregory Neil Shapiro do { \
98*d39bd2c1SGregory Neil Shapiro endp = strpbrk(hp, ":,"); \
99*d39bd2c1SGregory Neil Shapiro SEP_MXHOSTS(endp, sep); \
100*d39bd2c1SGregory Neil Shapiro } while (0)
101*d39bd2c1SGregory Neil Shapiro #endif /* NETINET6 */
102*d39bd2c1SGregory Neil Shapiro
1035b0945b5SGregory Neil Shapiro #if _FFR_OCC
1045b0945b5SGregory Neil Shapiro # include <ratectrl.h>
1055b0945b5SGregory Neil Shapiro #endif
106c2aa98e2SPeter Wemm
1072fb4f839SGregory Neil Shapiro #define ESCNULLMXRCPT "5.1.10"
1082fb4f839SGregory Neil Shapiro #define ERRNULLMX "556 Host does not accept mail: MX 0 ."
1092fb4f839SGregory Neil Shapiro
110*d39bd2c1SGregory Neil Shapiro #if _FFR_LOG_FAILOVER
111*d39bd2c1SGregory Neil Shapiro /*
112*d39bd2c1SGregory Neil Shapiro ** These are not very useful to show the protocol stage,
113*d39bd2c1SGregory Neil Shapiro ** but it's better than nothing right now.
114*d39bd2c1SGregory Neil Shapiro ** XXX the actual values must be 0..N, otherwise a lookup
115*d39bd2c1SGregory Neil Shapiro ** table must be used!
116*d39bd2c1SGregory Neil Shapiro */
117*d39bd2c1SGregory Neil Shapiro
118*d39bd2c1SGregory Neil Shapiro static char *mcis[] =
119*d39bd2c1SGregory Neil Shapiro {
120*d39bd2c1SGregory Neil Shapiro "CLOSED",
121*d39bd2c1SGregory Neil Shapiro "GREET",
122*d39bd2c1SGregory Neil Shapiro "OPEN",
123*d39bd2c1SGregory Neil Shapiro "MAIL",
124*d39bd2c1SGregory Neil Shapiro "RCPT",
125*d39bd2c1SGregory Neil Shapiro "DATA",
126*d39bd2c1SGregory Neil Shapiro "QUITING",
127*d39bd2c1SGregory Neil Shapiro "SSD",
128*d39bd2c1SGregory Neil Shapiro "ERROR",
129*d39bd2c1SGregory Neil Shapiro NULL
130*d39bd2c1SGregory Neil Shapiro };
131*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_LOG_FAILOVER */
132*d39bd2c1SGregory Neil Shapiro
133*d39bd2c1SGregory Neil Shapiro #if _FFR_LOG_STAGE
134*d39bd2c1SGregory Neil Shapiro static char *xs_states[] =
135*d39bd2c1SGregory Neil Shapiro {
136*d39bd2c1SGregory Neil Shapiro "none",
137*d39bd2c1SGregory Neil Shapiro "STARTTLS",
138*d39bd2c1SGregory Neil Shapiro "AUTH",
139*d39bd2c1SGregory Neil Shapiro "GREET",
140*d39bd2c1SGregory Neil Shapiro "EHLO",
141*d39bd2c1SGregory Neil Shapiro "MAIL",
142*d39bd2c1SGregory Neil Shapiro "RCPT",
143*d39bd2c1SGregory Neil Shapiro "DATA",
144*d39bd2c1SGregory Neil Shapiro "EOM",
145*d39bd2c1SGregory Neil Shapiro "DATA2",
146*d39bd2c1SGregory Neil Shapiro "QUIT",
147*d39bd2c1SGregory Neil Shapiro NULL
148*d39bd2c1SGregory Neil Shapiro };
149*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_LOG_STAGE */
150*d39bd2c1SGregory Neil Shapiro
151c2aa98e2SPeter Wemm /*
152c2aa98e2SPeter Wemm ** SENDALL -- actually send all the messages.
153c2aa98e2SPeter Wemm **
154c2aa98e2SPeter Wemm ** Parameters:
155c2aa98e2SPeter Wemm ** e -- the envelope to send.
156c2aa98e2SPeter Wemm ** mode -- the delivery mode to use. If SM_DEFAULT, use
157c2aa98e2SPeter Wemm ** the current e->e_sendmode.
158c2aa98e2SPeter Wemm **
159c2aa98e2SPeter Wemm ** Returns:
160c2aa98e2SPeter Wemm ** none.
161c2aa98e2SPeter Wemm **
162c2aa98e2SPeter Wemm ** Side Effects:
163c2aa98e2SPeter Wemm ** Scans the send lists and sends everything it finds.
164c2aa98e2SPeter Wemm ** Delivers any appropriate error messages.
165c2aa98e2SPeter Wemm ** If we are running in a non-interactive mode, takes the
166c2aa98e2SPeter Wemm ** appropriate action.
167c2aa98e2SPeter Wemm */
168c2aa98e2SPeter Wemm
169c2aa98e2SPeter Wemm void
sendall(e,mode)170c2aa98e2SPeter Wemm sendall(e, mode)
171c2aa98e2SPeter Wemm ENVELOPE *e;
172c2aa98e2SPeter Wemm int mode;
173c2aa98e2SPeter Wemm {
174c2aa98e2SPeter Wemm register ADDRESS *q;
175c2aa98e2SPeter Wemm char *owner;
176c2aa98e2SPeter Wemm int otherowners;
17706f25ae9SGregory Neil Shapiro int save_errno;
178c2aa98e2SPeter Wemm register ENVELOPE *ee;
179c2aa98e2SPeter Wemm ENVELOPE *splitenv = NULL;
180c2aa98e2SPeter Wemm int oldverbose = Verbose;
18140266059SGregory Neil Shapiro bool somedeliveries = false, expensive = false;
182c2aa98e2SPeter Wemm pid_t pid;
183c2aa98e2SPeter Wemm
184c2aa98e2SPeter Wemm /*
185c2aa98e2SPeter Wemm ** If this message is to be discarded, don't bother sending
186c2aa98e2SPeter Wemm ** the message at all.
187c2aa98e2SPeter Wemm */
188c2aa98e2SPeter Wemm
189c2aa98e2SPeter Wemm if (bitset(EF_DISCARD, e->e_flags))
190c2aa98e2SPeter Wemm {
191c2aa98e2SPeter Wemm if (tTd(13, 1))
19240266059SGregory Neil Shapiro sm_dprintf("sendall: discarding id %s\n", e->e_id);
193c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE;
19440266059SGregory Neil Shapiro if (LogLevel > 9)
19540266059SGregory Neil Shapiro logundelrcpts(e, "discarded", 9, true);
19640266059SGregory Neil Shapiro else if (LogLevel > 4)
197c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "discarded");
19840266059SGregory Neil Shapiro markstats(e, NULL, STATS_REJECT);
199c2aa98e2SPeter Wemm return;
200c2aa98e2SPeter Wemm }
201c2aa98e2SPeter Wemm
202c2aa98e2SPeter Wemm /*
203c2aa98e2SPeter Wemm ** If we have had global, fatal errors, don't bother sending
204c2aa98e2SPeter Wemm ** the message at all if we are in SMTP mode. Local errors
205c2aa98e2SPeter Wemm ** (e.g., a single address failing) will still cause the other
206c2aa98e2SPeter Wemm ** addresses to be sent.
207c2aa98e2SPeter Wemm */
208c2aa98e2SPeter Wemm
209c2aa98e2SPeter Wemm if (bitset(EF_FATALERRS, e->e_flags) &&
210c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON))
211c2aa98e2SPeter Wemm {
212c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE;
213c2aa98e2SPeter Wemm return;
214c2aa98e2SPeter Wemm }
215c2aa98e2SPeter Wemm
216c2aa98e2SPeter Wemm /* determine actual delivery mode */
217c2aa98e2SPeter Wemm if (mode == SM_DEFAULT)
218c2aa98e2SPeter Wemm {
219c2aa98e2SPeter Wemm mode = e->e_sendmode;
220c2aa98e2SPeter Wemm if (mode != SM_VERIFY && mode != SM_DEFER &&
221c2aa98e2SPeter Wemm shouldqueue(e->e_msgpriority, e->e_ctime))
222c2aa98e2SPeter Wemm mode = SM_QUEUE;
223c2aa98e2SPeter Wemm }
224c2aa98e2SPeter Wemm
225c2aa98e2SPeter Wemm if (tTd(13, 1))
226c2aa98e2SPeter Wemm {
22740266059SGregory Neil Shapiro sm_dprintf("\n===== SENDALL: mode %c, id %s, e_from ",
228c2aa98e2SPeter Wemm mode, e->e_id);
229e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), &e->e_from, false);
23040266059SGregory Neil Shapiro sm_dprintf("\te_flags = ");
231c2aa98e2SPeter Wemm printenvflags(e);
23240266059SGregory Neil Shapiro sm_dprintf("sendqueue:\n");
233e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), e->e_sendqueue, true);
234c2aa98e2SPeter Wemm }
235c2aa98e2SPeter Wemm
236c2aa98e2SPeter Wemm /*
237c2aa98e2SPeter Wemm ** Do any preprocessing necessary for the mode we are running.
238c2aa98e2SPeter Wemm ** Check to make sure the hop count is reasonable.
239c2aa98e2SPeter Wemm ** Delete sends to the sender in mailing lists.
240c2aa98e2SPeter Wemm */
241c2aa98e2SPeter Wemm
242c2aa98e2SPeter Wemm CurEnv = e;
243c2aa98e2SPeter Wemm if (tTd(62, 1))
244c2aa98e2SPeter Wemm checkfds(NULL);
245c2aa98e2SPeter Wemm
246c2aa98e2SPeter Wemm if (e->e_hopcount > MaxHopCount)
247c2aa98e2SPeter Wemm {
2488774250cSGregory Neil Shapiro char *recip;
2498774250cSGregory Neil Shapiro
2508774250cSGregory Neil Shapiro if (e->e_sendqueue != NULL &&
2518774250cSGregory Neil Shapiro e->e_sendqueue->q_paddr != NULL)
2528774250cSGregory Neil Shapiro recip = e->e_sendqueue->q_paddr;
2538774250cSGregory Neil Shapiro else
2548774250cSGregory Neil Shapiro recip = "(nobody)";
2558774250cSGregory Neil Shapiro
256c2aa98e2SPeter Wemm errno = 0;
2572fb4f839SGregory Neil Shapiro queueup(e, WILL_BE_QUEUED(mode) ? QUP_FL_ANNOUNCE : QUP_FL_NONE);
258c2aa98e2SPeter Wemm e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
25906f25ae9SGregory Neil Shapiro ExitStat = EX_UNAVAILABLE;
2608774250cSGregory Neil Shapiro syserr("554 5.4.6 Too many hops %d (%d max): from %s via %s, to %s",
261c2aa98e2SPeter Wemm e->e_hopcount, MaxHopCount, e->e_from.q_paddr,
262c2aa98e2SPeter Wemm RealHostName == NULL ? "localhost" : RealHostName,
2638774250cSGregory Neil Shapiro recip);
26406f25ae9SGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next)
26506f25ae9SGregory Neil Shapiro {
26606f25ae9SGregory Neil Shapiro if (QS_IS_DEAD(q->q_state))
26706f25ae9SGregory Neil Shapiro continue;
26806f25ae9SGregory Neil Shapiro q->q_state = QS_BADADDR;
26906f25ae9SGregory Neil Shapiro q->q_status = "5.4.6";
2708774250cSGregory Neil Shapiro q->q_rstatus = "554 5.4.6 Too many hops";
27106f25ae9SGregory Neil Shapiro }
272c2aa98e2SPeter Wemm return;
273c2aa98e2SPeter Wemm }
274c2aa98e2SPeter Wemm
275c2aa98e2SPeter Wemm /*
276c2aa98e2SPeter Wemm ** Do sender deletion.
277c2aa98e2SPeter Wemm **
27806f25ae9SGregory Neil Shapiro ** If the sender should be queued up, skip this.
279c2aa98e2SPeter Wemm ** This can happen if the name server is hosed when you
280c2aa98e2SPeter Wemm ** are trying to send mail. The result is that the sender
281c2aa98e2SPeter Wemm ** is instantiated in the queue as a recipient.
282c2aa98e2SPeter Wemm */
283c2aa98e2SPeter Wemm
284c2aa98e2SPeter Wemm if (!bitset(EF_METOO, e->e_flags) &&
28506f25ae9SGregory Neil Shapiro !QS_IS_QUEUEUP(e->e_from.q_state))
286c2aa98e2SPeter Wemm {
287c2aa98e2SPeter Wemm if (tTd(13, 5))
288c2aa98e2SPeter Wemm {
28940266059SGregory Neil Shapiro sm_dprintf("sendall: QS_SENDER ");
290e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), &e->e_from, false);
291c2aa98e2SPeter Wemm }
29206f25ae9SGregory Neil Shapiro e->e_from.q_state = QS_SENDER;
293c2aa98e2SPeter Wemm (void) recipient(&e->e_from, &e->e_sendqueue, 0, e);
294c2aa98e2SPeter Wemm }
295c2aa98e2SPeter Wemm
296c2aa98e2SPeter Wemm /*
297c2aa98e2SPeter Wemm ** Handle alias owners.
298c2aa98e2SPeter Wemm **
299c2aa98e2SPeter Wemm ** We scan up the q_alias chain looking for owners.
300c2aa98e2SPeter Wemm ** We discard owners that are the same as the return path.
301c2aa98e2SPeter Wemm */
302c2aa98e2SPeter Wemm
303c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next)
304c2aa98e2SPeter Wemm {
305c2aa98e2SPeter Wemm register struct address *a;
306c2aa98e2SPeter Wemm
307c2aa98e2SPeter Wemm for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias)
308c2aa98e2SPeter Wemm continue;
309c2aa98e2SPeter Wemm if (a != NULL)
310c2aa98e2SPeter Wemm q->q_owner = a->q_owner;
311c2aa98e2SPeter Wemm
312c2aa98e2SPeter Wemm if (q->q_owner != NULL &&
31306f25ae9SGregory Neil Shapiro !QS_IS_DEAD(q->q_state) &&
314c2aa98e2SPeter Wemm strcmp(q->q_owner, e->e_from.q_paddr) == 0)
315c2aa98e2SPeter Wemm q->q_owner = NULL;
316c2aa98e2SPeter Wemm }
317c2aa98e2SPeter Wemm
318c2aa98e2SPeter Wemm if (tTd(13, 25))
319c2aa98e2SPeter Wemm {
32040266059SGregory Neil Shapiro sm_dprintf("\nAfter first owner pass, sendq =\n");
321e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), e->e_sendqueue, true);
322c2aa98e2SPeter Wemm }
323c2aa98e2SPeter Wemm
324c2aa98e2SPeter Wemm owner = "";
325c2aa98e2SPeter Wemm otherowners = 1;
326c2aa98e2SPeter Wemm while (owner != NULL && otherowners > 0)
327c2aa98e2SPeter Wemm {
328c2aa98e2SPeter Wemm if (tTd(13, 28))
32940266059SGregory Neil Shapiro sm_dprintf("owner = \"%s\", otherowners = %d\n",
330c2aa98e2SPeter Wemm owner, otherowners);
331c2aa98e2SPeter Wemm owner = NULL;
332c2aa98e2SPeter Wemm otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0;
333c2aa98e2SPeter Wemm
334c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next)
335c2aa98e2SPeter Wemm {
336c2aa98e2SPeter Wemm if (tTd(13, 30))
337c2aa98e2SPeter Wemm {
33840266059SGregory Neil Shapiro sm_dprintf("Checking ");
339e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), q, false);
340c2aa98e2SPeter Wemm }
34106f25ae9SGregory Neil Shapiro if (QS_IS_DEAD(q->q_state))
342c2aa98e2SPeter Wemm {
343c2aa98e2SPeter Wemm if (tTd(13, 30))
34440266059SGregory Neil Shapiro sm_dprintf(" ... QS_IS_DEAD\n");
345c2aa98e2SPeter Wemm continue;
346c2aa98e2SPeter Wemm }
347c2aa98e2SPeter Wemm if (tTd(13, 29) && !tTd(13, 30))
348c2aa98e2SPeter Wemm {
34940266059SGregory Neil Shapiro sm_dprintf("Checking ");
350e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), q, false);
351c2aa98e2SPeter Wemm }
352c2aa98e2SPeter Wemm
353c2aa98e2SPeter Wemm if (q->q_owner != NULL)
354c2aa98e2SPeter Wemm {
355c2aa98e2SPeter Wemm if (owner == NULL)
356c2aa98e2SPeter Wemm {
357c2aa98e2SPeter Wemm if (tTd(13, 40))
35840266059SGregory Neil Shapiro sm_dprintf(" ... First owner = \"%s\"\n",
359c2aa98e2SPeter Wemm q->q_owner);
360c2aa98e2SPeter Wemm owner = q->q_owner;
361c2aa98e2SPeter Wemm }
362c2aa98e2SPeter Wemm else if (owner != q->q_owner)
363c2aa98e2SPeter Wemm {
364c2aa98e2SPeter Wemm if (strcmp(owner, q->q_owner) == 0)
365c2aa98e2SPeter Wemm {
366c2aa98e2SPeter Wemm if (tTd(13, 40))
36740266059SGregory Neil Shapiro sm_dprintf(" ... Same owner = \"%s\"\n",
368c2aa98e2SPeter Wemm owner);
369c2aa98e2SPeter Wemm
370c2aa98e2SPeter Wemm /* make future comparisons cheap */
371c2aa98e2SPeter Wemm q->q_owner = owner;
372c2aa98e2SPeter Wemm }
373c2aa98e2SPeter Wemm else
374c2aa98e2SPeter Wemm {
375c2aa98e2SPeter Wemm if (tTd(13, 40))
37640266059SGregory Neil Shapiro sm_dprintf(" ... Another owner \"%s\"\n",
377c2aa98e2SPeter Wemm q->q_owner);
378c2aa98e2SPeter Wemm otherowners++;
379c2aa98e2SPeter Wemm }
380c2aa98e2SPeter Wemm owner = q->q_owner;
381c2aa98e2SPeter Wemm }
382c2aa98e2SPeter Wemm else if (tTd(13, 40))
38340266059SGregory Neil Shapiro sm_dprintf(" ... Same owner = \"%s\"\n",
384c2aa98e2SPeter Wemm owner);
385c2aa98e2SPeter Wemm }
386c2aa98e2SPeter Wemm else
387c2aa98e2SPeter Wemm {
388c2aa98e2SPeter Wemm if (tTd(13, 40))
38940266059SGregory Neil Shapiro sm_dprintf(" ... Null owner\n");
390c2aa98e2SPeter Wemm otherowners++;
391c2aa98e2SPeter Wemm }
392c2aa98e2SPeter Wemm
39306f25ae9SGregory Neil Shapiro if (QS_IS_BADADDR(q->q_state))
39406f25ae9SGregory Neil Shapiro {
39506f25ae9SGregory Neil Shapiro if (tTd(13, 30))
39640266059SGregory Neil Shapiro sm_dprintf(" ... QS_IS_BADADDR\n");
39706f25ae9SGregory Neil Shapiro continue;
39806f25ae9SGregory Neil Shapiro }
39906f25ae9SGregory Neil Shapiro
40006f25ae9SGregory Neil Shapiro if (QS_IS_QUEUEUP(q->q_state))
40106f25ae9SGregory Neil Shapiro {
40206f25ae9SGregory Neil Shapiro MAILER *m = q->q_mailer;
40306f25ae9SGregory Neil Shapiro
40406f25ae9SGregory Neil Shapiro /*
40506f25ae9SGregory Neil Shapiro ** If we have temporary address failures
40606f25ae9SGregory Neil Shapiro ** (e.g., dns failure) and a fallback MX is
40706f25ae9SGregory Neil Shapiro ** set, send directly to the fallback MX host.
40806f25ae9SGregory Neil Shapiro */
40906f25ae9SGregory Neil Shapiro
410e92d3f3fSGregory Neil Shapiro if (FallbackMX != NULL &&
411e92d3f3fSGregory Neil Shapiro !wordinclass(FallbackMX, 'w') &&
41206f25ae9SGregory Neil Shapiro mode != SM_VERIFY &&
41340266059SGregory Neil Shapiro !bitnset(M_NOMX, m->m_flags) &&
41440266059SGregory Neil Shapiro strcmp(m->m_mailer, "[IPC]") == 0 &&
41506f25ae9SGregory Neil Shapiro m->m_argv[0] != NULL &&
41640266059SGregory Neil Shapiro strcmp(m->m_argv[0], "TCP") == 0)
41706f25ae9SGregory Neil Shapiro {
41806f25ae9SGregory Neil Shapiro int len;
41906f25ae9SGregory Neil Shapiro char *p;
42006f25ae9SGregory Neil Shapiro
42106f25ae9SGregory Neil Shapiro if (tTd(13, 30))
422e92d3f3fSGregory Neil Shapiro sm_dprintf(" ... FallbackMX\n");
42306f25ae9SGregory Neil Shapiro
424e92d3f3fSGregory Neil Shapiro len = strlen(FallbackMX) + 1;
42540266059SGregory Neil Shapiro p = sm_rpool_malloc_x(e->e_rpool, len);
426e92d3f3fSGregory Neil Shapiro (void) sm_strlcpy(p, FallbackMX, len);
42706f25ae9SGregory Neil Shapiro q->q_state = QS_OK;
42806f25ae9SGregory Neil Shapiro q->q_host = p;
42906f25ae9SGregory Neil Shapiro }
43006f25ae9SGregory Neil Shapiro else
43106f25ae9SGregory Neil Shapiro {
43206f25ae9SGregory Neil Shapiro if (tTd(13, 30))
43340266059SGregory Neil Shapiro sm_dprintf(" ... QS_IS_QUEUEUP\n");
43406f25ae9SGregory Neil Shapiro continue;
43506f25ae9SGregory Neil Shapiro }
43606f25ae9SGregory Neil Shapiro }
43706f25ae9SGregory Neil Shapiro
438c2aa98e2SPeter Wemm /*
439c2aa98e2SPeter Wemm ** If this mailer is expensive, and if we don't
440c2aa98e2SPeter Wemm ** want to make connections now, just mark these
441c2aa98e2SPeter Wemm ** addresses and return. This is useful if we
442c2aa98e2SPeter Wemm ** want to batch connections to reduce load. This
443c2aa98e2SPeter Wemm ** will cause the messages to be queued up, and a
444c2aa98e2SPeter Wemm ** daemon will come along to send the messages later.
445c2aa98e2SPeter Wemm */
446c2aa98e2SPeter Wemm
447c2aa98e2SPeter Wemm if (NoConnect && !Verbose &&
448c2aa98e2SPeter Wemm bitnset(M_EXPENSIVE, q->q_mailer->m_flags))
449c2aa98e2SPeter Wemm {
450c2aa98e2SPeter Wemm if (tTd(13, 30))
45140266059SGregory Neil Shapiro sm_dprintf(" ... expensive\n");
45206f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP;
45340266059SGregory Neil Shapiro expensive = true;
45406f25ae9SGregory Neil Shapiro }
45506f25ae9SGregory Neil Shapiro else if (bitnset(M_HOLD, q->q_mailer->m_flags) &&
45606f25ae9SGregory Neil Shapiro QueueLimitId == NULL &&
45706f25ae9SGregory Neil Shapiro QueueLimitSender == NULL &&
45806f25ae9SGregory Neil Shapiro QueueLimitRecipient == NULL)
45906f25ae9SGregory Neil Shapiro {
46006f25ae9SGregory Neil Shapiro if (tTd(13, 30))
46140266059SGregory Neil Shapiro sm_dprintf(" ... hold\n");
46206f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP;
46340266059SGregory Neil Shapiro expensive = true;
464c2aa98e2SPeter Wemm }
46540266059SGregory Neil Shapiro else if (QueueMode != QM_QUARANTINE &&
46640266059SGregory Neil Shapiro e->e_quarmsg != NULL)
46740266059SGregory Neil Shapiro {
46840266059SGregory Neil Shapiro if (tTd(13, 30))
46940266059SGregory Neil Shapiro sm_dprintf(" ... quarantine: %s\n",
47040266059SGregory Neil Shapiro e->e_quarmsg);
47140266059SGregory Neil Shapiro q->q_state = QS_QUEUEUP;
47240266059SGregory Neil Shapiro expensive = true;
47340266059SGregory Neil Shapiro }
474c2aa98e2SPeter Wemm else
475c2aa98e2SPeter Wemm {
476c2aa98e2SPeter Wemm if (tTd(13, 30))
47740266059SGregory Neil Shapiro sm_dprintf(" ... deliverable\n");
47840266059SGregory Neil Shapiro somedeliveries = true;
479c2aa98e2SPeter Wemm }
480c2aa98e2SPeter Wemm }
481c2aa98e2SPeter Wemm
482c2aa98e2SPeter Wemm if (owner != NULL && otherowners > 0)
483c2aa98e2SPeter Wemm {
484c2aa98e2SPeter Wemm /*
485c2aa98e2SPeter Wemm ** Split this envelope into two.
486c2aa98e2SPeter Wemm */
487c2aa98e2SPeter Wemm
48840266059SGregory Neil Shapiro ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool,
489d0cef73dSGregory Neil Shapiro sizeof(*ee));
49040266059SGregory Neil Shapiro STRUCTCOPY(*e, *ee);
49106f25ae9SGregory Neil Shapiro ee->e_message = NULL;
492c2aa98e2SPeter Wemm ee->e_id = NULL;
49306f25ae9SGregory Neil Shapiro assign_queueid(ee);
494c2aa98e2SPeter Wemm
495c2aa98e2SPeter Wemm if (tTd(13, 1))
49640266059SGregory Neil Shapiro sm_dprintf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n",
49740266059SGregory Neil Shapiro e->e_id, ee->e_id, owner,
49840266059SGregory Neil Shapiro otherowners);
499c2aa98e2SPeter Wemm
50040266059SGregory Neil Shapiro ee->e_header = copyheader(e->e_header, ee->e_rpool);
50140266059SGregory Neil Shapiro ee->e_sendqueue = copyqueue(e->e_sendqueue,
50240266059SGregory Neil Shapiro ee->e_rpool);
50340266059SGregory Neil Shapiro ee->e_errorqueue = copyqueue(e->e_errorqueue,
50440266059SGregory Neil Shapiro ee->e_rpool);
505c2aa98e2SPeter Wemm ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM);
506c2aa98e2SPeter Wemm ee->e_flags |= EF_NORECEIPT;
50740266059SGregory Neil Shapiro setsender(owner, ee, NULL, '\0', true);
508c2aa98e2SPeter Wemm if (tTd(13, 5))
509c2aa98e2SPeter Wemm {
51040266059SGregory Neil Shapiro sm_dprintf("sendall(split): QS_SENDER ");
511e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), &ee->e_from, false);
512c2aa98e2SPeter Wemm }
51306f25ae9SGregory Neil Shapiro ee->e_from.q_state = QS_SENDER;
514c2aa98e2SPeter Wemm ee->e_dfp = NULL;
51506f25ae9SGregory Neil Shapiro ee->e_lockfp = NULL;
516c2aa98e2SPeter Wemm ee->e_xfp = NULL;
51740266059SGregory Neil Shapiro ee->e_qgrp = e->e_qgrp;
51840266059SGregory Neil Shapiro ee->e_qdir = e->e_qdir;
519c2aa98e2SPeter Wemm ee->e_errormode = EM_MAIL;
520c2aa98e2SPeter Wemm ee->e_sibling = splitenv;
52106f25ae9SGregory Neil Shapiro ee->e_statmsg = NULL;
52240266059SGregory Neil Shapiro if (e->e_quarmsg != NULL)
52340266059SGregory Neil Shapiro ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool,
52440266059SGregory Neil Shapiro e->e_quarmsg);
525c2aa98e2SPeter Wemm splitenv = ee;
526c2aa98e2SPeter Wemm
527c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next)
528c2aa98e2SPeter Wemm {
529c2aa98e2SPeter Wemm if (q->q_owner == owner)
530c2aa98e2SPeter Wemm {
53106f25ae9SGregory Neil Shapiro q->q_state = QS_CLONED;
532c2aa98e2SPeter Wemm if (tTd(13, 6))
53340266059SGregory Neil Shapiro sm_dprintf("\t... stripping %s from original envelope\n",
534c2aa98e2SPeter Wemm q->q_paddr);
535c2aa98e2SPeter Wemm }
536c2aa98e2SPeter Wemm }
537c2aa98e2SPeter Wemm for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
538c2aa98e2SPeter Wemm {
539c2aa98e2SPeter Wemm if (q->q_owner != owner)
540c2aa98e2SPeter Wemm {
54106f25ae9SGregory Neil Shapiro q->q_state = QS_CLONED;
542c2aa98e2SPeter Wemm if (tTd(13, 6))
54340266059SGregory Neil Shapiro sm_dprintf("\t... dropping %s from cloned envelope\n",
544c2aa98e2SPeter Wemm q->q_paddr);
545c2aa98e2SPeter Wemm }
546c2aa98e2SPeter Wemm else
547c2aa98e2SPeter Wemm {
548c2aa98e2SPeter Wemm /* clear DSN parameters */
549c2aa98e2SPeter Wemm q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
550c2aa98e2SPeter Wemm q->q_flags |= DefaultNotify & ~QPINGONSUCCESS;
551c2aa98e2SPeter Wemm if (tTd(13, 6))
55240266059SGregory Neil Shapiro sm_dprintf("\t... moving %s to cloned envelope\n",
553c2aa98e2SPeter Wemm q->q_paddr);
554c2aa98e2SPeter Wemm }
555c2aa98e2SPeter Wemm }
556c2aa98e2SPeter Wemm
557c2aa98e2SPeter Wemm if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags))
55840266059SGregory Neil Shapiro dup_queue_file(e, ee, DATAFL_LETTER);
55906f25ae9SGregory Neil Shapiro
56006f25ae9SGregory Neil Shapiro /*
56106f25ae9SGregory Neil Shapiro ** Give the split envelope access to the parent
56206f25ae9SGregory Neil Shapiro ** transcript file for errors obtained while
56306f25ae9SGregory Neil Shapiro ** processing the recipients (done before the
56406f25ae9SGregory Neil Shapiro ** envelope splitting).
56506f25ae9SGregory Neil Shapiro */
56606f25ae9SGregory Neil Shapiro
56706f25ae9SGregory Neil Shapiro if (e->e_xfp != NULL)
56840266059SGregory Neil Shapiro ee->e_xfp = sm_io_dup(e->e_xfp);
56906f25ae9SGregory Neil Shapiro
57006f25ae9SGregory Neil Shapiro /* failed to dup e->e_xfp, start a new transcript */
57106f25ae9SGregory Neil Shapiro if (ee->e_xfp == NULL)
572c2aa98e2SPeter Wemm openxscript(ee);
57306f25ae9SGregory Neil Shapiro
574065a643dSPeter Wemm if (mode != SM_VERIFY && LogLevel > 4)
57540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
57640266059SGregory Neil Shapiro "%s: clone: owner=%s",
57740266059SGregory Neil Shapiro ee->e_id, owner);
578c2aa98e2SPeter Wemm }
579c2aa98e2SPeter Wemm }
580c2aa98e2SPeter Wemm
581c2aa98e2SPeter Wemm if (owner != NULL)
582c2aa98e2SPeter Wemm {
58340266059SGregory Neil Shapiro setsender(owner, e, NULL, '\0', true);
584c2aa98e2SPeter Wemm if (tTd(13, 5))
585c2aa98e2SPeter Wemm {
58640266059SGregory Neil Shapiro sm_dprintf("sendall(owner): QS_SENDER ");
587e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), &e->e_from, false);
588c2aa98e2SPeter Wemm }
58906f25ae9SGregory Neil Shapiro e->e_from.q_state = QS_SENDER;
590c2aa98e2SPeter Wemm e->e_errormode = EM_MAIL;
591c2aa98e2SPeter Wemm e->e_flags |= EF_NORECEIPT;
592c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS;
593c2aa98e2SPeter Wemm }
594c2aa98e2SPeter Wemm
595c2aa98e2SPeter Wemm /* if nothing to be delivered, just queue up everything */
59640266059SGregory Neil Shapiro if (!somedeliveries && !WILL_BE_QUEUED(mode) &&
597c2aa98e2SPeter Wemm mode != SM_VERIFY)
598c2aa98e2SPeter Wemm {
59940266059SGregory Neil Shapiro time_t now;
600193538b7SGregory Neil Shapiro
601c2aa98e2SPeter Wemm if (tTd(13, 29))
602ffb83623SGregory Neil Shapiro sm_dprintf("No deliveries: auto-queueing\n");
603c2aa98e2SPeter Wemm mode = SM_QUEUE;
60440266059SGregory Neil Shapiro now = curtime();
605c2aa98e2SPeter Wemm
606c2aa98e2SPeter Wemm /* treat this as a delivery in terms of counting tries */
607193538b7SGregory Neil Shapiro e->e_dtime = now;
608c2aa98e2SPeter Wemm if (!expensive)
609c2aa98e2SPeter Wemm e->e_ntries++;
610c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
611c2aa98e2SPeter Wemm {
612193538b7SGregory Neil Shapiro ee->e_dtime = now;
613c2aa98e2SPeter Wemm if (!expensive)
614c2aa98e2SPeter Wemm ee->e_ntries++;
615c2aa98e2SPeter Wemm }
616c2aa98e2SPeter Wemm }
617c2aa98e2SPeter Wemm
61840266059SGregory Neil Shapiro if ((WILL_BE_QUEUED(mode) || mode == SM_FORK ||
619e92d3f3fSGregory Neil Shapiro (mode != SM_VERIFY &&
620e92d3f3fSGregory Neil Shapiro (SuperSafe == SAFE_REALLY ||
621e92d3f3fSGregory Neil Shapiro SuperSafe == SAFE_REALLY_POSTMILTER))) &&
622c2aa98e2SPeter Wemm (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL))
623c2aa98e2SPeter Wemm {
6242fb4f839SGregory Neil Shapiro unsigned int qup_flags;
62540266059SGregory Neil Shapiro
62642e5d165SGregory Neil Shapiro /*
62742e5d165SGregory Neil Shapiro ** Be sure everything is instantiated in the queue.
62842e5d165SGregory Neil Shapiro ** Split envelopes first in case the machine crashes.
62942e5d165SGregory Neil Shapiro ** If the original were done first, we may lose
63042e5d165SGregory Neil Shapiro ** recipients.
63142e5d165SGregory Neil Shapiro */
63242e5d165SGregory Neil Shapiro
6332fb4f839SGregory Neil Shapiro if (WILL_BE_QUEUED(mode))
6342fb4f839SGregory Neil Shapiro qup_flags = QUP_FL_ANNOUNCE;
6352fb4f839SGregory Neil Shapiro else
6362fb4f839SGregory Neil Shapiro qup_flags = QUP_FL_NONE;
6372fb4f839SGregory Neil Shapiro #if HASFLOCK
6382fb4f839SGregory Neil Shapiro if (mode == SM_FORK)
6392fb4f839SGregory Neil Shapiro qup_flags |= QUP_FL_MSYNC;
6405b0945b5SGregory Neil Shapiro #endif
64140266059SGregory Neil Shapiro
642c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
6432fb4f839SGregory Neil Shapiro queueup(ee, qup_flags);
6442fb4f839SGregory Neil Shapiro queueup(e, qup_flags);
645c2aa98e2SPeter Wemm }
646c2aa98e2SPeter Wemm
647c2aa98e2SPeter Wemm if (tTd(62, 10))
648c2aa98e2SPeter Wemm checkfds("after envelope splitting");
649c2aa98e2SPeter Wemm
650c2aa98e2SPeter Wemm /*
651c2aa98e2SPeter Wemm ** If we belong in background, fork now.
652c2aa98e2SPeter Wemm */
653c2aa98e2SPeter Wemm
654c2aa98e2SPeter Wemm if (tTd(13, 20))
655c2aa98e2SPeter Wemm {
65640266059SGregory Neil Shapiro sm_dprintf("sendall: final mode = %c\n", mode);
657c2aa98e2SPeter Wemm if (tTd(13, 21))
658c2aa98e2SPeter Wemm {
65940266059SGregory Neil Shapiro sm_dprintf("\n================ Final Send Queue(s) =====================\n");
66040266059SGregory Neil Shapiro sm_dprintf("\n *** Envelope %s, e_from=%s ***\n",
661c2aa98e2SPeter Wemm e->e_id, e->e_from.q_paddr);
662e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), e->e_sendqueue, true);
663c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
664c2aa98e2SPeter Wemm {
66540266059SGregory Neil Shapiro sm_dprintf("\n *** Envelope %s, e_from=%s ***\n",
666c2aa98e2SPeter Wemm ee->e_id, ee->e_from.q_paddr);
667e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), ee->e_sendqueue, true);
668c2aa98e2SPeter Wemm }
66940266059SGregory Neil Shapiro sm_dprintf("==========================================================\n\n");
670c2aa98e2SPeter Wemm }
671c2aa98e2SPeter Wemm }
672c2aa98e2SPeter Wemm switch (mode)
673c2aa98e2SPeter Wemm {
674c2aa98e2SPeter Wemm case SM_VERIFY:
675c2aa98e2SPeter Wemm Verbose = 2;
676c2aa98e2SPeter Wemm break;
677c2aa98e2SPeter Wemm
678c2aa98e2SPeter Wemm case SM_QUEUE:
679c2aa98e2SPeter Wemm case SM_DEFER:
680c2aa98e2SPeter Wemm #if HASFLOCK
681c2aa98e2SPeter Wemm queueonly:
6825b0945b5SGregory Neil Shapiro #endif
683c2aa98e2SPeter Wemm if (e->e_nrcpts > 0)
684c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE;
6859bd497b8SGregory Neil Shapiro (void) dropenvelope(e, splitenv != NULL, true);
686c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
687c2aa98e2SPeter Wemm {
688c2aa98e2SPeter Wemm if (ee->e_nrcpts > 0)
689c2aa98e2SPeter Wemm ee->e_flags |= EF_INQUEUE;
6909bd497b8SGregory Neil Shapiro (void) dropenvelope(ee, false, true);
691c2aa98e2SPeter Wemm }
692c2aa98e2SPeter Wemm return;
693c2aa98e2SPeter Wemm
694c2aa98e2SPeter Wemm case SM_FORK:
695c2aa98e2SPeter Wemm if (e->e_xfp != NULL)
69640266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
697c2aa98e2SPeter Wemm
698c2aa98e2SPeter Wemm #if !HASFLOCK
699c2aa98e2SPeter Wemm /*
700c2aa98e2SPeter Wemm ** Since fcntl locking has the interesting semantic that
701c2aa98e2SPeter Wemm ** the lock is owned by a process, not by an open file
702c2aa98e2SPeter Wemm ** descriptor, we have to flush this to the queue, and
703c2aa98e2SPeter Wemm ** then restart from scratch in the child.
704c2aa98e2SPeter Wemm */
705c2aa98e2SPeter Wemm
706c2aa98e2SPeter Wemm {
707c2aa98e2SPeter Wemm /* save id for future use */
708c2aa98e2SPeter Wemm char *qid = e->e_id;
709c2aa98e2SPeter Wemm
710c2aa98e2SPeter Wemm /* now drop the envelope in the parent */
711c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE;
7129bd497b8SGregory Neil Shapiro (void) dropenvelope(e, splitenv != NULL, false);
713c2aa98e2SPeter Wemm
714c2aa98e2SPeter Wemm /* arrange to reacquire lock after fork */
715c2aa98e2SPeter Wemm e->e_id = qid;
716c2aa98e2SPeter Wemm }
717c2aa98e2SPeter Wemm
718c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
719c2aa98e2SPeter Wemm {
720c2aa98e2SPeter Wemm /* save id for future use */
721c2aa98e2SPeter Wemm char *qid = ee->e_id;
722c2aa98e2SPeter Wemm
723c2aa98e2SPeter Wemm /* drop envelope in parent */
724c2aa98e2SPeter Wemm ee->e_flags |= EF_INQUEUE;
7259bd497b8SGregory Neil Shapiro (void) dropenvelope(ee, false, false);
726c2aa98e2SPeter Wemm
727c2aa98e2SPeter Wemm /* and save qid for reacquisition */
728c2aa98e2SPeter Wemm ee->e_id = qid;
729c2aa98e2SPeter Wemm }
730e92d3f3fSGregory Neil Shapiro
731c2aa98e2SPeter Wemm #endif /* !HASFLOCK */
732c2aa98e2SPeter Wemm
73306f25ae9SGregory Neil Shapiro /*
73406f25ae9SGregory Neil Shapiro ** Since the delivery may happen in a child and the parent
73506f25ae9SGregory Neil Shapiro ** does not wait, the parent may close the maps thereby
73606f25ae9SGregory Neil Shapiro ** removing any shared memory used by the map. Therefore,
73706f25ae9SGregory Neil Shapiro ** close the maps now so the child will dynamically open
73806f25ae9SGregory Neil Shapiro ** them if necessary.
73906f25ae9SGregory Neil Shapiro */
74006f25ae9SGregory Neil Shapiro
74140266059SGregory Neil Shapiro closemaps(false);
74206f25ae9SGregory Neil Shapiro
743c2aa98e2SPeter Wemm pid = fork();
744c2aa98e2SPeter Wemm if (pid < 0)
745c2aa98e2SPeter Wemm {
74606f25ae9SGregory Neil Shapiro syserr("deliver: fork 1");
747c2aa98e2SPeter Wemm #if HASFLOCK
748c2aa98e2SPeter Wemm goto queueonly;
74906f25ae9SGregory Neil Shapiro #else /* HASFLOCK */
750c2aa98e2SPeter Wemm e->e_id = NULL;
751c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
752c2aa98e2SPeter Wemm ee->e_id = NULL;
753c2aa98e2SPeter Wemm return;
754c2aa98e2SPeter Wemm #endif /* HASFLOCK */
755c2aa98e2SPeter Wemm }
756c2aa98e2SPeter Wemm else if (pid > 0)
757c2aa98e2SPeter Wemm {
758c2aa98e2SPeter Wemm #if HASFLOCK
759c2aa98e2SPeter Wemm /* be sure we leave the temp files to our child */
760c2aa98e2SPeter Wemm /* close any random open files in the envelope */
761c2aa98e2SPeter Wemm closexscript(e);
7622fb4f839SGregory Neil Shapiro SM_CLOSE_FP(e->e_dfp);
763c2aa98e2SPeter Wemm e->e_flags &= ~EF_HAS_DF;
764c2aa98e2SPeter Wemm
765c2aa98e2SPeter Wemm /* can't call unlockqueue to avoid unlink of xfp */
766c2aa98e2SPeter Wemm if (e->e_lockfp != NULL)
76740266059SGregory Neil Shapiro (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
76806f25ae9SGregory Neil Shapiro else
76906f25ae9SGregory Neil Shapiro syserr("%s: sendall: null lockfp", e->e_id);
770c2aa98e2SPeter Wemm e->e_lockfp = NULL;
77106f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */
772c2aa98e2SPeter Wemm
773c2aa98e2SPeter Wemm /* make sure the parent doesn't own the envelope */
774c2aa98e2SPeter Wemm e->e_id = NULL;
775c2aa98e2SPeter Wemm
77640266059SGregory Neil Shapiro #if USE_DOUBLE_FORK
777c2aa98e2SPeter Wemm /* catch intermediate zombie */
778c2aa98e2SPeter Wemm (void) waitfor(pid);
7795b0945b5SGregory Neil Shapiro #endif
780c2aa98e2SPeter Wemm return;
781c2aa98e2SPeter Wemm }
782c2aa98e2SPeter Wemm
7838774250cSGregory Neil Shapiro /* Reset global flags */
7848774250cSGregory Neil Shapiro RestartRequest = NULL;
78540266059SGregory Neil Shapiro RestartWorkGroup = false;
7868774250cSGregory Neil Shapiro ShutdownRequest = NULL;
7878774250cSGregory Neil Shapiro PendingSignal = 0;
7888774250cSGregory Neil Shapiro
78942e5d165SGregory Neil Shapiro /*
79040266059SGregory Neil Shapiro ** Initialize exception stack and default exception
79140266059SGregory Neil Shapiro ** handler for child process.
79240266059SGregory Neil Shapiro */
79340266059SGregory Neil Shapiro
79440266059SGregory Neil Shapiro sm_exc_newthread(fatal_error);
79540266059SGregory Neil Shapiro
79640266059SGregory Neil Shapiro /*
79742e5d165SGregory Neil Shapiro ** Since we have accepted responsbility for the message,
79842e5d165SGregory Neil Shapiro ** change the SIGTERM handler. intsig() (the old handler)
79942e5d165SGregory Neil Shapiro ** would remove the envelope if this was a command line
80042e5d165SGregory Neil Shapiro ** message submission.
80142e5d165SGregory Neil Shapiro */
80242e5d165SGregory Neil Shapiro
80340266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL);
80442e5d165SGregory Neil Shapiro
80540266059SGregory Neil Shapiro #if USE_DOUBLE_FORK
806c2aa98e2SPeter Wemm /* double fork to avoid zombies */
807c2aa98e2SPeter Wemm pid = fork();
808c2aa98e2SPeter Wemm if (pid > 0)
809c2aa98e2SPeter Wemm exit(EX_OK);
81006f25ae9SGregory Neil Shapiro save_errno = errno;
81140266059SGregory Neil Shapiro #endif /* USE_DOUBLE_FORK */
81240266059SGregory Neil Shapiro
81340266059SGregory Neil Shapiro CurrentPid = getpid();
814c2aa98e2SPeter Wemm
815c2aa98e2SPeter Wemm /* be sure we are immune from the terminal */
816c2aa98e2SPeter Wemm disconnect(2, e);
81706f25ae9SGregory Neil Shapiro clearstats();
818c2aa98e2SPeter Wemm
819c2aa98e2SPeter Wemm /* prevent parent from waiting if there was an error */
820c2aa98e2SPeter Wemm if (pid < 0)
821c2aa98e2SPeter Wemm {
82206f25ae9SGregory Neil Shapiro errno = save_errno;
82306f25ae9SGregory Neil Shapiro syserr("deliver: fork 2");
824c2aa98e2SPeter Wemm #if HASFLOCK
825c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE;
8265b0945b5SGregory Neil Shapiro #else
827c2aa98e2SPeter Wemm e->e_id = NULL;
8285b0945b5SGregory Neil Shapiro #endif
82940266059SGregory Neil Shapiro finis(true, true, ExitStat);
830c2aa98e2SPeter Wemm }
831c2aa98e2SPeter Wemm
832c2aa98e2SPeter Wemm /* be sure to give error messages in child */
83340266059SGregory Neil Shapiro QuickAbort = false;
834c2aa98e2SPeter Wemm
835c2aa98e2SPeter Wemm /*
836c2aa98e2SPeter Wemm ** Close any cached connections.
837c2aa98e2SPeter Wemm **
838c2aa98e2SPeter Wemm ** We don't send the QUIT protocol because the parent
839c2aa98e2SPeter Wemm ** still knows about the connection.
840c2aa98e2SPeter Wemm **
841c2aa98e2SPeter Wemm ** This should only happen when delivering an error
842c2aa98e2SPeter Wemm ** message.
843c2aa98e2SPeter Wemm */
844c2aa98e2SPeter Wemm
84540266059SGregory Neil Shapiro mci_flush(false, NULL);
846c2aa98e2SPeter Wemm
847c2aa98e2SPeter Wemm #if HASFLOCK
848c2aa98e2SPeter Wemm break;
84906f25ae9SGregory Neil Shapiro #else /* HASFLOCK */
850c2aa98e2SPeter Wemm
851c2aa98e2SPeter Wemm /*
852c2aa98e2SPeter Wemm ** Now reacquire and run the various queue files.
853c2aa98e2SPeter Wemm */
854c2aa98e2SPeter Wemm
855c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
856c2aa98e2SPeter Wemm {
857c2aa98e2SPeter Wemm ENVELOPE *sibling = ee->e_sibling;
858c2aa98e2SPeter Wemm
85940266059SGregory Neil Shapiro (void) dowork(ee->e_qgrp, ee->e_qdir, ee->e_id,
86040266059SGregory Neil Shapiro false, false, ee);
861c2aa98e2SPeter Wemm ee->e_sibling = sibling;
862c2aa98e2SPeter Wemm }
86340266059SGregory Neil Shapiro (void) dowork(e->e_qgrp, e->e_qdir, e->e_id,
86440266059SGregory Neil Shapiro false, false, e);
86540266059SGregory Neil Shapiro finis(true, true, ExitStat);
86606f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */
867c2aa98e2SPeter Wemm }
868c2aa98e2SPeter Wemm
869c2aa98e2SPeter Wemm sendenvelope(e, mode);
8709bd497b8SGregory Neil Shapiro (void) dropenvelope(e, true, true);
871c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
872c2aa98e2SPeter Wemm {
873c2aa98e2SPeter Wemm CurEnv = ee;
874c2aa98e2SPeter Wemm if (mode != SM_VERIFY)
875c2aa98e2SPeter Wemm openxscript(ee);
876c2aa98e2SPeter Wemm sendenvelope(ee, mode);
8779bd497b8SGregory Neil Shapiro (void) dropenvelope(ee, true, true);
878c2aa98e2SPeter Wemm }
879c2aa98e2SPeter Wemm CurEnv = e;
880c2aa98e2SPeter Wemm
881c2aa98e2SPeter Wemm Verbose = oldverbose;
882c2aa98e2SPeter Wemm if (mode == SM_FORK)
88340266059SGregory Neil Shapiro finis(true, true, ExitStat);
884c2aa98e2SPeter Wemm }
885c2aa98e2SPeter Wemm
88606f25ae9SGregory Neil Shapiro static void
sendenvelope(e,mode)887c2aa98e2SPeter Wemm sendenvelope(e, mode)
888c2aa98e2SPeter Wemm register ENVELOPE *e;
889c2aa98e2SPeter Wemm int mode;
890c2aa98e2SPeter Wemm {
891c2aa98e2SPeter Wemm register ADDRESS *q;
892c2aa98e2SPeter Wemm bool didany;
893c2aa98e2SPeter Wemm
894c2aa98e2SPeter Wemm if (tTd(13, 10))
89540266059SGregory Neil Shapiro sm_dprintf("sendenvelope(%s) e_flags=0x%lx\n",
896c2aa98e2SPeter Wemm e->e_id == NULL ? "[NOQUEUE]" : e->e_id,
897c2aa98e2SPeter Wemm e->e_flags);
898c2aa98e2SPeter Wemm if (LogLevel > 80)
899c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, e->e_id,
90006f25ae9SGregory Neil Shapiro "sendenvelope, flags=0x%lx",
901c2aa98e2SPeter Wemm e->e_flags);
902c2aa98e2SPeter Wemm
903c2aa98e2SPeter Wemm /*
904c2aa98e2SPeter Wemm ** If we have had global, fatal errors, don't bother sending
905c2aa98e2SPeter Wemm ** the message at all if we are in SMTP mode. Local errors
906c2aa98e2SPeter Wemm ** (e.g., a single address failing) will still cause the other
907c2aa98e2SPeter Wemm ** addresses to be sent.
908c2aa98e2SPeter Wemm */
909c2aa98e2SPeter Wemm
910c2aa98e2SPeter Wemm if (bitset(EF_FATALERRS, e->e_flags) &&
911c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON))
912c2aa98e2SPeter Wemm {
913c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE;
914c2aa98e2SPeter Wemm return;
915c2aa98e2SPeter Wemm }
916c2aa98e2SPeter Wemm
91740266059SGregory Neil Shapiro /*
91840266059SGregory Neil Shapiro ** Don't attempt deliveries if we want to bounce now
91940266059SGregory Neil Shapiro ** or if deliver-by time is exceeded.
92040266059SGregory Neil Shapiro */
92140266059SGregory Neil Shapiro
92206f25ae9SGregory Neil Shapiro if (!bitset(EF_RESPONSE, e->e_flags) &&
92340266059SGregory Neil Shapiro (TimeOuts.to_q_return[e->e_timeoutclass] == NOW ||
92440266059SGregory Neil Shapiro (IS_DLVR_RETURN(e) && e->e_deliver_by > 0 &&
92540266059SGregory Neil Shapiro curtime() > e->e_ctime + e->e_deliver_by)))
92606f25ae9SGregory Neil Shapiro return;
92706f25ae9SGregory Neil Shapiro
928c2aa98e2SPeter Wemm /*
929c2aa98e2SPeter Wemm ** Run through the list and send everything.
930c2aa98e2SPeter Wemm **
931c2aa98e2SPeter Wemm ** Set EF_GLOBALERRS so that error messages during delivery
932c2aa98e2SPeter Wemm ** result in returned mail.
933c2aa98e2SPeter Wemm */
934c2aa98e2SPeter Wemm
935c2aa98e2SPeter Wemm e->e_nsent = 0;
936c2aa98e2SPeter Wemm e->e_flags |= EF_GLOBALERRS;
93706f25ae9SGregory Neil Shapiro
93840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{envid}"), e->e_envid);
93940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{bodytype}"), e->e_bodytype);
94040266059SGregory Neil Shapiro didany = false;
94140266059SGregory Neil Shapiro
94240266059SGregory Neil Shapiro if (!bitset(EF_SPLIT, e->e_flags))
94340266059SGregory Neil Shapiro {
94440266059SGregory Neil Shapiro ENVELOPE *oldsib;
94540266059SGregory Neil Shapiro ENVELOPE *ee;
94640266059SGregory Neil Shapiro
94740266059SGregory Neil Shapiro /*
94840266059SGregory Neil Shapiro ** Save old sibling and set it to NULL to avoid
94940266059SGregory Neil Shapiro ** queueing up the same envelopes again.
95040266059SGregory Neil Shapiro ** This requires that envelopes in that list have
95140266059SGregory Neil Shapiro ** been take care of before (or at some other place).
95240266059SGregory Neil Shapiro */
95340266059SGregory Neil Shapiro
95440266059SGregory Neil Shapiro oldsib = e->e_sibling;
95540266059SGregory Neil Shapiro e->e_sibling = NULL;
95640266059SGregory Neil Shapiro if (!split_by_recipient(e) &&
95740266059SGregory Neil Shapiro bitset(EF_FATALERRS, e->e_flags))
95840266059SGregory Neil Shapiro {
95940266059SGregory Neil Shapiro if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
96040266059SGregory Neil Shapiro e->e_flags |= EF_CLRQUEUE;
96140266059SGregory Neil Shapiro return;
96240266059SGregory Neil Shapiro }
96340266059SGregory Neil Shapiro for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
9642fb4f839SGregory Neil Shapiro queueup(ee, QUP_FL_MSYNC);
96540266059SGregory Neil Shapiro
96640266059SGregory Neil Shapiro /* clean up */
96740266059SGregory Neil Shapiro for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
96840266059SGregory Neil Shapiro {
96940266059SGregory Neil Shapiro /* now unlock the job */
97040266059SGregory Neil Shapiro closexscript(ee);
97140266059SGregory Neil Shapiro unlockqueue(ee);
97240266059SGregory Neil Shapiro
97340266059SGregory Neil Shapiro /* this envelope is marked unused */
9742fb4f839SGregory Neil Shapiro SM_CLOSE_FP(ee->e_dfp);
97540266059SGregory Neil Shapiro ee->e_id = NULL;
97640266059SGregory Neil Shapiro ee->e_flags &= ~EF_HAS_DF;
97740266059SGregory Neil Shapiro }
97840266059SGregory Neil Shapiro e->e_sibling = oldsib;
97940266059SGregory Neil Shapiro }
980c2aa98e2SPeter Wemm
981c2aa98e2SPeter Wemm /* now run through the queue */
982c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next)
983c2aa98e2SPeter Wemm {
984c2aa98e2SPeter Wemm #if XDEBUG
9852fb4f839SGregory Neil Shapiro char wbuf[MAXNAME + 20]; /* EAI: might be too short, but that's ok for debugging */
986c2aa98e2SPeter Wemm
987d0cef73dSGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof(wbuf), "sendall(%.*s)",
9882fb4f839SGregory Neil Shapiro MAXNAME, q->q_paddr); /* EAI: see above */
989c2aa98e2SPeter Wemm checkfd012(wbuf);
99006f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
991c2aa98e2SPeter Wemm if (mode == SM_VERIFY)
992c2aa98e2SPeter Wemm {
993c2aa98e2SPeter Wemm e->e_to = q->q_paddr;
99406f25ae9SGregory Neil Shapiro if (QS_IS_SENDABLE(q->q_state))
995c2aa98e2SPeter Wemm {
996c2aa98e2SPeter Wemm if (q->q_host != NULL && q->q_host[0] != '\0')
997c2aa98e2SPeter Wemm message("deliverable: mailer %s, host %s, user %s",
998c2aa98e2SPeter Wemm q->q_mailer->m_name,
999c2aa98e2SPeter Wemm q->q_host,
1000c2aa98e2SPeter Wemm q->q_user);
1001c2aa98e2SPeter Wemm else
1002c2aa98e2SPeter Wemm message("deliverable: mailer %s, user %s",
1003c2aa98e2SPeter Wemm q->q_mailer->m_name,
1004c2aa98e2SPeter Wemm q->q_user);
1005c2aa98e2SPeter Wemm }
1006c2aa98e2SPeter Wemm }
100706f25ae9SGregory Neil Shapiro else if (QS_IS_OK(q->q_state))
1008c2aa98e2SPeter Wemm {
1009c2aa98e2SPeter Wemm /*
1010c2aa98e2SPeter Wemm ** Checkpoint the send list every few addresses
1011c2aa98e2SPeter Wemm */
1012c2aa98e2SPeter Wemm
101342e5d165SGregory Neil Shapiro if (CheckpointInterval > 0 &&
101442e5d165SGregory Neil Shapiro e->e_nsent >= CheckpointInterval)
1015c2aa98e2SPeter Wemm {
10162fb4f839SGregory Neil Shapiro queueup(e, QUP_FL_NONE);
1017c2aa98e2SPeter Wemm e->e_nsent = 0;
1018c2aa98e2SPeter Wemm }
1019c2aa98e2SPeter Wemm (void) deliver(e, q);
102040266059SGregory Neil Shapiro didany = true;
1021c2aa98e2SPeter Wemm }
1022c2aa98e2SPeter Wemm }
1023c2aa98e2SPeter Wemm if (didany)
1024c2aa98e2SPeter Wemm {
1025c2aa98e2SPeter Wemm e->e_dtime = curtime();
1026c2aa98e2SPeter Wemm e->e_ntries++;
1027c2aa98e2SPeter Wemm }
1028c2aa98e2SPeter Wemm
1029c2aa98e2SPeter Wemm #if XDEBUG
1030c2aa98e2SPeter Wemm checkfd012("end of sendenvelope");
10315b0945b5SGregory Neil Shapiro #endif
1032c2aa98e2SPeter Wemm }
103340266059SGregory Neil Shapiro
103440266059SGregory Neil Shapiro #if REQUIRES_DIR_FSYNC
103540266059SGregory Neil Shapiro /*
103640266059SGregory Neil Shapiro ** SYNC_DIR -- fsync a directory based on a filename
103740266059SGregory Neil Shapiro **
103840266059SGregory Neil Shapiro ** Parameters:
103940266059SGregory Neil Shapiro ** filename -- path of file
104040266059SGregory Neil Shapiro ** panic -- panic?
104140266059SGregory Neil Shapiro **
104240266059SGregory Neil Shapiro ** Returns:
104340266059SGregory Neil Shapiro ** none
104440266059SGregory Neil Shapiro */
104540266059SGregory Neil Shapiro
104640266059SGregory Neil Shapiro void
sync_dir(filename,panic)104740266059SGregory Neil Shapiro sync_dir(filename, panic)
104840266059SGregory Neil Shapiro char *filename;
104940266059SGregory Neil Shapiro bool panic;
105040266059SGregory Neil Shapiro {
105140266059SGregory Neil Shapiro int dirfd;
105240266059SGregory Neil Shapiro char *dirp;
105340266059SGregory Neil Shapiro char dir[MAXPATHLEN];
105440266059SGregory Neil Shapiro
105513bd1963SGregory Neil Shapiro if (!RequiresDirfsync)
105613bd1963SGregory Neil Shapiro return;
105713bd1963SGregory Neil Shapiro
105840266059SGregory Neil Shapiro /* filesystems which require the directory be synced */
105940266059SGregory Neil Shapiro dirp = strrchr(filename, '/');
106040266059SGregory Neil Shapiro if (dirp != NULL)
106140266059SGregory Neil Shapiro {
1062d0cef73dSGregory Neil Shapiro if (sm_strlcpy(dir, filename, sizeof(dir)) >= sizeof(dir))
106340266059SGregory Neil Shapiro return;
106440266059SGregory Neil Shapiro dir[dirp - filename] = '\0';
106540266059SGregory Neil Shapiro dirp = dir;
106640266059SGregory Neil Shapiro }
106740266059SGregory Neil Shapiro else
106840266059SGregory Neil Shapiro dirp = ".";
106940266059SGregory Neil Shapiro dirfd = open(dirp, O_RDONLY, 0700);
107040266059SGregory Neil Shapiro if (tTd(40,32))
107140266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "sync_dir: %s: fsync(%d)",
107240266059SGregory Neil Shapiro dirp, dirfd);
107340266059SGregory Neil Shapiro if (dirfd >= 0)
107440266059SGregory Neil Shapiro {
107540266059SGregory Neil Shapiro if (fsync(dirfd) < 0)
107640266059SGregory Neil Shapiro {
107740266059SGregory Neil Shapiro if (panic)
107840266059SGregory Neil Shapiro syserr("!sync_dir: cannot fsync directory %s",
107940266059SGregory Neil Shapiro dirp);
108040266059SGregory Neil Shapiro else if (LogLevel > 1)
108140266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
108240266059SGregory Neil Shapiro "sync_dir: cannot fsync directory %s: %s",
108340266059SGregory Neil Shapiro dirp, sm_errstring(errno));
108440266059SGregory Neil Shapiro }
108540266059SGregory Neil Shapiro (void) close(dirfd);
108640266059SGregory Neil Shapiro }
108740266059SGregory Neil Shapiro }
108840266059SGregory Neil Shapiro #endif /* REQUIRES_DIR_FSYNC */
108940266059SGregory Neil Shapiro /*
1090c2aa98e2SPeter Wemm ** DUP_QUEUE_FILE -- duplicate a queue file into a split queue
1091c2aa98e2SPeter Wemm **
1092c2aa98e2SPeter Wemm ** Parameters:
1093c2aa98e2SPeter Wemm ** e -- the existing envelope
1094c2aa98e2SPeter Wemm ** ee -- the new envelope
109540266059SGregory Neil Shapiro ** type -- the queue file type (e.g., DATAFL_LETTER)
1096c2aa98e2SPeter Wemm **
1097c2aa98e2SPeter Wemm ** Returns:
1098c2aa98e2SPeter Wemm ** none
1099c2aa98e2SPeter Wemm */
1100c2aa98e2SPeter Wemm
110106f25ae9SGregory Neil Shapiro static void
dup_queue_file(e,ee,type)1102c2aa98e2SPeter Wemm dup_queue_file(e, ee, type)
110340266059SGregory Neil Shapiro ENVELOPE *e, *ee;
1104c2aa98e2SPeter Wemm int type;
1105c2aa98e2SPeter Wemm {
110606f25ae9SGregory Neil Shapiro char f1buf[MAXPATHLEN], f2buf[MAXPATHLEN];
1107c2aa98e2SPeter Wemm
1108c2aa98e2SPeter Wemm ee->e_dfp = NULL;
1109c2aa98e2SPeter Wemm ee->e_xfp = NULL;
111006f25ae9SGregory Neil Shapiro
111106f25ae9SGregory Neil Shapiro /*
111206f25ae9SGregory Neil Shapiro ** Make sure both are in the same directory.
111306f25ae9SGregory Neil Shapiro */
111406f25ae9SGregory Neil Shapiro
1115d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(f1buf, queuename(e, type), sizeof(f1buf));
1116d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(f2buf, queuename(ee, type), sizeof(f2buf));
1117959366dcSGregory Neil Shapiro
1118959366dcSGregory Neil Shapiro /* Force the df to disk if it's not there yet */
1119959366dcSGregory Neil Shapiro if (type == DATAFL_LETTER && e->e_dfp != NULL &&
1120959366dcSGregory Neil Shapiro sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 &&
1121959366dcSGregory Neil Shapiro errno != EINVAL)
1122959366dcSGregory Neil Shapiro {
1123959366dcSGregory Neil Shapiro syserr("!dup_queue_file: can't commit %s", f1buf);
1124959366dcSGregory Neil Shapiro /* NOTREACHED */
1125959366dcSGregory Neil Shapiro }
1126959366dcSGregory Neil Shapiro
1127c2aa98e2SPeter Wemm if (link(f1buf, f2buf) < 0)
1128c2aa98e2SPeter Wemm {
112906f25ae9SGregory Neil Shapiro int save_errno = errno;
1130c2aa98e2SPeter Wemm
1131c2aa98e2SPeter Wemm syserr("sendall: link(%s, %s)", f1buf, f2buf);
113206f25ae9SGregory Neil Shapiro if (save_errno == EEXIST)
1133c2aa98e2SPeter Wemm {
1134c2aa98e2SPeter Wemm if (unlink(f2buf) < 0)
1135c2aa98e2SPeter Wemm {
1136c2aa98e2SPeter Wemm syserr("!sendall: unlink(%s): permanent",
1137c2aa98e2SPeter Wemm f2buf);
1138c2aa98e2SPeter Wemm /* NOTREACHED */
1139c2aa98e2SPeter Wemm }
1140c2aa98e2SPeter Wemm if (link(f1buf, f2buf) < 0)
1141c2aa98e2SPeter Wemm {
1142c2aa98e2SPeter Wemm syserr("!sendall: link(%s, %s): permanent",
1143c2aa98e2SPeter Wemm f1buf, f2buf);
1144c2aa98e2SPeter Wemm /* NOTREACHED */
1145c2aa98e2SPeter Wemm }
1146c2aa98e2SPeter Wemm }
1147c2aa98e2SPeter Wemm }
114840266059SGregory Neil Shapiro SYNC_DIR(f2buf, true);
1149c2aa98e2SPeter Wemm }
115040266059SGregory Neil Shapiro /*
1151c2aa98e2SPeter Wemm ** DOFORK -- do a fork, retrying a couple of times on failure.
1152c2aa98e2SPeter Wemm **
1153c2aa98e2SPeter Wemm ** This MUST be a macro, since after a vfork we are running
1154c2aa98e2SPeter Wemm ** two processes on the same stack!!!
1155c2aa98e2SPeter Wemm **
1156c2aa98e2SPeter Wemm ** Parameters:
1157c2aa98e2SPeter Wemm ** none.
1158c2aa98e2SPeter Wemm **
1159c2aa98e2SPeter Wemm ** Returns:
1160c2aa98e2SPeter Wemm ** From a macro??? You've got to be kidding!
1161c2aa98e2SPeter Wemm **
1162c2aa98e2SPeter Wemm ** Side Effects:
1163c2aa98e2SPeter Wemm ** Modifies the ==> LOCAL <== variable 'pid', leaving:
1164c2aa98e2SPeter Wemm ** pid of child in parent, zero in child.
1165c2aa98e2SPeter Wemm ** -1 on unrecoverable error.
1166c2aa98e2SPeter Wemm **
1167c2aa98e2SPeter Wemm ** Notes:
1168c2aa98e2SPeter Wemm ** I'm awfully sorry this looks so awful. That's
1169c2aa98e2SPeter Wemm ** vfork for you.....
1170c2aa98e2SPeter Wemm */
1171c2aa98e2SPeter Wemm
1172c2aa98e2SPeter Wemm #define NFORKTRIES 5
1173c2aa98e2SPeter Wemm
1174c2aa98e2SPeter Wemm #ifndef FORK
1175c2aa98e2SPeter Wemm # define FORK fork
11765b0945b5SGregory Neil Shapiro #endif
1177c2aa98e2SPeter Wemm
1178c2aa98e2SPeter Wemm #define DOFORK(fORKfN) \
1179c2aa98e2SPeter Wemm {\
1180c2aa98e2SPeter Wemm register int i;\
1181c2aa98e2SPeter Wemm \
1182c2aa98e2SPeter Wemm for (i = NFORKTRIES; --i >= 0; )\
1183c2aa98e2SPeter Wemm {\
1184c2aa98e2SPeter Wemm pid = fORKfN();\
1185c2aa98e2SPeter Wemm if (pid >= 0)\
1186c2aa98e2SPeter Wemm break;\
1187c2aa98e2SPeter Wemm if (i > 0)\
118806f25ae9SGregory Neil Shapiro (void) sleep((unsigned) NFORKTRIES - i);\
1189c2aa98e2SPeter Wemm }\
1190c2aa98e2SPeter Wemm }
119140266059SGregory Neil Shapiro /*
1192c2aa98e2SPeter Wemm ** DOFORK -- simple fork interface to DOFORK.
1193c2aa98e2SPeter Wemm **
1194c2aa98e2SPeter Wemm ** Parameters:
1195c2aa98e2SPeter Wemm ** none.
1196c2aa98e2SPeter Wemm **
1197c2aa98e2SPeter Wemm ** Returns:
1198c2aa98e2SPeter Wemm ** pid of child in parent.
1199c2aa98e2SPeter Wemm ** zero in child.
1200c2aa98e2SPeter Wemm ** -1 on error.
1201c2aa98e2SPeter Wemm **
1202c2aa98e2SPeter Wemm ** Side Effects:
1203c2aa98e2SPeter Wemm ** returns twice, once in parent and once in child.
1204c2aa98e2SPeter Wemm */
1205c2aa98e2SPeter Wemm
12068774250cSGregory Neil Shapiro pid_t
dofork()1207c2aa98e2SPeter Wemm dofork()
1208c2aa98e2SPeter Wemm {
1209c2aa98e2SPeter Wemm register pid_t pid = -1;
1210c2aa98e2SPeter Wemm
1211c2aa98e2SPeter Wemm DOFORK(fork);
121206f25ae9SGregory Neil Shapiro return pid;
1213c2aa98e2SPeter Wemm }
121440266059SGregory Neil Shapiro
121540266059SGregory Neil Shapiro /*
121640266059SGregory Neil Shapiro ** COLONCMP -- compare host-signatures up to first ':' or EOS
121740266059SGregory Neil Shapiro **
121840266059SGregory Neil Shapiro ** This takes two strings which happen to be host-signatures and
121940266059SGregory Neil Shapiro ** compares them. If the lowest preference portions of the MX-RR's
122040266059SGregory Neil Shapiro ** match (up to ':' or EOS, whichever is first), then we have
122140266059SGregory Neil Shapiro ** match. This is used for coattail-piggybacking messages during
122240266059SGregory Neil Shapiro ** message delivery.
122340266059SGregory Neil Shapiro ** If the signatures are the same up to the first ':' the remainder of
122440266059SGregory Neil Shapiro ** the signatures are then compared with a normal strcmp(). This saves
122540266059SGregory Neil Shapiro ** re-examining the first part of the signatures.
122640266059SGregory Neil Shapiro **
122740266059SGregory Neil Shapiro ** Parameters:
122840266059SGregory Neil Shapiro ** a - first host-signature
122940266059SGregory Neil Shapiro ** b - second host-signature
123040266059SGregory Neil Shapiro **
123140266059SGregory Neil Shapiro ** Returns:
123240266059SGregory Neil Shapiro ** HS_MATCH_NO -- no "match".
123340266059SGregory Neil Shapiro ** HS_MATCH_FIRST -- "match" for the first MX preference
123440266059SGregory Neil Shapiro ** (up to the first colon (':')).
123540266059SGregory Neil Shapiro ** HS_MATCH_FULL -- match for the entire MX record.
1236*d39bd2c1SGregory Neil Shapiro ** HS_MATCH_SKIP -- match but only one of the entries has a "mark"
123740266059SGregory Neil Shapiro **
123840266059SGregory Neil Shapiro ** Side Effects:
123940266059SGregory Neil Shapiro ** none.
124040266059SGregory Neil Shapiro */
124140266059SGregory Neil Shapiro
124240266059SGregory Neil Shapiro #define HS_MATCH_NO 0
124340266059SGregory Neil Shapiro #define HS_MATCH_FIRST 1
124440266059SGregory Neil Shapiro #define HS_MATCH_FULL 2
1245*d39bd2c1SGregory Neil Shapiro #define HS_MATCH_SKIP 4
124640266059SGregory Neil Shapiro
124740266059SGregory Neil Shapiro static int
coloncmp(a,b)124840266059SGregory Neil Shapiro coloncmp(a, b)
124940266059SGregory Neil Shapiro register const char *a;
125040266059SGregory Neil Shapiro register const char *b;
125140266059SGregory Neil Shapiro {
125240266059SGregory Neil Shapiro int ret = HS_MATCH_NO;
125340266059SGregory Neil Shapiro int braclev = 0;
1254*d39bd2c1SGregory Neil Shapiro # if HSMARKS
1255*d39bd2c1SGregory Neil Shapiro bool a_hsmark = false;
1256*d39bd2c1SGregory Neil Shapiro bool b_hsmark = false;
125740266059SGregory Neil Shapiro
1258*d39bd2c1SGregory Neil Shapiro if (HSM_AD == *a)
1259*d39bd2c1SGregory Neil Shapiro {
1260*d39bd2c1SGregory Neil Shapiro a_hsmark = true;
1261*d39bd2c1SGregory Neil Shapiro ++a;
1262*d39bd2c1SGregory Neil Shapiro }
1263*d39bd2c1SGregory Neil Shapiro if (HSM_AD == *b)
1264*d39bd2c1SGregory Neil Shapiro {
1265*d39bd2c1SGregory Neil Shapiro b_hsmark = true;
1266*d39bd2c1SGregory Neil Shapiro ++b;
1267*d39bd2c1SGregory Neil Shapiro }
1268*d39bd2c1SGregory Neil Shapiro # endif
126940266059SGregory Neil Shapiro while (*a == *b++)
127040266059SGregory Neil Shapiro {
127140266059SGregory Neil Shapiro /* Need to account for IPv6 bracketed addresses */
127240266059SGregory Neil Shapiro if (*a == '[')
127340266059SGregory Neil Shapiro braclev++;
12745ef517c0SGregory Neil Shapiro else if (*a == ']' && braclev > 0)
127540266059SGregory Neil Shapiro braclev--;
127640266059SGregory Neil Shapiro else if (*a == ':' && braclev <= 0)
127740266059SGregory Neil Shapiro {
127840266059SGregory Neil Shapiro ret = HS_MATCH_FIRST;
127940266059SGregory Neil Shapiro a++;
128040266059SGregory Neil Shapiro break;
128140266059SGregory Neil Shapiro }
128240266059SGregory Neil Shapiro else if (*a == '\0')
1283*d39bd2c1SGregory Neil Shapiro {
1284*d39bd2c1SGregory Neil Shapiro # if HSMARKS
1285*d39bd2c1SGregory Neil Shapiro /* exactly one mark */
1286*d39bd2c1SGregory Neil Shapiro if (a_hsmark != b_hsmark)
1287*d39bd2c1SGregory Neil Shapiro return HS_MATCH_SKIP;
1288*d39bd2c1SGregory Neil Shapiro # endif
128940266059SGregory Neil Shapiro return HS_MATCH_FULL; /* a full match */
1290*d39bd2c1SGregory Neil Shapiro }
129140266059SGregory Neil Shapiro a++;
129240266059SGregory Neil Shapiro }
129340266059SGregory Neil Shapiro if (ret == HS_MATCH_NO &&
129440266059SGregory Neil Shapiro braclev <= 0 &&
129540266059SGregory Neil Shapiro ((*a == '\0' && *(b - 1) == ':') ||
129640266059SGregory Neil Shapiro (*a == ':' && *(b - 1) == '\0')))
129740266059SGregory Neil Shapiro return HS_MATCH_FIRST;
129840266059SGregory Neil Shapiro if (ret == HS_MATCH_FIRST && strcmp(a, b) == 0)
1299*d39bd2c1SGregory Neil Shapiro {
1300*d39bd2c1SGregory Neil Shapiro # if HSMARKS
1301*d39bd2c1SGregory Neil Shapiro /* exactly one mark */
1302*d39bd2c1SGregory Neil Shapiro if (a_hsmark != b_hsmark)
1303*d39bd2c1SGregory Neil Shapiro return HS_MATCH_SKIP;
1304*d39bd2c1SGregory Neil Shapiro # endif
130540266059SGregory Neil Shapiro return HS_MATCH_FULL;
1306*d39bd2c1SGregory Neil Shapiro }
130740266059SGregory Neil Shapiro
130840266059SGregory Neil Shapiro return ret;
130940266059SGregory Neil Shapiro }
1310e92d3f3fSGregory Neil Shapiro
1311e92d3f3fSGregory Neil Shapiro /*
1312e92d3f3fSGregory Neil Shapiro ** SHOULD_TRY_FBSH -- Should try FallbackSmartHost?
1313e92d3f3fSGregory Neil Shapiro **
1314e92d3f3fSGregory Neil Shapiro ** Parameters:
1315e92d3f3fSGregory Neil Shapiro ** e -- envelope
1316e92d3f3fSGregory Neil Shapiro ** tried_fallbacksmarthost -- has been tried already? (in/out)
1317e92d3f3fSGregory Neil Shapiro ** hostbuf -- buffer for hostname (expand FallbackSmartHost) (out)
1318e92d3f3fSGregory Neil Shapiro ** hbsz -- size of hostbuf
1319e92d3f3fSGregory Neil Shapiro ** status -- current delivery status
1320e92d3f3fSGregory Neil Shapiro **
1321e92d3f3fSGregory Neil Shapiro ** Returns:
1322e92d3f3fSGregory Neil Shapiro ** true iff FallbackSmartHost should be tried.
1323e92d3f3fSGregory Neil Shapiro */
1324e92d3f3fSGregory Neil Shapiro
1325d0cef73dSGregory Neil Shapiro static bool should_try_fbsh __P((ENVELOPE *, bool *, char *, size_t, int));
1326d0cef73dSGregory Neil Shapiro
1327e92d3f3fSGregory Neil Shapiro static bool
should_try_fbsh(e,tried_fallbacksmarthost,hostbuf,hbsz,status)1328e92d3f3fSGregory Neil Shapiro should_try_fbsh(e, tried_fallbacksmarthost, hostbuf, hbsz, status)
1329e92d3f3fSGregory Neil Shapiro ENVELOPE *e;
1330e92d3f3fSGregory Neil Shapiro bool *tried_fallbacksmarthost;
1331e92d3f3fSGregory Neil Shapiro char *hostbuf;
1332e92d3f3fSGregory Neil Shapiro size_t hbsz;
1333e92d3f3fSGregory Neil Shapiro int status;
1334e92d3f3fSGregory Neil Shapiro {
1335e92d3f3fSGregory Neil Shapiro /*
13364e4196cbSGregory Neil Shapiro ** If the host was not found or a temporary failure occurred
13374e4196cbSGregory Neil Shapiro ** and a FallbackSmartHost is defined (and we have not yet
13384e4196cbSGregory Neil Shapiro ** tried it), then make one last try with it as the host.
1339e92d3f3fSGregory Neil Shapiro */
1340e92d3f3fSGregory Neil Shapiro
13414e4196cbSGregory Neil Shapiro if ((status == EX_NOHOST || status == EX_TEMPFAIL) &&
13424e4196cbSGregory Neil Shapiro FallbackSmartHost != NULL && !*tried_fallbacksmarthost)
1343e92d3f3fSGregory Neil Shapiro {
1344e92d3f3fSGregory Neil Shapiro *tried_fallbacksmarthost = true;
1345e92d3f3fSGregory Neil Shapiro expand(FallbackSmartHost, hostbuf, hbsz, e);
1346e92d3f3fSGregory Neil Shapiro if (!wordinclass(hostbuf, 'w'))
1347e92d3f3fSGregory Neil Shapiro {
1348e92d3f3fSGregory Neil Shapiro if (tTd(11, 1))
1349e92d3f3fSGregory Neil Shapiro sm_dprintf("one last try with FallbackSmartHost %s\n",
1350e92d3f3fSGregory Neil Shapiro hostbuf);
1351e92d3f3fSGregory Neil Shapiro return true;
1352e92d3f3fSGregory Neil Shapiro }
1353e92d3f3fSGregory Neil Shapiro }
1354e92d3f3fSGregory Neil Shapiro return false;
1355e92d3f3fSGregory Neil Shapiro }
1356da7d7b9cSGregory Neil Shapiro
1357*d39bd2c1SGregory Neil Shapiro #if STARTTLS || SASL
135840266059SGregory Neil Shapiro /*
13592fb4f839SGregory Neil Shapiro ** CLTFEATURES -- Get features for SMTP client
13602fb4f839SGregory Neil Shapiro **
13612fb4f839SGregory Neil Shapiro ** Parameters:
13622fb4f839SGregory Neil Shapiro ** e -- envelope
1363*d39bd2c1SGregory Neil Shapiro ** servername -- name of server.
13642fb4f839SGregory Neil Shapiro **
13652fb4f839SGregory Neil Shapiro ** Returns:
13662fb4f839SGregory Neil Shapiro ** EX_OK or EX_TEMPFAIL
13672fb4f839SGregory Neil Shapiro */
13682fb4f839SGregory Neil Shapiro
13692fb4f839SGregory Neil Shapiro static int cltfeatures __P((ENVELOPE *, char *));
13702fb4f839SGregory Neil Shapiro static int
cltfeatures(e,servername)1371*d39bd2c1SGregory Neil Shapiro cltfeatures(e, servername)
13722fb4f839SGregory Neil Shapiro ENVELOPE *e;
1373*d39bd2c1SGregory Neil Shapiro char *servername;
13742fb4f839SGregory Neil Shapiro {
13752fb4f839SGregory Neil Shapiro int r, i, idx;
13762fb4f839SGregory Neil Shapiro char **pvp, c;
13772fb4f839SGregory Neil Shapiro char pvpbuf[PSBUFSIZE];
13782fb4f839SGregory Neil Shapiro char flags[64]; /* XXX */
13792fb4f839SGregory Neil Shapiro
13802fb4f839SGregory Neil Shapiro SM_ASSERT(e != NULL);
13812fb4f839SGregory Neil Shapiro SM_ASSERT(e->e_mci != NULL);
13822fb4f839SGregory Neil Shapiro macdefine(&e->e_mci->mci_macro, A_PERM, macid("{client_flags}"), "");
13832fb4f839SGregory Neil Shapiro pvp = NULL;
1384*d39bd2c1SGregory Neil Shapiro r = rscap("clt_features", servername, NULL, e, &pvp, pvpbuf,
13852fb4f839SGregory Neil Shapiro sizeof(pvpbuf));
13862fb4f839SGregory Neil Shapiro if (r != EX_OK)
13872fb4f839SGregory Neil Shapiro return EX_OK;
13882fb4f839SGregory Neil Shapiro if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
13892fb4f839SGregory Neil Shapiro return EX_OK;
13902fb4f839SGregory Neil Shapiro if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0)
13912fb4f839SGregory Neil Shapiro return EX_TEMPFAIL;
13922fb4f839SGregory Neil Shapiro
13932fb4f839SGregory Neil Shapiro /* XXX Note: this does not inherit defaults! */
13942fb4f839SGregory Neil Shapiro for (idx = 0, i = 1; pvp[i] != NULL; i++)
13952fb4f839SGregory Neil Shapiro {
13962fb4f839SGregory Neil Shapiro c = pvp[i][0];
13972fb4f839SGregory Neil Shapiro if (!(isascii(c) && !isspace(c) && isprint(c)))
13982fb4f839SGregory Neil Shapiro continue;
13992fb4f839SGregory Neil Shapiro if (idx >= sizeof(flags) - 4)
14002fb4f839SGregory Neil Shapiro break;
14012fb4f839SGregory Neil Shapiro flags[idx++] = c;
14022fb4f839SGregory Neil Shapiro if (isupper(c))
14032fb4f839SGregory Neil Shapiro flags[idx++] = c;
14042fb4f839SGregory Neil Shapiro flags[idx++] = ' ';
14052fb4f839SGregory Neil Shapiro }
14062fb4f839SGregory Neil Shapiro flags[idx] = '\0';
14072fb4f839SGregory Neil Shapiro
14082fb4f839SGregory Neil Shapiro macdefine(&e->e_mci->mci_macro, A_TEMP, macid("{client_flags}"), flags);
14092fb4f839SGregory Neil Shapiro if (tTd(10, 30))
1410*d39bd2c1SGregory Neil Shapiro sm_dprintf("cltfeatures: server=%s, mci=%p, flags=%s, {client_flags}=%s\n",
1411*d39bd2c1SGregory Neil Shapiro servername, e->e_mci, flags,
1412*d39bd2c1SGregory Neil Shapiro macvalue(macid("{client_flags}"), e));
14132fb4f839SGregory Neil Shapiro return EX_OK;
14142fb4f839SGregory Neil Shapiro }
1415*d39bd2c1SGregory Neil Shapiro #endif /* STARTTLS || SASL */
1416*d39bd2c1SGregory Neil Shapiro
1417*d39bd2c1SGregory Neil Shapiro #if _FFR_LOG_FAILOVER
1418*d39bd2c1SGregory Neil Shapiro /*
1419*d39bd2c1SGregory Neil Shapiro ** LOGFAILOVER -- log reason why trying another host
1420*d39bd2c1SGregory Neil Shapiro **
1421*d39bd2c1SGregory Neil Shapiro ** Parameters:
1422*d39bd2c1SGregory Neil Shapiro ** e -- envelope
1423*d39bd2c1SGregory Neil Shapiro ** m -- the mailer info for this mailer
1424*d39bd2c1SGregory Neil Shapiro ** mci -- mailer connection information
1425*d39bd2c1SGregory Neil Shapiro ** rcode -- the code signifying the particular failure
1426*d39bd2c1SGregory Neil Shapiro ** rcpt -- current RCPT
1427*d39bd2c1SGregory Neil Shapiro **
1428*d39bd2c1SGregory Neil Shapiro ** Returns:
1429*d39bd2c1SGregory Neil Shapiro ** none.
1430*d39bd2c1SGregory Neil Shapiro */
1431*d39bd2c1SGregory Neil Shapiro
1432*d39bd2c1SGregory Neil Shapiro static void logfailover __P((ENVELOPE *, MAILER *, MCI *, int, ADDRESS *));
1433*d39bd2c1SGregory Neil Shapiro static void
logfailover(e,m,mci,rcode,rcpt)1434*d39bd2c1SGregory Neil Shapiro logfailover(e, m, mci, rcode, rcpt)
1435*d39bd2c1SGregory Neil Shapiro ENVELOPE *e;
1436*d39bd2c1SGregory Neil Shapiro MAILER *m;
1437*d39bd2c1SGregory Neil Shapiro MCI *mci;
1438*d39bd2c1SGregory Neil Shapiro int rcode;
1439*d39bd2c1SGregory Neil Shapiro ADDRESS *rcpt;
1440*d39bd2c1SGregory Neil Shapiro {
1441*d39bd2c1SGregory Neil Shapiro char buf[MAXNAME];
1442*d39bd2c1SGregory Neil Shapiro char cbuf[SM_MAX(SYSLOG_BUFSIZE, MAXNAME)];
1443*d39bd2c1SGregory Neil Shapiro
1444*d39bd2c1SGregory Neil Shapiro buf[0] = '\0';
1445*d39bd2c1SGregory Neil Shapiro cbuf[0] = '\0';
1446*d39bd2c1SGregory Neil Shapiro sm_strlcat(cbuf, "deliver: ", sizeof(cbuf));
1447*d39bd2c1SGregory Neil Shapiro if (m != NULL && m->m_name != NULL)
1448*d39bd2c1SGregory Neil Shapiro {
1449*d39bd2c1SGregory Neil Shapiro sm_snprintf(buf, sizeof(buf),
1450*d39bd2c1SGregory Neil Shapiro "mailer=%s, ", m->m_name);
1451*d39bd2c1SGregory Neil Shapiro sm_strlcat(cbuf, buf, sizeof(cbuf));
1452*d39bd2c1SGregory Neil Shapiro }
1453*d39bd2c1SGregory Neil Shapiro if (mci != NULL && mci->mci_host != NULL)
1454*d39bd2c1SGregory Neil Shapiro {
1455*d39bd2c1SGregory Neil Shapiro extern SOCKADDR CurHostAddr;
1456*d39bd2c1SGregory Neil Shapiro
1457*d39bd2c1SGregory Neil Shapiro sm_snprintf(buf, sizeof(buf),
1458*d39bd2c1SGregory Neil Shapiro "relay=%.100s", mci->mci_host);
1459*d39bd2c1SGregory Neil Shapiro sm_strlcat(cbuf, buf, sizeof(cbuf));
1460*d39bd2c1SGregory Neil Shapiro if (CurHostAddr.sa.sa_family != 0)
1461*d39bd2c1SGregory Neil Shapiro {
1462*d39bd2c1SGregory Neil Shapiro sm_snprintf(buf, sizeof(buf),
1463*d39bd2c1SGregory Neil Shapiro " [%.100s]",
1464*d39bd2c1SGregory Neil Shapiro anynet_ntoa(&CurHostAddr));
1465*d39bd2c1SGregory Neil Shapiro sm_strlcat(cbuf, buf, sizeof(cbuf));
1466*d39bd2c1SGregory Neil Shapiro }
1467*d39bd2c1SGregory Neil Shapiro sm_strlcat(cbuf, ", ", sizeof(cbuf));
1468*d39bd2c1SGregory Neil Shapiro }
1469*d39bd2c1SGregory Neil Shapiro if (mci != NULL)
1470*d39bd2c1SGregory Neil Shapiro {
1471*d39bd2c1SGregory Neil Shapiro if (mci->mci_state >= 0 && mci->mci_state < SM_ARRAY_SIZE(mcis))
1472*d39bd2c1SGregory Neil Shapiro sm_snprintf(buf, sizeof(buf),
1473*d39bd2c1SGregory Neil Shapiro "state=%s, ", mcis[mci->mci_state]);
1474*d39bd2c1SGregory Neil Shapiro else
1475*d39bd2c1SGregory Neil Shapiro sm_snprintf(buf, sizeof(buf),
1476*d39bd2c1SGregory Neil Shapiro "state=%d, ", mci->mci_state);
1477*d39bd2c1SGregory Neil Shapiro sm_strlcat(cbuf, buf, sizeof(cbuf));
1478*d39bd2c1SGregory Neil Shapiro }
1479*d39bd2c1SGregory Neil Shapiro if (tTd(11, 64))
1480*d39bd2c1SGregory Neil Shapiro {
1481*d39bd2c1SGregory Neil Shapiro sm_snprintf(buf, sizeof(buf),
1482*d39bd2c1SGregory Neil Shapiro "rcode=%d, okrcpts=%d, retryrcpt=%d, e_rcode=%d, ",
1483*d39bd2c1SGregory Neil Shapiro rcode, mci->mci_okrcpts, mci->mci_retryrcpt,
1484*d39bd2c1SGregory Neil Shapiro e->e_rcode);
1485*d39bd2c1SGregory Neil Shapiro sm_strlcat(cbuf, buf, sizeof(cbuf));
1486*d39bd2c1SGregory Neil Shapiro }
1487*d39bd2c1SGregory Neil Shapiro if (rcode != EX_OK && rcpt != NULL
1488*d39bd2c1SGregory Neil Shapiro && !SM_IS_EMPTY(rcpt->q_rstatus)
1489*d39bd2c1SGregory Neil Shapiro && !bitset(QINTREPLY, rcpt->q_flags))
1490*d39bd2c1SGregory Neil Shapiro {
1491*d39bd2c1SGregory Neil Shapiro sm_snprintf(buf, sizeof(buf),
1492*d39bd2c1SGregory Neil Shapiro "q_rstatus=%s, ", rcpt->q_rstatus);
1493*d39bd2c1SGregory Neil Shapiro sm_strlcat(cbuf, buf, sizeof(cbuf));
1494*d39bd2c1SGregory Neil Shapiro }
1495*d39bd2c1SGregory Neil Shapiro else if (e->e_text != NULL)
1496*d39bd2c1SGregory Neil Shapiro {
1497*d39bd2c1SGregory Neil Shapiro sm_snprintf(buf, sizeof(buf),
1498*d39bd2c1SGregory Neil Shapiro "reply=%d %s%s%s, ",
1499*d39bd2c1SGregory Neil Shapiro e->e_rcode,
1500*d39bd2c1SGregory Neil Shapiro e->e_renhsc,
1501*d39bd2c1SGregory Neil Shapiro (e->e_renhsc[0] != '\0') ? " " : "",
1502*d39bd2c1SGregory Neil Shapiro e->e_text);
1503*d39bd2c1SGregory Neil Shapiro sm_strlcat(cbuf, buf, sizeof(cbuf));
1504*d39bd2c1SGregory Neil Shapiro }
1505*d39bd2c1SGregory Neil Shapiro sm_strlcat(cbuf,
1506*d39bd2c1SGregory Neil Shapiro "stat=tempfail: trying next host",
1507*d39bd2c1SGregory Neil Shapiro sizeof(cbuf));
1508*d39bd2c1SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "%s", cbuf);
1509*d39bd2c1SGregory Neil Shapiro }
1510*d39bd2c1SGregory Neil Shapiro #else /* _FFR_LOG_FAILOVER */
1511*d39bd2c1SGregory Neil Shapiro # define logfailover(e, m, mci, rcode, rcpt) ((void) 0)
1512*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_LOG_FAILOVER */
1513*d39bd2c1SGregory Neil Shapiro
1514*d39bd2c1SGregory Neil Shapiro #if STARTTLS || SASL
1515*d39bd2c1SGregory Neil Shapiro # define RM_TRAIL_DOT(name) \
1516*d39bd2c1SGregory Neil Shapiro do { \
1517*d39bd2c1SGregory Neil Shapiro dotpos = strlen(name) - 1; \
1518*d39bd2c1SGregory Neil Shapiro if (dotpos >= 0) \
1519*d39bd2c1SGregory Neil Shapiro { \
1520*d39bd2c1SGregory Neil Shapiro if (name[dotpos] == '.') \
1521*d39bd2c1SGregory Neil Shapiro name[dotpos] = '\0'; \
1522*d39bd2c1SGregory Neil Shapiro else \
1523*d39bd2c1SGregory Neil Shapiro dotpos = -1; \
1524*d39bd2c1SGregory Neil Shapiro } \
1525*d39bd2c1SGregory Neil Shapiro } while (0)
1526*d39bd2c1SGregory Neil Shapiro
1527*d39bd2c1SGregory Neil Shapiro # define FIX_TRAIL_DOT(name) \
1528*d39bd2c1SGregory Neil Shapiro do { \
1529*d39bd2c1SGregory Neil Shapiro if (dotpos >= 0) \
1530*d39bd2c1SGregory Neil Shapiro name[dotpos] = '.'; \
1531*d39bd2c1SGregory Neil Shapiro } while (0)
1532*d39bd2c1SGregory Neil Shapiro
1533*d39bd2c1SGregory Neil Shapiro
1534*d39bd2c1SGregory Neil Shapiro /*
1535*d39bd2c1SGregory Neil Shapiro ** SETSERVERMACROS -- set ${server_addr} and ${server_name}
1536*d39bd2c1SGregory Neil Shapiro **
1537*d39bd2c1SGregory Neil Shapiro ** Parameters:
1538*d39bd2c1SGregory Neil Shapiro ** mci -- mailer connection information
1539*d39bd2c1SGregory Neil Shapiro ** pdotpos -- return pointer to former dot position in hostname
1540*d39bd2c1SGregory Neil Shapiro **
1541*d39bd2c1SGregory Neil Shapiro ** Returns:
1542*d39bd2c1SGregory Neil Shapiro ** server name
1543*d39bd2c1SGregory Neil Shapiro */
1544*d39bd2c1SGregory Neil Shapiro
1545*d39bd2c1SGregory Neil Shapiro static char *setservermacros __P((MCI *, int *));
1546*d39bd2c1SGregory Neil Shapiro
1547*d39bd2c1SGregory Neil Shapiro static char *
setservermacros(mci,pdotpos)1548*d39bd2c1SGregory Neil Shapiro setservermacros(mci, pdotpos)
1549*d39bd2c1SGregory Neil Shapiro MCI *mci;
1550*d39bd2c1SGregory Neil Shapiro int *pdotpos;
1551*d39bd2c1SGregory Neil Shapiro {
1552*d39bd2c1SGregory Neil Shapiro char *srvname;
1553*d39bd2c1SGregory Neil Shapiro int dotpos;
1554*d39bd2c1SGregory Neil Shapiro extern SOCKADDR CurHostAddr;
1555*d39bd2c1SGregory Neil Shapiro
1556*d39bd2c1SGregory Neil Shapiro /* don't use CurHostName, it is changed in many places */
1557*d39bd2c1SGregory Neil Shapiro if (mci->mci_host != NULL)
1558*d39bd2c1SGregory Neil Shapiro {
1559*d39bd2c1SGregory Neil Shapiro srvname = mci->mci_host;
1560*d39bd2c1SGregory Neil Shapiro RM_TRAIL_DOT(srvname);
1561*d39bd2c1SGregory Neil Shapiro }
1562*d39bd2c1SGregory Neil Shapiro else if (mci->mci_mailer != NULL)
1563*d39bd2c1SGregory Neil Shapiro {
1564*d39bd2c1SGregory Neil Shapiro srvname = mci->mci_mailer->m_name;
1565*d39bd2c1SGregory Neil Shapiro dotpos = -1;
1566*d39bd2c1SGregory Neil Shapiro }
1567*d39bd2c1SGregory Neil Shapiro else
1568*d39bd2c1SGregory Neil Shapiro {
1569*d39bd2c1SGregory Neil Shapiro srvname = "local";
1570*d39bd2c1SGregory Neil Shapiro dotpos = -1;
1571*d39bd2c1SGregory Neil Shapiro }
1572*d39bd2c1SGregory Neil Shapiro
1573*d39bd2c1SGregory Neil Shapiro /* don't set {server_name} to NULL or "": see getauth() */
1574*d39bd2c1SGregory Neil Shapiro macdefine(&mci->mci_macro, A_TEMP, macid("{server_name}"),
1575*d39bd2c1SGregory Neil Shapiro srvname);
1576*d39bd2c1SGregory Neil Shapiro
1577*d39bd2c1SGregory Neil Shapiro /* CurHostAddr is set by makeconnection() and mci_get() */
1578*d39bd2c1SGregory Neil Shapiro if (CurHostAddr.sa.sa_family != 0)
1579*d39bd2c1SGregory Neil Shapiro {
1580*d39bd2c1SGregory Neil Shapiro macdefine(&mci->mci_macro, A_TEMP,
1581*d39bd2c1SGregory Neil Shapiro macid("{server_addr}"),
1582*d39bd2c1SGregory Neil Shapiro anynet_ntoa(&CurHostAddr));
1583*d39bd2c1SGregory Neil Shapiro }
1584*d39bd2c1SGregory Neil Shapiro else if (mci->mci_mailer != NULL)
1585*d39bd2c1SGregory Neil Shapiro {
1586*d39bd2c1SGregory Neil Shapiro /* mailer name is unique, use it as address */
1587*d39bd2c1SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM,
1588*d39bd2c1SGregory Neil Shapiro macid("{server_addr}"),
1589*d39bd2c1SGregory Neil Shapiro mci->mci_mailer->m_name);
1590*d39bd2c1SGregory Neil Shapiro }
1591*d39bd2c1SGregory Neil Shapiro else
1592*d39bd2c1SGregory Neil Shapiro {
1593*d39bd2c1SGregory Neil Shapiro /* don't set it to NULL or "": see getauth() */
1594*d39bd2c1SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM,
1595*d39bd2c1SGregory Neil Shapiro macid("{server_addr}"), "0");
1596*d39bd2c1SGregory Neil Shapiro }
1597*d39bd2c1SGregory Neil Shapiro
1598*d39bd2c1SGregory Neil Shapiro if (pdotpos != NULL)
1599*d39bd2c1SGregory Neil Shapiro *pdotpos = dotpos;
1600*d39bd2c1SGregory Neil Shapiro else
1601*d39bd2c1SGregory Neil Shapiro FIX_TRAIL_DOT(srvname);
1602*d39bd2c1SGregory Neil Shapiro return srvname;
1603*d39bd2c1SGregory Neil Shapiro }
1604*d39bd2c1SGregory Neil Shapiro #endif /* STARTTLS || SASL */
16052fb4f839SGregory Neil Shapiro
16062fb4f839SGregory Neil Shapiro /*
1607c2aa98e2SPeter Wemm ** DELIVER -- Deliver a message to a list of addresses.
1608c2aa98e2SPeter Wemm **
1609c2aa98e2SPeter Wemm ** This routine delivers to everyone on the same host as the
1610c2aa98e2SPeter Wemm ** user on the head of the list. It is clever about mailers
1611c2aa98e2SPeter Wemm ** that don't handle multiple users. It is NOT guaranteed
1612c2aa98e2SPeter Wemm ** that it will deliver to all these addresses however -- so
16135b0945b5SGregory Neil Shapiro ** deliver should be called once for each address on the list.
161440266059SGregory Neil Shapiro ** Deliver tries to be as opportunistic as possible about piggybacking
161540266059SGregory Neil Shapiro ** messages. Some definitions to make understanding easier follow below.
161640266059SGregory Neil Shapiro ** Piggybacking occurs when an existing connection to a mail host can
161740266059SGregory Neil Shapiro ** be used to send the same message to more than one recipient at the
161840266059SGregory Neil Shapiro ** same time. So "no piggybacking" means one message for one recipient
161940266059SGregory Neil Shapiro ** per connection. "Intentional piggybacking" happens when the
162040266059SGregory Neil Shapiro ** recipients' host address (not the mail host address) is used to
162140266059SGregory Neil Shapiro ** attempt piggybacking. Recipients with the same host address
162240266059SGregory Neil Shapiro ** have the same mail host. "Coincidental piggybacking" relies on
162340266059SGregory Neil Shapiro ** piggybacking based on all the mail host addresses in the MX-RR. This
162440266059SGregory Neil Shapiro ** is "coincidental" in the fact it could not be predicted until the
162540266059SGregory Neil Shapiro ** MX Resource Records for the hosts were obtained and examined. For
162640266059SGregory Neil Shapiro ** example (preference order and equivalence is important, not values):
162740266059SGregory Neil Shapiro ** domain1 IN MX 10 mxhost-A
162840266059SGregory Neil Shapiro ** IN MX 20 mxhost-B
162940266059SGregory Neil Shapiro ** domain2 IN MX 4 mxhost-A
163040266059SGregory Neil Shapiro ** IN MX 8 mxhost-B
163140266059SGregory Neil Shapiro ** Domain1 and domain2 can piggyback the same message to mxhost-A or
163240266059SGregory Neil Shapiro ** mxhost-B (if mxhost-A cannot be reached).
163340266059SGregory Neil Shapiro ** "Coattail piggybacking" relaxes the strictness of "coincidental
163440266059SGregory Neil Shapiro ** piggybacking" in the hope that most significant (lowest value)
163540266059SGregory Neil Shapiro ** MX preference host(s) can create more piggybacking. For example
163640266059SGregory Neil Shapiro ** (again, preference order and equivalence is important, not values):
163740266059SGregory Neil Shapiro ** domain3 IN MX 100 mxhost-C
163840266059SGregory Neil Shapiro ** IN MX 100 mxhost-D
163940266059SGregory Neil Shapiro ** IN MX 200 mxhost-E
164040266059SGregory Neil Shapiro ** domain4 IN MX 50 mxhost-C
164140266059SGregory Neil Shapiro ** IN MX 50 mxhost-D
164240266059SGregory Neil Shapiro ** IN MX 80 mxhost-F
164340266059SGregory Neil Shapiro ** A message for domain3 and domain4 can piggyback to mxhost-C if mxhost-C
164440266059SGregory Neil Shapiro ** is available. Same with mxhost-D because in both RR's the preference
164540266059SGregory Neil Shapiro ** value is the same as mxhost-C, respectively.
164640266059SGregory Neil Shapiro ** So deliver attempts coattail piggybacking when possible. If the
164740266059SGregory Neil Shapiro ** first MX preference level hosts cannot be used then the piggybacking
164840266059SGregory Neil Shapiro ** reverts to coincidental piggybacking. Using the above example you
164940266059SGregory Neil Shapiro ** cannot deliver to mxhost-F for domain3 regardless of preference value.
165040266059SGregory Neil Shapiro ** ("Coattail" from "riding on the coattails of your predecessor" meaning
165140266059SGregory Neil Shapiro ** gaining benefit from a predecessor effort with no or little addition
165240266059SGregory Neil Shapiro ** effort. The predecessor here being the preceding MX RR).
1653c2aa98e2SPeter Wemm **
1654c2aa98e2SPeter Wemm ** Parameters:
1655c2aa98e2SPeter Wemm ** e -- the envelope to deliver.
1656c2aa98e2SPeter Wemm ** firstto -- head of the address list to deliver to.
1657c2aa98e2SPeter Wemm **
1658c2aa98e2SPeter Wemm ** Returns:
1659c2aa98e2SPeter Wemm ** zero -- successfully delivered.
1660c2aa98e2SPeter Wemm ** else -- some failure, see ExitStat for more info.
1661c2aa98e2SPeter Wemm **
1662c2aa98e2SPeter Wemm ** Side Effects:
1663c2aa98e2SPeter Wemm ** The standard input is passed off to someone.
1664c2aa98e2SPeter Wemm */
1665c2aa98e2SPeter Wemm
1666*d39bd2c1SGregory Neil Shapiro #if !_FFR_DMTRIGGER
1667*d39bd2c1SGregory Neil Shapiro static
1668*d39bd2c1SGregory Neil Shapiro #endif
1669*d39bd2c1SGregory Neil Shapiro int
deliver(e,firstto)1670c2aa98e2SPeter Wemm deliver(e, firstto)
1671c2aa98e2SPeter Wemm register ENVELOPE *e;
1672c2aa98e2SPeter Wemm ADDRESS *firstto;
1673c2aa98e2SPeter Wemm {
1674c2aa98e2SPeter Wemm char *host; /* host being sent to */
1675c2aa98e2SPeter Wemm char *user; /* user being sent to */
1676c2aa98e2SPeter Wemm char **pvp;
1677c2aa98e2SPeter Wemm register char **mvp;
1678c2aa98e2SPeter Wemm register char *p;
1679c2aa98e2SPeter Wemm register MAILER *m; /* mailer for this recipient */
1680c2aa98e2SPeter Wemm ADDRESS *volatile ctladdr;
168140266059SGregory Neil Shapiro #if HASSETUSERCONTEXT
1682c2aa98e2SPeter Wemm ADDRESS *volatile contextaddr = NULL;
16835b0945b5SGregory Neil Shapiro #endif
1684c2aa98e2SPeter Wemm register MCI *volatile mci;
168540266059SGregory Neil Shapiro register ADDRESS *SM_NONVOLATILE to = firstto;
168640266059SGregory Neil Shapiro volatile bool clever = false; /* running user smtp to this mailer */
1687c2aa98e2SPeter Wemm ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */
1688c2aa98e2SPeter Wemm int rcode; /* response code */
168940266059SGregory Neil Shapiro SM_NONVOLATILE int lmtp_rcode = EX_OK;
169040266059SGregory Neil Shapiro SM_NONVOLATILE int nummxhosts = 0; /* number of MX hosts available */
169140266059SGregory Neil Shapiro SM_NONVOLATILE int hostnum = 0; /* current MX host index */
1692c2aa98e2SPeter Wemm char *firstsig; /* signature of firstto */
169340266059SGregory Neil Shapiro volatile pid_t pid = -1;
1694c2aa98e2SPeter Wemm char *volatile curhost;
169540266059SGregory Neil Shapiro SM_NONVOLATILE unsigned short port = 0;
169640266059SGregory Neil Shapiro SM_NONVOLATILE time_t enough = 0;
169706f25ae9SGregory Neil Shapiro #if NETUNIX
169840266059SGregory Neil Shapiro char *SM_NONVOLATILE mux_path = NULL; /* path to UNIX domain socket */
16995b0945b5SGregory Neil Shapiro #endif
1700c2aa98e2SPeter Wemm time_t xstart;
1701c2aa98e2SPeter Wemm bool suidwarn;
1702c2aa98e2SPeter Wemm bool anyok; /* at least one address was OK */
170340266059SGregory Neil Shapiro SM_NONVOLATILE bool goodmxfound = false; /* at least one MX was OK */
170406f25ae9SGregory Neil Shapiro bool ovr;
170540266059SGregory Neil Shapiro bool quarantine;
17065b0945b5SGregory Neil Shapiro #if STARTTLS
1707*d39bd2c1SGregory Neil Shapiro bool implicittls = false;
1708*d39bd2c1SGregory Neil Shapiro # if _FFR_SMTPS_CLIENT
1709*d39bd2c1SGregory Neil Shapiro bool smtptls = false;
1710*d39bd2c1SGregory Neil Shapiro # endif
17115b0945b5SGregory Neil Shapiro /* 0: try TLS, 1: try without TLS again, >1: don't try again */
17125b0945b5SGregory Neil Shapiro int tlsstate;
17135b0945b5SGregory Neil Shapiro # if DANE
17145b0945b5SGregory Neil Shapiro dane_vrfy_ctx_T dane_vrfy_ctx;
17155b0945b5SGregory Neil Shapiro STAB *ste;
1716*d39bd2c1SGregory Neil Shapiro char *vrfy;
1717*d39bd2c1SGregory Neil Shapiro int dane_req;
17185b0945b5SGregory Neil Shapiro
1719*d39bd2c1SGregory Neil Shapiro /* should this allow DANE_ALWAYS == DANEMODE(dane)? */
1720*d39bd2c1SGregory Neil Shapiro # define RCPT_MXSECURE(rcpt) (0 != ((rcpt)->q_flags & QMXSECURE))
17215b0945b5SGregory Neil Shapiro
1722*d39bd2c1SGregory Neil Shapiro # define STE_HAS_TLSA(ste) ((ste) != NULL && (ste)->s_tlsa != NULL)
17235b0945b5SGregory Neil Shapiro
1724*d39bd2c1SGregory Neil Shapiro /* NOTE: the following macros use some local variables directly! */
1725*d39bd2c1SGregory Neil Shapiro # define RCPT_HAS_DANE(rcpt) (RCPT_MXSECURE(rcpt) \
1726*d39bd2c1SGregory Neil Shapiro && !iscltflgset(e, D_NODANE) \
1727*d39bd2c1SGregory Neil Shapiro && STE_HAS_TLSA(ste) \
1728*d39bd2c1SGregory Neil Shapiro && (0 == (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLTEMPVRFY)) \
1729*d39bd2c1SGregory Neil Shapiro && (0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLADIP)) \
1730*d39bd2c1SGregory Neil Shapiro && CHK_DANE(dane_vrfy_ctx.dane_vrfy_chk) \
1731*d39bd2c1SGregory Neil Shapiro )
1732*d39bd2c1SGregory Neil Shapiro
1733*d39bd2c1SGregory Neil Shapiro # define RCPT_REQ_DANE(rcpt) (RCPT_HAS_DANE(rcpt) \
1734*d39bd2c1SGregory Neil Shapiro && TLSA_IS_FL(ste->s_tlsa, TLSAFLSUP))
1735*d39bd2c1SGregory Neil Shapiro
1736*d39bd2c1SGregory Neil Shapiro # define RCPT_REQ_TLS(rcpt) (RCPT_HAS_DANE(rcpt) \
1737*d39bd2c1SGregory Neil Shapiro && TLSA_IS_FL(ste->s_tlsa, TLSAFLUNS))
1738*d39bd2c1SGregory Neil Shapiro
1739*d39bd2c1SGregory Neil Shapiro # define CHK_DANE_RCPT(dane, rcpt) (CHK_DANE(dane) && \
1740*d39bd2c1SGregory Neil Shapiro (RCPT_MXSECURE(rcpt) || DANE_ALWAYS == DANEMODE(dane)))
1741*d39bd2c1SGregory Neil Shapiro
1742*d39bd2c1SGregory Neil Shapiro BITMAP256 mxads;
1743*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
1744*d39bd2c1SGregory Neil Shapiro #endif /* STARTTLS */
174506f25ae9SGregory Neil Shapiro int strsize;
174606f25ae9SGregory Neil Shapiro int rcptcount;
174740266059SGregory Neil Shapiro int ret;
174806f25ae9SGregory Neil Shapiro static int tobufsize = 0;
174906f25ae9SGregory Neil Shapiro static char *tobuf = NULL;
175040266059SGregory Neil Shapiro char *rpath; /* translated return path */
1751c2aa98e2SPeter Wemm int mpvect[2];
1752c2aa98e2SPeter Wemm int rpvect[2];
175306f25ae9SGregory Neil Shapiro char *mxhosts[MAXMXHOSTS + 1];
1754c2aa98e2SPeter Wemm char *pv[MAXPV + 1];
17552fb4f839SGregory Neil Shapiro char buf[MAXNAME + 1]; /* EAI:ok */
175694c01205SGregory Neil Shapiro char cbuf[MAXPATHLEN];
1757*d39bd2c1SGregory Neil Shapiro #if _FFR_8BITENVADDR
1758*d39bd2c1SGregory Neil Shapiro char xbuf[SM_MAX(SYSLOG_BUFSIZE, MAXNAME)];
1759*d39bd2c1SGregory Neil Shapiro #endif
1760c2aa98e2SPeter Wemm
1761c2aa98e2SPeter Wemm errno = 0;
1762d0cef73dSGregory Neil Shapiro SM_REQUIRE(firstto != NULL); /* same as to */
176306f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state))
176406f25ae9SGregory Neil Shapiro return 0;
1765c2aa98e2SPeter Wemm
1766c2aa98e2SPeter Wemm suidwarn = geteuid() == 0;
1767c2aa98e2SPeter Wemm
1768d0cef73dSGregory Neil Shapiro SM_REQUIRE(e != NULL);
1769c2aa98e2SPeter Wemm m = to->q_mailer;
1770c2aa98e2SPeter Wemm host = to->q_host;
1771c2aa98e2SPeter Wemm CurEnv = e; /* just in case */
1772c2aa98e2SPeter Wemm e->e_statmsg = NULL;
1773c2aa98e2SPeter Wemm SmtpError[0] = '\0';
1774c2aa98e2SPeter Wemm xstart = curtime();
17755b0945b5SGregory Neil Shapiro #if STARTTLS
17765b0945b5SGregory Neil Shapiro tlsstate = 0;
17775b0945b5SGregory Neil Shapiro # if DANE
17785b0945b5SGregory Neil Shapiro memset(&dane_vrfy_ctx, '\0', sizeof(dane_vrfy_ctx));
17795b0945b5SGregory Neil Shapiro ste = NULL;
17805b0945b5SGregory Neil Shapiro # endif
17815b0945b5SGregory Neil Shapiro #endif
1782c2aa98e2SPeter Wemm
1783c2aa98e2SPeter Wemm if (tTd(10, 1))
178440266059SGregory Neil Shapiro sm_dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
1785c2aa98e2SPeter Wemm e->e_id, m->m_name, host, to->q_user);
1786c2aa98e2SPeter Wemm if (tTd(10, 100))
178740266059SGregory Neil Shapiro printopenfds(false);
1788*d39bd2c1SGregory Neil Shapiro maps_reset_chged("deliver");
1789c2aa98e2SPeter Wemm
1790c2aa98e2SPeter Wemm /*
179140266059SGregory Neil Shapiro ** Clear {client_*} macros if this is a bounce message to
1792c2aa98e2SPeter Wemm ** prevent rejection by check_compat ruleset.
1793c2aa98e2SPeter Wemm */
1794c2aa98e2SPeter Wemm
1795c2aa98e2SPeter Wemm if (bitset(EF_RESPONSE, e->e_flags))
1796c2aa98e2SPeter Wemm {
179740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_name}"), "");
1798e92d3f3fSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_ptr}"), "");
179940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_addr}"), "");
180040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_port}"), "");
180140266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_resolve}"), "");
1802c2aa98e2SPeter Wemm }
1803c2aa98e2SPeter Wemm
180440266059SGregory Neil Shapiro SM_TRY
180540266059SGregory Neil Shapiro {
180640266059SGregory Neil Shapiro ADDRESS *skip_back = NULL;
180740266059SGregory Neil Shapiro
1808c2aa98e2SPeter Wemm /*
1809c2aa98e2SPeter Wemm ** Do initial argv setup.
1810c2aa98e2SPeter Wemm ** Insert the mailer name. Notice that $x expansion is
1811c2aa98e2SPeter Wemm ** NOT done on the mailer name. Then, if the mailer has
1812c2aa98e2SPeter Wemm ** a picky -f flag, we insert it as appropriate. This
1813c2aa98e2SPeter Wemm ** code does not check for 'pv' overflow; this places a
1814c2aa98e2SPeter Wemm ** manifest lower limit of 4 for MAXPV.
1815c2aa98e2SPeter Wemm ** The from address rewrite is expected to make
1816c2aa98e2SPeter Wemm ** the address relative to the other end.
1817c2aa98e2SPeter Wemm */
1818c2aa98e2SPeter Wemm
1819c2aa98e2SPeter Wemm /* rewrite from address, using rewriting rules */
1820c2aa98e2SPeter Wemm rcode = EX_OK;
1821d0cef73dSGregory Neil Shapiro SM_ASSERT(e->e_from.q_mailer != NULL);
1822c2aa98e2SPeter Wemm if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
1823c2aa98e2SPeter Wemm p = e->e_sender;
1824c2aa98e2SPeter Wemm else
1825c2aa98e2SPeter Wemm p = e->e_from.q_paddr;
182640266059SGregory Neil Shapiro rpath = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e);
1827da7d7b9cSGregory Neil Shapiro if (rcode != EX_OK && bitnset(M_xSMTP, m->m_flags))
1828da7d7b9cSGregory Neil Shapiro goto cleanup;
18292fb4f839SGregory Neil Shapiro
18302fb4f839SGregory Neil Shapiro /* need to check external format, not internal! */
18312fb4f839SGregory Neil Shapiro if (strlen(rpath) > MAXNAME_I)
1832c2aa98e2SPeter Wemm {
183340266059SGregory Neil Shapiro rpath = shortenstring(rpath, MAXSHORTSTR);
183440266059SGregory Neil Shapiro
183540266059SGregory Neil Shapiro /* avoid bogus errno */
183640266059SGregory Neil Shapiro errno = 0;
183740266059SGregory Neil Shapiro syserr("remotename: huge return path %s", rpath);
1838c2aa98e2SPeter Wemm }
183940266059SGregory Neil Shapiro rpath = sm_rpool_strdup_x(e->e_rpool, rpath);
184040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', rpath);
1841*d39bd2c1SGregory Neil Shapiro #if _FFR_8BITENVADDR
1842*d39bd2c1SGregory Neil Shapiro host = quote_internal_chars(host, NULL, &strsize, NULL);
1843*d39bd2c1SGregory Neil Shapiro #endif
184440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', host);
1845c2aa98e2SPeter Wemm Errors = 0;
1846c2aa98e2SPeter Wemm pvp = pv;
1847c2aa98e2SPeter Wemm *pvp++ = m->m_argv[0];
1848c2aa98e2SPeter Wemm
1849e92d3f3fSGregory Neil Shapiro /* ignore long term host status information if mailer flag W is set */
1850e92d3f3fSGregory Neil Shapiro if (bitnset(M_NOHOSTSTAT, m->m_flags))
1851e92d3f3fSGregory Neil Shapiro IgnoreHostStatus = true;
1852e92d3f3fSGregory Neil Shapiro
1853c2aa98e2SPeter Wemm /* insert -f or -r flag as appropriate */
185406f25ae9SGregory Neil Shapiro if (FromFlag &&
185506f25ae9SGregory Neil Shapiro (bitnset(M_FOPT, m->m_flags) ||
185606f25ae9SGregory Neil Shapiro bitnset(M_ROPT, m->m_flags)))
1857c2aa98e2SPeter Wemm {
1858c2aa98e2SPeter Wemm if (bitnset(M_FOPT, m->m_flags))
1859c2aa98e2SPeter Wemm *pvp++ = "-f";
1860c2aa98e2SPeter Wemm else
1861c2aa98e2SPeter Wemm *pvp++ = "-r";
186240266059SGregory Neil Shapiro *pvp++ = rpath;
1863c2aa98e2SPeter Wemm }
1864c2aa98e2SPeter Wemm
1865c2aa98e2SPeter Wemm /*
1866c2aa98e2SPeter Wemm ** Append the other fixed parts of the argv. These run
1867c2aa98e2SPeter Wemm ** up to the first entry containing "$u". There can only
1868c2aa98e2SPeter Wemm ** be one of these, and there are only a few more slots
1869c2aa98e2SPeter Wemm ** in the pv after it.
1870c2aa98e2SPeter Wemm */
1871c2aa98e2SPeter Wemm
1872c2aa98e2SPeter Wemm for (mvp = m->m_argv; (p = *++mvp) != NULL; )
1873c2aa98e2SPeter Wemm {
1874c2aa98e2SPeter Wemm /* can't use strchr here because of sign extension problems */
1875c2aa98e2SPeter Wemm while (*p != '\0')
1876c2aa98e2SPeter Wemm {
1877c2aa98e2SPeter Wemm if ((*p++ & 0377) == MACROEXPAND)
1878c2aa98e2SPeter Wemm {
1879c2aa98e2SPeter Wemm if (*p == 'u')
1880c2aa98e2SPeter Wemm break;
1881c2aa98e2SPeter Wemm }
1882c2aa98e2SPeter Wemm }
1883c2aa98e2SPeter Wemm
1884c2aa98e2SPeter Wemm if (*p != '\0')
1885c2aa98e2SPeter Wemm break;
1886c2aa98e2SPeter Wemm
1887c2aa98e2SPeter Wemm /* this entry is safe -- go ahead and process it */
1888d0cef73dSGregory Neil Shapiro expand(*mvp, buf, sizeof(buf), e);
1889*d39bd2c1SGregory Neil Shapiro p = buf;
1890*d39bd2c1SGregory Neil Shapiro #if _FFR_8BITENVADDR
1891*d39bd2c1SGregory Neil Shapiro /* apply to all args? */
1892*d39bd2c1SGregory Neil Shapiro if (strcmp(m->m_mailer, "[IPC]") == 0
1893*d39bd2c1SGregory Neil Shapiro && ((*mvp)[0] & 0377) == MACROEXPAND
1894*d39bd2c1SGregory Neil Shapiro /* for now only apply [i] -> [x] conversion to $h by default */
1895*d39bd2c1SGregory Neil Shapiro # ifndef _FFR_H2X_ONLY
1896*d39bd2c1SGregory Neil Shapiro # define _FFR_H2X_ONLY 1
1897*d39bd2c1SGregory Neil Shapiro # endif
1898*d39bd2c1SGregory Neil Shapiro # if _FFR_H2X_ONLY
1899*d39bd2c1SGregory Neil Shapiro && 'h' == (*mvp)[1] && '\0' == (*mvp)[2]
1900*d39bd2c1SGregory Neil Shapiro # endif
1901*d39bd2c1SGregory Neil Shapiro )
1902*d39bd2c1SGregory Neil Shapiro {
1903*d39bd2c1SGregory Neil Shapiro (void) dequote_internal_chars(buf, xbuf, sizeof(xbuf));
1904*d39bd2c1SGregory Neil Shapiro p = xbuf;
1905*d39bd2c1SGregory Neil Shapiro if (tTd(10, 33))
1906*d39bd2c1SGregory Neil Shapiro sm_dprintf("expand(%s), dequoted=%s\n", *mvp, p);
1907*d39bd2c1SGregory Neil Shapiro }
1908*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_8BITENVADDR */
1909*d39bd2c1SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, p);
1910c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV - 3])
1911c2aa98e2SPeter Wemm {
191206f25ae9SGregory Neil Shapiro syserr("554 5.3.5 Too many parameters to %s before $u",
191306f25ae9SGregory Neil Shapiro pv[0]);
191440266059SGregory Neil Shapiro rcode = -1;
191540266059SGregory Neil Shapiro goto cleanup;
1916c2aa98e2SPeter Wemm }
1917c2aa98e2SPeter Wemm }
1918c2aa98e2SPeter Wemm
1919c2aa98e2SPeter Wemm /*
1920c2aa98e2SPeter Wemm ** If we have no substitution for the user name in the argument
1921c2aa98e2SPeter Wemm ** list, we know that we must supply the names otherwise -- and
1922c2aa98e2SPeter Wemm ** SMTP is the answer!!
1923c2aa98e2SPeter Wemm */
1924c2aa98e2SPeter Wemm
1925c2aa98e2SPeter Wemm if (*mvp == NULL)
1926c2aa98e2SPeter Wemm {
1927602a2b1bSGregory Neil Shapiro /* running LMTP or SMTP */
192840266059SGregory Neil Shapiro clever = true;
1929c2aa98e2SPeter Wemm *pvp = NULL;
1930da7d7b9cSGregory Neil Shapiro setbitn(M_xSMTP, m->m_flags);
1931c2aa98e2SPeter Wemm }
1932602a2b1bSGregory Neil Shapiro else if (bitnset(M_LMTP, m->m_flags))
1933602a2b1bSGregory Neil Shapiro {
1934602a2b1bSGregory Neil Shapiro /* not running LMTP */
1935602a2b1bSGregory Neil Shapiro sm_syslog(LOG_ERR, NULL,
1936602a2b1bSGregory Neil Shapiro "Warning: mailer %s: LMTP flag (F=z) turned off",
1937602a2b1bSGregory Neil Shapiro m->m_name);
1938602a2b1bSGregory Neil Shapiro clrbitn(M_LMTP, m->m_flags);
1939602a2b1bSGregory Neil Shapiro }
1940c2aa98e2SPeter Wemm
1941c2aa98e2SPeter Wemm /*
1942c2aa98e2SPeter Wemm ** At this point *mvp points to the argument with $u. We
1943c2aa98e2SPeter Wemm ** run through our address list and append all the addresses
1944c2aa98e2SPeter Wemm ** we can. If we run out of space, do not fret! We can
1945c2aa98e2SPeter Wemm ** always send another copy later.
1946c2aa98e2SPeter Wemm */
1947c2aa98e2SPeter Wemm
194806f25ae9SGregory Neil Shapiro e->e_to = NULL;
194906f25ae9SGregory Neil Shapiro strsize = 2;
195006f25ae9SGregory Neil Shapiro rcptcount = 0;
1951c2aa98e2SPeter Wemm ctladdr = NULL;
195240266059SGregory Neil Shapiro if (firstto->q_signature == NULL)
195340266059SGregory Neil Shapiro firstto->q_signature = hostsignature(firstto->q_mailer,
19545b0945b5SGregory Neil Shapiro firstto->q_host,
1955*d39bd2c1SGregory Neil Shapiro QISSECURE(firstto),
1956*d39bd2c1SGregory Neil Shapiro &firstto->q_flags);
195740266059SGregory Neil Shapiro firstsig = firstto->q_signature;
1958*d39bd2c1SGregory Neil Shapiro #if DANE
1959*d39bd2c1SGregory Neil Shapiro # define NODANEREQYET (-1)
1960*d39bd2c1SGregory Neil Shapiro dane_req = NODANEREQYET;
1961*d39bd2c1SGregory Neil Shapiro #endif
196240266059SGregory Neil Shapiro
1963c2aa98e2SPeter Wemm for (; to != NULL; to = to->q_next)
1964c2aa98e2SPeter Wemm {
1965c2aa98e2SPeter Wemm /* avoid sending multiple recipients to dumb mailers */
196606f25ae9SGregory Neil Shapiro if (tochain != NULL && !bitnset(M_MUSER, m->m_flags))
196706f25ae9SGregory Neil Shapiro break;
1968c2aa98e2SPeter Wemm
1969c2aa98e2SPeter Wemm /* if already sent or not for this host, don't send */
197040266059SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) /* already sent; look at next */
1971c2aa98e2SPeter Wemm continue;
1972c2aa98e2SPeter Wemm
197340266059SGregory Neil Shapiro /*
197440266059SGregory Neil Shapiro ** Must be same mailer to keep grouping rcpts.
197540266059SGregory Neil Shapiro ** If mailers don't match: continue; sendqueue is not
197640266059SGregory Neil Shapiro ** sorted by mailers, so don't break;
197740266059SGregory Neil Shapiro */
197840266059SGregory Neil Shapiro
197940266059SGregory Neil Shapiro if (to->q_mailer != firstto->q_mailer)
198040266059SGregory Neil Shapiro continue;
198140266059SGregory Neil Shapiro
198240266059SGregory Neil Shapiro if (to->q_signature == NULL) /* for safety */
198340266059SGregory Neil Shapiro to->q_signature = hostsignature(to->q_mailer,
19845b0945b5SGregory Neil Shapiro to->q_host,
1985*d39bd2c1SGregory Neil Shapiro QISSECURE(to),
1986*d39bd2c1SGregory Neil Shapiro &to->q_flags);
198740266059SGregory Neil Shapiro
198840266059SGregory Neil Shapiro /*
198940266059SGregory Neil Shapiro ** This is for coincidental and tailcoat piggybacking messages
199040266059SGregory Neil Shapiro ** to the same mail host. While the signatures are identical
199140266059SGregory Neil Shapiro ** (that's the MX-RR's are identical) we can do coincidental
199240266059SGregory Neil Shapiro ** piggybacking. We try hard for coattail piggybacking
199340266059SGregory Neil Shapiro ** with the same mail host when the next recipient has the
199440266059SGregory Neil Shapiro ** same host at lowest preference. It may be that this
199540266059SGregory Neil Shapiro ** won't work out, so 'skip_back' is maintained if a backup
199640266059SGregory Neil Shapiro ** to coincidental piggybacking or full signature must happen.
199740266059SGregory Neil Shapiro */
199840266059SGregory Neil Shapiro
199940266059SGregory Neil Shapiro ret = firstto == to ? HS_MATCH_FULL :
200040266059SGregory Neil Shapiro coloncmp(to->q_signature, firstsig);
200140266059SGregory Neil Shapiro if (ret == HS_MATCH_FULL)
200240266059SGregory Neil Shapiro skip_back = to;
200340266059SGregory Neil Shapiro else if (ret == HS_MATCH_NO)
200406f25ae9SGregory Neil Shapiro break;
2005*d39bd2c1SGregory Neil Shapiro # if HSMARKS
2006*d39bd2c1SGregory Neil Shapiro else if (ret == HS_MATCH_SKIP)
2007*d39bd2c1SGregory Neil Shapiro continue;
2008*d39bd2c1SGregory Neil Shapiro # endif
200906f25ae9SGregory Neil Shapiro
201040266059SGregory Neil Shapiro if (!clever)
201140266059SGregory Neil Shapiro {
201240266059SGregory Neil Shapiro /* avoid overflowing tobuf */
201340266059SGregory Neil Shapiro strsize += strlen(to->q_paddr) + 1;
201440266059SGregory Neil Shapiro if (strsize > TOBUFSIZE)
201540266059SGregory Neil Shapiro break;
201640266059SGregory Neil Shapiro }
201740266059SGregory Neil Shapiro
201806f25ae9SGregory Neil Shapiro if (++rcptcount > to->q_mailer->m_maxrcpt)
201906f25ae9SGregory Neil Shapiro break;
2020c2aa98e2SPeter Wemm
2021*d39bd2c1SGregory Neil Shapiro #if DANE
2022*d39bd2c1SGregory Neil Shapiro if (TTD(10, 30))
2023*d39bd2c1SGregory Neil Shapiro {
2024*d39bd2c1SGregory Neil Shapiro char sep = ':';
2025*d39bd2c1SGregory Neil Shapiro
2026*d39bd2c1SGregory Neil Shapiro parse_hostsignature(to->q_signature, mxhosts, m, mxads);
2027*d39bd2c1SGregory Neil Shapiro FIX_MXHOSTS(mxhosts[0], p, sep);
2028*d39bd2c1SGregory Neil Shapiro # if HSMARKS
2029*d39bd2c1SGregory Neil Shapiro if (MXADS_ISSET(mxads, 0))
2030*d39bd2c1SGregory Neil Shapiro to->q_flags |= QMXSECURE;
2031*d39bd2c1SGregory Neil Shapiro else
2032*d39bd2c1SGregory Neil Shapiro to->q_flags &= ~QMXSECURE;
2033*d39bd2c1SGregory Neil Shapiro # endif
2034*d39bd2c1SGregory Neil Shapiro
2035*d39bd2c1SGregory Neil Shapiro gettlsa(mxhosts[0], NULL, &ste, RCPT_MXSECURE(to) ? TLSAFLADMX : 0, 0, m->m_port);
2036*d39bd2c1SGregory Neil Shapiro sm_dprintf("tochain: to=%s, rcptcount=%d, QSECURE=%d, QMXSECURE=%d, MXADS[0]=%d, ste=%p\n",
2037*d39bd2c1SGregory Neil Shapiro to->q_user, rcptcount, QISSECURE(to),
2038*d39bd2c1SGregory Neil Shapiro RCPT_MXSECURE(to), MXADS_ISSET(mxads, 0), ste);
2039*d39bd2c1SGregory Neil Shapiro sm_dprintf("tochain: hostsig=%s, mx=%s, tlsa_n=%d, tlsa_flags=%#lx, chk_dane=%d, dane_req=%d\n"
2040*d39bd2c1SGregory Neil Shapiro , to->q_signature, mxhosts[0]
2041*d39bd2c1SGregory Neil Shapiro , STE_HAS_TLSA(ste) ? ste->s_tlsa->dane_tlsa_n : -1
2042*d39bd2c1SGregory Neil Shapiro , STE_HAS_TLSA(ste) ? ste->s_tlsa->dane_tlsa_flags : -1
2043*d39bd2c1SGregory Neil Shapiro , CHK_DANE_RCPT(Dane, to)
2044*d39bd2c1SGregory Neil Shapiro , dane_req
2045*d39bd2c1SGregory Neil Shapiro );
2046*d39bd2c1SGregory Neil Shapiro if (p != NULL)
2047*d39bd2c1SGregory Neil Shapiro *p = sep;
2048*d39bd2c1SGregory Neil Shapiro }
2049*d39bd2c1SGregory Neil Shapiro if (NODANEREQYET == dane_req)
2050*d39bd2c1SGregory Neil Shapiro dane_req = CHK_DANE_RCPT(Dane, to);
2051*d39bd2c1SGregory Neil Shapiro else if (dane_req != CHK_DANE_RCPT(Dane, to))
2052*d39bd2c1SGregory Neil Shapiro {
2053*d39bd2c1SGregory Neil Shapiro if (tTd(10, 30))
2054*d39bd2c1SGregory Neil Shapiro sm_dprintf("tochain: to=%s, rcptcount=%d, status=skip\n",
2055*d39bd2c1SGregory Neil Shapiro to->q_user, rcptcount);
2056*d39bd2c1SGregory Neil Shapiro continue;
2057*d39bd2c1SGregory Neil Shapiro }
2058*d39bd2c1SGregory Neil Shapiro #endif /* DANE */
2059*d39bd2c1SGregory Neil Shapiro
20602fb4f839SGregory Neil Shapiro /*
20612fb4f839SGregory Neil Shapiro ** prepare envelope for new session to avoid leakage
20622fb4f839SGregory Neil Shapiro ** between delivery attempts.
20632fb4f839SGregory Neil Shapiro */
20642fb4f839SGregory Neil Shapiro
20652fb4f839SGregory Neil Shapiro smtpclrse(e);
20662fb4f839SGregory Neil Shapiro
2067c2aa98e2SPeter Wemm if (tTd(10, 1))
2068c2aa98e2SPeter Wemm {
206940266059SGregory Neil Shapiro sm_dprintf("\nsend to ");
2070e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), to, false);
2071c2aa98e2SPeter Wemm }
2072c2aa98e2SPeter Wemm
2073c2aa98e2SPeter Wemm /* compute effective uid/gid when sending */
2074c2aa98e2SPeter Wemm if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags))
207540266059SGregory Neil Shapiro #if HASSETUSERCONTEXT
2076c2aa98e2SPeter Wemm contextaddr = ctladdr = getctladdr(to);
20775b0945b5SGregory Neil Shapiro #else
207840266059SGregory Neil Shapiro ctladdr = getctladdr(to);
20795b0945b5SGregory Neil Shapiro #endif
2080c2aa98e2SPeter Wemm
2081c2aa98e2SPeter Wemm if (tTd(10, 2))
2082c2aa98e2SPeter Wemm {
208340266059SGregory Neil Shapiro sm_dprintf("ctladdr=");
2084e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), ctladdr, false);
2085c2aa98e2SPeter Wemm }
2086c2aa98e2SPeter Wemm
2087c2aa98e2SPeter Wemm user = to->q_user;
2088c2aa98e2SPeter Wemm e->e_to = to->q_paddr;
2089c2aa98e2SPeter Wemm
2090c2aa98e2SPeter Wemm /*
2091c2aa98e2SPeter Wemm ** Check to see that these people are allowed to
2092c2aa98e2SPeter Wemm ** talk to each other.
209342e5d165SGregory Neil Shapiro ** Check also for overflow of e_msgsize.
2094c2aa98e2SPeter Wemm */
2095c2aa98e2SPeter Wemm
209642e5d165SGregory Neil Shapiro if (m->m_maxsize != 0 &&
209742e5d165SGregory Neil Shapiro (e->e_msgsize > m->m_maxsize || e->e_msgsize < 0))
2098c2aa98e2SPeter Wemm {
2099c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN;
2100c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags))
2101c2aa98e2SPeter Wemm to->q_status = "5.2.3";
2102c2aa98e2SPeter Wemm else
2103c2aa98e2SPeter Wemm to->q_status = "5.3.4";
210440266059SGregory Neil Shapiro
210506f25ae9SGregory Neil Shapiro /* set to->q_rstatus = NULL; or to the following? */
210606f25ae9SGregory Neil Shapiro usrerrenh(to->q_status,
210706f25ae9SGregory Neil Shapiro "552 Message is too large; %ld bytes max",
210806f25ae9SGregory Neil Shapiro m->m_maxsize);
210940266059SGregory Neil Shapiro markfailure(e, to, NULL, EX_UNAVAILABLE, false);
211006f25ae9SGregory Neil Shapiro giveresponse(EX_UNAVAILABLE, to->q_status, m,
211140266059SGregory Neil Shapiro NULL, ctladdr, xstart, e, to);
2112c2aa98e2SPeter Wemm continue;
2113c2aa98e2SPeter Wemm }
2114602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0);
211540266059SGregory Neil Shapiro ovr = true;
2116c2aa98e2SPeter Wemm
2117c2aa98e2SPeter Wemm /* do config file checking of compatibility */
211840266059SGregory Neil Shapiro quarantine = (e->e_quarmsg != NULL);
211906f25ae9SGregory Neil Shapiro rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr,
2120959366dcSGregory Neil Shapiro e, RSF_RMCOMM|RSF_COUNT, 3, NULL,
2121da7d7b9cSGregory Neil Shapiro e->e_id, NULL, NULL);
2122c2aa98e2SPeter Wemm if (rcode == EX_OK)
2123c2aa98e2SPeter Wemm {
2124065a643dSPeter Wemm /* do in-code checking if not discarding */
2125065a643dSPeter Wemm if (!bitset(EF_DISCARD, e->e_flags))
212606f25ae9SGregory Neil Shapiro {
2127c2aa98e2SPeter Wemm rcode = checkcompat(to, e);
212840266059SGregory Neil Shapiro ovr = false;
212906f25ae9SGregory Neil Shapiro }
2130c2aa98e2SPeter Wemm }
2131c2aa98e2SPeter Wemm if (rcode != EX_OK)
2132c2aa98e2SPeter Wemm {
213306f25ae9SGregory Neil Shapiro markfailure(e, to, NULL, rcode, ovr);
213406f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m,
213540266059SGregory Neil Shapiro NULL, ctladdr, xstart, e, to);
2136c2aa98e2SPeter Wemm continue;
2137c2aa98e2SPeter Wemm }
213840266059SGregory Neil Shapiro if (!quarantine && e->e_quarmsg != NULL)
213940266059SGregory Neil Shapiro {
214040266059SGregory Neil Shapiro /*
214140266059SGregory Neil Shapiro ** check_compat or checkcompat() has tried
214240266059SGregory Neil Shapiro ** to quarantine but that isn't supported.
214340266059SGregory Neil Shapiro ** Revert the attempt.
214440266059SGregory Neil Shapiro */
214540266059SGregory Neil Shapiro
214640266059SGregory Neil Shapiro e->e_quarmsg = NULL;
214740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
214840266059SGregory Neil Shapiro macid("{quarantine}"), "");
214940266059SGregory Neil Shapiro }
2150065a643dSPeter Wemm if (bitset(EF_DISCARD, e->e_flags))
2151065a643dSPeter Wemm {
2152065a643dSPeter Wemm if (tTd(10, 5))
2153065a643dSPeter Wemm {
215440266059SGregory Neil Shapiro sm_dprintf("deliver: discarding recipient ");
2155e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), to, false);
2156065a643dSPeter Wemm }
2157065a643dSPeter Wemm
215806f25ae9SGregory Neil Shapiro /* pretend the message was sent */
215906f25ae9SGregory Neil Shapiro /* XXX should we log something here? */
216006f25ae9SGregory Neil Shapiro to->q_state = QS_DISCARDED;
216106f25ae9SGregory Neil Shapiro
2162065a643dSPeter Wemm /*
2163065a643dSPeter Wemm ** Remove discard bit to prevent discard of
216406f25ae9SGregory Neil Shapiro ** future recipients. This is safe because the
216506f25ae9SGregory Neil Shapiro ** true "global discard" has been handled before
216606f25ae9SGregory Neil Shapiro ** we get here.
2167065a643dSPeter Wemm */
2168065a643dSPeter Wemm
216906f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_DISCARD;
2170065a643dSPeter Wemm continue;
2171065a643dSPeter Wemm }
2172c2aa98e2SPeter Wemm
2173c2aa98e2SPeter Wemm /*
2174c2aa98e2SPeter Wemm ** Strip quote bits from names if the mailer is dumb
2175c2aa98e2SPeter Wemm ** about them.
2176c2aa98e2SPeter Wemm */
2177c2aa98e2SPeter Wemm
2178c2aa98e2SPeter Wemm if (bitnset(M_STRIPQ, m->m_flags))
2179c2aa98e2SPeter Wemm {
2180c2aa98e2SPeter Wemm stripquotes(user);
2181c2aa98e2SPeter Wemm stripquotes(host);
2182c2aa98e2SPeter Wemm }
2183e92d3f3fSGregory Neil Shapiro
218413bd1963SGregory Neil Shapiro /*
2185b6bacd31SGregory Neil Shapiro ** Strip all leading backslashes if requested and the
218613bd1963SGregory Neil Shapiro ** next character is alphanumerical (the latter can
218713bd1963SGregory Neil Shapiro ** probably relaxed a bit, see RFC2821).
218813bd1963SGregory Neil Shapiro */
218913bd1963SGregory Neil Shapiro
219013bd1963SGregory Neil Shapiro if (bitnset(M_STRIPBACKSL, m->m_flags) && user[0] == '\\')
219113bd1963SGregory Neil Shapiro stripbackslash(user);
2192c2aa98e2SPeter Wemm
2193c2aa98e2SPeter Wemm /* hack attack -- delivermail compatibility */
2194c2aa98e2SPeter Wemm if (m == ProgMailer && *user == '|')
2195c2aa98e2SPeter Wemm user++;
2196c2aa98e2SPeter Wemm
2197c2aa98e2SPeter Wemm /*
2198c2aa98e2SPeter Wemm ** If an error message has already been given, don't
2199c2aa98e2SPeter Wemm ** bother to send to this address.
2200c2aa98e2SPeter Wemm **
2201c2aa98e2SPeter Wemm ** >>>>>>>>>> This clause assumes that the local mailer
2202c2aa98e2SPeter Wemm ** >> NOTE >> cannot do any further aliasing; that
2203c2aa98e2SPeter Wemm ** >>>>>>>>>> function is subsumed by sendmail.
2204c2aa98e2SPeter Wemm */
2205c2aa98e2SPeter Wemm
220606f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state))
2207c2aa98e2SPeter Wemm continue;
2208c2aa98e2SPeter Wemm
2209c2aa98e2SPeter Wemm /*
2210c2aa98e2SPeter Wemm ** See if this user name is "special".
2211c2aa98e2SPeter Wemm ** If the user name has a slash in it, assume that this
2212c2aa98e2SPeter Wemm ** is a file -- send it off without further ado. Note
2213c2aa98e2SPeter Wemm ** that this type of addresses is not processed along
2214c2aa98e2SPeter Wemm ** with the others, so we fudge on the To person.
2215c2aa98e2SPeter Wemm */
2216c2aa98e2SPeter Wemm
2217c2aa98e2SPeter Wemm if (strcmp(m->m_mailer, "[FILE]") == 0)
2218c2aa98e2SPeter Wemm {
221940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', user);
2220c2aa98e2SPeter Wemm p = to->q_home;
2221c2aa98e2SPeter Wemm if (p == NULL && ctladdr != NULL)
2222c2aa98e2SPeter Wemm p = ctladdr->q_home;
222340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', p);
2224d0cef73dSGregory Neil Shapiro expand(m->m_argv[1], buf, sizeof(buf), e);
2225c2aa98e2SPeter Wemm if (strlen(buf) > 0)
2226c2aa98e2SPeter Wemm rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e);
2227c2aa98e2SPeter Wemm else
2228c2aa98e2SPeter Wemm {
2229c2aa98e2SPeter Wemm syserr("empty filename specification for mailer %s",
2230c2aa98e2SPeter Wemm m->m_name);
2231c2aa98e2SPeter Wemm rcode = EX_CONFIG;
2232c2aa98e2SPeter Wemm }
223306f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, NULL,
223440266059SGregory Neil Shapiro ctladdr, xstart, e, to);
223540266059SGregory Neil Shapiro markfailure(e, to, NULL, rcode, true);
2236c2aa98e2SPeter Wemm e->e_nsent++;
2237c2aa98e2SPeter Wemm if (rcode == EX_OK)
2238c2aa98e2SPeter Wemm {
223906f25ae9SGregory Neil Shapiro to->q_state = QS_SENT;
2240c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) &&
2241c2aa98e2SPeter Wemm bitset(QPINGONSUCCESS, to->q_flags))
2242c2aa98e2SPeter Wemm {
2243c2aa98e2SPeter Wemm to->q_flags |= QDELIVERED;
2244c2aa98e2SPeter Wemm to->q_status = "2.1.5";
224540266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp,
224640266059SGregory Neil Shapiro SM_TIME_DEFAULT,
224740266059SGregory Neil Shapiro "%s... Successfully delivered\n",
2248c2aa98e2SPeter Wemm to->q_paddr);
2249c2aa98e2SPeter Wemm }
2250c2aa98e2SPeter Wemm }
2251c2aa98e2SPeter Wemm to->q_statdate = curtime();
225240266059SGregory Neil Shapiro markstats(e, to, STATS_NORMAL);
2253c2aa98e2SPeter Wemm continue;
2254c2aa98e2SPeter Wemm }
2255c2aa98e2SPeter Wemm
2256c2aa98e2SPeter Wemm /*
2257c2aa98e2SPeter Wemm ** Address is verified -- add this user to mailer
2258c2aa98e2SPeter Wemm ** argv, and add it to the print list of recipients.
2259c2aa98e2SPeter Wemm */
2260c2aa98e2SPeter Wemm
2261c2aa98e2SPeter Wemm /* link together the chain of recipients */
2262c2aa98e2SPeter Wemm to->q_tchain = tochain;
2263c2aa98e2SPeter Wemm tochain = to;
226406f25ae9SGregory Neil Shapiro e->e_to = "[CHAIN]";
226506f25ae9SGregory Neil Shapiro
226640266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', user); /* to user */
2267c2aa98e2SPeter Wemm p = to->q_home;
2268c2aa98e2SPeter Wemm if (p == NULL && ctladdr != NULL)
2269c2aa98e2SPeter Wemm p = ctladdr->q_home;
227040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', p); /* user's home */
2271c2aa98e2SPeter Wemm
227206f25ae9SGregory Neil Shapiro /* set the ${dsn_notify} macro if applicable */
227306f25ae9SGregory Neil Shapiro if (bitset(QHASNOTIFY, to->q_flags))
227406f25ae9SGregory Neil Shapiro {
227506f25ae9SGregory Neil Shapiro char notify[MAXLINE];
227606f25ae9SGregory Neil Shapiro
227706f25ae9SGregory Neil Shapiro notify[0] = '\0';
227806f25ae9SGregory Neil Shapiro if (bitset(QPINGONSUCCESS, to->q_flags))
227940266059SGregory Neil Shapiro (void) sm_strlcat(notify, "SUCCESS,",
2280d0cef73dSGregory Neil Shapiro sizeof(notify));
228106f25ae9SGregory Neil Shapiro if (bitset(QPINGONFAILURE, to->q_flags))
228240266059SGregory Neil Shapiro (void) sm_strlcat(notify, "FAILURE,",
2283d0cef73dSGregory Neil Shapiro sizeof(notify));
228406f25ae9SGregory Neil Shapiro if (bitset(QPINGONDELAY, to->q_flags))
228540266059SGregory Neil Shapiro (void) sm_strlcat(notify, "DELAY,",
2286d0cef73dSGregory Neil Shapiro sizeof(notify));
228706f25ae9SGregory Neil Shapiro
228806f25ae9SGregory Neil Shapiro /* Set to NEVER or drop trailing comma */
228906f25ae9SGregory Neil Shapiro if (notify[0] == '\0')
229040266059SGregory Neil Shapiro (void) sm_strlcat(notify, "NEVER",
2291d0cef73dSGregory Neil Shapiro sizeof(notify));
229206f25ae9SGregory Neil Shapiro else
229306f25ae9SGregory Neil Shapiro notify[strlen(notify) - 1] = '\0';
229406f25ae9SGregory Neil Shapiro
229540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP,
229640266059SGregory Neil Shapiro macid("{dsn_notify}"), notify);
229706f25ae9SGregory Neil Shapiro }
229806f25ae9SGregory Neil Shapiro else
229940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
230040266059SGregory Neil Shapiro macid("{dsn_notify}"), NULL);
230106f25ae9SGregory Neil Shapiro
2302c2aa98e2SPeter Wemm /*
2303c2aa98e2SPeter Wemm ** Expand out this user into argument list.
2304c2aa98e2SPeter Wemm */
2305c2aa98e2SPeter Wemm
2306c2aa98e2SPeter Wemm if (!clever)
2307c2aa98e2SPeter Wemm {
2308d0cef73dSGregory Neil Shapiro expand(*mvp, buf, sizeof(buf), e);
2309*d39bd2c1SGregory Neil Shapiro p = buf;
2310*d39bd2c1SGregory Neil Shapiro #if _FFR_8BITENVADDR
2311*d39bd2c1SGregory Neil Shapiro if (((*mvp)[0] & 0377) == MACROEXPAND)
2312*d39bd2c1SGregory Neil Shapiro {
2313*d39bd2c1SGregory Neil Shapiro (void) dequote_internal_chars(buf, xbuf, sizeof(xbuf));
2314*d39bd2c1SGregory Neil Shapiro p = xbuf;
2315*d39bd2c1SGregory Neil Shapiro if (tTd(10, 33))
2316*d39bd2c1SGregory Neil Shapiro sm_dprintf("expand(%s), dequoted=%s\n", *mvp, p);
2317*d39bd2c1SGregory Neil Shapiro }
2318*d39bd2c1SGregory Neil Shapiro #endif
2319*d39bd2c1SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, p);
2320c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV - 2])
2321c2aa98e2SPeter Wemm {
2322c2aa98e2SPeter Wemm /* allow some space for trailing parms */
2323c2aa98e2SPeter Wemm break;
2324c2aa98e2SPeter Wemm }
2325c2aa98e2SPeter Wemm }
2326c2aa98e2SPeter Wemm }
2327c2aa98e2SPeter Wemm
2328c2aa98e2SPeter Wemm /* see if any addresses still exist */
232906f25ae9SGregory Neil Shapiro if (tochain == NULL)
2330c2aa98e2SPeter Wemm {
233140266059SGregory Neil Shapiro rcode = 0;
233240266059SGregory Neil Shapiro goto cleanup;
2333c2aa98e2SPeter Wemm }
2334c2aa98e2SPeter Wemm
2335c2aa98e2SPeter Wemm /* print out messages as full list */
233640266059SGregory Neil Shapiro strsize = 1;
233706f25ae9SGregory Neil Shapiro for (to = tochain; to != NULL; to = to->q_tchain)
233840266059SGregory Neil Shapiro strsize += strlen(to->q_paddr) + 1;
233940266059SGregory Neil Shapiro if (strsize < TOBUFSIZE)
234040266059SGregory Neil Shapiro strsize = TOBUFSIZE;
234140266059SGregory Neil Shapiro if (strsize > tobufsize)
234206f25ae9SGregory Neil Shapiro {
23435b0945b5SGregory Neil Shapiro SM_FREE(tobuf);
234440266059SGregory Neil Shapiro tobuf = sm_pmalloc_x(strsize);
234540266059SGregory Neil Shapiro tobufsize = strsize;
234606f25ae9SGregory Neil Shapiro }
234740266059SGregory Neil Shapiro p = tobuf;
234840266059SGregory Neil Shapiro *p = '\0';
234906f25ae9SGregory Neil Shapiro for (to = tochain; to != NULL; to = to->q_tchain)
235006f25ae9SGregory Neil Shapiro {
235140266059SGregory Neil Shapiro (void) sm_strlcpyn(p, tobufsize - (p - tobuf), 2,
235240266059SGregory Neil Shapiro ",", to->q_paddr);
235340266059SGregory Neil Shapiro p += strlen(p);
235406f25ae9SGregory Neil Shapiro }
2355c2aa98e2SPeter Wemm e->e_to = tobuf + 1;
2356c2aa98e2SPeter Wemm
2357c2aa98e2SPeter Wemm /*
2358c2aa98e2SPeter Wemm ** Fill out any parameters after the $u parameter.
2359c2aa98e2SPeter Wemm */
2360c2aa98e2SPeter Wemm
236140266059SGregory Neil Shapiro if (!clever)
236240266059SGregory Neil Shapiro {
236340266059SGregory Neil Shapiro while (*++mvp != NULL)
2364c2aa98e2SPeter Wemm {
2365d0cef73dSGregory Neil Shapiro expand(*mvp, buf, sizeof(buf), e);
2366*d39bd2c1SGregory Neil Shapiro p = buf;
2367*d39bd2c1SGregory Neil Shapiro #if _FFR_8BITENVADDR && 0
2368*d39bd2c1SGregory Neil Shapiro /* disabled for now - is there a use case for this? */
2369*d39bd2c1SGregory Neil Shapiro if (((*mvp)[0] & 0377) == MACROEXPAND)
2370*d39bd2c1SGregory Neil Shapiro {
2371*d39bd2c1SGregory Neil Shapiro (void) dequote_internal_chars(buf, xbuf, sizeof(xbuf));
2372*d39bd2c1SGregory Neil Shapiro p = xbuf;
2373*d39bd2c1SGregory Neil Shapiro if (tTd(10, 33))
2374*d39bd2c1SGregory Neil Shapiro sm_dprintf("expand(%s), dequoted=%s\n", *mvp, p);
2375*d39bd2c1SGregory Neil Shapiro }
2376*d39bd2c1SGregory Neil Shapiro #endif
2377*d39bd2c1SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, p);
2378c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV])
237906f25ae9SGregory Neil Shapiro syserr("554 5.3.0 deliver: pv overflow after $u for %s",
238006f25ae9SGregory Neil Shapiro pv[0]);
2381c2aa98e2SPeter Wemm }
238240266059SGregory Neil Shapiro }
2383c2aa98e2SPeter Wemm *pvp++ = NULL;
2384c2aa98e2SPeter Wemm
2385c2aa98e2SPeter Wemm /*
2386c2aa98e2SPeter Wemm ** Call the mailer.
2387c2aa98e2SPeter Wemm ** The argument vector gets built, pipes
2388c2aa98e2SPeter Wemm ** are created as necessary, and we fork & exec as
2389c2aa98e2SPeter Wemm ** appropriate.
2390c2aa98e2SPeter Wemm ** If we are running SMTP, we just need to clean up.
2391c2aa98e2SPeter Wemm */
2392c2aa98e2SPeter Wemm
23936f9c8e5bSGregory Neil Shapiro /* XXX this seems a bit weird */
2394c2aa98e2SPeter Wemm if (ctladdr == NULL && m != ProgMailer && m != FileMailer &&
2395c2aa98e2SPeter Wemm bitset(QGOODUID, e->e_from.q_flags))
2396c2aa98e2SPeter Wemm ctladdr = &e->e_from;
2397c2aa98e2SPeter Wemm
2398c2aa98e2SPeter Wemm #if NAMED_BIND
2399c2aa98e2SPeter Wemm if (ConfigLevel < 2)
2400c2aa98e2SPeter Wemm _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */
24015b0945b5SGregory Neil Shapiro #endif
2402c2aa98e2SPeter Wemm
2403c2aa98e2SPeter Wemm if (tTd(11, 1))
2404c2aa98e2SPeter Wemm {
240540266059SGregory Neil Shapiro sm_dprintf("openmailer:");
2406e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), pv);
2407c2aa98e2SPeter Wemm }
2408c2aa98e2SPeter Wemm errno = 0;
2409602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0);
2410c2aa98e2SPeter Wemm CurHostName = NULL;
2411c2aa98e2SPeter Wemm
2412c2aa98e2SPeter Wemm /*
2413c2aa98e2SPeter Wemm ** Deal with the special case of mail handled through an IPC
2414c2aa98e2SPeter Wemm ** connection.
2415c2aa98e2SPeter Wemm ** In this case we don't actually fork. We must be
2416c2aa98e2SPeter Wemm ** running SMTP for this to work. We will return a
2417c2aa98e2SPeter Wemm ** zero pid to indicate that we are running IPC.
2418c2aa98e2SPeter Wemm ** We also handle a debug version that just talks to stdin/out.
2419c2aa98e2SPeter Wemm */
2420c2aa98e2SPeter Wemm
2421c2aa98e2SPeter Wemm curhost = NULL;
2422c2aa98e2SPeter Wemm SmtpPhase = NULL;
2423c2aa98e2SPeter Wemm mci = NULL;
2424c2aa98e2SPeter Wemm
2425c2aa98e2SPeter Wemm #if XDEBUG
2426c2aa98e2SPeter Wemm {
2427c2aa98e2SPeter Wemm char wbuf[MAXLINE];
2428c2aa98e2SPeter Wemm
2429c2aa98e2SPeter Wemm /* make absolutely certain 0, 1, and 2 are in use */
2430d0cef73dSGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof(wbuf), "%s... openmailer(%s)",
243140266059SGregory Neil Shapiro shortenstring(e->e_to, MAXSHORTSTR),
243240266059SGregory Neil Shapiro m->m_name);
2433c2aa98e2SPeter Wemm checkfd012(wbuf);
2434c2aa98e2SPeter Wemm }
243506f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
2436c2aa98e2SPeter Wemm
2437c2aa98e2SPeter Wemm /* check for 8-bit available */
2438c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) &&
2439c2aa98e2SPeter Wemm bitnset(M_7BITS, m->m_flags) &&
2440c2aa98e2SPeter Wemm (bitset(EF_DONT_MIME, e->e_flags) ||
2441c2aa98e2SPeter Wemm !(bitset(MM_MIME8BIT, MimeMode) ||
2442c2aa98e2SPeter Wemm (bitset(EF_IS_MIME, e->e_flags) &&
2443c2aa98e2SPeter Wemm bitset(MM_CVTMIME, MimeMode)))))
2444c2aa98e2SPeter Wemm {
2445c2aa98e2SPeter Wemm e->e_status = "5.6.3";
244606f25ae9SGregory Neil Shapiro usrerrenh(e->e_status,
244706f25ae9SGregory Neil Shapiro "554 Cannot send 8-bit data to 7-bit destination");
244806f25ae9SGregory Neil Shapiro rcode = EX_DATAERR;
2449c2aa98e2SPeter Wemm goto give_up;
2450c2aa98e2SPeter Wemm }
2451c2aa98e2SPeter Wemm
2452c2aa98e2SPeter Wemm if (tTd(62, 8))
2453c2aa98e2SPeter Wemm checkfds("before delivery");
2454c2aa98e2SPeter Wemm
2455c2aa98e2SPeter Wemm /* check for Local Person Communication -- not for mortals!!! */
2456c2aa98e2SPeter Wemm if (strcmp(m->m_mailer, "[LPC]") == 0)
2457c2aa98e2SPeter Wemm {
245840266059SGregory Neil Shapiro if (clever)
245940266059SGregory Neil Shapiro {
246040266059SGregory Neil Shapiro /* flush any expired connections */
246140266059SGregory Neil Shapiro (void) mci_scan(NULL);
246240266059SGregory Neil Shapiro
246340266059SGregory Neil Shapiro /* try to get a cached connection or just a slot */
246440266059SGregory Neil Shapiro mci = mci_get(m->m_name, m);
246540266059SGregory Neil Shapiro if (mci->mci_host == NULL)
246640266059SGregory Neil Shapiro mci->mci_host = m->m_name;
246740266059SGregory Neil Shapiro CurHostName = mci->mci_host;
246840266059SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED)
246940266059SGregory Neil Shapiro {
247040266059SGregory Neil Shapiro message("Using cached SMTP/LPC connection for %s...",
247140266059SGregory Neil Shapiro m->m_name);
247240266059SGregory Neil Shapiro mci->mci_deliveries++;
247340266059SGregory Neil Shapiro goto do_transfer;
247440266059SGregory Neil Shapiro }
247540266059SGregory Neil Shapiro }
247640266059SGregory Neil Shapiro else
247740266059SGregory Neil Shapiro {
247840266059SGregory Neil Shapiro mci = mci_new(e->e_rpool);
247940266059SGregory Neil Shapiro }
248040266059SGregory Neil Shapiro mci->mci_in = smioin;
248140266059SGregory Neil Shapiro mci->mci_out = smioout;
248240266059SGregory Neil Shapiro mci->mci_mailer = m;
248340266059SGregory Neil Shapiro mci->mci_host = m->m_name;
248440266059SGregory Neil Shapiro if (clever)
248540266059SGregory Neil Shapiro {
248640266059SGregory Neil Shapiro mci->mci_state = MCIS_OPENING;
248740266059SGregory Neil Shapiro mci_cache(mci);
248840266059SGregory Neil Shapiro }
248940266059SGregory Neil Shapiro else
249040266059SGregory Neil Shapiro mci->mci_state = MCIS_OPEN;
2491c2aa98e2SPeter Wemm }
249240266059SGregory Neil Shapiro else if (strcmp(m->m_mailer, "[IPC]") == 0)
2493c2aa98e2SPeter Wemm {
2494c2aa98e2SPeter Wemm register int i;
2495c2aa98e2SPeter Wemm
2496c2aa98e2SPeter Wemm if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0')
2497c2aa98e2SPeter Wemm {
249806f25ae9SGregory Neil Shapiro syserr("null destination for %s mailer", m->m_mailer);
2499c2aa98e2SPeter Wemm rcode = EX_CONFIG;
2500c2aa98e2SPeter Wemm goto give_up;
2501c2aa98e2SPeter Wemm }
2502c2aa98e2SPeter Wemm
250306f25ae9SGregory Neil Shapiro #if NETUNIX
250406f25ae9SGregory Neil Shapiro if (strcmp(pv[0], "FILE") == 0)
250506f25ae9SGregory Neil Shapiro {
250606f25ae9SGregory Neil Shapiro curhost = CurHostName = "localhost";
250706f25ae9SGregory Neil Shapiro mux_path = pv[1];
250806f25ae9SGregory Neil Shapiro }
250906f25ae9SGregory Neil Shapiro else
251006f25ae9SGregory Neil Shapiro #endif /* NETUNIX */
25112fb4f839SGregory Neil Shapiro /* "else" in #if code above */
251206f25ae9SGregory Neil Shapiro {
2513c2aa98e2SPeter Wemm CurHostName = pv[1];
25145b0945b5SGregory Neil Shapiro /* XXX ??? */
2515*d39bd2c1SGregory Neil Shapiro curhost = hostsignature(m, pv[1],
2516*d39bd2c1SGregory Neil Shapiro QISSECURE(firstto),
2517*d39bd2c1SGregory Neil Shapiro &firstto->q_flags);
251806f25ae9SGregory Neil Shapiro }
2519c2aa98e2SPeter Wemm
2520c2aa98e2SPeter Wemm if (curhost == NULL || curhost[0] == '\0')
2521c2aa98e2SPeter Wemm {
2522c2aa98e2SPeter Wemm syserr("null host signature for %s", pv[1]);
2523c2aa98e2SPeter Wemm rcode = EX_CONFIG;
2524c2aa98e2SPeter Wemm goto give_up;
2525c2aa98e2SPeter Wemm }
2526c2aa98e2SPeter Wemm
2527c2aa98e2SPeter Wemm if (!clever)
2528c2aa98e2SPeter Wemm {
252906f25ae9SGregory Neil Shapiro syserr("554 5.3.5 non-clever IPC");
2530c2aa98e2SPeter Wemm rcode = EX_CONFIG;
2531c2aa98e2SPeter Wemm goto give_up;
2532c2aa98e2SPeter Wemm }
253306f25ae9SGregory Neil Shapiro if (pv[2] != NULL
253406f25ae9SGregory Neil Shapiro #if NETUNIX
253506f25ae9SGregory Neil Shapiro && mux_path == NULL
25365b0945b5SGregory Neil Shapiro #endif
253706f25ae9SGregory Neil Shapiro )
2538c2aa98e2SPeter Wemm {
253940266059SGregory Neil Shapiro port = htons((unsigned short) atoi(pv[2]));
2540c2aa98e2SPeter Wemm if (port == 0)
2541c2aa98e2SPeter Wemm {
254206f25ae9SGregory Neil Shapiro #ifdef NO_GETSERVBYNAME
254306f25ae9SGregory Neil Shapiro syserr("Invalid port number: %s", pv[2]);
254406f25ae9SGregory Neil Shapiro #else /* NO_GETSERVBYNAME */
2545c2aa98e2SPeter Wemm struct servent *sp = getservbyname(pv[2], "tcp");
2546c2aa98e2SPeter Wemm
2547c2aa98e2SPeter Wemm if (sp == NULL)
2548c2aa98e2SPeter Wemm syserr("Service %s unknown", pv[2]);
2549c2aa98e2SPeter Wemm else
2550c2aa98e2SPeter Wemm port = sp->s_port;
255106f25ae9SGregory Neil Shapiro #endif /* NO_GETSERVBYNAME */
2552c2aa98e2SPeter Wemm }
2553c2aa98e2SPeter Wemm }
2554c2aa98e2SPeter Wemm
2555*d39bd2c1SGregory Neil Shapiro nummxhosts = parse_hostsignature(curhost, mxhosts, m
2556*d39bd2c1SGregory Neil Shapiro #if DANE
2557*d39bd2c1SGregory Neil Shapiro , mxads
2558*d39bd2c1SGregory Neil Shapiro #endif
2559*d39bd2c1SGregory Neil Shapiro );
256040266059SGregory Neil Shapiro if (TimeOuts.to_aconnect > 0)
256140266059SGregory Neil Shapiro enough = curtime() + TimeOuts.to_aconnect;
256206f25ae9SGregory Neil Shapiro tryhost:
256306f25ae9SGregory Neil Shapiro while (hostnum < nummxhosts)
256406f25ae9SGregory Neil Shapiro {
256506f25ae9SGregory Neil Shapiro char sep = ':';
256606f25ae9SGregory Neil Shapiro char *endp;
25672fb4f839SGregory Neil Shapiro static char hostbuf[MAXNAME_I + 1];
2568e92d3f3fSGregory Neil Shapiro bool tried_fallbacksmarthost = false;
25695b0945b5SGregory Neil Shapiro #if DANE
25705b0945b5SGregory Neil Shapiro unsigned long tlsa_flags;
2571*d39bd2c1SGregory Neil Shapiro # if HSMARKS
2572*d39bd2c1SGregory Neil Shapiro bool mxsecure;
2573*d39bd2c1SGregory Neil Shapiro # endif
257406f25ae9SGregory Neil Shapiro
25755b0945b5SGregory Neil Shapiro ste = NULL;
25765b0945b5SGregory Neil Shapiro tlsa_flags = 0;
2577*d39bd2c1SGregory Neil Shapiro # if HSMARKS
2578*d39bd2c1SGregory Neil Shapiro mxsecure = MXADS_ISSET(mxads, hostnum);
25795b0945b5SGregory Neil Shapiro # endif
2580*d39bd2c1SGregory Neil Shapiro #endif /* DANE */
2581*d39bd2c1SGregory Neil Shapiro FIX_MXHOSTS(mxhosts[hostnum], endp, sep);
258206f25ae9SGregory Neil Shapiro
258340266059SGregory Neil Shapiro if (hostnum == 1 && skip_back != NULL)
258440266059SGregory Neil Shapiro {
258540266059SGregory Neil Shapiro /*
258640266059SGregory Neil Shapiro ** Coattail piggybacking is no longer an
258740266059SGregory Neil Shapiro ** option with the mail host next to be tried
258840266059SGregory Neil Shapiro ** no longer the lowest MX preference
258940266059SGregory Neil Shapiro ** (hostnum == 1 meaning we're on the second
259040266059SGregory Neil Shapiro ** preference). We do not try to coattail
259140266059SGregory Neil Shapiro ** piggyback more than the first MX preference.
259240266059SGregory Neil Shapiro ** Revert 'tochain' to last location for
259340266059SGregory Neil Shapiro ** coincidental piggybacking. This works this
259440266059SGregory Neil Shapiro ** easily because the q_tchain kept getting
259540266059SGregory Neil Shapiro ** added to the top of the linked list.
259640266059SGregory Neil Shapiro */
259740266059SGregory Neil Shapiro
259840266059SGregory Neil Shapiro tochain = skip_back;
259940266059SGregory Neil Shapiro }
260040266059SGregory Neil Shapiro
260106f25ae9SGregory Neil Shapiro if (*mxhosts[hostnum] == '\0')
2602c2aa98e2SPeter Wemm {
2603c2aa98e2SPeter Wemm syserr("deliver: null host name in signature");
260406f25ae9SGregory Neil Shapiro hostnum++;
260506f25ae9SGregory Neil Shapiro if (endp != NULL)
260606f25ae9SGregory Neil Shapiro *endp = sep;
2607c2aa98e2SPeter Wemm continue;
2608c2aa98e2SPeter Wemm }
260940266059SGregory Neil Shapiro (void) sm_strlcpy(hostbuf, mxhosts[hostnum],
2610d0cef73dSGregory Neil Shapiro sizeof(hostbuf));
261106f25ae9SGregory Neil Shapiro hostnum++;
261206f25ae9SGregory Neil Shapiro if (endp != NULL)
261306f25ae9SGregory Neil Shapiro *endp = sep;
26145b0945b5SGregory Neil Shapiro #if STARTTLS
26155b0945b5SGregory Neil Shapiro tlsstate = 0;
26165b0945b5SGregory Neil Shapiro #endif
2617c2aa98e2SPeter Wemm
2618e92d3f3fSGregory Neil Shapiro one_last_try:
2619c2aa98e2SPeter Wemm /* see if we already know that this host is fried */
2620c2aa98e2SPeter Wemm CurHostName = hostbuf;
2621c2aa98e2SPeter Wemm mci = mci_get(hostbuf, m);
2622*d39bd2c1SGregory Neil Shapiro
2623*d39bd2c1SGregory Neil Shapiro #if DANE
2624*d39bd2c1SGregory Neil Shapiro tlsa_flags = 0;
2625*d39bd2c1SGregory Neil Shapiro # if HSMARKS
2626*d39bd2c1SGregory Neil Shapiro if (mxsecure)
2627*d39bd2c1SGregory Neil Shapiro firstto->q_flags |= QMXSECURE;
2628*d39bd2c1SGregory Neil Shapiro else
2629*d39bd2c1SGregory Neil Shapiro firstto->q_flags &= ~QMXSECURE;
2630*d39bd2c1SGregory Neil Shapiro # endif
2631*d39bd2c1SGregory Neil Shapiro if (TTD(90, 30))
2632*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: mci_get: 1: mci=%p, host=%s, mx=%s, ste=%p, dane=%#x, mci_state=%d, QMXSECURE=%d, reqdane=%d, chk_dane_rcpt=%d, firstto=%s, to=%s\n",
2633*d39bd2c1SGregory Neil Shapiro mci, host, hostbuf, ste, Dane,
2634*d39bd2c1SGregory Neil Shapiro mci->mci_state, RCPT_MXSECURE(firstto),
2635*d39bd2c1SGregory Neil Shapiro RCPT_REQ_DANE(firstto),
2636*d39bd2c1SGregory Neil Shapiro CHK_DANE_RCPT(Dane, firstto),
2637*d39bd2c1SGregory Neil Shapiro firstto->q_user, e->e_to);
2638*d39bd2c1SGregory Neil Shapiro
2639*d39bd2c1SGregory Neil Shapiro if (CHK_DANE_RCPT(Dane, firstto))
2640*d39bd2c1SGregory Neil Shapiro {
2641*d39bd2c1SGregory Neil Shapiro (void) gettlsa(hostbuf, NULL, &ste,
2642*d39bd2c1SGregory Neil Shapiro RCPT_MXSECURE(firstto) ? TLSAFLADMX : 0,
2643*d39bd2c1SGregory Neil Shapiro 0, m->m_port);
2644*d39bd2c1SGregory Neil Shapiro }
2645*d39bd2c1SGregory Neil Shapiro if (TTD(90, 30))
2646*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: host=%s, mx=%s, ste=%p, chk_dane=%d\n",
2647*d39bd2c1SGregory Neil Shapiro host, hostbuf, ste,
2648*d39bd2c1SGregory Neil Shapiro CHK_DANE_RCPT(Dane, firstto));
2649*d39bd2c1SGregory Neil Shapiro
2650*d39bd2c1SGregory Neil Shapiro /* XXX: check expiration! */
2651*d39bd2c1SGregory Neil Shapiro if (ste != NULL && TLSA_RR_TEMPFAIL(ste->s_tlsa))
2652*d39bd2c1SGregory Neil Shapiro {
2653*d39bd2c1SGregory Neil Shapiro if (tTd(11, 1))
2654*d39bd2c1SGregory Neil Shapiro sm_dprintf("skip: host=%s, TLSA_RR_lookup=%d\n"
2655*d39bd2c1SGregory Neil Shapiro , hostbuf
2656*d39bd2c1SGregory Neil Shapiro , ste->s_tlsa->dane_tlsa_dnsrc);
2657*d39bd2c1SGregory Neil Shapiro
2658*d39bd2c1SGregory Neil Shapiro tlsa_flags |= TLSAFLTEMP;
2659*d39bd2c1SGregory Neil Shapiro }
2660*d39bd2c1SGregory Neil Shapiro else if (ste != NULL && TTD(90, 30))
2661*d39bd2c1SGregory Neil Shapiro {
2662*d39bd2c1SGregory Neil Shapiro if (ste->s_tlsa != NULL)
2663*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: host=%s, mx=%s, tlsa_n=%d, tlsa_flags=%#lx, ssl=%p, chk=%#x, res=%d\n"
2664*d39bd2c1SGregory Neil Shapiro , host, hostbuf
2665*d39bd2c1SGregory Neil Shapiro , ste->s_tlsa->dane_tlsa_n
2666*d39bd2c1SGregory Neil Shapiro , ste->s_tlsa->dane_tlsa_flags
2667*d39bd2c1SGregory Neil Shapiro , mci->mci_ssl
2668*d39bd2c1SGregory Neil Shapiro , mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk
2669*d39bd2c1SGregory Neil Shapiro , mci->mci_tlsi.tlsi_dvc.dane_vrfy_res
2670*d39bd2c1SGregory Neil Shapiro );
2671*d39bd2c1SGregory Neil Shapiro else
2672*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: host=%s, mx=%s, notlsa\n", host, hostbuf);
2673*d39bd2c1SGregory Neil Shapiro }
2674*d39bd2c1SGregory Neil Shapiro
2675*d39bd2c1SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED)
2676*d39bd2c1SGregory Neil Shapiro {
2677*d39bd2c1SGregory Neil Shapiro bool dane_old, dane_new, new_session;
2678*d39bd2c1SGregory Neil Shapiro
2679*d39bd2c1SGregory Neil Shapiro /* CHK_DANE(Dane): implicit via ste != NULL */
2680*d39bd2c1SGregory Neil Shapiro dane_new = !iscltflgset(e, D_NODANE) &&
2681*d39bd2c1SGregory Neil Shapiro ste != NULL && ste->s_tlsa != NULL &&
2682*d39bd2c1SGregory Neil Shapiro TLSA_IS_FL(ste->s_tlsa, TLSAFLSUP);
2683*d39bd2c1SGregory Neil Shapiro dane_old = CHK_DANE(mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk);
2684*d39bd2c1SGregory Neil Shapiro new_session = (dane_old != dane_new);
2685*d39bd2c1SGregory Neil Shapiro vrfy = "";
2686*d39bd2c1SGregory Neil Shapiro if (dane_old && new_session)
2687*d39bd2c1SGregory Neil Shapiro {
2688*d39bd2c1SGregory Neil Shapiro vrfy = macget(&mci->mci_macro, macid("{verify}"));
2689*d39bd2c1SGregory Neil Shapiro new_session = NULL == vrfy || strcmp("TRUSTED", vrfy) != 0;
2690*d39bd2c1SGregory Neil Shapiro }
2691*d39bd2c1SGregory Neil Shapiro if (TTD(11, 32))
2692*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: host=%s, mx=%s, dane_old=%d, dane_new=%d, new_session=%d, vrfy=%s\n",
2693*d39bd2c1SGregory Neil Shapiro host, hostbuf, dane_old,
2694*d39bd2c1SGregory Neil Shapiro dane_new, new_session, vrfy);
2695*d39bd2c1SGregory Neil Shapiro if (new_session)
2696*d39bd2c1SGregory Neil Shapiro {
2697*d39bd2c1SGregory Neil Shapiro if (TTD(11, 34))
2698*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: host=%s, mx=%s, old_mci=%p, state=%d\n",
2699*d39bd2c1SGregory Neil Shapiro host, hostbuf,
2700*d39bd2c1SGregory Neil Shapiro mci, mci->mci_state);
2701*d39bd2c1SGregory Neil Shapiro smtpquit(mci->mci_mailer, mci, e);
2702*d39bd2c1SGregory Neil Shapiro if (TTD(11, 34))
2703*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: host=%s, mx=%s, new_mci=%p, state=%d\n",
2704*d39bd2c1SGregory Neil Shapiro host, hostbuf,
2705*d39bd2c1SGregory Neil Shapiro mci, mci->mci_state);
2706*d39bd2c1SGregory Neil Shapiro }
2707*d39bd2c1SGregory Neil Shapiro else
2708*d39bd2c1SGregory Neil Shapiro {
2709*d39bd2c1SGregory Neil Shapiro /* are tlsa_flags the same as dane_vrfy_chk? */
2710*d39bd2c1SGregory Neil Shapiro tlsa_flags = mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk;
2711*d39bd2c1SGregory Neil Shapiro memcpy(&dane_vrfy_ctx,
2712*d39bd2c1SGregory Neil Shapiro &mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk,
2713*d39bd2c1SGregory Neil Shapiro sizeof(dane_vrfy_ctx));
2714*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_host = NULL;
2715*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_sni = NULL;
2716*d39bd2c1SGregory Neil Shapiro if (TTD(90, 40))
2717*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: host=%s, mx=%s, state=reuse, chk=%#x\n",
2718*d39bd2c1SGregory Neil Shapiro host, hostbuf, mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk);
2719*d39bd2c1SGregory Neil Shapiro }
2720*d39bd2c1SGregory Neil Shapiro }
2721*d39bd2c1SGregory Neil Shapiro #endif /* DANE */
2722c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED)
2723c2aa98e2SPeter Wemm {
272440266059SGregory Neil Shapiro char *type;
272540266059SGregory Neil Shapiro
2726c2aa98e2SPeter Wemm if (tTd(11, 1))
2727c2aa98e2SPeter Wemm {
272840266059SGregory Neil Shapiro sm_dprintf("openmailer: ");
2729e92d3f3fSGregory Neil Shapiro mci_dump(sm_debug_file(), mci, false);
2730c2aa98e2SPeter Wemm }
2731c2aa98e2SPeter Wemm CurHostName = mci->mci_host;
273240266059SGregory Neil Shapiro if (bitnset(M_LMTP, m->m_flags))
273340266059SGregory Neil Shapiro type = "L";
273440266059SGregory Neil Shapiro else if (bitset(MCIF_ESMTP, mci->mci_flags))
273540266059SGregory Neil Shapiro type = "ES";
273640266059SGregory Neil Shapiro else
273740266059SGregory Neil Shapiro type = "S";
273840266059SGregory Neil Shapiro message("Using cached %sMTP connection to %s via %s...",
273940266059SGregory Neil Shapiro type, hostbuf, m->m_name);
274006f25ae9SGregory Neil Shapiro mci->mci_deliveries++;
2741c2aa98e2SPeter Wemm break;
2742c2aa98e2SPeter Wemm }
2743c2aa98e2SPeter Wemm mci->mci_mailer = m;
27445b0945b5SGregory Neil Shapiro
2745c2aa98e2SPeter Wemm if (mci->mci_exitstat != EX_OK)
2746c2aa98e2SPeter Wemm {
2747c2aa98e2SPeter Wemm if (mci->mci_exitstat == EX_TEMPFAIL)
274840266059SGregory Neil Shapiro goodmxfound = true;
2749e92d3f3fSGregory Neil Shapiro
2750e92d3f3fSGregory Neil Shapiro /* Try FallbackSmartHost? */
2751e92d3f3fSGregory Neil Shapiro if (should_try_fbsh(e, &tried_fallbacksmarthost,
2752d0cef73dSGregory Neil Shapiro hostbuf, sizeof(hostbuf),
2753e92d3f3fSGregory Neil Shapiro mci->mci_exitstat))
2754e92d3f3fSGregory Neil Shapiro goto one_last_try;
2755e92d3f3fSGregory Neil Shapiro
2756c2aa98e2SPeter Wemm continue;
2757c2aa98e2SPeter Wemm }
2758c2aa98e2SPeter Wemm
2759c2aa98e2SPeter Wemm if (mci_lock_host(mci) != EX_OK)
2760c2aa98e2SPeter Wemm {
2761c2aa98e2SPeter Wemm mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
276240266059SGregory Neil Shapiro goodmxfound = true;
2763c2aa98e2SPeter Wemm continue;
2764c2aa98e2SPeter Wemm }
2765c2aa98e2SPeter Wemm
2766c2aa98e2SPeter Wemm /* try the connection */
276740266059SGregory Neil Shapiro sm_setproctitle(true, e, "%s %s: %s",
276806f25ae9SGregory Neil Shapiro qid_printname(e),
276906f25ae9SGregory Neil Shapiro hostbuf, "user open");
27702fb4f839SGregory Neil Shapiro
2771*d39bd2c1SGregory Neil Shapiro i = EX_OK;
27722fb4f839SGregory Neil Shapiro e->e_mci = mci;
2773*d39bd2c1SGregory Neil Shapiro #if STARTTLS || SASL
27742fb4f839SGregory Neil Shapiro if ((i = cltfeatures(e, hostbuf)) != EX_OK)
27752fb4f839SGregory Neil Shapiro {
27762fb4f839SGregory Neil Shapiro if (LogLevel > 8)
27772fb4f839SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
27782fb4f839SGregory Neil Shapiro "clt_features=TEMPFAIL, host=%s, status=skipped"
27792fb4f839SGregory Neil Shapiro , hostbuf);
27802fb4f839SGregory Neil Shapiro /* XXX handle error! */
27812fb4f839SGregory Neil Shapiro (void) sm_strlcpy(SmtpError,
27822fb4f839SGregory Neil Shapiro "clt_features=TEMPFAIL",
27832fb4f839SGregory Neil Shapiro sizeof(SmtpError));
27845b0945b5SGregory Neil Shapiro # if DANE
27852fb4f839SGregory Neil Shapiro tlsa_flags &= ~TLSAFLTEMP;
27862fb4f839SGregory Neil Shapiro # endif
27872fb4f839SGregory Neil Shapiro }
27882fb4f839SGregory Neil Shapiro # if DANE
27892fb4f839SGregory Neil Shapiro /* hack: disable DANE if requested */
27902fb4f839SGregory Neil Shapiro if (iscltflgset(e, D_NODANE))
27912fb4f839SGregory Neil Shapiro ste = NULL;
27922fb4f839SGregory Neil Shapiro tlsa_flags |= ste != NULL ? Dane : DANE_NEVER;
27935b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_chk = tlsa_flags;
27945b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_port = m->m_port;
2795*d39bd2c1SGregory Neil Shapiro if (TTD(11, 11))
2796*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: makeconnection=before, chk=%#x, tlsa_flags=%#lx, {client_flags}=%s, stat=%d, dane_enabled=%d\n",
2797*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_chk,
2798*d39bd2c1SGregory Neil Shapiro tlsa_flags,
2799*d39bd2c1SGregory Neil Shapiro macvalue(macid("{client_flags}"), e),
2800*d39bd2c1SGregory Neil Shapiro i, dane_vrfy_ctx.dane_vrfy_dane_enabled);
2801*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
2802*d39bd2c1SGregory Neil Shapiro #endif /* STARTTLS || SASL */
2803*d39bd2c1SGregory Neil Shapiro #if NETUNIX
2804*d39bd2c1SGregory Neil Shapiro if (mux_path != NULL)
2805*d39bd2c1SGregory Neil Shapiro {
2806*d39bd2c1SGregory Neil Shapiro message("Connecting to %s via %s...",
2807*d39bd2c1SGregory Neil Shapiro mux_path, m->m_name);
2808*d39bd2c1SGregory Neil Shapiro if (EX_OK == i)
2809*d39bd2c1SGregory Neil Shapiro {
2810*d39bd2c1SGregory Neil Shapiro i = makeconnection_ds((char *) mux_path, mci);
2811*d39bd2c1SGregory Neil Shapiro #if DANE
2812*d39bd2c1SGregory Neil Shapiro /* fake it: "IP is secure" */
2813*d39bd2c1SGregory Neil Shapiro tlsa_flags |= TLSAFLADIP;
28145b0945b5SGregory Neil Shapiro #endif
2815*d39bd2c1SGregory Neil Shapiro }
2816*d39bd2c1SGregory Neil Shapiro }
2817*d39bd2c1SGregory Neil Shapiro else
2818*d39bd2c1SGregory Neil Shapiro #endif /* NETUNIX */
2819*d39bd2c1SGregory Neil Shapiro /* "else" in #if code above */
2820*d39bd2c1SGregory Neil Shapiro {
2821*d39bd2c1SGregory Neil Shapiro if (port == 0)
2822*d39bd2c1SGregory Neil Shapiro message("Connecting to %s via %s...",
2823*d39bd2c1SGregory Neil Shapiro hostbuf, m->m_name);
2824*d39bd2c1SGregory Neil Shapiro else
2825*d39bd2c1SGregory Neil Shapiro message("Connecting to %s port %d via %s...",
2826*d39bd2c1SGregory Neil Shapiro hostbuf, ntohs(port),
2827*d39bd2c1SGregory Neil Shapiro m->m_name);
2828*d39bd2c1SGregory Neil Shapiro
2829*d39bd2c1SGregory Neil Shapiro /*
2830*d39bd2c1SGregory Neil Shapiro ** set the current connection information,
2831*d39bd2c1SGregory Neil Shapiro ** required to set {client_flags} in e->e_mci
2832*d39bd2c1SGregory Neil Shapiro */
2833*d39bd2c1SGregory Neil Shapiro
28342fb4f839SGregory Neil Shapiro if (EX_OK == i)
28352fb4f839SGregory Neil Shapiro i = makeconnection(hostbuf, port, mci,
28362fb4f839SGregory Neil Shapiro e, enough
28375b0945b5SGregory Neil Shapiro #if DANE
28385b0945b5SGregory Neil Shapiro , &tlsa_flags
28395b0945b5SGregory Neil Shapiro #endif
28405b0945b5SGregory Neil Shapiro );
2841*d39bd2c1SGregory Neil Shapiro }
28425b0945b5SGregory Neil Shapiro #if DANE
2843*d39bd2c1SGregory Neil Shapiro if (TTD(11, 11))
2844*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: makeconnection=after, chk=%#x, tlsa_flags=%#lx, stat=%d\n",
2845*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_chk,
2846*d39bd2c1SGregory Neil Shapiro tlsa_flags, i);
2847*d39bd2c1SGregory Neil Shapiro #if OLD_WAY_TLSA_FLAGS
28485b0945b5SGregory Neil Shapiro if (dane_vrfy_ctx.dane_vrfy_chk != DANE_ALWAYS)
28495b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_chk = DANEMODE(tlsa_flags);
2850*d39bd2c1SGregory Neil Shapiro #else
2851*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_chk = tlsa_flags;
2852*d39bd2c1SGregory Neil Shapiro #endif
28535b0945b5SGregory Neil Shapiro if (EX_TEMPFAIL == i &&
28545b0945b5SGregory Neil Shapiro ((tlsa_flags & (TLSAFLTEMP|DANE_SECURE)) ==
28555b0945b5SGregory Neil Shapiro (TLSAFLTEMP|DANE_SECURE)))
28565b0945b5SGregory Neil Shapiro {
28575b0945b5SGregory Neil Shapiro (void) sm_strlcpy(SmtpError,
28585b0945b5SGregory Neil Shapiro " for TLSA RR",
28595b0945b5SGregory Neil Shapiro sizeof(SmtpError));
28605b0945b5SGregory Neil Shapiro # if NAMED_BIND
28615b0945b5SGregory Neil Shapiro SM_SET_H_ERRNO(TRY_AGAIN);
28625b0945b5SGregory Neil Shapiro # endif
28635b0945b5SGregory Neil Shapiro }
2864*d39bd2c1SGregory Neil Shapiro #endif /* DANE */
28658774250cSGregory Neil Shapiro mci->mci_errno = errno;
2866c2aa98e2SPeter Wemm mci->mci_lastuse = curtime();
286706f25ae9SGregory Neil Shapiro mci->mci_deliveries = 0;
2868c2aa98e2SPeter Wemm mci->mci_exitstat = i;
28696f9c8e5bSGregory Neil Shapiro mci_clr_extensions(mci);
2870c2aa98e2SPeter Wemm #if NAMED_BIND
2871c2aa98e2SPeter Wemm mci->mci_herrno = h_errno;
28725b0945b5SGregory Neil Shapiro #endif
287340266059SGregory Neil Shapiro
287440266059SGregory Neil Shapiro /*
287540266059SGregory Neil Shapiro ** Have we tried long enough to get a connection?
287640266059SGregory Neil Shapiro ** If yes, skip to the fallback MX hosts
287740266059SGregory Neil Shapiro ** (if existent).
287840266059SGregory Neil Shapiro */
287940266059SGregory Neil Shapiro
288040266059SGregory Neil Shapiro if (enough > 0 && mci->mci_lastuse >= enough)
288140266059SGregory Neil Shapiro {
288240266059SGregory Neil Shapiro int h;
288340266059SGregory Neil Shapiro #if NAMED_BIND
2884e92d3f3fSGregory Neil Shapiro extern int NumFallbackMXHosts;
28855b0945b5SGregory Neil Shapiro #else
2886e92d3f3fSGregory Neil Shapiro const int NumFallbackMXHosts = 0;
28875b0945b5SGregory Neil Shapiro #endif
288840266059SGregory Neil Shapiro
288940266059SGregory Neil Shapiro if (hostnum < nummxhosts && LogLevel > 9)
289040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
289140266059SGregory Neil Shapiro "Timeout.to_aconnect occurred before exhausting all addresses");
289240266059SGregory Neil Shapiro
289340266059SGregory Neil Shapiro /* turn off timeout if fallback available */
2894e92d3f3fSGregory Neil Shapiro if (NumFallbackMXHosts > 0)
289540266059SGregory Neil Shapiro enough = 0;
289640266059SGregory Neil Shapiro
289740266059SGregory Neil Shapiro /* skip to a fallback MX host */
2898e92d3f3fSGregory Neil Shapiro h = nummxhosts - NumFallbackMXHosts;
289940266059SGregory Neil Shapiro if (hostnum < h)
290040266059SGregory Neil Shapiro hostnum = h;
290140266059SGregory Neil Shapiro }
2902c2aa98e2SPeter Wemm if (i == EX_OK)
2903c2aa98e2SPeter Wemm {
290440266059SGregory Neil Shapiro goodmxfound = true;
2905605302a5SGregory Neil Shapiro markstats(e, firstto, STATS_CONNECT);
2906c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPENING;
2907c2aa98e2SPeter Wemm mci_cache(mci);
2908c2aa98e2SPeter Wemm if (TrafficLogFile != NULL)
290940266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile,
291040266059SGregory Neil Shapiro SM_TIME_DEFAULT,
291140266059SGregory Neil Shapiro "%05d === CONNECT %s\n",
291240266059SGregory Neil Shapiro (int) CurrentPid,
291340266059SGregory Neil Shapiro hostbuf);
2914c2aa98e2SPeter Wemm break;
2915c2aa98e2SPeter Wemm }
2916c2aa98e2SPeter Wemm else
2917c2aa98e2SPeter Wemm {
2918e92d3f3fSGregory Neil Shapiro /* Try FallbackSmartHost? */
2919e92d3f3fSGregory Neil Shapiro if (should_try_fbsh(e, &tried_fallbacksmarthost,
2920d0cef73dSGregory Neil Shapiro hostbuf, sizeof(hostbuf), i))
2921e92d3f3fSGregory Neil Shapiro goto one_last_try;
2922e92d3f3fSGregory Neil Shapiro
2923c2aa98e2SPeter Wemm if (tTd(11, 1))
2924*d39bd2c1SGregory Neil Shapiro sm_dprintf("openmailer: makeconnection(%s) => stat=%d, errno=%d\n",
2925*d39bd2c1SGregory Neil Shapiro hostbuf, i, errno);
2926c2aa98e2SPeter Wemm if (i == EX_TEMPFAIL)
292740266059SGregory Neil Shapiro goodmxfound = true;
2928c2aa98e2SPeter Wemm mci_unlock_host(mci);
2929c2aa98e2SPeter Wemm }
2930c2aa98e2SPeter Wemm
2931c2aa98e2SPeter Wemm /* enter status of this host */
2932c2aa98e2SPeter Wemm setstat(i);
2933c2aa98e2SPeter Wemm
2934c2aa98e2SPeter Wemm /* should print some message here for -v mode */
2935c2aa98e2SPeter Wemm }
2936c2aa98e2SPeter Wemm if (mci == NULL)
2937c2aa98e2SPeter Wemm {
2938c2aa98e2SPeter Wemm syserr("deliver: no host name");
2939c2aa98e2SPeter Wemm rcode = EX_SOFTWARE;
2940c2aa98e2SPeter Wemm goto give_up;
2941c2aa98e2SPeter Wemm }
2942c2aa98e2SPeter Wemm mci->mci_pid = 0;
2943c2aa98e2SPeter Wemm }
2944c2aa98e2SPeter Wemm else
2945c2aa98e2SPeter Wemm {
2946c2aa98e2SPeter Wemm /* flush any expired connections */
2947c2aa98e2SPeter Wemm (void) mci_scan(NULL);
2948c2aa98e2SPeter Wemm mci = NULL;
2949c2aa98e2SPeter Wemm
2950c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags))
2951c2aa98e2SPeter Wemm {
2952c2aa98e2SPeter Wemm /* try to get a cached connection */
2953c2aa98e2SPeter Wemm mci = mci_get(m->m_name, m);
2954c2aa98e2SPeter Wemm if (mci->mci_host == NULL)
2955c2aa98e2SPeter Wemm mci->mci_host = m->m_name;
2956c2aa98e2SPeter Wemm CurHostName = mci->mci_host;
2957c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED)
2958c2aa98e2SPeter Wemm {
2959c2aa98e2SPeter Wemm message("Using cached LMTP connection for %s...",
2960c2aa98e2SPeter Wemm m->m_name);
296106f25ae9SGregory Neil Shapiro mci->mci_deliveries++;
2962c2aa98e2SPeter Wemm goto do_transfer;
2963c2aa98e2SPeter Wemm }
2964c2aa98e2SPeter Wemm }
2965c2aa98e2SPeter Wemm
2966c2aa98e2SPeter Wemm /* announce the connection to verbose listeners */
2967c2aa98e2SPeter Wemm if (host == NULL || host[0] == '\0')
2968c2aa98e2SPeter Wemm message("Connecting to %s...", m->m_name);
2969c2aa98e2SPeter Wemm else
2970c2aa98e2SPeter Wemm message("Connecting to %s via %s...", host, m->m_name);
2971c2aa98e2SPeter Wemm if (TrafficLogFile != NULL)
2972c2aa98e2SPeter Wemm {
2973c2aa98e2SPeter Wemm char **av;
2974c2aa98e2SPeter Wemm
297540266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
297640266059SGregory Neil Shapiro "%05d === EXEC", (int) CurrentPid);
2977c2aa98e2SPeter Wemm for (av = pv; *av != NULL; av++)
297840266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile,
297940266059SGregory Neil Shapiro SM_TIME_DEFAULT, " %s",
298040266059SGregory Neil Shapiro *av);
298140266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
298240266059SGregory Neil Shapiro "\n");
2983c2aa98e2SPeter Wemm }
2984c2aa98e2SPeter Wemm
2985c2aa98e2SPeter Wemm checkfd012("before creating mail pipe");
2986c2aa98e2SPeter Wemm
2987c2aa98e2SPeter Wemm /* create a pipe to shove the mail through */
2988c2aa98e2SPeter Wemm if (pipe(mpvect) < 0)
2989c2aa98e2SPeter Wemm {
2990c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): pipe (to mailer)",
2991c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
2992c2aa98e2SPeter Wemm if (tTd(11, 1))
299340266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n");
2994c2aa98e2SPeter Wemm rcode = EX_OSERR;
2995c2aa98e2SPeter Wemm goto give_up;
2996c2aa98e2SPeter Wemm }
2997c2aa98e2SPeter Wemm
2998c2aa98e2SPeter Wemm #if XDEBUG
2999c2aa98e2SPeter Wemm /* make sure we didn't get one of the standard I/O files */
3000c2aa98e2SPeter Wemm if (mpvect[0] < 3 || mpvect[1] < 3)
3001c2aa98e2SPeter Wemm {
3002c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): bogus mpvect %d %d",
3003c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name,
3004c2aa98e2SPeter Wemm mpvect[0], mpvect[1]);
300540266059SGregory Neil Shapiro printopenfds(true);
3006c2aa98e2SPeter Wemm if (tTd(11, 1))
300740266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n");
3008c2aa98e2SPeter Wemm rcode = EX_OSERR;
3009c2aa98e2SPeter Wemm goto give_up;
3010c2aa98e2SPeter Wemm }
3011c2aa98e2SPeter Wemm
3012c2aa98e2SPeter Wemm /* make sure system call isn't dead meat */
3013c2aa98e2SPeter Wemm checkfdopen(mpvect[0], "mpvect[0]");
3014c2aa98e2SPeter Wemm checkfdopen(mpvect[1], "mpvect[1]");
3015c2aa98e2SPeter Wemm if (mpvect[0] == mpvect[1] ||
3016c2aa98e2SPeter Wemm (e->e_lockfp != NULL &&
301740266059SGregory Neil Shapiro (mpvect[0] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD,
301840266059SGregory Neil Shapiro NULL) ||
301940266059SGregory Neil Shapiro mpvect[1] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD,
302040266059SGregory Neil Shapiro NULL))))
3021c2aa98e2SPeter Wemm {
3022c2aa98e2SPeter Wemm if (e->e_lockfp == NULL)
3023c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): overlapping mpvect %d %d",
3024c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR),
3025c2aa98e2SPeter Wemm m->m_name, mpvect[0], mpvect[1]);
3026c2aa98e2SPeter Wemm else
3027c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d",
3028c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR),
3029c2aa98e2SPeter Wemm m->m_name, mpvect[0], mpvect[1],
303040266059SGregory Neil Shapiro sm_io_getinfo(e->e_lockfp,
303140266059SGregory Neil Shapiro SM_IO_WHAT_FD, NULL));
3032c2aa98e2SPeter Wemm }
303306f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
3034c2aa98e2SPeter Wemm
303506f25ae9SGregory Neil Shapiro /* create a return pipe */
3036c2aa98e2SPeter Wemm if (pipe(rpvect) < 0)
3037c2aa98e2SPeter Wemm {
3038c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): pipe (from mailer)",
3039c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR),
3040c2aa98e2SPeter Wemm m->m_name);
3041c2aa98e2SPeter Wemm (void) close(mpvect[0]);
3042c2aa98e2SPeter Wemm (void) close(mpvect[1]);
3043c2aa98e2SPeter Wemm if (tTd(11, 1))
304440266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n");
3045c2aa98e2SPeter Wemm rcode = EX_OSERR;
3046c2aa98e2SPeter Wemm goto give_up;
3047c2aa98e2SPeter Wemm }
3048c2aa98e2SPeter Wemm checkfdopen(rpvect[0], "rpvect[0]");
3049c2aa98e2SPeter Wemm checkfdopen(rpvect[1], "rpvect[1]");
3050c2aa98e2SPeter Wemm
3051c2aa98e2SPeter Wemm /*
3052c2aa98e2SPeter Wemm ** Actually fork the mailer process.
3053c2aa98e2SPeter Wemm ** DOFORK is clever about retrying.
3054c2aa98e2SPeter Wemm **
3055c2aa98e2SPeter Wemm ** Dispose of SIGCHLD signal catchers that may be laying
305606f25ae9SGregory Neil Shapiro ** around so that endmailer will get it.
3057c2aa98e2SPeter Wemm */
3058c2aa98e2SPeter Wemm
305940266059SGregory Neil Shapiro if (e->e_xfp != NULL) /* for debugging */
306040266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
306140266059SGregory Neil Shapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
306240266059SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL);
306306f25ae9SGregory Neil Shapiro
306406f25ae9SGregory Neil Shapiro
3065c2aa98e2SPeter Wemm DOFORK(FORK);
3066c2aa98e2SPeter Wemm /* pid is set by DOFORK */
306706f25ae9SGregory Neil Shapiro
3068c2aa98e2SPeter Wemm if (pid < 0)
3069c2aa98e2SPeter Wemm {
3070c2aa98e2SPeter Wemm /* failure */
3071c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot fork",
3072c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
3073c2aa98e2SPeter Wemm (void) close(mpvect[0]);
3074c2aa98e2SPeter Wemm (void) close(mpvect[1]);
3075c2aa98e2SPeter Wemm (void) close(rpvect[0]);
3076c2aa98e2SPeter Wemm (void) close(rpvect[1]);
3077c2aa98e2SPeter Wemm if (tTd(11, 1))
307840266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n");
3079c2aa98e2SPeter Wemm rcode = EX_OSERR;
3080c2aa98e2SPeter Wemm goto give_up;
3081c2aa98e2SPeter Wemm }
3082c2aa98e2SPeter Wemm else if (pid == 0)
3083c2aa98e2SPeter Wemm {
308406f25ae9SGregory Neil Shapiro int save_errno;
308540266059SGregory Neil Shapiro int sff;
3086c2aa98e2SPeter Wemm int new_euid = NO_UID;
3087c2aa98e2SPeter Wemm int new_ruid = NO_UID;
3088c2aa98e2SPeter Wemm int new_gid = NO_GID;
308940266059SGregory Neil Shapiro char *user = NULL;
3090c2aa98e2SPeter Wemm struct stat stb;
3091c2aa98e2SPeter Wemm extern int DtableSize;
3092c2aa98e2SPeter Wemm
309340266059SGregory Neil Shapiro CurrentPid = getpid();
309440266059SGregory Neil Shapiro
309513058a91SGregory Neil Shapiro /* clear the events to turn off SIGALRMs */
309640266059SGregory Neil Shapiro sm_clear_events();
309713058a91SGregory Neil Shapiro
30988774250cSGregory Neil Shapiro /* Reset global flags */
30998774250cSGregory Neil Shapiro RestartRequest = NULL;
310040266059SGregory Neil Shapiro RestartWorkGroup = false;
31018774250cSGregory Neil Shapiro ShutdownRequest = NULL;
31028774250cSGregory Neil Shapiro PendingSignal = 0;
31038774250cSGregory Neil Shapiro
3104c2aa98e2SPeter Wemm if (e->e_lockfp != NULL)
310540266059SGregory Neil Shapiro (void) close(sm_io_getinfo(e->e_lockfp,
310640266059SGregory Neil Shapiro SM_IO_WHAT_FD,
310740266059SGregory Neil Shapiro NULL));
3108c2aa98e2SPeter Wemm
3109c2aa98e2SPeter Wemm /* child -- set up input & exec mailer */
311040266059SGregory Neil Shapiro (void) sm_signal(SIGALRM, sm_signal_noop);
311140266059SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL);
311240266059SGregory Neil Shapiro (void) sm_signal(SIGHUP, SIG_IGN);
311340266059SGregory Neil Shapiro (void) sm_signal(SIGINT, SIG_IGN);
311440266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL);
311513058a91SGregory Neil Shapiro #ifdef SIGUSR1
311640266059SGregory Neil Shapiro (void) sm_signal(SIGUSR1, sm_signal_noop);
31175b0945b5SGregory Neil Shapiro #endif
3118c2aa98e2SPeter Wemm
3119c2aa98e2SPeter Wemm if (m != FileMailer || stat(tochain->q_user, &stb) < 0)
3120c2aa98e2SPeter Wemm stb.st_mode = 0;
3121c2aa98e2SPeter Wemm
3122c2aa98e2SPeter Wemm #if HASSETUSERCONTEXT
3123c2aa98e2SPeter Wemm /*
3124c2aa98e2SPeter Wemm ** Set user resources.
3125c2aa98e2SPeter Wemm */
3126c2aa98e2SPeter Wemm
3127c2aa98e2SPeter Wemm if (contextaddr != NULL)
3128c2aa98e2SPeter Wemm {
312913bd1963SGregory Neil Shapiro int sucflags;
3130c2aa98e2SPeter Wemm struct passwd *pwd;
3131c2aa98e2SPeter Wemm
3132c2aa98e2SPeter Wemm if (contextaddr->q_ruser != NULL)
3133c2aa98e2SPeter Wemm pwd = sm_getpwnam(contextaddr->q_ruser);
3134c2aa98e2SPeter Wemm else
3135c2aa98e2SPeter Wemm pwd = sm_getpwnam(contextaddr->q_user);
313613bd1963SGregory Neil Shapiro sucflags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
3137906a940eSEdward Tomasz Napierala # ifdef LOGIN_SETCPUMASK
3138906a940eSEdward Tomasz Napierala sucflags |= LOGIN_SETCPUMASK;
31395b0945b5SGregory Neil Shapiro # endif
3140906a940eSEdward Tomasz Napierala # ifdef LOGIN_SETLOGINCLASS
3141906a940eSEdward Tomasz Napierala sucflags |= LOGIN_SETLOGINCLASS;
31425b0945b5SGregory Neil Shapiro # endif
314313bd1963SGregory Neil Shapiro # ifdef LOGIN_SETMAC
314413bd1963SGregory Neil Shapiro sucflags |= LOGIN_SETMAC;
31455b0945b5SGregory Neil Shapiro # endif
3146959366dcSGregory Neil Shapiro if (pwd != NULL &&
3147959366dcSGregory Neil Shapiro setusercontext(NULL, pwd, pwd->pw_uid,
314813bd1963SGregory Neil Shapiro sucflags) == -1 &&
3149959366dcSGregory Neil Shapiro suidwarn)
3150959366dcSGregory Neil Shapiro {
3151959366dcSGregory Neil Shapiro syserr("openmailer: setusercontext() failed");
3152959366dcSGregory Neil Shapiro exit(EX_TEMPFAIL);
3153959366dcSGregory Neil Shapiro }
3154c2aa98e2SPeter Wemm }
315506f25ae9SGregory Neil Shapiro #endif /* HASSETUSERCONTEXT */
3156c2aa98e2SPeter Wemm
315740266059SGregory Neil Shapiro #if HASNICE
3158c2aa98e2SPeter Wemm /* tweak niceness */
3159c2aa98e2SPeter Wemm if (m->m_nice != 0)
316006f25ae9SGregory Neil Shapiro (void) nice(m->m_nice);
31612fb4f839SGregory Neil Shapiro #endif
3162c2aa98e2SPeter Wemm
3163c2aa98e2SPeter Wemm /* reset group id */
3164c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, m->m_flags))
3165e92d3f3fSGregory Neil Shapiro {
3166e92d3f3fSGregory Neil Shapiro if (m->m_gid == NO_GID)
3167e92d3f3fSGregory Neil Shapiro new_gid = RunAsGid;
3168e92d3f3fSGregory Neil Shapiro else
3169c2aa98e2SPeter Wemm new_gid = m->m_gid;
3170e92d3f3fSGregory Neil Shapiro }
3171c2aa98e2SPeter Wemm else if (bitset(S_ISGID, stb.st_mode))
3172c2aa98e2SPeter Wemm new_gid = stb.st_gid;
3173c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_gid != 0)
3174c2aa98e2SPeter Wemm {
3175c2aa98e2SPeter Wemm if (!DontInitGroups)
3176c2aa98e2SPeter Wemm {
317740266059SGregory Neil Shapiro user = ctladdr->q_ruser;
317840266059SGregory Neil Shapiro if (user == NULL)
317940266059SGregory Neil Shapiro user = ctladdr->q_user;
3180c2aa98e2SPeter Wemm
318140266059SGregory Neil Shapiro if (initgroups(user,
318240266059SGregory Neil Shapiro ctladdr->q_gid) == -1
318340266059SGregory Neil Shapiro && suidwarn)
318406f25ae9SGregory Neil Shapiro {
3185da7d7b9cSGregory Neil Shapiro syserr("openmailer: initgroups(%s, %ld) failed",
3186da7d7b9cSGregory Neil Shapiro user, (long) ctladdr->q_gid);
318706f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL);
318806f25ae9SGregory Neil Shapiro }
3189c2aa98e2SPeter Wemm }
3190c2aa98e2SPeter Wemm else
3191c2aa98e2SPeter Wemm {
3192c2aa98e2SPeter Wemm GIDSET_T gidset[1];
3193c2aa98e2SPeter Wemm
3194c2aa98e2SPeter Wemm gidset[0] = ctladdr->q_gid;
319540266059SGregory Neil Shapiro if (setgroups(1, gidset) == -1
319640266059SGregory Neil Shapiro && suidwarn)
319706f25ae9SGregory Neil Shapiro {
3198c2aa98e2SPeter Wemm syserr("openmailer: setgroups() failed");
319906f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL);
320006f25ae9SGregory Neil Shapiro }
3201c2aa98e2SPeter Wemm }
3202c2aa98e2SPeter Wemm new_gid = ctladdr->q_gid;
3203c2aa98e2SPeter Wemm }
3204c2aa98e2SPeter Wemm else
3205c2aa98e2SPeter Wemm {
3206c2aa98e2SPeter Wemm if (!DontInitGroups)
3207c2aa98e2SPeter Wemm {
320840266059SGregory Neil Shapiro user = DefUser;
320940266059SGregory Neil Shapiro if (initgroups(DefUser, DefGid) == -1 &&
321040266059SGregory Neil Shapiro suidwarn)
321106f25ae9SGregory Neil Shapiro {
3212da7d7b9cSGregory Neil Shapiro syserr("openmailer: initgroups(%s, %ld) failed",
3213da7d7b9cSGregory Neil Shapiro DefUser, (long) DefGid);
321406f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL);
321506f25ae9SGregory Neil Shapiro }
3216c2aa98e2SPeter Wemm }
3217c2aa98e2SPeter Wemm else
3218c2aa98e2SPeter Wemm {
3219c2aa98e2SPeter Wemm GIDSET_T gidset[1];
3220c2aa98e2SPeter Wemm
3221c2aa98e2SPeter Wemm gidset[0] = DefGid;
322240266059SGregory Neil Shapiro if (setgroups(1, gidset) == -1
322340266059SGregory Neil Shapiro && suidwarn)
322406f25ae9SGregory Neil Shapiro {
3225c2aa98e2SPeter Wemm syserr("openmailer: setgroups() failed");
322606f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL);
322706f25ae9SGregory Neil Shapiro }
3228c2aa98e2SPeter Wemm }
3229e92d3f3fSGregory Neil Shapiro if (m->m_gid == NO_GID)
3230c2aa98e2SPeter Wemm new_gid = DefGid;
3231c2aa98e2SPeter Wemm else
3232c2aa98e2SPeter Wemm new_gid = m->m_gid;
3233c2aa98e2SPeter Wemm }
323406f25ae9SGregory Neil Shapiro if (new_gid != NO_GID)
323506f25ae9SGregory Neil Shapiro {
323606f25ae9SGregory Neil Shapiro if (RunAsUid != 0 &&
323706f25ae9SGregory Neil Shapiro bitnset(M_SPECIFIC_UID, m->m_flags) &&
323806f25ae9SGregory Neil Shapiro new_gid != getgid() &&
323906f25ae9SGregory Neil Shapiro new_gid != getegid())
324006f25ae9SGregory Neil Shapiro {
324106f25ae9SGregory Neil Shapiro /* Only root can change the gid */
3242da7d7b9cSGregory Neil Shapiro syserr("openmailer: insufficient privileges to change gid, RunAsUid=%ld, new_gid=%ld, gid=%ld, egid=%ld",
3243da7d7b9cSGregory Neil Shapiro (long) RunAsUid, (long) new_gid,
3244da7d7b9cSGregory Neil Shapiro (long) getgid(), (long) getegid());
324506f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL);
324606f25ae9SGregory Neil Shapiro }
324706f25ae9SGregory Neil Shapiro
324806f25ae9SGregory Neil Shapiro if (setgid(new_gid) < 0 && suidwarn)
324906f25ae9SGregory Neil Shapiro {
3250c2aa98e2SPeter Wemm syserr("openmailer: setgid(%ld) failed",
3251c2aa98e2SPeter Wemm (long) new_gid);
325206f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL);
325306f25ae9SGregory Neil Shapiro }
325406f25ae9SGregory Neil Shapiro }
325506f25ae9SGregory Neil Shapiro
325606f25ae9SGregory Neil Shapiro /* change root to some "safe" directory */
325706f25ae9SGregory Neil Shapiro if (m->m_rootdir != NULL)
325806f25ae9SGregory Neil Shapiro {
3259d0cef73dSGregory Neil Shapiro expand(m->m_rootdir, cbuf, sizeof(cbuf), e);
326006f25ae9SGregory Neil Shapiro if (tTd(11, 20))
326140266059SGregory Neil Shapiro sm_dprintf("openmailer: chroot %s\n",
326294c01205SGregory Neil Shapiro cbuf);
326394c01205SGregory Neil Shapiro if (chroot(cbuf) < 0)
326406f25ae9SGregory Neil Shapiro {
326506f25ae9SGregory Neil Shapiro syserr("openmailer: Cannot chroot(%s)",
326694c01205SGregory Neil Shapiro cbuf);
326706f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL);
326806f25ae9SGregory Neil Shapiro }
326906f25ae9SGregory Neil Shapiro if (chdir("/") < 0)
327006f25ae9SGregory Neil Shapiro {
327106f25ae9SGregory Neil Shapiro syserr("openmailer: cannot chdir(/)");
327206f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL);
327306f25ae9SGregory Neil Shapiro }
327406f25ae9SGregory Neil Shapiro }
3275c2aa98e2SPeter Wemm
3276c2aa98e2SPeter Wemm /* reset user id */
3277c2aa98e2SPeter Wemm endpwent();
327840266059SGregory Neil Shapiro sm_mbdb_terminate();
3279c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, m->m_flags))
328013058a91SGregory Neil Shapiro {
3281e92d3f3fSGregory Neil Shapiro if (m->m_uid == NO_UID)
3282e92d3f3fSGregory Neil Shapiro new_euid = RunAsUid;
3283e92d3f3fSGregory Neil Shapiro else
3284c2aa98e2SPeter Wemm new_euid = m->m_uid;
328513058a91SGregory Neil Shapiro
328613058a91SGregory Neil Shapiro /*
328713058a91SGregory Neil Shapiro ** Undo the effects of the uid change in main
328813058a91SGregory Neil Shapiro ** for signal handling. The real uid may
328913058a91SGregory Neil Shapiro ** be used by mailer in adding a "From "
329013058a91SGregory Neil Shapiro ** line.
329113058a91SGregory Neil Shapiro */
329213058a91SGregory Neil Shapiro
329313058a91SGregory Neil Shapiro if (RealUid != 0 && RealUid != getuid())
329440266059SGregory Neil Shapiro {
329540266059SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETEUID
329640266059SGregory Neil Shapiro # if HASSETREUID
329740266059SGregory Neil Shapiro if (setreuid(RealUid, geteuid()) < 0)
329840266059SGregory Neil Shapiro {
329940266059SGregory Neil Shapiro syserr("openmailer: setreuid(%d, %d) failed",
330040266059SGregory Neil Shapiro (int) RealUid, (int) geteuid());
330140266059SGregory Neil Shapiro exit(EX_OSERR);
330240266059SGregory Neil Shapiro }
330340266059SGregory Neil Shapiro # endif /* HASSETREUID */
330440266059SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD == USE_SETEUID */
330540266059SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETREUID
330613058a91SGregory Neil Shapiro new_ruid = RealUid;
33075b0945b5SGregory Neil Shapiro #endif
330840266059SGregory Neil Shapiro }
330913058a91SGregory Neil Shapiro }
3310c2aa98e2SPeter Wemm else if (bitset(S_ISUID, stb.st_mode))
3311c2aa98e2SPeter Wemm new_ruid = stb.st_uid;
3312c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_uid != 0)
3313c2aa98e2SPeter Wemm new_ruid = ctladdr->q_uid;
3314e92d3f3fSGregory Neil Shapiro else if (m->m_uid != NO_UID)
3315c2aa98e2SPeter Wemm new_ruid = m->m_uid;
3316c2aa98e2SPeter Wemm else
3317c2aa98e2SPeter Wemm new_ruid = DefUid;
3318605302a5SGregory Neil Shapiro
3319605302a5SGregory Neil Shapiro #if _FFR_USE_SETLOGIN
3320605302a5SGregory Neil Shapiro /* run disconnected from terminal and set login name */
3321605302a5SGregory Neil Shapiro if (setsid() >= 0 &&
3322605302a5SGregory Neil Shapiro ctladdr != NULL && ctladdr->q_uid != 0 &&
3323605302a5SGregory Neil Shapiro new_euid == ctladdr->q_uid)
3324605302a5SGregory Neil Shapiro {
3325605302a5SGregory Neil Shapiro struct passwd *pwd;
3326605302a5SGregory Neil Shapiro
3327605302a5SGregory Neil Shapiro pwd = sm_getpwuid(ctladdr->q_uid);
3328605302a5SGregory Neil Shapiro if (pwd != NULL && suidwarn)
3329605302a5SGregory Neil Shapiro (void) setlogin(pwd->pw_name);
3330605302a5SGregory Neil Shapiro endpwent();
3331605302a5SGregory Neil Shapiro }
3332605302a5SGregory Neil Shapiro #endif /* _FFR_USE_SETLOGIN */
3333605302a5SGregory Neil Shapiro
3334c2aa98e2SPeter Wemm if (new_euid != NO_UID)
3335c2aa98e2SPeter Wemm {
333606f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && new_euid != RunAsUid)
333706f25ae9SGregory Neil Shapiro {
333806f25ae9SGregory Neil Shapiro /* Only root can change the uid */
3339da7d7b9cSGregory Neil Shapiro syserr("openmailer: insufficient privileges to change uid, new_euid=%ld, RunAsUid=%ld",
3340da7d7b9cSGregory Neil Shapiro (long) new_euid, (long) RunAsUid);
334106f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL);
334206f25ae9SGregory Neil Shapiro }
334306f25ae9SGregory Neil Shapiro
3344c2aa98e2SPeter Wemm vendor_set_uid(new_euid);
334506f25ae9SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETEUID
3346c2aa98e2SPeter Wemm if (seteuid(new_euid) < 0 && suidwarn)
334706f25ae9SGregory Neil Shapiro {
3348c2aa98e2SPeter Wemm syserr("openmailer: seteuid(%ld) failed",
3349c2aa98e2SPeter Wemm (long) new_euid);
335006f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL);
335106f25ae9SGregory Neil Shapiro }
335206f25ae9SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD == USE_SETEUID */
335306f25ae9SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETREUID
3354c2aa98e2SPeter Wemm if (setreuid(new_ruid, new_euid) < 0 && suidwarn)
335506f25ae9SGregory Neil Shapiro {
3356c2aa98e2SPeter Wemm syserr("openmailer: setreuid(%ld, %ld) failed",
3357c2aa98e2SPeter Wemm (long) new_ruid, (long) new_euid);
335806f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL);
335906f25ae9SGregory Neil Shapiro }
336006f25ae9SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD == USE_SETREUID */
336106f25ae9SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETUID
3362c2aa98e2SPeter Wemm if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn)
336306f25ae9SGregory Neil Shapiro {
3364c2aa98e2SPeter Wemm syserr("openmailer: setuid(%ld) failed",
3365c2aa98e2SPeter Wemm (long) new_euid);
336606f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL);
336706f25ae9SGregory Neil Shapiro }
336806f25ae9SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD == USE_SETUID */
3369c2aa98e2SPeter Wemm }
3370c2aa98e2SPeter Wemm else if (new_ruid != NO_UID)
3371c2aa98e2SPeter Wemm {
3372c2aa98e2SPeter Wemm vendor_set_uid(new_ruid);
3373c2aa98e2SPeter Wemm if (setuid(new_ruid) < 0 && suidwarn)
337406f25ae9SGregory Neil Shapiro {
3375c2aa98e2SPeter Wemm syserr("openmailer: setuid(%ld) failed",
3376c2aa98e2SPeter Wemm (long) new_ruid);
337706f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL);
337806f25ae9SGregory Neil Shapiro }
3379c2aa98e2SPeter Wemm }
3380c2aa98e2SPeter Wemm
3381c2aa98e2SPeter Wemm if (tTd(11, 2))
3382da7d7b9cSGregory Neil Shapiro sm_dprintf("openmailer: running as r/euid=%ld/%ld, r/egid=%ld/%ld\n",
3383da7d7b9cSGregory Neil Shapiro (long) getuid(), (long) geteuid(),
3384da7d7b9cSGregory Neil Shapiro (long) getgid(), (long) getegid());
3385c2aa98e2SPeter Wemm
3386c2aa98e2SPeter Wemm /* move into some "safe" directory */
3387c2aa98e2SPeter Wemm if (m->m_execdir != NULL)
3388c2aa98e2SPeter Wemm {
3389c2aa98e2SPeter Wemm char *q;
3390c2aa98e2SPeter Wemm
3391c2aa98e2SPeter Wemm for (p = m->m_execdir; p != NULL; p = q)
3392c2aa98e2SPeter Wemm {
3393c2aa98e2SPeter Wemm q = strchr(p, ':');
3394c2aa98e2SPeter Wemm if (q != NULL)
3395c2aa98e2SPeter Wemm *q = '\0';
3396d0cef73dSGregory Neil Shapiro expand(p, cbuf, sizeof(cbuf), e);
3397c2aa98e2SPeter Wemm if (q != NULL)
3398c2aa98e2SPeter Wemm *q++ = ':';
3399c2aa98e2SPeter Wemm if (tTd(11, 20))
340040266059SGregory Neil Shapiro sm_dprintf("openmailer: trydir %s\n",
340194c01205SGregory Neil Shapiro cbuf);
340294c01205SGregory Neil Shapiro if (cbuf[0] != '\0' &&
340394c01205SGregory Neil Shapiro chdir(cbuf) >= 0)
3404c2aa98e2SPeter Wemm break;
3405c2aa98e2SPeter Wemm }
3406c2aa98e2SPeter Wemm }
3407c2aa98e2SPeter Wemm
340840266059SGregory Neil Shapiro /* Check safety of program to be run */
340940266059SGregory Neil Shapiro sff = SFF_ROOTOK|SFF_EXECOK;
341040266059SGregory Neil Shapiro if (!bitnset(DBS_RUNWRITABLEPROGRAM,
341140266059SGregory Neil Shapiro DontBlameSendmail))
341240266059SGregory Neil Shapiro sff |= SFF_NOGWFILES|SFF_NOWWFILES;
341340266059SGregory Neil Shapiro if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH,
341440266059SGregory Neil Shapiro DontBlameSendmail))
341540266059SGregory Neil Shapiro sff |= SFF_NOPATHCHECK;
341640266059SGregory Neil Shapiro else
341740266059SGregory Neil Shapiro sff |= SFF_SAFEDIRPATH;
341840266059SGregory Neil Shapiro ret = safefile(m->m_mailer, getuid(), getgid(),
341940266059SGregory Neil Shapiro user, sff, 0, NULL);
342040266059SGregory Neil Shapiro if (ret != 0)
342140266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
342240266059SGregory Neil Shapiro "Warning: program %s unsafe: %s",
342340266059SGregory Neil Shapiro m->m_mailer, sm_errstring(ret));
342440266059SGregory Neil Shapiro
3425c2aa98e2SPeter Wemm /* arrange to filter std & diag output of command */
3426c2aa98e2SPeter Wemm (void) close(rpvect[0]);
3427c2aa98e2SPeter Wemm if (dup2(rpvect[1], STDOUT_FILENO) < 0)
3428c2aa98e2SPeter Wemm {
3429c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup pipe %d for stdout",
3430c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR),
3431c2aa98e2SPeter Wemm m->m_name, rpvect[1]);
3432c2aa98e2SPeter Wemm _exit(EX_OSERR);
3433c2aa98e2SPeter Wemm }
3434c2aa98e2SPeter Wemm (void) close(rpvect[1]);
343506f25ae9SGregory Neil Shapiro
3436c2aa98e2SPeter Wemm if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0)
3437c2aa98e2SPeter Wemm {
3438c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup stdout for stderr",
3439c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR),
3440c2aa98e2SPeter Wemm m->m_name);
3441c2aa98e2SPeter Wemm _exit(EX_OSERR);
3442c2aa98e2SPeter Wemm }
3443c2aa98e2SPeter Wemm
3444c2aa98e2SPeter Wemm /* arrange to get standard input */
3445c2aa98e2SPeter Wemm (void) close(mpvect[1]);
3446c2aa98e2SPeter Wemm if (dup2(mpvect[0], STDIN_FILENO) < 0)
3447c2aa98e2SPeter Wemm {
3448c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup pipe %d for stdin",
3449c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR),
3450c2aa98e2SPeter Wemm m->m_name, mpvect[0]);
3451c2aa98e2SPeter Wemm _exit(EX_OSERR);
3452c2aa98e2SPeter Wemm }
3453c2aa98e2SPeter Wemm (void) close(mpvect[0]);
3454c2aa98e2SPeter Wemm
3455c2aa98e2SPeter Wemm /* arrange for all the files to be closed */
3456e92d3f3fSGregory Neil Shapiro sm_close_on_exec(STDERR_FILENO + 1, DtableSize);
3457c2aa98e2SPeter Wemm
3458605302a5SGregory Neil Shapiro #if !_FFR_USE_SETLOGIN
3459c2aa98e2SPeter Wemm /* run disconnected from terminal */
3460c2aa98e2SPeter Wemm (void) setsid();
34615b0945b5SGregory Neil Shapiro #endif
3462c2aa98e2SPeter Wemm
3463c2aa98e2SPeter Wemm /* try to execute the mailer */
346406f25ae9SGregory Neil Shapiro (void) execve(m->m_mailer, (ARGV_T) pv,
346506f25ae9SGregory Neil Shapiro (ARGV_T) UserEnviron);
346606f25ae9SGregory Neil Shapiro save_errno = errno;
3467c2aa98e2SPeter Wemm syserr("Cannot exec %s", m->m_mailer);
3468c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) ||
346906f25ae9SGregory Neil Shapiro transienterror(save_errno))
3470c2aa98e2SPeter Wemm _exit(EX_OSERR);
3471c2aa98e2SPeter Wemm _exit(EX_UNAVAILABLE);
3472c2aa98e2SPeter Wemm }
3473c2aa98e2SPeter Wemm
3474c2aa98e2SPeter Wemm /*
3475c2aa98e2SPeter Wemm ** Set up return value.
3476c2aa98e2SPeter Wemm */
3477c2aa98e2SPeter Wemm
3478c2aa98e2SPeter Wemm if (mci == NULL)
3479c2aa98e2SPeter Wemm {
348040266059SGregory Neil Shapiro if (clever)
348140266059SGregory Neil Shapiro {
348240266059SGregory Neil Shapiro /*
348340266059SGregory Neil Shapiro ** Allocate from general heap, not
348440266059SGregory Neil Shapiro ** envelope rpool, because this mci
348540266059SGregory Neil Shapiro ** is going to be cached.
348640266059SGregory Neil Shapiro */
348740266059SGregory Neil Shapiro
348840266059SGregory Neil Shapiro mci = mci_new(NULL);
348940266059SGregory Neil Shapiro }
349040266059SGregory Neil Shapiro else
349140266059SGregory Neil Shapiro {
349240266059SGregory Neil Shapiro /*
349340266059SGregory Neil Shapiro ** Prevent a storage leak by allocating
349440266059SGregory Neil Shapiro ** this from the envelope rpool.
349540266059SGregory Neil Shapiro */
349640266059SGregory Neil Shapiro
349740266059SGregory Neil Shapiro mci = mci_new(e->e_rpool);
349840266059SGregory Neil Shapiro }
3499c2aa98e2SPeter Wemm }
3500c2aa98e2SPeter Wemm mci->mci_mailer = m;
3501c2aa98e2SPeter Wemm if (clever)
3502c2aa98e2SPeter Wemm {
3503c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPENING;
3504c2aa98e2SPeter Wemm mci_cache(mci);
3505c2aa98e2SPeter Wemm }
3506c2aa98e2SPeter Wemm else
3507c2aa98e2SPeter Wemm {
3508c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPEN;
3509c2aa98e2SPeter Wemm }
3510c2aa98e2SPeter Wemm mci->mci_pid = pid;
3511c2aa98e2SPeter Wemm (void) close(mpvect[0]);
351240266059SGregory Neil Shapiro mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
3513e92d3f3fSGregory Neil Shapiro (void *) &(mpvect[1]), SM_IO_WRONLY_B,
351440266059SGregory Neil Shapiro NULL);
3515c2aa98e2SPeter Wemm if (mci->mci_out == NULL)
3516c2aa98e2SPeter Wemm {
3517c2aa98e2SPeter Wemm syserr("deliver: cannot create mailer output channel, fd=%d",
3518c2aa98e2SPeter Wemm mpvect[1]);
3519c2aa98e2SPeter Wemm (void) close(mpvect[1]);
3520c2aa98e2SPeter Wemm (void) close(rpvect[0]);
3521c2aa98e2SPeter Wemm (void) close(rpvect[1]);
3522c2aa98e2SPeter Wemm rcode = EX_OSERR;
3523c2aa98e2SPeter Wemm goto give_up;
3524c2aa98e2SPeter Wemm }
352506f25ae9SGregory Neil Shapiro
3526c2aa98e2SPeter Wemm (void) close(rpvect[1]);
352740266059SGregory Neil Shapiro mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
3528e92d3f3fSGregory Neil Shapiro (void *) &(rpvect[0]), SM_IO_RDONLY_B,
352940266059SGregory Neil Shapiro NULL);
3530c2aa98e2SPeter Wemm if (mci->mci_in == NULL)
3531c2aa98e2SPeter Wemm {
3532c2aa98e2SPeter Wemm syserr("deliver: cannot create mailer input channel, fd=%d",
3533c2aa98e2SPeter Wemm mpvect[1]);
3534c2aa98e2SPeter Wemm (void) close(rpvect[0]);
35352fb4f839SGregory Neil Shapiro SM_CLOSE_FP(mci->mci_out);
3536c2aa98e2SPeter Wemm rcode = EX_OSERR;
3537c2aa98e2SPeter Wemm goto give_up;
3538c2aa98e2SPeter Wemm }
3539c2aa98e2SPeter Wemm }
3540c2aa98e2SPeter Wemm
3541c2aa98e2SPeter Wemm /*
3542c2aa98e2SPeter Wemm ** If we are in SMTP opening state, send initial protocol.
3543c2aa98e2SPeter Wemm */
3544c2aa98e2SPeter Wemm
3545c2aa98e2SPeter Wemm if (bitnset(M_7BITS, m->m_flags) &&
3546c2aa98e2SPeter Wemm (!clever || mci->mci_state == MCIS_OPENING))
3547c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_7BIT;
3548c2aa98e2SPeter Wemm if (clever && mci->mci_state != MCIS_CLOSED)
3549c2aa98e2SPeter Wemm {
355040266059SGregory Neil Shapiro #if STARTTLS || SASL
355140266059SGregory Neil Shapiro char *srvname;
3552*d39bd2c1SGregory Neil Shapiro int dotpos;
355340266059SGregory Neil Shapiro # if SASL
3554193538b7SGregory Neil Shapiro # define DONE_AUTH(f) bitset(MCIF_AUTHACT, f)
35555b0945b5SGregory Neil Shapiro # endif
355606f25ae9SGregory Neil Shapiro # if STARTTLS
3557193538b7SGregory Neil Shapiro # define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f)
35585b0945b5SGregory Neil Shapiro # endif
3559c2aa98e2SPeter Wemm
3560*d39bd2c1SGregory Neil Shapiro srvname = setservermacros(mci, &dotpos);
35615b0945b5SGregory Neil Shapiro # if DANE
35625b0945b5SGregory Neil Shapiro SM_FREE(dane_vrfy_ctx.dane_vrfy_host);
35635b0945b5SGregory Neil Shapiro SM_FREE(dane_vrfy_ctx.dane_vrfy_sni);
35645b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_fp[0] = '\0';
3565*d39bd2c1SGregory Neil Shapiro if (STE_HAS_TLSA(ste) && ste->s_tlsa->dane_tlsa_sni != NULL)
35665b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_sni = sm_strdup(ste->s_tlsa->dane_tlsa_sni);
35675b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_host = sm_strdup(srvname);
3568*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
3569*d39bd2c1SGregory Neil Shapiro /* undo change of srvname (== mci->mci_host) */
35705b0945b5SGregory Neil Shapiro FIX_TRAIL_DOT(srvname);
357140266059SGregory Neil Shapiro
357240266059SGregory Neil Shapiro reconnect: /* after switching to an encrypted connection */
35735b0945b5SGregory Neil Shapiro # if DANE
35745b0945b5SGregory Neil Shapiro if (DONE_STARTTLS(mci->mci_flags))
35755b0945b5SGregory Neil Shapiro {
35765b0945b5SGregory Neil Shapiro /* use a "reset" function? */
3577*d39bd2c1SGregory Neil Shapiro /* when is it required to "reset" this data? */
35785b0945b5SGregory Neil Shapiro SM_FREE(dane_vrfy_ctx.dane_vrfy_host);
35795b0945b5SGregory Neil Shapiro SM_FREE(dane_vrfy_ctx.dane_vrfy_sni);
35805b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_fp[0] = '\0';
3581*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_res = DANE_VRFY_NONE;
3582*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_dane_enabled = false;
3583*d39bd2c1SGregory Neil Shapiro if (TTD(90, 40))
3584*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: reset: chk=%#x, dane_enabled=%d\n",
3585*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_chk,
3586*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_dane_enabled);
35875b0945b5SGregory Neil Shapiro }
35882fb4f839SGregory Neil Shapiro # endif /* DANE */
35895b0945b5SGregory Neil Shapiro
359040266059SGregory Neil Shapiro #endif /* STARTTLS || SASL */
359140266059SGregory Neil Shapiro
359240266059SGregory Neil Shapiro /* set the current connection information */
359340266059SGregory Neil Shapiro e->e_mci = mci;
359440266059SGregory Neil Shapiro #if SASL
359540266059SGregory Neil Shapiro mci->mci_saslcap = NULL;
35965b0945b5SGregory Neil Shapiro #endif
35972fb4f839SGregory Neil Shapiro #if _FFR_MTA_STS
35982fb4f839SGregory Neil Shapiro # define USEMTASTS (MTASTS && !SM_TLSI_IS(&(mci->mci_tlsi), TLSI_FL_NOSTS) && !iscltflgset(e, D_NOSTS))
35992fb4f839SGregory Neil Shapiro # if DANE
36002fb4f839SGregory Neil Shapiro # define CHKMTASTS (USEMTASTS && (ste == NULL || ste->s_tlsa == NULL || SM_TLSI_IS(&(mci->mci_tlsi), TLSI_FL_NODANE)))
36012fb4f839SGregory Neil Shapiro # else
36022fb4f839SGregory Neil Shapiro # define CHKMTASTS USEMTASTS
36032fb4f839SGregory Neil Shapiro # endif
36042fb4f839SGregory Neil Shapiro #endif /* _FFR_MTA_STS */
36052fb4f839SGregory Neil Shapiro #if _FFR_MTA_STS
36062fb4f839SGregory Neil Shapiro if (!DONE_STARTTLS(mci->mci_flags))
36072fb4f839SGregory Neil Shapiro {
36082fb4f839SGregory Neil Shapiro /*
36092fb4f839SGregory Neil Shapiro ** HACK: use the domain of the first valid RCPT for STS.
36102fb4f839SGregory Neil Shapiro ** It seems whoever wrote the specs did not consider
36112fb4f839SGregory Neil Shapiro ** SMTP sessions versus transactions.
36122fb4f839SGregory Neil Shapiro ** (but what would you expect from people who try
36132fb4f839SGregory Neil Shapiro ** to use https for "security" after relying on DNS?)
36142fb4f839SGregory Neil Shapiro */
36152fb4f839SGregory Neil Shapiro
36162fb4f839SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{rcpt_addr}"), "");
36172fb4f839SGregory Neil Shapiro # if DANE
3618*d39bd2c1SGregory Neil Shapiro if (MTASTS && STE_HAS_TLSA(ste))
36192fb4f839SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{sts_sni}"), "DANE");
36202fb4f839SGregory Neil Shapiro else
36212fb4f839SGregory Neil Shapiro # endif
36222fb4f839SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{sts_sni}"), "");
36232fb4f839SGregory Neil Shapiro if (USEMTASTS && firstto->q_user != NULL)
36242fb4f839SGregory Neil Shapiro {
36252fb4f839SGregory Neil Shapiro if (tTd(10, 64))
36262fb4f839SGregory Neil Shapiro {
36272fb4f839SGregory Neil Shapiro sm_dprintf("firstto ");
36282fb4f839SGregory Neil Shapiro printaddr(sm_debug_file(), firstto, false);
36292fb4f839SGregory Neil Shapiro }
36302fb4f839SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP,
36312fb4f839SGregory Neil Shapiro macid("{rcpt_addr}"), firstto->q_user);
36322fb4f839SGregory Neil Shapiro }
36332fb4f839SGregory Neil Shapiro else if (USEMTASTS)
36342fb4f839SGregory Neil Shapiro {
36352fb4f839SGregory Neil Shapiro if (tTd(10, 64))
36362fb4f839SGregory Neil Shapiro {
36372fb4f839SGregory Neil Shapiro sm_dprintf("tochain ");
36382fb4f839SGregory Neil Shapiro printaddr(sm_debug_file(), tochain, false);
36392fb4f839SGregory Neil Shapiro }
36402fb4f839SGregory Neil Shapiro for (to = tochain; to != NULL; to = to->q_tchain)
36412fb4f839SGregory Neil Shapiro {
36422fb4f839SGregory Neil Shapiro if (!QS_IS_UNMARKED(to->q_state))
36432fb4f839SGregory Neil Shapiro continue;
36442fb4f839SGregory Neil Shapiro if (to->q_user == NULL)
36452fb4f839SGregory Neil Shapiro continue;
36462fb4f839SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP,
36472fb4f839SGregory Neil Shapiro macid("{rcpt_addr}"), to->q_user);
36482fb4f839SGregory Neil Shapiro break;
36492fb4f839SGregory Neil Shapiro }
36502fb4f839SGregory Neil Shapiro }
36512fb4f839SGregory Neil Shapiro }
36522fb4f839SGregory Neil Shapiro #endif /* _FFR_MTA_STS */
36532fb4f839SGregory Neil Shapiro #if USE_EAI
36542fb4f839SGregory Neil Shapiro if (!addr_is_ascii(e->e_from.q_paddr) && !e->e_smtputf8)
36552fb4f839SGregory Neil Shapiro e->e_smtputf8 = true;
36562fb4f839SGregory Neil Shapiro for (to = tochain; to != NULL && !e->e_smtputf8; to = to->q_tchain)
36572fb4f839SGregory Neil Shapiro {
36582fb4f839SGregory Neil Shapiro if (!QS_IS_UNMARKED(to->q_state))
36592fb4f839SGregory Neil Shapiro continue;
36602fb4f839SGregory Neil Shapiro if (!addr_is_ascii(to->q_user))
36612fb4f839SGregory Neil Shapiro e->e_smtputf8 = true;
36622fb4f839SGregory Neil Shapiro }
36632fb4f839SGregory Neil Shapiro /* XXX reset e_smtputf8 to original state at the end? */
36642fb4f839SGregory Neil Shapiro #endif /* USE_EAI */
36652fb4f839SGregory Neil Shapiro
3666*d39bd2c1SGregory Neil Shapiro #define ONLY_HELO(f) bitset(MCIF_ONLY_EHLO, f)
3667*d39bd2c1SGregory Neil Shapiro #define SET_HELO(f) f |= MCIF_ONLY_EHLO
3668*d39bd2c1SGregory Neil Shapiro #define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO
3669*d39bd2c1SGregory Neil Shapiro
3670*d39bd2c1SGregory Neil Shapiro #if _FFR_SMTPS_CLIENT && STARTTLS
3671*d39bd2c1SGregory Neil Shapiro /*
3672*d39bd2c1SGregory Neil Shapiro ** For M_SMTPS_CLIENT, we do the STARTTLS code first,
3673*d39bd2c1SGregory Neil Shapiro ** then jump back and start the SMTP conversation.
3674*d39bd2c1SGregory Neil Shapiro */
3675*d39bd2c1SGregory Neil Shapiro
3676*d39bd2c1SGregory Neil Shapiro implicittls = bitnset(M_SMTPS_CLIENT, mci->mci_mailer->m_flags);
3677*d39bd2c1SGregory Neil Shapiro if (implicittls)
3678*d39bd2c1SGregory Neil Shapiro goto dotls;
3679*d39bd2c1SGregory Neil Shapiro backtosmtp:
3680*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_SMTPS_CLIENT && STARTTLS */
3681*d39bd2c1SGregory Neil Shapiro
368240266059SGregory Neil Shapiro smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags));
368340266059SGregory Neil Shapiro CLR_HELO(mci->mci_flags);
368440266059SGregory Neil Shapiro
368540266059SGregory Neil Shapiro if (IS_DLVR_RETURN(e))
368640266059SGregory Neil Shapiro {
368740266059SGregory Neil Shapiro /*
368840266059SGregory Neil Shapiro ** Check whether other side can deliver e-mail
368940266059SGregory Neil Shapiro ** fast enough
369040266059SGregory Neil Shapiro */
369140266059SGregory Neil Shapiro
369240266059SGregory Neil Shapiro if (!bitset(MCIF_DLVR_BY, mci->mci_flags))
369340266059SGregory Neil Shapiro {
369440266059SGregory Neil Shapiro e->e_status = "5.4.7";
369540266059SGregory Neil Shapiro usrerrenh(e->e_status,
369640266059SGregory Neil Shapiro "554 Server does not support Deliver By");
369740266059SGregory Neil Shapiro rcode = EX_UNAVAILABLE;
369840266059SGregory Neil Shapiro goto give_up;
369940266059SGregory Neil Shapiro }
370040266059SGregory Neil Shapiro if (e->e_deliver_by > 0 &&
370140266059SGregory Neil Shapiro e->e_deliver_by - (curtime() - e->e_ctime) <
370240266059SGregory Neil Shapiro mci->mci_min_by)
370340266059SGregory Neil Shapiro {
370440266059SGregory Neil Shapiro e->e_status = "5.4.7";
370540266059SGregory Neil Shapiro usrerrenh(e->e_status,
370640266059SGregory Neil Shapiro "554 Message can't be delivered in time; %ld < %ld",
37075b0945b5SGregory Neil Shapiro e->e_deliver_by - (long) (curtime() -
37085b0945b5SGregory Neil Shapiro e->e_ctime),
370940266059SGregory Neil Shapiro mci->mci_min_by);
371040266059SGregory Neil Shapiro rcode = EX_UNAVAILABLE;
371140266059SGregory Neil Shapiro goto give_up;
371240266059SGregory Neil Shapiro }
371340266059SGregory Neil Shapiro }
371440266059SGregory Neil Shapiro
371540266059SGregory Neil Shapiro #if STARTTLS
3716*d39bd2c1SGregory Neil Shapiro # if _FFR_SMTPS_CLIENT
3717*d39bd2c1SGregory Neil Shapiro dotls:
3718*d39bd2c1SGregory Neil Shapiro # endif
371940266059SGregory Neil Shapiro /* first TLS then AUTH to provide a security layer */
372040266059SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED &&
372140266059SGregory Neil Shapiro !DONE_STARTTLS(mci->mci_flags))
372240266059SGregory Neil Shapiro {
372340266059SGregory Neil Shapiro int olderrors;
372440266059SGregory Neil Shapiro bool usetls;
372540266059SGregory Neil Shapiro bool saveQuickAbort = QuickAbort;
372640266059SGregory Neil Shapiro bool saveSuprErrs = SuprErrs;
3727*d39bd2c1SGregory Neil Shapiro char *srvname = NULL;
372840266059SGregory Neil Shapiro
372940266059SGregory Neil Shapiro rcode = EX_OK;
3730*d39bd2c1SGregory Neil Shapiro usetls = bitset(MCIF_TLS, mci->mci_flags) || implicittls;
373140266059SGregory Neil Shapiro if (usetls)
373240266059SGregory Neil Shapiro usetls = !iscltflgset(e, D_NOTLS);
37335b0945b5SGregory Neil Shapiro if (usetls)
37345b0945b5SGregory Neil Shapiro usetls = tlsstate == 0;
373540266059SGregory Neil Shapiro
3736*d39bd2c1SGregory Neil Shapiro srvname = macvalue(macid("{server_name}"), e);
373740266059SGregory Neil Shapiro if (usetls)
373840266059SGregory Neil Shapiro {
373940266059SGregory Neil Shapiro olderrors = Errors;
374040266059SGregory Neil Shapiro QuickAbort = false;
374140266059SGregory Neil Shapiro SuprErrs = true;
3742*d39bd2c1SGregory Neil Shapiro if (rscheck("try_tls", srvname, NULL, e,
3743*d39bd2c1SGregory Neil Shapiro RSF_RMCOMM|RSF_STATUS, 7, srvname,
3744*d39bd2c1SGregory Neil Shapiro NOQID, NULL, NULL) != EX_OK
374540266059SGregory Neil Shapiro || Errors > olderrors)
3746d0cef73dSGregory Neil Shapiro {
374740266059SGregory Neil Shapiro usetls = false;
3748d0cef73dSGregory Neil Shapiro }
374940266059SGregory Neil Shapiro SuprErrs = saveSuprErrs;
375040266059SGregory Neil Shapiro QuickAbort = saveQuickAbort;
375140266059SGregory Neil Shapiro }
375240266059SGregory Neil Shapiro
375306f25ae9SGregory Neil Shapiro if (usetls)
375406f25ae9SGregory Neil Shapiro {
3755*d39bd2c1SGregory Neil Shapiro if ((rcode = starttls(m, mci, e, implicittls
37565b0945b5SGregory Neil Shapiro # if DANE
37575b0945b5SGregory Neil Shapiro , &dane_vrfy_ctx
37585b0945b5SGregory Neil Shapiro # endif
37595b0945b5SGregory Neil Shapiro )) == EX_OK)
376006f25ae9SGregory Neil Shapiro {
376106f25ae9SGregory Neil Shapiro /* start again without STARTTLS */
376206f25ae9SGregory Neil Shapiro mci->mci_flags |= MCIF_TLSACT;
37632fb4f839SGregory Neil Shapiro # if DANE && _FFR_MTA_STS
37642fb4f839SGregory Neil Shapiro /* if DANE is used (and STS should be used): disable STS */
37652fb4f839SGregory Neil Shapiro /* also check MTASTS and NOSTS flag? */
3766*d39bd2c1SGregory Neil Shapiro if (STE_HAS_TLSA(ste) &&
37672fb4f839SGregory Neil Shapiro !SM_TLSI_IS(&(mci->mci_tlsi), TLSI_FL_NODANE))
37682fb4f839SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{rcpt_addr}"), "");
37692fb4f839SGregory Neil Shapiro # endif
377006f25ae9SGregory Neil Shapiro }
377106f25ae9SGregory Neil Shapiro else
377206f25ae9SGregory Neil Shapiro {
377306f25ae9SGregory Neil Shapiro char *s;
377406f25ae9SGregory Neil Shapiro
377506f25ae9SGregory Neil Shapiro /*
37769bd497b8SGregory Neil Shapiro ** TLS negotiation failed, what to do?
377706f25ae9SGregory Neil Shapiro ** fall back to unencrypted connection
377806f25ae9SGregory Neil Shapiro ** or abort? How to decide?
377906f25ae9SGregory Neil Shapiro ** set a macro and call a ruleset.
378006f25ae9SGregory Neil Shapiro */
378140266059SGregory Neil Shapiro
378206f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLS;
378306f25ae9SGregory Neil Shapiro switch (rcode)
378406f25ae9SGregory Neil Shapiro {
378506f25ae9SGregory Neil Shapiro case EX_TEMPFAIL:
378606f25ae9SGregory Neil Shapiro s = "TEMP";
378706f25ae9SGregory Neil Shapiro break;
3788*d39bd2c1SGregory Neil Shapiro #if 0
3789*d39bd2c1SGregory Neil Shapiro /* see starttls() */
379006f25ae9SGregory Neil Shapiro case EX_USAGE:
379106f25ae9SGregory Neil Shapiro s = "USAGE";
379206f25ae9SGregory Neil Shapiro break;
3793*d39bd2c1SGregory Neil Shapiro #endif
379406f25ae9SGregory Neil Shapiro case EX_PROTOCOL:
379506f25ae9SGregory Neil Shapiro s = "PROTOCOL";
379606f25ae9SGregory Neil Shapiro break;
379706f25ae9SGregory Neil Shapiro case EX_SOFTWARE:
379806f25ae9SGregory Neil Shapiro s = "SOFTWARE";
379906f25ae9SGregory Neil Shapiro break;
38004e4196cbSGregory Neil Shapiro case EX_UNAVAILABLE:
38014e4196cbSGregory Neil Shapiro s = "NONE";
38024e4196cbSGregory Neil Shapiro break;
3803*d39bd2c1SGregory Neil Shapiro
3804*d39bd2c1SGregory Neil Shapiro /*
3805*d39bd2c1SGregory Neil Shapiro ** Possible return from ruleset
3806*d39bd2c1SGregory Neil Shapiro ** tls_clt_features via
3807*d39bd2c1SGregory Neil Shapiro ** get_tls_se_features().
3808*d39bd2c1SGregory Neil Shapiro */
3809*d39bd2c1SGregory Neil Shapiro
38102fb4f839SGregory Neil Shapiro case EX_CONFIG:
38112fb4f839SGregory Neil Shapiro s = "CONFIG";
38122fb4f839SGregory Neil Shapiro break;
381306f25ae9SGregory Neil Shapiro
381406f25ae9SGregory Neil Shapiro /* everything else is a failure */
381506f25ae9SGregory Neil Shapiro default:
381606f25ae9SGregory Neil Shapiro s = "FAILURE";
381706f25ae9SGregory Neil Shapiro rcode = EX_TEMPFAIL;
381806f25ae9SGregory Neil Shapiro }
3819*d39bd2c1SGregory Neil Shapiro # if DANE
3820*d39bd2c1SGregory Neil Shapiro /*
3821*d39bd2c1SGregory Neil Shapiro ** TLSA found but STARTTLS "failed"?
3822*d39bd2c1SGregory Neil Shapiro ** What is the best way to "fail"?
3823*d39bd2c1SGregory Neil Shapiro ** XXX: check expiration!
3824*d39bd2c1SGregory Neil Shapiro */
3825*d39bd2c1SGregory Neil Shapiro
3826*d39bd2c1SGregory Neil Shapiro if (!iscltflgset(e, D_NODANE) &&
3827*d39bd2c1SGregory Neil Shapiro STE_HAS_TLSA(ste) &&
3828*d39bd2c1SGregory Neil Shapiro TLSA_HAS_RRs(ste->s_tlsa))
3829*d39bd2c1SGregory Neil Shapiro {
3830*d39bd2c1SGregory Neil Shapiro if (LogLevel > 8)
3831*d39bd2c1SGregory Neil Shapiro sm_syslog(LOG_NOTICE, NOQID,
3832*d39bd2c1SGregory Neil Shapiro "STARTTLS=client, relay=%.100s, warning=DANE configured in DNS but STARTTLS failed",
3833*d39bd2c1SGregory Neil Shapiro srvname);
3834*d39bd2c1SGregory Neil Shapiro /* XXX include TLSA RR from DNS? */
3835*d39bd2c1SGregory Neil Shapiro
3836*d39bd2c1SGregory Neil Shapiro /*
3837*d39bd2c1SGregory Neil Shapiro ** Only override codes which
3838*d39bd2c1SGregory Neil Shapiro ** do not cause a failure
3839*d39bd2c1SGregory Neil Shapiro ** in the default rules.
3840*d39bd2c1SGregory Neil Shapiro */
3841*d39bd2c1SGregory Neil Shapiro
3842*d39bd2c1SGregory Neil Shapiro if (EX_PROTOCOL != rcode &&
3843*d39bd2c1SGregory Neil Shapiro EX_SOFTWARE != rcode &&
3844*d39bd2c1SGregory Neil Shapiro EX_CONFIG != rcode)
3845*d39bd2c1SGregory Neil Shapiro {
3846*d39bd2c1SGregory Neil Shapiro /* s = "DANE_TEMP"; */
3847*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_chk |= TLSAFLNOTLS;
3848*d39bd2c1SGregory Neil Shapiro }
3849*d39bd2c1SGregory Neil Shapiro }
3850*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
385140266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
385240266059SGregory Neil Shapiro macid("{verify}"), s);
385306f25ae9SGregory Neil Shapiro }
385406f25ae9SGregory Neil Shapiro }
385506f25ae9SGregory Neil Shapiro else
38565b0945b5SGregory Neil Shapiro {
38575b0945b5SGregory Neil Shapiro p = tlsstate == 0 ? "NONE": "CLEAR";
38585b0945b5SGregory Neil Shapiro # if DANE
38595b0945b5SGregory Neil Shapiro /*
38605b0945b5SGregory Neil Shapiro ** TLSA found but STARTTLS not offered?
38615b0945b5SGregory Neil Shapiro ** What is the best way to "fail"?
38625b0945b5SGregory Neil Shapiro ** XXX: check expiration!
38635b0945b5SGregory Neil Shapiro */
38645b0945b5SGregory Neil Shapiro
38655b0945b5SGregory Neil Shapiro if (!bitset(MCIF_TLS, mci->mci_flags) &&
38662fb4f839SGregory Neil Shapiro !iscltflgset(e, D_NODANE) &&
3867*d39bd2c1SGregory Neil Shapiro STE_HAS_TLSA(ste) &&
3868*d39bd2c1SGregory Neil Shapiro TLSA_HAS_RRs(ste->s_tlsa))
38695b0945b5SGregory Neil Shapiro {
38705b0945b5SGregory Neil Shapiro if (LogLevel > 8)
38715b0945b5SGregory Neil Shapiro sm_syslog(LOG_NOTICE, NOQID,
3872*d39bd2c1SGregory Neil Shapiro "STARTTLS=client, relay=%.100s, warning=DANE configured in DNS but STARTTLS not offered",
3873*d39bd2c1SGregory Neil Shapiro srvname);
38745b0945b5SGregory Neil Shapiro /* XXX include TLSA RR from DNS? */
38755b0945b5SGregory Neil Shapiro }
38765b0945b5SGregory Neil Shapiro # endif /* DANE */
387740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
38785b0945b5SGregory Neil Shapiro macid("{verify}"), p);
38795b0945b5SGregory Neil Shapiro }
388006f25ae9SGregory Neil Shapiro olderrors = Errors;
388140266059SGregory Neil Shapiro QuickAbort = false;
388240266059SGregory Neil Shapiro SuprErrs = true;
388306f25ae9SGregory Neil Shapiro
388406f25ae9SGregory Neil Shapiro /*
388506f25ae9SGregory Neil Shapiro ** rcode == EX_SOFTWARE is special:
38869bd497b8SGregory Neil Shapiro ** the TLS negotiation failed
38872fb4f839SGregory Neil Shapiro ** we have to drop the connection no matter what.
388806f25ae9SGregory Neil Shapiro ** However, we call tls_server to give it the chance
388906f25ae9SGregory Neil Shapiro ** to log the problem and return an appropriate
389006f25ae9SGregory Neil Shapiro ** error code.
389106f25ae9SGregory Neil Shapiro */
389240266059SGregory Neil Shapiro
389306f25ae9SGregory Neil Shapiro if (rscheck("tls_server",
389440266059SGregory Neil Shapiro macvalue(macid("{verify}"), e),
3895959366dcSGregory Neil Shapiro NULL, e, RSF_RMCOMM|RSF_COUNT, 5,
3896*d39bd2c1SGregory Neil Shapiro srvname, NOQID, NULL, NULL) != EX_OK ||
389706f25ae9SGregory Neil Shapiro Errors > olderrors ||
389806f25ae9SGregory Neil Shapiro rcode == EX_SOFTWARE)
389906f25ae9SGregory Neil Shapiro {
390006f25ae9SGregory Neil Shapiro char enhsc[ENHSCLEN];
390106f25ae9SGregory Neil Shapiro extern char MsgBuf[];
390206f25ae9SGregory Neil Shapiro
390306f25ae9SGregory Neil Shapiro if (ISSMTPCODE(MsgBuf) &&
390406f25ae9SGregory Neil Shapiro extenhsc(MsgBuf + 4, ' ', enhsc) > 0)
390506f25ae9SGregory Neil Shapiro {
390640266059SGregory Neil Shapiro p = sm_rpool_strdup_x(e->e_rpool,
390740266059SGregory Neil Shapiro MsgBuf);
390806f25ae9SGregory Neil Shapiro }
390906f25ae9SGregory Neil Shapiro else
391006f25ae9SGregory Neil Shapiro {
391106f25ae9SGregory Neil Shapiro p = "403 4.7.0 server not authenticated.";
391240266059SGregory Neil Shapiro (void) sm_strlcpy(enhsc, "4.7.0",
3913d0cef73dSGregory Neil Shapiro sizeof(enhsc));
391406f25ae9SGregory Neil Shapiro }
391506f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs;
391606f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort;
391706f25ae9SGregory Neil Shapiro
391806f25ae9SGregory Neil Shapiro if (rcode == EX_SOFTWARE)
391906f25ae9SGregory Neil Shapiro {
392006f25ae9SGregory Neil Shapiro /* drop the connection */
3921*d39bd2c1SGregory Neil Shapiro mci->mci_state = MCIS_ERROR;
39222fb4f839SGregory Neil Shapiro SM_CLOSE_FP(mci->mci_out);
392306f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLSACT;
392406f25ae9SGregory Neil Shapiro (void) endmailer(mci, e, pv);
39255b0945b5SGregory Neil Shapiro
39265b0945b5SGregory Neil Shapiro if ((TLSFallbacktoClear ||
39275b0945b5SGregory Neil Shapiro SM_TLSI_IS(&(mci->mci_tlsi),
39285b0945b5SGregory Neil Shapiro TLSI_FL_FB2CLR)) &&
39295b0945b5SGregory Neil Shapiro !SM_TLSI_IS(&(mci->mci_tlsi),
39305b0945b5SGregory Neil Shapiro TLSI_FL_NOFB2CLR)
39315b0945b5SGregory Neil Shapiro # if DANE
39325b0945b5SGregory Neil Shapiro && dane_vrfy_ctx.dane_vrfy_chk !=
39335b0945b5SGregory Neil Shapiro DANE_SECURE
39345b0945b5SGregory Neil Shapiro # endif
39352fb4f839SGregory Neil Shapiro # if _FFR_MTA_STS
39362fb4f839SGregory Neil Shapiro && !SM_TLSI_IS(&(mci->mci_tlsi),
39372fb4f839SGregory Neil Shapiro TLSI_FL_STS_NOFB2CLR)
39382fb4f839SGregory Neil Shapiro # endif
39395b0945b5SGregory Neil Shapiro )
39405b0945b5SGregory Neil Shapiro {
39415b0945b5SGregory Neil Shapiro ++tlsstate;
39425b0945b5SGregory Neil Shapiro }
394306f25ae9SGregory Neil Shapiro }
394406f25ae9SGregory Neil Shapiro else
394506f25ae9SGregory Neil Shapiro {
394606f25ae9SGregory Neil Shapiro /* abort transfer */
394706f25ae9SGregory Neil Shapiro smtpquit(m, mci, e);
394806f25ae9SGregory Neil Shapiro }
394906f25ae9SGregory Neil Shapiro
3950193538b7SGregory Neil Shapiro /* avoid bogus error msg */
3951193538b7SGregory Neil Shapiro mci->mci_errno = 0;
3952193538b7SGregory Neil Shapiro
395306f25ae9SGregory Neil Shapiro /* temp or permanent failure? */
395406f25ae9SGregory Neil Shapiro rcode = (*p == '4') ? EX_TEMPFAIL
395506f25ae9SGregory Neil Shapiro : EX_UNAVAILABLE;
395640266059SGregory Neil Shapiro mci_setstat(mci, rcode, enhsc, p);
395706f25ae9SGregory Neil Shapiro
395806f25ae9SGregory Neil Shapiro /*
395906f25ae9SGregory Neil Shapiro ** hack to get the error message into
396006f25ae9SGregory Neil Shapiro ** the envelope (done in giveresponse())
396106f25ae9SGregory Neil Shapiro */
396240266059SGregory Neil Shapiro
396340266059SGregory Neil Shapiro (void) sm_strlcpy(SmtpError, p,
3964d0cef73dSGregory Neil Shapiro sizeof(SmtpError));
396506f25ae9SGregory Neil Shapiro }
3966d0cef73dSGregory Neil Shapiro else if (mci->mci_state == MCIS_CLOSED)
3967d0cef73dSGregory Neil Shapiro {
3968d0cef73dSGregory Neil Shapiro /* connection close caused by 421 */
3969d0cef73dSGregory Neil Shapiro mci->mci_errno = 0;
3970d0cef73dSGregory Neil Shapiro rcode = EX_TEMPFAIL;
3971d0cef73dSGregory Neil Shapiro mci_setstat(mci, rcode, NULL, "421");
3972d0cef73dSGregory Neil Shapiro }
3973d0cef73dSGregory Neil Shapiro else
3974d0cef73dSGregory Neil Shapiro rcode = 0;
3975d0cef73dSGregory Neil Shapiro
397606f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort;
397706f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs;
3978193538b7SGregory Neil Shapiro if (DONE_STARTTLS(mci->mci_flags) &&
3979*d39bd2c1SGregory Neil Shapiro mci->mci_state != MCIS_CLOSED
3980*d39bd2c1SGregory Neil Shapiro # if _FFR_SMTPS_CLIENT
3981*d39bd2c1SGregory Neil Shapiro && !implicittls && !smtptls
3982*d39bd2c1SGregory Neil Shapiro # endif
3983*d39bd2c1SGregory Neil Shapiro )
398406f25ae9SGregory Neil Shapiro {
3985193538b7SGregory Neil Shapiro SET_HELO(mci->mci_flags);
39866f9c8e5bSGregory Neil Shapiro mci_clr_extensions(mci);
398706f25ae9SGregory Neil Shapiro goto reconnect;
398806f25ae9SGregory Neil Shapiro }
39895b0945b5SGregory Neil Shapiro if (tlsstate == 1)
39905b0945b5SGregory Neil Shapiro {
39915b0945b5SGregory Neil Shapiro if (tTd(11, 1))
39925b0945b5SGregory Neil Shapiro {
39935b0945b5SGregory Neil Shapiro sm_syslog(LOG_DEBUG, NOQID,
39945b0945b5SGregory Neil Shapiro "STARTTLS=client, relay=%.100s, tlsstate=%d, status=trying_again",
39955b0945b5SGregory Neil Shapiro mci->mci_host, tlsstate);
39965b0945b5SGregory Neil Shapiro mci_dump(NULL, mci, true);
39975b0945b5SGregory Neil Shapiro }
39985b0945b5SGregory Neil Shapiro ++tlsstate;
39995b0945b5SGregory Neil Shapiro
40005b0945b5SGregory Neil Shapiro /*
40015b0945b5SGregory Neil Shapiro ** Fake the status so a new connection is
40025b0945b5SGregory Neil Shapiro ** tried, otherwise the TLS error will
40035b0945b5SGregory Neil Shapiro ** "persist" during this delivery attempt.
40045b0945b5SGregory Neil Shapiro */
40055b0945b5SGregory Neil Shapiro
40065b0945b5SGregory Neil Shapiro mci->mci_errno = 0;
40075b0945b5SGregory Neil Shapiro rcode = EX_OK;
40085b0945b5SGregory Neil Shapiro mci_setstat(mci, rcode, NULL, NULL);
40095b0945b5SGregory Neil Shapiro goto one_last_try;
40105b0945b5SGregory Neil Shapiro }
401106f25ae9SGregory Neil Shapiro }
4012*d39bd2c1SGregory Neil Shapiro
4013*d39bd2c1SGregory Neil Shapiro # if _FFR_SMTPS_CLIENT
4014*d39bd2c1SGregory Neil Shapiro /*
4015*d39bd2c1SGregory Neil Shapiro ** For M_SMTPS_CLIENT, we do the STARTTLS code first,
4016*d39bd2c1SGregory Neil Shapiro ** then jump back and start the SMTP conversation.
4017*d39bd2c1SGregory Neil Shapiro */
4018*d39bd2c1SGregory Neil Shapiro
4019*d39bd2c1SGregory Neil Shapiro if (implicittls && !smtptls)
4020*d39bd2c1SGregory Neil Shapiro {
4021*d39bd2c1SGregory Neil Shapiro smtptls = true;
4022*d39bd2c1SGregory Neil Shapiro if (!DONE_STARTTLS(mci->mci_flags))
4023*d39bd2c1SGregory Neil Shapiro {
4024*d39bd2c1SGregory Neil Shapiro if (rcode == EX_TEMPFAIL)
4025*d39bd2c1SGregory Neil Shapiro {
4026*d39bd2c1SGregory Neil Shapiro e->e_status = "4.3.3";
4027*d39bd2c1SGregory Neil Shapiro usrerrenh(e->e_status, "454 TLS session initiation failed");
4028*d39bd2c1SGregory Neil Shapiro }
4029*d39bd2c1SGregory Neil Shapiro else
4030*d39bd2c1SGregory Neil Shapiro {
4031*d39bd2c1SGregory Neil Shapiro e->e_status = "5.3.3";
4032*d39bd2c1SGregory Neil Shapiro usrerrenh(e->e_status, "554 TLS session initiation failed");
4033*d39bd2c1SGregory Neil Shapiro }
4034*d39bd2c1SGregory Neil Shapiro goto give_up;
4035*d39bd2c1SGregory Neil Shapiro }
4036*d39bd2c1SGregory Neil Shapiro goto backtosmtp;
4037*d39bd2c1SGregory Neil Shapiro }
4038*d39bd2c1SGregory Neil Shapiro # endif /* _FFR_SMTPS_CLIENT */
403906f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
404006f25ae9SGregory Neil Shapiro #if SASL
404106f25ae9SGregory Neil Shapiro /* if other server supports authentication let's authenticate */
404206f25ae9SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED &&
404306f25ae9SGregory Neil Shapiro mci->mci_saslcap != NULL &&
404440266059SGregory Neil Shapiro !DONE_AUTH(mci->mci_flags) && !iscltflgset(e, D_NOAUTH))
404506f25ae9SGregory Neil Shapiro {
404640266059SGregory Neil Shapiro /* Should we require some minimum authentication? */
404740266059SGregory Neil Shapiro if ((ret = smtpauth(m, mci, e)) == EX_OK)
404806f25ae9SGregory Neil Shapiro {
404906f25ae9SGregory Neil Shapiro int result;
405040266059SGregory Neil Shapiro sasl_ssf_t *ssf = NULL;
405106f25ae9SGregory Neil Shapiro
405240266059SGregory Neil Shapiro /* Get security strength (features) */
405306f25ae9SGregory Neil Shapiro result = sasl_getprop(mci->mci_conn, SASL_SSF,
405494c01205SGregory Neil Shapiro # if SASL >= 20000
405594c01205SGregory Neil Shapiro (const void **) &ssf);
40565b0945b5SGregory Neil Shapiro # else
405706f25ae9SGregory Neil Shapiro (void **) &ssf);
40585b0945b5SGregory Neil Shapiro # endif
405940266059SGregory Neil Shapiro
406040266059SGregory Neil Shapiro /* XXX authid? */
406106f25ae9SGregory Neil Shapiro if (LogLevel > 9)
406206f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID,
406340266059SGregory Neil Shapiro "AUTH=client, relay=%.100s, mech=%.16s, bits=%d",
406406f25ae9SGregory Neil Shapiro mci->mci_host,
406540266059SGregory Neil Shapiro macvalue(macid("{auth_type}"), e),
406640266059SGregory Neil Shapiro result == SASL_OK ? *ssf : 0);
40678774250cSGregory Neil Shapiro
406806f25ae9SGregory Neil Shapiro /*
406940266059SGregory Neil Shapiro ** Only switch to encrypted connection
407006f25ae9SGregory Neil Shapiro ** if a security layer has been negotiated
407106f25ae9SGregory Neil Shapiro */
407240266059SGregory Neil Shapiro
407306f25ae9SGregory Neil Shapiro if (result == SASL_OK && *ssf > 0)
407406f25ae9SGregory Neil Shapiro {
4075af9557fdSGregory Neil Shapiro int tmo;
4076af9557fdSGregory Neil Shapiro
407706f25ae9SGregory Neil Shapiro /*
407840266059SGregory Neil Shapiro ** Convert I/O layer to use SASL.
407940266059SGregory Neil Shapiro ** If the call fails, the connection
408040266059SGregory Neil Shapiro ** is aborted.
408106f25ae9SGregory Neil Shapiro */
408240266059SGregory Neil Shapiro
4083af9557fdSGregory Neil Shapiro tmo = DATA_PROGRESS_TIMEOUT * 1000;
408440266059SGregory Neil Shapiro if (sfdcsasl(&mci->mci_in,
408540266059SGregory Neil Shapiro &mci->mci_out,
4086af9557fdSGregory Neil Shapiro mci->mci_conn, tmo) == 0)
408706f25ae9SGregory Neil Shapiro {
40886f9c8e5bSGregory Neil Shapiro mci_clr_extensions(mci);
408940266059SGregory Neil Shapiro mci->mci_flags |= MCIF_AUTHACT|
409040266059SGregory Neil Shapiro MCIF_ONLY_EHLO;
409106f25ae9SGregory Neil Shapiro goto reconnect;
409206f25ae9SGregory Neil Shapiro }
409340266059SGregory Neil Shapiro syserr("AUTH TLS switch failed in client");
409406f25ae9SGregory Neil Shapiro }
409506f25ae9SGregory Neil Shapiro /* else? XXX */
409606f25ae9SGregory Neil Shapiro mci->mci_flags |= MCIF_AUTHACT;
409706f25ae9SGregory Neil Shapiro
409806f25ae9SGregory Neil Shapiro }
409940266059SGregory Neil Shapiro else if (ret == EX_TEMPFAIL)
410040266059SGregory Neil Shapiro {
410140266059SGregory Neil Shapiro if (LogLevel > 8)
410240266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
410340266059SGregory Neil Shapiro "AUTH=client, relay=%.100s, temporary failure, connection abort",
410440266059SGregory Neil Shapiro mci->mci_host);
410540266059SGregory Neil Shapiro smtpquit(m, mci, e);
410640266059SGregory Neil Shapiro
410740266059SGregory Neil Shapiro /* avoid bogus error msg */
410840266059SGregory Neil Shapiro mci->mci_errno = 0;
410940266059SGregory Neil Shapiro rcode = EX_TEMPFAIL;
4110e92d3f3fSGregory Neil Shapiro mci_setstat(mci, rcode, "4.3.0", p);
411140266059SGregory Neil Shapiro
411240266059SGregory Neil Shapiro /*
411340266059SGregory Neil Shapiro ** hack to get the error message into
411440266059SGregory Neil Shapiro ** the envelope (done in giveresponse())
411540266059SGregory Neil Shapiro */
411640266059SGregory Neil Shapiro
411740266059SGregory Neil Shapiro (void) sm_strlcpy(SmtpError,
411840266059SGregory Neil Shapiro "Temporary AUTH failure",
4119d0cef73dSGregory Neil Shapiro sizeof(SmtpError));
412040266059SGregory Neil Shapiro }
412106f25ae9SGregory Neil Shapiro }
412206f25ae9SGregory Neil Shapiro #endif /* SASL */
412306f25ae9SGregory Neil Shapiro }
412406f25ae9SGregory Neil Shapiro
4125c2aa98e2SPeter Wemm do_transfer:
4126c2aa98e2SPeter Wemm /* clear out per-message flags from connection structure */
4127c2aa98e2SPeter Wemm mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7);
4128c2aa98e2SPeter Wemm
4129c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) &&
4130c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) &&
4131c2aa98e2SPeter Wemm bitnset(M_7BITS, m->m_flags))
4132c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CVT8TO7;
4133c2aa98e2SPeter Wemm
4134c2aa98e2SPeter Wemm #if MIME7TO8
4135c2aa98e2SPeter Wemm if (bitnset(M_MAKE8BIT, m->m_flags) &&
4136c2aa98e2SPeter Wemm !bitset(MCIF_7BIT, mci->mci_flags) &&
4137c2aa98e2SPeter Wemm (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL &&
41382fb4f839SGregory Neil Shapiro (SM_STRCASEEQ(p, "quoted-printable") ||
41392fb4f839SGregory Neil Shapiro SM_STRCASEEQ(p, "base64")) &&
4140c2aa98e2SPeter Wemm (p = hvalue("Content-Type", e->e_header)) != NULL)
4141c2aa98e2SPeter Wemm {
4142c2aa98e2SPeter Wemm /* may want to convert 7 -> 8 */
4143c2aa98e2SPeter Wemm /* XXX should really parse it here -- and use a class XXX */
414440266059SGregory Neil Shapiro if (sm_strncasecmp(p, "text/plain", 10) == 0 &&
4145c2aa98e2SPeter Wemm (p[10] == '\0' || p[10] == ' ' || p[10] == ';'))
4146c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CVT7TO8;
4147c2aa98e2SPeter Wemm }
414806f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */
4149c2aa98e2SPeter Wemm
4150c2aa98e2SPeter Wemm if (tTd(11, 1))
4151c2aa98e2SPeter Wemm {
415240266059SGregory Neil Shapiro sm_dprintf("openmailer: ");
4153e92d3f3fSGregory Neil Shapiro mci_dump(sm_debug_file(), mci, false);
4154c2aa98e2SPeter Wemm }
4155c2aa98e2SPeter Wemm
415640266059SGregory Neil Shapiro #if _FFR_CLIENT_SIZE
415740266059SGregory Neil Shapiro /*
415840266059SGregory Neil Shapiro ** See if we know the maximum size and
415940266059SGregory Neil Shapiro ** abort if the message is too big.
416040266059SGregory Neil Shapiro **
416140266059SGregory Neil Shapiro ** NOTE: _FFR_CLIENT_SIZE is untested.
416240266059SGregory Neil Shapiro */
416340266059SGregory Neil Shapiro
416440266059SGregory Neil Shapiro if (bitset(MCIF_SIZE, mci->mci_flags) &&
416540266059SGregory Neil Shapiro mci->mci_maxsize > 0 &&
416640266059SGregory Neil Shapiro e->e_msgsize > mci->mci_maxsize)
416740266059SGregory Neil Shapiro {
416840266059SGregory Neil Shapiro e->e_flags |= EF_NO_BODY_RETN;
416940266059SGregory Neil Shapiro if (bitnset(M_LOCALMAILER, m->m_flags))
417040266059SGregory Neil Shapiro e->e_status = "5.2.3";
417140266059SGregory Neil Shapiro else
417240266059SGregory Neil Shapiro e->e_status = "5.3.4";
417340266059SGregory Neil Shapiro
417440266059SGregory Neil Shapiro usrerrenh(e->e_status,
417540266059SGregory Neil Shapiro "552 Message is too large; %ld bytes max",
417640266059SGregory Neil Shapiro mci->mci_maxsize);
417740266059SGregory Neil Shapiro rcode = EX_DATAERR;
417840266059SGregory Neil Shapiro
417940266059SGregory Neil Shapiro /* Need an e_message for error */
4180d0cef73dSGregory Neil Shapiro (void) sm_snprintf(SmtpError, sizeof(SmtpError),
418140266059SGregory Neil Shapiro "Message is too large; %ld bytes max",
418240266059SGregory Neil Shapiro mci->mci_maxsize);
418340266059SGregory Neil Shapiro goto give_up;
418440266059SGregory Neil Shapiro }
418540266059SGregory Neil Shapiro #endif /* _FFR_CLIENT_SIZE */
418640266059SGregory Neil Shapiro
4187c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_OPEN)
4188c2aa98e2SPeter Wemm {
4189c2aa98e2SPeter Wemm /* couldn't open the mailer */
4190c2aa98e2SPeter Wemm rcode = mci->mci_exitstat;
4191c2aa98e2SPeter Wemm errno = mci->mci_errno;
4192602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(mci->mci_herrno);
4193c2aa98e2SPeter Wemm if (rcode == EX_OK)
4194c2aa98e2SPeter Wemm {
4195c2aa98e2SPeter Wemm /* shouldn't happen */
419606f25ae9SGregory Neil Shapiro syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s",
419740266059SGregory Neil Shapiro (unsigned long) mci, rcode, errno,
419840266059SGregory Neil Shapiro mci->mci_state, firstsig);
4199e92d3f3fSGregory Neil Shapiro mci_dump_all(smioout, true);
4200c2aa98e2SPeter Wemm rcode = EX_SOFTWARE;
4201c2aa98e2SPeter Wemm }
420206f25ae9SGregory Neil Shapiro else if (nummxhosts > hostnum)
4203c2aa98e2SPeter Wemm {
4204*d39bd2c1SGregory Neil Shapiro logfailover(e, m, mci, rcode, NULL);
4205c2aa98e2SPeter Wemm /* try next MX site */
4206c2aa98e2SPeter Wemm goto tryhost;
4207c2aa98e2SPeter Wemm }
4208c2aa98e2SPeter Wemm }
4209c2aa98e2SPeter Wemm else if (!clever)
4210c2aa98e2SPeter Wemm {
42114e4196cbSGregory Neil Shapiro bool ok;
42124e4196cbSGregory Neil Shapiro
4213c2aa98e2SPeter Wemm /*
4214c2aa98e2SPeter Wemm ** Format and send message.
4215c2aa98e2SPeter Wemm */
4216c2aa98e2SPeter Wemm
42174e4196cbSGregory Neil Shapiro rcode = EX_OK;
42184e4196cbSGregory Neil Shapiro errno = 0;
42194e4196cbSGregory Neil Shapiro ok = putfromline(mci, e);
42204e4196cbSGregory Neil Shapiro if (ok)
42214e4196cbSGregory Neil Shapiro ok = (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER);
42224e4196cbSGregory Neil Shapiro if (ok)
42234e4196cbSGregory Neil Shapiro ok = (*e->e_putbody)(mci, e, NULL);
4224ffb83623SGregory Neil Shapiro if (ok && bitset(MCIF_INLONGLINE, mci->mci_flags))
4225ffb83623SGregory Neil Shapiro ok = putline("", mci);
4226c2aa98e2SPeter Wemm
42274e4196cbSGregory Neil Shapiro /*
42284e4196cbSGregory Neil Shapiro ** Ignore an I/O error that was caused by EPIPE.
42294e4196cbSGregory Neil Shapiro ** Some broken mailers don't read the entire body
42304e4196cbSGregory Neil Shapiro ** but just exit() thus causing an I/O error.
42314e4196cbSGregory Neil Shapiro */
42324e4196cbSGregory Neil Shapiro
42334e4196cbSGregory Neil Shapiro if (!ok && (sm_io_error(mci->mci_out) && errno == EPIPE))
42344e4196cbSGregory Neil Shapiro ok = true;
42354e4196cbSGregory Neil Shapiro
42364e4196cbSGregory Neil Shapiro /* (always) get the exit status */
4237c2aa98e2SPeter Wemm rcode = endmailer(mci, e, pv);
42384e4196cbSGregory Neil Shapiro if (!ok)
42394e4196cbSGregory Neil Shapiro rcode = EX_TEMPFAIL;
424040266059SGregory Neil Shapiro if (rcode == EX_TEMPFAIL && SmtpError[0] == '\0')
4241602a2b1bSGregory Neil Shapiro {
4242602a2b1bSGregory Neil Shapiro /*
4243602a2b1bSGregory Neil Shapiro ** Need an e_message for mailq display.
4244602a2b1bSGregory Neil Shapiro ** We set SmtpError as
4245602a2b1bSGregory Neil Shapiro */
4246602a2b1bSGregory Neil Shapiro
4247d0cef73dSGregory Neil Shapiro (void) sm_snprintf(SmtpError, sizeof(SmtpError),
4248602a2b1bSGregory Neil Shapiro "%s mailer (%s) exited with EX_TEMPFAIL",
4249602a2b1bSGregory Neil Shapiro m->m_name, m->m_mailer);
4250602a2b1bSGregory Neil Shapiro }
4251c2aa98e2SPeter Wemm }
4252c2aa98e2SPeter Wemm else
4253c2aa98e2SPeter Wemm {
4254c2aa98e2SPeter Wemm /*
4255c2aa98e2SPeter Wemm ** Send the MAIL FROM: protocol
4256c2aa98e2SPeter Wemm */
4257c2aa98e2SPeter Wemm
425840266059SGregory Neil Shapiro /* XXX this isn't pipelined... */
4259c2aa98e2SPeter Wemm rcode = smtpmailfrom(m, mci, e);
42602fb4f839SGregory Neil Shapiro mci->mci_okrcpts = 0;
42612fb4f839SGregory Neil Shapiro mci->mci_retryrcpt = rcode == EX_TEMPFAIL;
4262c2aa98e2SPeter Wemm if (rcode == EX_OK)
4263c2aa98e2SPeter Wemm {
42642fb4f839SGregory Neil Shapiro register int rc;
426540266059SGregory Neil Shapiro #if PIPELINING
426640266059SGregory Neil Shapiro ADDRESS *volatile pchain;
42675b0945b5SGregory Neil Shapiro #endif
4268*d39bd2c1SGregory Neil Shapiro #if STARTTLS
4269*d39bd2c1SGregory Neil Shapiro ADDRESS addr;
4270*d39bd2c1SGregory Neil Shapiro #endif
4271c2aa98e2SPeter Wemm
4272c2aa98e2SPeter Wemm /* send the recipient list */
42732fb4f839SGregory Neil Shapiro rc = EX_OK;
4274c2aa98e2SPeter Wemm tobuf[0] = '\0';
427540266059SGregory Neil Shapiro mci->mci_retryrcpt = false;
427640266059SGregory Neil Shapiro mci->mci_tolist = tobuf;
427740266059SGregory Neil Shapiro #if PIPELINING
427840266059SGregory Neil Shapiro pchain = NULL;
427940266059SGregory Neil Shapiro mci->mci_nextaddr = NULL;
42805b0945b5SGregory Neil Shapiro #endif
428106f25ae9SGregory Neil Shapiro
4282c2aa98e2SPeter Wemm for (to = tochain; to != NULL; to = to->q_tchain)
4283c2aa98e2SPeter Wemm {
428440266059SGregory Neil Shapiro if (!QS_IS_UNMARKED(to->q_state))
4285c2aa98e2SPeter Wemm continue;
428606f25ae9SGregory Neil Shapiro
428740266059SGregory Neil Shapiro /* mark recipient state as "ok so far" */
428840266059SGregory Neil Shapiro to->q_state = QS_OK;
428940266059SGregory Neil Shapiro e->e_to = to->q_paddr;
42902fb4f839SGregory Neil Shapiro #if _FFR_MTA_STS
42912fb4f839SGregory Neil Shapiro if (CHKMTASTS && to->q_user != NULL)
42922fb4f839SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP,
42932fb4f839SGregory Neil Shapiro macid("{rcpt_addr}"), to->q_user);
42942fb4f839SGregory Neil Shapiro else
42952fb4f839SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
42962fb4f839SGregory Neil Shapiro macid("{rcpt_addr}"), "");
42972fb4f839SGregory Neil Shapiro #endif /* _FFR_MTA_STS */
429806f25ae9SGregory Neil Shapiro #if STARTTLS
4299*d39bd2c1SGregory Neil Shapiro # if DANE
4300*d39bd2c1SGregory Neil Shapiro vrfy = macvalue(macid("{verify}"), e);
4301*d39bd2c1SGregory Neil Shapiro if (NULL == vrfy)
4302*d39bd2c1SGregory Neil Shapiro vrfy = "NONE";
4303*d39bd2c1SGregory Neil Shapiro vrfy = sm_strdup(vrfy);
4304*d39bd2c1SGregory Neil Shapiro if (TTD(10, 32))
4305*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: 0: vrfy=%s, to=%s, mx=%s, QMXSECURE=%d, secure=%d, ste=%p, dane=%#x\n",
4306*d39bd2c1SGregory Neil Shapiro vrfy, to->q_user, CurHostName, RCPT_MXSECURE(to),
4307*d39bd2c1SGregory Neil Shapiro RCPT_REQ_DANE(to), ste, Dane);
4308*d39bd2c1SGregory Neil Shapiro if (NULL == ste && CHK_DANE_RCPT(Dane, to))
4309*d39bd2c1SGregory Neil Shapiro {
4310*d39bd2c1SGregory Neil Shapiro (void) gettlsa(CurHostName, NULL, &ste,
4311*d39bd2c1SGregory Neil Shapiro RCPT_MXSECURE(to) ? TLSAFLADMX : 0,
4312*d39bd2c1SGregory Neil Shapiro 0, m->m_port);
4313*d39bd2c1SGregory Neil Shapiro }
4314*d39bd2c1SGregory Neil Shapiro if (TTD(10, 32))
4315*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: 2: vrfy=%s, to=%s, QMXSECURE=%d, secure=%d, ste=%p, dane=%#x, SUP=%#x, !TEMP=%d, ADIP=%d, chk_dane=%d, vrfy_chk=%#x, mcif=%#lx\n",
4316*d39bd2c1SGregory Neil Shapiro vrfy, to->q_user,
4317*d39bd2c1SGregory Neil Shapiro RCPT_MXSECURE(to), RCPT_REQ_DANE(to), ste, Dane,
4318*d39bd2c1SGregory Neil Shapiro STE_HAS_TLSA(ste) ? TLSA_IS_FL(ste->s_tlsa, TLSAFLSUP) : -1,
4319*d39bd2c1SGregory Neil Shapiro (0 == (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLTEMPVRFY)),
4320*d39bd2c1SGregory Neil Shapiro (0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLADIP)),
4321*d39bd2c1SGregory Neil Shapiro CHK_DANE(dane_vrfy_ctx.dane_vrfy_chk),
4322*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_chk,
4323*d39bd2c1SGregory Neil Shapiro mci->mci_flags
4324*d39bd2c1SGregory Neil Shapiro );
4325*d39bd2c1SGregory Neil Shapiro
4326*d39bd2c1SGregory Neil Shapiro if (strcmp("DANE_FAIL", vrfy) == 0)
4327*d39bd2c1SGregory Neil Shapiro {
4328*d39bd2c1SGregory Neil Shapiro if (!RCPT_REQ_DANE(to))
4329*d39bd2c1SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM, macid("{verify}"), "FAIL");
4330*d39bd2c1SGregory Neil Shapiro else
4331*d39bd2c1SGregory Neil Shapiro SM_FREE(vrfy);
4332*d39bd2c1SGregory Neil Shapiro }
4333*d39bd2c1SGregory Neil Shapiro
4334*d39bd2c1SGregory Neil Shapiro /*
4335*d39bd2c1SGregory Neil Shapiro ** Note: MCIF_TLS should be reset when
4336*d39bd2c1SGregory Neil Shapiro ** when starttls was successful because
4337*d39bd2c1SGregory Neil Shapiro ** the server should not offer it anymore.
4338*d39bd2c1SGregory Neil Shapiro */
4339*d39bd2c1SGregory Neil Shapiro
4340*d39bd2c1SGregory Neil Shapiro else if (strcmp("TRUSTED", vrfy) != 0 &&
4341*d39bd2c1SGregory Neil Shapiro RCPT_REQ_DANE(to))
4342*d39bd2c1SGregory Neil Shapiro {
4343*d39bd2c1SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM, macid("{verify}"),
4344*d39bd2c1SGregory Neil Shapiro (0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLNOTLS)) ?
4345*d39bd2c1SGregory Neil Shapiro "DANE_TEMP" :
4346*d39bd2c1SGregory Neil Shapiro (bitset(MCIF_TLS|MCIF_TLSACT, mci->mci_flags) ?
4347*d39bd2c1SGregory Neil Shapiro "DANE_FAIL" : "DANE_NOTLS"));
4348*d39bd2c1SGregory Neil Shapiro }
4349*d39bd2c1SGregory Neil Shapiro /* DANE: unsupported types: require TLS but not available? */
4350*d39bd2c1SGregory Neil Shapiro else if (strcmp("TRUSTED", vrfy) != 0 &&
4351*d39bd2c1SGregory Neil Shapiro RCPT_REQ_TLS(to)
4352*d39bd2c1SGregory Neil Shapiro && (!bitset(MCIF_TLS|MCIF_TLSACT, mci->mci_flags)
4353*d39bd2c1SGregory Neil Shapiro || (0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLNOTLS))))
4354*d39bd2c1SGregory Neil Shapiro {
4355*d39bd2c1SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM, macid("{verify}"),
4356*d39bd2c1SGregory Neil Shapiro (0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLNOTLS)) ?
4357*d39bd2c1SGregory Neil Shapiro "DANE_TEMP" : "DANE_NOTLS");
4358*d39bd2c1SGregory Neil Shapiro }
4359*d39bd2c1SGregory Neil Shapiro else
4360*d39bd2c1SGregory Neil Shapiro SM_FREE(vrfy);
4361*d39bd2c1SGregory Neil Shapiro if (TTD(10, 32))
4362*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: 7: verify=%s, secure=%d\n",
4363*d39bd2c1SGregory Neil Shapiro macvalue(macid("{verify}"), e),
4364*d39bd2c1SGregory Neil Shapiro RCPT_REQ_DANE(to));
4365*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
4366*d39bd2c1SGregory Neil Shapiro
43672fb4f839SGregory Neil Shapiro rc = rscheck("tls_rcpt", to->q_user, NULL, e,
4368959366dcSGregory Neil Shapiro RSF_RMCOMM|RSF_COUNT, 3,
4369*d39bd2c1SGregory Neil Shapiro mci->mci_host, e->e_id, &addr, NULL);
4370*d39bd2c1SGregory Neil Shapiro
4371*d39bd2c1SGregory Neil Shapiro # if DANE
4372*d39bd2c1SGregory Neil Shapiro if (vrfy != NULL)
4373*d39bd2c1SGregory Neil Shapiro {
4374*d39bd2c1SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM, macid("{verify}"), vrfy);
4375*d39bd2c1SGregory Neil Shapiro SM_FREE(vrfy);
4376*d39bd2c1SGregory Neil Shapiro }
4377*d39bd2c1SGregory Neil Shapiro # endif
4378*d39bd2c1SGregory Neil Shapiro
4379*d39bd2c1SGregory Neil Shapiro if (TTD(10, 32))
4380*d39bd2c1SGregory Neil Shapiro sm_dprintf("deliver: 9: verify=%s, to=%s, tls_rcpt=%d\n",
4381*d39bd2c1SGregory Neil Shapiro macvalue(macid("{verify}"), e),
4382*d39bd2c1SGregory Neil Shapiro to->q_user, rc);
4383*d39bd2c1SGregory Neil Shapiro
43842fb4f839SGregory Neil Shapiro if (rc != EX_OK)
4385c2aa98e2SPeter Wemm {
4386*d39bd2c1SGregory Neil Shapiro char *dsn;
4387*d39bd2c1SGregory Neil Shapiro
43882fb4f839SGregory Neil Shapiro to->q_flags |= QINTREPLY;
43892fb4f839SGregory Neil Shapiro markfailure(e, to, mci, rc, false);
4390*d39bd2c1SGregory Neil Shapiro if (addr.q_host != NULL &&
4391*d39bd2c1SGregory Neil Shapiro isenhsc(addr.q_host, ' ') > 0)
4392*d39bd2c1SGregory Neil Shapiro dsn = addr.q_host;
4393*d39bd2c1SGregory Neil Shapiro else
4394*d39bd2c1SGregory Neil Shapiro dsn = NULL;
4395*d39bd2c1SGregory Neil Shapiro giveresponse(rc, dsn, m, mci,
439640266059SGregory Neil Shapiro ctladdr, xstart, e, to);
43972fb4f839SGregory Neil Shapiro if (rc == EX_TEMPFAIL)
439840266059SGregory Neil Shapiro {
439940266059SGregory Neil Shapiro mci->mci_retryrcpt = true;
440040266059SGregory Neil Shapiro to->q_state = QS_RETRY;
440140266059SGregory Neil Shapiro }
440206f25ae9SGregory Neil Shapiro continue;
440306f25ae9SGregory Neil Shapiro }
440406f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
440506f25ae9SGregory Neil Shapiro
44062fb4f839SGregory Neil Shapiro rc = smtprcpt(to, m, mci, e, ctladdr, xstart);
440740266059SGregory Neil Shapiro #if PIPELINING
44082fb4f839SGregory Neil Shapiro if (rc == EX_OK &&
440940266059SGregory Neil Shapiro bitset(MCIF_PIPELINED, mci->mci_flags))
441006f25ae9SGregory Neil Shapiro {
441140266059SGregory Neil Shapiro /*
441240266059SGregory Neil Shapiro ** Add new element to list of
441340266059SGregory Neil Shapiro ** recipients for pipelining.
441440266059SGregory Neil Shapiro */
441540266059SGregory Neil Shapiro
441640266059SGregory Neil Shapiro to->q_pchain = NULL;
441740266059SGregory Neil Shapiro if (mci->mci_nextaddr == NULL)
441840266059SGregory Neil Shapiro mci->mci_nextaddr = to;
441940266059SGregory Neil Shapiro if (pchain == NULL)
442040266059SGregory Neil Shapiro pchain = to;
4421c2aa98e2SPeter Wemm else
4422c2aa98e2SPeter Wemm {
442340266059SGregory Neil Shapiro pchain->q_pchain = to;
442440266059SGregory Neil Shapiro pchain = pchain->q_pchain;
442540266059SGregory Neil Shapiro }
442640266059SGregory Neil Shapiro }
442740266059SGregory Neil Shapiro #endif /* PIPELINING */
44282fb4f839SGregory Neil Shapiro if (rc != EX_OK)
442940266059SGregory Neil Shapiro {
44302fb4f839SGregory Neil Shapiro markfailure(e, to, mci, rc, false);
44312fb4f839SGregory Neil Shapiro giveresponse(rc, to->q_status, m, mci,
443240266059SGregory Neil Shapiro ctladdr, xstart, e, to);
44332fb4f839SGregory Neil Shapiro if (rc == EX_TEMPFAIL)
443440266059SGregory Neil Shapiro to->q_state = QS_RETRY;
4435c2aa98e2SPeter Wemm }
4436c2aa98e2SPeter Wemm }
4437c2aa98e2SPeter Wemm
443840266059SGregory Neil Shapiro /* No recipients in list and no missing responses? */
443940266059SGregory Neil Shapiro if (tobuf[0] == '\0'
444040266059SGregory Neil Shapiro #if PIPELINING
44412fb4f839SGregory Neil Shapiro /* && bitset(MCIF_PIPELINED, mci->mci_flags) */
444240266059SGregory Neil Shapiro && mci->mci_nextaddr == NULL
44435b0945b5SGregory Neil Shapiro #endif
444440266059SGregory Neil Shapiro )
4445c2aa98e2SPeter Wemm {
44462fb4f839SGregory Neil Shapiro rcode = rc;
4447c2aa98e2SPeter Wemm e->e_to = NULL;
4448c2aa98e2SPeter Wemm if (bitset(MCIF_CACHED, mci->mci_flags))
4449c2aa98e2SPeter Wemm smtprset(m, mci, e);
4450c2aa98e2SPeter Wemm }
4451c2aa98e2SPeter Wemm else
4452c2aa98e2SPeter Wemm {
4453c2aa98e2SPeter Wemm e->e_to = tobuf + 1;
445440266059SGregory Neil Shapiro rcode = smtpdata(m, mci, e, ctladdr, xstart);
4455c2aa98e2SPeter Wemm }
4456c2aa98e2SPeter Wemm }
44572fb4f839SGregory Neil Shapiro
44582fb4f839SGregory Neil Shapiro if (rcode == EX_TEMPFAIL && nummxhosts > hostnum
44592fb4f839SGregory Neil Shapiro && (mci->mci_retryrcpt || mci->mci_okrcpts > 0)
44602fb4f839SGregory Neil Shapiro )
4461c2aa98e2SPeter Wemm {
4462*d39bd2c1SGregory Neil Shapiro logfailover(e, m, mci, rcode, to);
4463c2aa98e2SPeter Wemm /* try next MX site */
4464c2aa98e2SPeter Wemm goto tryhost;
4465c2aa98e2SPeter Wemm }
4466c2aa98e2SPeter Wemm }
4467c2aa98e2SPeter Wemm #if NAMED_BIND
4468c2aa98e2SPeter Wemm if (ConfigLevel < 2)
4469c2aa98e2SPeter Wemm _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */
44705b0945b5SGregory Neil Shapiro #endif
4471c2aa98e2SPeter Wemm
4472c2aa98e2SPeter Wemm if (tTd(62, 1))
4473c2aa98e2SPeter Wemm checkfds("after delivery");
4474c2aa98e2SPeter Wemm
4475c2aa98e2SPeter Wemm /*
4476c2aa98e2SPeter Wemm ** Do final status disposal.
4477c2aa98e2SPeter Wemm ** We check for something in tobuf for the SMTP case.
4478c2aa98e2SPeter Wemm ** If we got a temporary failure, arrange to queue the
4479c2aa98e2SPeter Wemm ** addressees.
4480c2aa98e2SPeter Wemm */
4481c2aa98e2SPeter Wemm
4482c2aa98e2SPeter Wemm give_up:
4483c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags))
4484c2aa98e2SPeter Wemm {
4485c2aa98e2SPeter Wemm lmtp_rcode = rcode;
4486c2aa98e2SPeter Wemm tobuf[0] = '\0';
448740266059SGregory Neil Shapiro anyok = false;
448840266059SGregory Neil Shapiro strsize = 0;
4489c2aa98e2SPeter Wemm }
4490c2aa98e2SPeter Wemm else
4491c2aa98e2SPeter Wemm anyok = rcode == EX_OK;
4492c2aa98e2SPeter Wemm
4493c2aa98e2SPeter Wemm for (to = tochain; to != NULL; to = to->q_tchain)
4494c2aa98e2SPeter Wemm {
4495c2aa98e2SPeter Wemm /* see if address already marked */
449606f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state))
4497c2aa98e2SPeter Wemm continue;
4498c2aa98e2SPeter Wemm
4499c2aa98e2SPeter Wemm /* if running LMTP, get the status for each address */
4500c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags))
4501c2aa98e2SPeter Wemm {
4502c2aa98e2SPeter Wemm if (lmtp_rcode == EX_OK)
4503c2aa98e2SPeter Wemm rcode = smtpgetstat(m, mci, e);
4504c2aa98e2SPeter Wemm if (rcode == EX_OK)
4505c2aa98e2SPeter Wemm {
450640266059SGregory Neil Shapiro strsize += sm_strlcat2(tobuf + strsize, ",",
450740266059SGregory Neil Shapiro to->q_paddr,
450840266059SGregory Neil Shapiro tobufsize - strsize);
450940266059SGregory Neil Shapiro SM_ASSERT(strsize < tobufsize);
451040266059SGregory Neil Shapiro anyok = true;
4511c2aa98e2SPeter Wemm }
4512c2aa98e2SPeter Wemm else
4513c2aa98e2SPeter Wemm {
4514c2aa98e2SPeter Wemm e->e_to = to->q_paddr;
451540266059SGregory Neil Shapiro markfailure(e, to, mci, rcode, true);
451606f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, mci,
451740266059SGregory Neil Shapiro ctladdr, xstart, e, to);
4518c2aa98e2SPeter Wemm e->e_to = tobuf + 1;
4519c2aa98e2SPeter Wemm continue;
4520c2aa98e2SPeter Wemm }
4521c2aa98e2SPeter Wemm }
4522c2aa98e2SPeter Wemm else
4523c2aa98e2SPeter Wemm {
4524c2aa98e2SPeter Wemm /* mark bad addresses */
4525c2aa98e2SPeter Wemm if (rcode != EX_OK)
4526c2aa98e2SPeter Wemm {
4527c2aa98e2SPeter Wemm if (goodmxfound && rcode == EX_NOHOST)
4528c2aa98e2SPeter Wemm rcode = EX_TEMPFAIL;
452940266059SGregory Neil Shapiro markfailure(e, to, mci, rcode, true);
4530c2aa98e2SPeter Wemm continue;
4531c2aa98e2SPeter Wemm }
4532c2aa98e2SPeter Wemm }
4533c2aa98e2SPeter Wemm
4534c2aa98e2SPeter Wemm /* successful delivery */
453506f25ae9SGregory Neil Shapiro to->q_state = QS_SENT;
4536c2aa98e2SPeter Wemm to->q_statdate = curtime();
4537c2aa98e2SPeter Wemm e->e_nsent++;
453806f25ae9SGregory Neil Shapiro
453906f25ae9SGregory Neil Shapiro /*
454006f25ae9SGregory Neil Shapiro ** Checkpoint the send list every few addresses
454106f25ae9SGregory Neil Shapiro */
454206f25ae9SGregory Neil Shapiro
454342e5d165SGregory Neil Shapiro if (CheckpointInterval > 0 && e->e_nsent >= CheckpointInterval)
454406f25ae9SGregory Neil Shapiro {
45452fb4f839SGregory Neil Shapiro queueup(e, QUP_FL_NONE);
454606f25ae9SGregory Neil Shapiro e->e_nsent = 0;
454706f25ae9SGregory Neil Shapiro }
454806f25ae9SGregory Neil Shapiro
4549c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) &&
4550c2aa98e2SPeter Wemm bitset(QPINGONSUCCESS, to->q_flags))
4551c2aa98e2SPeter Wemm {
4552c2aa98e2SPeter Wemm to->q_flags |= QDELIVERED;
4553c2aa98e2SPeter Wemm to->q_status = "2.1.5";
455440266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
455540266059SGregory Neil Shapiro "%s... Successfully delivered\n",
4556c2aa98e2SPeter Wemm to->q_paddr);
4557c2aa98e2SPeter Wemm }
4558c2aa98e2SPeter Wemm else if (bitset(QPINGONSUCCESS, to->q_flags) &&
4559c2aa98e2SPeter Wemm bitset(QPRIMARY, to->q_flags) &&
4560c2aa98e2SPeter Wemm !bitset(MCIF_DSN, mci->mci_flags))
4561c2aa98e2SPeter Wemm {
4562c2aa98e2SPeter Wemm to->q_flags |= QRELAYED;
456340266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
456440266059SGregory Neil Shapiro "%s... relayed; expect no further notifications\n",
456540266059SGregory Neil Shapiro to->q_paddr);
456640266059SGregory Neil Shapiro }
456740266059SGregory Neil Shapiro else if (IS_DLVR_NOTIFY(e) &&
456840266059SGregory Neil Shapiro !bitset(MCIF_DLVR_BY, mci->mci_flags) &&
456940266059SGregory Neil Shapiro bitset(QPRIMARY, to->q_flags) &&
457040266059SGregory Neil Shapiro (!bitset(QHASNOTIFY, to->q_flags) ||
457140266059SGregory Neil Shapiro bitset(QPINGONSUCCESS, to->q_flags) ||
457240266059SGregory Neil Shapiro bitset(QPINGONFAILURE, to->q_flags) ||
457340266059SGregory Neil Shapiro bitset(QPINGONDELAY, to->q_flags)))
457440266059SGregory Neil Shapiro {
457540266059SGregory Neil Shapiro /* RFC 2852, 4.1.4.2: no NOTIFY, or not NEVER */
457640266059SGregory Neil Shapiro to->q_flags |= QBYNRELAY;
457740266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
457840266059SGregory Neil Shapiro "%s... Deliver-by notify: relayed\n",
457940266059SGregory Neil Shapiro to->q_paddr);
458040266059SGregory Neil Shapiro }
458140266059SGregory Neil Shapiro else if (IS_DLVR_TRACE(e) &&
458240266059SGregory Neil Shapiro (!bitset(QHASNOTIFY, to->q_flags) ||
458340266059SGregory Neil Shapiro bitset(QPINGONSUCCESS, to->q_flags) ||
458440266059SGregory Neil Shapiro bitset(QPINGONFAILURE, to->q_flags) ||
458540266059SGregory Neil Shapiro bitset(QPINGONDELAY, to->q_flags)) &&
458640266059SGregory Neil Shapiro bitset(QPRIMARY, to->q_flags))
458740266059SGregory Neil Shapiro {
458840266059SGregory Neil Shapiro /* RFC 2852, 4.1.4: no NOTIFY, or not NEVER */
458940266059SGregory Neil Shapiro to->q_flags |= QBYTRACE;
459040266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
459140266059SGregory Neil Shapiro "%s... Deliver-By trace: relayed\n",
4592c2aa98e2SPeter Wemm to->q_paddr);
4593c2aa98e2SPeter Wemm }
4594c2aa98e2SPeter Wemm }
4595c2aa98e2SPeter Wemm
4596c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags))
4597c2aa98e2SPeter Wemm {
4598c2aa98e2SPeter Wemm /*
4599c2aa98e2SPeter Wemm ** Global information applies to the last recipient only;
4600c2aa98e2SPeter Wemm ** clear it out to avoid bogus errors.
4601c2aa98e2SPeter Wemm */
4602c2aa98e2SPeter Wemm
4603c2aa98e2SPeter Wemm rcode = EX_OK;
4604c2aa98e2SPeter Wemm e->e_statmsg = NULL;
4605c2aa98e2SPeter Wemm
4606c2aa98e2SPeter Wemm /* reset the mci state for the next transaction */
460740266059SGregory Neil Shapiro if (mci != NULL &&
460840266059SGregory Neil Shapiro (mci->mci_state == MCIS_MAIL ||
460940266059SGregory Neil Shapiro mci->mci_state == MCIS_RCPT ||
461040266059SGregory Neil Shapiro mci->mci_state == MCIS_DATA))
4611323f6dcbSGregory Neil Shapiro {
4612c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPEN;
4613323f6dcbSGregory Neil Shapiro SmtpPhase = mci->mci_phase = "idle";
4614323f6dcbSGregory Neil Shapiro sm_setproctitle(true, e, "%s: %s", CurHostName,
4615323f6dcbSGregory Neil Shapiro mci->mci_phase);
4616323f6dcbSGregory Neil Shapiro }
4617c2aa98e2SPeter Wemm }
4618c2aa98e2SPeter Wemm
4619c2aa98e2SPeter Wemm if (tobuf[0] != '\0')
462040266059SGregory Neil Shapiro {
46212fb4f839SGregory Neil Shapiro giveresponse(rcode,
46222fb4f839SGregory Neil Shapiro #if _FFR_NULLMX_STATUS
46232fb4f839SGregory Neil Shapiro (NULL == mci || SM_IS_EMPTY(mci->mci_status))
46242fb4f839SGregory Neil Shapiro ? NULL :
46252fb4f839SGregory Neil Shapiro #endif
46262fb4f839SGregory Neil Shapiro mci->mci_status,
46272fb4f839SGregory Neil Shapiro m, mci, ctladdr, xstart, e, NULL);
462840266059SGregory Neil Shapiro #if 0
462940266059SGregory Neil Shapiro /*
463040266059SGregory Neil Shapiro ** This code is disabled for now because I am not
463140266059SGregory Neil Shapiro ** sure that copying status from the first recipient
463240266059SGregory Neil Shapiro ** to all non-status'ed recipients is a good idea.
463340266059SGregory Neil Shapiro */
463440266059SGregory Neil Shapiro
463540266059SGregory Neil Shapiro if (tochain->q_message != NULL &&
463640266059SGregory Neil Shapiro !bitnset(M_LMTP, m->m_flags) && rcode != EX_OK)
463740266059SGregory Neil Shapiro {
463840266059SGregory Neil Shapiro for (to = tochain->q_tchain; to != NULL;
463940266059SGregory Neil Shapiro to = to->q_tchain)
464040266059SGregory Neil Shapiro {
464140266059SGregory Neil Shapiro /* see if address already marked */
464240266059SGregory Neil Shapiro if (QS_IS_QUEUEUP(to->q_state) &&
464340266059SGregory Neil Shapiro to->q_message == NULL)
464440266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool,
464540266059SGregory Neil Shapiro tochain->q_message);
464640266059SGregory Neil Shapiro }
464740266059SGregory Neil Shapiro }
464840266059SGregory Neil Shapiro #endif /* 0 */
464940266059SGregory Neil Shapiro }
4650c2aa98e2SPeter Wemm if (anyok)
465140266059SGregory Neil Shapiro markstats(e, tochain, STATS_NORMAL);
4652c2aa98e2SPeter Wemm mci_store_persistent(mci);
4653c2aa98e2SPeter Wemm
46545b0945b5SGregory Neil Shapiro #if _FFR_OCC
46555b0945b5SGregory Neil Shapiro /*
46565b0945b5SGregory Neil Shapiro ** HACK: this is NOT the right place to "close" a connection!
46575b0945b5SGregory Neil Shapiro ** use smtpquit?
46585b0945b5SGregory Neil Shapiro ** add a flag to mci to indicate that rate/conc. was increased?
46595b0945b5SGregory Neil Shapiro */
46605b0945b5SGregory Neil Shapiro
46615b0945b5SGregory Neil Shapiro if (clever)
46625b0945b5SGregory Neil Shapiro {
46635b0945b5SGregory Neil Shapiro extern SOCKADDR CurHostAddr;
46645b0945b5SGregory Neil Shapiro
46655b0945b5SGregory Neil Shapiro /* check family... {} */
46665b0945b5SGregory Neil Shapiro /* r = anynet_pton(AF_INET, p, dst); */
46675b0945b5SGregory Neil Shapiro occ_close(e, mci, host, &CurHostAddr);
46685b0945b5SGregory Neil Shapiro }
46695b0945b5SGregory Neil Shapiro #endif /* _FFR_OCC */
46705b0945b5SGregory Neil Shapiro
467140266059SGregory Neil Shapiro /* Some recipients were tempfailed, try them on the next host */
467240266059SGregory Neil Shapiro if (mci != NULL && mci->mci_retryrcpt && nummxhosts > hostnum)
467340266059SGregory Neil Shapiro {
4674*d39bd2c1SGregory Neil Shapiro logfailover(e, m, mci, rcode, to);
467540266059SGregory Neil Shapiro /* try next MX site */
467640266059SGregory Neil Shapiro goto tryhost;
467740266059SGregory Neil Shapiro }
467840266059SGregory Neil Shapiro
4679c2aa98e2SPeter Wemm /* now close the connection */
4680c2aa98e2SPeter Wemm if (clever && mci != NULL && mci->mci_state != MCIS_CLOSED &&
4681c2aa98e2SPeter Wemm !bitset(MCIF_CACHED, mci->mci_flags))
4682c2aa98e2SPeter Wemm smtpquit(m, mci, e);
4683c2aa98e2SPeter Wemm
468440266059SGregory Neil Shapiro cleanup: ;
468540266059SGregory Neil Shapiro }
468640266059SGregory Neil Shapiro SM_FINALLY
468740266059SGregory Neil Shapiro {
4688c2aa98e2SPeter Wemm /*
4689c2aa98e2SPeter Wemm ** Restore state and return.
4690c2aa98e2SPeter Wemm */
4691c2aa98e2SPeter Wemm #if XDEBUG
4692c2aa98e2SPeter Wemm char wbuf[MAXLINE];
4693c2aa98e2SPeter Wemm
4694c2aa98e2SPeter Wemm /* make absolutely certain 0, 1, and 2 are in use */
4695d0cef73dSGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof(wbuf),
469640266059SGregory Neil Shapiro "%s... end of deliver(%s)",
4697c2aa98e2SPeter Wemm e->e_to == NULL ? "NO-TO-LIST"
469840266059SGregory Neil Shapiro : shortenstring(e->e_to,
469940266059SGregory Neil Shapiro MAXSHORTSTR),
4700c2aa98e2SPeter Wemm m->m_name);
4701c2aa98e2SPeter Wemm checkfd012(wbuf);
470206f25ae9SGregory Neil Shapiro #endif /* XDEBUG */
4703c2aa98e2SPeter Wemm
4704c2aa98e2SPeter Wemm errno = 0;
470540266059SGregory Neil Shapiro
470640266059SGregory Neil Shapiro /*
470740266059SGregory Neil Shapiro ** It was originally necessary to set macro 'g' to NULL
470840266059SGregory Neil Shapiro ** because it previously pointed to an auto buffer.
470940266059SGregory Neil Shapiro ** We don't do this any more, so this may be unnecessary.
471040266059SGregory Neil Shapiro */
471140266059SGregory Neil Shapiro
471240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', (char *) NULL);
471306f25ae9SGregory Neil Shapiro e->e_to = NULL;
471440266059SGregory Neil Shapiro }
471540266059SGregory Neil Shapiro SM_END_TRY
471606f25ae9SGregory Neil Shapiro return rcode;
4717c2aa98e2SPeter Wemm }
471806f25ae9SGregory Neil Shapiro
471940266059SGregory Neil Shapiro /*
4720*d39bd2c1SGregory Neil Shapiro ** EX2ENHSC -- return proper enhanced status code for an EX_ code
4721*d39bd2c1SGregory Neil Shapiro **
4722*d39bd2c1SGregory Neil Shapiro ** Parameters:
4723*d39bd2c1SGregory Neil Shapiro ** xcode -- EX_* code
4724*d39bd2c1SGregory Neil Shapiro **
4725*d39bd2c1SGregory Neil Shapiro ** Returns:
4726*d39bd2c1SGregory Neil Shapiro ** enhanced status code if appropriate
4727*d39bd2c1SGregory Neil Shapiro ** NULL otherwise
4728*d39bd2c1SGregory Neil Shapiro */
4729*d39bd2c1SGregory Neil Shapiro
4730*d39bd2c1SGregory Neil Shapiro static char *ex2enhsc __P((int));
4731*d39bd2c1SGregory Neil Shapiro
4732*d39bd2c1SGregory Neil Shapiro static char *
ex2enhsc(xcode)4733*d39bd2c1SGregory Neil Shapiro ex2enhsc(xcode)
4734*d39bd2c1SGregory Neil Shapiro int xcode;
4735*d39bd2c1SGregory Neil Shapiro {
4736*d39bd2c1SGregory Neil Shapiro switch (xcode)
4737*d39bd2c1SGregory Neil Shapiro {
4738*d39bd2c1SGregory Neil Shapiro case EX_USAGE:
4739*d39bd2c1SGregory Neil Shapiro return "5.5.4";
4740*d39bd2c1SGregory Neil Shapiro break;
4741*d39bd2c1SGregory Neil Shapiro
4742*d39bd2c1SGregory Neil Shapiro case EX_DATAERR:
4743*d39bd2c1SGregory Neil Shapiro return "5.5.2";
4744*d39bd2c1SGregory Neil Shapiro break;
4745*d39bd2c1SGregory Neil Shapiro
4746*d39bd2c1SGregory Neil Shapiro case EX_NOUSER:
4747*d39bd2c1SGregory Neil Shapiro return "5.1.1";
4748*d39bd2c1SGregory Neil Shapiro break;
4749*d39bd2c1SGregory Neil Shapiro
4750*d39bd2c1SGregory Neil Shapiro case EX_NOHOST:
4751*d39bd2c1SGregory Neil Shapiro return "5.1.2";
4752*d39bd2c1SGregory Neil Shapiro break;
4753*d39bd2c1SGregory Neil Shapiro
4754*d39bd2c1SGregory Neil Shapiro case EX_NOINPUT:
4755*d39bd2c1SGregory Neil Shapiro case EX_CANTCREAT:
4756*d39bd2c1SGregory Neil Shapiro case EX_NOPERM:
4757*d39bd2c1SGregory Neil Shapiro return "5.3.0";
4758*d39bd2c1SGregory Neil Shapiro break;
4759*d39bd2c1SGregory Neil Shapiro
4760*d39bd2c1SGregory Neil Shapiro case EX_UNAVAILABLE:
4761*d39bd2c1SGregory Neil Shapiro case EX_SOFTWARE:
4762*d39bd2c1SGregory Neil Shapiro case EX_OSFILE:
4763*d39bd2c1SGregory Neil Shapiro case EX_PROTOCOL:
4764*d39bd2c1SGregory Neil Shapiro case EX_CONFIG:
4765*d39bd2c1SGregory Neil Shapiro return "5.5.0";
4766*d39bd2c1SGregory Neil Shapiro break;
4767*d39bd2c1SGregory Neil Shapiro
4768*d39bd2c1SGregory Neil Shapiro case EX_OSERR:
4769*d39bd2c1SGregory Neil Shapiro case EX_IOERR:
4770*d39bd2c1SGregory Neil Shapiro return "4.5.0";
4771*d39bd2c1SGregory Neil Shapiro break;
4772*d39bd2c1SGregory Neil Shapiro
4773*d39bd2c1SGregory Neil Shapiro case EX_TEMPFAIL:
4774*d39bd2c1SGregory Neil Shapiro return "4.2.0";
4775*d39bd2c1SGregory Neil Shapiro break;
4776*d39bd2c1SGregory Neil Shapiro }
4777*d39bd2c1SGregory Neil Shapiro return NULL;
4778*d39bd2c1SGregory Neil Shapiro }
4779*d39bd2c1SGregory Neil Shapiro
4780*d39bd2c1SGregory Neil Shapiro /*
4781c2aa98e2SPeter Wemm ** MARKFAILURE -- mark a failure on a specific address.
4782c2aa98e2SPeter Wemm **
4783c2aa98e2SPeter Wemm ** Parameters:
4784c2aa98e2SPeter Wemm ** e -- the envelope we are sending.
4785c2aa98e2SPeter Wemm ** q -- the address to mark.
4786c2aa98e2SPeter Wemm ** mci -- mailer connection information.
4787c2aa98e2SPeter Wemm ** rcode -- the code signifying the particular failure.
478806f25ae9SGregory Neil Shapiro ** ovr -- override an existing code?
4789c2aa98e2SPeter Wemm **
4790c2aa98e2SPeter Wemm ** Returns:
4791c2aa98e2SPeter Wemm ** none.
4792c2aa98e2SPeter Wemm **
4793c2aa98e2SPeter Wemm ** Side Effects:
4794c2aa98e2SPeter Wemm ** marks the address (and possibly the envelope) with the
4795c2aa98e2SPeter Wemm ** failure so that an error will be returned or
4796c2aa98e2SPeter Wemm ** the message will be queued, as appropriate.
4797c2aa98e2SPeter Wemm */
4798c2aa98e2SPeter Wemm
479940266059SGregory Neil Shapiro void
markfailure(e,q,mci,rcode,ovr)480006f25ae9SGregory Neil Shapiro markfailure(e, q, mci, rcode, ovr)
4801c2aa98e2SPeter Wemm register ENVELOPE *e;
4802c2aa98e2SPeter Wemm register ADDRESS *q;
4803c2aa98e2SPeter Wemm register MCI *mci;
4804c2aa98e2SPeter Wemm int rcode;
480506f25ae9SGregory Neil Shapiro bool ovr;
4806c2aa98e2SPeter Wemm {
480740266059SGregory Neil Shapiro int save_errno = errno;
480806f25ae9SGregory Neil Shapiro char *status = NULL;
480906f25ae9SGregory Neil Shapiro char *rstatus = NULL;
4810c2aa98e2SPeter Wemm
4811c2aa98e2SPeter Wemm switch (rcode)
4812c2aa98e2SPeter Wemm {
4813c2aa98e2SPeter Wemm case EX_OK:
4814c2aa98e2SPeter Wemm break;
4815c2aa98e2SPeter Wemm
4816c2aa98e2SPeter Wemm case EX_TEMPFAIL:
4817c2aa98e2SPeter Wemm case EX_IOERR:
4818c2aa98e2SPeter Wemm case EX_OSERR:
481906f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP;
4820c2aa98e2SPeter Wemm break;
4821c2aa98e2SPeter Wemm
4822c2aa98e2SPeter Wemm default:
482306f25ae9SGregory Neil Shapiro q->q_state = QS_BADADDR;
4824c2aa98e2SPeter Wemm break;
4825c2aa98e2SPeter Wemm }
4826c2aa98e2SPeter Wemm
4827c2aa98e2SPeter Wemm /* find most specific error code possible */
4828c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_status != NULL)
4829c2aa98e2SPeter Wemm {
483040266059SGregory Neil Shapiro status = sm_rpool_strdup_x(e->e_rpool, mci->mci_status);
4831c2aa98e2SPeter Wemm if (mci->mci_rstatus != NULL)
483240266059SGregory Neil Shapiro rstatus = sm_rpool_strdup_x(e->e_rpool,
483340266059SGregory Neil Shapiro mci->mci_rstatus);
4834c2aa98e2SPeter Wemm }
4835c2aa98e2SPeter Wemm else if (e->e_status != NULL)
483606f25ae9SGregory Neil Shapiro status = e->e_status;
4837c2aa98e2SPeter Wemm else
4838*d39bd2c1SGregory Neil Shapiro status = ex2enhsc(rcode);
4839c2aa98e2SPeter Wemm
484006f25ae9SGregory Neil Shapiro /* new status? */
484106f25ae9SGregory Neil Shapiro if (status != NULL && *status != '\0' && (ovr || q->q_status == NULL ||
484206f25ae9SGregory Neil Shapiro *q->q_status == '\0' || *q->q_status < *status))
484306f25ae9SGregory Neil Shapiro {
484406f25ae9SGregory Neil Shapiro q->q_status = status;
484506f25ae9SGregory Neil Shapiro q->q_rstatus = rstatus;
484606f25ae9SGregory Neil Shapiro }
4847c2aa98e2SPeter Wemm if (rcode != EX_OK && q->q_rstatus == NULL &&
4848c2aa98e2SPeter Wemm q->q_mailer != NULL && q->q_mailer->m_diagtype != NULL &&
48492fb4f839SGregory Neil Shapiro SM_STRCASEEQ(q->q_mailer->m_diagtype, "X-UNIX"))
4850c2aa98e2SPeter Wemm {
485106f25ae9SGregory Neil Shapiro char buf[16];
4852c2aa98e2SPeter Wemm
4853d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%d", rcode);
485440266059SGregory Neil Shapiro q->q_rstatus = sm_rpool_strdup_x(e->e_rpool, buf);
4855c2aa98e2SPeter Wemm }
485606f25ae9SGregory Neil Shapiro
485706f25ae9SGregory Neil Shapiro q->q_statdate = curtime();
485806f25ae9SGregory Neil Shapiro if (CurHostName != NULL && CurHostName[0] != '\0' &&
485906f25ae9SGregory Neil Shapiro mci != NULL && !bitset(M_LOCALMAILER, mci->mci_flags))
486040266059SGregory Neil Shapiro q->q_statmta = sm_rpool_strdup_x(e->e_rpool, CurHostName);
486140266059SGregory Neil Shapiro
486240266059SGregory Neil Shapiro /* restore errno */
486340266059SGregory Neil Shapiro errno = save_errno;
4864c2aa98e2SPeter Wemm }
486540266059SGregory Neil Shapiro /*
4866c2aa98e2SPeter Wemm ** ENDMAILER -- Wait for mailer to terminate.
4867c2aa98e2SPeter Wemm **
4868c2aa98e2SPeter Wemm ** We should never get fatal errors (e.g., segmentation
4869c2aa98e2SPeter Wemm ** violation), so we report those specially. For other
4870c2aa98e2SPeter Wemm ** errors, we choose a status message (into statmsg),
4871c2aa98e2SPeter Wemm ** and if it represents an error, we print it.
4872c2aa98e2SPeter Wemm **
4873c2aa98e2SPeter Wemm ** Parameters:
487413058a91SGregory Neil Shapiro ** mci -- the mailer connection info.
4875c2aa98e2SPeter Wemm ** e -- the current envelope.
4876c2aa98e2SPeter Wemm ** pv -- the parameter vector that invoked the mailer
4877c2aa98e2SPeter Wemm ** (for error messages).
4878c2aa98e2SPeter Wemm **
4879c2aa98e2SPeter Wemm ** Returns:
4880c2aa98e2SPeter Wemm ** exit code of mailer.
4881c2aa98e2SPeter Wemm **
4882c2aa98e2SPeter Wemm ** Side Effects:
4883c2aa98e2SPeter Wemm ** none.
4884c2aa98e2SPeter Wemm */
4885c2aa98e2SPeter Wemm
488606f25ae9SGregory Neil Shapiro static jmp_buf EndWaitTimeout;
488706f25ae9SGregory Neil Shapiro
488806f25ae9SGregory Neil Shapiro static void
endwaittimeout(ignore)4889b6bacd31SGregory Neil Shapiro endwaittimeout(ignore)
4890b6bacd31SGregory Neil Shapiro int ignore;
489106f25ae9SGregory Neil Shapiro {
48928774250cSGregory Neil Shapiro /*
48938774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
48948774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
48958774250cSGregory Neil Shapiro ** DOING.
48968774250cSGregory Neil Shapiro */
48978774250cSGregory Neil Shapiro
489806f25ae9SGregory Neil Shapiro errno = ETIMEDOUT;
489906f25ae9SGregory Neil Shapiro longjmp(EndWaitTimeout, 1);
490006f25ae9SGregory Neil Shapiro }
490106f25ae9SGregory Neil Shapiro
4902c2aa98e2SPeter Wemm int
endmailer(mci,e,pv)4903c2aa98e2SPeter Wemm endmailer(mci, e, pv)
4904c2aa98e2SPeter Wemm register MCI *mci;
4905c2aa98e2SPeter Wemm register ENVELOPE *e;
4906c2aa98e2SPeter Wemm char **pv;
4907c2aa98e2SPeter Wemm {
4908c2aa98e2SPeter Wemm int st;
490906f25ae9SGregory Neil Shapiro int save_errno = errno;
491006f25ae9SGregory Neil Shapiro char buf[MAXLINE];
491140266059SGregory Neil Shapiro SM_EVENT *ev = NULL;
491206f25ae9SGregory Neil Shapiro
4913c2aa98e2SPeter Wemm
4914c2aa98e2SPeter Wemm mci_unlock_host(mci);
4915c2aa98e2SPeter Wemm
49168774250cSGregory Neil Shapiro /* close output to mailer */
49172fb4f839SGregory Neil Shapiro SM_CLOSE_FP(mci->mci_out);
49188774250cSGregory Neil Shapiro
49198774250cSGregory Neil Shapiro /* copy any remaining input to transcript */
49208774250cSGregory Neil Shapiro if (mci->mci_in != NULL && mci->mci_state != MCIS_ERROR &&
49218774250cSGregory Neil Shapiro e->e_xfp != NULL)
49228774250cSGregory Neil Shapiro {
4923d0cef73dSGregory Neil Shapiro while (sfgets(buf, sizeof(buf), mci->mci_in,
49248774250cSGregory Neil Shapiro TimeOuts.to_quit, "Draining Input") != NULL)
492540266059SGregory Neil Shapiro (void) sm_io_fputs(e->e_xfp, SM_TIME_DEFAULT, buf);
49268774250cSGregory Neil Shapiro }
49278774250cSGregory Neil Shapiro
492806f25ae9SGregory Neil Shapiro #if SASL
492940266059SGregory Neil Shapiro /* close SASL connection */
493006f25ae9SGregory Neil Shapiro if (bitset(MCIF_AUTHACT, mci->mci_flags))
493106f25ae9SGregory Neil Shapiro {
493206f25ae9SGregory Neil Shapiro sasl_dispose(&mci->mci_conn);
493306f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_AUTHACT;
493406f25ae9SGregory Neil Shapiro }
493506f25ae9SGregory Neil Shapiro #endif /* SASL */
493606f25ae9SGregory Neil Shapiro
493706f25ae9SGregory Neil Shapiro #if STARTTLS
493806f25ae9SGregory Neil Shapiro /* shutdown TLS */
493906f25ae9SGregory Neil Shapiro (void) endtlsclt(mci);
49405b0945b5SGregory Neil Shapiro #endif
494106f25ae9SGregory Neil Shapiro
494206f25ae9SGregory Neil Shapiro /* now close the input */
49432fb4f839SGregory Neil Shapiro SM_CLOSE_FP(mci->mci_in);
4944c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED;
4945c2aa98e2SPeter Wemm
494606f25ae9SGregory Neil Shapiro errno = save_errno;
494706f25ae9SGregory Neil Shapiro
4948c2aa98e2SPeter Wemm /* in the IPC case there is nothing to wait for */
4949c2aa98e2SPeter Wemm if (mci->mci_pid == 0)
495006f25ae9SGregory Neil Shapiro return EX_OK;
4951c2aa98e2SPeter Wemm
495206f25ae9SGregory Neil Shapiro /* put a timeout around the wait */
495306f25ae9SGregory Neil Shapiro if (mci->mci_mailer->m_wait > 0)
495406f25ae9SGregory Neil Shapiro {
495506f25ae9SGregory Neil Shapiro if (setjmp(EndWaitTimeout) == 0)
495640266059SGregory Neil Shapiro ev = sm_setevent(mci->mci_mailer->m_wait,
495706f25ae9SGregory Neil Shapiro endwaittimeout, 0);
495806f25ae9SGregory Neil Shapiro else
495906f25ae9SGregory Neil Shapiro {
496042e5d165SGregory Neil Shapiro syserr("endmailer %s: wait timeout (%ld)",
496106f25ae9SGregory Neil Shapiro mci->mci_mailer->m_name,
496242e5d165SGregory Neil Shapiro (long) mci->mci_mailer->m_wait);
496306f25ae9SGregory Neil Shapiro return EX_TEMPFAIL;
496406f25ae9SGregory Neil Shapiro }
496506f25ae9SGregory Neil Shapiro }
4966c2aa98e2SPeter Wemm
496706f25ae9SGregory Neil Shapiro /* wait for the mailer process, collect status */
4968c2aa98e2SPeter Wemm st = waitfor(mci->mci_pid);
496906f25ae9SGregory Neil Shapiro save_errno = errno;
497006f25ae9SGregory Neil Shapiro if (ev != NULL)
497140266059SGregory Neil Shapiro sm_clrevent(ev);
497206f25ae9SGregory Neil Shapiro errno = save_errno;
497306f25ae9SGregory Neil Shapiro
4974c2aa98e2SPeter Wemm if (st == -1)
4975c2aa98e2SPeter Wemm {
4976c2aa98e2SPeter Wemm syserr("endmailer %s: wait", mci->mci_mailer->m_name);
497706f25ae9SGregory Neil Shapiro return EX_SOFTWARE;
4978c2aa98e2SPeter Wemm }
4979c2aa98e2SPeter Wemm
4980c2aa98e2SPeter Wemm if (WIFEXITED(st))
4981c2aa98e2SPeter Wemm {
4982c2aa98e2SPeter Wemm /* normal death -- return status */
4983c2aa98e2SPeter Wemm return (WEXITSTATUS(st));
4984c2aa98e2SPeter Wemm }
4985c2aa98e2SPeter Wemm
4986c2aa98e2SPeter Wemm /* it died a horrid death */
498706f25ae9SGregory Neil Shapiro syserr("451 4.3.0 mailer %s died with signal %d%s",
498806f25ae9SGregory Neil Shapiro mci->mci_mailer->m_name, WTERMSIG(st),
498906f25ae9SGregory Neil Shapiro WCOREDUMP(st) ? " (core dumped)" :
499006f25ae9SGregory Neil Shapiro (WIFSTOPPED(st) ? " (stopped)" : ""));
4991c2aa98e2SPeter Wemm
4992c2aa98e2SPeter Wemm /* log the arguments */
4993c2aa98e2SPeter Wemm if (pv != NULL && e->e_xfp != NULL)
4994c2aa98e2SPeter Wemm {
4995c2aa98e2SPeter Wemm register char **av;
4996c2aa98e2SPeter Wemm
499740266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "Arguments:");
4998c2aa98e2SPeter Wemm for (av = pv; *av != NULL; av++)
499940266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, " %s",
500040266059SGregory Neil Shapiro *av);
500140266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "\n");
5002c2aa98e2SPeter Wemm }
5003c2aa98e2SPeter Wemm
5004c2aa98e2SPeter Wemm ExitStat = EX_TEMPFAIL;
500506f25ae9SGregory Neil Shapiro return EX_TEMPFAIL;
5006c2aa98e2SPeter Wemm }
500740266059SGregory Neil Shapiro /*
5008c2aa98e2SPeter Wemm ** GIVERESPONSE -- Interpret an error response from a mailer
5009c2aa98e2SPeter Wemm **
5010c2aa98e2SPeter Wemm ** Parameters:
501106f25ae9SGregory Neil Shapiro ** status -- the status code from the mailer (high byte
5012c2aa98e2SPeter Wemm ** only; core dumps must have been taken care of
5013c2aa98e2SPeter Wemm ** already).
501406f25ae9SGregory Neil Shapiro ** dsn -- the DSN associated with the address, if any.
5015c2aa98e2SPeter Wemm ** m -- the mailer info for this mailer.
5016c2aa98e2SPeter Wemm ** mci -- the mailer connection info -- can be NULL if the
5017c2aa98e2SPeter Wemm ** response is given before the connection is made.
5018c2aa98e2SPeter Wemm ** ctladdr -- the controlling address for the recipient
5019c2aa98e2SPeter Wemm ** address(es).
5020c2aa98e2SPeter Wemm ** xstart -- the transaction start time, for computing
5021c2aa98e2SPeter Wemm ** transaction delays.
5022c2aa98e2SPeter Wemm ** e -- the current envelope.
502340266059SGregory Neil Shapiro ** to -- the current recipient (NULL if none).
5024c2aa98e2SPeter Wemm **
5025c2aa98e2SPeter Wemm ** Returns:
5026c2aa98e2SPeter Wemm ** none.
5027c2aa98e2SPeter Wemm **
5028c2aa98e2SPeter Wemm ** Side Effects:
5029c2aa98e2SPeter Wemm ** Errors may be incremented.
5030c2aa98e2SPeter Wemm ** ExitStat may be set.
5031c2aa98e2SPeter Wemm */
5032c2aa98e2SPeter Wemm
5033c2aa98e2SPeter Wemm void
giveresponse(status,dsn,m,mci,ctladdr,xstart,e,to)503440266059SGregory Neil Shapiro giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to)
503506f25ae9SGregory Neil Shapiro int status;
503606f25ae9SGregory Neil Shapiro char *dsn;
5037c2aa98e2SPeter Wemm register MAILER *m;
5038c2aa98e2SPeter Wemm register MCI *mci;
5039c2aa98e2SPeter Wemm ADDRESS *ctladdr;
5040c2aa98e2SPeter Wemm time_t xstart;
5041c2aa98e2SPeter Wemm ENVELOPE *e;
504240266059SGregory Neil Shapiro ADDRESS *to;
5043c2aa98e2SPeter Wemm {
5044c2aa98e2SPeter Wemm register const char *statmsg;
504506f25ae9SGregory Neil Shapiro int errnum = errno;
504606f25ae9SGregory Neil Shapiro int off = 4;
504740266059SGregory Neil Shapiro bool usestat = false;
504806f25ae9SGregory Neil Shapiro char dsnbuf[ENHSCLEN];
5049c2aa98e2SPeter Wemm char buf[MAXLINE];
505040266059SGregory Neil Shapiro char *exmsg;
5051c2aa98e2SPeter Wemm
5052c2aa98e2SPeter Wemm if (e == NULL)
5053af9557fdSGregory Neil Shapiro {
5054c2aa98e2SPeter Wemm syserr("giveresponse: null envelope");
5055af9557fdSGregory Neil Shapiro /* NOTREACHED */
5056af9557fdSGregory Neil Shapiro SM_ASSERT(0);
5057af9557fdSGregory Neil Shapiro }
5058c2aa98e2SPeter Wemm
50592fb4f839SGregory Neil Shapiro if (tTd(11, 4))
5060*d39bd2c1SGregory Neil Shapiro sm_dprintf("giveresponse: status=%d, e->e_message=%s, dsn=%s, SmtpError=%s\n",
5061*d39bd2c1SGregory Neil Shapiro status, e->e_message, dsn, SmtpError);
50622fb4f839SGregory Neil Shapiro
5063c2aa98e2SPeter Wemm /*
5064c2aa98e2SPeter Wemm ** Compute status message from code.
5065c2aa98e2SPeter Wemm */
5066c2aa98e2SPeter Wemm
506740266059SGregory Neil Shapiro exmsg = sm_sysexmsg(status);
506806f25ae9SGregory Neil Shapiro if (status == 0)
5069c2aa98e2SPeter Wemm {
507006f25ae9SGregory Neil Shapiro statmsg = "250 2.0.0 Sent";
5071c2aa98e2SPeter Wemm if (e->e_statmsg != NULL)
5072c2aa98e2SPeter Wemm {
5073d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%s (%s)",
507406f25ae9SGregory Neil Shapiro statmsg,
507506f25ae9SGregory Neil Shapiro shortenstring(e->e_statmsg, 403));
5076c2aa98e2SPeter Wemm statmsg = buf;
5077c2aa98e2SPeter Wemm }
5078c2aa98e2SPeter Wemm }
507940266059SGregory Neil Shapiro else if (exmsg == NULL)
5080c2aa98e2SPeter Wemm {
5081d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf),
508206f25ae9SGregory Neil Shapiro "554 5.3.0 unknown mailer error %d",
508306f25ae9SGregory Neil Shapiro status);
508406f25ae9SGregory Neil Shapiro status = EX_UNAVAILABLE;
5085c2aa98e2SPeter Wemm statmsg = buf;
508640266059SGregory Neil Shapiro usestat = true;
5087c2aa98e2SPeter Wemm }
508806f25ae9SGregory Neil Shapiro else if (status == EX_TEMPFAIL)
5089c2aa98e2SPeter Wemm {
5090c2aa98e2SPeter Wemm char *bp = buf;
5091c2aa98e2SPeter Wemm
509240266059SGregory Neil Shapiro (void) sm_strlcpy(bp, exmsg + 1, SPACELEFT(buf, bp));
5093c2aa98e2SPeter Wemm bp += strlen(bp);
5094c2aa98e2SPeter Wemm #if NAMED_BIND
5095c2aa98e2SPeter Wemm if (h_errno == TRY_AGAIN)
509640266059SGregory Neil Shapiro statmsg = sm_errstring(h_errno + E_DNSBASE);
5097c2aa98e2SPeter Wemm else
50982fb4f839SGregory Neil Shapiro #endif
5099c2aa98e2SPeter Wemm {
510006f25ae9SGregory Neil Shapiro if (errnum != 0)
510140266059SGregory Neil Shapiro statmsg = sm_errstring(errnum);
5102c2aa98e2SPeter Wemm else
5103c2aa98e2SPeter Wemm statmsg = SmtpError;
5104c2aa98e2SPeter Wemm }
5105c2aa98e2SPeter Wemm if (statmsg != NULL && statmsg[0] != '\0')
510606f25ae9SGregory Neil Shapiro {
510706f25ae9SGregory Neil Shapiro switch (errnum)
510806f25ae9SGregory Neil Shapiro {
510906f25ae9SGregory Neil Shapiro #ifdef ENETDOWN
511006f25ae9SGregory Neil Shapiro case ENETDOWN: /* Network is down */
51115b0945b5SGregory Neil Shapiro #endif
511206f25ae9SGregory Neil Shapiro #ifdef ENETUNREACH
511306f25ae9SGregory Neil Shapiro case ENETUNREACH: /* Network is unreachable */
51145b0945b5SGregory Neil Shapiro #endif
511506f25ae9SGregory Neil Shapiro #ifdef ENETRESET
511606f25ae9SGregory Neil Shapiro case ENETRESET: /* Network dropped connection on reset */
51175b0945b5SGregory Neil Shapiro #endif
511806f25ae9SGregory Neil Shapiro #ifdef ECONNABORTED
511906f25ae9SGregory Neil Shapiro case ECONNABORTED: /* Software caused connection abort */
51205b0945b5SGregory Neil Shapiro #endif
512106f25ae9SGregory Neil Shapiro #ifdef EHOSTDOWN
512206f25ae9SGregory Neil Shapiro case EHOSTDOWN: /* Host is down */
51235b0945b5SGregory Neil Shapiro #endif
512406f25ae9SGregory Neil Shapiro #ifdef EHOSTUNREACH
512506f25ae9SGregory Neil Shapiro case EHOSTUNREACH: /* No route to host */
51265b0945b5SGregory Neil Shapiro #endif
5127b6bacd31SGregory Neil Shapiro if (mci != NULL && mci->mci_host != NULL)
512806f25ae9SGregory Neil Shapiro {
512940266059SGregory Neil Shapiro (void) sm_strlcpyn(bp,
513040266059SGregory Neil Shapiro SPACELEFT(buf, bp),
513140266059SGregory Neil Shapiro 2, ": ",
513240266059SGregory Neil Shapiro mci->mci_host);
513306f25ae9SGregory Neil Shapiro bp += strlen(bp);
513406f25ae9SGregory Neil Shapiro }
513506f25ae9SGregory Neil Shapiro break;
513606f25ae9SGregory Neil Shapiro }
513740266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ": ",
513840266059SGregory Neil Shapiro statmsg);
51395b0945b5SGregory Neil Shapiro #if DANE
51405b0945b5SGregory Neil Shapiro if (errnum == 0 && SmtpError[0] != '\0' &&
51415b0945b5SGregory Neil Shapiro h_errno == TRY_AGAIN &&
51425b0945b5SGregory Neil Shapiro mci->mci_exitstat == EX_TEMPFAIL)
51435b0945b5SGregory Neil Shapiro {
51445b0945b5SGregory Neil Shapiro (void) sm_strlcat(bp, SmtpError,
51455b0945b5SGregory Neil Shapiro SPACELEFT(buf, bp));
51465b0945b5SGregory Neil Shapiro bp += strlen(bp);
51475b0945b5SGregory Neil Shapiro }
51485b0945b5SGregory Neil Shapiro #endif /* DANE */
514940266059SGregory Neil Shapiro usestat = true;
515006f25ae9SGregory Neil Shapiro }
5151c2aa98e2SPeter Wemm statmsg = buf;
5152c2aa98e2SPeter Wemm }
5153c2aa98e2SPeter Wemm #if NAMED_BIND
515406f25ae9SGregory Neil Shapiro else if (status == EX_NOHOST && h_errno != 0)
5155c2aa98e2SPeter Wemm {
515640266059SGregory Neil Shapiro statmsg = sm_errstring(h_errno + E_DNSBASE);
5157d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%s (%s)", exmsg + 1,
515840266059SGregory Neil Shapiro statmsg);
5159c2aa98e2SPeter Wemm statmsg = buf;
516040266059SGregory Neil Shapiro usestat = true;
5161c2aa98e2SPeter Wemm }
516206f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
51632fb4f839SGregory Neil Shapiro #if USE_EAI
51642fb4f839SGregory Neil Shapiro else if (errnum == 0 && status == EX_DATAERR
51652fb4f839SGregory Neil Shapiro && e->e_message != NULL && e->e_message[0] != '\0')
51662fb4f839SGregory Neil Shapiro {
51672fb4f839SGregory Neil Shapiro int m;
51682fb4f839SGregory Neil Shapiro
51692fb4f839SGregory Neil Shapiro /* XREF: 2nd arg must be coordinated with smtpmailfrom() */
51702fb4f839SGregory Neil Shapiro m = skipaddrhost(e->e_message, false);
51712fb4f839SGregory Neil Shapiro
51722fb4f839SGregory Neil Shapiro /*
51732fb4f839SGregory Neil Shapiro ** XXX Why is the SMTP reply code needed here?
51742fb4f839SGregory Neil Shapiro ** How to avoid a hard-coded value?
51752fb4f839SGregory Neil Shapiro */
51762fb4f839SGregory Neil Shapiro
51772fb4f839SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "550 %s", e->e_message + m);
51782fb4f839SGregory Neil Shapiro statmsg = buf;
51792fb4f839SGregory Neil Shapiro usestat = true;
51802fb4f839SGregory Neil Shapiro }
51812fb4f839SGregory Neil Shapiro #endif /* USE_EAI */
5182c2aa98e2SPeter Wemm else
5183c2aa98e2SPeter Wemm {
518440266059SGregory Neil Shapiro statmsg = exmsg;
518506f25ae9SGregory Neil Shapiro if (*statmsg++ == ':' && errnum != 0)
5186c2aa98e2SPeter Wemm {
5187d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%s: %s", statmsg,
518840266059SGregory Neil Shapiro sm_errstring(errnum));
5189c2aa98e2SPeter Wemm statmsg = buf;
519040266059SGregory Neil Shapiro usestat = true;
5191c2aa98e2SPeter Wemm }
5192605302a5SGregory Neil Shapiro else if (bitnset(M_LMTP, m->m_flags) && e->e_statmsg != NULL)
5193605302a5SGregory Neil Shapiro {
5194d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%s (%s)", statmsg,
5195605302a5SGregory Neil Shapiro shortenstring(e->e_statmsg, 403));
5196605302a5SGregory Neil Shapiro statmsg = buf;
5197605302a5SGregory Neil Shapiro usestat = true;
5198605302a5SGregory Neil Shapiro }
5199c2aa98e2SPeter Wemm }
5200c2aa98e2SPeter Wemm
5201c2aa98e2SPeter Wemm /*
5202c2aa98e2SPeter Wemm ** Print the message as appropriate
5203c2aa98e2SPeter Wemm */
5204c2aa98e2SPeter Wemm
520506f25ae9SGregory Neil Shapiro if (status == EX_OK || status == EX_TEMPFAIL)
5206c2aa98e2SPeter Wemm {
5207c2aa98e2SPeter Wemm extern char MsgBuf[];
5208c2aa98e2SPeter Wemm
520906f25ae9SGregory Neil Shapiro if ((off = isenhsc(statmsg + 4, ' ')) > 0)
521006f25ae9SGregory Neil Shapiro {
521106f25ae9SGregory Neil Shapiro if (dsn == NULL)
521206f25ae9SGregory Neil Shapiro {
5213d0cef73dSGregory Neil Shapiro (void) sm_snprintf(dsnbuf, sizeof(dsnbuf),
521406f25ae9SGregory Neil Shapiro "%.*s", off, statmsg + 4);
521506f25ae9SGregory Neil Shapiro dsn = dsnbuf;
521606f25ae9SGregory Neil Shapiro }
521706f25ae9SGregory Neil Shapiro off += 5;
521806f25ae9SGregory Neil Shapiro }
521906f25ae9SGregory Neil Shapiro else
522006f25ae9SGregory Neil Shapiro {
522106f25ae9SGregory Neil Shapiro off = 4;
522206f25ae9SGregory Neil Shapiro }
522306f25ae9SGregory Neil Shapiro message("%s", statmsg + off);
522406f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && e->e_xfp != NULL)
522540266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "%s\n",
522640266059SGregory Neil Shapiro &MsgBuf[4]);
5227c2aa98e2SPeter Wemm }
5228c2aa98e2SPeter Wemm else
5229c2aa98e2SPeter Wemm {
523006f25ae9SGregory Neil Shapiro char mbuf[ENHSCLEN + 4];
5231c2aa98e2SPeter Wemm
5232c2aa98e2SPeter Wemm Errors++;
523306f25ae9SGregory Neil Shapiro if ((off = isenhsc(statmsg + 4, ' ')) > 0 &&
5234d0cef73dSGregory Neil Shapiro off < sizeof(mbuf) - 4)
523506f25ae9SGregory Neil Shapiro {
523606f25ae9SGregory Neil Shapiro if (dsn == NULL)
523706f25ae9SGregory Neil Shapiro {
5238d0cef73dSGregory Neil Shapiro (void) sm_snprintf(dsnbuf, sizeof(dsnbuf),
523906f25ae9SGregory Neil Shapiro "%.*s", off, statmsg + 4);
524006f25ae9SGregory Neil Shapiro dsn = dsnbuf;
524106f25ae9SGregory Neil Shapiro }
524206f25ae9SGregory Neil Shapiro off += 5;
524340266059SGregory Neil Shapiro
524440266059SGregory Neil Shapiro /* copy only part of statmsg to mbuf */
524540266059SGregory Neil Shapiro (void) sm_strlcpy(mbuf, statmsg, off);
5246d0cef73dSGregory Neil Shapiro (void) sm_strlcat(mbuf, " %s", sizeof(mbuf));
524706f25ae9SGregory Neil Shapiro }
524806f25ae9SGregory Neil Shapiro else
524906f25ae9SGregory Neil Shapiro {
525006f25ae9SGregory Neil Shapiro dsnbuf[0] = '\0';
5251d0cef73dSGregory Neil Shapiro (void) sm_snprintf(mbuf, sizeof(mbuf), "%.3s %%s",
525240266059SGregory Neil Shapiro statmsg);
525306f25ae9SGregory Neil Shapiro off = 4;
525406f25ae9SGregory Neil Shapiro }
525506f25ae9SGregory Neil Shapiro usrerr(mbuf, &statmsg[off]);
5256c2aa98e2SPeter Wemm }
5257c2aa98e2SPeter Wemm
5258c2aa98e2SPeter Wemm /*
5259c2aa98e2SPeter Wemm ** Final cleanup.
5260da7d7b9cSGregory Neil Shapiro ** Log a record of the transaction. Compute the new ExitStat
5261da7d7b9cSGregory Neil Shapiro ** -- if we already had an error, stick with that.
5262c2aa98e2SPeter Wemm */
5263c2aa98e2SPeter Wemm
5264c2aa98e2SPeter Wemm if (OpMode != MD_VERIFY && !bitset(EF_VRFYONLY, e->e_flags) &&
526506f25ae9SGregory Neil Shapiro LogLevel > ((status == EX_TEMPFAIL) ? 8 : (status == EX_OK) ? 7 : 6))
5266da7d7b9cSGregory Neil Shapiro logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e, to, status);
5267c2aa98e2SPeter Wemm
5268c2aa98e2SPeter Wemm if (tTd(11, 2))
52692fb4f839SGregory Neil Shapiro sm_dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s, errnum=%d, statmsg=%s\n",
527006f25ae9SGregory Neil Shapiro status,
527106f25ae9SGregory Neil Shapiro dsn == NULL ? "<NULL>" : dsn,
527240266059SGregory Neil Shapiro e->e_message == NULL ? "<NULL>" : e->e_message,
52732fb4f839SGregory Neil Shapiro errnum, statmsg);
5274c2aa98e2SPeter Wemm
527506f25ae9SGregory Neil Shapiro if (status != EX_TEMPFAIL)
527606f25ae9SGregory Neil Shapiro setstat(status);
527706f25ae9SGregory Neil Shapiro if (status != EX_OK && (status != EX_TEMPFAIL || e->e_message == NULL))
527840266059SGregory Neil Shapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, statmsg + off);
527940266059SGregory Neil Shapiro if (status != EX_OK && to != NULL && to->q_message == NULL)
5280c2aa98e2SPeter Wemm {
528140266059SGregory Neil Shapiro if (!usestat && e->e_message != NULL)
528240266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool,
528340266059SGregory Neil Shapiro e->e_message);
528440266059SGregory Neil Shapiro else
528540266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool,
528640266059SGregory Neil Shapiro statmsg + off);
5287c2aa98e2SPeter Wemm }
5288c2aa98e2SPeter Wemm errno = 0;
5289602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0);
5290c2aa98e2SPeter Wemm }
5291*d39bd2c1SGregory Neil Shapiro
5292*d39bd2c1SGregory Neil Shapiro #if _FFR_8BITENVADDR
5293*d39bd2c1SGregory Neil Shapiro # define GET_HOST_VALUE \
5294*d39bd2c1SGregory Neil Shapiro (void) dequote_internal_chars(p, xbuf, sizeof(xbuf)); \
5295*d39bd2c1SGregory Neil Shapiro p = xbuf;
5296*d39bd2c1SGregory Neil Shapiro #else
5297*d39bd2c1SGregory Neil Shapiro # define GET_HOST_VALUE
5298*d39bd2c1SGregory Neil Shapiro #endif
5299*d39bd2c1SGregory Neil Shapiro
530040266059SGregory Neil Shapiro /*
5301c2aa98e2SPeter Wemm ** LOGDELIVERY -- log the delivery in the system log
5302c2aa98e2SPeter Wemm **
5303c2aa98e2SPeter Wemm ** Care is taken to avoid logging lines that are too long, because
5304c2aa98e2SPeter Wemm ** some versions of syslog have an unfortunate proclivity for core
5305c2aa98e2SPeter Wemm ** dumping. This is a hack, to be sure, that is at best empirical.
5306c2aa98e2SPeter Wemm **
5307c2aa98e2SPeter Wemm ** Parameters:
5308c2aa98e2SPeter Wemm ** m -- the mailer info. Can be NULL for initial queue.
5309c2aa98e2SPeter Wemm ** mci -- the mailer connection info -- can be NULL if the
531006f25ae9SGregory Neil Shapiro ** log is occurring when no connection is active.
531106f25ae9SGregory Neil Shapiro ** dsn -- the DSN attached to the status.
531206f25ae9SGregory Neil Shapiro ** status -- the message to print for the status.
5313c2aa98e2SPeter Wemm ** ctladdr -- the controlling address for the to list.
5314c2aa98e2SPeter Wemm ** xstart -- the transaction start time, used for
5315c2aa98e2SPeter Wemm ** computing transaction delay.
5316c2aa98e2SPeter Wemm ** e -- the current envelope.
5317da7d7b9cSGregory Neil Shapiro ** to -- the current recipient (NULL if none).
5318*d39bd2c1SGregory Neil Shapiro ** rcode -- status code.
5319c2aa98e2SPeter Wemm **
5320c2aa98e2SPeter Wemm ** Returns:
5321c2aa98e2SPeter Wemm ** none
5322c2aa98e2SPeter Wemm **
5323c2aa98e2SPeter Wemm ** Side Effects:
5324c2aa98e2SPeter Wemm ** none
5325c2aa98e2SPeter Wemm */
5326c2aa98e2SPeter Wemm
5327c2aa98e2SPeter Wemm void
logdelivery(m,mci,dsn,status,ctladdr,xstart,e,to,rcode)5328da7d7b9cSGregory Neil Shapiro logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode)
5329c2aa98e2SPeter Wemm MAILER *m;
5330c2aa98e2SPeter Wemm register MCI *mci;
533106f25ae9SGregory Neil Shapiro char *dsn;
533206f25ae9SGregory Neil Shapiro const char *status;
5333c2aa98e2SPeter Wemm ADDRESS *ctladdr;
5334c2aa98e2SPeter Wemm time_t xstart;
5335c2aa98e2SPeter Wemm register ENVELOPE *e;
5336da7d7b9cSGregory Neil Shapiro ADDRESS *to;
5337da7d7b9cSGregory Neil Shapiro int rcode;
5338c2aa98e2SPeter Wemm {
5339c2aa98e2SPeter Wemm register char *bp;
5340c2aa98e2SPeter Wemm register char *p;
5341c2aa98e2SPeter Wemm int l;
534240266059SGregory Neil Shapiro time_t now = curtime();
5343c2aa98e2SPeter Wemm char buf[1024];
53442fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
53452fb4f839SGregory Neil Shapiro char xbuf[SM_MAX(SYSLOG_BUFSIZE, MAXNAME)]; /* EAI:ok */
53462fb4f839SGregory Neil Shapiro #endif
53472fb4f839SGregory Neil Shapiro char *xstr;
5348c2aa98e2SPeter Wemm
5349c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256
5350*d39bd2c1SGregory Neil Shapiro int xtype, rtype;
5351*d39bd2c1SGregory Neil Shapiro
5352c2aa98e2SPeter Wemm /* ctladdr: max 106 bytes */
5353c2aa98e2SPeter Wemm bp = buf;
5354c2aa98e2SPeter Wemm if (ctladdr != NULL)
5355c2aa98e2SPeter Wemm {
535640266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", ctladdr=",
5357c2aa98e2SPeter Wemm shortenstring(ctladdr->q_paddr, 83));
5358c2aa98e2SPeter Wemm bp += strlen(bp);
5359c2aa98e2SPeter Wemm if (bitset(QGOODUID, ctladdr->q_flags))
5360c2aa98e2SPeter Wemm {
536140266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
536206f25ae9SGregory Neil Shapiro (int) ctladdr->q_uid,
536306f25ae9SGregory Neil Shapiro (int) ctladdr->q_gid);
5364c2aa98e2SPeter Wemm bp += strlen(bp);
5365c2aa98e2SPeter Wemm }
5366c2aa98e2SPeter Wemm }
5367c2aa98e2SPeter Wemm
5368c2aa98e2SPeter Wemm /* delay & xdelay: max 41 bytes */
536940266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", delay=",
537040266059SGregory Neil Shapiro pintvl(now - e->e_ctime, true));
5371c2aa98e2SPeter Wemm bp += strlen(bp);
5372c2aa98e2SPeter Wemm
5373c2aa98e2SPeter Wemm if (xstart != (time_t) 0)
5374c2aa98e2SPeter Wemm {
537540266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=",
537640266059SGregory Neil Shapiro pintvl(now - xstart, true));
5377c2aa98e2SPeter Wemm bp += strlen(bp);
5378c2aa98e2SPeter Wemm }
5379c2aa98e2SPeter Wemm
5380c2aa98e2SPeter Wemm /* mailer: assume about 19 bytes (max 10 byte mailer name) */
5381c2aa98e2SPeter Wemm if (m != NULL)
5382c2aa98e2SPeter Wemm {
538340266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=",
538440266059SGregory Neil Shapiro m->m_name);
5385c2aa98e2SPeter Wemm bp += strlen(bp);
5386c2aa98e2SPeter Wemm }
5387c2aa98e2SPeter Wemm
5388da7d7b9cSGregory Neil Shapiro # if _FFR_LOG_MORE2
53895b0945b5SGregory Neil Shapiro LOG_MORE(buf, bp);
53905b0945b5SGregory Neil Shapiro # endif
5391da7d7b9cSGregory Neil Shapiro
539206f25ae9SGregory Neil Shapiro /* pri: changes with each delivery attempt */
539340266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld",
5394ba00ec3dSGregory Neil Shapiro PRT_NONNEGL(e->e_msgpriority));
539506f25ae9SGregory Neil Shapiro bp += strlen(bp);
539606f25ae9SGregory Neil Shapiro
5397c2aa98e2SPeter Wemm /* relay: max 66 bytes for IPv4 addresses */
5398c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_host != NULL)
5399c2aa98e2SPeter Wemm {
5400c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr;
5401c2aa98e2SPeter Wemm
540240266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", relay=",
5403c2aa98e2SPeter Wemm shortenstring(mci->mci_host, 40));
5404c2aa98e2SPeter Wemm bp += strlen(bp);
5405c2aa98e2SPeter Wemm
5406c2aa98e2SPeter Wemm if (CurHostAddr.sa.sa_family != 0)
5407c2aa98e2SPeter Wemm {
540840266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " [%s]",
5409c2aa98e2SPeter Wemm anynet_ntoa(&CurHostAddr));
5410c2aa98e2SPeter Wemm }
5411c2aa98e2SPeter Wemm }
541240266059SGregory Neil Shapiro else if (strcmp(status, "quarantined") == 0)
541340266059SGregory Neil Shapiro {
541440266059SGregory Neil Shapiro if (e->e_quarmsg != NULL)
541540266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
541640266059SGregory Neil Shapiro ", quarantine=%s",
541740266059SGregory Neil Shapiro shortenstring(e->e_quarmsg, 40));
541840266059SGregory Neil Shapiro }
541906f25ae9SGregory Neil Shapiro else if (strcmp(status, "queued") != 0)
5420c2aa98e2SPeter Wemm {
5421c2aa98e2SPeter Wemm p = macvalue('h', e);
5422c2aa98e2SPeter Wemm if (p != NULL && p[0] != '\0')
5423c2aa98e2SPeter Wemm {
5424*d39bd2c1SGregory Neil Shapiro GET_HOST_VALUE;
542540266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
542640266059SGregory Neil Shapiro ", relay=%s", shortenstring(p, 40));
5427c2aa98e2SPeter Wemm }
5428c2aa98e2SPeter Wemm }
5429c2aa98e2SPeter Wemm bp += strlen(bp);
5430c2aa98e2SPeter Wemm
5431*d39bd2c1SGregory Neil Shapiro p = ex2enhsc(rcode);
5432*d39bd2c1SGregory Neil Shapiro if (p != NULL)
5433*d39bd2c1SGregory Neil Shapiro xtype = p[0] - '0';
5434*d39bd2c1SGregory Neil Shapiro else
5435*d39bd2c1SGregory Neil Shapiro xtype = 0;
5436*d39bd2c1SGregory Neil Shapiro
5437*d39bd2c1SGregory Neil Shapiro #ifndef WHERE2REPORT
5438*d39bd2c1SGregory Neil Shapiro # define WHERE2REPORT "please see <https://sendmail.org/Report>, "
5439*d39bd2c1SGregory Neil Shapiro #endif
5440*d39bd2c1SGregory Neil Shapiro
544106f25ae9SGregory Neil Shapiro /* dsn */
544206f25ae9SGregory Neil Shapiro if (dsn != NULL && *dsn != '\0')
544306f25ae9SGregory Neil Shapiro {
544440266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", dsn=",
544506f25ae9SGregory Neil Shapiro shortenstring(dsn, ENHSCLEN));
544606f25ae9SGregory Neil Shapiro bp += strlen(bp);
5447*d39bd2c1SGregory Neil Shapiro if (xtype > 0 && ISSMTPCODE(dsn) &&
5448*d39bd2c1SGregory Neil Shapiro (rtype = dsn[0] - '0') > 0 && rtype != xtype)
5449*d39bd2c1SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
5450*d39bd2c1SGregory Neil Shapiro "ERROR: inconsistent dsn, %srcode=%d, dsn=%s",
5451*d39bd2c1SGregory Neil Shapiro WHERE2REPORT, rcode, dsn);
545206f25ae9SGregory Neil Shapiro }
545306f25ae9SGregory Neil Shapiro
545413d88268SGregory Neil Shapiro # if _FFR_LOG_NTRIES
545513d88268SGregory Neil Shapiro /* ntries */
545613d88268SGregory Neil Shapiro if (e->e_ntries >= 0)
545713d88268SGregory Neil Shapiro {
545813d88268SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
545913d88268SGregory Neil Shapiro ", ntries=%d", e->e_ntries + 1);
546013d88268SGregory Neil Shapiro bp += strlen(bp);
546113d88268SGregory Neil Shapiro }
546213d88268SGregory Neil Shapiro # endif /* _FFR_LOG_NTRIES */
546313d88268SGregory Neil Shapiro
5464c2aa98e2SPeter Wemm # define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4)
5465c2aa98e2SPeter Wemm # if (STATLEN) < 63
5466c2aa98e2SPeter Wemm # undef STATLEN
5467c2aa98e2SPeter Wemm # define STATLEN 63
54682fb4f839SGregory Neil Shapiro # endif
5469c2aa98e2SPeter Wemm # if (STATLEN) > 203
5470c2aa98e2SPeter Wemm # undef STATLEN
5471c2aa98e2SPeter Wemm # define STATLEN 203
54722fb4f839SGregory Neil Shapiro # endif
5473c2aa98e2SPeter Wemm
5474*d39bd2c1SGregory Neil Shapiro # if _FFR_LOG_STAGE
5475*d39bd2c1SGregory Neil Shapiro /* only do this when reply= is logged? */
5476*d39bd2c1SGregory Neil Shapiro if (rcode != EX_OK && e->e_estate >= 0)
5477*d39bd2c1SGregory Neil Shapiro {
5478*d39bd2c1SGregory Neil Shapiro if (e->e_estate >= 0 && e->e_estate < SM_ARRAY_SIZE(xs_states))
5479*d39bd2c1SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
5480*d39bd2c1SGregory Neil Shapiro ", stage=%s", xs_states[e->e_estate]);
5481*d39bd2c1SGregory Neil Shapiro else
5482*d39bd2c1SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
5483*d39bd2c1SGregory Neil Shapiro ", stage=%d", e->e_estate);
5484*d39bd2c1SGregory Neil Shapiro bp += strlen(bp);
5485*d39bd2c1SGregory Neil Shapiro }
5486*d39bd2c1SGregory Neil Shapiro # endif /* _FFR_LOG_STAGE */
5487*d39bd2c1SGregory Neil Shapiro
5488da7d7b9cSGregory Neil Shapiro /*
5489da7d7b9cSGregory Neil Shapiro ** Notes:
5490da7d7b9cSGregory Neil Shapiro ** per-rcpt status: to->q_rstatus
5491da7d7b9cSGregory Neil Shapiro ** global status: e->e_text
5492da7d7b9cSGregory Neil Shapiro **
5493da7d7b9cSGregory Neil Shapiro ** We (re)use STATLEN here, is that a good choice?
5494da7d7b9cSGregory Neil Shapiro **
5495da7d7b9cSGregory Neil Shapiro ** stat=Deferred: ...
5496da7d7b9cSGregory Neil Shapiro ** has sometimes the same text?
5497da7d7b9cSGregory Neil Shapiro **
54985b0945b5SGregory Neil Shapiro ** Note: in some case the normal logging might show the same server
54995b0945b5SGregory Neil Shapiro ** reply - how to avoid that?
5500da7d7b9cSGregory Neil Shapiro */
5501da7d7b9cSGregory Neil Shapiro
55022fb4f839SGregory Neil Shapiro /* only show errors from server */
5503*d39bd2c1SGregory Neil Shapiro if (rcode != EX_OK && (NULL == to || !bitset(QINTREPLY, to->q_flags)))
5504*d39bd2c1SGregory Neil Shapiro {
5505*d39bd2c1SGregory Neil Shapiro if (to != NULL && !SM_IS_EMPTY(to->q_rstatus))
5506da7d7b9cSGregory Neil Shapiro {
5507da7d7b9cSGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
5508da7d7b9cSGregory Neil Shapiro ", reply=%s",
5509da7d7b9cSGregory Neil Shapiro shortenstring(to->q_rstatus, STATLEN));
5510da7d7b9cSGregory Neil Shapiro bp += strlen(bp);
5511*d39bd2c1SGregory Neil Shapiro if (ISSMTPCODE(to->q_rstatus) &&
5512*d39bd2c1SGregory Neil Shapiro (rtype = to->q_rstatus[0] - '0') > 0 &&
5513*d39bd2c1SGregory Neil Shapiro ((xtype > 0 && rtype != xtype) || rtype < 4))
5514*d39bd2c1SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
5515*d39bd2c1SGregory Neil Shapiro "ERROR: inconsistent reply, %srcode=%d, q_rstatus=%s",
5516*d39bd2c1SGregory Neil Shapiro WHERE2REPORT, rcode, to->q_rstatus);
5517da7d7b9cSGregory Neil Shapiro }
5518*d39bd2c1SGregory Neil Shapiro else if (e->e_text != NULL)
5519da7d7b9cSGregory Neil Shapiro {
5520da7d7b9cSGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
5521da7d7b9cSGregory Neil Shapiro ", reply=%d %s%s%s",
5522da7d7b9cSGregory Neil Shapiro e->e_rcode,
5523da7d7b9cSGregory Neil Shapiro e->e_renhsc,
5524da7d7b9cSGregory Neil Shapiro (e->e_renhsc[0] != '\0') ? " " : "",
5525da7d7b9cSGregory Neil Shapiro shortenstring(e->e_text, STATLEN));
5526da7d7b9cSGregory Neil Shapiro bp += strlen(bp);
5527*d39bd2c1SGregory Neil Shapiro rtype = REPLYTYPE(e->e_rcode);
5528*d39bd2c1SGregory Neil Shapiro if (rtype > 0 &&
5529*d39bd2c1SGregory Neil Shapiro ((xtype > 0 && rtype != xtype) || rtype < 4))
5530*d39bd2c1SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
5531*d39bd2c1SGregory Neil Shapiro "ERROR: inconsistent reply, %srcode=%d, e_rcode=%d, e_text=%s",
5532*d39bd2c1SGregory Neil Shapiro WHERE2REPORT, rcode, e->e_rcode, e->e_text);
5533da7d7b9cSGregory Neil Shapiro }
55342fb4f839SGregory Neil Shapiro #if _FFR_NULLMX_STATUS
55352fb4f839SGregory Neil Shapiro /* Hack for MX 0 . : how to make this general? */
5536*d39bd2c1SGregory Neil Shapiro else if (NULL == to && dsn != NULL &&
55372fb4f839SGregory Neil Shapiro strcmp(dsn, ESCNULLMXRCPT) == 0)
55382fb4f839SGregory Neil Shapiro {
55392fb4f839SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
55402fb4f839SGregory Neil Shapiro ", status=%s", ERRNULLMX);
55412fb4f839SGregory Neil Shapiro bp += strlen(bp);
55422fb4f839SGregory Neil Shapiro }
55432fb4f839SGregory Neil Shapiro #endif
5544*d39bd2c1SGregory Neil Shapiro }
5545da7d7b9cSGregory Neil Shapiro
5546c2aa98e2SPeter Wemm /* stat: max 210 bytes */
5547d0cef73dSGregory Neil Shapiro if ((bp - buf) > (sizeof(buf) - ((STATLEN) + 20)))
5548c2aa98e2SPeter Wemm {
5549c2aa98e2SPeter Wemm /* desperation move -- truncate data */
5550d0cef73dSGregory Neil Shapiro bp = buf + sizeof(buf) - ((STATLEN) + 17);
555140266059SGregory Neil Shapiro (void) sm_strlcpy(bp, "...", SPACELEFT(buf, bp));
5552c2aa98e2SPeter Wemm bp += 3;
5553c2aa98e2SPeter Wemm }
5554c2aa98e2SPeter Wemm
555540266059SGregory Neil Shapiro (void) sm_strlcpy(bp, ", stat=", SPACELEFT(buf, bp));
5556c2aa98e2SPeter Wemm bp += strlen(bp);
5557c2aa98e2SPeter Wemm
555840266059SGregory Neil Shapiro (void) sm_strlcpy(bp, shortenstring(status, STATLEN),
555940266059SGregory Neil Shapiro SPACELEFT(buf, bp));
5560c2aa98e2SPeter Wemm
5561c2aa98e2SPeter Wemm /* id, to: max 13 + TOBUFSIZE bytes */
5562c2aa98e2SPeter Wemm l = SYSLOG_BUFSIZE - 100 - strlen(buf);
556340266059SGregory Neil Shapiro if (l < 0)
556440266059SGregory Neil Shapiro l = 0;
556506f25ae9SGregory Neil Shapiro p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to;
556640266059SGregory Neil Shapiro while (strlen(p) >= l)
5567c2aa98e2SPeter Wemm {
556806f25ae9SGregory Neil Shapiro register char *q;
5569c2aa98e2SPeter Wemm
557006f25ae9SGregory Neil Shapiro for (q = p + l; q > p; q--)
557106f25ae9SGregory Neil Shapiro {
5572da7d7b9cSGregory Neil Shapiro /* XXX a comma in an address will break this! */
557306f25ae9SGregory Neil Shapiro if (*q == ',')
557406f25ae9SGregory Neil Shapiro break;
557506f25ae9SGregory Neil Shapiro }
557606f25ae9SGregory Neil Shapiro if (p == q)
557706f25ae9SGregory Neil Shapiro break;
55782fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR
55792fb4f839SGregory Neil Shapiro /* XXX is this correct? dequote all of p? */
55802fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(p, xbuf, sizeof(xbuf));
55812fb4f839SGregory Neil Shapiro xstr = xbuf;
55822fb4f839SGregory Neil Shapiro # else
55832fb4f839SGregory Neil Shapiro xstr = p;
55842fb4f839SGregory Neil Shapiro # endif
558540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]%s",
55862fb4f839SGregory Neil Shapiro (int) (++q - p), xstr, buf);
5587c2aa98e2SPeter Wemm p = q;
5588c2aa98e2SPeter Wemm }
55892fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR
55902fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(p, xbuf, sizeof(xbuf));
55912fb4f839SGregory Neil Shapiro xstr = xbuf;
55922fb4f839SGregory Neil Shapiro # else
55932fb4f839SGregory Neil Shapiro xstr = p;
55942fb4f839SGregory Neil Shapiro # endif
55952fb4f839SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s%s", l, xstr, buf);
5596c2aa98e2SPeter Wemm
559706f25ae9SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */
5598c2aa98e2SPeter Wemm
5599c2aa98e2SPeter Wemm l = SYSLOG_BUFSIZE - 85;
560040266059SGregory Neil Shapiro if (l < 0)
560140266059SGregory Neil Shapiro l = 0;
560206f25ae9SGregory Neil Shapiro p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to;
560340266059SGregory Neil Shapiro while (strlen(p) >= l)
5604c2aa98e2SPeter Wemm {
560506f25ae9SGregory Neil Shapiro register char *q;
5606c2aa98e2SPeter Wemm
560706f25ae9SGregory Neil Shapiro for (q = p + l; q > p; q--)
560806f25ae9SGregory Neil Shapiro {
560906f25ae9SGregory Neil Shapiro if (*q == ',')
561006f25ae9SGregory Neil Shapiro break;
561106f25ae9SGregory Neil Shapiro }
561206f25ae9SGregory Neil Shapiro if (p == q)
561306f25ae9SGregory Neil Shapiro break;
561406f25ae9SGregory Neil Shapiro
561540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]",
561642e5d165SGregory Neil Shapiro (int) (++q - p), p);
5617c2aa98e2SPeter Wemm p = q;
5618c2aa98e2SPeter Wemm }
561906f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s", l, p);
5620c2aa98e2SPeter Wemm
5621c2aa98e2SPeter Wemm if (ctladdr != NULL)
5622c2aa98e2SPeter Wemm {
5623c2aa98e2SPeter Wemm bp = buf;
562440266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "ctladdr=",
5625c2aa98e2SPeter Wemm shortenstring(ctladdr->q_paddr, 83));
5626c2aa98e2SPeter Wemm bp += strlen(bp);
5627c2aa98e2SPeter Wemm if (bitset(QGOODUID, ctladdr->q_flags))
5628c2aa98e2SPeter Wemm {
562940266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
5630c2aa98e2SPeter Wemm ctladdr->q_uid, ctladdr->q_gid);
5631c2aa98e2SPeter Wemm bp += strlen(bp);
5632c2aa98e2SPeter Wemm }
5633c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%s", buf);
5634c2aa98e2SPeter Wemm }
5635c2aa98e2SPeter Wemm bp = buf;
563640266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "delay=",
563740266059SGregory Neil Shapiro pintvl(now - e->e_ctime, true));
5638c2aa98e2SPeter Wemm bp += strlen(bp);
5639c2aa98e2SPeter Wemm if (xstart != (time_t) 0)
5640c2aa98e2SPeter Wemm {
564140266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=",
564240266059SGregory Neil Shapiro pintvl(now - xstart, true));
5643c2aa98e2SPeter Wemm bp += strlen(bp);
5644c2aa98e2SPeter Wemm }
5645c2aa98e2SPeter Wemm
5646c2aa98e2SPeter Wemm if (m != NULL)
5647c2aa98e2SPeter Wemm {
564840266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=",
564940266059SGregory Neil Shapiro m->m_name);
5650c2aa98e2SPeter Wemm bp += strlen(bp);
5651c2aa98e2SPeter Wemm }
5652c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf);
5653c2aa98e2SPeter Wemm
5654c2aa98e2SPeter Wemm buf[0] = '\0';
5655c2aa98e2SPeter Wemm bp = buf;
5656c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_host != NULL)
5657c2aa98e2SPeter Wemm {
5658c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr;
5659c2aa98e2SPeter Wemm
566040266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s",
566140266059SGregory Neil Shapiro mci->mci_host);
5662c2aa98e2SPeter Wemm bp += strlen(bp);
5663c2aa98e2SPeter Wemm
5664c2aa98e2SPeter Wemm if (CurHostAddr.sa.sa_family != 0)
566540266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
566640266059SGregory Neil Shapiro " [%.100s]",
5667c2aa98e2SPeter Wemm anynet_ntoa(&CurHostAddr));
5668c2aa98e2SPeter Wemm }
566940266059SGregory Neil Shapiro else if (strcmp(status, "quarantined") == 0)
567040266059SGregory Neil Shapiro {
567140266059SGregory Neil Shapiro if (e->e_quarmsg != NULL)
567240266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
567340266059SGregory Neil Shapiro ", quarantine=%.100s",
567440266059SGregory Neil Shapiro e->e_quarmsg);
567540266059SGregory Neil Shapiro }
567606f25ae9SGregory Neil Shapiro else if (strcmp(status, "queued") != 0)
5677c2aa98e2SPeter Wemm {
5678c2aa98e2SPeter Wemm p = macvalue('h', e);
5679c2aa98e2SPeter Wemm if (p != NULL && p[0] != '\0')
5680*d39bd2c1SGregory Neil Shapiro {
5681*d39bd2c1SGregory Neil Shapiro GET_HOST_VALUE;
5682d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "relay=%.100s", p);
5683c2aa98e2SPeter Wemm }
5684*d39bd2c1SGregory Neil Shapiro }
5685c2aa98e2SPeter Wemm if (buf[0] != '\0')
5686c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf);
5687c2aa98e2SPeter Wemm
568806f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(status, 63));
568906f25ae9SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */
5690c2aa98e2SPeter Wemm }
569140266059SGregory Neil Shapiro /*
5692c2aa98e2SPeter Wemm ** PUTFROMLINE -- output a UNIX-style from line (or whatever)
5693c2aa98e2SPeter Wemm **
5694c2aa98e2SPeter Wemm ** This can be made an arbitrary message separator by changing $l
5695c2aa98e2SPeter Wemm **
5696c2aa98e2SPeter Wemm ** One of the ugliest hacks seen by human eyes is contained herein:
5697c2aa98e2SPeter Wemm ** UUCP wants those stupid "remote from <host>" lines. Why oh why
5698c2aa98e2SPeter Wemm ** does a well-meaning programmer such as myself have to deal with
5699c2aa98e2SPeter Wemm ** this kind of antique garbage????
5700c2aa98e2SPeter Wemm **
5701c2aa98e2SPeter Wemm ** Parameters:
5702c2aa98e2SPeter Wemm ** mci -- the connection information.
5703c2aa98e2SPeter Wemm ** e -- the envelope.
5704c2aa98e2SPeter Wemm **
5705c2aa98e2SPeter Wemm ** Returns:
57064e4196cbSGregory Neil Shapiro ** true iff line was written successfully
5707c2aa98e2SPeter Wemm **
5708c2aa98e2SPeter Wemm ** Side Effects:
5709c2aa98e2SPeter Wemm ** outputs some text to fp.
5710c2aa98e2SPeter Wemm */
5711c2aa98e2SPeter Wemm
57124e4196cbSGregory Neil Shapiro bool
putfromline(mci,e)5713c2aa98e2SPeter Wemm putfromline(mci, e)
5714c2aa98e2SPeter Wemm register MCI *mci;
5715c2aa98e2SPeter Wemm ENVELOPE *e;
5716c2aa98e2SPeter Wemm {
5717c2aa98e2SPeter Wemm char *template = UnixFromLine;
5718c2aa98e2SPeter Wemm char buf[MAXLINE];
5719c2aa98e2SPeter Wemm char xbuf[MAXLINE];
5720c2aa98e2SPeter Wemm
5721c2aa98e2SPeter Wemm if (bitnset(M_NHDR, mci->mci_mailer->m_flags))
57224e4196cbSGregory Neil Shapiro return true;
5723c2aa98e2SPeter Wemm
5724c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER;
5725c2aa98e2SPeter Wemm
5726c2aa98e2SPeter Wemm if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags))
5727c2aa98e2SPeter Wemm {
5728c2aa98e2SPeter Wemm char *bang;
5729c2aa98e2SPeter Wemm
5730d0cef73dSGregory Neil Shapiro expand("\201g", buf, sizeof(buf), e);
5731c2aa98e2SPeter Wemm bang = strchr(buf, '!');
5732c2aa98e2SPeter Wemm if (bang == NULL)
5733c2aa98e2SPeter Wemm {
5734c2aa98e2SPeter Wemm char *at;
57352fb4f839SGregory Neil Shapiro char hname[MAXNAME]; /* EAI:ok */
5736c2aa98e2SPeter Wemm
5737c2aa98e2SPeter Wemm /*
5738c2aa98e2SPeter Wemm ** If we can construct a UUCP path, do so
5739c2aa98e2SPeter Wemm */
5740c2aa98e2SPeter Wemm
5741c2aa98e2SPeter Wemm at = strrchr(buf, '@');
5742c2aa98e2SPeter Wemm if (at == NULL)
5743c2aa98e2SPeter Wemm {
5744d0cef73dSGregory Neil Shapiro expand("\201k", hname, sizeof(hname), e);
5745c2aa98e2SPeter Wemm at = hname;
5746c2aa98e2SPeter Wemm }
5747c2aa98e2SPeter Wemm else
5748c2aa98e2SPeter Wemm *at++ = '\0';
5749d0cef73dSGregory Neil Shapiro (void) sm_snprintf(xbuf, sizeof(xbuf),
5750c2aa98e2SPeter Wemm "From %.800s \201d remote from %.100s\n",
5751c2aa98e2SPeter Wemm buf, at);
5752c2aa98e2SPeter Wemm }
5753c2aa98e2SPeter Wemm else
5754c2aa98e2SPeter Wemm {
5755c2aa98e2SPeter Wemm *bang++ = '\0';
5756d0cef73dSGregory Neil Shapiro (void) sm_snprintf(xbuf, sizeof(xbuf),
5757c2aa98e2SPeter Wemm "From %.800s \201d remote from %.100s\n",
5758c2aa98e2SPeter Wemm bang, buf);
5759c2aa98e2SPeter Wemm template = xbuf;
5760c2aa98e2SPeter Wemm }
5761c2aa98e2SPeter Wemm }
5762d0cef73dSGregory Neil Shapiro expand(template, buf, sizeof(buf), e);
57634e4196cbSGregory Neil Shapiro return putxline(buf, strlen(buf), mci, PXLF_HEADER);
5764c2aa98e2SPeter Wemm }
57654e4196cbSGregory Neil Shapiro
576640266059SGregory Neil Shapiro /*
5767c2aa98e2SPeter Wemm ** PUTBODY -- put the body of a message.
5768c2aa98e2SPeter Wemm **
5769c2aa98e2SPeter Wemm ** Parameters:
5770c2aa98e2SPeter Wemm ** mci -- the connection information.
5771c2aa98e2SPeter Wemm ** e -- the envelope to put out.
5772c2aa98e2SPeter Wemm ** separator -- if non-NULL, a message separator that must
5773c2aa98e2SPeter Wemm ** not be permitted in the resulting message.
5774c2aa98e2SPeter Wemm **
5775c2aa98e2SPeter Wemm ** Returns:
57764e4196cbSGregory Neil Shapiro ** true iff message was written successfully
5777c2aa98e2SPeter Wemm **
5778c2aa98e2SPeter Wemm ** Side Effects:
5779c2aa98e2SPeter Wemm ** The message is written onto fp.
5780c2aa98e2SPeter Wemm */
5781c2aa98e2SPeter Wemm
5782c2aa98e2SPeter Wemm /* values for output state variable */
57834e4196cbSGregory Neil Shapiro #define OSTATE_HEAD 0 /* at beginning of line */
57844e4196cbSGregory Neil Shapiro #define OSTATE_CR 1 /* read a carriage return */
57854e4196cbSGregory Neil Shapiro #define OSTATE_INLINE 2 /* putting rest of line */
5786c2aa98e2SPeter Wemm
57874e4196cbSGregory Neil Shapiro bool
putbody(mci,e,separator)5788c2aa98e2SPeter Wemm putbody(mci, e, separator)
5789c2aa98e2SPeter Wemm register MCI *mci;
5790c2aa98e2SPeter Wemm register ENVELOPE *e;
5791c2aa98e2SPeter Wemm char *separator;
5792c2aa98e2SPeter Wemm {
579340266059SGregory Neil Shapiro bool dead = false;
57944e4196cbSGregory Neil Shapiro bool ioerr = false;
57954e4196cbSGregory Neil Shapiro int save_errno;
5796c2aa98e2SPeter Wemm char buf[MAXLINE];
579740266059SGregory Neil Shapiro #if MIME8TO7
5798065a643dSPeter Wemm char *boundaries[MAXMIMENESTING + 1];
57995b0945b5SGregory Neil Shapiro #endif
5800c2aa98e2SPeter Wemm
5801c2aa98e2SPeter Wemm /*
5802c2aa98e2SPeter Wemm ** Output the body of the message
5803c2aa98e2SPeter Wemm */
5804c2aa98e2SPeter Wemm
5805c2aa98e2SPeter Wemm if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
5806c2aa98e2SPeter Wemm {
580740266059SGregory Neil Shapiro char *df = queuename(e, DATAFL_LETTER);
5808c2aa98e2SPeter Wemm
580940266059SGregory Neil Shapiro e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df,
5810a7ec597cSGregory Neil Shapiro SM_IO_RDONLY_B, NULL);
5811c2aa98e2SPeter Wemm if (e->e_dfp == NULL)
581206f25ae9SGregory Neil Shapiro {
581306f25ae9SGregory Neil Shapiro char *msg = "!putbody: Cannot open %s for %s from %s";
581406f25ae9SGregory Neil Shapiro
581506f25ae9SGregory Neil Shapiro if (errno == ENOENT)
581606f25ae9SGregory Neil Shapiro msg++;
581706f25ae9SGregory Neil Shapiro syserr(msg, df, e->e_to, e->e_from.q_paddr);
581806f25ae9SGregory Neil Shapiro }
581940266059SGregory Neil Shapiro
5820c2aa98e2SPeter Wemm }
5821c2aa98e2SPeter Wemm if (e->e_dfp == NULL)
5822c2aa98e2SPeter Wemm {
5823c2aa98e2SPeter Wemm if (bitset(MCIF_INHEADER, mci->mci_flags))
5824c2aa98e2SPeter Wemm {
58254e4196cbSGregory Neil Shapiro if (!putline("", mci))
58264e4196cbSGregory Neil Shapiro goto writeerr;
5827c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_INHEADER;
5828c2aa98e2SPeter Wemm }
58294e4196cbSGregory Neil Shapiro if (!putline("<<< No Message Collected >>>", mci))
58304e4196cbSGregory Neil Shapiro goto writeerr;
5831c2aa98e2SPeter Wemm goto endofmessage;
5832c2aa98e2SPeter Wemm }
583306f25ae9SGregory Neil Shapiro
5834c2aa98e2SPeter Wemm if (e->e_dfino == (ino_t) 0)
5835c2aa98e2SPeter Wemm {
5836c2aa98e2SPeter Wemm struct stat stbuf;
5837c2aa98e2SPeter Wemm
583840266059SGregory Neil Shapiro if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &stbuf)
583940266059SGregory Neil Shapiro < 0)
5840c2aa98e2SPeter Wemm e->e_dfino = -1;
5841c2aa98e2SPeter Wemm else
5842c2aa98e2SPeter Wemm {
5843c2aa98e2SPeter Wemm e->e_dfdev = stbuf.st_dev;
5844c2aa98e2SPeter Wemm e->e_dfino = stbuf.st_ino;
5845c2aa98e2SPeter Wemm }
5846c2aa98e2SPeter Wemm }
584706f25ae9SGregory Neil Shapiro
584840266059SGregory Neil Shapiro /* paranoia: the data file should always be in a rewound state */
584906f25ae9SGregory Neil Shapiro (void) bfrewind(e->e_dfp);
5850c2aa98e2SPeter Wemm
58514e4196cbSGregory Neil Shapiro /* simulate an I/O timeout when used as source */
58524e4196cbSGregory Neil Shapiro if (tTd(84, 101))
58534e4196cbSGregory Neil Shapiro sleep(319);
58544e4196cbSGregory Neil Shapiro
5855c2aa98e2SPeter Wemm #if MIME8TO7
5856c2aa98e2SPeter Wemm if (bitset(MCIF_CVT8TO7, mci->mci_flags))
5857c2aa98e2SPeter Wemm {
5858c2aa98e2SPeter Wemm /*
5859c2aa98e2SPeter Wemm ** Do 8 to 7 bit MIME conversion.
5860c2aa98e2SPeter Wemm */
5861c2aa98e2SPeter Wemm
5862c2aa98e2SPeter Wemm /* make sure it looks like a MIME message */
58634e4196cbSGregory Neil Shapiro if (hvalue("MIME-Version", e->e_header) == NULL &&
58644e4196cbSGregory Neil Shapiro !putline("MIME-Version: 1.0", mci))
58654e4196cbSGregory Neil Shapiro goto writeerr;
5866c2aa98e2SPeter Wemm
5867c2aa98e2SPeter Wemm if (hvalue("Content-Type", e->e_header) == NULL)
5868c2aa98e2SPeter Wemm {
5869d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf),
5870c2aa98e2SPeter Wemm "Content-Type: text/plain; charset=%s",
5871c2aa98e2SPeter Wemm defcharset(e));
58724e4196cbSGregory Neil Shapiro if (!putline(buf, mci))
58734e4196cbSGregory Neil Shapiro goto writeerr;
5874c2aa98e2SPeter Wemm }
5875c2aa98e2SPeter Wemm
5876c2aa98e2SPeter Wemm /* now do the hard work */
5877c2aa98e2SPeter Wemm boundaries[0] = NULL;
5878c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER;
5879af9557fdSGregory Neil Shapiro if (mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER, 0) ==
58804e4196cbSGregory Neil Shapiro SM_IO_EOF)
58814e4196cbSGregory Neil Shapiro goto writeerr;
5882c2aa98e2SPeter Wemm }
5883c2aa98e2SPeter Wemm # if MIME7TO8
5884c2aa98e2SPeter Wemm else if (bitset(MCIF_CVT7TO8, mci->mci_flags))
5885c2aa98e2SPeter Wemm {
58864e4196cbSGregory Neil Shapiro if (!mime7to8(mci, e->e_header, e))
58874e4196cbSGregory Neil Shapiro goto writeerr;
5888c2aa98e2SPeter Wemm }
588906f25ae9SGregory Neil Shapiro # endif /* MIME7TO8 */
5890065a643dSPeter Wemm else if (MaxMimeHeaderLength > 0 || MaxMimeFieldLength > 0)
5891065a643dSPeter Wemm {
589206f25ae9SGregory Neil Shapiro bool oldsuprerrs = SuprErrs;
589306f25ae9SGregory Neil Shapiro
5894065a643dSPeter Wemm /* Use mime8to7 to check multipart for MIME header overflows */
5895065a643dSPeter Wemm boundaries[0] = NULL;
5896065a643dSPeter Wemm mci->mci_flags |= MCIF_INHEADER;
589706f25ae9SGregory Neil Shapiro
589806f25ae9SGregory Neil Shapiro /*
589906f25ae9SGregory Neil Shapiro ** If EF_DONT_MIME is set, we have a broken MIME message
590006f25ae9SGregory Neil Shapiro ** and don't want to generate a new bounce message whose
590106f25ae9SGregory Neil Shapiro ** body propagates the broken MIME. We can't just not call
590206f25ae9SGregory Neil Shapiro ** mime8to7() as is done above since we need the security
590306f25ae9SGregory Neil Shapiro ** checks. The best we can do is suppress the errors.
590406f25ae9SGregory Neil Shapiro */
590506f25ae9SGregory Neil Shapiro
590606f25ae9SGregory Neil Shapiro if (bitset(EF_DONT_MIME, e->e_flags))
590740266059SGregory Neil Shapiro SuprErrs = true;
590806f25ae9SGregory Neil Shapiro
59094e4196cbSGregory Neil Shapiro if (mime8to7(mci, e->e_header, e, boundaries,
5910af9557fdSGregory Neil Shapiro M87F_OUTER|M87F_NO8TO7, 0) == SM_IO_EOF)
59114e4196cbSGregory Neil Shapiro goto writeerr;
591206f25ae9SGregory Neil Shapiro
591306f25ae9SGregory Neil Shapiro /* restore SuprErrs */
591406f25ae9SGregory Neil Shapiro SuprErrs = oldsuprerrs;
5915065a643dSPeter Wemm }
5916c2aa98e2SPeter Wemm else
591706f25ae9SGregory Neil Shapiro #endif /* MIME8TO7 */
5918c2aa98e2SPeter Wemm {
5919c2aa98e2SPeter Wemm int ostate;
5920c2aa98e2SPeter Wemm register char *bp;
5921c2aa98e2SPeter Wemm register char *pbp;
5922c2aa98e2SPeter Wemm register int c;
5923c2aa98e2SPeter Wemm register char *xp;
5924c2aa98e2SPeter Wemm int padc;
5925c2aa98e2SPeter Wemm char *buflim;
5926c2aa98e2SPeter Wemm int pos = 0;
592706f25ae9SGregory Neil Shapiro char peekbuf[12];
5928c2aa98e2SPeter Wemm
5929c2aa98e2SPeter Wemm if (bitset(MCIF_INHEADER, mci->mci_flags))
5930c2aa98e2SPeter Wemm {
59314e4196cbSGregory Neil Shapiro if (!putline("", mci))
59324e4196cbSGregory Neil Shapiro goto writeerr;
5933c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_INHEADER;
5934c2aa98e2SPeter Wemm }
5935c2aa98e2SPeter Wemm
5936c2aa98e2SPeter Wemm /* determine end of buffer; allow for short mailer lines */
5937d0cef73dSGregory Neil Shapiro buflim = &buf[sizeof(buf) - 1];
5938c2aa98e2SPeter Wemm if (mci->mci_mailer->m_linelimit > 0 &&
5939d0cef73dSGregory Neil Shapiro mci->mci_mailer->m_linelimit < sizeof(buf) - 1)
5940c2aa98e2SPeter Wemm buflim = &buf[mci->mci_mailer->m_linelimit - 1];
5941c2aa98e2SPeter Wemm
5942c2aa98e2SPeter Wemm /* copy temp file to output with mapping */
59434e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD;
5944c2aa98e2SPeter Wemm bp = buf;
5945c2aa98e2SPeter Wemm pbp = peekbuf;
594640266059SGregory Neil Shapiro while (!sm_io_error(mci->mci_out) && !dead)
5947c2aa98e2SPeter Wemm {
5948c2aa98e2SPeter Wemm if (pbp > peekbuf)
5949c2aa98e2SPeter Wemm c = *--pbp;
595040266059SGregory Neil Shapiro else if ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT))
595140266059SGregory Neil Shapiro == SM_IO_EOF)
5952c2aa98e2SPeter Wemm break;
5953c2aa98e2SPeter Wemm if (bitset(MCIF_7BIT, mci->mci_flags))
5954c2aa98e2SPeter Wemm c &= 0x7f;
5955c2aa98e2SPeter Wemm switch (ostate)
5956c2aa98e2SPeter Wemm {
59574e4196cbSGregory Neil Shapiro case OSTATE_HEAD:
5958c2aa98e2SPeter Wemm if (c == '\0' &&
595940266059SGregory Neil Shapiro bitnset(M_NONULLS,
596040266059SGregory Neil Shapiro mci->mci_mailer->m_flags))
5961c2aa98e2SPeter Wemm break;
5962c2aa98e2SPeter Wemm if (c != '\r' && c != '\n' && bp < buflim)
5963c2aa98e2SPeter Wemm {
5964c2aa98e2SPeter Wemm *bp++ = c;
5965c2aa98e2SPeter Wemm break;
5966c2aa98e2SPeter Wemm }
5967c2aa98e2SPeter Wemm
5968c2aa98e2SPeter Wemm /* check beginning of line for special cases */
5969c2aa98e2SPeter Wemm *bp = '\0';
5970c2aa98e2SPeter Wemm pos = 0;
597140266059SGregory Neil Shapiro padc = SM_IO_EOF;
5972c2aa98e2SPeter Wemm if (buf[0] == 'F' &&
597340266059SGregory Neil Shapiro bitnset(M_ESCFROM, mci->mci_mailer->m_flags)
597440266059SGregory Neil Shapiro && strncmp(buf, "From ", 5) == 0)
5975c2aa98e2SPeter Wemm {
5976c2aa98e2SPeter Wemm padc = '>';
5977c2aa98e2SPeter Wemm }
5978c2aa98e2SPeter Wemm if (buf[0] == '-' && buf[1] == '-' &&
5979c2aa98e2SPeter Wemm separator != NULL)
5980c2aa98e2SPeter Wemm {
5981c2aa98e2SPeter Wemm /* possible separator */
5982c2aa98e2SPeter Wemm int sl = strlen(separator);
5983c2aa98e2SPeter Wemm
598440266059SGregory Neil Shapiro if (strncmp(&buf[2], separator, sl)
598540266059SGregory Neil Shapiro == 0)
5986c2aa98e2SPeter Wemm padc = ' ';
5987c2aa98e2SPeter Wemm }
5988c2aa98e2SPeter Wemm if (buf[0] == '.' &&
5989c2aa98e2SPeter Wemm bitnset(M_XDOT, mci->mci_mailer->m_flags))
5990c2aa98e2SPeter Wemm {
5991c2aa98e2SPeter Wemm padc = '.';
5992c2aa98e2SPeter Wemm }
5993c2aa98e2SPeter Wemm
5994c2aa98e2SPeter Wemm /* now copy out saved line */
5995c2aa98e2SPeter Wemm if (TrafficLogFile != NULL)
5996c2aa98e2SPeter Wemm {
599740266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile,
599840266059SGregory Neil Shapiro SM_TIME_DEFAULT,
599940266059SGregory Neil Shapiro "%05d >>> ",
600040266059SGregory Neil Shapiro (int) CurrentPid);
600140266059SGregory Neil Shapiro if (padc != SM_IO_EOF)
600240266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile,
600340266059SGregory Neil Shapiro SM_TIME_DEFAULT,
600440266059SGregory Neil Shapiro padc);
6005c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++)
600640266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile,
600740266059SGregory Neil Shapiro SM_TIME_DEFAULT,
600840266059SGregory Neil Shapiro (unsigned char) *xp);
6009c2aa98e2SPeter Wemm if (c == '\n')
601040266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile,
601140266059SGregory Neil Shapiro SM_TIME_DEFAULT,
601240266059SGregory Neil Shapiro mci->mci_mailer->m_eol);
6013c2aa98e2SPeter Wemm }
601440266059SGregory Neil Shapiro if (padc != SM_IO_EOF)
6015c2aa98e2SPeter Wemm {
601640266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out,
601740266059SGregory Neil Shapiro SM_TIME_DEFAULT, padc)
601840266059SGregory Neil Shapiro == SM_IO_EOF)
601906f25ae9SGregory Neil Shapiro {
602040266059SGregory Neil Shapiro dead = true;
602106f25ae9SGregory Neil Shapiro continue;
602206f25ae9SGregory Neil Shapiro }
6023c2aa98e2SPeter Wemm pos++;
6024c2aa98e2SPeter Wemm }
6025c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++)
6026c2aa98e2SPeter Wemm {
602740266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out,
602840266059SGregory Neil Shapiro SM_TIME_DEFAULT,
602940266059SGregory Neil Shapiro (unsigned char) *xp)
603040266059SGregory Neil Shapiro == SM_IO_EOF)
603106f25ae9SGregory Neil Shapiro {
603240266059SGregory Neil Shapiro dead = true;
603306f25ae9SGregory Neil Shapiro break;
6034c2aa98e2SPeter Wemm }
6035193538b7SGregory Neil Shapiro }
603606f25ae9SGregory Neil Shapiro if (dead)
603706f25ae9SGregory Neil Shapiro continue;
6038c2aa98e2SPeter Wemm if (c == '\n')
6039c2aa98e2SPeter Wemm {
604040266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out,
604140266059SGregory Neil Shapiro SM_TIME_DEFAULT,
604240266059SGregory Neil Shapiro mci->mci_mailer->m_eol)
604340266059SGregory Neil Shapiro == SM_IO_EOF)
604406f25ae9SGregory Neil Shapiro break;
6045c2aa98e2SPeter Wemm pos = 0;
6046c2aa98e2SPeter Wemm }
6047c2aa98e2SPeter Wemm else
6048c2aa98e2SPeter Wemm {
6049c2aa98e2SPeter Wemm pos += bp - buf;
6050c2aa98e2SPeter Wemm if (c != '\r')
60515ef517c0SGregory Neil Shapiro {
60525ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf +
60535ef517c0SGregory Neil Shapiro sizeof(peekbuf));
6054c2aa98e2SPeter Wemm *pbp++ = c;
6055c2aa98e2SPeter Wemm }
60565ef517c0SGregory Neil Shapiro }
605706f25ae9SGregory Neil Shapiro
6058c2aa98e2SPeter Wemm bp = buf;
6059c2aa98e2SPeter Wemm
6060c2aa98e2SPeter Wemm /* determine next state */
6061c2aa98e2SPeter Wemm if (c == '\n')
60624e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD;
6063c2aa98e2SPeter Wemm else if (c == '\r')
60644e4196cbSGregory Neil Shapiro ostate = OSTATE_CR;
6065c2aa98e2SPeter Wemm else
60664e4196cbSGregory Neil Shapiro ostate = OSTATE_INLINE;
6067c2aa98e2SPeter Wemm continue;
6068c2aa98e2SPeter Wemm
60694e4196cbSGregory Neil Shapiro case OSTATE_CR:
6070c2aa98e2SPeter Wemm if (c == '\n')
6071c2aa98e2SPeter Wemm {
6072c2aa98e2SPeter Wemm /* got CRLF */
607340266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out,
607440266059SGregory Neil Shapiro SM_TIME_DEFAULT,
607540266059SGregory Neil Shapiro mci->mci_mailer->m_eol)
607640266059SGregory Neil Shapiro == SM_IO_EOF)
607706f25ae9SGregory Neil Shapiro continue;
607806f25ae9SGregory Neil Shapiro
6079c2aa98e2SPeter Wemm if (TrafficLogFile != NULL)
6080c2aa98e2SPeter Wemm {
608140266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile,
608240266059SGregory Neil Shapiro SM_TIME_DEFAULT,
608340266059SGregory Neil Shapiro mci->mci_mailer->m_eol);
6084c2aa98e2SPeter Wemm }
6085d0cef73dSGregory Neil Shapiro pos = 0;
60864e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD;
6087c2aa98e2SPeter Wemm continue;
6088c2aa98e2SPeter Wemm }
6089c2aa98e2SPeter Wemm
6090c2aa98e2SPeter Wemm /* had a naked carriage return */
60915ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + sizeof(peekbuf));
6092c2aa98e2SPeter Wemm *pbp++ = c;
6093c2aa98e2SPeter Wemm c = '\r';
60944e4196cbSGregory Neil Shapiro ostate = OSTATE_INLINE;
6095c2aa98e2SPeter Wemm goto putch;
6096c2aa98e2SPeter Wemm
60974e4196cbSGregory Neil Shapiro case OSTATE_INLINE:
6098c2aa98e2SPeter Wemm if (c == '\r')
6099c2aa98e2SPeter Wemm {
61004e4196cbSGregory Neil Shapiro ostate = OSTATE_CR;
6101c2aa98e2SPeter Wemm continue;
6102c2aa98e2SPeter Wemm }
6103c2aa98e2SPeter Wemm if (c == '\0' &&
610440266059SGregory Neil Shapiro bitnset(M_NONULLS,
610540266059SGregory Neil Shapiro mci->mci_mailer->m_flags))
6106c2aa98e2SPeter Wemm break;
6107c2aa98e2SPeter Wemm putch:
6108c2aa98e2SPeter Wemm if (mci->mci_mailer->m_linelimit > 0 &&
610906f25ae9SGregory Neil Shapiro pos >= mci->mci_mailer->m_linelimit - 1 &&
6110c2aa98e2SPeter Wemm c != '\n')
6111c2aa98e2SPeter Wemm {
611206f25ae9SGregory Neil Shapiro int d;
611306f25ae9SGregory Neil Shapiro
611406f25ae9SGregory Neil Shapiro /* check next character for EOL */
611506f25ae9SGregory Neil Shapiro if (pbp > peekbuf)
611606f25ae9SGregory Neil Shapiro d = *(pbp - 1);
611740266059SGregory Neil Shapiro else if ((d = sm_io_getc(e->e_dfp,
611840266059SGregory Neil Shapiro SM_TIME_DEFAULT))
611940266059SGregory Neil Shapiro != SM_IO_EOF)
61205ef517c0SGregory Neil Shapiro {
61215ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf +
61225ef517c0SGregory Neil Shapiro sizeof(peekbuf));
612306f25ae9SGregory Neil Shapiro *pbp++ = d;
61245ef517c0SGregory Neil Shapiro }
612506f25ae9SGregory Neil Shapiro
612640266059SGregory Neil Shapiro if (d == '\n' || d == SM_IO_EOF)
612706f25ae9SGregory Neil Shapiro {
612806f25ae9SGregory Neil Shapiro if (TrafficLogFile != NULL)
612940266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile,
613040266059SGregory Neil Shapiro SM_TIME_DEFAULT,
613140266059SGregory Neil Shapiro (unsigned char) c);
613240266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out,
613340266059SGregory Neil Shapiro SM_TIME_DEFAULT,
613440266059SGregory Neil Shapiro (unsigned char) c)
613540266059SGregory Neil Shapiro == SM_IO_EOF)
613606f25ae9SGregory Neil Shapiro {
613740266059SGregory Neil Shapiro dead = true;
613806f25ae9SGregory Neil Shapiro continue;
613906f25ae9SGregory Neil Shapiro }
614006f25ae9SGregory Neil Shapiro pos++;
614106f25ae9SGregory Neil Shapiro continue;
614206f25ae9SGregory Neil Shapiro }
614306f25ae9SGregory Neil Shapiro
614440266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out,
614540266059SGregory Neil Shapiro SM_TIME_DEFAULT, '!')
614640266059SGregory Neil Shapiro == SM_IO_EOF ||
614740266059SGregory Neil Shapiro sm_io_fputs(mci->mci_out,
614840266059SGregory Neil Shapiro SM_TIME_DEFAULT,
614940266059SGregory Neil Shapiro mci->mci_mailer->m_eol)
615040266059SGregory Neil Shapiro == SM_IO_EOF)
615106f25ae9SGregory Neil Shapiro {
615240266059SGregory Neil Shapiro dead = true;
615306f25ae9SGregory Neil Shapiro continue;
615406f25ae9SGregory Neil Shapiro }
615506f25ae9SGregory Neil Shapiro
6156c2aa98e2SPeter Wemm if (TrafficLogFile != NULL)
6157c2aa98e2SPeter Wemm {
615840266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile,
615940266059SGregory Neil Shapiro SM_TIME_DEFAULT,
616040266059SGregory Neil Shapiro "!%s",
6161c2aa98e2SPeter Wemm mci->mci_mailer->m_eol);
6162c2aa98e2SPeter Wemm }
61634e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD;
61645ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf +
61655ef517c0SGregory Neil Shapiro sizeof(peekbuf));
6166c2aa98e2SPeter Wemm *pbp++ = c;
6167c2aa98e2SPeter Wemm continue;
6168c2aa98e2SPeter Wemm }
6169c2aa98e2SPeter Wemm if (c == '\n')
6170c2aa98e2SPeter Wemm {
6171c2aa98e2SPeter Wemm if (TrafficLogFile != NULL)
617240266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile,
617340266059SGregory Neil Shapiro SM_TIME_DEFAULT,
617440266059SGregory Neil Shapiro mci->mci_mailer->m_eol);
617540266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out,
617640266059SGregory Neil Shapiro SM_TIME_DEFAULT,
617740266059SGregory Neil Shapiro mci->mci_mailer->m_eol)
617840266059SGregory Neil Shapiro == SM_IO_EOF)
617906f25ae9SGregory Neil Shapiro continue;
6180c2aa98e2SPeter Wemm pos = 0;
61814e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD;
6182c2aa98e2SPeter Wemm }
6183c2aa98e2SPeter Wemm else
6184c2aa98e2SPeter Wemm {
6185c2aa98e2SPeter Wemm if (TrafficLogFile != NULL)
618640266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile,
618740266059SGregory Neil Shapiro SM_TIME_DEFAULT,
618840266059SGregory Neil Shapiro (unsigned char) c);
618940266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out,
619040266059SGregory Neil Shapiro SM_TIME_DEFAULT,
619140266059SGregory Neil Shapiro (unsigned char) c)
619240266059SGregory Neil Shapiro == SM_IO_EOF)
619306f25ae9SGregory Neil Shapiro {
619440266059SGregory Neil Shapiro dead = true;
619506f25ae9SGregory Neil Shapiro continue;
619606f25ae9SGregory Neil Shapiro }
6197c2aa98e2SPeter Wemm pos++;
61984e4196cbSGregory Neil Shapiro ostate = OSTATE_INLINE;
6199c2aa98e2SPeter Wemm }
6200c2aa98e2SPeter Wemm break;
6201c2aa98e2SPeter Wemm }
6202c2aa98e2SPeter Wemm }
6203c2aa98e2SPeter Wemm
6204c2aa98e2SPeter Wemm /* make sure we are at the beginning of a line */
6205c2aa98e2SPeter Wemm if (bp > buf)
6206c2aa98e2SPeter Wemm {
6207c2aa98e2SPeter Wemm if (TrafficLogFile != NULL)
6208c2aa98e2SPeter Wemm {
6209c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++)
621040266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile,
621140266059SGregory Neil Shapiro SM_TIME_DEFAULT,
621240266059SGregory Neil Shapiro (unsigned char) *xp);
6213c2aa98e2SPeter Wemm }
6214c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++)
6215c2aa98e2SPeter Wemm {
621640266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
621740266059SGregory Neil Shapiro (unsigned char) *xp)
621840266059SGregory Neil Shapiro == SM_IO_EOF)
621906f25ae9SGregory Neil Shapiro {
622040266059SGregory Neil Shapiro dead = true;
622106f25ae9SGregory Neil Shapiro break;
622206f25ae9SGregory Neil Shapiro }
6223193538b7SGregory Neil Shapiro }
6224c2aa98e2SPeter Wemm pos += bp - buf;
6225c2aa98e2SPeter Wemm }
622606f25ae9SGregory Neil Shapiro if (!dead && pos > 0)
6227c2aa98e2SPeter Wemm {
6228c2aa98e2SPeter Wemm if (TrafficLogFile != NULL)
622940266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile,
623040266059SGregory Neil Shapiro SM_TIME_DEFAULT,
623140266059SGregory Neil Shapiro mci->mci_mailer->m_eol);
62324e4196cbSGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
62334e4196cbSGregory Neil Shapiro mci->mci_mailer->m_eol) == SM_IO_EOF)
62344e4196cbSGregory Neil Shapiro goto writeerr;
6235c2aa98e2SPeter Wemm }
6236c2aa98e2SPeter Wemm }
6237c2aa98e2SPeter Wemm
623840266059SGregory Neil Shapiro if (sm_io_error(e->e_dfp))
6239c2aa98e2SPeter Wemm {
624040266059SGregory Neil Shapiro syserr("putbody: %s/%cf%s: read error",
624140266059SGregory Neil Shapiro qid_printqueue(e->e_dfqgrp, e->e_dfqdir),
624240266059SGregory Neil Shapiro DATAFL_LETTER, e->e_id);
6243c2aa98e2SPeter Wemm ExitStat = EX_IOERR;
62444e4196cbSGregory Neil Shapiro ioerr = true;
6245c2aa98e2SPeter Wemm }
6246c2aa98e2SPeter Wemm
6247c2aa98e2SPeter Wemm endofmessage:
624806f25ae9SGregory Neil Shapiro /*
624906f25ae9SGregory Neil Shapiro ** Since mailfile() uses e_dfp in a child process,
625006f25ae9SGregory Neil Shapiro ** the file offset in the stdio library for the
625106f25ae9SGregory Neil Shapiro ** parent process will not agree with the in-kernel
625206f25ae9SGregory Neil Shapiro ** file offset since the file descriptor is shared
625306f25ae9SGregory Neil Shapiro ** between the processes. Therefore, it is vital
625406f25ae9SGregory Neil Shapiro ** that the file always be rewound. This forces the
625506f25ae9SGregory Neil Shapiro ** kernel offset (lseek) and stdio library (ftell)
625606f25ae9SGregory Neil Shapiro ** offset to match.
625706f25ae9SGregory Neil Shapiro */
625806f25ae9SGregory Neil Shapiro
62594e4196cbSGregory Neil Shapiro save_errno = errno;
626006f25ae9SGregory Neil Shapiro if (e->e_dfp != NULL)
626106f25ae9SGregory Neil Shapiro (void) bfrewind(e->e_dfp);
626206f25ae9SGregory Neil Shapiro
6263c2aa98e2SPeter Wemm /* some mailers want extra blank line at end of message */
626406f25ae9SGregory Neil Shapiro if (!dead && bitnset(M_BLANKEND, mci->mci_mailer->m_flags) &&
6265c2aa98e2SPeter Wemm buf[0] != '\0' && buf[0] != '\n')
6266c2aa98e2SPeter Wemm {
62674e4196cbSGregory Neil Shapiro if (!putline("", mci))
62684e4196cbSGregory Neil Shapiro goto writeerr;
62694e4196cbSGregory Neil Shapiro }
62704e4196cbSGregory Neil Shapiro
62714e4196cbSGregory Neil Shapiro if (!dead &&
62724e4196cbSGregory Neil Shapiro (sm_io_flush(mci->mci_out, SM_TIME_DEFAULT) == SM_IO_EOF ||
62734e4196cbSGregory Neil Shapiro (sm_io_error(mci->mci_out) && errno != EPIPE)))
62744e4196cbSGregory Neil Shapiro {
62754e4196cbSGregory Neil Shapiro save_errno = errno;
6276c2aa98e2SPeter Wemm syserr("putbody: write error");
6277c2aa98e2SPeter Wemm ExitStat = EX_IOERR;
62784e4196cbSGregory Neil Shapiro ioerr = true;
6279c2aa98e2SPeter Wemm }
628006f25ae9SGregory Neil Shapiro
62814e4196cbSGregory Neil Shapiro errno = save_errno;
62824e4196cbSGregory Neil Shapiro return !dead && !ioerr;
62834e4196cbSGregory Neil Shapiro
62844e4196cbSGregory Neil Shapiro writeerr:
62854e4196cbSGregory Neil Shapiro return false;
6286c2aa98e2SPeter Wemm }
62874e4196cbSGregory Neil Shapiro
628840266059SGregory Neil Shapiro /*
6289c2aa98e2SPeter Wemm ** MAILFILE -- Send a message to a file.
6290c2aa98e2SPeter Wemm **
629140266059SGregory Neil Shapiro ** If the file has the set-user-ID/set-group-ID bits set, but NO
629240266059SGregory Neil Shapiro ** execute bits, sendmail will try to become the owner of that file
6293c2aa98e2SPeter Wemm ** rather than the real user. Obviously, this only works if
6294c2aa98e2SPeter Wemm ** sendmail runs as root.
6295c2aa98e2SPeter Wemm **
6296c2aa98e2SPeter Wemm ** This could be done as a subordinate mailer, except that it
6297c2aa98e2SPeter Wemm ** is used implicitly to save messages in ~/dead.letter. We
6298c2aa98e2SPeter Wemm ** view this as being sufficiently important as to include it
6299c2aa98e2SPeter Wemm ** here. For example, if the system is dying, we shouldn't have
6300c2aa98e2SPeter Wemm ** to create another process plus some pipes to save the message.
6301c2aa98e2SPeter Wemm **
6302c2aa98e2SPeter Wemm ** Parameters:
6303c2aa98e2SPeter Wemm ** filename -- the name of the file to send to.
6304c2aa98e2SPeter Wemm ** mailer -- mailer definition for recipient -- if NULL,
6305c2aa98e2SPeter Wemm ** use FileMailer.
6306c2aa98e2SPeter Wemm ** ctladdr -- the controlling address header -- includes
6307c2aa98e2SPeter Wemm ** the userid/groupid to be when sending.
6308c2aa98e2SPeter Wemm ** sfflags -- flags for opening.
6309c2aa98e2SPeter Wemm ** e -- the current envelope.
6310c2aa98e2SPeter Wemm **
6311c2aa98e2SPeter Wemm ** Returns:
6312c2aa98e2SPeter Wemm ** The exit code associated with the operation.
6313c2aa98e2SPeter Wemm **
6314c2aa98e2SPeter Wemm ** Side Effects:
6315c2aa98e2SPeter Wemm ** none.
6316c2aa98e2SPeter Wemm */
6317c2aa98e2SPeter Wemm
631840266059SGregory Neil Shapiro # define RETURN(st) exit(st);
631940266059SGregory Neil Shapiro
6320c2aa98e2SPeter Wemm static jmp_buf CtxMailfileTimeout;
6321c2aa98e2SPeter Wemm
6322c2aa98e2SPeter Wemm int
mailfile(filename,mailer,ctladdr,sfflags,e)6323c2aa98e2SPeter Wemm mailfile(filename, mailer, ctladdr, sfflags, e)
6324c2aa98e2SPeter Wemm char *volatile filename;
6325c2aa98e2SPeter Wemm MAILER *volatile mailer;
6326c2aa98e2SPeter Wemm ADDRESS *ctladdr;
632706f25ae9SGregory Neil Shapiro volatile long sfflags;
6328c2aa98e2SPeter Wemm register ENVELOPE *e;
6329c2aa98e2SPeter Wemm {
633040266059SGregory Neil Shapiro register SM_FILE_T *f;
6331c2aa98e2SPeter Wemm register pid_t pid = -1;
633206f25ae9SGregory Neil Shapiro volatile int mode;
633306f25ae9SGregory Neil Shapiro int len;
633406f25ae9SGregory Neil Shapiro off_t curoff;
6335c2aa98e2SPeter Wemm bool suidwarn = geteuid() == 0;
6336c2aa98e2SPeter Wemm char *p;
633706f25ae9SGregory Neil Shapiro char *volatile realfile;
633840266059SGregory Neil Shapiro SM_EVENT *ev;
633994c01205SGregory Neil Shapiro char buf[MAXPATHLEN];
634094c01205SGregory Neil Shapiro char targetfile[MAXPATHLEN];
6341c2aa98e2SPeter Wemm
6342c2aa98e2SPeter Wemm if (tTd(11, 1))
6343c2aa98e2SPeter Wemm {
634440266059SGregory Neil Shapiro sm_dprintf("mailfile %s\n ctladdr=", filename);
6345e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), ctladdr, false);
6346c2aa98e2SPeter Wemm }
6347c2aa98e2SPeter Wemm
6348c2aa98e2SPeter Wemm if (mailer == NULL)
6349c2aa98e2SPeter Wemm mailer = FileMailer;
6350c2aa98e2SPeter Wemm
6351c2aa98e2SPeter Wemm if (e->e_xfp != NULL)
635240266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
6353c2aa98e2SPeter Wemm
6354c2aa98e2SPeter Wemm /*
6355c2aa98e2SPeter Wemm ** Special case /dev/null. This allows us to restrict file
6356c2aa98e2SPeter Wemm ** delivery to regular files only.
6357c2aa98e2SPeter Wemm */
6358c2aa98e2SPeter Wemm
635940266059SGregory Neil Shapiro if (sm_path_isdevnull(filename))
6360c2aa98e2SPeter Wemm return EX_OK;
6361c2aa98e2SPeter Wemm
6362c2aa98e2SPeter Wemm /* check for 8-bit available */
6363c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) &&
6364c2aa98e2SPeter Wemm bitnset(M_7BITS, mailer->m_flags) &&
6365c2aa98e2SPeter Wemm (bitset(EF_DONT_MIME, e->e_flags) ||
6366c2aa98e2SPeter Wemm !(bitset(MM_MIME8BIT, MimeMode) ||
6367c2aa98e2SPeter Wemm (bitset(EF_IS_MIME, e->e_flags) &&
6368c2aa98e2SPeter Wemm bitset(MM_CVTMIME, MimeMode)))))
6369c2aa98e2SPeter Wemm {
6370c2aa98e2SPeter Wemm e->e_status = "5.6.3";
637106f25ae9SGregory Neil Shapiro usrerrenh(e->e_status,
637206f25ae9SGregory Neil Shapiro "554 Cannot send 8-bit data to 7-bit destination");
637340266059SGregory Neil Shapiro errno = 0;
637406f25ae9SGregory Neil Shapiro return EX_DATAERR;
637506f25ae9SGregory Neil Shapiro }
637606f25ae9SGregory Neil Shapiro
637706f25ae9SGregory Neil Shapiro /* Find the actual file */
637806f25ae9SGregory Neil Shapiro if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0')
637906f25ae9SGregory Neil Shapiro {
638006f25ae9SGregory Neil Shapiro len = strlen(SafeFileEnv);
638106f25ae9SGregory Neil Shapiro
638206f25ae9SGregory Neil Shapiro if (strncmp(SafeFileEnv, filename, len) == 0)
638306f25ae9SGregory Neil Shapiro filename += len;
638406f25ae9SGregory Neil Shapiro
6385d0cef73dSGregory Neil Shapiro if (len + strlen(filename) + 1 >= sizeof(targetfile))
638606f25ae9SGregory Neil Shapiro {
638706f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s/%s)",
638806f25ae9SGregory Neil Shapiro SafeFileEnv, filename);
638906f25ae9SGregory Neil Shapiro return EX_CANTCREAT;
639006f25ae9SGregory Neil Shapiro }
6391d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(targetfile, SafeFileEnv, sizeof(targetfile));
639206f25ae9SGregory Neil Shapiro realfile = targetfile + len;
639306f25ae9SGregory Neil Shapiro if (*filename == '/')
639406f25ae9SGregory Neil Shapiro filename++;
6395605302a5SGregory Neil Shapiro if (*filename != '\0')
6396605302a5SGregory Neil Shapiro {
6397605302a5SGregory Neil Shapiro /* paranoia: trailing / should be removed in readcf */
6398605302a5SGregory Neil Shapiro if (targetfile[len - 1] != '/')
6399605302a5SGregory Neil Shapiro (void) sm_strlcat(targetfile,
6400d0cef73dSGregory Neil Shapiro "/", sizeof(targetfile));
6401605302a5SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename,
6402d0cef73dSGregory Neil Shapiro sizeof(targetfile));
6403605302a5SGregory Neil Shapiro }
640406f25ae9SGregory Neil Shapiro }
640506f25ae9SGregory Neil Shapiro else if (mailer->m_rootdir != NULL)
640606f25ae9SGregory Neil Shapiro {
6407d0cef73dSGregory Neil Shapiro expand(mailer->m_rootdir, targetfile, sizeof(targetfile), e);
640806f25ae9SGregory Neil Shapiro len = strlen(targetfile);
640906f25ae9SGregory Neil Shapiro
641006f25ae9SGregory Neil Shapiro if (strncmp(targetfile, filename, len) == 0)
641106f25ae9SGregory Neil Shapiro filename += len;
641206f25ae9SGregory Neil Shapiro
6413d0cef73dSGregory Neil Shapiro if (len + strlen(filename) + 1 >= sizeof(targetfile))
641406f25ae9SGregory Neil Shapiro {
641506f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s/%s)",
641606f25ae9SGregory Neil Shapiro targetfile, filename);
641706f25ae9SGregory Neil Shapiro return EX_CANTCREAT;
641806f25ae9SGregory Neil Shapiro }
641906f25ae9SGregory Neil Shapiro realfile = targetfile + len;
642006f25ae9SGregory Neil Shapiro if (targetfile[len - 1] != '/')
6421d0cef73dSGregory Neil Shapiro (void) sm_strlcat(targetfile, "/", sizeof(targetfile));
642206f25ae9SGregory Neil Shapiro if (*filename == '/')
642340266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename + 1,
6424d0cef73dSGregory Neil Shapiro sizeof(targetfile));
642506f25ae9SGregory Neil Shapiro else
642640266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename,
6427d0cef73dSGregory Neil Shapiro sizeof(targetfile));
642806f25ae9SGregory Neil Shapiro }
642906f25ae9SGregory Neil Shapiro else
643006f25ae9SGregory Neil Shapiro {
6431d0cef73dSGregory Neil Shapiro if (sm_strlcpy(targetfile, filename, sizeof(targetfile)) >=
6432d0cef73dSGregory Neil Shapiro sizeof(targetfile))
643306f25ae9SGregory Neil Shapiro {
643406f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s)", filename);
643506f25ae9SGregory Neil Shapiro return EX_CANTCREAT;
643606f25ae9SGregory Neil Shapiro }
643706f25ae9SGregory Neil Shapiro realfile = targetfile;
6438c2aa98e2SPeter Wemm }
6439c2aa98e2SPeter Wemm
6440c2aa98e2SPeter Wemm /*
6441c2aa98e2SPeter Wemm ** Fork so we can change permissions here.
6442c2aa98e2SPeter Wemm ** Note that we MUST use fork, not vfork, because of
6443c2aa98e2SPeter Wemm ** the complications of calling subroutines, etc.
6444c2aa98e2SPeter Wemm */
6445c2aa98e2SPeter Wemm
6446605302a5SGregory Neil Shapiro
6447605302a5SGregory Neil Shapiro /*
6448605302a5SGregory Neil Shapiro ** Dispose of SIGCHLD signal catchers that may be laying
6449605302a5SGregory Neil Shapiro ** around so that the waitfor() below will get it.
6450605302a5SGregory Neil Shapiro */
6451605302a5SGregory Neil Shapiro
6452605302a5SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL);
6453605302a5SGregory Neil Shapiro
6454c2aa98e2SPeter Wemm DOFORK(fork);
6455c2aa98e2SPeter Wemm
6456c2aa98e2SPeter Wemm if (pid < 0)
645706f25ae9SGregory Neil Shapiro return EX_OSERR;
6458c2aa98e2SPeter Wemm else if (pid == 0)
6459c2aa98e2SPeter Wemm {
6460c2aa98e2SPeter Wemm /* child -- actually write to file */
6461c2aa98e2SPeter Wemm struct stat stb;
6462c2aa98e2SPeter Wemm MCI mcibuf;
6463065a643dSPeter Wemm int err;
6464c2aa98e2SPeter Wemm volatile int oflags = O_WRONLY|O_APPEND;
6465c2aa98e2SPeter Wemm
64668774250cSGregory Neil Shapiro /* Reset global flags */
64678774250cSGregory Neil Shapiro RestartRequest = NULL;
646840266059SGregory Neil Shapiro RestartWorkGroup = false;
64698774250cSGregory Neil Shapiro ShutdownRequest = NULL;
64708774250cSGregory Neil Shapiro PendingSignal = 0;
647140266059SGregory Neil Shapiro CurrentPid = getpid();
64728774250cSGregory Neil Shapiro
6473c2aa98e2SPeter Wemm if (e->e_lockfp != NULL)
6474af9557fdSGregory Neil Shapiro {
6475af9557fdSGregory Neil Shapiro int fd;
6476af9557fdSGregory Neil Shapiro
6477af9557fdSGregory Neil Shapiro fd = sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL);
6478af9557fdSGregory Neil Shapiro /* SM_ASSERT(fd >= 0); */
6479af9557fdSGregory Neil Shapiro if (fd >= 0)
6480af9557fdSGregory Neil Shapiro (void) close(fd);
6481af9557fdSGregory Neil Shapiro }
6482c2aa98e2SPeter Wemm
648340266059SGregory Neil Shapiro (void) sm_signal(SIGINT, SIG_DFL);
648440266059SGregory Neil Shapiro (void) sm_signal(SIGHUP, SIG_DFL);
648540266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL);
6486c2aa98e2SPeter Wemm (void) umask(OldUmask);
6487c2aa98e2SPeter Wemm e->e_to = filename;
6488c2aa98e2SPeter Wemm ExitStat = EX_OK;
6489c2aa98e2SPeter Wemm
6490c2aa98e2SPeter Wemm if (setjmp(CtxMailfileTimeout) != 0)
6491c2aa98e2SPeter Wemm {
649240266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL);
6493c2aa98e2SPeter Wemm }
6494c2aa98e2SPeter Wemm
6495c2aa98e2SPeter Wemm if (TimeOuts.to_fileopen > 0)
649640266059SGregory Neil Shapiro ev = sm_setevent(TimeOuts.to_fileopen, mailfiletimeout,
649740266059SGregory Neil Shapiro 0);
6498c2aa98e2SPeter Wemm else
6499c2aa98e2SPeter Wemm ev = NULL;
6500c2aa98e2SPeter Wemm
650140266059SGregory Neil Shapiro /* check file mode to see if set-user-ID */
650206f25ae9SGregory Neil Shapiro if (stat(targetfile, &stb) < 0)
6503c2aa98e2SPeter Wemm mode = FileMode;
650406f25ae9SGregory Neil Shapiro else
6505c2aa98e2SPeter Wemm mode = stb.st_mode;
6506c2aa98e2SPeter Wemm
6507c2aa98e2SPeter Wemm /* limit the errors to those actually caused in the child */
6508c2aa98e2SPeter Wemm errno = 0;
6509c2aa98e2SPeter Wemm ExitStat = EX_OK;
6510c2aa98e2SPeter Wemm
651106f25ae9SGregory Neil Shapiro /* Allow alias expansions to use the S_IS{U,G}ID bits */
651206f25ae9SGregory Neil Shapiro if ((ctladdr != NULL && !bitset(QALIAS, ctladdr->q_flags)) ||
651306f25ae9SGregory Neil Shapiro bitset(SFF_RUNASREALUID, sfflags))
6514c2aa98e2SPeter Wemm {
651540266059SGregory Neil Shapiro /* ignore set-user-ID and set-group-ID bits */
6516c2aa98e2SPeter Wemm mode &= ~(S_ISGID|S_ISUID);
651706f25ae9SGregory Neil Shapiro if (tTd(11, 20))
651840266059SGregory Neil Shapiro sm_dprintf("mailfile: ignoring set-user-ID/set-group-ID bits\n");
6519c2aa98e2SPeter Wemm }
6520c2aa98e2SPeter Wemm
652140266059SGregory Neil Shapiro /* we have to open the data file BEFORE setuid() */
6522c2aa98e2SPeter Wemm if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
6523c2aa98e2SPeter Wemm {
652440266059SGregory Neil Shapiro char *df = queuename(e, DATAFL_LETTER);
6525c2aa98e2SPeter Wemm
652640266059SGregory Neil Shapiro e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df,
6527a7ec597cSGregory Neil Shapiro SM_IO_RDONLY_B, NULL);
6528c2aa98e2SPeter Wemm if (e->e_dfp == NULL)
6529c2aa98e2SPeter Wemm {
6530c2aa98e2SPeter Wemm syserr("mailfile: Cannot open %s for %s from %s",
6531c2aa98e2SPeter Wemm df, e->e_to, e->e_from.q_paddr);
6532c2aa98e2SPeter Wemm }
6533c2aa98e2SPeter Wemm }
6534c2aa98e2SPeter Wemm
6535c2aa98e2SPeter Wemm /* select a new user to run as */
6536c2aa98e2SPeter Wemm if (!bitset(SFF_RUNASREALUID, sfflags))
6537c2aa98e2SPeter Wemm {
6538c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, mailer->m_flags))
6539c2aa98e2SPeter Wemm {
6540c2aa98e2SPeter Wemm RealUserName = NULL;
6541e92d3f3fSGregory Neil Shapiro if (mailer->m_uid == NO_UID)
6542e92d3f3fSGregory Neil Shapiro RealUid = RunAsUid;
6543e92d3f3fSGregory Neil Shapiro else
6544c2aa98e2SPeter Wemm RealUid = mailer->m_uid;
654506f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && RealUid != RunAsUid)
654606f25ae9SGregory Neil Shapiro {
654706f25ae9SGregory Neil Shapiro /* Only root can change the uid */
6548da7d7b9cSGregory Neil Shapiro syserr("mailfile: insufficient privileges to change uid, RunAsUid=%ld, RealUid=%ld",
6549da7d7b9cSGregory Neil Shapiro (long) RunAsUid, (long) RealUid);
655040266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL);
655106f25ae9SGregory Neil Shapiro }
6552c2aa98e2SPeter Wemm }
6553c2aa98e2SPeter Wemm else if (bitset(S_ISUID, mode))
6554c2aa98e2SPeter Wemm {
6555c2aa98e2SPeter Wemm RealUserName = NULL;
6556c2aa98e2SPeter Wemm RealUid = stb.st_uid;
6557c2aa98e2SPeter Wemm }
6558c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_uid != 0)
6559c2aa98e2SPeter Wemm {
6560c2aa98e2SPeter Wemm if (ctladdr->q_ruser != NULL)
6561c2aa98e2SPeter Wemm RealUserName = ctladdr->q_ruser;
6562c2aa98e2SPeter Wemm else
6563c2aa98e2SPeter Wemm RealUserName = ctladdr->q_user;
6564c2aa98e2SPeter Wemm RealUid = ctladdr->q_uid;
6565c2aa98e2SPeter Wemm }
6566e92d3f3fSGregory Neil Shapiro else if (mailer != NULL && mailer->m_uid != NO_UID)
6567c2aa98e2SPeter Wemm {
6568c2aa98e2SPeter Wemm RealUserName = DefUser;
6569c2aa98e2SPeter Wemm RealUid = mailer->m_uid;
6570c2aa98e2SPeter Wemm }
6571c2aa98e2SPeter Wemm else
6572c2aa98e2SPeter Wemm {
6573c2aa98e2SPeter Wemm RealUserName = DefUser;
6574c2aa98e2SPeter Wemm RealUid = DefUid;
6575c2aa98e2SPeter Wemm }
6576c2aa98e2SPeter Wemm
6577c2aa98e2SPeter Wemm /* select a new group to run as */
6578c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, mailer->m_flags))
657906f25ae9SGregory Neil Shapiro {
6580e92d3f3fSGregory Neil Shapiro if (mailer->m_gid == NO_GID)
6581e92d3f3fSGregory Neil Shapiro RealGid = RunAsGid;
6582e92d3f3fSGregory Neil Shapiro else
6583c2aa98e2SPeter Wemm RealGid = mailer->m_gid;
658406f25ae9SGregory Neil Shapiro if (RunAsUid != 0 &&
658506f25ae9SGregory Neil Shapiro (RealGid != getgid() ||
658606f25ae9SGregory Neil Shapiro RealGid != getegid()))
658706f25ae9SGregory Neil Shapiro {
658806f25ae9SGregory Neil Shapiro /* Only root can change the gid */
6589da7d7b9cSGregory Neil Shapiro syserr("mailfile: insufficient privileges to change gid, RealGid=%ld, RunAsUid=%ld, gid=%ld, egid=%ld",
6590da7d7b9cSGregory Neil Shapiro (long) RealGid, (long) RunAsUid,
6591da7d7b9cSGregory Neil Shapiro (long) getgid(), (long) getegid());
659240266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL);
659306f25ae9SGregory Neil Shapiro }
659406f25ae9SGregory Neil Shapiro }
6595c2aa98e2SPeter Wemm else if (bitset(S_ISGID, mode))
6596c2aa98e2SPeter Wemm RealGid = stb.st_gid;
659706f25ae9SGregory Neil Shapiro else if (ctladdr != NULL &&
659806f25ae9SGregory Neil Shapiro ctladdr->q_uid == DefUid &&
659906f25ae9SGregory Neil Shapiro ctladdr->q_gid == 0)
6600193538b7SGregory Neil Shapiro {
6601193538b7SGregory Neil Shapiro /*
6602193538b7SGregory Neil Shapiro ** Special case: This means it is an
6603193538b7SGregory Neil Shapiro ** alias and we should act as DefaultUser.
6604193538b7SGregory Neil Shapiro ** See alias()'s comments.
6605193538b7SGregory Neil Shapiro */
6606193538b7SGregory Neil Shapiro
660706f25ae9SGregory Neil Shapiro RealGid = DefGid;
6608193538b7SGregory Neil Shapiro RealUserName = DefUser;
6609193538b7SGregory Neil Shapiro }
6610193538b7SGregory Neil Shapiro else if (ctladdr != NULL && ctladdr->q_uid != 0)
6611193538b7SGregory Neil Shapiro RealGid = ctladdr->q_gid;
6612e92d3f3fSGregory Neil Shapiro else if (mailer != NULL && mailer->m_gid != NO_GID)
6613c2aa98e2SPeter Wemm RealGid = mailer->m_gid;
6614c2aa98e2SPeter Wemm else
6615c2aa98e2SPeter Wemm RealGid = DefGid;
6616c2aa98e2SPeter Wemm }
6617c2aa98e2SPeter Wemm
6618c2aa98e2SPeter Wemm /* last ditch */
6619c2aa98e2SPeter Wemm if (!bitset(SFF_ROOTOK, sfflags))
6620c2aa98e2SPeter Wemm {
6621c2aa98e2SPeter Wemm if (RealUid == 0)
6622c2aa98e2SPeter Wemm RealUid = DefUid;
6623c2aa98e2SPeter Wemm if (RealGid == 0)
6624c2aa98e2SPeter Wemm RealGid = DefGid;
6625c2aa98e2SPeter Wemm }
6626c2aa98e2SPeter Wemm
6627c2aa98e2SPeter Wemm /* set group id list (needs /etc/group access) */
6628c2aa98e2SPeter Wemm if (RealUserName != NULL && !DontInitGroups)
6629c2aa98e2SPeter Wemm {
6630c2aa98e2SPeter Wemm if (initgroups(RealUserName, RealGid) == -1 && suidwarn)
663106f25ae9SGregory Neil Shapiro {
6632da7d7b9cSGregory Neil Shapiro syserr("mailfile: initgroups(%s, %ld) failed",
6633da7d7b9cSGregory Neil Shapiro RealUserName, (long) RealGid);
663440266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL);
663506f25ae9SGregory Neil Shapiro }
6636c2aa98e2SPeter Wemm }
6637c2aa98e2SPeter Wemm else
6638c2aa98e2SPeter Wemm {
6639c2aa98e2SPeter Wemm GIDSET_T gidset[1];
6640c2aa98e2SPeter Wemm
6641c2aa98e2SPeter Wemm gidset[0] = RealGid;
6642c2aa98e2SPeter Wemm if (setgroups(1, gidset) == -1 && suidwarn)
664306f25ae9SGregory Neil Shapiro {
6644c2aa98e2SPeter Wemm syserr("mailfile: setgroups() failed");
664540266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL);
664606f25ae9SGregory Neil Shapiro }
6647c2aa98e2SPeter Wemm }
6648c2aa98e2SPeter Wemm
664906f25ae9SGregory Neil Shapiro /*
665006f25ae9SGregory Neil Shapiro ** If you have a safe environment, go into it.
665106f25ae9SGregory Neil Shapiro */
6652c2aa98e2SPeter Wemm
665306f25ae9SGregory Neil Shapiro if (realfile != targetfile)
665406f25ae9SGregory Neil Shapiro {
6655605302a5SGregory Neil Shapiro char save;
6656605302a5SGregory Neil Shapiro
6657605302a5SGregory Neil Shapiro save = *realfile;
665806f25ae9SGregory Neil Shapiro *realfile = '\0';
665906f25ae9SGregory Neil Shapiro if (tTd(11, 20))
666040266059SGregory Neil Shapiro sm_dprintf("mailfile: chroot %s\n", targetfile);
666106f25ae9SGregory Neil Shapiro if (chroot(targetfile) < 0)
6662c2aa98e2SPeter Wemm {
6663c2aa98e2SPeter Wemm syserr("mailfile: Cannot chroot(%s)",
666406f25ae9SGregory Neil Shapiro targetfile);
666540266059SGregory Neil Shapiro RETURN(EX_CANTCREAT);
6666c2aa98e2SPeter Wemm }
6667605302a5SGregory Neil Shapiro *realfile = save;
6668c2aa98e2SPeter Wemm }
666906f25ae9SGregory Neil Shapiro
667006f25ae9SGregory Neil Shapiro if (tTd(11, 40))
667140266059SGregory Neil Shapiro sm_dprintf("mailfile: deliver to %s\n", realfile);
667206f25ae9SGregory Neil Shapiro
6673c2aa98e2SPeter Wemm if (chdir("/") < 0)
667406f25ae9SGregory Neil Shapiro {
6675c2aa98e2SPeter Wemm syserr("mailfile: cannot chdir(/)");
667640266059SGregory Neil Shapiro RETURN(EX_CANTCREAT);
667706f25ae9SGregory Neil Shapiro }
6678c2aa98e2SPeter Wemm
6679c2aa98e2SPeter Wemm /* now reset the group and user ids */
6680c2aa98e2SPeter Wemm endpwent();
668140266059SGregory Neil Shapiro sm_mbdb_terminate();
6682c2aa98e2SPeter Wemm if (setgid(RealGid) < 0 && suidwarn)
668306f25ae9SGregory Neil Shapiro {
6684c2aa98e2SPeter Wemm syserr("mailfile: setgid(%ld) failed", (long) RealGid);
668540266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL);
668606f25ae9SGregory Neil Shapiro }
6687c2aa98e2SPeter Wemm vendor_set_uid(RealUid);
6688c2aa98e2SPeter Wemm if (setuid(RealUid) < 0 && suidwarn)
668906f25ae9SGregory Neil Shapiro {
6690c2aa98e2SPeter Wemm syserr("mailfile: setuid(%ld) failed", (long) RealUid);
669140266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL);
669206f25ae9SGregory Neil Shapiro }
669306f25ae9SGregory Neil Shapiro
669406f25ae9SGregory Neil Shapiro if (tTd(11, 2))
6695da7d7b9cSGregory Neil Shapiro sm_dprintf("mailfile: running as r/euid=%ld/%ld, r/egid=%ld/%ld\n",
6696da7d7b9cSGregory Neil Shapiro (long) getuid(), (long) geteuid(),
6697da7d7b9cSGregory Neil Shapiro (long) getgid(), (long) getegid());
669806f25ae9SGregory Neil Shapiro
6699c2aa98e2SPeter Wemm
6700c2aa98e2SPeter Wemm /* move into some "safe" directory */
6701c2aa98e2SPeter Wemm if (mailer->m_execdir != NULL)
6702c2aa98e2SPeter Wemm {
6703c2aa98e2SPeter Wemm char *q;
6704c2aa98e2SPeter Wemm
6705c2aa98e2SPeter Wemm for (p = mailer->m_execdir; p != NULL; p = q)
6706c2aa98e2SPeter Wemm {
6707c2aa98e2SPeter Wemm q = strchr(p, ':');
6708c2aa98e2SPeter Wemm if (q != NULL)
6709c2aa98e2SPeter Wemm *q = '\0';
6710d0cef73dSGregory Neil Shapiro expand(p, buf, sizeof(buf), e);
6711c2aa98e2SPeter Wemm if (q != NULL)
6712c2aa98e2SPeter Wemm *q++ = ':';
6713c2aa98e2SPeter Wemm if (tTd(11, 20))
671440266059SGregory Neil Shapiro sm_dprintf("mailfile: trydir %s\n",
671540266059SGregory Neil Shapiro buf);
6716c2aa98e2SPeter Wemm if (buf[0] != '\0' && chdir(buf) >= 0)
6717c2aa98e2SPeter Wemm break;
6718c2aa98e2SPeter Wemm }
6719c2aa98e2SPeter Wemm }
6720c2aa98e2SPeter Wemm
672106f25ae9SGregory Neil Shapiro /*
672206f25ae9SGregory Neil Shapiro ** Recheck the file after we have assumed the ID of the
672306f25ae9SGregory Neil Shapiro ** delivery user to make sure we can deliver to it as
672406f25ae9SGregory Neil Shapiro ** that user. This is necessary if sendmail is running
672506f25ae9SGregory Neil Shapiro ** as root and the file is on an NFS mount which treats
672606f25ae9SGregory Neil Shapiro ** root as nobody.
672706f25ae9SGregory Neil Shapiro */
672806f25ae9SGregory Neil Shapiro
672906f25ae9SGregory Neil Shapiro #if HASLSTAT
673006f25ae9SGregory Neil Shapiro if (bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail))
673106f25ae9SGregory Neil Shapiro err = stat(realfile, &stb);
673206f25ae9SGregory Neil Shapiro else
673306f25ae9SGregory Neil Shapiro err = lstat(realfile, &stb);
673406f25ae9SGregory Neil Shapiro #else /* HASLSTAT */
673506f25ae9SGregory Neil Shapiro err = stat(realfile, &stb);
673606f25ae9SGregory Neil Shapiro #endif /* HASLSTAT */
673706f25ae9SGregory Neil Shapiro
673806f25ae9SGregory Neil Shapiro if (err < 0)
673906f25ae9SGregory Neil Shapiro {
674006f25ae9SGregory Neil Shapiro stb.st_mode = ST_MODE_NOFILE;
674106f25ae9SGregory Neil Shapiro mode = FileMode;
674206f25ae9SGregory Neil Shapiro oflags |= O_CREAT|O_EXCL;
674306f25ae9SGregory Neil Shapiro }
674406f25ae9SGregory Neil Shapiro else if (bitset(S_IXUSR|S_IXGRP|S_IXOTH, mode) ||
674506f25ae9SGregory Neil Shapiro (!bitnset(DBS_FILEDELIVERYTOHARDLINK,
674606f25ae9SGregory Neil Shapiro DontBlameSendmail) &&
674706f25ae9SGregory Neil Shapiro stb.st_nlink != 1) ||
674806f25ae9SGregory Neil Shapiro (realfile != targetfile && !S_ISREG(mode)))
674906f25ae9SGregory Neil Shapiro exit(EX_CANTCREAT);
675006f25ae9SGregory Neil Shapiro else
675106f25ae9SGregory Neil Shapiro mode = stb.st_mode;
675206f25ae9SGregory Neil Shapiro
675306f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail))
6754c2aa98e2SPeter Wemm sfflags |= SFF_NOSLINK;
675506f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail))
6756c2aa98e2SPeter Wemm sfflags |= SFF_NOHLINK;
6757c2aa98e2SPeter Wemm sfflags &= ~SFF_OPENASROOT;
675806f25ae9SGregory Neil Shapiro f = safefopen(realfile, oflags, mode, sfflags);
6759c2aa98e2SPeter Wemm if (f == NULL)
6760c2aa98e2SPeter Wemm {
676106f25ae9SGregory Neil Shapiro if (transienterror(errno))
676206f25ae9SGregory Neil Shapiro {
676306f25ae9SGregory Neil Shapiro usrerr("454 4.3.0 cannot open %s: %s",
676406f25ae9SGregory Neil Shapiro shortenstring(realfile, MAXSHORTSTR),
676540266059SGregory Neil Shapiro sm_errstring(errno));
676640266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL);
676706f25ae9SGregory Neil Shapiro }
676806f25ae9SGregory Neil Shapiro else
676906f25ae9SGregory Neil Shapiro {
677006f25ae9SGregory Neil Shapiro usrerr("554 5.3.0 cannot open %s: %s",
677106f25ae9SGregory Neil Shapiro shortenstring(realfile, MAXSHORTSTR),
677240266059SGregory Neil Shapiro sm_errstring(errno));
677340266059SGregory Neil Shapiro RETURN(EX_CANTCREAT);
6774c2aa98e2SPeter Wemm }
677506f25ae9SGregory Neil Shapiro }
677640266059SGregory Neil Shapiro if (filechanged(realfile, sm_io_getinfo(f, SM_IO_WHAT_FD, NULL),
677740266059SGregory Neil Shapiro &stb))
6778c2aa98e2SPeter Wemm {
677906f25ae9SGregory Neil Shapiro syserr("554 5.3.0 file changed after open");
678040266059SGregory Neil Shapiro RETURN(EX_CANTCREAT);
6781c2aa98e2SPeter Wemm }
678240266059SGregory Neil Shapiro if (fstat(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), &stb) < 0)
6783c2aa98e2SPeter Wemm {
678440266059SGregory Neil Shapiro syserr("554 5.3.0 cannot fstat %s",
678540266059SGregory Neil Shapiro sm_errstring(errno));
678640266059SGregory Neil Shapiro RETURN(EX_CANTCREAT);
6787c2aa98e2SPeter Wemm }
6788c2aa98e2SPeter Wemm
678906f25ae9SGregory Neil Shapiro curoff = stb.st_size;
679006f25ae9SGregory Neil Shapiro
6791c2aa98e2SPeter Wemm if (ev != NULL)
679240266059SGregory Neil Shapiro sm_clrevent(ev);
6793c2aa98e2SPeter Wemm
6794d0cef73dSGregory Neil Shapiro memset(&mcibuf, '\0', sizeof(mcibuf));
6795c2aa98e2SPeter Wemm mcibuf.mci_mailer = mailer;
6796c2aa98e2SPeter Wemm mcibuf.mci_out = f;
6797c2aa98e2SPeter Wemm if (bitnset(M_7BITS, mailer->m_flags))
6798c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_7BIT;
6799c2aa98e2SPeter Wemm
6800c2aa98e2SPeter Wemm /* clear out per-message flags from connection structure */
6801c2aa98e2SPeter Wemm mcibuf.mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7);
6802c2aa98e2SPeter Wemm
6803c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) &&
6804c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) &&
6805c2aa98e2SPeter Wemm bitnset(M_7BITS, mailer->m_flags))
6806c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_CVT8TO7;
6807c2aa98e2SPeter Wemm
6808c2aa98e2SPeter Wemm #if MIME7TO8
6809c2aa98e2SPeter Wemm if (bitnset(M_MAKE8BIT, mailer->m_flags) &&
6810c2aa98e2SPeter Wemm !bitset(MCIF_7BIT, mcibuf.mci_flags) &&
6811c2aa98e2SPeter Wemm (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL &&
68122fb4f839SGregory Neil Shapiro (SM_STRCASEEQ(p, "quoted-printable") ||
68132fb4f839SGregory Neil Shapiro SM_STRCASEEQ(p, "base64")) &&
6814c2aa98e2SPeter Wemm (p = hvalue("Content-Type", e->e_header)) != NULL)
6815c2aa98e2SPeter Wemm {
6816c2aa98e2SPeter Wemm /* may want to convert 7 -> 8 */
6817c2aa98e2SPeter Wemm /* XXX should really parse it here -- and use a class XXX */
681840266059SGregory Neil Shapiro if (sm_strncasecmp(p, "text/plain", 10) == 0 &&
6819c2aa98e2SPeter Wemm (p[10] == '\0' || p[10] == ' ' || p[10] == ';'))
6820c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_CVT7TO8;
6821c2aa98e2SPeter Wemm }
682206f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */
6823c2aa98e2SPeter Wemm
68244e4196cbSGregory Neil Shapiro if (!putfromline(&mcibuf, e) ||
68254e4196cbSGregory Neil Shapiro !(*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER) ||
68264e4196cbSGregory Neil Shapiro !(*e->e_putbody)(&mcibuf, e, NULL) ||
68274e4196cbSGregory Neil Shapiro !putline("\n", &mcibuf) ||
68284e4196cbSGregory Neil Shapiro (sm_io_flush(f, SM_TIME_DEFAULT) != 0 ||
682940266059SGregory Neil Shapiro (SuperSafe != SAFE_NO &&
683040266059SGregory Neil Shapiro fsync(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL)) < 0) ||
68314e4196cbSGregory Neil Shapiro sm_io_error(f)))
6832c2aa98e2SPeter Wemm {
6833c2aa98e2SPeter Wemm setstat(EX_IOERR);
683406f25ae9SGregory Neil Shapiro #if !NOFTRUNCATE
683540266059SGregory Neil Shapiro (void) ftruncate(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL),
683640266059SGregory Neil Shapiro curoff);
68375b0945b5SGregory Neil Shapiro #endif
6838c2aa98e2SPeter Wemm }
6839c2aa98e2SPeter Wemm
6840c2aa98e2SPeter Wemm /* reset ISUID & ISGID bits for paranoid systems */
6841c2aa98e2SPeter Wemm #if HASFCHMOD
684240266059SGregory Neil Shapiro (void) fchmod(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL),
684340266059SGregory Neil Shapiro (MODE_T) mode);
68442fb4f839SGregory Neil Shapiro #else
684506f25ae9SGregory Neil Shapiro (void) chmod(filename, (MODE_T) mode);
68462fb4f839SGregory Neil Shapiro #endif
684740266059SGregory Neil Shapiro if (sm_io_close(f, SM_TIME_DEFAULT) < 0)
684806f25ae9SGregory Neil Shapiro setstat(EX_IOERR);
684940266059SGregory Neil Shapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
685006f25ae9SGregory Neil Shapiro (void) setuid(RealUid);
6851c2aa98e2SPeter Wemm exit(ExitStat);
6852c2aa98e2SPeter Wemm /* NOTREACHED */
6853c2aa98e2SPeter Wemm }
6854c2aa98e2SPeter Wemm else
6855c2aa98e2SPeter Wemm {
6856c2aa98e2SPeter Wemm /* parent -- wait for exit status */
6857c2aa98e2SPeter Wemm int st;
6858c2aa98e2SPeter Wemm
6859c2aa98e2SPeter Wemm st = waitfor(pid);
6860c2aa98e2SPeter Wemm if (st == -1)
6861c2aa98e2SPeter Wemm {
6862c2aa98e2SPeter Wemm syserr("mailfile: %s: wait", mailer->m_name);
686306f25ae9SGregory Neil Shapiro return EX_SOFTWARE;
6864c2aa98e2SPeter Wemm }
6865c2aa98e2SPeter Wemm if (WIFEXITED(st))
686640266059SGregory Neil Shapiro {
686740266059SGregory Neil Shapiro errno = 0;
6868c2aa98e2SPeter Wemm return (WEXITSTATUS(st));
686940266059SGregory Neil Shapiro }
6870c2aa98e2SPeter Wemm else
6871c2aa98e2SPeter Wemm {
6872c2aa98e2SPeter Wemm syserr("mailfile: %s: child died on signal %d",
6873c2aa98e2SPeter Wemm mailer->m_name, st);
687406f25ae9SGregory Neil Shapiro return EX_UNAVAILABLE;
6875c2aa98e2SPeter Wemm }
6876c2aa98e2SPeter Wemm /* NOTREACHED */
6877c2aa98e2SPeter Wemm }
6878c2aa98e2SPeter Wemm return EX_UNAVAILABLE; /* avoid compiler warning on IRIX */
6879c2aa98e2SPeter Wemm }
6880c2aa98e2SPeter Wemm
6881c2aa98e2SPeter Wemm static void
mailfiletimeout(ignore)6882b6bacd31SGregory Neil Shapiro mailfiletimeout(ignore)
6883b6bacd31SGregory Neil Shapiro int ignore;
6884c2aa98e2SPeter Wemm {
68858774250cSGregory Neil Shapiro /*
68868774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
68878774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
68888774250cSGregory Neil Shapiro ** DOING.
68898774250cSGregory Neil Shapiro */
68908774250cSGregory Neil Shapiro
68918774250cSGregory Neil Shapiro errno = ETIMEDOUT;
6892c2aa98e2SPeter Wemm longjmp(CtxMailfileTimeout, 1);
6893c2aa98e2SPeter Wemm }
68945b0945b5SGregory Neil Shapiro
68955b0945b5SGregory Neil Shapiro #if DANE
68965b0945b5SGregory Neil Shapiro
68975b0945b5SGregory Neil Shapiro /*
68985b0945b5SGregory Neil Shapiro ** GETMPORT -- return the port of a mailer
68995b0945b5SGregory Neil Shapiro **
69005b0945b5SGregory Neil Shapiro ** Parameters:
69015b0945b5SGregory Neil Shapiro ** m -- the mailer describing this host.
69025b0945b5SGregory Neil Shapiro **
69035b0945b5SGregory Neil Shapiro ** Returns:
69045b0945b5SGregory Neil Shapiro ** the port of the mailer if defined.
69055b0945b5SGregory Neil Shapiro ** 0 otherwise
69065b0945b5SGregory Neil Shapiro ** <0 error
69075b0945b5SGregory Neil Shapiro */
69085b0945b5SGregory Neil Shapiro
69095b0945b5SGregory Neil Shapiro static int getmport __P((MAILER *));
69105b0945b5SGregory Neil Shapiro
69115b0945b5SGregory Neil Shapiro static int
getmport(m)69125b0945b5SGregory Neil Shapiro getmport(m)
69135b0945b5SGregory Neil Shapiro MAILER *m;
69145b0945b5SGregory Neil Shapiro {
69155b0945b5SGregory Neil Shapiro unsigned long ulval;
69165b0945b5SGregory Neil Shapiro char *buf, *ep;
69175b0945b5SGregory Neil Shapiro
69185b0945b5SGregory Neil Shapiro if (m->m_port > 0)
69195b0945b5SGregory Neil Shapiro return m->m_port;
69205b0945b5SGregory Neil Shapiro
69215b0945b5SGregory Neil Shapiro if (NULL == m->m_argv[0] ||NULL == m->m_argv[1])
69225b0945b5SGregory Neil Shapiro return -1;
69235b0945b5SGregory Neil Shapiro buf = m->m_argv[2];
69245b0945b5SGregory Neil Shapiro if (NULL == buf)
69255b0945b5SGregory Neil Shapiro return 0;
69265b0945b5SGregory Neil Shapiro
69275b0945b5SGregory Neil Shapiro errno = 0;
69285b0945b5SGregory Neil Shapiro ulval = strtoul(buf, &ep, 0);
69295b0945b5SGregory Neil Shapiro if (buf[0] == '\0' || *ep != '\0')
69305b0945b5SGregory Neil Shapiro return -1;
69315b0945b5SGregory Neil Shapiro if (errno == ERANGE && ulval == ULONG_MAX)
69325b0945b5SGregory Neil Shapiro return -1;
69335b0945b5SGregory Neil Shapiro if (ulval > USHRT_MAX)
69345b0945b5SGregory Neil Shapiro return -1;
69355b0945b5SGregory Neil Shapiro m->m_port = (unsigned short) ulval;
69365b0945b5SGregory Neil Shapiro if (tTd(17, 30))
69375b0945b5SGregory Neil Shapiro sm_dprintf("getmport: mailer=%s, port=%d\n", m->m_name,
69385b0945b5SGregory Neil Shapiro m->m_port);
69395b0945b5SGregory Neil Shapiro return m->m_port;
69405b0945b5SGregory Neil Shapiro }
69415b0945b5SGregory Neil Shapiro # define GETMPORT(m) getmport(m)
69425b0945b5SGregory Neil Shapiro #else /* DANE */
69435b0945b5SGregory Neil Shapiro # define GETMPORT(m) 25
69445b0945b5SGregory Neil Shapiro #endif /* DANE */
69455b0945b5SGregory Neil Shapiro
694640266059SGregory Neil Shapiro /*
6947*d39bd2c1SGregory Neil Shapiro ** HOSTSIGNATURE -- return the "signature" for a host (list).
6948c2aa98e2SPeter Wemm **
6949c2aa98e2SPeter Wemm ** The signature describes how we are going to send this -- it
6950c2aa98e2SPeter Wemm ** can be just the hostname (for non-Internet hosts) or can be
6951c2aa98e2SPeter Wemm ** an ordered list of MX hosts.
6952c2aa98e2SPeter Wemm **
6953c2aa98e2SPeter Wemm ** Parameters:
6954c2aa98e2SPeter Wemm ** m -- the mailer describing this host.
6955*d39bd2c1SGregory Neil Shapiro ** host -- the host name (can be a list).
6956*d39bd2c1SGregory Neil Shapiro ** ad -- DNSSEC: ad flag for lookup of host.
6957*d39bd2c1SGregory Neil Shapiro ** pqflags -- (pointer to) q_flags (can be NULL)
6958c2aa98e2SPeter Wemm **
6959c2aa98e2SPeter Wemm ** Returns:
6960c2aa98e2SPeter Wemm ** The signature for this host.
6961c2aa98e2SPeter Wemm **
6962c2aa98e2SPeter Wemm ** Side Effects:
6963c2aa98e2SPeter Wemm ** Can tweak the symbol table.
6964c2aa98e2SPeter Wemm */
696540266059SGregory Neil Shapiro
696606f25ae9SGregory Neil Shapiro #define MAXHOSTSIGNATURE 8192 /* max len of hostsignature */
6967c2aa98e2SPeter Wemm
696840266059SGregory Neil Shapiro char *
hostsignature(m,host,ad,pqflags)6969*d39bd2c1SGregory Neil Shapiro hostsignature(m, host, ad, pqflags)
6970c2aa98e2SPeter Wemm register MAILER *m;
6971c2aa98e2SPeter Wemm char *host;
69725b0945b5SGregory Neil Shapiro bool ad;
6973*d39bd2c1SGregory Neil Shapiro unsigned long *pqflags;
6974c2aa98e2SPeter Wemm {
6975c2aa98e2SPeter Wemm register char *p;
6976c2aa98e2SPeter Wemm register STAB *s;
697740266059SGregory Neil Shapiro time_t now;
697806f25ae9SGregory Neil Shapiro #if NAMED_BIND
697906f25ae9SGregory Neil Shapiro char sep = ':';
698006f25ae9SGregory Neil Shapiro char prevsep = ':';
6981c2aa98e2SPeter Wemm int i;
6982c2aa98e2SPeter Wemm int len;
6983c2aa98e2SPeter Wemm int nmx;
698406f25ae9SGregory Neil Shapiro int hl;
6985c2aa98e2SPeter Wemm char *hp;
6986c2aa98e2SPeter Wemm char *endp;
69872fb4f839SGregory Neil Shapiro char *lstr;
6988c2aa98e2SPeter Wemm int oldoptions = _res.options;
6989c2aa98e2SPeter Wemm char *mxhosts[MAXMXHOSTS + 1];
699040266059SGregory Neil Shapiro unsigned short mxprefs[MAXMXHOSTS + 1];
699106f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
6992*d39bd2c1SGregory Neil Shapiro int admx;
699306f25ae9SGregory Neil Shapiro
699406f25ae9SGregory Neil Shapiro if (tTd(17, 3))
6995*d39bd2c1SGregory Neil Shapiro sm_dprintf("hostsignature: host=%s, ad=%d\n", host, ad);
6996*d39bd2c1SGregory Neil Shapiro if (pqflags != NULL && !ad)
6997*d39bd2c1SGregory Neil Shapiro *pqflags &= ~QMXSECURE;
699806f25ae9SGregory Neil Shapiro
699906f25ae9SGregory Neil Shapiro /*
70008774250cSGregory Neil Shapiro ** If local delivery (and not remote), just return a constant.
700106f25ae9SGregory Neil Shapiro */
700206f25ae9SGregory Neil Shapiro
70038774250cSGregory Neil Shapiro if (bitnset(M_LOCALMAILER, m->m_flags) &&
700440266059SGregory Neil Shapiro strcmp(m->m_mailer, "[IPC]") != 0 &&
700540266059SGregory Neil Shapiro !(m->m_argv[0] != NULL && strcmp(m->m_argv[0], "TCP") == 0))
700606f25ae9SGregory Neil Shapiro return "localhost";
7007c2aa98e2SPeter Wemm
700813d88268SGregory Neil Shapiro /* an empty host does not have MX records */
700913d88268SGregory Neil Shapiro if (*host == '\0')
701013d88268SGregory Neil Shapiro return "_empty_";
701113d88268SGregory Neil Shapiro
7012c2aa98e2SPeter Wemm /*
7013c2aa98e2SPeter Wemm ** Check to see if this uses IPC -- if not, it can't have MX records.
7014c2aa98e2SPeter Wemm */
7015c2aa98e2SPeter Wemm
701640266059SGregory Neil Shapiro if (strcmp(m->m_mailer, "[IPC]") != 0 ||
701740266059SGregory Neil Shapiro CurEnv->e_sendmode == SM_DEFER)
7018c2aa98e2SPeter Wemm {
701940266059SGregory Neil Shapiro /* just an ordinary mailer or deferred mode */
7020c2aa98e2SPeter Wemm return host;
7021c2aa98e2SPeter Wemm }
702206f25ae9SGregory Neil Shapiro #if NETUNIX
702306f25ae9SGregory Neil Shapiro else if (m->m_argv[0] != NULL &&
702406f25ae9SGregory Neil Shapiro strcmp(m->m_argv[0], "FILE") == 0)
702506f25ae9SGregory Neil Shapiro {
702606f25ae9SGregory Neil Shapiro /* rendezvous in the file system, no MX records */
702706f25ae9SGregory Neil Shapiro return host;
702806f25ae9SGregory Neil Shapiro }
702906f25ae9SGregory Neil Shapiro #endif /* NETUNIX */
7030c2aa98e2SPeter Wemm
7031c2aa98e2SPeter Wemm /*
7032c2aa98e2SPeter Wemm ** Look it up in the symbol table.
7033c2aa98e2SPeter Wemm */
7034c2aa98e2SPeter Wemm
703540266059SGregory Neil Shapiro now = curtime();
7036c2aa98e2SPeter Wemm s = stab(host, ST_HOSTSIG, ST_ENTER);
703740266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL)
703840266059SGregory Neil Shapiro {
703940266059SGregory Neil Shapiro if (s->s_hostsig.hs_exp >= now)
704006f25ae9SGregory Neil Shapiro {
704106f25ae9SGregory Neil Shapiro if (tTd(17, 3))
7042*d39bd2c1SGregory Neil Shapiro sm_dprintf("hostsignature: stab(%s) found %s\n", host,
704340266059SGregory Neil Shapiro s->s_hostsig.hs_sig);
704440266059SGregory Neil Shapiro return s->s_hostsig.hs_sig;
704506f25ae9SGregory Neil Shapiro }
7046c2aa98e2SPeter Wemm
704740266059SGregory Neil Shapiro /* signature is expired: clear it */
704840266059SGregory Neil Shapiro sm_free(s->s_hostsig.hs_sig);
704940266059SGregory Neil Shapiro s->s_hostsig.hs_sig = NULL;
705040266059SGregory Neil Shapiro }
705140266059SGregory Neil Shapiro
705240266059SGregory Neil Shapiro /* set default TTL */
705340266059SGregory Neil Shapiro s->s_hostsig.hs_exp = now + SM_DEFAULT_TTL;
705440266059SGregory Neil Shapiro
7055c2aa98e2SPeter Wemm /*
705640266059SGregory Neil Shapiro ** Not already there or expired -- create a signature.
7057c2aa98e2SPeter Wemm */
7058c2aa98e2SPeter Wemm
7059c2aa98e2SPeter Wemm #if NAMED_BIND
7060c2aa98e2SPeter Wemm if (ConfigLevel < 2)
7061c2aa98e2SPeter Wemm _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */
7062c2aa98e2SPeter Wemm
7063c2aa98e2SPeter Wemm for (hp = host; hp != NULL; hp = endp)
7064c2aa98e2SPeter Wemm {
706506f25ae9SGregory Neil Shapiro # if NETINET6
706606f25ae9SGregory Neil Shapiro if (*hp == '[')
706706f25ae9SGregory Neil Shapiro {
706806f25ae9SGregory Neil Shapiro endp = strchr(hp + 1, ']');
7069c2aa98e2SPeter Wemm if (endp != NULL)
707006f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,");
707106f25ae9SGregory Neil Shapiro }
707206f25ae9SGregory Neil Shapiro else
707306f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,");
707406f25ae9SGregory Neil Shapiro # else /* NETINET6 */
707506f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,");
707606f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
707706f25ae9SGregory Neil Shapiro if (endp != NULL)
707806f25ae9SGregory Neil Shapiro {
707906f25ae9SGregory Neil Shapiro sep = *endp;
7080c2aa98e2SPeter Wemm *endp = '\0';
708106f25ae9SGregory Neil Shapiro }
7082c2aa98e2SPeter Wemm
7083c2aa98e2SPeter Wemm if (bitnset(M_NOMX, m->m_flags))
7084c2aa98e2SPeter Wemm {
7085c2aa98e2SPeter Wemm /* skip MX lookups */
7086c2aa98e2SPeter Wemm nmx = 1;
7087c2aa98e2SPeter Wemm mxhosts[0] = hp;
7088c2aa98e2SPeter Wemm }
7089c2aa98e2SPeter Wemm else
7090c2aa98e2SPeter Wemm {
7091c2aa98e2SPeter Wemm auto int rcode;
709240266059SGregory Neil Shapiro int ttl;
7093c2aa98e2SPeter Wemm
7094*d39bd2c1SGregory Neil Shapiro admx = 0;
70955b0945b5SGregory Neil Shapiro nmx = getmxrr(hp, mxhosts, mxprefs,
7096*d39bd2c1SGregory Neil Shapiro DROPLOCALHOST|(ad ? ISAD :0)|
7097*d39bd2c1SGregory Neil Shapiro ((NULL == endp) ? TRYFALLBACK : 0),
7098*d39bd2c1SGregory Neil Shapiro &rcode, &ttl, GETMPORT(m), &admx);
7099c2aa98e2SPeter Wemm if (nmx <= 0)
7100c2aa98e2SPeter Wemm {
710113058a91SGregory Neil Shapiro int save_errno;
7102c2aa98e2SPeter Wemm register MCI *mci;
7103c2aa98e2SPeter Wemm
7104c2aa98e2SPeter Wemm /* update the connection info for this host */
710513058a91SGregory Neil Shapiro save_errno = errno;
7106c2aa98e2SPeter Wemm mci = mci_get(hp, m);
710713058a91SGregory Neil Shapiro mci->mci_errno = save_errno;
7108c2aa98e2SPeter Wemm mci->mci_herrno = h_errno;
7109193538b7SGregory Neil Shapiro mci->mci_lastuse = now;
71105b0945b5SGregory Neil Shapiro if (nmx == NULLMX)
71112fb4f839SGregory Neil Shapiro mci_setstat(mci, rcode, ESCNULLMXRCPT,
71122fb4f839SGregory Neil Shapiro ERRNULLMX);
71135b0945b5SGregory Neil Shapiro else if (rcode == EX_NOHOST)
711406f25ae9SGregory Neil Shapiro mci_setstat(mci, rcode, "5.1.2",
711506f25ae9SGregory Neil Shapiro "550 Host unknown");
711606f25ae9SGregory Neil Shapiro else
7117c2aa98e2SPeter Wemm mci_setstat(mci, rcode, NULL, NULL);
7118c2aa98e2SPeter Wemm
7119c2aa98e2SPeter Wemm /* use the original host name as signature */
7120c2aa98e2SPeter Wemm nmx = 1;
7121c2aa98e2SPeter Wemm mxhosts[0] = hp;
7122c2aa98e2SPeter Wemm }
7123*d39bd2c1SGregory Neil Shapiro
7124*d39bd2c1SGregory Neil Shapiro /*
7125*d39bd2c1SGregory Neil Shapiro ** NOTE: this sets QMXSECURE if the ad flags is set
7126*d39bd2c1SGregory Neil Shapiro ** for at least one host in the host list. XXX
7127*d39bd2c1SGregory Neil Shapiro */
7128*d39bd2c1SGregory Neil Shapiro
7129*d39bd2c1SGregory Neil Shapiro if (pqflags != NULL && admx)
7130*d39bd2c1SGregory Neil Shapiro *pqflags |= QMXSECURE;
713106f25ae9SGregory Neil Shapiro if (tTd(17, 3))
7132*d39bd2c1SGregory Neil Shapiro sm_dprintf("hostsignature: host=%s, getmxrr=%d, mxhosts[0]=%s, admx=%d\n",
7133*d39bd2c1SGregory Neil Shapiro hp, nmx, mxhosts[0], admx);
713440266059SGregory Neil Shapiro
713540266059SGregory Neil Shapiro /*
713640266059SGregory Neil Shapiro ** Set new TTL: we use only one!
713740266059SGregory Neil Shapiro ** We could try to use the minimum instead.
713840266059SGregory Neil Shapiro */
713940266059SGregory Neil Shapiro
714040266059SGregory Neil Shapiro s->s_hostsig.hs_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL);
7141c2aa98e2SPeter Wemm }
7142c2aa98e2SPeter Wemm
7143c2aa98e2SPeter Wemm len = 0;
7144c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++)
7145c2aa98e2SPeter Wemm len += strlen(mxhosts[i]) + 1;
714640266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL)
714740266059SGregory Neil Shapiro len += strlen(s->s_hostsig.hs_sig) + 1;
7148*d39bd2c1SGregory Neil Shapiro # if DANE && HSMARKS
7149*d39bd2c1SGregory Neil Shapiro if (admx && DANE_SEC(Dane))
7150*d39bd2c1SGregory Neil Shapiro len += nmx;
7151*d39bd2c1SGregory Neil Shapiro # endif
715240266059SGregory Neil Shapiro if (len < 0 || len >= MAXHOSTSIGNATURE)
715306f25ae9SGregory Neil Shapiro {
715406f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, "hostsignature for host '%s' exceeds maxlen (%d): %d",
715506f25ae9SGregory Neil Shapiro host, MAXHOSTSIGNATURE, len);
715606f25ae9SGregory Neil Shapiro len = MAXHOSTSIGNATURE;
715706f25ae9SGregory Neil Shapiro }
715840266059SGregory Neil Shapiro p = sm_pmalloc_x(len);
715940266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL)
7160c2aa98e2SPeter Wemm {
716140266059SGregory Neil Shapiro (void) sm_strlcpy(p, s->s_hostsig.hs_sig, len);
716240266059SGregory Neil Shapiro sm_free(s->s_hostsig.hs_sig); /* XXX */
716340266059SGregory Neil Shapiro s->s_hostsig.hs_sig = p;
716406f25ae9SGregory Neil Shapiro hl = strlen(p);
716506f25ae9SGregory Neil Shapiro p += hl;
716606f25ae9SGregory Neil Shapiro *p++ = prevsep;
716706f25ae9SGregory Neil Shapiro len -= hl + 1;
7168c2aa98e2SPeter Wemm }
7169c2aa98e2SPeter Wemm else
717040266059SGregory Neil Shapiro s->s_hostsig.hs_sig = p;
7171c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++)
7172c2aa98e2SPeter Wemm {
717306f25ae9SGregory Neil Shapiro hl = strlen(mxhosts[i]);
7174*d39bd2c1SGregory Neil Shapiro if (len <= 1 ||
7175*d39bd2c1SGregory Neil Shapiro # if DANE && HSMARKS
7176*d39bd2c1SGregory Neil Shapiro len - 1 < (hl + ((admx && DANE_SEC(Dane)) ? 1 : 0))
7177*d39bd2c1SGregory Neil Shapiro # else
7178*d39bd2c1SGregory Neil Shapiro len - 1 < hl
7179*d39bd2c1SGregory Neil Shapiro # endif
7180*d39bd2c1SGregory Neil Shapiro )
718106f25ae9SGregory Neil Shapiro {
718206f25ae9SGregory Neil Shapiro /* force to drop out of outer loop */
718306f25ae9SGregory Neil Shapiro len = -1;
718406f25ae9SGregory Neil Shapiro break;
7185c2aa98e2SPeter Wemm }
718606f25ae9SGregory Neil Shapiro if (i != 0)
718706f25ae9SGregory Neil Shapiro {
718806f25ae9SGregory Neil Shapiro if (mxprefs[i] == mxprefs[i - 1])
718906f25ae9SGregory Neil Shapiro *p++ = ',';
719006f25ae9SGregory Neil Shapiro else
719106f25ae9SGregory Neil Shapiro *p++ = ':';
719206f25ae9SGregory Neil Shapiro len--;
719306f25ae9SGregory Neil Shapiro }
7194*d39bd2c1SGregory Neil Shapiro # if DANE && HSMARKS
7195*d39bd2c1SGregory Neil Shapiro if (admx && DANE_SEC(Dane))
7196*d39bd2c1SGregory Neil Shapiro {
7197*d39bd2c1SGregory Neil Shapiro *p++ = HSM_AD;
7198*d39bd2c1SGregory Neil Shapiro len--;
7199*d39bd2c1SGregory Neil Shapiro }
7200*d39bd2c1SGregory Neil Shapiro # endif
720140266059SGregory Neil Shapiro (void) sm_strlcpy(p, mxhosts[i], len);
720206f25ae9SGregory Neil Shapiro p += hl;
720306f25ae9SGregory Neil Shapiro len -= hl;
720406f25ae9SGregory Neil Shapiro }
720506f25ae9SGregory Neil Shapiro
720606f25ae9SGregory Neil Shapiro /*
720706f25ae9SGregory Neil Shapiro ** break out of loop if len exceeded MAXHOSTSIGNATURE
720806f25ae9SGregory Neil Shapiro ** because we won't have more space for further hosts
720906f25ae9SGregory Neil Shapiro ** anyway (separated by : in the .cf file).
721006f25ae9SGregory Neil Shapiro */
721106f25ae9SGregory Neil Shapiro
721206f25ae9SGregory Neil Shapiro if (len < 0)
721306f25ae9SGregory Neil Shapiro break;
7214c2aa98e2SPeter Wemm if (endp != NULL)
721506f25ae9SGregory Neil Shapiro *endp++ = sep;
721606f25ae9SGregory Neil Shapiro prevsep = sep;
7217c2aa98e2SPeter Wemm }
72182fb4f839SGregory Neil Shapiro lstr = makelower_a(&s->s_hostsig.hs_sig, NULL);
72192fb4f839SGregory Neil Shapiro ASSIGN_IFDIFF(s->s_hostsig.hs_sig, lstr);
7220c2aa98e2SPeter Wemm if (ConfigLevel < 2)
7221c2aa98e2SPeter Wemm _res.options = oldoptions;
722206f25ae9SGregory Neil Shapiro #else /* NAMED_BIND */
7223c2aa98e2SPeter Wemm /* not using BIND -- the signature is just the host name */
722440266059SGregory Neil Shapiro /*
722540266059SGregory Neil Shapiro ** 'host' points to storage that will be freed after we are
722640266059SGregory Neil Shapiro ** done processing the current envelope, so we copy it.
722740266059SGregory Neil Shapiro */
722840266059SGregory Neil Shapiro s->s_hostsig.hs_sig = sm_pstrdup_x(host);
722906f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */
7230c2aa98e2SPeter Wemm if (tTd(17, 1))
7231*d39bd2c1SGregory Neil Shapiro sm_dprintf("hostsignature: host=%s, result=%s\n", host, s->s_hostsig.hs_sig);
723240266059SGregory Neil Shapiro return s->s_hostsig.hs_sig;
7233c2aa98e2SPeter Wemm }
7234*d39bd2c1SGregory Neil Shapiro
723540266059SGregory Neil Shapiro /*
723606f25ae9SGregory Neil Shapiro ** PARSE_HOSTSIGNATURE -- parse the "signature" and return MX host array.
723706f25ae9SGregory Neil Shapiro **
723806f25ae9SGregory Neil Shapiro ** The signature describes how we are going to send this -- it
723906f25ae9SGregory Neil Shapiro ** can be just the hostname (for non-Internet hosts) or can be
724006f25ae9SGregory Neil Shapiro ** an ordered list of MX hosts which must be randomized for equal
724106f25ae9SGregory Neil Shapiro ** MX preference values.
724206f25ae9SGregory Neil Shapiro **
724306f25ae9SGregory Neil Shapiro ** Parameters:
724406f25ae9SGregory Neil Shapiro ** sig -- the host signature.
724506f25ae9SGregory Neil Shapiro ** mxhosts -- array to populate.
724640266059SGregory Neil Shapiro ** mailer -- mailer.
724706f25ae9SGregory Neil Shapiro **
724806f25ae9SGregory Neil Shapiro ** Returns:
724906f25ae9SGregory Neil Shapiro ** The number of hosts inserted into mxhosts array.
725006f25ae9SGregory Neil Shapiro **
7251*d39bd2c1SGregory Neil Shapiro ** NOTES:
7252*d39bd2c1SGregory Neil Shapiro ** mxhosts must have at least MAXMXHOSTS entries
7253*d39bd2c1SGregory Neil Shapiro ** mxhosts[] will point to elements in sig --
7254*d39bd2c1SGregory Neil Shapiro ** hence any changes to mxhosts[] will modify sig!
7255*d39bd2c1SGregory Neil Shapiro **
725606f25ae9SGregory Neil Shapiro ** Side Effects:
725706f25ae9SGregory Neil Shapiro ** Randomizes equal MX preference hosts in mxhosts.
725806f25ae9SGregory Neil Shapiro */
725906f25ae9SGregory Neil Shapiro
726006f25ae9SGregory Neil Shapiro static int
parse_hostsignature(sig,mxhosts,mailer,mxads)7261*d39bd2c1SGregory Neil Shapiro parse_hostsignature(sig, mxhosts, mailer
7262*d39bd2c1SGregory Neil Shapiro #if DANE
7263*d39bd2c1SGregory Neil Shapiro , mxads
7264*d39bd2c1SGregory Neil Shapiro #endif
7265*d39bd2c1SGregory Neil Shapiro )
726606f25ae9SGregory Neil Shapiro char *sig;
726706f25ae9SGregory Neil Shapiro char **mxhosts;
726806f25ae9SGregory Neil Shapiro MAILER *mailer;
7269*d39bd2c1SGregory Neil Shapiro #if DANE
7270*d39bd2c1SGregory Neil Shapiro BITMAP256 mxads;
7271*d39bd2c1SGregory Neil Shapiro #endif
727206f25ae9SGregory Neil Shapiro {
727340266059SGregory Neil Shapiro unsigned short curpref = 0;
727440266059SGregory Neil Shapiro int nmx = 0, i, j; /* NOTE: i, j, and nmx must have same type */
727506f25ae9SGregory Neil Shapiro char *hp, *endp;
727640266059SGregory Neil Shapiro unsigned short prefer[MAXMXHOSTS];
727706f25ae9SGregory Neil Shapiro long rndm[MAXMXHOSTS];
727806f25ae9SGregory Neil Shapiro
7279*d39bd2c1SGregory Neil Shapiro #if DANE
7280*d39bd2c1SGregory Neil Shapiro clrbitmap(mxads);
7281*d39bd2c1SGregory Neil Shapiro #endif
728206f25ae9SGregory Neil Shapiro for (hp = sig; hp != NULL; hp = endp)
728306f25ae9SGregory Neil Shapiro {
728406f25ae9SGregory Neil Shapiro char sep = ':';
728506f25ae9SGregory Neil Shapiro
7286*d39bd2c1SGregory Neil Shapiro FIX_MXHOSTS(hp, endp, sep);
7287*d39bd2c1SGregory Neil Shapiro #if HSMARKS
7288*d39bd2c1SGregory Neil Shapiro if (HSM_AD == *hp)
728906f25ae9SGregory Neil Shapiro {
7290*d39bd2c1SGregory Neil Shapiro MXADS_SET(mxads, nmx);
7291*d39bd2c1SGregory Neil Shapiro mxhosts[nmx] = hp + 1;
729206f25ae9SGregory Neil Shapiro }
729306f25ae9SGregory Neil Shapiro else
7294*d39bd2c1SGregory Neil Shapiro #endif
729506f25ae9SGregory Neil Shapiro mxhosts[nmx] = hp;
729606f25ae9SGregory Neil Shapiro prefer[nmx] = curpref;
729706f25ae9SGregory Neil Shapiro if (mci_match(hp, mailer))
729806f25ae9SGregory Neil Shapiro rndm[nmx] = 0;
729906f25ae9SGregory Neil Shapiro else
730006f25ae9SGregory Neil Shapiro rndm[nmx] = get_random();
730106f25ae9SGregory Neil Shapiro
730206f25ae9SGregory Neil Shapiro if (endp != NULL)
730306f25ae9SGregory Neil Shapiro {
730406f25ae9SGregory Neil Shapiro /*
730506f25ae9SGregory Neil Shapiro ** Since we don't have the original MX prefs,
730606f25ae9SGregory Neil Shapiro ** make our own. If the separator is a ':', that
730706f25ae9SGregory Neil Shapiro ** means the preference for the next host will be
730806f25ae9SGregory Neil Shapiro ** higher than this one, so simply increment curpref.
730906f25ae9SGregory Neil Shapiro */
731006f25ae9SGregory Neil Shapiro
731106f25ae9SGregory Neil Shapiro if (sep == ':')
731206f25ae9SGregory Neil Shapiro curpref++;
731306f25ae9SGregory Neil Shapiro
731406f25ae9SGregory Neil Shapiro *endp++ = sep;
731506f25ae9SGregory Neil Shapiro }
731606f25ae9SGregory Neil Shapiro if (++nmx >= MAXMXHOSTS)
731706f25ae9SGregory Neil Shapiro break;
731806f25ae9SGregory Neil Shapiro }
731906f25ae9SGregory Neil Shapiro
732006f25ae9SGregory Neil Shapiro /* sort the records using the random factor for equal preferences */
732106f25ae9SGregory Neil Shapiro for (i = 0; i < nmx; i++)
732206f25ae9SGregory Neil Shapiro {
732306f25ae9SGregory Neil Shapiro for (j = i + 1; j < nmx; j++)
732406f25ae9SGregory Neil Shapiro {
732506f25ae9SGregory Neil Shapiro /*
732606f25ae9SGregory Neil Shapiro ** List is already sorted by MX preference, only
732706f25ae9SGregory Neil Shapiro ** need to look for equal preference MX records
732806f25ae9SGregory Neil Shapiro */
732906f25ae9SGregory Neil Shapiro
733006f25ae9SGregory Neil Shapiro if (prefer[i] < prefer[j])
733106f25ae9SGregory Neil Shapiro break;
733206f25ae9SGregory Neil Shapiro
733306f25ae9SGregory Neil Shapiro if (prefer[i] > prefer[j] ||
733406f25ae9SGregory Neil Shapiro (prefer[i] == prefer[j] && rndm[i] > rndm[j]))
733506f25ae9SGregory Neil Shapiro {
733640266059SGregory Neil Shapiro register unsigned short tempp;
733706f25ae9SGregory Neil Shapiro register long tempr;
733806f25ae9SGregory Neil Shapiro register char *temp1;
733906f25ae9SGregory Neil Shapiro
734006f25ae9SGregory Neil Shapiro tempp = prefer[i];
734106f25ae9SGregory Neil Shapiro prefer[i] = prefer[j];
734206f25ae9SGregory Neil Shapiro prefer[j] = tempp;
734306f25ae9SGregory Neil Shapiro temp1 = mxhosts[i];
734406f25ae9SGregory Neil Shapiro mxhosts[i] = mxhosts[j];
734506f25ae9SGregory Neil Shapiro mxhosts[j] = temp1;
734606f25ae9SGregory Neil Shapiro tempr = rndm[i];
734706f25ae9SGregory Neil Shapiro rndm[i] = rndm[j];
734806f25ae9SGregory Neil Shapiro rndm[j] = tempr;
734906f25ae9SGregory Neil Shapiro }
735006f25ae9SGregory Neil Shapiro }
735106f25ae9SGregory Neil Shapiro }
735206f25ae9SGregory Neil Shapiro return nmx;
735306f25ae9SGregory Neil Shapiro }
735406f25ae9SGregory Neil Shapiro
735506f25ae9SGregory Neil Shapiro #if STARTTLS
735606f25ae9SGregory Neil Shapiro static SSL_CTX *clt_ctx = NULL;
735740266059SGregory Neil Shapiro static bool tls_ok_clt = true;
7358*d39bd2c1SGregory Neil Shapiro # if DANE
7359*d39bd2c1SGregory Neil Shapiro static bool ctx_dane_enabled = false;
7360*d39bd2c1SGregory Neil Shapiro # endif
736106f25ae9SGregory Neil Shapiro
736240266059SGregory Neil Shapiro /*
736340266059SGregory Neil Shapiro ** SETCLTTLS -- client side TLS: allow/disallow.
736440266059SGregory Neil Shapiro **
736540266059SGregory Neil Shapiro ** Parameters:
736640266059SGregory Neil Shapiro ** tls_ok -- should tls be done?
736740266059SGregory Neil Shapiro **
736840266059SGregory Neil Shapiro ** Returns:
736940266059SGregory Neil Shapiro ** none.
737040266059SGregory Neil Shapiro **
737140266059SGregory Neil Shapiro ** Side Effects:
737240266059SGregory Neil Shapiro ** sets tls_ok_clt (static variable in this module)
737340266059SGregory Neil Shapiro */
737440266059SGregory Neil Shapiro
737540266059SGregory Neil Shapiro void
setclttls(tls_ok)737640266059SGregory Neil Shapiro setclttls(tls_ok)
737740266059SGregory Neil Shapiro bool tls_ok;
737840266059SGregory Neil Shapiro {
737940266059SGregory Neil Shapiro tls_ok_clt = tls_ok;
738040266059SGregory Neil Shapiro return;
738140266059SGregory Neil Shapiro }
7382*d39bd2c1SGregory Neil Shapiro
738340266059SGregory Neil Shapiro /*
738406f25ae9SGregory Neil Shapiro ** INITCLTTLS -- initialize client side TLS
738506f25ae9SGregory Neil Shapiro **
738606f25ae9SGregory Neil Shapiro ** Parameters:
7387*d39bd2c1SGregory Neil Shapiro ** tls_ok -- should TLS initialization be done?
738806f25ae9SGregory Neil Shapiro **
738906f25ae9SGregory Neil Shapiro ** Returns:
739006f25ae9SGregory Neil Shapiro ** succeeded?
739140266059SGregory Neil Shapiro **
739240266059SGregory Neil Shapiro ** Side Effects:
7393*d39bd2c1SGregory Neil Shapiro ** sets tls_ok_clt, ctx_dane_enabled (static variables
7394*d39bd2c1SGregory Neil Shapiro ** in this module)
739506f25ae9SGregory Neil Shapiro */
739606f25ae9SGregory Neil Shapiro
739706f25ae9SGregory Neil Shapiro bool
initclttls(tls_ok)739840266059SGregory Neil Shapiro initclttls(tls_ok)
739940266059SGregory Neil Shapiro bool tls_ok;
740006f25ae9SGregory Neil Shapiro {
740140266059SGregory Neil Shapiro if (!tls_ok_clt)
740240266059SGregory Neil Shapiro return false;
740340266059SGregory Neil Shapiro tls_ok_clt = tls_ok;
740440266059SGregory Neil Shapiro if (!tls_ok_clt)
740540266059SGregory Neil Shapiro return false;
740606f25ae9SGregory Neil Shapiro if (clt_ctx != NULL)
740740266059SGregory Neil Shapiro return true; /* already done */
74089bd497b8SGregory Neil Shapiro tls_ok_clt = inittls(&clt_ctx, TLS_I_CLT, Clt_SSL_Options, false,
74099bd497b8SGregory Neil Shapiro CltCertFile, CltKeyFile,
74105b0945b5SGregory Neil Shapiro # if _FFR_CLIENTCA
74115b0945b5SGregory Neil Shapiro (CltCACertPath != NULL) ? CltCACertPath :
74125b0945b5SGregory Neil Shapiro # endif
74135b0945b5SGregory Neil Shapiro CACertPath,
74145b0945b5SGregory Neil Shapiro # if _FFR_CLIENTCA
74155b0945b5SGregory Neil Shapiro (CltCACertFile != NULL) ? CltCACertFile :
74165b0945b5SGregory Neil Shapiro # endif
74175b0945b5SGregory Neil Shapiro CACertFile,
74185b0945b5SGregory Neil Shapiro DHParams);
7419*d39bd2c1SGregory Neil Shapiro # if _FFR_TESTS
7420*d39bd2c1SGregory Neil Shapiro if (tls_ok_clt && tTd(90, 104))
7421*d39bd2c1SGregory Neil Shapiro {
7422*d39bd2c1SGregory Neil Shapiro sm_dprintf("test=simulate initclttls error\n");
7423*d39bd2c1SGregory Neil Shapiro tls_ok_clt = false;
7424*d39bd2c1SGregory Neil Shapiro }
7425*d39bd2c1SGregory Neil Shapiro # endif /* _FFR_TESTS */
7426*d39bd2c1SGregory Neil Shapiro # if DANE
7427*d39bd2c1SGregory Neil Shapiro if (tls_ok_clt && CHK_DANE(Dane))
7428*d39bd2c1SGregory Neil Shapiro {
7429*d39bd2c1SGregory Neil Shapiro # if HAVE_SSL_CTX_dane_enable
7430*d39bd2c1SGregory Neil Shapiro int r;
7431*d39bd2c1SGregory Neil Shapiro
7432*d39bd2c1SGregory Neil Shapiro r = SSL_CTX_dane_enable(clt_ctx);
7433*d39bd2c1SGregory Neil Shapiro # if _FFR_TESTS
7434*d39bd2c1SGregory Neil Shapiro if (tTd(90, 103))
7435*d39bd2c1SGregory Neil Shapiro {
7436*d39bd2c1SGregory Neil Shapiro sm_dprintf("test=simulate SSL_CTX_dane_enable error\n");
7437*d39bd2c1SGregory Neil Shapiro # if defined(SSL_F_DANE_CTX_ENABLE)
7438*d39bd2c1SGregory Neil Shapiro SSLerr(SSL_F_DANE_CTX_ENABLE, ERR_R_MALLOC_FAILURE);
7439*d39bd2c1SGregory Neil Shapiro # endif
7440*d39bd2c1SGregory Neil Shapiro r = -1;
7441*d39bd2c1SGregory Neil Shapiro }
7442*d39bd2c1SGregory Neil Shapiro # endif /* _FFR_TESTS */
7443*d39bd2c1SGregory Neil Shapiro ctx_dane_enabled = (r > 0);
7444*d39bd2c1SGregory Neil Shapiro if (r <= 0)
7445*d39bd2c1SGregory Neil Shapiro {
7446*d39bd2c1SGregory Neil Shapiro if (LogLevel > 1)
7447*d39bd2c1SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
7448*d39bd2c1SGregory Neil Shapiro "SSL_CTX_dane_enable=%d", r);
7449*d39bd2c1SGregory Neil Shapiro tlslogerr(LOG_ERR, 7, "init_client");
7450*d39bd2c1SGregory Neil Shapiro }
7451*d39bd2c1SGregory Neil Shapiro else if (LogLevel > 13)
7452*d39bd2c1SGregory Neil Shapiro sm_syslog(LOG_DEBUG, NOQID,
7453*d39bd2c1SGregory Neil Shapiro "SSL_CTX_dane_enable=%d", r);
7454*d39bd2c1SGregory Neil Shapiro # else
7455*d39bd2c1SGregory Neil Shapiro ctx_dane_enabled = false;
7456*d39bd2c1SGregory Neil Shapiro # endif /* HAVE_SSL_CTX_dane_enable */
7457*d39bd2c1SGregory Neil Shapiro }
7458*d39bd2c1SGregory Neil Shapiro if (tTd(90, 90))
7459*d39bd2c1SGregory Neil Shapiro sm_dprintf("func=initclttls, ctx_dane_enabled=%d\n", ctx_dane_enabled);
7460*d39bd2c1SGregory Neil Shapiro # endif /* DANE */
7461*d39bd2c1SGregory Neil Shapiro
746240266059SGregory Neil Shapiro return tls_ok_clt;
746306f25ae9SGregory Neil Shapiro }
746406f25ae9SGregory Neil Shapiro
746540266059SGregory Neil Shapiro /*
746606f25ae9SGregory Neil Shapiro ** STARTTLS -- try to start secure connection (client side)
746706f25ae9SGregory Neil Shapiro **
746806f25ae9SGregory Neil Shapiro ** Parameters:
746906f25ae9SGregory Neil Shapiro ** m -- the mailer.
747006f25ae9SGregory Neil Shapiro ** mci -- the mailer connection info.
747106f25ae9SGregory Neil Shapiro ** e -- the envelope.
7472*d39bd2c1SGregory Neil Shapiro ** implicit -- implicit TLS (SMTP over TLS, no STARTTLS command)
747306f25ae9SGregory Neil Shapiro **
747406f25ae9SGregory Neil Shapiro ** Returns:
747506f25ae9SGregory Neil Shapiro ** success?
747606f25ae9SGregory Neil Shapiro ** (maybe this should be some other code than EX_
747706f25ae9SGregory Neil Shapiro ** that denotes which stage failed.)
747806f25ae9SGregory Neil Shapiro */
747906f25ae9SGregory Neil Shapiro
748006f25ae9SGregory Neil Shapiro static int
starttls(m,mci,e,implicit,dane_vrfy_ctx)7481*d39bd2c1SGregory Neil Shapiro starttls(m, mci, e, implicit
74825b0945b5SGregory Neil Shapiro # if DANE
74835b0945b5SGregory Neil Shapiro , dane_vrfy_ctx
74845b0945b5SGregory Neil Shapiro # endif
74855b0945b5SGregory Neil Shapiro )
748606f25ae9SGregory Neil Shapiro MAILER *m;
748706f25ae9SGregory Neil Shapiro MCI *mci;
748806f25ae9SGregory Neil Shapiro ENVELOPE *e;
7489*d39bd2c1SGregory Neil Shapiro bool implicit;
74905b0945b5SGregory Neil Shapiro # if DANE
74915b0945b5SGregory Neil Shapiro dane_vrfy_ctx_P dane_vrfy_ctx;
74925b0945b5SGregory Neil Shapiro # endif
749306f25ae9SGregory Neil Shapiro {
749406f25ae9SGregory Neil Shapiro int smtpresult;
749542e5d165SGregory Neil Shapiro int result = 0;
74962fb4f839SGregory Neil Shapiro int ret = EX_OK;
749742e5d165SGregory Neil Shapiro int rfd, wfd;
749806f25ae9SGregory Neil Shapiro SSL *clt_ssl = NULL;
749940266059SGregory Neil Shapiro time_t tlsstart;
75005b0945b5SGregory Neil Shapiro extern int TLSsslidx;
750106f25ae9SGregory Neil Shapiro
7502*d39bd2c1SGregory Neil Shapiro # if DANE
7503*d39bd2c1SGregory Neil Shapiro if (TTD(90, 60))
7504*d39bd2c1SGregory Neil Shapiro sm_dprintf("starttls=client: Dane=%d, dane_vrfy_chk=%#x\n",
7505*d39bd2c1SGregory Neil Shapiro Dane,dane_vrfy_ctx->dane_vrfy_chk);
7506*d39bd2c1SGregory Neil Shapiro # endif
750740266059SGregory Neil Shapiro if (clt_ctx == NULL && !initclttls(true))
750842e5d165SGregory Neil Shapiro return EX_TEMPFAIL;
75099bd497b8SGregory Neil Shapiro
75105b0945b5SGregory Neil Shapiro if (!TLS_set_engine(SSLEngine, false))
75119bd497b8SGregory Neil Shapiro {
75129bd497b8SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
75135b0945b5SGregory Neil Shapiro "STARTTLS=client, engine=%s, TLS_set_engine=failed",
75145b0945b5SGregory Neil Shapiro SSLEngine);
75159bd497b8SGregory Neil Shapiro return EX_TEMPFAIL;
75169bd497b8SGregory Neil Shapiro }
75179bd497b8SGregory Neil Shapiro
75182fb4f839SGregory Neil Shapiro /* clt_ssl needed for get_tls_se_features() hence create here */
751906f25ae9SGregory Neil Shapiro if ((clt_ssl = SSL_new(clt_ctx)) == NULL)
752006f25ae9SGregory Neil Shapiro {
752106f25ae9SGregory Neil Shapiro if (LogLevel > 5)
752206f25ae9SGregory Neil Shapiro {
752340266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
752440266059SGregory Neil Shapiro "STARTTLS=client, error: SSL_new failed");
75255b0945b5SGregory Neil Shapiro tlslogerr(LOG_WARNING, 9, "client");
752606f25ae9SGregory Neil Shapiro }
7527*d39bd2c1SGregory Neil Shapiro return EX_TEMPFAIL;
752806f25ae9SGregory Neil Shapiro }
7529da7d7b9cSGregory Neil Shapiro
75302fb4f839SGregory Neil Shapiro ret = get_tls_se_features(e, clt_ssl, &mci->mci_tlsi, false);
75312fb4f839SGregory Neil Shapiro if (EX_OK != ret)
7532da7d7b9cSGregory Neil Shapiro {
7533da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
75342fb4f839SGregory Neil Shapiro "STARTTLS=client, get_tls_se_features=failed, ret=%d",
75352fb4f839SGregory Neil Shapiro ret);
75362fb4f839SGregory Neil Shapiro goto fail;
7537da7d7b9cSGregory Neil Shapiro }
75382fb4f839SGregory Neil Shapiro
7539*d39bd2c1SGregory Neil Shapiro if (!implicit)
7540*d39bd2c1SGregory Neil Shapiro {
75412fb4f839SGregory Neil Shapiro smtpmessage("STARTTLS", m, mci);
75422fb4f839SGregory Neil Shapiro
75432fb4f839SGregory Neil Shapiro /* get the reply */
75442fb4f839SGregory Neil Shapiro smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL,
7545*d39bd2c1SGregory Neil Shapiro XS_STARTTLS, NULL);
75462fb4f839SGregory Neil Shapiro
75472fb4f839SGregory Neil Shapiro /* check return code from server */
75482fb4f839SGregory Neil Shapiro if (REPLYTYPE(smtpresult) == 4)
75492fb4f839SGregory Neil Shapiro {
75502fb4f839SGregory Neil Shapiro ret = EX_TEMPFAIL;
75512fb4f839SGregory Neil Shapiro goto fail;
75522fb4f839SGregory Neil Shapiro }
7553*d39bd2c1SGregory Neil Shapiro #if 0
7554*d39bd2c1SGregory Neil Shapiro /*
7555*d39bd2c1SGregory Neil Shapiro ** RFC 3207 says
7556*d39bd2c1SGregory Neil Shapiro ** 501 Syntax error (no parameters allowed)
7557*d39bd2c1SGregory Neil Shapiro ** since sendmail does not use arguments, that's basically
7558*d39bd2c1SGregory Neil Shapiro ** a "cannot happen", hence treat it as any other 5xy,
7559*d39bd2c1SGregory Neil Shapiro ** which means it is also properly handled by the rules.
7560*d39bd2c1SGregory Neil Shapiro */
7561*d39bd2c1SGregory Neil Shapiro
75622fb4f839SGregory Neil Shapiro if (smtpresult == 501)
75632fb4f839SGregory Neil Shapiro {
75642fb4f839SGregory Neil Shapiro ret = EX_USAGE;
75652fb4f839SGregory Neil Shapiro goto fail;
75662fb4f839SGregory Neil Shapiro }
7567*d39bd2c1SGregory Neil Shapiro #endif /* 0 */
75682fb4f839SGregory Neil Shapiro if (smtpresult == -1)
75692fb4f839SGregory Neil Shapiro {
75702fb4f839SGregory Neil Shapiro ret = smtpresult;
75712fb4f839SGregory Neil Shapiro goto fail;
75722fb4f839SGregory Neil Shapiro }
75732fb4f839SGregory Neil Shapiro
75742fb4f839SGregory Neil Shapiro /* not an expected reply but we have to deal with it */
75752fb4f839SGregory Neil Shapiro if (REPLYTYPE(smtpresult) == 5)
75762fb4f839SGregory Neil Shapiro {
75772fb4f839SGregory Neil Shapiro ret = EX_UNAVAILABLE;
75782fb4f839SGregory Neil Shapiro goto fail;
75792fb4f839SGregory Neil Shapiro }
75802fb4f839SGregory Neil Shapiro if (smtpresult != 220)
75812fb4f839SGregory Neil Shapiro {
75822fb4f839SGregory Neil Shapiro ret = EX_PROTOCOL;
75832fb4f839SGregory Neil Shapiro goto fail;
75842fb4f839SGregory Neil Shapiro }
7585*d39bd2c1SGregory Neil Shapiro }
75862fb4f839SGregory Neil Shapiro
75872fb4f839SGregory Neil Shapiro if (LogLevel > 13)
75882fb4f839SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "STARTTLS=client, start=ok");
75892fb4f839SGregory Neil Shapiro
75902fb4f839SGregory Neil Shapiro /* SSL_clear(clt_ssl); ? */
75915b0945b5SGregory Neil Shapiro result = SSL_set_ex_data(clt_ssl, TLSsslidx, &mci->mci_tlsi);
75925b0945b5SGregory Neil Shapiro if (0 == result)
75935b0945b5SGregory Neil Shapiro {
75945b0945b5SGregory Neil Shapiro if (LogLevel > 5)
75955b0945b5SGregory Neil Shapiro {
75965b0945b5SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
75975b0945b5SGregory Neil Shapiro "STARTTLS=client, error: SSL_set_ex_data failed=%d, idx=%d",
75985b0945b5SGregory Neil Shapiro result, TLSsslidx);
75995b0945b5SGregory Neil Shapiro tlslogerr(LOG_WARNING, 9, "client");
76005b0945b5SGregory Neil Shapiro }
76012fb4f839SGregory Neil Shapiro goto fail;
76025b0945b5SGregory Neil Shapiro }
76035b0945b5SGregory Neil Shapiro # if DANE
76045b0945b5SGregory Neil Shapiro if (SM_TLSI_IS(&(mci->mci_tlsi), TLSI_FL_NODANE))
76055b0945b5SGregory Neil Shapiro dane_vrfy_ctx->dane_vrfy_chk = DANE_NEVER;
7606*d39bd2c1SGregory Neil Shapiro if (TTD(90, 60))
7607*d39bd2c1SGregory Neil Shapiro sm_dprintf("starttls=client: 2: dane_vrfy_chk=%#x CHK_DANE=%d\n",
7608*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx->dane_vrfy_chk,
7609*d39bd2c1SGregory Neil Shapiro CHK_DANE(dane_vrfy_ctx->dane_vrfy_chk));
7610*d39bd2c1SGregory Neil Shapiro if (CHK_DANE(dane_vrfy_ctx->dane_vrfy_chk))
76115b0945b5SGregory Neil Shapiro {
76125b0945b5SGregory Neil Shapiro int r;
76135b0945b5SGregory Neil Shapiro
76145b0945b5SGregory Neil Shapiro /* set SNI only if there is a TLSA RR */
7615*d39bd2c1SGregory Neil Shapiro if (tTd(90, 40))
7616*d39bd2c1SGregory Neil Shapiro sm_dprintf("dane_get_tlsa=%p, dane_vrfy_host=%s, dane_vrfy_sni=%s, ctx_dane_enabled=%d, dane_enabled=%d\n",
7617*d39bd2c1SGregory Neil Shapiro dane_get_tlsa(dane_vrfy_ctx),
7618*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx->dane_vrfy_host,
7619*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx->dane_vrfy_sni,
7620*d39bd2c1SGregory Neil Shapiro ctx_dane_enabled,
7621*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx->dane_vrfy_dane_enabled);
76225b0945b5SGregory Neil Shapiro if (dane_get_tlsa(dane_vrfy_ctx) != NULL &&
76235b0945b5SGregory Neil Shapiro !(SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_host) &&
76242fb4f839SGregory Neil Shapiro SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_sni)))
76252fb4f839SGregory Neil Shapiro {
76262fb4f839SGregory Neil Shapiro # if _FFR_MTA_STS
76272fb4f839SGregory Neil Shapiro SM_FREE(STS_SNI);
76282fb4f839SGregory Neil Shapiro # endif
7629*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx->dane_vrfy_dane_enabled = ctx_dane_enabled;
7630*d39bd2c1SGregory Neil Shapiro if ((r = ssl_dane_enable(dane_vrfy_ctx, clt_ssl)) < 0)
7631*d39bd2c1SGregory Neil Shapiro {
7632*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx->dane_vrfy_dane_enabled = false;
7633*d39bd2c1SGregory Neil Shapiro if (LogLevel > 5)
7634*d39bd2c1SGregory Neil Shapiro {
7635*d39bd2c1SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
7636*d39bd2c1SGregory Neil Shapiro "STARTTLS=client, host=%s, ssl_dane_enable=%d",
7637*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx->dane_vrfy_host, r);
7638*d39bd2c1SGregory Neil Shapiro }
7639*d39bd2c1SGregory Neil Shapiro }
7640*d39bd2c1SGregory Neil Shapiro if (SM_NOTDONE == r)
7641*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx->dane_vrfy_dane_enabled = false;
7642*d39bd2c1SGregory Neil Shapiro if (tTd(90, 40))
7643*d39bd2c1SGregory Neil Shapiro sm_dprintf("ssl_dane_enable=%d, chk=%#x, dane_enabled=%d\n",
7644*d39bd2c1SGregory Neil Shapiro r, dane_vrfy_ctx->dane_vrfy_chk,
7645*d39bd2c1SGregory Neil Shapiro dane_vrfy_ctx->dane_vrfy_dane_enabled);
76462fb4f839SGregory Neil Shapiro if ((r = SSL_set_tlsext_host_name(clt_ssl,
76475b0945b5SGregory Neil Shapiro (!SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_sni)
76485b0945b5SGregory Neil Shapiro ? dane_vrfy_ctx->dane_vrfy_sni
76495b0945b5SGregory Neil Shapiro : dane_vrfy_ctx->dane_vrfy_host))) <= 0)
76505b0945b5SGregory Neil Shapiro {
76515b0945b5SGregory Neil Shapiro if (LogLevel > 5)
76525b0945b5SGregory Neil Shapiro {
76535b0945b5SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
76545b0945b5SGregory Neil Shapiro "STARTTLS=client, host=%s, SSL_set_tlsext_host_name=%d",
76555b0945b5SGregory Neil Shapiro dane_vrfy_ctx->dane_vrfy_host, r);
76565b0945b5SGregory Neil Shapiro }
76575b0945b5SGregory Neil Shapiro tlslogerr(LOG_ERR, 5, "client");
76585b0945b5SGregory Neil Shapiro /* return EX_SOFTWARE; */
76595b0945b5SGregory Neil Shapiro }
76605b0945b5SGregory Neil Shapiro }
76612fb4f839SGregory Neil Shapiro }
76625b0945b5SGregory Neil Shapiro memcpy(&mci->mci_tlsi.tlsi_dvc, dane_vrfy_ctx, sizeof(*dane_vrfy_ctx));
76635b0945b5SGregory Neil Shapiro # endif /* DANE */
76642fb4f839SGregory Neil Shapiro # if _FFR_MTA_STS
76652fb4f839SGregory Neil Shapiro if (STS_SNI != NULL)
76662fb4f839SGregory Neil Shapiro {
76672fb4f839SGregory Neil Shapiro int r;
76682fb4f839SGregory Neil Shapiro
76692fb4f839SGregory Neil Shapiro if ((r = SSL_set_tlsext_host_name(clt_ssl, STS_SNI)) <= 0)
76702fb4f839SGregory Neil Shapiro {
76712fb4f839SGregory Neil Shapiro if (LogLevel > 5)
76722fb4f839SGregory Neil Shapiro {
76732fb4f839SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
76742fb4f839SGregory Neil Shapiro "STARTTLS=client, host=%s, SSL_set_tlsext_host_name=%d",
76752fb4f839SGregory Neil Shapiro STS_SNI, r);
76762fb4f839SGregory Neil Shapiro }
76772fb4f839SGregory Neil Shapiro tlslogerr(LOG_ERR, 5, "client");
76782fb4f839SGregory Neil Shapiro /* return EX_SOFTWARE; */
76792fb4f839SGregory Neil Shapiro }
76802fb4f839SGregory Neil Shapiro }
76812fb4f839SGregory Neil Shapiro # endif /* _FFR_MTA_STS */
768206f25ae9SGregory Neil Shapiro
768340266059SGregory Neil Shapiro rfd = sm_io_getinfo(mci->mci_in, SM_IO_WHAT_FD, NULL);
768440266059SGregory Neil Shapiro wfd = sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, NULL);
768542e5d165SGregory Neil Shapiro
768642e5d165SGregory Neil Shapiro if (rfd < 0 || wfd < 0 ||
768740266059SGregory Neil Shapiro (result = SSL_set_rfd(clt_ssl, rfd)) != 1 ||
768840266059SGregory Neil Shapiro (result = SSL_set_wfd(clt_ssl, wfd)) != 1)
768906f25ae9SGregory Neil Shapiro {
769006f25ae9SGregory Neil Shapiro if (LogLevel > 5)
769106f25ae9SGregory Neil Shapiro {
769240266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
769340266059SGregory Neil Shapiro "STARTTLS=client, error: SSL_set_xfd failed=%d",
769440266059SGregory Neil Shapiro result);
76955b0945b5SGregory Neil Shapiro tlslogerr(LOG_WARNING, 9, "client");
769606f25ae9SGregory Neil Shapiro }
76972fb4f839SGregory Neil Shapiro goto fail;
769806f25ae9SGregory Neil Shapiro }
769906f25ae9SGregory Neil Shapiro SSL_set_connect_state(clt_ssl);
770040266059SGregory Neil Shapiro tlsstart = curtime();
770140266059SGregory Neil Shapiro
770240266059SGregory Neil Shapiro ssl_retry:
770306f25ae9SGregory Neil Shapiro if ((result = SSL_connect(clt_ssl)) <= 0)
770406f25ae9SGregory Neil Shapiro {
77054e4196cbSGregory Neil Shapiro int i, ssl_err;
7706da7d7b9cSGregory Neil Shapiro int save_errno = errno;
770706f25ae9SGregory Neil Shapiro
77084e4196cbSGregory Neil Shapiro ssl_err = SSL_get_error(clt_ssl, result);
77094e4196cbSGregory Neil Shapiro i = tls_retry(clt_ssl, rfd, wfd, tlsstart,
77104e4196cbSGregory Neil Shapiro TimeOuts.to_starttls, ssl_err, "client");
77114e4196cbSGregory Neil Shapiro if (i > 0)
77124e4196cbSGregory Neil Shapiro goto ssl_retry;
771340266059SGregory Neil Shapiro
771413bd1963SGregory Neil Shapiro if (LogLevel > 5)
771513bd1963SGregory Neil Shapiro {
7716ba00ec3dSGregory Neil Shapiro unsigned long l;
7717ba00ec3dSGregory Neil Shapiro const char *sr;
7718ba00ec3dSGregory Neil Shapiro
7719ba00ec3dSGregory Neil Shapiro l = ERR_peek_error();
7720ba00ec3dSGregory Neil Shapiro sr = ERR_reason_error_string(l);
77214e4196cbSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
7722ba00ec3dSGregory Neil Shapiro "STARTTLS=client, error: connect failed=%d, reason=%s, SSL_error=%d, errno=%d, retry=%d",
7723ba00ec3dSGregory Neil Shapiro result, sr == NULL ? "unknown" : sr, ssl_err,
7724da7d7b9cSGregory Neil Shapiro save_errno, i);
77255b0945b5SGregory Neil Shapiro tlslogerr(LOG_WARNING, 9, "client");
772613bd1963SGregory Neil Shapiro }
772740266059SGregory Neil Shapiro
77282fb4f839SGregory Neil Shapiro goto fail;
772906f25ae9SGregory Neil Shapiro }
773006f25ae9SGregory Neil Shapiro mci->mci_ssl = clt_ssl;
773140266059SGregory Neil Shapiro result = tls_get_info(mci->mci_ssl, false, mci->mci_host,
773240266059SGregory Neil Shapiro &mci->mci_macro, true);
773306f25ae9SGregory Neil Shapiro
773440266059SGregory Neil Shapiro /* switch to use TLS... */
773506f25ae9SGregory Neil Shapiro if (sfdctls(&mci->mci_in, &mci->mci_out, mci->mci_ssl) == 0)
773606f25ae9SGregory Neil Shapiro return EX_OK;
773706f25ae9SGregory Neil Shapiro
77382fb4f839SGregory Neil Shapiro fail:
773906f25ae9SGregory Neil Shapiro /* failure */
77405b0945b5SGregory Neil Shapiro SM_SSL_FREE(clt_ssl);
77412fb4f839SGregory Neil Shapiro return (EX_OK == ret) ? EX_SOFTWARE : ret;
774206f25ae9SGregory Neil Shapiro }
77432fb4f839SGregory Neil Shapiro
774440266059SGregory Neil Shapiro /*
774506f25ae9SGregory Neil Shapiro ** ENDTLSCLT -- shutdown secure connection (client side)
774606f25ae9SGregory Neil Shapiro **
774706f25ae9SGregory Neil Shapiro ** Parameters:
774806f25ae9SGregory Neil Shapiro ** mci -- the mailer connection info.
774906f25ae9SGregory Neil Shapiro **
775006f25ae9SGregory Neil Shapiro ** Returns:
775106f25ae9SGregory Neil Shapiro ** success?
775206f25ae9SGregory Neil Shapiro */
775340266059SGregory Neil Shapiro
775440266059SGregory Neil Shapiro static int
endtlsclt(mci)775506f25ae9SGregory Neil Shapiro endtlsclt(mci)
775606f25ae9SGregory Neil Shapiro MCI *mci;
775706f25ae9SGregory Neil Shapiro {
775806f25ae9SGregory Neil Shapiro int r;
775906f25ae9SGregory Neil Shapiro
776006f25ae9SGregory Neil Shapiro if (!bitset(MCIF_TLSACT, mci->mci_flags))
776106f25ae9SGregory Neil Shapiro return EX_OK;
77625b0945b5SGregory Neil Shapiro r = endtls(&mci->mci_ssl, "client");
776306f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLSACT;
776406f25ae9SGregory Neil Shapiro return r;
776506f25ae9SGregory Neil Shapiro }
776640266059SGregory Neil Shapiro #endif /* STARTTLS */
776740266059SGregory Neil Shapiro #if STARTTLS || SASL
776840266059SGregory Neil Shapiro /*
776940266059SGregory Neil Shapiro ** ISCLTFLGSET -- check whether client flag is set.
777006f25ae9SGregory Neil Shapiro **
777106f25ae9SGregory Neil Shapiro ** Parameters:
777240266059SGregory Neil Shapiro ** e -- envelope.
777340266059SGregory Neil Shapiro ** flag -- flag to check in {client_flags}
777406f25ae9SGregory Neil Shapiro **
777506f25ae9SGregory Neil Shapiro ** Returns:
777640266059SGregory Neil Shapiro ** true iff flag is set.
777706f25ae9SGregory Neil Shapiro */
777806f25ae9SGregory Neil Shapiro
777940266059SGregory Neil Shapiro static bool
iscltflgset(e,flag)778040266059SGregory Neil Shapiro iscltflgset(e, flag)
778140266059SGregory Neil Shapiro ENVELOPE *e;
778240266059SGregory Neil Shapiro int flag;
778306f25ae9SGregory Neil Shapiro {
778440266059SGregory Neil Shapiro char *p;
7785602a2b1bSGregory Neil Shapiro
778640266059SGregory Neil Shapiro p = macvalue(macid("{client_flags}"), e);
778740266059SGregory Neil Shapiro if (p == NULL)
778840266059SGregory Neil Shapiro return false;
778940266059SGregory Neil Shapiro for (; *p != '\0'; p++)
779006f25ae9SGregory Neil Shapiro {
779140266059SGregory Neil Shapiro /* look for just this one flag */
779240266059SGregory Neil Shapiro if (*p == (char) flag)
779340266059SGregory Neil Shapiro return true;
779406f25ae9SGregory Neil Shapiro }
779540266059SGregory Neil Shapiro return false;
779606f25ae9SGregory Neil Shapiro }
779740266059SGregory Neil Shapiro #endif /* STARTTLS || SASL */
7798*d39bd2c1SGregory Neil Shapiro
7799*d39bd2c1SGregory Neil Shapiro #if _FFR_TESTS
7800*d39bd2c1SGregory Neil Shapiro void
t_parsehostsig(hs,mailer)7801*d39bd2c1SGregory Neil Shapiro t_parsehostsig(hs, mailer)
7802*d39bd2c1SGregory Neil Shapiro char *hs;
7803*d39bd2c1SGregory Neil Shapiro MAILER *mailer;
7804*d39bd2c1SGregory Neil Shapiro {
7805*d39bd2c1SGregory Neil Shapiro int nummxhosts, i;
7806*d39bd2c1SGregory Neil Shapiro char *mxhosts[MAXMXHOSTS + 1];
7807*d39bd2c1SGregory Neil Shapiro #if DANE
7808*d39bd2c1SGregory Neil Shapiro BITMAP256 mxads;
7809*d39bd2c1SGregory Neil Shapiro #endif
7810*d39bd2c1SGregory Neil Shapiro
7811*d39bd2c1SGregory Neil Shapiro if (NULL == mailer)
7812*d39bd2c1SGregory Neil Shapiro mailer = LocalMailer;
7813*d39bd2c1SGregory Neil Shapiro nummxhosts = parse_hostsignature(hs, mxhosts, mailer
7814*d39bd2c1SGregory Neil Shapiro #if DANE
7815*d39bd2c1SGregory Neil Shapiro , mxads
7816*d39bd2c1SGregory Neil Shapiro #endif
7817*d39bd2c1SGregory Neil Shapiro );
7818*d39bd2c1SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7819*d39bd2c1SGregory Neil Shapiro "nummxhosts=%d\n", nummxhosts);
7820*d39bd2c1SGregory Neil Shapiro for (i = 0; i < nummxhosts; i++)
7821*d39bd2c1SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7822*d39bd2c1SGregory Neil Shapiro "mx[%d]=%s, ad=%d\n", i, mxhosts[i], MXADS_ISSET(mxads, 0));
7823*d39bd2c1SGregory Neil Shapiro }
7824*d39bd2c1SGregory Neil Shapiro
7825*d39bd2c1SGregory Neil Shapiro void
t_hostsig(a,hs,mailer)7826*d39bd2c1SGregory Neil Shapiro t_hostsig(a, hs, mailer)
7827*d39bd2c1SGregory Neil Shapiro ADDRESS *a;
7828*d39bd2c1SGregory Neil Shapiro char *hs;
7829*d39bd2c1SGregory Neil Shapiro MAILER *mailer;
7830*d39bd2c1SGregory Neil Shapiro {
7831*d39bd2c1SGregory Neil Shapiro char *q;
7832*d39bd2c1SGregory Neil Shapiro
7833*d39bd2c1SGregory Neil Shapiro if (NULL != a)
7834*d39bd2c1SGregory Neil Shapiro q = hostsignature(a->q_mailer, a->q_host, true, &a->q_flags);
7835*d39bd2c1SGregory Neil Shapiro else if (NULL != hs)
7836*d39bd2c1SGregory Neil Shapiro {
7837*d39bd2c1SGregory Neil Shapiro SM_REQUIRE(NULL != mailer);
7838*d39bd2c1SGregory Neil Shapiro q = hostsignature(mailer, hs, true, NULL);
7839*d39bd2c1SGregory Neil Shapiro }
7840*d39bd2c1SGregory Neil Shapiro else
7841*d39bd2c1SGregory Neil Shapiro SM_REQUIRE(NULL != hs);
7842*d39bd2c1SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "hostsig %s\n", q);
7843*d39bd2c1SGregory Neil Shapiro t_parsehostsig(q, (NULL != a) ? a->q_mailer : mailer);
7844*d39bd2c1SGregory Neil Shapiro }
7845*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_TESTS */
7846