Commit | Line | Data |
---|---|---|
d185cb11 | 1 | /* |
792e6158 | 2 | * Copyright (c) 1983, 1995 Eric P. Allman |
31de980b KB |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
bee79b64 | 5 | * |
417f7a11 | 6 | * %sccs.include.redist.c% |
bee79b64 | 7 | */ |
d185cb11 DF |
8 | |
9 | #ifndef lint | |
a5386d1b | 10 | static char sccsid[] = "@(#)deliver.c 8.159 (Berkeley) %G%"; |
bee79b64 | 11 | #endif /* not lint */ |
d185cb11 | 12 | |
97543758 | 13 | #include "sendmail.h" |
7b6e7aee | 14 | #include <errno.h> |
efe7f723 | 15 | #if NAMED_BIND |
f28c9fe2 | 16 | #include <resolv.h> |
8e5c6745 EA |
17 | |
18 | extern int h_errno; | |
35af2f06 | 19 | #endif |
b3cbe40f | 20 | |
965c2488 EA |
21 | extern char SmtpError[]; |
22 | ||
b3cbe40f | 23 | /* |
6acfa498 | 24 | ** SENDALL -- actually send all the messages. |
b3cbe40f | 25 | ** |
b3cbe40f | 26 | ** Parameters: |
6acfa498 EA |
27 | ** e -- the envelope to send. |
28 | ** mode -- the delivery mode to use. If SM_DEFAULT, use | |
29 | ** the current e->e_sendmode. | |
b3cbe40f EA |
30 | ** |
31 | ** Returns: | |
6acfa498 | 32 | ** none. |
b3cbe40f EA |
33 | ** |
34 | ** Side Effects: | |
6acfa498 EA |
35 | ** Scans the send lists and sends everything it finds. |
36 | ** Delivers any appropriate error messages. | |
37 | ** If we are running in a non-interactive mode, takes the | |
38 | ** appropriate action. | |
b3cbe40f EA |
39 | */ |
40 | ||
ea07b2d2 | 41 | void |
6acfa498 EA |
42 | sendall(e, mode) |
43 | ENVELOPE *e; | |
44 | char mode; | |
b3cbe40f | 45 | { |
6acfa498 EA |
46 | register ADDRESS *q; |
47 | char *owner; | |
48 | int otherowners; | |
11024b4c | 49 | bool oldverbose = Verbose; |
1ce944f0 | 50 | bool somedeliveries = FALSE; |
11024b4c | 51 | int pid; |
ea07b2d2 | 52 | extern void sendenvelope(); |
1d303d98 EA |
53 | int pid; |
54 | #ifdef LOCKF | |
55 | struct flock lfd; | |
56 | #endif | |
b3cbe40f | 57 | |
d4f6a25e EA |
58 | /* |
59 | ** If we have had global, fatal errors, don't bother sending | |
60 | ** the message at all if we are in SMTP mode. Local errors | |
61 | ** (e.g., a single address failing) will still cause the other | |
62 | ** addresses to be sent. | |
63 | */ | |
64 | ||
198d9e9c EA |
65 | if (bitset(EF_FATALERRS, e->e_flags) && |
66 | (OpMode == MD_SMTP || OpMode == MD_DAEMON)) | |
004a2b9c | 67 | { |
004a2b9c EA |
68 | e->e_flags |= EF_CLRQUEUE; |
69 | return; | |
70 | } | |
71 | ||
6acfa498 | 72 | /* determine actual delivery mode */ |
fc826a82 | 73 | CurrentLA = getla(); |
6acfa498 EA |
74 | if (mode == SM_DEFAULT) |
75 | { | |
6acfa498 EA |
76 | mode = e->e_sendmode; |
77 | if (mode != SM_VERIFY && | |
78 | shouldqueue(e->e_msgpriority, e->e_ctime)) | |
79 | mode = SM_QUEUE; | |
f28c9fe2 | 80 | } |
3135d20c | 81 | |
6acfa498 | 82 | if (tTd(13, 1)) |
3135d20c | 83 | { |
1ce944f0 EA |
84 | extern void printenvflags(); |
85 | ||
b5618bbc EA |
86 | printf("\n===== SENDALL: mode %c, id %s, e_from ", |
87 | mode, e->e_id); | |
6acfa498 | 88 | printaddr(&e->e_from, FALSE); |
1ce944f0 EA |
89 | printf("\te_flags = "); |
90 | printenvflags(e); | |
6acfa498 EA |
91 | printf("sendqueue:\n"); |
92 | printaddr(e->e_sendqueue, TRUE); | |
3135d20c EA |
93 | } |
94 | ||
a530c75f | 95 | /* |
6acfa498 EA |
96 | ** Do any preprocessing necessary for the mode we are running. |
97 | ** Check to make sure the hop count is reasonable. | |
98 | ** Delete sends to the sender in mailing lists. | |
a530c75f EA |
99 | */ |
100 | ||
6acfa498 | 101 | CurEnv = e; |
a530c75f | 102 | |
6acfa498 | 103 | if (e->e_hopcount > MaxHopCount) |
779597d8 | 104 | { |
6acfa498 | 105 | errno = 0; |
1ce944f0 | 106 | queueup(e, TRUE, mode == SM_QUEUE); |
ec33213e | 107 | e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE; |
7905af2d | 108 | syserr("554 Too many hops %d (%d max): from %s via %s, to %s", |
6acfa498 | 109 | e->e_hopcount, MaxHopCount, e->e_from.q_paddr, |
389c0d5e EA |
110 | RealHostName == NULL ? "localhost" : RealHostName, |
111 | e->e_sendqueue->q_paddr); | |
7905af2d | 112 | e->e_sendqueue->q_status = "5.4.6"; |
6acfa498 | 113 | return; |
779597d8 | 114 | } |
b3cbe40f | 115 | |
2eb74b19 EA |
116 | /* |
117 | ** Do sender deletion. | |
118 | ** | |
119 | ** If the sender has the QQUEUEUP flag set, skip this. | |
120 | ** This can happen if the name server is hosed when you | |
121 | ** are trying to send mail. The result is that the sender | |
122 | ** is instantiated in the queue as a recipient. | |
123 | */ | |
124 | ||
80ec5253 EA |
125 | if (!bitset(EF_METOO, e->e_flags) && |
126 | !bitset(QQUEUEUP, e->e_from.q_flags)) | |
b3cbe40f | 127 | { |
6acfa498 | 128 | if (tTd(13, 5)) |
779597d8 | 129 | { |
6acfa498 EA |
130 | printf("sendall: QDONTSEND "); |
131 | printaddr(&e->e_from, FALSE); | |
779597d8 | 132 | } |
6acfa498 | 133 | e->e_from.q_flags |= QDONTSEND; |
f8c2f9fd | 134 | (void) recipient(&e->e_from, &e->e_sendqueue, 0, e); |
b3cbe40f | 135 | } |
e6b0a75b | 136 | |
1d303d98 EA |
137 | # ifdef QUEUE |
138 | if ((mode == SM_QUEUE || mode == SM_FORK || | |
139 | (mode != SM_VERIFY && SuperSafe)) && | |
140 | !bitset(EF_INQUEUE, e->e_flags)) | |
141 | { | |
142 | /* be sure everything is instantiated in the queue */ | |
143 | queueup(e, TRUE, mode == SM_QUEUE); | |
144 | } | |
145 | #endif /* QUEUE */ | |
146 | ||
147 | switch (mode) | |
148 | { | |
149 | case SM_VERIFY: | |
150 | Verbose = TRUE; | |
151 | break; | |
152 | ||
153 | case SM_QUEUE: | |
154 | queueonly: | |
155 | e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; | |
156 | return; | |
157 | ||
158 | case SM_FORK: | |
159 | if (e->e_xfp != NULL) | |
160 | (void) fflush(e->e_xfp); | |
161 | ||
162 | # ifdef LOCKF | |
163 | /* | |
164 | ** Since lockf has the interesting semantic that the | |
165 | ** lock is lost when we fork, we have to risk losing | |
166 | ** the lock here by closing before the fork, and then | |
167 | ** trying to get it back in the child. | |
168 | */ | |
169 | ||
170 | if (e->e_lockfp != NULL) | |
171 | { | |
172 | (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp"); | |
173 | e->e_lockfp = NULL; | |
174 | } | |
175 | # endif /* LOCKF */ | |
176 | ||
177 | pid = fork(); | |
178 | if (pid < 0) | |
179 | { | |
180 | goto queueonly; | |
181 | } | |
182 | else if (pid > 0) | |
183 | { | |
184 | /* be sure we leave the temp files to our child */ | |
185 | e->e_id = e->e_df = NULL; | |
186 | # ifndef LOCKF | |
187 | if (e->e_lockfp != NULL) | |
188 | { | |
189 | (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp"); | |
190 | e->e_lockfp = NULL; | |
191 | } | |
192 | # endif | |
193 | ||
194 | /* close any random open files in the envelope */ | |
195 | if (e->e_dfp != NULL) | |
196 | { | |
197 | (void) xfclose(e->e_dfp, "sendenvelope", "dfp"); | |
198 | e->e_dfp = NULL; | |
199 | } | |
200 | if (e->e_xfp != NULL) | |
201 | { | |
202 | (void) xfclose(e->e_xfp, "sendenvelope", "xfp"); | |
203 | e->e_xfp = NULL; | |
204 | } | |
205 | return; | |
206 | } | |
207 | ||
208 | /* double fork to avoid zombies */ | |
209 | if (fork() > 0) | |
210 | exit(EX_OK); | |
211 | ||
212 | /* be sure we are immune from the terminal */ | |
213 | disconnect(FALSE, e); | |
214 | ||
215 | # ifdef LOCKF | |
216 | /* | |
217 | ** Now try to get our lock back. | |
218 | */ | |
219 | ||
220 | lfd.l_type = F_WRLCK; | |
221 | lfd.l_whence = lfd.l_start = lfd.l_len = 0; | |
222 | e->e_lockfp = fopen(queuename(e, 'q'), "r+"); | |
223 | if (e->e_lockfp == NULL || | |
224 | fcntl(fileno(e->e_lockfp), F_SETLK, &lfd) < 0) | |
225 | { | |
226 | /* oops.... lost it */ | |
227 | if (tTd(13, 1)) | |
228 | printf("sendenvelope: %s lost lock: lockfp=%x, %s\n", | |
229 | e->e_id, e->e_lockfp, errstring(errno)); | |
230 | ||
231 | # ifdef LOG | |
232 | if (LogLevel > 29) | |
233 | syslog(LOG_NOTICE, "%s: lost lock: %m", | |
234 | e->e_id); | |
235 | # endif /* LOG */ | |
236 | exit(EX_OK); | |
237 | } | |
238 | # endif /* LOCKF */ | |
239 | ||
240 | /* | |
241 | ** Close any cached connections. | |
242 | ** | |
243 | ** We don't send the QUIT protocol because the parent | |
244 | ** still knows about the connection. | |
245 | ** | |
246 | ** This should only happen when delivering an error | |
247 | ** message. | |
248 | */ | |
249 | ||
250 | mci_flush(FALSE, NULL); | |
251 | ||
252 | break; | |
253 | } | |
254 | ||
255 | /* | |
256 | ** If we haven't fully expanded aliases, do it now | |
257 | */ | |
258 | ||
259 | if (bitset(EF_VRFYONLY, e->e_flags)) | |
260 | { | |
261 | e->e_flags &= ~EF_VRFYONLY; | |
262 | for (q = e->e_sendqueue; q != NULL; q = q->q_next) | |
263 | { | |
264 | extern ADDRESS *recipient(); | |
265 | ||
266 | if (bitset(QVERIFIED, q->q_flags)) | |
267 | recipient(q, &e->e_sendqueue, e); | |
268 | } | |
269 | } | |
270 | ||
1ab402f2 | 271 | /* |
6acfa498 EA |
272 | ** Handle alias owners. |
273 | ** | |
274 | ** We scan up the q_alias chain looking for owners. | |
275 | ** We discard owners that are the same as the return path. | |
b3cbe40f EA |
276 | */ |
277 | ||
6acfa498 | 278 | for (q = e->e_sendqueue; q != NULL; q = q->q_next) |
b3cbe40f | 279 | { |
6acfa498 | 280 | register struct address *a; |
779597d8 | 281 | |
6acfa498 | 282 | for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) |
779597d8 | 283 | continue; |
6acfa498 EA |
284 | if (a != NULL) |
285 | q->q_owner = a->q_owner; | |
286 | ||
287 | if (q->q_owner != NULL && | |
288 | !bitset(QDONTSEND, q->q_flags) && | |
289 | strcmp(q->q_owner, e->e_from.q_paddr) == 0) | |
290 | q->q_owner = NULL; | |
291 | } | |
292 | ||
293 | owner = ""; | |
294 | otherowners = 1; | |
295 | while (owner != NULL && otherowners > 0) | |
296 | { | |
297 | owner = NULL; | |
298 | otherowners = 0; | |
1bf7c76b | 299 | |
6acfa498 | 300 | for (q = e->e_sendqueue; q != NULL; q = q->q_next) |
78bbbc48 | 301 | { |
6acfa498 EA |
302 | if (bitset(QDONTSEND, q->q_flags)) |
303 | continue; | |
779597d8 | 304 | |
6acfa498 EA |
305 | if (q->q_owner != NULL) |
306 | { | |
307 | if (owner == NULL) | |
308 | owner = q->q_owner; | |
309 | else if (owner != q->q_owner) | |
310 | { | |
311 | if (strcmp(owner, q->q_owner) == 0) | |
312 | { | |
313 | /* make future comparisons cheap */ | |
314 | q->q_owner = owner; | |
315 | } | |
316 | else | |
317 | { | |
318 | otherowners++; | |
319 | } | |
320 | owner = q->q_owner; | |
321 | } | |
322 | } | |
323 | else | |
324 | { | |
325 | otherowners++; | |
326 | } | |
1ce944f0 EA |
327 | |
328 | /* | |
329 | ** If this mailer is expensive, and if we don't | |
330 | ** want to make connections now, just mark these | |
331 | ** addresses and return. This is useful if we | |
332 | ** want to batch connections to reduce load. This | |
333 | ** will cause the messages to be queued up, and a | |
334 | ** daemon will come along to send the messages later. | |
335 | */ | |
336 | ||
337 | if (bitset(QBADADDR|QQUEUEUP, q->q_flags)) | |
338 | continue; | |
339 | if (NoConnect && !Verbose && | |
340 | bitnset(M_EXPENSIVE, q->q_mailer->m_flags)) | |
341 | { | |
342 | q->q_flags |= QQUEUEUP; | |
343 | e->e_to = q->q_paddr; | |
344 | message("queued"); | |
345 | if (LogLevel > 8) | |
346 | logdelivery(q->q_mailer, NULL, | |
347 | "queued", NULL, | |
348 | (time_t) 0, e); | |
349 | e->e_to = NULL; | |
350 | } | |
351 | else | |
352 | { | |
353 | somedeliveries = TRUE; | |
354 | } | |
779597d8 EA |
355 | } |
356 | ||
6acfa498 | 357 | if (owner != NULL && otherowners > 0) |
b3cbe40f | 358 | { |
04f6f6a9 | 359 | register ENVELOPE *ee; |
6acfa498 EA |
360 | extern HDR *copyheader(); |
361 | extern ADDRESS *copyqueue(); | |
779597d8 | 362 | |
6acfa498 EA |
363 | /* |
364 | ** Split this envelope into two. | |
365 | */ | |
74c5fe7c | 366 | |
6acfa498 EA |
367 | ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); |
368 | *ee = *e; | |
369 | ee->e_id = NULL; | |
370 | (void) queuename(ee, '\0'); | |
0df76d69 | 371 | |
6acfa498 EA |
372 | if (tTd(13, 1)) |
373 | printf("sendall: split %s into %s\n", | |
374 | e->e_id, ee->e_id); | |
779597d8 | 375 | |
6acfa498 EA |
376 | ee->e_header = copyheader(e->e_header); |
377 | ee->e_sendqueue = copyqueue(e->e_sendqueue); | |
378 | ee->e_errorqueue = copyqueue(e->e_errorqueue); | |
f052a727 | 379 | ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM); |
5b4215a7 | 380 | ee->e_flags |= EF_NORECEIPT; |
6acfa498 EA |
381 | setsender(owner, ee, NULL, TRUE); |
382 | if (tTd(13, 5)) | |
383 | { | |
384 | printf("sendall(split): QDONTSEND "); | |
385 | printaddr(&ee->e_from, FALSE); | |
386 | } | |
387 | ee->e_from.q_flags |= QDONTSEND; | |
388 | ee->e_dfp = NULL; | |
389 | ee->e_xfp = NULL; | |
6acfa498 | 390 | ee->e_errormode = EM_MAIL; |
6acfa498 EA |
391 | |
392 | for (q = e->e_sendqueue; q != NULL; q = q->q_next) | |
f052a727 | 393 | { |
6acfa498 | 394 | if (q->q_owner == owner) |
0cf862de | 395 | { |
6acfa498 | 396 | q->q_flags |= QDONTSEND; |
0cf862de EA |
397 | q->q_flags &= ~QQUEUEUP; |
398 | } | |
f052a727 | 399 | } |
6acfa498 | 400 | for (q = ee->e_sendqueue; q != NULL; q = q->q_next) |
f052a727 | 401 | { |
6acfa498 | 402 | if (q->q_owner != owner) |
0cf862de | 403 | { |
6acfa498 | 404 | q->q_flags |= QDONTSEND; |
0cf862de EA |
405 | q->q_flags &= ~QQUEUEUP; |
406 | } | |
f052a727 EA |
407 | else |
408 | { | |
409 | /* clear DSN parameters */ | |
410 | q->q_flags &= ~(QHASNOTIFY|QPINGONSUCCESS); | |
411 | q->q_flags |= QPINGONFAILURE|QPINGONDELAY; | |
412 | } | |
413 | } | |
e6b0a75b | 414 | |
18a81ac0 | 415 | if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags)) |
e6b0a75b | 416 | { |
18a81ac0 EA |
417 | char df1buf[20], df2buf[20]; |
418 | ||
6acfa498 | 419 | ee->e_dfp = NULL; |
18a81ac0 EA |
420 | strcpy(df1buf, queuename(e, 'd')); |
421 | strcpy(df2buf, queuename(ee, 'd')); | |
422 | if (link(df1buf, df2buf) < 0) | |
6acfa498 EA |
423 | { |
424 | syserr("sendall: link(%s, %s)", | |
18a81ac0 | 425 | df1buf, df2buf); |
6acfa498 | 426 | } |
e6b0a75b | 427 | } |
6acfa498 EA |
428 | #ifdef LOG |
429 | if (LogLevel > 4) | |
9cc11aa8 EA |
430 | syslog(LOG_INFO, "%s: clone %s, owner=%s", |
431 | ee->e_id, e->e_id, owner); | |
6acfa498 | 432 | #endif |
04f6f6a9 EA |
433 | CurEnv = ee; |
434 | sendenvelope(ee, mode, announcequeueup); | |
435 | dropenvelope(ee); | |
779597d8 | 436 | } |
b3cbe40f EA |
437 | } |
438 | ||
04f6f6a9 EA |
439 | /* |
440 | ** Split off envelopes have been sent -- now send original | |
441 | */ | |
442 | ||
6acfa498 | 443 | if (owner != NULL) |
e6b0a75b | 444 | { |
6acfa498 EA |
445 | setsender(owner, e, NULL, TRUE); |
446 | if (tTd(13, 5)) | |
447 | { | |
448 | printf("sendall(owner): QDONTSEND "); | |
449 | printaddr(&e->e_from, FALSE); | |
450 | } | |
451 | e->e_from.q_flags |= QDONTSEND; | |
452 | e->e_errormode = EM_MAIL; | |
5b4215a7 | 453 | e->e_flags |= EF_NORECEIPT; |
e6b0a75b | 454 | } |
1ef61b9f | 455 | |
1ce944f0 EA |
456 | /* if nothing to be delivered, just queue up everything */ |
457 | if (!somedeliveries && mode != SM_QUEUE && mode != SM_VERIFY) | |
458 | mode = SM_QUEUE; | |
459 | ||
11024b4c EA |
460 | bool oldverbose = Verbose; |
461 | ||
462 | if (splitenv != NULL) | |
463 | { | |
464 | if (tTd(13, 1)) | |
465 | { | |
466 | printf("\nsendall: Split queue; remaining queue:\n"); | |
467 | printaddr(e->e_sendqueue, TRUE); | |
468 | } | |
469 | ||
470 | for (ee = splitenv; ee != NULL; ee = ee->e_sibling) | |
471 | { | |
472 | CurEnv = ee; | |
473 | if (mode != SM_VERIFY) | |
474 | openxscript(ee); | |
475 | sendenvelope(ee, mode); | |
476 | dropenvelope(ee); | |
477 | } | |
478 | ||
479 | CurEnv = e; | |
480 | } | |
481 | sendenvelope(e, mode); | |
482 | Verbose = oldverbose; | |
6acfa498 EA |
483 | } |
484 | ||
ea07b2d2 | 485 | void |
11024b4c | 486 | sendenvelope(e, mode) |
6acfa498 EA |
487 | register ENVELOPE *e; |
488 | char mode; | |
489 | { | |
6acfa498 | 490 | register ADDRESS *q; |
11024b4c EA |
491 | bool didany; |
492 | ||
493 | /* | |
494 | ** If we have had global, fatal errors, don't bother sending | |
495 | ** the message at all if we are in SMTP mode. Local errors | |
496 | ** (e.g., a single address failing) will still cause the other | |
497 | ** addresses to be sent. | |
498 | */ | |
499 | ||
500 | if (bitset(EF_FATALERRS, e->e_flags) && | |
501 | (OpMode == MD_SMTP || OpMode == MD_DAEMON)) | |
502 | { | |
503 | e->e_flags |= EF_CLRQUEUE; | |
504 | return; | |
505 | } | |
f2e44ded | 506 | |
ed45aae1 | 507 | /* |
6acfa498 | 508 | ** Run through the list and send everything. |
0fc3fb21 EA |
509 | ** |
510 | ** Set EF_GLOBALERRS so that error messages during delivery | |
511 | ** result in returned mail. | |
ed45aae1 EA |
512 | */ |
513 | ||
6acfa498 | 514 | e->e_nsent = 0; |
0fc3fb21 | 515 | e->e_flags |= EF_GLOBALERRS; |
f009d24b | 516 | didany = FALSE; |
69c74bb8 | 517 | |
69c74bb8 | 518 | /* now run through the queue */ |
6acfa498 | 519 | for (q = e->e_sendqueue; q != NULL; q = q->q_next) |
f2e44ded | 520 | { |
a40faef5 | 521 | #if XDEBUG |
f9fbda25 EA |
522 | char wbuf[MAXNAME + 20]; |
523 | ||
524 | (void) sprintf(wbuf, "sendall(%s)", q->q_paddr); | |
525 | checkfd012(wbuf); | |
526 | #endif | |
6acfa498 | 527 | if (mode == SM_VERIFY) |
1627a785 | 528 | { |
6acfa498 EA |
529 | e->e_to = q->q_paddr; |
530 | if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) | |
d1c234d8 | 531 | { |
58057ca3 EA |
532 | if (q->q_host != NULL && q->q_host[0] != '\0') |
533 | message("deliverable: mailer %s, host %s, user %s", | |
534 | q->q_mailer->m_name, | |
535 | q->q_host, | |
536 | q->q_user); | |
537 | else | |
538 | message("deliverable: mailer %s, user %s", | |
539 | q->q_mailer->m_name, | |
540 | q->q_user); | |
d1c234d8 | 541 | } |
6acfa498 EA |
542 | } |
543 | else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) | |
544 | { | |
545 | # ifdef QUEUE | |
546 | /* | |
547 | ** Checkpoint the send list every few addresses | |
548 | */ | |
549 | ||
550 | if (e->e_nsent >= CheckpointInterval) | |
551 | { | |
552 | queueup(e, TRUE, FALSE); | |
553 | e->e_nsent = 0; | |
554 | } | |
555 | # endif /* QUEUE */ | |
556 | (void) deliver(e, q); | |
f009d24b | 557 | didany = TRUE; |
1627a785 | 558 | } |
f2e44ded | 559 | } |
f009d24b EA |
560 | if (didany) |
561 | { | |
562 | e->e_dtime = curtime(); | |
563 | e->e_ntries++; | |
564 | } | |
f2e44ded | 565 | |
a40faef5 | 566 | #if XDEBUG |
f9fbda25 EA |
567 | checkfd012("end of sendenvelope"); |
568 | #endif | |
569 | ||
6acfa498 EA |
570 | if (mode == SM_FORK) |
571 | finis(); | |
779597d8 EA |
572 | } |
573 | \f/* | |
6acfa498 EA |
574 | ** DOFORK -- do a fork, retrying a couple of times on failure. |
575 | ** | |
576 | ** This MUST be a macro, since after a vfork we are running | |
577 | ** two processes on the same stack!!! | |
b9e44c3d EA |
578 | ** |
579 | ** Parameters: | |
6acfa498 | 580 | ** none. |
b9e44c3d EA |
581 | ** |
582 | ** Returns: | |
6acfa498 | 583 | ** From a macro??? You've got to be kidding! |
b9e44c3d EA |
584 | ** |
585 | ** Side Effects: | |
6acfa498 EA |
586 | ** Modifies the ==> LOCAL <== variable 'pid', leaving: |
587 | ** pid of child in parent, zero in child. | |
588 | ** -1 on unrecoverable error. | |
589 | ** | |
590 | ** Notes: | |
591 | ** I'm awfully sorry this looks so awful. That's | |
592 | ** vfork for you..... | |
b9e44c3d EA |
593 | */ |
594 | ||
6acfa498 | 595 | # define NFORKTRIES 5 |
140717b5 EA |
596 | |
597 | # ifndef FORK | |
598 | # define FORK fork | |
599 | # endif | |
67e64653 EA |
600 | |
601 | # define DOFORK(fORKfN) \ | |
602 | {\ | |
603 | register int i;\ | |
604 | \ | |
11e32817 | 605 | for (i = NFORKTRIES; --i >= 0; )\ |
67e64653 EA |
606 | {\ |
607 | pid = fORKfN();\ | |
608 | if (pid >= 0)\ | |
609 | break;\ | |
11e32817 | 610 | if (i > 0)\ |
901911f8 | 611 | sleep((unsigned) NFORKTRIES - i);\ |
67e64653 EA |
612 | }\ |
613 | } | |
614 | \f/* | |
2cf55cb7 EA |
615 | ** DOFORK -- simple fork interface to DOFORK. |
616 | ** | |
617 | ** Parameters: | |
618 | ** none. | |
619 | ** | |
620 | ** Returns: | |
621 | ** pid of child in parent. | |
622 | ** zero in child. | |
623 | ** -1 on error. | |
624 | ** | |
625 | ** Side Effects: | |
626 | ** returns twice, once in parent and once in child. | |
627 | */ | |
628 | ||
179d940c | 629 | int |
2cf55cb7 EA |
630 | dofork() |
631 | { | |
ea07b2d2 | 632 | register int pid = -1; |
2cf55cb7 EA |
633 | |
634 | DOFORK(fork); | |
635 | return (pid); | |
636 | } | |
637 | \f/* | |
6acfa498 | 638 | ** DELIVER -- Deliver a message to a list of addresses. |
e6b0a75b | 639 | ** |
6acfa498 EA |
640 | ** This routine delivers to everyone on the same host as the |
641 | ** user on the head of the list. It is clever about mailers | |
642 | ** that don't handle multiple users. It is NOT guaranteed | |
643 | ** that it will deliver to all these addresses however -- so | |
644 | ** deliver should be called once for each address on the | |
645 | ** list. | |
e6b0a75b EA |
646 | ** |
647 | ** Parameters: | |
6acfa498 EA |
648 | ** e -- the envelope to deliver. |
649 | ** firstto -- head of the address list to deliver to. | |
e6b0a75b EA |
650 | ** |
651 | ** Returns: | |
6acfa498 EA |
652 | ** zero -- successfully delivered. |
653 | ** else -- some failure, see ExitStat for more info. | |
e6b0a75b EA |
654 | ** |
655 | ** Side Effects: | |
6acfa498 | 656 | ** The standard input is passed off to someone. |
e6b0a75b EA |
657 | */ |
658 | ||
ea07b2d2 | 659 | int |
6acfa498 | 660 | deliver(e, firstto) |
30eab7ca | 661 | register ENVELOPE *e; |
6acfa498 | 662 | ADDRESS *firstto; |
e6b0a75b | 663 | { |
6acfa498 EA |
664 | char *host; /* host being sent to */ |
665 | char *user; /* user being sent to */ | |
666 | char **pvp; | |
667 | register char **mvp; | |
668 | register char *p; | |
669 | register MAILER *m; /* mailer for this recipient */ | |
670 | ADDRESS *ctladdr; | |
671 | register MCI *mci; | |
672 | register ADDRESS *to = firstto; | |
673 | bool clever = FALSE; /* running user smtp to this mailer */ | |
ea07b2d2 | 674 | ADDRESS *tochain = NULL; /* users chain in this mailer call */ |
6acfa498 EA |
675 | int rcode; /* response code */ |
676 | char *firstsig; /* signature of firstto */ | |
ea07b2d2 | 677 | int pid = -1; |
6acfa498 | 678 | char *curhost; |
3500a891 | 679 | time_t xstart; |
6acfa498 EA |
680 | int mpvect[2]; |
681 | int rpvect[2]; | |
682 | char *pv[MAXPV+1]; | |
683 | char tobuf[TOBUFSIZE]; /* text line of to people */ | |
8446c922 EA |
684 | char buf[MAXNAME + 1]; |
685 | char rpathbuf[MAXNAME + 1]; /* translated return path */ | |
6acfa498 | 686 | extern int checkcompat(); |
179d940c | 687 | extern void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int)); |
e6b0a75b | 688 | |
6acfa498 EA |
689 | errno = 0; |
690 | if (!ForceMail && bitset(QDONTSEND|QPSEUDO, to->q_flags)) | |
691 | return (0); | |
2ae0e0ed | 692 | |
efe7f723 | 693 | #if NAMED_BIND |
6acfa498 | 694 | /* unless interactive, try twice, over a minute */ |
198d9e9c EA |
695 | if (OpMode == MD_DAEMON || OpMode == MD_SMTP) |
696 | { | |
6acfa498 EA |
697 | _res.retrans = 30; |
698 | _res.retry = 2; | |
699 | } | |
700 | #endif | |
1ab402f2 | 701 | |
6acfa498 EA |
702 | m = to->q_mailer; |
703 | host = to->q_host; | |
704 | CurEnv = e; /* just in case */ | |
0992263e | 705 | e->e_statmsg = NULL; |
fe3849ea | 706 | SmtpError[0] = '\0'; |
4c309714 | 707 | xstart = curtime(); |
6acfa498 EA |
708 | |
709 | if (tTd(10, 1)) | |
116d2937 EA |
710 | printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", |
711 | e->e_id, m->m_name, host, to->q_user); | |
35f14050 EA |
712 | if (tTd(10, 100)) |
713 | printopenfds(FALSE); | |
6acfa498 | 714 | |
6acfa498 EA |
715 | /* |
716 | ** Do initial argv setup. | |
717 | ** Insert the mailer name. Notice that $x expansion is | |
718 | ** NOT done on the mailer name. Then, if the mailer has | |
719 | ** a picky -f flag, we insert it as appropriate. This | |
720 | ** code does not check for 'pv' overflow; this places a | |
721 | ** manifest lower limit of 4 for MAXPV. | |
722 | ** The from address rewrite is expected to make | |
723 | ** the address relative to the other end. | |
724 | */ | |
725 | ||
726 | /* rewrite from address, using rewriting rules */ | |
9e43a19e | 727 | rcode = EX_OK; |
295b05c5 EA |
728 | if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) |
729 | p = e->e_sender; | |
730 | else | |
731 | p = e->e_from.q_paddr; | |
732 | (void) strcpy(rpathbuf, remotename(p, m, | |
9e43a19e EA |
733 | RF_SENDERADDR|RF_CANONICAL, |
734 | &rcode, e)); | |
6acfa498 EA |
735 | define('g', rpathbuf, e); /* translated return path */ |
736 | define('h', host, e); /* to host */ | |
737 | Errors = 0; | |
738 | pvp = pv; | |
739 | *pvp++ = m->m_argv[0]; | |
740 | ||
741 | /* insert -f or -r flag as appropriate */ | |
742 | if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) | |
743 | { | |
744 | if (bitnset(M_FOPT, m->m_flags)) | |
745 | *pvp++ = "-f"; | |
746 | else | |
747 | *pvp++ = "-r"; | |
748 | *pvp++ = newstr(rpathbuf); | |
749 | } | |
750 | ||
751 | /* | |
752 | ** Append the other fixed parts of the argv. These run | |
753 | ** up to the first entry containing "$u". There can only | |
754 | ** be one of these, and there are only a few more slots | |
755 | ** in the pv after it. | |
756 | */ | |
757 | ||
758 | for (mvp = m->m_argv; (p = *++mvp) != NULL; ) | |
759 | { | |
760 | /* can't use strchr here because of sign extension problems */ | |
761 | while (*p != '\0') | |
762 | { | |
763 | if ((*p++ & 0377) == MACROEXPAND) | |
764 | { | |
765 | if (*p == 'u') | |
766 | break; | |
767 | } | |
768 | } | |
769 | ||
770 | if (*p != '\0') | |
771 | break; | |
772 | ||
773 | /* this entry is safe -- go ahead and process it */ | |
832e8a27 | 774 | expand(*mvp, buf, sizeof buf, e); |
6acfa498 EA |
775 | *pvp++ = newstr(buf); |
776 | if (pvp >= &pv[MAXPV - 3]) | |
777 | { | |
778 | syserr("554 Too many parameters to %s before $u", pv[0]); | |
779 | return (-1); | |
780 | } | |
781 | } | |
782 | ||
783 | /* | |
784 | ** If we have no substitution for the user name in the argument | |
785 | ** list, we know that we must supply the names otherwise -- and | |
786 | ** SMTP is the answer!! | |
787 | */ | |
788 | ||
789 | if (*mvp == NULL) | |
790 | { | |
791 | /* running SMTP */ | |
792 | # ifdef SMTP | |
793 | clever = TRUE; | |
794 | *pvp = NULL; | |
795 | # else /* SMTP */ | |
796 | /* oops! we don't implement SMTP */ | |
fe3849ea | 797 | syserr("554 SMTP style mailer not implemented"); |
7338e3d4 | 798 | return (EX_SOFTWARE); |
6acfa498 | 799 | # endif /* SMTP */ |
e6b0a75b | 800 | } |
1ab402f2 | 801 | |
6acfa498 EA |
802 | /* |
803 | ** At this point *mvp points to the argument with $u. We | |
804 | ** run through our address list and append all the addresses | |
805 | ** we can. If we run out of space, do not fret! We can | |
806 | ** always send another copy later. | |
807 | */ | |
808 | ||
809 | tobuf[0] = '\0'; | |
810 | e->e_to = tobuf; | |
811 | ctladdr = NULL; | |
812 | firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); | |
813 | for (; to != NULL; to = to->q_next) | |
e6b0a75b | 814 | { |
6acfa498 EA |
815 | /* avoid sending multiple recipients to dumb mailers */ |
816 | if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) | |
817 | break; | |
30eab7ca | 818 | |
6acfa498 EA |
819 | /* if already sent or not for this host, don't send */ |
820 | if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || | |
821 | to->q_mailer != firstto->q_mailer || | |
822 | strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) | |
823 | continue; | |
824 | ||
825 | /* avoid overflowing tobuf */ | |
826 | if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) | |
827 | break; | |
828 | ||
829 | if (tTd(10, 1)) | |
30eab7ca | 830 | { |
6acfa498 EA |
831 | printf("\nsend to "); |
832 | printaddr(to, FALSE); | |
833 | } | |
30eab7ca | 834 | |
6acfa498 | 835 | /* compute effective uid/gid when sending */ |
2bade550 | 836 | if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) |
c8de5c6d | 837 | ctladdr = getctladdr(to); |
6acfa498 | 838 | |
bdd1eb9a EA |
839 | if (tTd(10, 2)) |
840 | { | |
841 | printf("ctladdr="); | |
842 | printaddr(ctladdr, FALSE); | |
843 | } | |
844 | ||
6acfa498 EA |
845 | user = to->q_user; |
846 | e->e_to = to->q_paddr; | |
847 | if (tTd(10, 5)) | |
848 | { | |
849 | printf("deliver: QDONTSEND "); | |
850 | printaddr(to, FALSE); | |
30eab7ca | 851 | } |
6acfa498 | 852 | to->q_flags |= QDONTSEND; |
30eab7ca | 853 | |
6acfa498 EA |
854 | /* |
855 | ** Check to see that these people are allowed to | |
856 | ** talk to each other. | |
857 | */ | |
858 | ||
859 | if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) | |
860 | { | |
c7a0eaaf | 861 | e->e_flags |= EF_NO_BODY_RETN; |
179d940c | 862 | to->q_status = "5.2.3"; |
6acfa498 | 863 | usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); |
3500a891 | 864 | giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, xstart, e); |
6acfa498 EA |
865 | continue; |
866 | } | |
fdcfa6b8 EA |
867 | #if NAMED_BIND |
868 | h_errno = 0; | |
869 | #endif | |
6acfa498 EA |
870 | rcode = checkcompat(to, e); |
871 | if (rcode != EX_OK) | |
872 | { | |
a542cc51 | 873 | markfailure(e, to, NULL, rcode); |
3500a891 | 874 | giveresponse(rcode, m, NULL, ctladdr, xstart, e); |
6acfa498 EA |
875 | continue; |
876 | } | |
877 | ||
878 | /* | |
879 | ** Strip quote bits from names if the mailer is dumb | |
880 | ** about them. | |
881 | */ | |
882 | ||
883 | if (bitnset(M_STRIPQ, m->m_flags)) | |
884 | { | |
885 | stripquotes(user); | |
886 | stripquotes(host); | |
887 | } | |
888 | ||
889 | /* hack attack -- delivermail compatibility */ | |
890 | if (m == ProgMailer && *user == '|') | |
891 | user++; | |
892 | ||
893 | /* | |
894 | ** If an error message has already been given, don't | |
895 | ** bother to send to this address. | |
896 | ** | |
897 | ** >>>>>>>>>> This clause assumes that the local mailer | |
898 | ** >> NOTE >> cannot do any further aliasing; that | |
899 | ** >>>>>>>>>> function is subsumed by sendmail. | |
900 | */ | |
901 | ||
902 | if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) | |
903 | continue; | |
904 | ||
905 | /* save statistics.... */ | |
906 | markstats(e, to); | |
907 | ||
908 | /* | |
909 | ** See if this user name is "special". | |
910 | ** If the user name has a slash in it, assume that this | |
911 | ** is a file -- send it off without further ado. Note | |
912 | ** that this type of addresses is not processed along | |
913 | ** with the others, so we fudge on the To person. | |
914 | */ | |
915 | ||
376c6f37 | 916 | if (strcmp(m->m_mailer, "[FILE]") == 0) |
6acfa498 | 917 | { |
b6f25ddb | 918 | rcode = mailfile(user, ctladdr, SFF_CREAT, e); |
3500a891 | 919 | giveresponse(rcode, m, NULL, ctladdr, xstart, e); |
f8c2f9fd | 920 | e->e_nsent++; |
6acfa498 | 921 | if (rcode == EX_OK) |
f8c2f9fd | 922 | { |
6acfa498 | 923 | to->q_flags |= QSENT; |
f8c2f9fd EA |
924 | if (bitnset(M_LOCALMAILER, m->m_flags) && |
925 | (e->e_receiptto != NULL || | |
926 | bitset(QPINGONSUCCESS, to->q_flags))) | |
927 | { | |
126c1099 | 928 | to->q_flags |= QDELIVERED; |
7905af2d | 929 | to->q_status = "2.1.5"; |
f8c2f9fd EA |
930 | fprintf(e->e_xfp, "%s... Successfully delivered\n", |
931 | to->q_paddr); | |
932 | } | |
933 | } | |
68d9129a | 934 | to->q_statdate = curtime(); |
6acfa498 EA |
935 | continue; |
936 | } | |
937 | ||
938 | /* | |
939 | ** Address is verified -- add this user to mailer | |
940 | ** argv, and add it to the print list of recipients. | |
941 | */ | |
942 | ||
943 | /* link together the chain of recipients */ | |
944 | to->q_tchain = tochain; | |
945 | tochain = to; | |
946 | ||
947 | /* create list of users for error messages */ | |
948 | (void) strcat(tobuf, ","); | |
949 | (void) strcat(tobuf, to->q_paddr); | |
950 | define('u', user, e); /* to user */ | |
ce4c39a9 EA |
951 | p = to->q_home; |
952 | if (p == NULL && ctladdr != NULL) | |
953 | p = ctladdr->q_home; | |
954 | define('z', p, e); /* user's home */ | |
6acfa498 EA |
955 | |
956 | /* | |
957 | ** Expand out this user into argument list. | |
958 | */ | |
959 | ||
960 | if (!clever) | |
961 | { | |
832e8a27 | 962 | expand(*mvp, buf, sizeof buf, e); |
6acfa498 EA |
963 | *pvp++ = newstr(buf); |
964 | if (pvp >= &pv[MAXPV - 2]) | |
965 | { | |
966 | /* allow some space for trailing parms */ | |
967 | break; | |
968 | } | |
969 | } | |
e6b0a75b | 970 | } |
1ab402f2 | 971 | |
6acfa498 EA |
972 | /* see if any addresses still exist */ |
973 | if (tobuf[0] == '\0') | |
974 | { | |
975 | define('g', (char *) NULL, e); | |
976 | return (0); | |
977 | } | |
978 | ||
979 | /* print out messages as full list */ | |
980 | e->e_to = tobuf + 1; | |
981 | ||
982 | /* | |
983 | ** Fill out any parameters after the $u parameter. | |
984 | */ | |
985 | ||
986 | while (!clever && *++mvp != NULL) | |
987 | { | |
832e8a27 | 988 | expand(*mvp, buf, sizeof buf, e); |
6acfa498 EA |
989 | *pvp++ = newstr(buf); |
990 | if (pvp >= &pv[MAXPV]) | |
991 | syserr("554 deliver: pv overflow after $u for %s", pv[0]); | |
992 | } | |
993 | *pvp++ = NULL; | |
994 | ||
995 | /* | |
996 | ** Call the mailer. | |
997 | ** The argument vector gets built, pipes | |
998 | ** are created as necessary, and we fork & exec as | |
999 | ** appropriate. | |
1000 | ** If we are running SMTP, we just need to clean up. | |
1001 | */ | |
e6b0a75b | 1002 | |
c8de5c6d | 1003 | /*XXX this seems a bit wierd */ |
0aeae945 | 1004 | if (ctladdr == NULL && m != ProgMailer && m != FileMailer && |
a773ed15 | 1005 | bitset(QGOODUID, e->e_from.q_flags)) |
c8de5c6d EA |
1006 | ctladdr = &e->e_from; |
1007 | ||
efe7f723 | 1008 | #if NAMED_BIND |
6acfa498 EA |
1009 | if (ConfigLevel < 2) |
1010 | _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ | |
1011 | #endif | |
779597d8 | 1012 | |
9678c96d | 1013 | if (tTd(11, 1)) |
b3cbe40f | 1014 | { |
857afefe | 1015 | printf("openmailer:"); |
6acfa498 | 1016 | printav(pv); |
b3cbe40f | 1017 | } |
d829793b | 1018 | errno = 0; |
fdcfa6b8 EA |
1019 | #if NAMED_BIND |
1020 | h_errno = 0; | |
1021 | #endif | |
779597d8 | 1022 | |
a542cc51 | 1023 | CurHostName = NULL; |
57c97d4a | 1024 | |
1ab402f2 EA |
1025 | /* |
1026 | ** Deal with the special case of mail handled through an IPC | |
1027 | ** connection. | |
1028 | ** In this case we don't actually fork. We must be | |
1029 | ** running SMTP for this to work. We will return a | |
1030 | ** zero pid to indicate that we are running IPC. | |
5463e94d | 1031 | ** We also handle a debug version that just talks to stdin/out. |
1ab402f2 EA |
1032 | */ |
1033 | ||
6acfa498 | 1034 | curhost = NULL; |
649a3283 | 1035 | SmtpPhase = NULL; |
fe3849ea | 1036 | mci = NULL; |
6acfa498 | 1037 | |
a40faef5 | 1038 | #if XDEBUG |
061a3d08 EA |
1039 | { |
1040 | char wbuf[MAXLINE]; | |
1041 | ||
1042 | /* make absolutely certain 0, 1, and 2 are in use */ | |
1043 | sprintf(wbuf, "%s... openmailer(%s)", e->e_to, m->m_name); | |
1044 | checkfd012(wbuf); | |
1045 | } | |
1046 | #endif | |
1047 | ||
e3c84ea8 EA |
1048 | /* check for 8-bit available */ |
1049 | if (bitset(EF_HAS8BIT, e->e_flags) && | |
1050 | bitnset(M_7BITS, m->m_flags) && | |
a5386d1b EA |
1051 | (!bitset(MM_MIME8BIT, MimeMode) || |
1052 | bitset(EF_DONT_MIME, e->e_flags))) | |
e3c84ea8 EA |
1053 | { |
1054 | usrerr("554 Cannot send 8-bit data to 7-bit destination"); | |
1055 | rcode = EX_DATAERR; | |
4e1c01f9 | 1056 | e->e_status = "5.6.3"; |
e3c84ea8 EA |
1057 | goto give_up; |
1058 | } | |
1059 | ||
5463e94d EA |
1060 | /* check for Local Person Communication -- not for mortals!!! */ |
1061 | if (strcmp(m->m_mailer, "[LPC]") == 0) | |
1062 | { | |
f2e44ded | 1063 | mci = (MCI *) xalloc(sizeof *mci); |
3eb4fac4 | 1064 | bzero((char *) mci, sizeof *mci); |
2ae0e0ed EA |
1065 | mci->mci_in = stdin; |
1066 | mci->mci_out = stdout; | |
f2e44ded | 1067 | mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; |
e62e1144 | 1068 | mci->mci_mailer = m; |
5463e94d | 1069 | } |
f2e44ded EA |
1070 | else if (strcmp(m->m_mailer, "[IPC]") == 0 || |
1071 | strcmp(m->m_mailer, "[TCP]") == 0) | |
1ab402f2 | 1072 | { |
140717b5 | 1073 | #ifdef DAEMON |
7e70d3c8 | 1074 | register int i; |
ea07b2d2 | 1075 | register u_short port = 0; |
1ab402f2 | 1076 | |
7bdee402 EA |
1077 | if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') |
1078 | { | |
1079 | syserr("null host name for %s mailer", m->m_mailer); | |
1080 | rcode = EX_CONFIG; | |
1081 | goto give_up; | |
1082 | } | |
1083 | ||
6acfa498 EA |
1084 | CurHostName = pv[1]; |
1085 | curhost = hostsignature(m, pv[1], e); | |
f2e44ded | 1086 | |
f2b8376e EA |
1087 | if (curhost == NULL || curhost[0] == '\0') |
1088 | { | |
7bdee402 | 1089 | syserr("null host signature for %s", pv[1]); |
37750f57 | 1090 | rcode = EX_CONFIG; |
6acfa498 | 1091 | goto give_up; |
f2b8376e EA |
1092 | } |
1093 | ||
1ab402f2 | 1094 | if (!clever) |
f2b8376e | 1095 | { |
b6edea3d | 1096 | syserr("554 non-clever IPC"); |
fe3849ea | 1097 | rcode = EX_CONFIG; |
6acfa498 | 1098 | goto give_up; |
f2b8376e | 1099 | } |
6acfa498 | 1100 | if (pv[2] != NULL) |
26b672df EA |
1101 | { |
1102 | port = htons(atoi(pv[2])); | |
1103 | if (port == 0) | |
1104 | { | |
1105 | struct servent *sp = getservbyname(pv[2], "tcp"); | |
1106 | ||
1107 | if (sp == NULL) | |
1108 | syserr("Service %s unknown", pv[2]); | |
1109 | else | |
1110 | port = sp->s_port; | |
1111 | } | |
1112 | } | |
6acfa498 | 1113 | tryhost: |
7e70d3c8 | 1114 | while (*curhost != '\0') |
e2abd3be | 1115 | { |
7e70d3c8 | 1116 | register char *p; |
8446c922 | 1117 | static char hostbuf[MAXNAME + 1]; |
7e70d3c8 EA |
1118 | |
1119 | /* pull the next host from the signature */ | |
1120 | p = strchr(curhost, ':'); | |
1121 | if (p == NULL) | |
1122 | p = &curhost[strlen(curhost)]; | |
fe3849ea EA |
1123 | if (p == curhost) |
1124 | { | |
1125 | syserr("deliver: null host name in signature"); | |
7c40218a | 1126 | curhost++; |
fe3849ea EA |
1127 | continue; |
1128 | } | |
7e70d3c8 EA |
1129 | strncpy(hostbuf, curhost, p - curhost); |
1130 | hostbuf[p - curhost] = '\0'; | |
1131 | if (*p != '\0') | |
1132 | p++; | |
1133 | curhost = p; | |
1134 | ||
8657d05f | 1135 | /* see if we already know that this host is fried */ |
7e70d3c8 EA |
1136 | CurHostName = hostbuf; |
1137 | mci = mci_get(hostbuf, m); | |
f2e44ded | 1138 | if (mci->mci_state != MCIS_CLOSED) |
237bda52 EA |
1139 | { |
1140 | if (tTd(11, 1)) | |
1141 | { | |
1142 | printf("openmailer: "); | |
deff97fd | 1143 | mci_dump(mci, FALSE); |
237bda52 | 1144 | } |
322eceee | 1145 | CurHostName = mci->mci_host; |
5f14cfca EA |
1146 | message("Using cached connection to %s via %s...", |
1147 | hostbuf, m->m_name); | |
6acfa498 | 1148 | break; |
237bda52 | 1149 | } |
e62e1144 | 1150 | mci->mci_mailer = m; |
f2e44ded EA |
1151 | if (mci->mci_exitstat != EX_OK) |
1152 | continue; | |
1153 | ||
1154 | /* try the connection */ | |
7e70d3c8 | 1155 | setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); |
5f14cfca | 1156 | message("Connecting to %s via %s...", |
7e70d3c8 EA |
1157 | hostbuf, m->m_name); |
1158 | i = makeconnection(hostbuf, port, mci, | |
f2e44ded EA |
1159 | bitnset(M_SECURE_PORT, m->m_flags)); |
1160 | mci->mci_exitstat = i; | |
1161 | mci->mci_errno = errno; | |
efe7f723 | 1162 | #if NAMED_BIND |
8e5c6745 EA |
1163 | mci->mci_herrno = h_errno; |
1164 | #endif | |
f2e44ded | 1165 | if (i == EX_OK) |
e2abd3be | 1166 | { |
f2e44ded EA |
1167 | mci->mci_state = MCIS_OPENING; |
1168 | mci_cache(mci); | |
8e5c6745 EA |
1169 | if (TrafficLogFile != NULL) |
1170 | fprintf(TrafficLogFile, "%05d == CONNECT %s\n", | |
1171 | getpid(), hostbuf); | |
f2e44ded | 1172 | break; |
e2abd3be | 1173 | } |
f2e44ded EA |
1174 | else if (tTd(11, 1)) |
1175 | printf("openmailer: makeconnection => stat=%d, errno=%d\n", | |
1176 | i, errno); | |
1177 | ||
2ae0e0ed EA |
1178 | /* enter status of this host */ |
1179 | setstat(i); | |
fe3849ea EA |
1180 | |
1181 | /* should print some message here for -v mode */ | |
1182 | } | |
1183 | if (mci == NULL) | |
1184 | { | |
1185 | syserr("deliver: no host name"); | |
1186 | rcode = EX_OSERR; | |
1187 | goto give_up; | |
1ea752a1 | 1188 | } |
3eb4fac4 | 1189 | mci->mci_pid = 0; |
f2e44ded | 1190 | #else /* no DAEMON */ |
b6edea3d | 1191 | syserr("554 openmailer: no IPC"); |
237bda52 EA |
1192 | if (tTd(11, 1)) |
1193 | printf("openmailer: NULL\n"); | |
fe3849ea EA |
1194 | rcode = EX_UNAVAILABLE; |
1195 | goto give_up; | |
f2e44ded | 1196 | #endif /* DAEMON */ |
1ab402f2 | 1197 | } |
f2e44ded | 1198 | else |
b3cbe40f | 1199 | { |
c1dc4fb9 EA |
1200 | /* flush any expired connections */ |
1201 | (void) mci_scan(NULL); | |
1202 | ||
1203 | /* announce the connection to verbose listeners */ | |
5f14cfca EA |
1204 | if (host == NULL || host[0] == '\0') |
1205 | message("Connecting to %s...", m->m_name); | |
1206 | else | |
1207 | message("Connecting to %s via %s...", host, m->m_name); | |
8e5c6745 | 1208 | if (TrafficLogFile != NULL) |
4a101ce5 | 1209 | { |
8e5c6745 | 1210 | char **av; |
f22c6db0 | 1211 | |
8e5c6745 EA |
1212 | fprintf(TrafficLogFile, "%05d === EXEC", getpid()); |
1213 | for (av = pv; *av != NULL; av++) | |
1214 | fprintf(TrafficLogFile, " %s", *av); | |
1215 | fprintf(TrafficLogFile, "\n"); | |
4a101ce5 EA |
1216 | } |
1217 | ||
f2e44ded EA |
1218 | /* create a pipe to shove the mail through */ |
1219 | if (pipe(mpvect) < 0) | |
1220 | { | |
f22c6db0 EA |
1221 | syserr("%s... openmailer(%s): pipe (to mailer)", |
1222 | e->e_to, m->m_name); | |
237bda52 EA |
1223 | if (tTd(11, 1)) |
1224 | printf("openmailer: NULL\n"); | |
6acfa498 EA |
1225 | rcode = EX_OSERR; |
1226 | goto give_up; | |
f2e44ded | 1227 | } |
e6b0a75b | 1228 | |
f2e44ded EA |
1229 | /* if this mailer speaks smtp, create a return pipe */ |
1230 | if (clever && pipe(rpvect) < 0) | |
1231 | { | |
f22c6db0 EA |
1232 | syserr("%s... openmailer(%s): pipe (from mailer)", |
1233 | e->e_to, m->m_name); | |
f2e44ded EA |
1234 | (void) close(mpvect[0]); |
1235 | (void) close(mpvect[1]); | |
237bda52 EA |
1236 | if (tTd(11, 1)) |
1237 | printf("openmailer: NULL\n"); | |
6acfa498 EA |
1238 | rcode = EX_OSERR; |
1239 | goto give_up; | |
f2e44ded | 1240 | } |
e6b0a75b | 1241 | |
f2e44ded EA |
1242 | /* |
1243 | ** Actually fork the mailer process. | |
1244 | ** DOFORK is clever about retrying. | |
1245 | ** | |
1246 | ** Dispose of SIGCHLD signal catchers that may be laying | |
1247 | ** around so that endmail will get it. | |
1248 | */ | |
1ab402f2 | 1249 | |
f2e44ded EA |
1250 | if (e->e_xfp != NULL) |
1251 | (void) fflush(e->e_xfp); /* for debugging */ | |
1252 | (void) fflush(stdout); | |
1cc8903f | 1253 | # ifdef SIGCHLD |
39270cfd | 1254 | (void) setsignal(SIGCHLD, SIG_DFL); |
f3d8f6d6 | 1255 | # endif /* SIGCHLD */ |
f2e44ded EA |
1256 | DOFORK(FORK); |
1257 | /* pid is set by DOFORK */ | |
1258 | if (pid < 0) | |
e6b0a75b | 1259 | { |
f2e44ded | 1260 | /* failure */ |
f22c6db0 EA |
1261 | syserr("%s... openmailer(%s): cannot fork", |
1262 | e->e_to, m->m_name); | |
f2e44ded EA |
1263 | (void) close(mpvect[0]); |
1264 | (void) close(mpvect[1]); | |
1265 | if (clever) | |
1266 | { | |
1267 | (void) close(rpvect[0]); | |
1268 | (void) close(rpvect[1]); | |
1269 | } | |
237bda52 EA |
1270 | if (tTd(11, 1)) |
1271 | printf("openmailer: NULL\n"); | |
6acfa498 EA |
1272 | rcode = EX_OSERR; |
1273 | goto give_up; | |
e6b0a75b | 1274 | } |
f2e44ded EA |
1275 | else if (pid == 0) |
1276 | { | |
1277 | int i; | |
f62b79ae | 1278 | int saveerrno; |
33a75b9a | 1279 | struct stat stb; |
f2e44ded | 1280 | extern int DtableSize; |
f2ba91d2 | 1281 | |
2c2b6557 | 1282 | if (e->e_lockfp != NULL) |
633a3177 | 1283 | (void) close(fileno(e->e_lockfp)); |
2c2b6557 | 1284 | |
f2e44ded | 1285 | /* child -- set up input & exec mailer */ |
39270cfd EA |
1286 | (void) setsignal(SIGINT, SIG_IGN); |
1287 | (void) setsignal(SIGHUP, SIG_IGN); | |
1288 | (void) setsignal(SIGTERM, SIG_DFL); | |
49086753 | 1289 | |
7af42ad2 | 1290 | if (m != FileMailer || stat(tochain->q_user, &stb) < 0) |
33a75b9a EA |
1291 | stb.st_mode = 0; |
1292 | ||
dcc15ef5 EA |
1293 | /* tweak niceness */ |
1294 | if (m->m_nice != 0) | |
1295 | nice(m->m_nice); | |
1296 | ||
33a75b9a | 1297 | /* reset group id */ |
1ff27f9b | 1298 | if (bitnset(M_SPECIFIC_UID, m->m_flags)) |
1ff27f9b | 1299 | (void) setgid(m->m_gid); |
33a75b9a EA |
1300 | else if (bitset(S_ISGID, stb.st_mode)) |
1301 | (void) setgid(stb.st_gid); | |
1302 | else if (ctladdr != NULL && ctladdr->q_gid != 0) | |
f5195abb EA |
1303 | { |
1304 | (void) initgroups(ctladdr->q_ruser? | |
1305 | ctladdr->q_ruser: ctladdr->q_user, | |
1306 | ctladdr->q_gid); | |
1307 | (void) setgid(ctladdr->q_gid); | |
f5195abb | 1308 | } |
1ff27f9b | 1309 | else |
8d6e073f | 1310 | { |
f5195abb EA |
1311 | (void) initgroups(DefUser, DefGid); |
1312 | if (m->m_gid == 0) | |
94d9df0e | 1313 | (void) setgid(DefGid); |
f5195abb EA |
1314 | else |
1315 | (void) setgid(m->m_gid); | |
33a75b9a EA |
1316 | } |
1317 | ||
1318 | /* reset user id */ | |
1319 | if (bitnset(M_SPECIFIC_UID, m->m_flags)) | |
1320 | (void) setuid(m->m_uid); | |
1321 | else if (bitset(S_ISUID, stb.st_mode)) | |
1322 | (void) setuid(stb.st_uid); | |
1323 | else if (ctladdr != NULL && ctladdr->q_uid != 0) | |
1324 | (void) setuid(ctladdr->q_uid); | |
1325 | else | |
1326 | { | |
f5195abb | 1327 | if (m->m_uid == 0) |
8d6e073f | 1328 | (void) setuid(DefUid); |
8d6e073f | 1329 | else |
f5195abb | 1330 | (void) setuid(m->m_uid); |
8d6e073f EA |
1331 | } |
1332 | ||
1333 | if (tTd(11, 2)) | |
1334 | printf("openmailer: running as r/euid=%d/%d\n", | |
1335 | getuid(), geteuid()); | |
1336 | ||
6f5db107 EA |
1337 | /* move into some "safe" directory */ |
1338 | if (m->m_execdir != NULL) | |
1339 | { | |
1340 | char *p, *q; | |
8446c922 | 1341 | char buf[MAXLINE + 1]; |
6f5db107 EA |
1342 | |
1343 | for (p = m->m_execdir; p != NULL; p = q) | |
1344 | { | |
1345 | q = strchr(p, ':'); | |
1346 | if (q != NULL) | |
1347 | *q = '\0'; | |
832e8a27 | 1348 | expand(p, buf, sizeof buf, e); |
6f5db107 EA |
1349 | if (q != NULL) |
1350 | *q++ = ':'; | |
1351 | if (tTd(11, 20)) | |
1352 | printf("openmailer: trydir %s\n", | |
1353 | buf); | |
1354 | if (buf[0] != '\0' && chdir(buf) >= 0) | |
1355 | break; | |
1356 | } | |
1357 | } | |
1358 | ||
f2e44ded EA |
1359 | /* arrange to filter std & diag output of command */ |
1360 | if (clever) | |
1361 | { | |
1362 | (void) close(rpvect[0]); | |
4a101ce5 EA |
1363 | if (dup2(rpvect[1], STDOUT_FILENO) < 0) |
1364 | { | |
f22c6db0 EA |
1365 | syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", |
1366 | e->e_to, m->m_name, rpvect[1]); | |
4a101ce5 EA |
1367 | _exit(EX_OSERR); |
1368 | } | |
f2e44ded EA |
1369 | (void) close(rpvect[1]); |
1370 | } | |
52f56f58 EA |
1371 | else if (OpMode == MD_SMTP || OpMode == MD_DAEMON || |
1372 | HoldErrs || DisConnected) | |
f2e44ded EA |
1373 | { |
1374 | /* put mailer output in transcript */ | |
4a101ce5 EA |
1375 | if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) |
1376 | { | |
f22c6db0 EA |
1377 | syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", |
1378 | e->e_to, m->m_name, | |
4a101ce5 EA |
1379 | fileno(e->e_xfp)); |
1380 | _exit(EX_OSERR); | |
1381 | } | |
1382 | } | |
1383 | if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) | |
1384 | { | |
f22c6db0 EA |
1385 | syserr("%s... openmailer(%s): cannot dup stdout for stderr", |
1386 | e->e_to, m->m_name); | |
4a101ce5 | 1387 | _exit(EX_OSERR); |
f2e44ded | 1388 | } |
49086753 | 1389 | |
f2e44ded EA |
1390 | /* arrange to get standard input */ |
1391 | (void) close(mpvect[1]); | |
d74803dd | 1392 | if (dup2(mpvect[0], STDIN_FILENO) < 0) |
208e82d2 | 1393 | { |
f22c6db0 EA |
1394 | syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", |
1395 | e->e_to, m->m_name, mpvect[0]); | |
f2e44ded | 1396 | _exit(EX_OSERR); |
208e82d2 | 1397 | } |
f2e44ded | 1398 | (void) close(mpvect[0]); |
7338e3d4 | 1399 | |
f2e44ded EA |
1400 | /* arrange for all the files to be closed */ |
1401 | for (i = 3; i < DtableSize; i++) | |
1402 | { | |
1403 | register int j; | |
8d6e073f | 1404 | |
f2e44ded | 1405 | if ((j = fcntl(i, F_GETFD, 0)) != -1) |
8d6e073f | 1406 | (void) fcntl(i, F_SETFD, j | 1); |
f2e44ded | 1407 | } |
1ab402f2 | 1408 | |
53d9380f EA |
1409 | /* run disconnected from terminal */ |
1410 | (void) setsid(); | |
1411 | ||
f2e44ded | 1412 | /* try to execute the mailer */ |
05b75231 | 1413 | execve(m->m_mailer, (ARGV_T) pv, (ARGV_T) UserEnviron); |
f62b79ae | 1414 | saveerrno = errno; |
f2e44ded | 1415 | syserr("Cannot exec %s", m->m_mailer); |
2bade550 EA |
1416 | if (bitnset(M_LOCALMAILER, m->m_flags) || |
1417 | transienterror(saveerrno)) | |
55b12947 | 1418 | _exit(EX_OSERR); |
f2e44ded EA |
1419 | _exit(EX_UNAVAILABLE); |
1420 | } | |
1421 | ||
1422 | /* | |
1423 | ** Set up return value. | |
1424 | */ | |
1425 | ||
1426 | mci = (MCI *) xalloc(sizeof *mci); | |
3eb4fac4 | 1427 | bzero((char *) mci, sizeof *mci); |
f2e44ded EA |
1428 | mci->mci_mailer = m; |
1429 | mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; | |
3eb4fac4 | 1430 | mci->mci_pid = pid; |
f2e44ded EA |
1431 | (void) close(mpvect[0]); |
1432 | mci->mci_out = fdopen(mpvect[1], "w"); | |
e9d81da2 EA |
1433 | if (mci->mci_out == NULL) |
1434 | { | |
1435 | syserr("deliver: cannot create mailer output channel, fd=%d", | |
1436 | mpvect[1]); | |
1437 | (void) close(mpvect[1]); | |
1438 | if (clever) | |
1439 | { | |
1440 | (void) close(rpvect[0]); | |
1441 | (void) close(rpvect[1]); | |
1442 | } | |
1443 | rcode = EX_OSERR; | |
1444 | goto give_up; | |
1445 | } | |
f2e44ded EA |
1446 | if (clever) |
1447 | { | |
1448 | (void) close(rpvect[1]); | |
1449 | mci->mci_in = fdopen(rpvect[0], "r"); | |
e9d81da2 EA |
1450 | if (mci->mci_in == NULL) |
1451 | { | |
1452 | syserr("deliver: cannot create mailer input channel, fd=%d", | |
1453 | mpvect[1]); | |
1454 | (void) close(rpvect[0]); | |
1455 | fclose(mci->mci_out); | |
1456 | mci->mci_out = NULL; | |
1457 | rcode = EX_OSERR; | |
1458 | goto give_up; | |
1459 | } | |
f2e44ded EA |
1460 | } |
1461 | else | |
1462 | { | |
1463 | mci->mci_flags |= MCIF_TEMP; | |
1464 | mci->mci_in = NULL; | |
4287d84d | 1465 | } |
b3cbe40f EA |
1466 | } |
1467 | ||
6acfa498 EA |
1468 | /* |
1469 | ** If we are in SMTP opening state, send initial protocol. | |
1470 | */ | |
1471 | ||
1472 | if (clever && mci->mci_state != MCIS_CLOSED) | |
1473 | { | |
1474 | smtpinit(m, mci, e); | |
1475 | } | |
f900f13b EA |
1476 | |
1477 | if (bitset(EF_HAS8BIT, e->e_flags) && bitnset(M_7BITS, m->m_flags)) | |
1478 | mci->mci_flags |= MCIF_CVT8TO7; | |
1479 | else | |
1480 | mci->mci_flags &= ~MCIF_CVT8TO7; | |
1481 | ||
6acfa498 EA |
1482 | if (tTd(11, 1)) |
1483 | { | |
1484 | printf("openmailer: "); | |
deff97fd | 1485 | mci_dump(mci, FALSE); |
6acfa498 EA |
1486 | } |
1487 | ||
1488 | if (mci->mci_state != MCIS_OPEN) | |
1489 | { | |
1490 | /* couldn't open the mailer */ | |
1491 | rcode = mci->mci_exitstat; | |
1492 | errno = mci->mci_errno; | |
efe7f723 | 1493 | #if NAMED_BIND |
8e5c6745 EA |
1494 | h_errno = mci->mci_herrno; |
1495 | #endif | |
6acfa498 EA |
1496 | if (rcode == EX_OK) |
1497 | { | |
1498 | /* shouldn't happen */ | |
1499 | syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", | |
1500 | rcode, mci->mci_state, firstsig); | |
1501 | rcode = EX_SOFTWARE; | |
1502 | } | |
c7a0eaaf | 1503 | else if (curhost != NULL && *curhost != '\0') |
e80c91fc EA |
1504 | { |
1505 | /* try next MX site */ | |
1506 | goto tryhost; | |
1507 | } | |
6acfa498 EA |
1508 | } |
1509 | else if (!clever) | |
1510 | { | |
1511 | /* | |
1512 | ** Format and send message. | |
1513 | */ | |
1514 | ||
23fafb99 | 1515 | putfromline(mci, e); |
51d448e5 EA |
1516 | (*e->e_puthdr)(mci, e->e_header, e); |
1517 | (*e->e_putbody)(mci, e, NULL); | |
6acfa498 EA |
1518 | |
1519 | /* get the exit status */ | |
1520 | rcode = endmailer(mci, e, pv); | |
1521 | } | |
1522 | else | |
1523 | #ifdef SMTP | |
1524 | { | |
1525 | /* | |
1526 | ** Send the MAIL FROM: protocol | |
1527 | */ | |
1528 | ||
1529 | rcode = smtpmailfrom(m, mci, e); | |
1530 | if (rcode == EX_OK) | |
1531 | { | |
1532 | register char *t = tobuf; | |
1533 | register int i; | |
1534 | ||
1535 | /* send the recipient list */ | |
1536 | tobuf[0] = '\0'; | |
1537 | for (to = tochain; to != NULL; to = to->q_tchain) | |
1538 | { | |
1539 | e->e_to = to->q_paddr; | |
1540 | if ((i = smtprcpt(to, m, mci, e)) != EX_OK) | |
1541 | { | |
a542cc51 | 1542 | markfailure(e, to, mci, i); |
3500a891 | 1543 | giveresponse(i, m, mci, ctladdr, xstart, e); |
6acfa498 EA |
1544 | } |
1545 | else | |
1546 | { | |
1547 | *t++ = ','; | |
1548 | for (p = to->q_paddr; *p; *t++ = *p++) | |
1549 | continue; | |
51d3cbf1 | 1550 | *t = '\0'; |
6acfa498 EA |
1551 | } |
1552 | } | |
1553 | ||
1554 | /* now send the data */ | |
1555 | if (tobuf[0] == '\0') | |
1556 | { | |
1557 | rcode = EX_OK; | |
1558 | e->e_to = NULL; | |
1559 | if (bitset(MCIF_CACHED, mci->mci_flags)) | |
1560 | smtprset(m, mci, e); | |
1561 | } | |
1562 | else | |
1563 | { | |
1564 | e->e_to = tobuf + 1; | |
1565 | rcode = smtpdata(m, mci, e); | |
1566 | } | |
1567 | ||
1568 | /* now close the connection */ | |
1569 | if (!bitset(MCIF_CACHED, mci->mci_flags)) | |
1570 | smtpquit(m, mci, e); | |
1571 | } | |
95203269 | 1572 | if (rcode != EX_OK && curhost != NULL && *curhost != '\0') |
6acfa498 EA |
1573 | { |
1574 | /* try next MX site */ | |
1575 | goto tryhost; | |
1576 | } | |
1577 | } | |
1578 | #else /* not SMTP */ | |
1579 | { | |
1580 | syserr("554 deliver: need SMTP compiled to use clever mailer"); | |
1581 | rcode = EX_CONFIG; | |
1582 | goto give_up; | |
1583 | } | |
1584 | #endif /* SMTP */ | |
efe7f723 | 1585 | #if NAMED_BIND |
6acfa498 EA |
1586 | if (ConfigLevel < 2) |
1587 | _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ | |
1588 | #endif | |
1589 | ||
1590 | /* arrange a return receipt if requested */ | |
fe3849ea EA |
1591 | if (rcode == EX_OK && e->e_receiptto != NULL && |
1592 | bitnset(M_LOCALMAILER, m->m_flags)) | |
6acfa498 EA |
1593 | { |
1594 | e->e_flags |= EF_SENDRECEIPT; | |
1595 | /* do we want to send back more info? */ | |
1596 | } | |
1597 | ||
1598 | /* | |
1599 | ** Do final status disposal. | |
1600 | ** We check for something in tobuf for the SMTP case. | |
1601 | ** If we got a temporary failure, arrange to queue the | |
1602 | ** addressees. | |
1603 | */ | |
1604 | ||
1605 | give_up: | |
1606 | if (tobuf[0] != '\0') | |
3500a891 | 1607 | giveresponse(rcode, m, mci, ctladdr, xstart, e); |
6acfa498 EA |
1608 | for (to = tochain; to != NULL; to = to->q_tchain) |
1609 | { | |
1610 | if (rcode != EX_OK) | |
a542cc51 | 1611 | markfailure(e, to, mci, rcode); |
c8e44a17 | 1612 | else if (!bitset(QBADADDR|QQUEUEUP, to->q_flags)) |
6acfa498 EA |
1613 | { |
1614 | to->q_flags |= QSENT; | |
f8c2f9fd | 1615 | to->q_statdate = curtime(); |
6acfa498 | 1616 | e->e_nsent++; |
68d9129a EA |
1617 | if (bitnset(M_LOCALMAILER, m->m_flags) && |
1618 | (e->e_receiptto != NULL || | |
1619 | bitset(QPINGONSUCCESS, to->q_flags))) | |
fe3849ea | 1620 | { |
126c1099 | 1621 | to->q_flags |= QDELIVERED; |
7905af2d | 1622 | to->q_status = "2.1.5"; |
fe3849ea EA |
1623 | fprintf(e->e_xfp, "%s... Successfully delivered\n", |
1624 | to->q_paddr); | |
1625 | } | |
c8e44a17 | 1626 | else if (bitset(QPINGONSUCCESS, to->q_flags) && |
66d16835 | 1627 | bitset(QPRIMARY, to->q_flags) && |
c8e44a17 EA |
1628 | !bitset(MCIF_DSN, mci->mci_flags)) |
1629 | { | |
1630 | to->q_flags |= QRELAYED; | |
1631 | fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n", | |
1632 | to->q_paddr); | |
1633 | } | |
6acfa498 EA |
1634 | } |
1635 | } | |
1636 | ||
1637 | /* | |
1638 | ** Restore state and return. | |
1639 | */ | |
1640 | ||
a40faef5 | 1641 | #if XDEBUG |
061a3d08 EA |
1642 | { |
1643 | char wbuf[MAXLINE]; | |
1644 | ||
1645 | /* make absolutely certain 0, 1, and 2 are in use */ | |
164f3011 EA |
1646 | sprintf(wbuf, "%s... end of deliver(%s)", |
1647 | e->e_to == NULL ? "NO-TO-LIST" : e->e_to, | |
1648 | m->m_name); | |
061a3d08 EA |
1649 | checkfd012(wbuf); |
1650 | } | |
1651 | #endif | |
1652 | ||
6acfa498 EA |
1653 | errno = 0; |
1654 | define('g', (char *) NULL, e); | |
1655 | return (rcode); | |
1656 | } | |
1657 | \f/* | |
1658 | ** MARKFAILURE -- mark a failure on a specific address. | |
1659 | ** | |
1660 | ** Parameters: | |
1661 | ** e -- the envelope we are sending. | |
1662 | ** q -- the address to mark. | |
a542cc51 | 1663 | ** mci -- mailer connection information. |
6acfa498 EA |
1664 | ** rcode -- the code signifying the particular failure. |
1665 | ** | |
1666 | ** Returns: | |
1667 | ** none. | |
1668 | ** | |
1669 | ** Side Effects: | |
1670 | ** marks the address (and possibly the envelope) with the | |
1671 | ** failure so that an error will be returned or | |
1672 | ** the message will be queued, as appropriate. | |
1673 | */ | |
1674 | ||
179d940c | 1675 | void |
a542cc51 | 1676 | markfailure(e, q, mci, rcode) |
6acfa498 EA |
1677 | register ENVELOPE *e; |
1678 | register ADDRESS *q; | |
a542cc51 | 1679 | register MCI *mci; |
6acfa498 EA |
1680 | int rcode; |
1681 | { | |
a542cc51 | 1682 | char *stat = NULL; |
6acfa498 | 1683 | |
26c2fd9b EA |
1684 | switch (rcode) |
1685 | { | |
1686 | case EX_OK: | |
1687 | break; | |
1688 | ||
1689 | case EX_TEMPFAIL: | |
1690 | case EX_IOERR: | |
1691 | case EX_OSERR: | |
6acfa498 | 1692 | q->q_flags |= QQUEUEUP; |
26c2fd9b EA |
1693 | break; |
1694 | ||
1695 | default: | |
8e5c6745 | 1696 | q->q_flags |= QBADADDR; |
26c2fd9b EA |
1697 | break; |
1698 | } | |
a542cc51 | 1699 | |
4e1c01f9 | 1700 | /* find most specific error code possible */ |
a542cc51 EA |
1701 | if (q->q_status == NULL && mci != NULL) |
1702 | q->q_status = mci->mci_status; | |
4e1c01f9 EA |
1703 | if (q->q_status == NULL) |
1704 | q->q_status = e->e_status; | |
1705 | if (q->q_status == NULL) | |
a542cc51 | 1706 | { |
4e1c01f9 EA |
1707 | switch (rcode) |
1708 | { | |
1709 | case EX_USAGE: | |
1710 | stat = "5.5.4"; | |
1711 | break; | |
a542cc51 | 1712 | |
4e1c01f9 EA |
1713 | case EX_DATAERR: |
1714 | stat = "5.5.2"; | |
1715 | break; | |
a542cc51 | 1716 | |
4e1c01f9 EA |
1717 | case EX_NOUSER: |
1718 | stat = "5.1.1"; | |
1719 | break; | |
09d45ea9 | 1720 | |
4e1c01f9 EA |
1721 | case EX_NOHOST: |
1722 | stat = "5.1.2"; | |
1723 | break; | |
a542cc51 | 1724 | |
4e1c01f9 EA |
1725 | case EX_NOINPUT: |
1726 | case EX_CANTCREAT: | |
1727 | case EX_NOPERM: | |
1728 | stat = "5.3.0"; | |
1729 | break; | |
a542cc51 | 1730 | |
4e1c01f9 EA |
1731 | case EX_UNAVAILABLE: |
1732 | case EX_SOFTWARE: | |
1733 | case EX_OSFILE: | |
1734 | case EX_PROTOCOL: | |
1735 | case EX_CONFIG: | |
1736 | stat = "5.5.0"; | |
1737 | break; | |
a542cc51 | 1738 | |
4e1c01f9 EA |
1739 | case EX_OSERR: |
1740 | case EX_IOERR: | |
1741 | stat = "4.5.0"; | |
1742 | break; | |
1743 | ||
1744 | case EX_TEMPFAIL: | |
1745 | stat = "4.2.0"; | |
1746 | break; | |
1747 | } | |
1748 | if (stat != NULL) | |
1749 | q->q_status = stat; | |
a542cc51 | 1750 | } |
a542cc51 | 1751 | |
68d9129a | 1752 | q->q_statdate = curtime(); |
429602a4 EA |
1753 | if (CurHostName != NULL && CurHostName[0] != '\0') |
1754 | q->q_statmta = newstr(CurHostName); | |
a542cc51 EA |
1755 | if (rcode != EX_OK && q->q_rstatus == NULL) |
1756 | { | |
1757 | char buf[30]; | |
1758 | ||
1759 | (void) sprintf(buf, "%d", rcode); | |
1760 | q->q_rstatus = newstr(buf); | |
1761 | } | |
6acfa498 EA |
1762 | } |
1763 | \f/* | |
1764 | ** ENDMAILER -- Wait for mailer to terminate. | |
1765 | ** | |
1766 | ** We should never get fatal errors (e.g., segmentation | |
1767 | ** violation), so we report those specially. For other | |
1768 | ** errors, we choose a status message (into statmsg), | |
1769 | ** and if it represents an error, we print it. | |
1770 | ** | |
1771 | ** Parameters: | |
1772 | ** pid -- pid of mailer. | |
1773 | ** e -- the current envelope. | |
1774 | ** pv -- the parameter vector that invoked the mailer | |
1775 | ** (for error messages). | |
1776 | ** | |
1777 | ** Returns: | |
1778 | ** exit code of mailer. | |
1779 | ** | |
1780 | ** Side Effects: | |
1781 | ** none. | |
1782 | */ | |
1783 | ||
179d940c | 1784 | int |
6acfa498 EA |
1785 | endmailer(mci, e, pv) |
1786 | register MCI *mci; | |
1787 | register ENVELOPE *e; | |
1788 | char **pv; | |
1789 | { | |
1790 | int st; | |
1791 | ||
1792 | /* close any connections */ | |
1793 | if (mci->mci_in != NULL) | |
14809fd5 | 1794 | (void) xfclose(mci->mci_in, mci->mci_mailer->m_name, "mci_in"); |
6acfa498 | 1795 | if (mci->mci_out != NULL) |
14809fd5 | 1796 | (void) xfclose(mci->mci_out, mci->mci_mailer->m_name, "mci_out"); |
6acfa498 EA |
1797 | mci->mci_in = mci->mci_out = NULL; |
1798 | mci->mci_state = MCIS_CLOSED; | |
49086753 | 1799 | |
6acfa498 EA |
1800 | /* in the IPC case there is nothing to wait for */ |
1801 | if (mci->mci_pid == 0) | |
1802 | return (EX_OK); | |
1803 | ||
1804 | /* wait for the mailer process to die and collect status */ | |
1805 | st = waitfor(mci->mci_pid); | |
1806 | if (st == -1) | |
b3cbe40f | 1807 | { |
6acfa498 EA |
1808 | syserr("endmailer %s: wait", pv[0]); |
1809 | return (EX_SOFTWARE); | |
2ae0e0ed | 1810 | } |
6acfa498 | 1811 | |
e3791bb6 | 1812 | if (WIFEXITED(st)) |
237bda52 | 1813 | { |
e3791bb6 EA |
1814 | /* normal death -- return status */ |
1815 | return (WEXITSTATUS(st)); | |
1816 | } | |
6acfa498 | 1817 | |
e3791bb6 | 1818 | /* it died a horrid death */ |
0baa9aea EA |
1819 | syserr("451 mailer %s died with signal %o", |
1820 | mci->mci_mailer->m_name, st); | |
6acfa498 | 1821 | |
e3791bb6 | 1822 | /* log the arguments */ |
c1e6eba2 | 1823 | if (pv != NULL && e->e_xfp != NULL) |
e3791bb6 EA |
1824 | { |
1825 | register char **av; | |
6acfa498 | 1826 | |
e3791bb6 EA |
1827 | fprintf(e->e_xfp, "Arguments:"); |
1828 | for (av = pv; *av != NULL; av++) | |
1829 | fprintf(e->e_xfp, " %s", *av); | |
1830 | fprintf(e->e_xfp, "\n"); | |
237bda52 | 1831 | } |
e6b0a75b | 1832 | |
e3791bb6 EA |
1833 | ExitStat = EX_TEMPFAIL; |
1834 | return (EX_TEMPFAIL); | |
b3cbe40f EA |
1835 | } |
1836 | \f/* | |
1837 | ** GIVERESPONSE -- Interpret an error response from a mailer | |
1838 | ** | |
1839 | ** Parameters: | |
1840 | ** stat -- the status code from the mailer (high byte | |
1841 | ** only; core dumps must have been taken care of | |
1842 | ** already). | |
c0ae0b24 EA |
1843 | ** m -- the mailer info for this mailer. |
1844 | ** mci -- the mailer connection info -- can be NULL if the | |
1845 | ** response is given before the connection is made. | |
5c18c358 EA |
1846 | ** ctladdr -- the controlling address for the recipient |
1847 | ** address(es). | |
3500a891 EA |
1848 | ** xstart -- the transaction start time, for computing |
1849 | ** transaction delays. | |
c0ae0b24 | 1850 | ** e -- the current envelope. |
b3cbe40f EA |
1851 | ** |
1852 | ** Returns: | |
29871fef | 1853 | ** none. |
b3cbe40f EA |
1854 | ** |
1855 | ** Side Effects: | |
d916f0ca | 1856 | ** Errors may be incremented. |
b3cbe40f | 1857 | ** ExitStat may be set. |
b3cbe40f EA |
1858 | */ |
1859 | ||
179d940c | 1860 | void |
3500a891 | 1861 | giveresponse(stat, m, mci, ctladdr, xstart, e) |
b3cbe40f | 1862 | int stat; |
7338e3d4 | 1863 | register MAILER *m; |
c0ae0b24 | 1864 | register MCI *mci; |
5c18c358 | 1865 | ADDRESS *ctladdr; |
3500a891 | 1866 | time_t xstart; |
baa0c390 | 1867 | ENVELOPE *e; |
b3cbe40f | 1868 | { |
c51d6c4c | 1869 | register const char *statmsg; |
b3cbe40f EA |
1870 | extern char *SysExMsg[]; |
1871 | register int i; | |
a0c75a49 | 1872 | extern int N_SysEx; |
baa0c390 | 1873 | char buf[MAXLINE]; |
b3cbe40f | 1874 | |
74c5fe7c EA |
1875 | /* |
1876 | ** Compute status message from code. | |
1877 | */ | |
1878 | ||
b3cbe40f | 1879 | i = stat - EX__BASE; |
7338e3d4 | 1880 | if (stat == 0) |
4a101ce5 | 1881 | { |
7338e3d4 | 1882 | statmsg = "250 Sent"; |
988a20e2 | 1883 | if (e->e_statmsg != NULL) |
4a101ce5 | 1884 | { |
988a20e2 | 1885 | (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); |
4a101ce5 EA |
1886 | statmsg = buf; |
1887 | } | |
1888 | } | |
7338e3d4 EA |
1889 | else if (i < 0 || i > N_SysEx) |
1890 | { | |
1891 | (void) sprintf(buf, "554 unknown mailer error %d", stat); | |
1892 | stat = EX_UNAVAILABLE; | |
1893 | statmsg = buf; | |
1894 | } | |
baa0c390 EA |
1895 | else if (stat == EX_TEMPFAIL) |
1896 | { | |
2388926b | 1897 | (void) strcpy(buf, SysExMsg[i] + 1); |
efe7f723 | 1898 | #if NAMED_BIND |
88d7486c | 1899 | if (h_errno == TRY_AGAIN) |
92f2b65e | 1900 | statmsg = errstring(h_errno+E_DNSBASE); |
46f6ec52 | 1901 | else |
a0c75a49 | 1902 | #endif |
46f6ec52 | 1903 | { |
88d7486c | 1904 | if (errno != 0) |
88d7486c | 1905 | statmsg = errstring(errno); |
88d7486c MAN |
1906 | else |
1907 | { | |
46f6ec52 | 1908 | #ifdef SMTP |
88d7486c | 1909 | statmsg = SmtpError; |
f3d8f6d6 | 1910 | #else /* SMTP */ |
88d7486c | 1911 | statmsg = NULL; |
f3d8f6d6 | 1912 | #endif /* SMTP */ |
88d7486c | 1913 | } |
46f6ec52 EA |
1914 | } |
1915 | if (statmsg != NULL && statmsg[0] != '\0') | |
1916 | { | |
e41c463e | 1917 | (void) strcat(buf, ": "); |
46f6ec52 | 1918 | (void) strcat(buf, statmsg); |
baa0c390 | 1919 | } |
baa0c390 EA |
1920 | statmsg = buf; |
1921 | } | |
efe7f723 | 1922 | #if NAMED_BIND |
8e5c6745 EA |
1923 | else if (stat == EX_NOHOST && h_errno != 0) |
1924 | { | |
92f2b65e | 1925 | statmsg = errstring(h_errno + E_DNSBASE); |
1fd465b3 | 1926 | (void) sprintf(buf, "%s (%s)", SysExMsg[i] + 1, statmsg); |
8e5c6745 EA |
1927 | statmsg = buf; |
1928 | } | |
1929 | #endif | |
b3cbe40f | 1930 | else |
46f6ec52 | 1931 | { |
b3cbe40f | 1932 | statmsg = SysExMsg[i]; |
2388926b EA |
1933 | if (*statmsg++ == ':') |
1934 | { | |
1935 | (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); | |
1936 | statmsg = buf; | |
1937 | } | |
46f6ec52 | 1938 | } |
7338e3d4 EA |
1939 | |
1940 | /* | |
1941 | ** Print the message as appropriate | |
1942 | */ | |
1943 | ||
baa0c390 | 1944 | if (stat == EX_OK || stat == EX_TEMPFAIL) |
fe3849ea EA |
1945 | { |
1946 | extern char MsgBuf[]; | |
1947 | ||
b10e0325 | 1948 | message("%s", &statmsg[4]); |
fe3849ea EA |
1949 | if (stat == EX_TEMPFAIL && e->e_xfp != NULL) |
1950 | fprintf(e->e_xfp, "%s\n", &MsgBuf[4]); | |
1951 | } | |
b3cbe40f EA |
1952 | else |
1953 | { | |
1fd465b3 EA |
1954 | char mbuf[8]; |
1955 | ||
d916f0ca | 1956 | Errors++; |
1fd465b3 EA |
1957 | sprintf(mbuf, "%.3s %%s", statmsg); |
1958 | usrerr(mbuf, &statmsg[4]); | |
b3cbe40f EA |
1959 | } |
1960 | ||
1961 | /* | |
1962 | ** Final cleanup. | |
1963 | ** Log a record of the transaction. Compute the new | |
1964 | ** ExitStat -- if we already had an error, stick with | |
1965 | ** that. | |
1966 | */ | |
1967 | ||
68f7099c | 1968 | if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) |
3500a891 | 1969 | logdelivery(m, mci, &statmsg[4], ctladdr, xstart, e); |
96476cab | 1970 | |
ed3d2b02 EA |
1971 | if (tTd(11, 2)) |
1972 | printf("giveresponse: stat=%d, e->e_message=%s\n", | |
7ad0fe38 | 1973 | stat, e->e_message == NULL ? "<NULL>" : e->e_message); |
ed3d2b02 | 1974 | |
ed45aae1 EA |
1975 | if (stat != EX_TEMPFAIL) |
1976 | setstat(stat); | |
f2a96b27 | 1977 | if (stat != EX_OK && (stat != EX_TEMPFAIL || e->e_message == NULL)) |
baa0c390 EA |
1978 | { |
1979 | if (e->e_message != NULL) | |
1980 | free(e->e_message); | |
1981 | e->e_message = newstr(&statmsg[4]); | |
1982 | } | |
e4602f52 | 1983 | errno = 0; |
efe7f723 | 1984 | #if NAMED_BIND |
88d7486c | 1985 | h_errno = 0; |
a0c75a49 | 1986 | #endif |
b3cbe40f EA |
1987 | } |
1988 | \f/* | |
fe033a8f EA |
1989 | ** LOGDELIVERY -- log the delivery in the system log |
1990 | ** | |
eaad1064 EA |
1991 | ** Care is taken to avoid logging lines that are too long, because |
1992 | ** some versions of syslog have an unfortunate proclivity for core | |
1993 | ** dumping. This is a hack, to be sure, that is at best empirical. | |
1994 | ** | |
fe033a8f | 1995 | ** Parameters: |
c0ae0b24 EA |
1996 | ** m -- the mailer info. Can be NULL for initial queue. |
1997 | ** mci -- the mailer connection info -- can be NULL if the | |
1998 | ** log is occuring when no connection is active. | |
1999 | ** stat -- the message to print for the status. | |
5c18c358 | 2000 | ** ctladdr -- the controlling address for the to list. |
3500a891 EA |
2001 | ** xstart -- the transaction start time, used for |
2002 | ** computing transaction delay. | |
c0ae0b24 | 2003 | ** e -- the current envelope. |
fe033a8f EA |
2004 | ** |
2005 | ** Returns: | |
2006 | ** none | |
2007 | ** | |
2008 | ** Side Effects: | |
2009 | ** none | |
2010 | */ | |
2011 | ||
179d940c | 2012 | void |
3500a891 | 2013 | logdelivery(m, mci, stat, ctladdr, xstart, e) |
c0ae0b24 EA |
2014 | MAILER *m; |
2015 | register MCI *mci; | |
179d940c | 2016 | const char *stat; |
5c18c358 | 2017 | ADDRESS *ctladdr; |
3500a891 | 2018 | time_t xstart; |
f2e44ded | 2019 | register ENVELOPE *e; |
fe033a8f | 2020 | { |
fc93dffb | 2021 | # ifdef LOG |
5c18c358 | 2022 | register char *bp; |
eaad1064 EA |
2023 | register char *p; |
2024 | int l; | |
ef71c549 | 2025 | char buf[512]; |
fe033a8f | 2026 | |
2bbc90ee | 2027 | # if (SYSLOG_BUFSIZE) >= 256 |
5c18c358 EA |
2028 | bp = buf; |
2029 | if (ctladdr != NULL) | |
2030 | { | |
2031 | strcpy(bp, ", ctladdr="); | |
ab88ddec | 2032 | strcat(bp, shortenstring(ctladdr->q_paddr, 83)); |
5c18c358 EA |
2033 | bp += strlen(bp); |
2034 | if (bitset(QGOODUID, ctladdr->q_flags)) | |
2035 | { | |
2036 | (void) sprintf(bp, " (%d/%d)", | |
2037 | ctladdr->q_uid, ctladdr->q_gid); | |
2038 | bp += strlen(bp); | |
2039 | } | |
2040 | } | |
2041 | ||
3500a891 | 2042 | sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); |
5c18c358 | 2043 | bp += strlen(bp); |
c0ae0b24 | 2044 | |
3500a891 EA |
2045 | if (xstart != (time_t) 0) |
2046 | { | |
2047 | sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); | |
2048 | bp += strlen(bp); | |
2049 | } | |
2050 | ||
4e82a943 | 2051 | if (m != NULL) |
9b95d94a | 2052 | { |
5c18c358 EA |
2053 | (void) strcpy(bp, ", mailer="); |
2054 | (void) strcat(bp, m->m_name); | |
2055 | bp += strlen(bp); | |
9b95d94a | 2056 | } |
4e82a943 EA |
2057 | |
2058 | if (mci != NULL && mci->mci_host != NULL) | |
9b95d94a | 2059 | { |
9b95d94a | 2060 | # ifdef DAEMON |
3341995c | 2061 | extern SOCKADDR CurHostAddr; |
4e82a943 EA |
2062 | # endif |
2063 | ||
5c18c358 EA |
2064 | (void) strcpy(bp, ", relay="); |
2065 | (void) strcat(bp, mci->mci_host); | |
9b95d94a | 2066 | |
4e82a943 | 2067 | # ifdef DAEMON |
d285c43b | 2068 | (void) strcat(bp, " ["); |
5c18c358 | 2069 | (void) strcat(bp, anynet_ntoa(&CurHostAddr)); |
d285c43b | 2070 | (void) strcat(bp, "]"); |
9b95d94a | 2071 | # endif |
9b95d94a | 2072 | } |
8fbbb079 | 2073 | else if (strcmp(stat, "queued") != 0) |
4e82a943 EA |
2074 | { |
2075 | char *p = macvalue('h', e); | |
fc93dffb | 2076 | |
4e82a943 EA |
2077 | if (p != NULL && p[0] != '\0') |
2078 | { | |
5c18c358 EA |
2079 | (void) strcpy(bp, ", relay="); |
2080 | (void) strcat(bp, p); | |
4e82a943 EA |
2081 | } |
2082 | } | |
95203269 | 2083 | bp += strlen(bp); |
eaad1064 | 2084 | |
2bbc90ee EA |
2085 | #define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) |
2086 | #if (STATLEN) < 63 | |
2087 | # undef STATLEN | |
2088 | # define STATLEN 63 | |
2089 | #endif | |
2090 | #if (STATLEN) > 203 | |
2091 | # undef STATLEN | |
2092 | # define STATLEN 203 | |
2093 | #endif | |
2094 | ||
2095 | if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) | |
eaad1064 EA |
2096 | { |
2097 | /* desperation move -- truncate data */ | |
2bbc90ee | 2098 | bp = buf + sizeof buf - ((STATLEN) + 17); |
eaad1064 EA |
2099 | strcpy(bp, "..."); |
2100 | bp += 3; | |
2101 | } | |
2102 | ||
2103 | (void) strcpy(bp, ", stat="); | |
2104 | bp += strlen(bp); | |
2bbc90ee EA |
2105 | |
2106 | (void) strcpy(bp, shortenstring(stat, (STATLEN))); | |
ef71c549 | 2107 | |
eaad1064 EA |
2108 | l = SYSLOG_BUFSIZE - 100 - strlen(buf); |
2109 | p = e->e_to; | |
2604d017 | 2110 | while (strlen(p) >= (SIZE_T) l) |
eaad1064 EA |
2111 | { |
2112 | register char *q = strchr(p + l, ','); | |
2113 | ||
58e480ef | 2114 | if (q == NULL) |
eaad1064 EA |
2115 | break; |
2116 | syslog(LOG_INFO, "%s: to=%.*s [more]%s", | |
2117 | e->e_id, ++q - p, p, buf); | |
2118 | p = q; | |
2119 | } | |
2120 | syslog(LOG_INFO, "%s: to=%s%s", e->e_id, p, buf); | |
2bbc90ee EA |
2121 | |
2122 | # else /* we have a very short log buffer size */ | |
2123 | ||
ec33213e | 2124 | l = SYSLOG_BUFSIZE - 85; |
2bbc90ee EA |
2125 | p = e->e_to; |
2126 | while (strlen(p) >= l) | |
2127 | { | |
2128 | register char *q = strchr(p + l, ','); | |
2129 | ||
2130 | if (q == NULL) | |
2131 | break; | |
2132 | syslog(LOG_INFO, "%s: to=%.*s [more]", | |
2133 | e->e_id, ++q - p, p); | |
2134 | p = q; | |
2135 | } | |
2136 | syslog(LOG_INFO, "%s: to=%s", e->e_id, p); | |
2137 | ||
2138 | if (ctladdr != NULL) | |
2139 | { | |
2140 | bp = buf; | |
2141 | strcpy(buf, "ctladdr="); | |
2142 | bp += strlen(buf); | |
2143 | strcpy(bp, shortenstring(ctladdr->q_paddr, 83)); | |
2144 | bp += strlen(buf); | |
2145 | if (bitset(QGOODUID, ctladdr->q_flags)) | |
2146 | { | |
2147 | (void) sprintf(bp, " (%d/%d)", | |
2148 | ctladdr->q_uid, ctladdr->q_gid); | |
2149 | bp += strlen(bp); | |
2150 | } | |
2151 | syslog(LOG_INFO, "%s: %s", e->e_id, buf); | |
2152 | } | |
3e05a82f EA |
2153 | bp = buf; |
2154 | sprintf(bp, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); | |
2155 | bp += strlen(bp); | |
3500a891 EA |
2156 | if (xstart != (time_t) 0) |
2157 | { | |
2158 | sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); | |
2159 | bp += strlen(bp); | |
2160 | } | |
2bbc90ee EA |
2161 | |
2162 | if (m != NULL) | |
3e05a82f EA |
2163 | { |
2164 | sprintf(bp, ", mailer=%s", m->m_name); | |
2165 | bp += strlen(bp); | |
2166 | } | |
e5b0f01f | 2167 | syslog(LOG_INFO, "%s: %s", e->e_id, buf); |
2bbc90ee | 2168 | |
e5b0f01f | 2169 | buf[0] = '\0'; |
2bbc90ee EA |
2170 | if (mci != NULL && mci->mci_host != NULL) |
2171 | { | |
2172 | # ifdef DAEMON | |
2173 | extern SOCKADDR CurHostAddr; | |
2174 | # endif | |
2175 | ||
2c5b66fc | 2176 | sprintf(buf, "relay=%s", mci->mci_host); |
2bbc90ee EA |
2177 | |
2178 | # ifdef DAEMON | |
e5b0f01f EA |
2179 | (void) strcat(buf, " ["); |
2180 | (void) strcat(buf, anynet_ntoa(&CurHostAddr)); | |
2181 | (void) strcat(buf, "]"); | |
2bbc90ee | 2182 | # endif |
2bbc90ee | 2183 | } |
8fbbb079 | 2184 | else if (strcmp(stat, "queued") != 0) |
2bbc90ee EA |
2185 | { |
2186 | char *p = macvalue('h', e); | |
2187 | ||
2188 | if (p != NULL && p[0] != '\0') | |
2c5b66fc | 2189 | sprintf(buf, "relay=%s", p); |
2bbc90ee | 2190 | } |
e5b0f01f EA |
2191 | if (buf[0] != '\0') |
2192 | syslog(LOG_INFO, "%s: %s", e->e_id, buf); | |
2bbc90ee | 2193 | |
2bbc90ee EA |
2194 | syslog(LOG_INFO, "%s: stat=%s", e->e_id, shortenstring(stat, 63)); |
2195 | # endif /* short log buffer */ | |
f3d8f6d6 | 2196 | # endif /* LOG */ |
fe033a8f EA |
2197 | } |
2198 | \f/* | |
dd1fe05b | 2199 | ** PUTFROMLINE -- output a UNIX-style from line (or whatever) |
b3cbe40f | 2200 | ** |
3c567393 EA |
2201 | ** then passes the rest of the message through. If we have |
2202 | ** managed to extract a date already, use that; otherwise, | |
2203 | ** use the current date/time. | |
b3cbe40f | 2204 | ** |
a73ae8ac EA |
2205 | ** One of the ugliest hacks seen by human eyes is contained herein: |
2206 | ** UUCP wants those stupid "remote from <host>" lines. Why oh why | |
2207 | ** does a well-meaning programmer such as myself have to deal with | |
2208 | ** this kind of antique garbage???? | |
dd1fe05b | 2209 | ** |
b3cbe40f | 2210 | ** Parameters: |
23fafb99 EA |
2211 | ** mci -- the connection information. |
2212 | ** e -- the envelope. | |
b3cbe40f EA |
2213 | ** |
2214 | ** Returns: | |
dd1fe05b | 2215 | ** none |
b3cbe40f EA |
2216 | ** |
2217 | ** Side Effects: | |
dd1fe05b | 2218 | ** outputs some text to fp. |
b3cbe40f EA |
2219 | */ |
2220 | ||
179d940c | 2221 | void |
23fafb99 EA |
2222 | putfromline(mci, e) |
2223 | register MCI *mci; | |
f2e44ded | 2224 | ENVELOPE *e; |
b3cbe40f | 2225 | { |
2bee003d | 2226 | char *template = "\201l\n"; |
dd1fe05b | 2227 | char buf[MAXLINE]; |
3c567393 | 2228 | extern char SentDate[]; |
b3cbe40f | 2229 | |
23fafb99 | 2230 | if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) |
dd1fe05b | 2231 | return; |
74c5fe7c | 2232 | |
23fafb99 | 2233 | if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) |
79bd7c07 | 2234 | { |
9aecbdbe EA |
2235 | char *bang; |
2236 | char xbuf[MAXLINE]; | |
79bd7c07 | 2237 | |
832e8a27 | 2238 | expand("\201g", buf, sizeof buf, e); |
f3d8f6d6 | 2239 | bang = strchr(buf, '!'); |
dd1fe05b | 2240 | if (bang == NULL) |
1673be04 EA |
2241 | { |
2242 | errno = 0; | |
2243 | syserr("554 No ! in UUCP From address! (%s given)", buf); | |
2244 | } | |
dd1fe05b | 2245 | else |
7338e3d4 | 2246 | { |
9aecbdbe | 2247 | *bang++ = '\0'; |
2bee003d | 2248 | (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); |
9aecbdbe | 2249 | template = xbuf; |
7338e3d4 | 2250 | } |
79bd7c07 | 2251 | } |
832e8a27 | 2252 | expand(template, buf, sizeof buf, e); |
7905af2d | 2253 | putxline(buf, mci, PXLF_NOTHINGSPECIAL); |
79bd7c07 EA |
2254 | } |
2255 | \f/* | |
6acfa498 | 2256 | ** PUTBODY -- put the body of a message. |
cbdb7357 EA |
2257 | ** |
2258 | ** Parameters: | |
23fafb99 | 2259 | ** mci -- the connection information. |
6acfa498 | 2260 | ** e -- the envelope to put out. |
2f6a8a78 EA |
2261 | ** separator -- if non-NULL, a message separator that must |
2262 | ** not be permitted in the resulting message. | |
cbdb7357 EA |
2263 | ** |
2264 | ** Returns: | |
2265 | ** none. | |
2266 | ** | |
2267 | ** Side Effects: | |
6acfa498 | 2268 | ** The message is written onto fp. |
cbdb7357 EA |
2269 | */ |
2270 | ||
0d721ffb EA |
2271 | /* values for output state variable */ |
2272 | #define OS_HEAD 0 /* at beginning of line */ | |
2273 | #define OS_CR 1 /* read a carriage return */ | |
2274 | #define OS_INLINE 2 /* putting rest of line */ | |
2275 | ||
179d940c | 2276 | void |
51d448e5 | 2277 | putbody(mci, e, separator) |
23fafb99 | 2278 | register MCI *mci; |
6acfa498 | 2279 | register ENVELOPE *e; |
2f6a8a78 | 2280 | char *separator; |
cbdb7357 | 2281 | { |
6acfa498 | 2282 | char buf[MAXLINE]; |
cbdb7357 | 2283 | |
3c7fe765 | 2284 | /* |
6acfa498 | 2285 | ** Output the body of the message |
3c7fe765 EA |
2286 | */ |
2287 | ||
18a81ac0 | 2288 | if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) |
cd37f61d | 2289 | { |
18a81ac0 EA |
2290 | char *df = queuename(e, 'd'); |
2291 | ||
2292 | e->e_dfp = fopen(df, "r"); | |
cd37f61d EA |
2293 | if (e->e_dfp == NULL) |
2294 | syserr("putbody: Cannot open %s for %s from %s", | |
18a81ac0 | 2295 | df, e->e_to, e->e_from.q_paddr); |
cd37f61d | 2296 | } |
6acfa498 | 2297 | if (e->e_dfp == NULL) |
7338e3d4 | 2298 | { |
cd37f61d | 2299 | if (bitset(MCIF_INHEADER, mci->mci_flags)) |
78bbbc48 | 2300 | { |
cd37f61d EA |
2301 | putline("", mci); |
2302 | mci->mci_flags &= ~MCIF_INHEADER; | |
c23930c0 | 2303 | } |
cd37f61d EA |
2304 | putline("<<< No Message Collected >>>", mci); |
2305 | goto endofmessage; | |
84daea29 | 2306 | } |
cd37f61d | 2307 | if (e->e_dfino == (ino_t) 0) |
f009d24b EA |
2308 | { |
2309 | struct stat stbuf; | |
2310 | ||
2311 | if (fstat(fileno(e->e_dfp), &stbuf) < 0) | |
2312 | e->e_dfino = -1; | |
2313 | else | |
bb4fde22 EA |
2314 | { |
2315 | e->e_dfdev = stbuf.st_dev; | |
f009d24b | 2316 | e->e_dfino = stbuf.st_ino; |
bb4fde22 | 2317 | } |
f009d24b | 2318 | } |
0d721ffb | 2319 | rewind(e->e_dfp); |
c23930c0 | 2320 | |
8bc4f1c6 | 2321 | #if MIME8TO7 |
0d721ffb EA |
2322 | if (bitset(MCIF_CVT8TO7, mci->mci_flags)) |
2323 | { | |
022362dd EA |
2324 | char *boundaries[MAXMIMENESTING + 1]; |
2325 | ||
bb4fde22 EA |
2326 | /* |
2327 | ** Do 8 to 7 bit MIME conversion. | |
2328 | */ | |
2329 | ||
2330 | /* make sure it looks like a MIME message */ | |
0d721ffb EA |
2331 | if (hvalue("MIME-Version", e->e_header) == NULL) |
2332 | putline("MIME-Version: 1.0", mci); | |
bb4fde22 | 2333 | |
bb4fde22 | 2334 | if (hvalue("Content-Type", e->e_header) == NULL) |
a50ac3e2 | 2335 | { |
a50ac3e2 | 2336 | sprintf(buf, "Content-Type: text/plain; charset=%s", |
3caf3b1f | 2337 | defcharset(e)); |
a50ac3e2 EA |
2338 | putline(buf, mci); |
2339 | } | |
bb4fde22 EA |
2340 | |
2341 | /* now do the hard work */ | |
022362dd EA |
2342 | boundaries[0] = NULL; |
2343 | mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER); | |
0d721ffb EA |
2344 | } |
2345 | else | |
8bc4f1c6 | 2346 | #endif |
0d721ffb EA |
2347 | { |
2348 | int ostate; | |
2349 | register char *bp; | |
2350 | register char *pbp; | |
2351 | register int c; | |
2352 | int padc; | |
2353 | char *buflim; | |
ea07b2d2 | 2354 | int pos = 0; |
0d721ffb EA |
2355 | char peekbuf[10]; |
2356 | ||
2357 | /* we can pass it through unmodified */ | |
2358 | if (bitset(MCIF_INHEADER, mci->mci_flags)) | |
c23930c0 | 2359 | { |
0d721ffb EA |
2360 | putline("", mci); |
2361 | mci->mci_flags &= ~MCIF_INHEADER; | |
c23930c0 | 2362 | } |
0d721ffb EA |
2363 | |
2364 | /* determine end of buffer; allow for short mailer lines */ | |
2365 | buflim = &buf[sizeof buf - 1]; | |
098e8e2c EA |
2366 | if (mci->mci_mailer->m_linelimit > 0 && |
2367 | mci->mci_mailer->m_linelimit < sizeof buf - 1) | |
0d721ffb EA |
2368 | buflim = &buf[mci->mci_mailer->m_linelimit - 1]; |
2369 | ||
2370 | /* copy temp file to output with mapping */ | |
2371 | ostate = OS_HEAD; | |
2372 | bp = buf; | |
2373 | pbp = peekbuf; | |
2374 | while (!ferror(mci->mci_out)) | |
84daea29 | 2375 | { |
0d721ffb EA |
2376 | register char *xp; |
2377 | ||
2378 | if (pbp > peekbuf) | |
2379 | c = *--pbp; | |
52d719ca | 2380 | else if ((c = getc(e->e_dfp)) == EOF) |
0d721ffb EA |
2381 | break; |
2382 | if (bitset(MCIF_7BIT, mci->mci_flags)) | |
2383 | c &= 0x7f; | |
2384 | switch (ostate) | |
2f6a8a78 | 2385 | { |
0d721ffb EA |
2386 | case OS_HEAD: |
2387 | if (c != '\r' && c != '\n' && bp < buflim) | |
2388 | { | |
2389 | *bp++ = c; | |
2390 | break; | |
2391 | } | |
2392 | ||
2393 | /* check beginning of line for special cases */ | |
2394 | *bp = '\0'; | |
2395 | pos = 0; | |
2396 | padc = EOF; | |
c23930c0 EA |
2397 | if (buf[0] == 'F' && |
2398 | bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && | |
2399 | strncmp(buf, "From ", 5) == 0) | |
0d721ffb EA |
2400 | { |
2401 | padc = '>'; | |
2402 | } | |
c23930c0 EA |
2403 | if (buf[0] == '-' && buf[1] == '-' && |
2404 | separator != NULL) | |
2405 | { | |
2406 | /* possible separator */ | |
2407 | int sl = strlen(separator); | |
2f6a8a78 | 2408 | |
c23930c0 | 2409 | if (strncmp(&buf[2], separator, sl) == 0) |
0d721ffb | 2410 | padc = ' '; |
c23930c0 | 2411 | } |
0d721ffb EA |
2412 | if (buf[0] == '.' && |
2413 | bitnset(M_XDOT, mci->mci_mailer->m_flags)) | |
2414 | { | |
2415 | padc = '.'; | |
2416 | } | |
2417 | ||
2418 | /* now copy out saved line */ | |
2419 | if (TrafficLogFile != NULL) | |
2420 | { | |
2421 | fprintf(TrafficLogFile, "%05d >>> ", getpid()); | |
2422 | if (padc != EOF) | |
52d719ca | 2423 | putc(padc, TrafficLogFile); |
0d721ffb | 2424 | for (xp = buf; xp < bp; xp++) |
52d719ca | 2425 | putc(*xp, TrafficLogFile); |
0d721ffb EA |
2426 | if (c == '\n') |
2427 | fputs(mci->mci_mailer->m_eol, | |
2428 | TrafficLogFile); | |
2429 | } | |
2430 | if (padc != EOF) | |
2431 | { | |
52d719ca | 2432 | putc(padc, mci->mci_out); |
0d721ffb EA |
2433 | pos++; |
2434 | } | |
2435 | for (xp = buf; xp < bp; xp++) | |
52d719ca | 2436 | putc(*xp, mci->mci_out); |
0d721ffb EA |
2437 | if (c == '\n') |
2438 | { | |
2439 | fputs(mci->mci_mailer->m_eol, | |
2440 | mci->mci_out); | |
2441 | pos = 0; | |
2442 | } | |
2443 | else | |
2444 | { | |
2445 | pos += bp - buf; | |
a4041586 EA |
2446 | if (c != '\r') |
2447 | *pbp++ = c; | |
0d721ffb EA |
2448 | } |
2449 | bp = buf; | |
2450 | ||
2451 | /* determine next state */ | |
2452 | if (c == '\n') | |
2453 | ostate = OS_HEAD; | |
2454 | else if (c == '\r') | |
2455 | ostate = OS_CR; | |
2456 | else | |
2457 | ostate = OS_INLINE; | |
2458 | continue; | |
2459 | ||
2460 | case OS_CR: | |
2461 | if (c == '\n') | |
2462 | { | |
2463 | /* got CRLF */ | |
2464 | fputs(mci->mci_mailer->m_eol, mci->mci_out); | |
2465 | if (TrafficLogFile != NULL) | |
2466 | { | |
2467 | fputs(mci->mci_mailer->m_eol, | |
2468 | TrafficLogFile); | |
2469 | } | |
2470 | ostate = OS_HEAD; | |
2471 | continue; | |
2472 | } | |
2473 | ||
2474 | /* had a naked carriage return */ | |
2475 | *pbp++ = c; | |
2476 | c = '\r'; | |
68e6bb99 | 2477 | goto putch; |
0d721ffb EA |
2478 | |
2479 | case OS_INLINE: | |
2480 | if (c == '\r') | |
2481 | { | |
2482 | ostate = OS_CR; | |
2483 | continue; | |
2484 | } | |
68e6bb99 | 2485 | putch: |
098e8e2c EA |
2486 | if (mci->mci_mailer->m_linelimit > 0 && |
2487 | pos > mci->mci_mailer->m_linelimit && | |
0d721ffb EA |
2488 | c != '\n') |
2489 | { | |
2490 | putc('!', mci->mci_out); | |
2491 | fputs(mci->mci_mailer->m_eol, mci->mci_out); | |
2492 | if (TrafficLogFile != NULL) | |
2493 | { | |
2494 | fprintf(TrafficLogFile, "!%s", | |
2495 | mci->mci_mailer->m_eol); | |
2496 | } | |
2497 | ostate = OS_HEAD; | |
2498 | *pbp++ = c; | |
2499 | continue; | |
2500 | } | |
2501 | if (TrafficLogFile != NULL) | |
52d719ca | 2502 | putc(c, TrafficLogFile); |
0d721ffb EA |
2503 | putc(c, mci->mci_out); |
2504 | pos++; | |
a4041586 | 2505 | ostate = c == '\n' ? OS_HEAD : OS_INLINE; |
0d721ffb | 2506 | break; |
2f6a8a78 | 2507 | } |
84daea29 | 2508 | } |
0d721ffb | 2509 | } |
84daea29 | 2510 | |
0d721ffb EA |
2511 | if (ferror(e->e_dfp)) |
2512 | { | |
18a81ac0 | 2513 | syserr("putbody: df%s: read error", e->e_id); |
0d721ffb | 2514 | ExitStat = EX_IOERR; |
baa2b877 | 2515 | } |
75f95954 | 2516 | |
0d721ffb | 2517 | endofmessage: |
1537ac22 | 2518 | /* some mailers want extra blank line at end of message */ |
23fafb99 EA |
2519 | if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && |
2520 | buf[0] != '\0' && buf[0] != '\n') | |
2521 | putline("", mci); | |
1537ac22 | 2522 | |
23fafb99 EA |
2523 | (void) fflush(mci->mci_out); |
2524 | if (ferror(mci->mci_out) && errno != EPIPE) | |
84daea29 | 2525 | { |
6acfa498 EA |
2526 | syserr("putbody: write error"); |
2527 | ExitStat = EX_IOERR; | |
84daea29 | 2528 | } |
6acfa498 | 2529 | errno = 0; |
bc854e30 | 2530 | } |
6acfa498 EA |
2531 | \f/* |
2532 | ** MAILFILE -- Send a message to a file. | |
2533 | ** | |
2534 | ** If the file has the setuid/setgid bits set, but NO execute | |
2535 | ** bits, sendmail will try to become the owner of that file | |
2536 | ** rather than the real user. Obviously, this only works if | |
2537 | ** sendmail runs as root. | |
2538 | ** | |
2539 | ** This could be done as a subordinate mailer, except that it | |
2540 | ** is used implicitly to save messages in ~/dead.letter. We | |
2541 | ** view this as being sufficiently important as to include it | |
2542 | ** here. For example, if the system is dying, we shouldn't have | |
2543 | ** to create another process plus some pipes to save the message. | |
2544 | ** | |
2545 | ** Parameters: | |
2546 | ** filename -- the name of the file to send to. | |
2547 | ** ctladdr -- the controlling address header -- includes | |
2548 | ** the userid/groupid to be when sending. | |
b6f25ddb EA |
2549 | ** sfflags -- flags for opening. |
2550 | ** e -- the current envelope. | |
6acfa498 EA |
2551 | ** |
2552 | ** Returns: | |
2553 | ** The exit code associated with the operation. | |
2554 | ** | |
2555 | ** Side Effects: | |
2556 | ** none. | |
2557 | */ | |
bc854e30 | 2558 | |
179d940c | 2559 | int |
b6f25ddb | 2560 | mailfile(filename, ctladdr, sfflags, e) |
6acfa498 EA |
2561 | char *filename; |
2562 | ADDRESS *ctladdr; | |
b6f25ddb | 2563 | int sfflags; |
bc854e30 | 2564 | register ENVELOPE *e; |
bc854e30 | 2565 | { |
6acfa498 | 2566 | register FILE *f; |
ea07b2d2 | 2567 | register int pid = -1; |
6acfa498 | 2568 | int mode; |
84daea29 | 2569 | |
831d7357 EA |
2570 | if (tTd(11, 1)) |
2571 | { | |
2572 | printf("mailfile %s\n ctladdr=", filename); | |
2573 | printaddr(ctladdr, FALSE); | |
2574 | } | |
2575 | ||
8e5c6745 EA |
2576 | if (e->e_xfp != NULL) |
2577 | fflush(e->e_xfp); | |
2578 | ||
6acfa498 EA |
2579 | /* |
2580 | ** Fork so we can change permissions here. | |
2581 | ** Note that we MUST use fork, not vfork, because of | |
2582 | ** the complications of calling subroutines, etc. | |
2583 | */ | |
2584 | ||
2585 | DOFORK(fork); | |
2586 | ||
2587 | if (pid < 0) | |
2588 | return (EX_OSERR); | |
2589 | else if (pid == 0) | |
75f95954 | 2590 | { |
6acfa498 EA |
2591 | /* child -- actually write to file */ |
2592 | struct stat stb; | |
2c2b6557 | 2593 | struct stat fsb; |
23fafb99 | 2594 | MCI mcibuf; |
99fd9645 | 2595 | int oflags = O_WRONLY|O_APPEND; |
8726396d | 2596 | int oflags = O_WRONLY|O_APPEND; |
75f95954 | 2597 | |
2c2b6557 | 2598 | if (e->e_lockfp != NULL) |
da8ca152 | 2599 | (void) close(fileno(e->e_lockfp)); |
2c2b6557 | 2600 | |
39270cfd EA |
2601 | (void) setsignal(SIGINT, SIG_DFL); |
2602 | (void) setsignal(SIGHUP, SIG_DFL); | |
2603 | (void) setsignal(SIGTERM, SIG_DFL); | |
6acfa498 | 2604 | (void) umask(OldUmask); |
b6f25ddb EA |
2605 | e->e_to = filename; |
2606 | ExitStat = EX_OK; | |
75f95954 | 2607 | |
99fd9645 EA |
2608 | #ifdef HASLSTAT |
2609 | if ((SafeFileEnv != NULL ? lstat(filename, &stb) | |
2610 | : stat(filename, &stb)) < 0) | |
2611 | #else | |
6acfa498 | 2612 | if (stat(filename, &stb) < 0) |
8726396d | 2613 | { |
99fd9645 EA |
2614 | #endif |
2615 | { | |
6f7f4e2c | 2616 | stb.st_mode = FileMode; |
99fd9645 EA |
2617 | oflags |= O_CREAT|O_EXCL; |
2618 | } | |
2619 | else if (bitset(0111, stb.st_mode) || stb.st_nlink != 1 || | |
2620 | (SafeFileEnv != NULL && !S_ISREG(stb.st_mode))) | |
2c2b6557 | 2621 | exit(EX_CANTCREAT); |
6acfa498 | 2622 | mode = stb.st_mode; |
07800f98 | 2623 | |
6acfa498 EA |
2624 | /* limit the errors to those actually caused in the child */ |
2625 | errno = 0; | |
2626 | ExitStat = EX_OK; | |
07800f98 | 2627 | |
b6f25ddb | 2628 | if (ctladdr != NULL || bitset(SFF_RUNASREALUID, sfflags)) |
07800f98 | 2629 | { |
6acfa498 EA |
2630 | /* ignore setuid and setgid bits */ |
2631 | mode &= ~(S_ISGID|S_ISUID); | |
07800f98 | 2632 | } |
07800f98 | 2633 | |
6acfa498 | 2634 | /* we have to open the dfile BEFORE setuid */ |
18a81ac0 | 2635 | if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) |
813d8709 | 2636 | { |
18a81ac0 EA |
2637 | char *df = queuename(e, 'd'); |
2638 | ||
2639 | e->e_dfp = fopen(df, "r"); | |
6acfa498 | 2640 | if (e->e_dfp == NULL) |
78bbbc48 | 2641 | { |
6acfa498 | 2642 | syserr("mailfile: Cannot open %s for %s from %s", |
18a81ac0 | 2643 | df, e->e_to, e->e_from.q_paddr); |
78bbbc48 | 2644 | } |
6acfa498 | 2645 | } |
78bbbc48 | 2646 | |
e0c8c651 | 2647 | if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') |
99fd9645 EA |
2648 | { |
2649 | int i; | |
2650 | ||
2651 | if (chroot(SafeFileEnv) < 0) | |
2652 | { | |
2653 | syserr("mailfile: Cannot chroot(%s)", | |
2654 | SafeFileEnv); | |
2655 | exit(EX_CANTCREAT); | |
2656 | } | |
2657 | i = strlen(SafeFileEnv); | |
2658 | if (strncmp(SafeFileEnv, filename, i) == 0) | |
2659 | filename += i; | |
2660 | } | |
2661 | if (chdir("/") < 0) | |
2662 | syserr("mailfile: cannot chdir(/)"); | |
2663 | ||
b6f25ddb EA |
2664 | /* select a new user to run as */ |
2665 | if (!bitset(SFF_RUNASREALUID, sfflags)) | |
6acfa498 | 2666 | { |
b6f25ddb EA |
2667 | if (bitset(S_ISUID, mode)) |
2668 | { | |
2669 | RealUserName = NULL; | |
2670 | RealUid = stb.st_uid; | |
2671 | } | |
2672 | else if (ctladdr != NULL && ctladdr->q_uid != 0) | |
2673 | { | |
2674 | if (ctladdr->q_ruser != NULL) | |
2675 | RealUserName = ctladdr->q_ruser; | |
2676 | else | |
2677 | RealUserName = ctladdr->q_user; | |
2678 | RealUid = ctladdr->q_uid; | |
2679 | } | |
2680 | else if (FileMailer != NULL && FileMailer->m_uid != 0) | |
2681 | { | |
2682 | RealUserName = DefUser; | |
2683 | RealUid = FileMailer->m_uid; | |
2684 | } | |
2685 | else | |
2686 | { | |
2687 | RealUserName = DefUser; | |
2688 | RealUid = DefUid; | |
2689 | } | |
2690 | ||
2691 | /* select a new group to run as */ | |
2692 | if (bitset(S_ISGID, mode)) | |
2693 | RealGid = stb.st_gid; | |
2694 | else if (ctladdr != NULL && ctladdr->q_uid != 0) | |
2695 | RealGid = ctladdr->q_gid; | |
0c35b842 | 2696 | else if (FileMailer != NULL && FileMailer->m_gid != 0) |
b6f25ddb | 2697 | RealGid = FileMailer->m_gid; |
0c35b842 | 2698 | else |
b6f25ddb | 2699 | RealGid = DefGid; |
813d8709 | 2700 | } |
b6f25ddb EA |
2701 | |
2702 | /* last ditch */ | |
2703 | if (!bitset(SFF_ROOTOK, sfflags)) | |
4ae3ff58 | 2704 | { |
b6f25ddb EA |
2705 | if (RealUid == 0) |
2706 | RealUid = DefUid; | |
2707 | if (RealGid == 0) | |
2708 | RealGid = DefGid; | |
4ae3ff58 | 2709 | } |
b6f25ddb EA |
2710 | |
2711 | /* now set the group and user ids */ | |
2712 | if (RealUserName != NULL) | |
2713 | (void) initgroups(RealUserName, RealGid); | |
2714 | else | |
2715 | (void) setgid(RealGid); | |
2716 | (void) setuid(RealUid); | |
2717 | ||
2718 | sfflags |= SFF_NOPATHCHECK; | |
2719 | sfflags &= ~SFF_OPENASROOT; | |
2720 | f = safefopen(filename, oflags, FileMode, sfflags); | |
6acfa498 | 2721 | if (f == NULL) |
cbdb7357 | 2722 | { |
6814f197 | 2723 | message("554 cannot open: %s", errstring(errno)); |
6acfa498 | 2724 | exit(EX_CANTCREAT); |
cbdb7357 | 2725 | } |
8dcff118 | 2726 | |
23fafb99 EA |
2727 | bzero(&mcibuf, sizeof mcibuf); |
2728 | mcibuf.mci_mailer = FileMailer; | |
2729 | mcibuf.mci_out = f; | |
2730 | if (bitnset(M_7BITS, FileMailer->m_flags)) | |
2731 | mcibuf.mci_flags |= MCIF_7BIT; | |
2732 | ||
2733 | putfromline(&mcibuf, e); | |
51d448e5 EA |
2734 | (*e->e_puthdr)(&mcibuf, e->e_header, e); |
2735 | (*e->e_putbody)(&mcibuf, e, NULL); | |
23fafb99 | 2736 | putline("\n", &mcibuf); |
6acfa498 EA |
2737 | if (ferror(f)) |
2738 | { | |
6814f197 | 2739 | message("451 I/O error: %s", errstring(errno)); |
6acfa498 | 2740 | setstat(EX_IOERR); |
8dcff118 | 2741 | } |
6acfa498 EA |
2742 | (void) xfclose(f, "mailfile", filename); |
2743 | (void) fflush(stdout); | |
3c7fe765 | 2744 | |
6acfa498 EA |
2745 | /* reset ISUID & ISGID bits for paranoid systems */ |
2746 | (void) chmod(filename, (int) stb.st_mode); | |
2747 | exit(ExitStat); | |
2748 | /*NOTREACHED*/ | |
bc854e30 | 2749 | } |
6acfa498 | 2750 | else |
3c7fe765 | 2751 | { |
6acfa498 EA |
2752 | /* parent -- wait for exit status */ |
2753 | int st; | |
bc854e30 | 2754 | |
6acfa498 | 2755 | st = waitfor(pid); |
e3791bb6 EA |
2756 | if (WIFEXITED(st)) |
2757 | return (WEXITSTATUS(st)); | |
6acfa498 | 2758 | else |
6814f197 EA |
2759 | { |
2760 | syserr("child died on signal %d", st); | |
e3791bb6 | 2761 | return (EX_UNAVAILABLE); |
6814f197 | 2762 | } |
6acfa498 | 2763 | /*NOTREACHED*/ |
3c7fe765 EA |
2764 | } |
2765 | } | |
7e70d3c8 EA |
2766 | \f/* |
2767 | ** HOSTSIGNATURE -- return the "signature" for a host. | |
2768 | ** | |
2769 | ** The signature describes how we are going to send this -- it | |
2770 | ** can be just the hostname (for non-Internet hosts) or can be | |
2771 | ** an ordered list of MX hosts. | |
2772 | ** | |
2773 | ** Parameters: | |
2774 | ** m -- the mailer describing this host. | |
2775 | ** host -- the host name. | |
2776 | ** e -- the current envelope. | |
2777 | ** | |
2778 | ** Returns: | |
2779 | ** The signature for this host. | |
2780 | ** | |
2781 | ** Side Effects: | |
2782 | ** Can tweak the symbol table. | |
2783 | */ | |
2784 | ||
2785 | char * | |
2786 | hostsignature(m, host, e) | |
2787 | register MAILER *m; | |
2788 | char *host; | |
2789 | ENVELOPE *e; | |
2790 | { | |
2791 | register char *p; | |
2792 | register STAB *s; | |
2793 | int i; | |
2794 | int len; | |
efe7f723 | 2795 | #if NAMED_BIND |
7e70d3c8 EA |
2796 | int nmx; |
2797 | auto int rcode; | |
db113c28 EA |
2798 | char *hp; |
2799 | char *endp; | |
ea07b2d2 | 2800 | int oldoptions = _res.options; |
7e70d3c8 | 2801 | char *mxhosts[MAXMXHOSTS + 1]; |
7e70d3c8 EA |
2802 | #endif |
2803 | ||
2804 | /* | |
2805 | ** Check to see if this uses IPC -- if not, it can't have MX records. | |
2806 | */ | |
2807 | ||
2808 | p = m->m_mailer; | |
2809 | if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) | |
2810 | { | |
2811 | /* just an ordinary mailer */ | |
2812 | return host; | |
2813 | } | |
2814 | ||
7e70d3c8 EA |
2815 | /* |
2816 | ** Look it up in the symbol table. | |
2817 | */ | |
2818 | ||
2819 | s = stab(host, ST_HOSTSIG, ST_ENTER); | |
2820 | if (s->s_hostsig != NULL) | |
2821 | return s->s_hostsig; | |
2822 | ||
2823 | /* | |
2824 | ** Not already there -- create a signature. | |
2825 | */ | |
2826 | ||
efe7f723 | 2827 | #if NAMED_BIND |
c8f4bc0b | 2828 | if (ConfigLevel < 2) |
c8f4bc0b | 2829 | _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ |
c8f4bc0b | 2830 | |
db113c28 | 2831 | for (hp = host; hp != NULL; hp = endp) |
7e70d3c8 | 2832 | { |
db113c28 EA |
2833 | endp = strchr(hp, ':'); |
2834 | if (endp != NULL) | |
2835 | *endp = '\0'; | |
7e70d3c8 | 2836 | |
c3577cd6 | 2837 | nmx = getmxrr(hp, mxhosts, TRUE, &rcode); |
7e70d3c8 | 2838 | |
db113c28 EA |
2839 | if (nmx <= 0) |
2840 | { | |
2841 | register MCI *mci; | |
7e70d3c8 | 2842 | |
db113c28 EA |
2843 | /* update the connection info for this host */ |
2844 | mci = mci_get(hp, m); | |
2845 | mci->mci_exitstat = rcode; | |
2846 | mci->mci_errno = errno; | |
8e5c6745 | 2847 | mci->mci_herrno = h_errno; |
db113c28 EA |
2848 | |
2849 | /* and return the original host name as the signature */ | |
2850 | nmx = 1; | |
2851 | mxhosts[0] = hp; | |
2852 | } | |
2853 | ||
2854 | len = 0; | |
2855 | for (i = 0; i < nmx; i++) | |
2856 | { | |
2857 | len += strlen(mxhosts[i]) + 1; | |
2858 | } | |
2859 | if (s->s_hostsig != NULL) | |
2860 | len += strlen(s->s_hostsig) + 1; | |
2861 | p = xalloc(len); | |
2862 | if (s->s_hostsig != NULL) | |
2863 | { | |
2864 | (void) strcpy(p, s->s_hostsig); | |
2865 | free(s->s_hostsig); | |
2866 | s->s_hostsig = p; | |
2867 | p += strlen(p); | |
7e70d3c8 | 2868 | *p++ = ':'; |
db113c28 EA |
2869 | } |
2870 | else | |
2871 | s->s_hostsig = p; | |
2872 | for (i = 0; i < nmx; i++) | |
2873 | { | |
2874 | if (i != 0) | |
2875 | *p++ = ':'; | |
2876 | strcpy(p, mxhosts[i]); | |
2877 | p += strlen(p); | |
2878 | } | |
2879 | if (endp != NULL) | |
2880 | *endp++ = ':'; | |
7e70d3c8 EA |
2881 | } |
2882 | makelower(s->s_hostsig); | |
c8f4bc0b EA |
2883 | if (ConfigLevel < 2) |
2884 | _res.options = oldoptions; | |
7e70d3c8 EA |
2885 | #else |
2886 | /* not using BIND -- the signature is just the host name */ | |
2887 | s->s_hostsig = host; | |
2888 | #endif | |
2889 | if (tTd(17, 1)) | |
2890 | printf("hostsignature(%s) = %s\n", host, s->s_hostsig); | |
2891 | return s->s_hostsig; | |
2892 | } |