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