Commit | Line | Data |
---|---|---|
d185cb11 | 1 | /* |
dc45ba8c | 2 | * Copyright (c) 1983 Eric P. Allman |
bee79b64 KB |
3 | * Copyright (c) 1988 Regents of the University of California. |
4 | * All rights reserved. | |
5 | * | |
417f7a11 | 6 | * %sccs.include.redist.c% |
bee79b64 | 7 | */ |
d185cb11 DF |
8 | |
9 | #ifndef lint | |
5a972da1 | 10 | static char sccsid[] = "@(#)deliver.c 6.79 (Berkeley) %G%"; |
bee79b64 | 11 | #endif /* not lint */ |
d185cb11 | 12 | |
97543758 | 13 | #include "sendmail.h" |
49c069a9 | 14 | #include <signal.h> |
7b6e7aee KB |
15 | #include <netdb.h> |
16 | #include <errno.h> | |
35af2f06 | 17 | #ifdef NAMED_BIND |
f28c9fe2 KB |
18 | #include <arpa/nameser.h> |
19 | #include <resolv.h> | |
35af2f06 | 20 | #endif |
b3cbe40f EA |
21 | |
22 | /* | |
6acfa498 | 23 | ** SENDALL -- actually send all the messages. |
b3cbe40f | 24 | ** |
b3cbe40f | 25 | ** Parameters: |
6acfa498 EA |
26 | ** e -- the envelope to send. |
27 | ** mode -- the delivery mode to use. If SM_DEFAULT, use | |
28 | ** the current e->e_sendmode. | |
b3cbe40f EA |
29 | ** |
30 | ** Returns: | |
6acfa498 | 31 | ** none. |
b3cbe40f EA |
32 | ** |
33 | ** Side Effects: | |
6acfa498 EA |
34 | ** Scans the send lists and sends everything it finds. |
35 | ** Delivers any appropriate error messages. | |
36 | ** If we are running in a non-interactive mode, takes the | |
37 | ** appropriate action. | |
b3cbe40f EA |
38 | */ |
39 | ||
6acfa498 EA |
40 | sendall(e, mode) |
41 | ENVELOPE *e; | |
42 | char mode; | |
b3cbe40f | 43 | { |
6acfa498 EA |
44 | register ADDRESS *q; |
45 | char *owner; | |
46 | int otherowners; | |
47 | register ENVELOPE *ee; | |
48 | ENVELOPE *splitenv = NULL; | |
959cf51d | 49 | bool announcequeueup; |
1d303d98 EA |
50 | int pid; |
51 | #ifdef LOCKF | |
52 | struct flock lfd; | |
53 | #endif | |
b3cbe40f | 54 | |
6acfa498 EA |
55 | /* determine actual delivery mode */ |
56 | if (mode == SM_DEFAULT) | |
57 | { | |
6acfa498 EA |
58 | mode = e->e_sendmode; |
59 | if (mode != SM_VERIFY && | |
60 | shouldqueue(e->e_msgpriority, e->e_ctime)) | |
61 | mode = SM_QUEUE; | |
959cf51d | 62 | announcequeueup = mode == SM_QUEUE; |
f28c9fe2 | 63 | } |
959cf51d EA |
64 | else |
65 | announcequeueup = FALSE; | |
3135d20c | 66 | |
6acfa498 | 67 | if (tTd(13, 1)) |
3135d20c | 68 | { |
6acfa498 EA |
69 | printf("\nSENDALL: mode %c, e_from ", mode); |
70 | printaddr(&e->e_from, FALSE); | |
71 | printf("sendqueue:\n"); | |
72 | printaddr(e->e_sendqueue, TRUE); | |
3135d20c EA |
73 | } |
74 | ||
a530c75f | 75 | /* |
6acfa498 EA |
76 | ** Do any preprocessing necessary for the mode we are running. |
77 | ** Check to make sure the hop count is reasonable. | |
78 | ** Delete sends to the sender in mailing lists. | |
a530c75f EA |
79 | */ |
80 | ||
6acfa498 | 81 | CurEnv = e; |
a530c75f | 82 | |
6acfa498 | 83 | if (e->e_hopcount > MaxHopCount) |
779597d8 | 84 | { |
6acfa498 EA |
85 | errno = 0; |
86 | syserr("554 too many hops %d (%d max): from %s, to %s", | |
87 | e->e_hopcount, MaxHopCount, e->e_from.q_paddr, | |
88 | e->e_sendqueue->q_paddr); | |
89 | return; | |
779597d8 | 90 | } |
b3cbe40f | 91 | |
2eb74b19 EA |
92 | /* |
93 | ** Do sender deletion. | |
94 | ** | |
95 | ** If the sender has the QQUEUEUP flag set, skip this. | |
96 | ** This can happen if the name server is hosed when you | |
97 | ** are trying to send mail. The result is that the sender | |
98 | ** is instantiated in the queue as a recipient. | |
99 | */ | |
100 | ||
101 | if (!MeToo && !bitset(QQUEUEUP, e->e_from.q_flags)) | |
b3cbe40f | 102 | { |
6acfa498 | 103 | if (tTd(13, 5)) |
779597d8 | 104 | { |
6acfa498 EA |
105 | printf("sendall: QDONTSEND "); |
106 | printaddr(&e->e_from, FALSE); | |
779597d8 | 107 | } |
6acfa498 EA |
108 | e->e_from.q_flags |= QDONTSEND; |
109 | (void) recipient(&e->e_from, &e->e_sendqueue, e); | |
b3cbe40f | 110 | } |
e6b0a75b | 111 | |
1d303d98 EA |
112 | # ifdef QUEUE |
113 | if ((mode == SM_QUEUE || mode == SM_FORK || | |
114 | (mode != SM_VERIFY && SuperSafe)) && | |
115 | !bitset(EF_INQUEUE, e->e_flags)) | |
116 | { | |
117 | /* be sure everything is instantiated in the queue */ | |
118 | queueup(e, TRUE, mode == SM_QUEUE); | |
119 | } | |
120 | #endif /* QUEUE */ | |
121 | ||
122 | switch (mode) | |
123 | { | |
124 | case SM_VERIFY: | |
125 | Verbose = TRUE; | |
126 | break; | |
127 | ||
128 | case SM_QUEUE: | |
129 | queueonly: | |
130 | e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; | |
131 | return; | |
132 | ||
133 | case SM_FORK: | |
134 | if (e->e_xfp != NULL) | |
135 | (void) fflush(e->e_xfp); | |
136 | ||
137 | # ifdef LOCKF | |
138 | /* | |
139 | ** Since lockf has the interesting semantic that the | |
140 | ** lock is lost when we fork, we have to risk losing | |
141 | ** the lock here by closing before the fork, and then | |
142 | ** trying to get it back in the child. | |
143 | */ | |
144 | ||
145 | if (e->e_lockfp != NULL) | |
146 | { | |
147 | (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp"); | |
148 | e->e_lockfp = NULL; | |
149 | } | |
150 | # endif /* LOCKF */ | |
151 | ||
152 | pid = fork(); | |
153 | if (pid < 0) | |
154 | { | |
155 | goto queueonly; | |
156 | } | |
157 | else if (pid > 0) | |
158 | { | |
159 | /* be sure we leave the temp files to our child */ | |
160 | e->e_id = e->e_df = NULL; | |
161 | # ifndef LOCKF | |
162 | if (e->e_lockfp != NULL) | |
163 | { | |
164 | (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp"); | |
165 | e->e_lockfp = NULL; | |
166 | } | |
167 | # endif | |
168 | ||
169 | /* close any random open files in the envelope */ | |
170 | if (e->e_dfp != NULL) | |
171 | { | |
172 | (void) xfclose(e->e_dfp, "sendenvelope", "dfp"); | |
173 | e->e_dfp = NULL; | |
174 | } | |
175 | if (e->e_xfp != NULL) | |
176 | { | |
177 | (void) xfclose(e->e_xfp, "sendenvelope", "xfp"); | |
178 | e->e_xfp = NULL; | |
179 | } | |
180 | return; | |
181 | } | |
182 | ||
183 | /* double fork to avoid zombies */ | |
184 | if (fork() > 0) | |
185 | exit(EX_OK); | |
186 | ||
187 | /* be sure we are immune from the terminal */ | |
188 | disconnect(FALSE, e); | |
189 | ||
190 | # ifdef LOCKF | |
191 | /* | |
192 | ** Now try to get our lock back. | |
193 | */ | |
194 | ||
195 | lfd.l_type = F_WRLCK; | |
196 | lfd.l_whence = lfd.l_start = lfd.l_len = 0; | |
197 | e->e_lockfp = fopen(queuename(e, 'q'), "r+"); | |
198 | if (e->e_lockfp == NULL || | |
199 | fcntl(fileno(e->e_lockfp), F_SETLK, &lfd) < 0) | |
200 | { | |
201 | /* oops.... lost it */ | |
202 | if (tTd(13, 1)) | |
203 | printf("sendenvelope: %s lost lock: lockfp=%x, %s\n", | |
204 | e->e_id, e->e_lockfp, errstring(errno)); | |
205 | ||
206 | # ifdef LOG | |
207 | if (LogLevel > 29) | |
208 | syslog(LOG_NOTICE, "%s: lost lock: %m", | |
209 | e->e_id); | |
210 | # endif /* LOG */ | |
211 | exit(EX_OK); | |
212 | } | |
213 | # endif /* LOCKF */ | |
214 | ||
215 | /* | |
216 | ** Close any cached connections. | |
217 | ** | |
218 | ** We don't send the QUIT protocol because the parent | |
219 | ** still knows about the connection. | |
220 | ** | |
221 | ** This should only happen when delivering an error | |
222 | ** message. | |
223 | */ | |
224 | ||
225 | mci_flush(FALSE, NULL); | |
226 | ||
227 | break; | |
228 | } | |
229 | ||
230 | /* | |
231 | ** If we haven't fully expanded aliases, do it now | |
232 | */ | |
233 | ||
234 | if (bitset(EF_VRFYONLY, e->e_flags)) | |
235 | { | |
236 | e->e_flags &= ~EF_VRFYONLY; | |
237 | for (q = e->e_sendqueue; q != NULL; q = q->q_next) | |
238 | { | |
239 | extern ADDRESS *recipient(); | |
240 | ||
241 | if (bitset(QVERIFIED, q->q_flags)) | |
242 | recipient(q, &e->e_sendqueue, e); | |
243 | } | |
244 | } | |
245 | ||
1ab402f2 | 246 | /* |
6acfa498 EA |
247 | ** Handle alias owners. |
248 | ** | |
249 | ** We scan up the q_alias chain looking for owners. | |
250 | ** We discard owners that are the same as the return path. | |
b3cbe40f EA |
251 | */ |
252 | ||
6acfa498 | 253 | for (q = e->e_sendqueue; q != NULL; q = q->q_next) |
b3cbe40f | 254 | { |
6acfa498 | 255 | register struct address *a; |
779597d8 | 256 | |
6acfa498 | 257 | for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) |
779597d8 | 258 | continue; |
6acfa498 EA |
259 | if (a != NULL) |
260 | q->q_owner = a->q_owner; | |
261 | ||
262 | if (q->q_owner != NULL && | |
263 | !bitset(QDONTSEND, q->q_flags) && | |
264 | strcmp(q->q_owner, e->e_from.q_paddr) == 0) | |
265 | q->q_owner = NULL; | |
266 | } | |
267 | ||
268 | owner = ""; | |
269 | otherowners = 1; | |
270 | while (owner != NULL && otherowners > 0) | |
271 | { | |
272 | owner = NULL; | |
273 | otherowners = 0; | |
1bf7c76b | 274 | |
6acfa498 | 275 | for (q = e->e_sendqueue; q != NULL; q = q->q_next) |
78bbbc48 | 276 | { |
6acfa498 EA |
277 | if (bitset(QDONTSEND, q->q_flags)) |
278 | continue; | |
779597d8 | 279 | |
6acfa498 EA |
280 | if (q->q_owner != NULL) |
281 | { | |
282 | if (owner == NULL) | |
283 | owner = q->q_owner; | |
284 | else if (owner != q->q_owner) | |
285 | { | |
286 | if (strcmp(owner, q->q_owner) == 0) | |
287 | { | |
288 | /* make future comparisons cheap */ | |
289 | q->q_owner = owner; | |
290 | } | |
291 | else | |
292 | { | |
293 | otherowners++; | |
294 | } | |
295 | owner = q->q_owner; | |
296 | } | |
297 | } | |
298 | else | |
299 | { | |
300 | otherowners++; | |
301 | } | |
779597d8 EA |
302 | } |
303 | ||
6acfa498 | 304 | if (owner != NULL && otherowners > 0) |
b3cbe40f | 305 | { |
6acfa498 EA |
306 | extern HDR *copyheader(); |
307 | extern ADDRESS *copyqueue(); | |
779597d8 | 308 | |
6acfa498 EA |
309 | /* |
310 | ** Split this envelope into two. | |
311 | */ | |
74c5fe7c | 312 | |
6acfa498 EA |
313 | ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); |
314 | *ee = *e; | |
315 | ee->e_id = NULL; | |
316 | (void) queuename(ee, '\0'); | |
0df76d69 | 317 | |
6acfa498 EA |
318 | if (tTd(13, 1)) |
319 | printf("sendall: split %s into %s\n", | |
320 | e->e_id, ee->e_id); | |
779597d8 | 321 | |
6acfa498 EA |
322 | ee->e_header = copyheader(e->e_header); |
323 | ee->e_sendqueue = copyqueue(e->e_sendqueue); | |
324 | ee->e_errorqueue = copyqueue(e->e_errorqueue); | |
988a20e2 | 325 | ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS); |
6acfa498 EA |
326 | setsender(owner, ee, NULL, TRUE); |
327 | if (tTd(13, 5)) | |
328 | { | |
329 | printf("sendall(split): QDONTSEND "); | |
330 | printaddr(&ee->e_from, FALSE); | |
331 | } | |
332 | ee->e_from.q_flags |= QDONTSEND; | |
333 | ee->e_dfp = NULL; | |
334 | ee->e_xfp = NULL; | |
335 | ee->e_lockfp = NULL; | |
336 | ee->e_df = NULL; | |
337 | ee->e_errormode = EM_MAIL; | |
338 | ee->e_sibling = splitenv; | |
339 | splitenv = ee; | |
340 | ||
341 | for (q = e->e_sendqueue; q != NULL; q = q->q_next) | |
342 | if (q->q_owner == owner) | |
343 | q->q_flags |= QDONTSEND; | |
344 | for (q = ee->e_sendqueue; q != NULL; q = q->q_next) | |
345 | if (q->q_owner != owner) | |
346 | q->q_flags |= QDONTSEND; | |
e6b0a75b | 347 | |
6acfa498 | 348 | if (e->e_df != NULL && mode != SM_VERIFY) |
e6b0a75b | 349 | { |
6acfa498 EA |
350 | ee->e_dfp = NULL; |
351 | ee->e_df = newstr(queuename(ee, 'd')); | |
352 | if (link(e->e_df, ee->e_df) < 0) | |
353 | { | |
354 | syserr("sendall: link(%s, %s)", | |
355 | e->e_df, ee->e_df); | |
356 | } | |
e6b0a75b | 357 | } |
6acfa498 EA |
358 | |
359 | if (mode != SM_VERIFY) | |
360 | openxscript(ee); | |
361 | #ifdef LOG | |
362 | if (LogLevel > 4) | |
363 | syslog(LOG_INFO, "%s: clone %s", | |
364 | ee->e_id, e->e_id); | |
365 | #endif | |
779597d8 | 366 | } |
b3cbe40f EA |
367 | } |
368 | ||
6acfa498 | 369 | if (owner != NULL) |
e6b0a75b | 370 | { |
6acfa498 EA |
371 | setsender(owner, e, NULL, TRUE); |
372 | if (tTd(13, 5)) | |
373 | { | |
374 | printf("sendall(owner): QDONTSEND "); | |
375 | printaddr(&e->e_from, FALSE); | |
376 | } | |
377 | e->e_from.q_flags |= QDONTSEND; | |
378 | e->e_errormode = EM_MAIL; | |
e6b0a75b | 379 | } |
1ef61b9f | 380 | |
6acfa498 | 381 | if (splitenv != NULL) |
f2e44ded | 382 | { |
6acfa498 | 383 | if (tTd(13, 1)) |
35af2f06 | 384 | { |
6acfa498 EA |
385 | printf("\nsendall: Split queue; remaining queue:\n"); |
386 | printaddr(e->e_sendqueue, TRUE); | |
35af2f06 | 387 | } |
f2e44ded | 388 | |
6acfa498 EA |
389 | for (ee = splitenv; ee != NULL; ee = ee->e_sibling) |
390 | { | |
391 | CurEnv = ee; | |
392 | sendenvelope(ee, mode); | |
393 | } | |
f2e44ded | 394 | |
6acfa498 | 395 | CurEnv = e; |
f2e44ded | 396 | } |
6acfa498 | 397 | sendenvelope(e, mode); |
e62e1144 | 398 | |
6acfa498 EA |
399 | for (; splitenv != NULL; splitenv = splitenv->e_sibling) |
400 | dropenvelope(splitenv); | |
401 | } | |
402 | ||
403 | sendenvelope(e, mode) | |
404 | register ENVELOPE *e; | |
405 | char mode; | |
406 | { | |
6acfa498 | 407 | register ADDRESS *q; |
1d303d98 | 408 | bool oldverbose = Verbose; |
f2e44ded | 409 | |
ed45aae1 | 410 | /* |
6acfa498 | 411 | ** Run through the list and send everything. |
ed45aae1 EA |
412 | */ |
413 | ||
6acfa498 EA |
414 | e->e_nsent = 0; |
415 | for (q = e->e_sendqueue; q != NULL; q = q->q_next) | |
f2e44ded | 416 | { |
6acfa498 | 417 | if (mode == SM_VERIFY) |
1627a785 | 418 | { |
6acfa498 EA |
419 | e->e_to = q->q_paddr; |
420 | if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) | |
d1c234d8 EA |
421 | { |
422 | message("deliverable: mailer %s, host %s, user %s", | |
423 | q->q_mailer->m_name, | |
424 | q->q_host, | |
425 | q->q_user); | |
426 | } | |
6acfa498 EA |
427 | } |
428 | else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) | |
429 | { | |
430 | # ifdef QUEUE | |
431 | /* | |
432 | ** Checkpoint the send list every few addresses | |
433 | */ | |
434 | ||
435 | if (e->e_nsent >= CheckpointInterval) | |
436 | { | |
437 | queueup(e, TRUE, FALSE); | |
438 | e->e_nsent = 0; | |
439 | } | |
440 | # endif /* QUEUE */ | |
441 | (void) deliver(e, q); | |
1627a785 | 442 | } |
f2e44ded | 443 | } |
6acfa498 | 444 | Verbose = oldverbose; |
f2e44ded EA |
445 | |
446 | /* | |
6acfa498 | 447 | ** Now run through and check for errors. |
f2e44ded | 448 | */ |
ed45aae1 | 449 | |
6acfa498 EA |
450 | if (mode == SM_VERIFY) |
451 | { | |
452 | return; | |
453 | } | |
454 | ||
455 | for (q = e->e_sendqueue; q != NULL; q = q->q_next) | |
456 | { | |
457 | if (tTd(13, 3)) | |
458 | { | |
459 | printf("Checking "); | |
460 | printaddr(q, FALSE); | |
461 | } | |
462 | ||
463 | /* only send errors if the message failed */ | |
988a20e2 EA |
464 | if (!bitset(QBADADDR, q->q_flags) || |
465 | bitset(QDONTSEND, q->q_flags)) | |
6acfa498 EA |
466 | continue; |
467 | ||
468 | e->e_flags |= EF_FATALERRS; | |
469 | ||
470 | if (q->q_owner == NULL && strcmp(e->e_from.q_paddr, "<>") != 0) | |
471 | (void) sendtolist(e->e_from.q_paddr, NULL, | |
472 | &e->e_errorqueue, e); | |
473 | } | |
474 | ||
475 | if (mode == SM_FORK) | |
476 | finis(); | |
779597d8 EA |
477 | } |
478 | \f/* | |
6acfa498 EA |
479 | ** DOFORK -- do a fork, retrying a couple of times on failure. |
480 | ** | |
481 | ** This MUST be a macro, since after a vfork we are running | |
482 | ** two processes on the same stack!!! | |
b9e44c3d EA |
483 | ** |
484 | ** Parameters: | |
6acfa498 | 485 | ** none. |
b9e44c3d EA |
486 | ** |
487 | ** Returns: | |
6acfa498 | 488 | ** From a macro??? You've got to be kidding! |
b9e44c3d EA |
489 | ** |
490 | ** Side Effects: | |
6acfa498 EA |
491 | ** Modifies the ==> LOCAL <== variable 'pid', leaving: |
492 | ** pid of child in parent, zero in child. | |
493 | ** -1 on unrecoverable error. | |
494 | ** | |
495 | ** Notes: | |
496 | ** I'm awfully sorry this looks so awful. That's | |
497 | ** vfork for you..... | |
b9e44c3d EA |
498 | */ |
499 | ||
6acfa498 | 500 | # define NFORKTRIES 5 |
140717b5 EA |
501 | |
502 | # ifndef FORK | |
503 | # define FORK fork | |
504 | # endif | |
67e64653 EA |
505 | |
506 | # define DOFORK(fORKfN) \ | |
507 | {\ | |
508 | register int i;\ | |
509 | \ | |
11e32817 | 510 | for (i = NFORKTRIES; --i >= 0; )\ |
67e64653 EA |
511 | {\ |
512 | pid = fORKfN();\ | |
513 | if (pid >= 0)\ | |
514 | break;\ | |
11e32817 | 515 | if (i > 0)\ |
901911f8 | 516 | sleep((unsigned) NFORKTRIES - i);\ |
67e64653 EA |
517 | }\ |
518 | } | |
519 | \f/* | |
2cf55cb7 EA |
520 | ** DOFORK -- simple fork interface to DOFORK. |
521 | ** | |
522 | ** Parameters: | |
523 | ** none. | |
524 | ** | |
525 | ** Returns: | |
526 | ** pid of child in parent. | |
527 | ** zero in child. | |
528 | ** -1 on error. | |
529 | ** | |
530 | ** Side Effects: | |
531 | ** returns twice, once in parent and once in child. | |
532 | */ | |
533 | ||
534 | dofork() | |
535 | { | |
536 | register int pid; | |
537 | ||
538 | DOFORK(fork); | |
539 | return (pid); | |
540 | } | |
541 | \f/* | |
6acfa498 | 542 | ** DELIVER -- Deliver a message to a list of addresses. |
e6b0a75b | 543 | ** |
6acfa498 EA |
544 | ** This routine delivers to everyone on the same host as the |
545 | ** user on the head of the list. It is clever about mailers | |
546 | ** that don't handle multiple users. It is NOT guaranteed | |
547 | ** that it will deliver to all these addresses however -- so | |
548 | ** deliver should be called once for each address on the | |
549 | ** list. | |
e6b0a75b EA |
550 | ** |
551 | ** Parameters: | |
6acfa498 EA |
552 | ** e -- the envelope to deliver. |
553 | ** firstto -- head of the address list to deliver to. | |
e6b0a75b EA |
554 | ** |
555 | ** Returns: | |
6acfa498 EA |
556 | ** zero -- successfully delivered. |
557 | ** else -- some failure, see ExitStat for more info. | |
e6b0a75b EA |
558 | ** |
559 | ** Side Effects: | |
6acfa498 | 560 | ** The standard input is passed off to someone. |
e6b0a75b EA |
561 | */ |
562 | ||
6acfa498 | 563 | deliver(e, firstto) |
30eab7ca | 564 | register ENVELOPE *e; |
6acfa498 | 565 | ADDRESS *firstto; |
e6b0a75b | 566 | { |
6acfa498 EA |
567 | char *host; /* host being sent to */ |
568 | char *user; /* user being sent to */ | |
569 | char **pvp; | |
570 | register char **mvp; | |
571 | register char *p; | |
572 | register MAILER *m; /* mailer for this recipient */ | |
573 | ADDRESS *ctladdr; | |
574 | register MCI *mci; | |
575 | register ADDRESS *to = firstto; | |
576 | bool clever = FALSE; /* running user smtp to this mailer */ | |
577 | ADDRESS *tochain = NULL; /* chain of users in this mailer call */ | |
578 | int rcode; /* response code */ | |
579 | char *firstsig; /* signature of firstto */ | |
580 | int pid; | |
581 | char *curhost; | |
582 | int mpvect[2]; | |
583 | int rpvect[2]; | |
584 | char *pv[MAXPV+1]; | |
585 | char tobuf[TOBUFSIZE]; /* text line of to people */ | |
586 | char buf[MAXNAME]; | |
587 | char rpathbuf[MAXNAME]; /* translated return path */ | |
588 | extern int checkcompat(); | |
6acfa498 | 589 | extern FILE *fdopen(); |
e6b0a75b | 590 | |
6acfa498 EA |
591 | errno = 0; |
592 | if (!ForceMail && bitset(QDONTSEND|QPSEUDO, to->q_flags)) | |
593 | return (0); | |
2ae0e0ed | 594 | |
6acfa498 EA |
595 | #ifdef NAMED_BIND |
596 | /* unless interactive, try twice, over a minute */ | |
597 | if (OpMode == MD_DAEMON || OpMode == MD_SMTP) { | |
598 | _res.retrans = 30; | |
599 | _res.retry = 2; | |
600 | } | |
601 | #endif | |
1ab402f2 | 602 | |
6acfa498 EA |
603 | m = to->q_mailer; |
604 | host = to->q_host; | |
605 | CurEnv = e; /* just in case */ | |
0992263e | 606 | e->e_statmsg = NULL; |
6acfa498 EA |
607 | |
608 | if (tTd(10, 1)) | |
609 | printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", | |
610 | m->m_mno, host, to->q_user); | |
611 | ||
612 | /* | |
613 | ** If this mailer is expensive, and if we don't want to make | |
614 | ** connections now, just mark these addresses and return. | |
615 | ** This is useful if we want to batch connections to | |
616 | ** reduce load. This will cause the messages to be | |
617 | ** queued up, and a daemon will come along to send the | |
618 | ** messages later. | |
619 | ** This should be on a per-mailer basis. | |
620 | */ | |
621 | ||
622 | if (NoConnect && !bitset(EF_QUEUERUN, e->e_flags) && | |
623 | bitnset(M_EXPENSIVE, m->m_flags) && !Verbose) | |
e6b0a75b | 624 | { |
6acfa498 EA |
625 | for (; to != NULL; to = to->q_next) |
626 | { | |
627 | if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || | |
628 | to->q_mailer != m) | |
629 | continue; | |
630 | to->q_flags |= QQUEUEUP|QDONTSEND; | |
631 | e->e_to = to->q_paddr; | |
632 | message("queued"); | |
633 | if (LogLevel > 8) | |
634 | logdelivery(m, NULL, "queued", e); | |
635 | } | |
636 | e->e_to = NULL; | |
637 | return (0); | |
638 | } | |
639 | ||
640 | /* | |
641 | ** Do initial argv setup. | |
642 | ** Insert the mailer name. Notice that $x expansion is | |
643 | ** NOT done on the mailer name. Then, if the mailer has | |
644 | ** a picky -f flag, we insert it as appropriate. This | |
645 | ** code does not check for 'pv' overflow; this places a | |
646 | ** manifest lower limit of 4 for MAXPV. | |
647 | ** The from address rewrite is expected to make | |
648 | ** the address relative to the other end. | |
649 | */ | |
650 | ||
651 | /* rewrite from address, using rewriting rules */ | |
9e43a19e EA |
652 | rcode = EX_OK; |
653 | (void) strcpy(rpathbuf, remotename(e->e_from.q_paddr, m, | |
654 | RF_SENDERADDR|RF_CANONICAL, | |
655 | &rcode, e)); | |
6acfa498 EA |
656 | define('g', rpathbuf, e); /* translated return path */ |
657 | define('h', host, e); /* to host */ | |
658 | Errors = 0; | |
659 | pvp = pv; | |
660 | *pvp++ = m->m_argv[0]; | |
661 | ||
662 | /* insert -f or -r flag as appropriate */ | |
663 | if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) | |
664 | { | |
665 | if (bitnset(M_FOPT, m->m_flags)) | |
666 | *pvp++ = "-f"; | |
667 | else | |
668 | *pvp++ = "-r"; | |
669 | *pvp++ = newstr(rpathbuf); | |
670 | } | |
671 | ||
672 | /* | |
673 | ** Append the other fixed parts of the argv. These run | |
674 | ** up to the first entry containing "$u". There can only | |
675 | ** be one of these, and there are only a few more slots | |
676 | ** in the pv after it. | |
677 | */ | |
678 | ||
679 | for (mvp = m->m_argv; (p = *++mvp) != NULL; ) | |
680 | { | |
681 | /* can't use strchr here because of sign extension problems */ | |
682 | while (*p != '\0') | |
683 | { | |
684 | if ((*p++ & 0377) == MACROEXPAND) | |
685 | { | |
686 | if (*p == 'u') | |
687 | break; | |
688 | } | |
689 | } | |
690 | ||
691 | if (*p != '\0') | |
692 | break; | |
693 | ||
694 | /* this entry is safe -- go ahead and process it */ | |
695 | expand(*mvp, buf, &buf[sizeof buf - 1], e); | |
696 | *pvp++ = newstr(buf); | |
697 | if (pvp >= &pv[MAXPV - 3]) | |
698 | { | |
699 | syserr("554 Too many parameters to %s before $u", pv[0]); | |
700 | return (-1); | |
701 | } | |
702 | } | |
703 | ||
704 | /* | |
705 | ** If we have no substitution for the user name in the argument | |
706 | ** list, we know that we must supply the names otherwise -- and | |
707 | ** SMTP is the answer!! | |
708 | */ | |
709 | ||
710 | if (*mvp == NULL) | |
711 | { | |
712 | /* running SMTP */ | |
713 | # ifdef SMTP | |
714 | clever = TRUE; | |
715 | *pvp = NULL; | |
716 | # else /* SMTP */ | |
717 | /* oops! we don't implement SMTP */ | |
718 | syserr("554 SMTP style mailer"); | |
7338e3d4 | 719 | return (EX_SOFTWARE); |
6acfa498 | 720 | # endif /* SMTP */ |
e6b0a75b | 721 | } |
1ab402f2 | 722 | |
6acfa498 EA |
723 | /* |
724 | ** At this point *mvp points to the argument with $u. We | |
725 | ** run through our address list and append all the addresses | |
726 | ** we can. If we run out of space, do not fret! We can | |
727 | ** always send another copy later. | |
728 | */ | |
729 | ||
730 | tobuf[0] = '\0'; | |
731 | e->e_to = tobuf; | |
732 | ctladdr = NULL; | |
733 | firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); | |
734 | for (; to != NULL; to = to->q_next) | |
e6b0a75b | 735 | { |
6acfa498 EA |
736 | /* avoid sending multiple recipients to dumb mailers */ |
737 | if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) | |
738 | break; | |
30eab7ca | 739 | |
6acfa498 EA |
740 | /* if already sent or not for this host, don't send */ |
741 | if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || | |
742 | to->q_mailer != firstto->q_mailer || | |
743 | strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) | |
744 | continue; | |
745 | ||
746 | /* avoid overflowing tobuf */ | |
747 | if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) | |
748 | break; | |
749 | ||
750 | if (tTd(10, 1)) | |
30eab7ca | 751 | { |
6acfa498 EA |
752 | printf("\nsend to "); |
753 | printaddr(to, FALSE); | |
754 | } | |
30eab7ca | 755 | |
6acfa498 EA |
756 | /* compute effective uid/gid when sending */ |
757 | if (to->q_mailer == ProgMailer) | |
758 | ctladdr = getctladdr(to); | |
759 | ||
760 | user = to->q_user; | |
761 | e->e_to = to->q_paddr; | |
762 | if (tTd(10, 5)) | |
763 | { | |
764 | printf("deliver: QDONTSEND "); | |
765 | printaddr(to, FALSE); | |
30eab7ca | 766 | } |
6acfa498 | 767 | to->q_flags |= QDONTSEND; |
30eab7ca | 768 | |
6acfa498 EA |
769 | /* |
770 | ** Check to see that these people are allowed to | |
771 | ** talk to each other. | |
772 | */ | |
773 | ||
774 | if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) | |
775 | { | |
776 | NoReturn = TRUE; | |
777 | usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); | |
778 | giveresponse(EX_UNAVAILABLE, m, NULL, e); | |
779 | continue; | |
780 | } | |
781 | rcode = checkcompat(to, e); | |
782 | if (rcode != EX_OK) | |
783 | { | |
784 | giveresponse(rcode, m, NULL, e); | |
785 | continue; | |
786 | } | |
787 | ||
788 | /* | |
789 | ** Strip quote bits from names if the mailer is dumb | |
790 | ** about them. | |
791 | */ | |
792 | ||
793 | if (bitnset(M_STRIPQ, m->m_flags)) | |
794 | { | |
795 | stripquotes(user); | |
796 | stripquotes(host); | |
797 | } | |
798 | ||
799 | /* hack attack -- delivermail compatibility */ | |
800 | if (m == ProgMailer && *user == '|') | |
801 | user++; | |
802 | ||
803 | /* | |
804 | ** If an error message has already been given, don't | |
805 | ** bother to send to this address. | |
806 | ** | |
807 | ** >>>>>>>>>> This clause assumes that the local mailer | |
808 | ** >> NOTE >> cannot do any further aliasing; that | |
809 | ** >>>>>>>>>> function is subsumed by sendmail. | |
810 | */ | |
811 | ||
812 | if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) | |
813 | continue; | |
814 | ||
815 | /* save statistics.... */ | |
816 | markstats(e, to); | |
817 | ||
818 | /* | |
819 | ** See if this user name is "special". | |
820 | ** If the user name has a slash in it, assume that this | |
821 | ** is a file -- send it off without further ado. Note | |
822 | ** that this type of addresses is not processed along | |
823 | ** with the others, so we fudge on the To person. | |
824 | */ | |
825 | ||
826 | if (m == FileMailer) | |
827 | { | |
828 | rcode = mailfile(user, getctladdr(to), e); | |
829 | giveresponse(rcode, m, NULL, e); | |
830 | if (rcode == EX_OK) | |
831 | to->q_flags |= QSENT; | |
832 | continue; | |
833 | } | |
834 | ||
835 | /* | |
836 | ** Address is verified -- add this user to mailer | |
837 | ** argv, and add it to the print list of recipients. | |
838 | */ | |
839 | ||
840 | /* link together the chain of recipients */ | |
841 | to->q_tchain = tochain; | |
842 | tochain = to; | |
843 | ||
844 | /* create list of users for error messages */ | |
845 | (void) strcat(tobuf, ","); | |
846 | (void) strcat(tobuf, to->q_paddr); | |
847 | define('u', user, e); /* to user */ | |
848 | define('z', to->q_home, e); /* user's home */ | |
849 | ||
850 | /* | |
851 | ** Expand out this user into argument list. | |
852 | */ | |
853 | ||
854 | if (!clever) | |
855 | { | |
856 | expand(*mvp, buf, &buf[sizeof buf - 1], e); | |
857 | *pvp++ = newstr(buf); | |
858 | if (pvp >= &pv[MAXPV - 2]) | |
859 | { | |
860 | /* allow some space for trailing parms */ | |
861 | break; | |
862 | } | |
863 | } | |
e6b0a75b | 864 | } |
1ab402f2 | 865 | |
6acfa498 EA |
866 | /* see if any addresses still exist */ |
867 | if (tobuf[0] == '\0') | |
868 | { | |
869 | define('g', (char *) NULL, e); | |
870 | return (0); | |
871 | } | |
872 | ||
873 | /* print out messages as full list */ | |
874 | e->e_to = tobuf + 1; | |
875 | ||
876 | /* | |
877 | ** Fill out any parameters after the $u parameter. | |
878 | */ | |
879 | ||
880 | while (!clever && *++mvp != NULL) | |
881 | { | |
882 | expand(*mvp, buf, &buf[sizeof buf - 1], e); | |
883 | *pvp++ = newstr(buf); | |
884 | if (pvp >= &pv[MAXPV]) | |
885 | syserr("554 deliver: pv overflow after $u for %s", pv[0]); | |
886 | } | |
887 | *pvp++ = NULL; | |
888 | ||
889 | /* | |
890 | ** Call the mailer. | |
891 | ** The argument vector gets built, pipes | |
892 | ** are created as necessary, and we fork & exec as | |
893 | ** appropriate. | |
894 | ** If we are running SMTP, we just need to clean up. | |
895 | */ | |
e6b0a75b | 896 | |
6acfa498 EA |
897 | if (ctladdr == NULL && m != ProgMailer) |
898 | ctladdr = &e->e_from; | |
899 | #ifdef NAMED_BIND | |
900 | if (ConfigLevel < 2) | |
901 | _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ | |
902 | #endif | |
779597d8 | 903 | |
9678c96d | 904 | if (tTd(11, 1)) |
b3cbe40f | 905 | { |
857afefe | 906 | printf("openmailer:"); |
6acfa498 | 907 | printav(pv); |
b3cbe40f | 908 | } |
d829793b | 909 | errno = 0; |
779597d8 | 910 | |
57c97d4a EA |
911 | CurHostName = m->m_mailer; |
912 | ||
1ab402f2 EA |
913 | /* |
914 | ** Deal with the special case of mail handled through an IPC | |
915 | ** connection. | |
916 | ** In this case we don't actually fork. We must be | |
917 | ** running SMTP for this to work. We will return a | |
918 | ** zero pid to indicate that we are running IPC. | |
5463e94d | 919 | ** We also handle a debug version that just talks to stdin/out. |
1ab402f2 EA |
920 | */ |
921 | ||
6acfa498 EA |
922 | curhost = NULL; |
923 | ||
5463e94d EA |
924 | /* check for Local Person Communication -- not for mortals!!! */ |
925 | if (strcmp(m->m_mailer, "[LPC]") == 0) | |
926 | { | |
f2e44ded | 927 | mci = (MCI *) xalloc(sizeof *mci); |
3eb4fac4 | 928 | bzero((char *) mci, sizeof *mci); |
2ae0e0ed EA |
929 | mci->mci_in = stdin; |
930 | mci->mci_out = stdout; | |
f2e44ded | 931 | mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; |
e62e1144 | 932 | mci->mci_mailer = m; |
5463e94d | 933 | } |
f2e44ded EA |
934 | else if (strcmp(m->m_mailer, "[IPC]") == 0 || |
935 | strcmp(m->m_mailer, "[TCP]") == 0) | |
1ab402f2 | 936 | { |
140717b5 | 937 | #ifdef DAEMON |
7e70d3c8 | 938 | register int i; |
f7eb07a3 | 939 | register u_short port; |
1ab402f2 | 940 | |
6acfa498 EA |
941 | CurHostName = pv[1]; |
942 | curhost = hostsignature(m, pv[1], e); | |
f2e44ded | 943 | |
f2b8376e EA |
944 | if (curhost == NULL || curhost[0] == '\0') |
945 | { | |
946 | syserr("null signature"); | |
6acfa498 EA |
947 | rcode = EX_OSERR; |
948 | goto give_up; | |
f2b8376e EA |
949 | } |
950 | ||
1ab402f2 | 951 | if (!clever) |
f2b8376e | 952 | { |
b6edea3d | 953 | syserr("554 non-clever IPC"); |
6acfa498 EA |
954 | rcode = EX_OSERR; |
955 | goto give_up; | |
f2b8376e | 956 | } |
6acfa498 EA |
957 | if (pv[2] != NULL) |
958 | port = atoi(pv[2]); | |
e2d7c32a | 959 | else |
f7eb07a3 | 960 | port = 0; |
6acfa498 EA |
961 | tryhost: |
962 | mci = NULL; | |
7e70d3c8 | 963 | while (*curhost != '\0') |
e2abd3be | 964 | { |
7e70d3c8 | 965 | register char *p; |
2388926b | 966 | static char hostbuf[MAXNAME]; |
7e70d3c8 | 967 | |
6acfa498 EA |
968 | mci = NULL; |
969 | ||
7e70d3c8 EA |
970 | /* pull the next host from the signature */ |
971 | p = strchr(curhost, ':'); | |
972 | if (p == NULL) | |
973 | p = &curhost[strlen(curhost)]; | |
974 | strncpy(hostbuf, curhost, p - curhost); | |
975 | hostbuf[p - curhost] = '\0'; | |
976 | if (*p != '\0') | |
977 | p++; | |
978 | curhost = p; | |
979 | ||
8657d05f | 980 | /* see if we already know that this host is fried */ |
7e70d3c8 EA |
981 | CurHostName = hostbuf; |
982 | mci = mci_get(hostbuf, m); | |
f2e44ded | 983 | if (mci->mci_state != MCIS_CLOSED) |
237bda52 EA |
984 | { |
985 | if (tTd(11, 1)) | |
986 | { | |
987 | printf("openmailer: "); | |
988 | mci_dump(mci); | |
989 | } | |
322eceee | 990 | CurHostName = mci->mci_host; |
6acfa498 | 991 | break; |
237bda52 | 992 | } |
e62e1144 | 993 | mci->mci_mailer = m; |
f2e44ded EA |
994 | if (mci->mci_exitstat != EX_OK) |
995 | continue; | |
996 | ||
997 | /* try the connection */ | |
7e70d3c8 | 998 | setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); |
b6edea3d | 999 | message("Connecting to %s (%s)...", |
7e70d3c8 EA |
1000 | hostbuf, m->m_name); |
1001 | i = makeconnection(hostbuf, port, mci, | |
f2e44ded EA |
1002 | bitnset(M_SECURE_PORT, m->m_flags)); |
1003 | mci->mci_exitstat = i; | |
1004 | mci->mci_errno = errno; | |
1005 | if (i == EX_OK) | |
e2abd3be | 1006 | { |
f2e44ded EA |
1007 | mci->mci_state = MCIS_OPENING; |
1008 | mci_cache(mci); | |
1009 | break; | |
e2abd3be | 1010 | } |
f2e44ded EA |
1011 | else if (tTd(11, 1)) |
1012 | printf("openmailer: makeconnection => stat=%d, errno=%d\n", | |
1013 | i, errno); | |
1014 | ||
2ae0e0ed EA |
1015 | |
1016 | /* enter status of this host */ | |
1017 | setstat(i); | |
1ea752a1 | 1018 | } |
3eb4fac4 | 1019 | mci->mci_pid = 0; |
f2e44ded | 1020 | #else /* no DAEMON */ |
b6edea3d | 1021 | syserr("554 openmailer: no IPC"); |
237bda52 EA |
1022 | if (tTd(11, 1)) |
1023 | printf("openmailer: NULL\n"); | |
2ae0e0ed | 1024 | return NULL; |
f2e44ded | 1025 | #endif /* DAEMON */ |
1ab402f2 | 1026 | } |
f2e44ded | 1027 | else |
b3cbe40f | 1028 | { |
4a101ce5 EA |
1029 | int i; |
1030 | struct stat stbuf; | |
1031 | ||
1032 | /* make absolutely certain 0, 1, and 2 are in use */ | |
1033 | for (i = 0; i < 3; i++) | |
1034 | { | |
1035 | if (fstat(i, &stbuf) < 0) | |
1036 | { | |
1037 | /* oops.... */ | |
f22c6db0 EA |
1038 | int fd; |
1039 | ||
1040 | syserr("%s... openmailer(%s): fd %d not open", | |
1041 | e->e_to, m->m_name, i); | |
1042 | fd = open("/dev/null", O_RDONLY, 0666); | |
1043 | if (fd != i) | |
1044 | { | |
1045 | (void) dup2(fd, i); | |
1046 | (void) close(fd); | |
1047 | } | |
4a101ce5 EA |
1048 | } |
1049 | } | |
1050 | ||
f2e44ded EA |
1051 | /* create a pipe to shove the mail through */ |
1052 | if (pipe(mpvect) < 0) | |
1053 | { | |
f22c6db0 EA |
1054 | syserr("%s... openmailer(%s): pipe (to mailer)", |
1055 | e->e_to, m->m_name); | |
237bda52 EA |
1056 | if (tTd(11, 1)) |
1057 | printf("openmailer: NULL\n"); | |
6acfa498 EA |
1058 | rcode = EX_OSERR; |
1059 | goto give_up; | |
f2e44ded | 1060 | } |
e6b0a75b | 1061 | |
f2e44ded EA |
1062 | /* if this mailer speaks smtp, create a return pipe */ |
1063 | if (clever && pipe(rpvect) < 0) | |
1064 | { | |
f22c6db0 EA |
1065 | syserr("%s... openmailer(%s): pipe (from mailer)", |
1066 | e->e_to, m->m_name); | |
f2e44ded EA |
1067 | (void) close(mpvect[0]); |
1068 | (void) close(mpvect[1]); | |
237bda52 EA |
1069 | if (tTd(11, 1)) |
1070 | printf("openmailer: NULL\n"); | |
6acfa498 EA |
1071 | rcode = EX_OSERR; |
1072 | goto give_up; | |
f2e44ded | 1073 | } |
e6b0a75b | 1074 | |
f2e44ded EA |
1075 | /* |
1076 | ** Actually fork the mailer process. | |
1077 | ** DOFORK is clever about retrying. | |
1078 | ** | |
1079 | ** Dispose of SIGCHLD signal catchers that may be laying | |
1080 | ** around so that endmail will get it. | |
1081 | */ | |
1ab402f2 | 1082 | |
f2e44ded EA |
1083 | if (e->e_xfp != NULL) |
1084 | (void) fflush(e->e_xfp); /* for debugging */ | |
1085 | (void) fflush(stdout); | |
1cc8903f | 1086 | # ifdef SIGCHLD |
f2e44ded | 1087 | (void) signal(SIGCHLD, SIG_DFL); |
f3d8f6d6 | 1088 | # endif /* SIGCHLD */ |
f2e44ded EA |
1089 | DOFORK(FORK); |
1090 | /* pid is set by DOFORK */ | |
1091 | if (pid < 0) | |
e6b0a75b | 1092 | { |
f2e44ded | 1093 | /* failure */ |
f22c6db0 EA |
1094 | syserr("%s... openmailer(%s): cannot fork", |
1095 | e->e_to, m->m_name); | |
f2e44ded EA |
1096 | (void) close(mpvect[0]); |
1097 | (void) close(mpvect[1]); | |
1098 | if (clever) | |
1099 | { | |
1100 | (void) close(rpvect[0]); | |
1101 | (void) close(rpvect[1]); | |
1102 | } | |
237bda52 EA |
1103 | if (tTd(11, 1)) |
1104 | printf("openmailer: NULL\n"); | |
6acfa498 EA |
1105 | rcode = EX_OSERR; |
1106 | goto give_up; | |
e6b0a75b | 1107 | } |
f2e44ded EA |
1108 | else if (pid == 0) |
1109 | { | |
1110 | int i; | |
f62b79ae | 1111 | int saveerrno; |
8381386b EA |
1112 | char **ep; |
1113 | char *env[MAXUSERENVIRON]; | |
1114 | extern char **environ; | |
f2e44ded | 1115 | extern int DtableSize; |
f2ba91d2 | 1116 | |
f2e44ded EA |
1117 | /* child -- set up input & exec mailer */ |
1118 | /* make diagnostic output be standard output */ | |
1119 | (void) signal(SIGINT, SIG_IGN); | |
1120 | (void) signal(SIGHUP, SIG_IGN); | |
1121 | (void) signal(SIGTERM, SIG_DFL); | |
49086753 | 1122 | |
1c7897ef EA |
1123 | /* close any other cached connections */ |
1124 | mci_flush(FALSE, mci); | |
1125 | ||
6f5db107 EA |
1126 | /* move into some "safe" directory */ |
1127 | if (m->m_execdir != NULL) | |
1128 | { | |
1129 | char *p, *q; | |
1130 | char buf[MAXLINE]; | |
1131 | ||
1132 | for (p = m->m_execdir; p != NULL; p = q) | |
1133 | { | |
1134 | q = strchr(p, ':'); | |
1135 | if (q != NULL) | |
1136 | *q = '\0'; | |
1137 | expand(p, buf, &buf[sizeof buf] - 1, e); | |
1138 | if (q != NULL) | |
1139 | *q++ = ':'; | |
1140 | if (tTd(11, 20)) | |
1141 | printf("openmailer: trydir %s\n", | |
1142 | buf); | |
1143 | if (buf[0] != '\0' && chdir(buf) >= 0) | |
1144 | break; | |
1145 | } | |
1146 | } | |
1147 | ||
f2e44ded EA |
1148 | /* arrange to filter std & diag output of command */ |
1149 | if (clever) | |
1150 | { | |
1151 | (void) close(rpvect[0]); | |
4a101ce5 EA |
1152 | if (dup2(rpvect[1], STDOUT_FILENO) < 0) |
1153 | { | |
f22c6db0 EA |
1154 | syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", |
1155 | e->e_to, m->m_name, rpvect[1]); | |
4a101ce5 EA |
1156 | _exit(EX_OSERR); |
1157 | } | |
f2e44ded EA |
1158 | (void) close(rpvect[1]); |
1159 | } | |
1160 | else if (OpMode == MD_SMTP || HoldErrs) | |
1161 | { | |
1162 | /* put mailer output in transcript */ | |
4a101ce5 EA |
1163 | if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) |
1164 | { | |
f22c6db0 EA |
1165 | syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", |
1166 | e->e_to, m->m_name, | |
4a101ce5 EA |
1167 | fileno(e->e_xfp)); |
1168 | _exit(EX_OSERR); | |
1169 | } | |
1170 | } | |
1171 | if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) | |
1172 | { | |
f22c6db0 EA |
1173 | syserr("%s... openmailer(%s): cannot dup stdout for stderr", |
1174 | e->e_to, m->m_name); | |
4a101ce5 | 1175 | _exit(EX_OSERR); |
f2e44ded | 1176 | } |
49086753 | 1177 | |
f2e44ded EA |
1178 | /* arrange to get standard input */ |
1179 | (void) close(mpvect[1]); | |
d74803dd | 1180 | if (dup2(mpvect[0], STDIN_FILENO) < 0) |
208e82d2 | 1181 | { |
f22c6db0 EA |
1182 | syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", |
1183 | e->e_to, m->m_name, mpvect[0]); | |
f2e44ded | 1184 | _exit(EX_OSERR); |
208e82d2 | 1185 | } |
f2e44ded EA |
1186 | (void) close(mpvect[0]); |
1187 | if (!bitnset(M_RESTR, m->m_flags)) | |
a13c4f97 | 1188 | { |
f2e44ded EA |
1189 | if (ctladdr == NULL || ctladdr->q_uid == 0) |
1190 | { | |
1191 | (void) setgid(DefGid); | |
1192 | (void) initgroups(DefUser, DefGid); | |
1193 | (void) setuid(DefUid); | |
1194 | } | |
1195 | else | |
1196 | { | |
1197 | (void) setgid(ctladdr->q_gid); | |
1198 | (void) initgroups(ctladdr->q_ruser? | |
1199 | ctladdr->q_ruser: ctladdr->q_user, | |
1200 | ctladdr->q_gid); | |
1201 | (void) setuid(ctladdr->q_uid); | |
1202 | } | |
a13c4f97 | 1203 | } |
7338e3d4 | 1204 | |
f2e44ded EA |
1205 | /* arrange for all the files to be closed */ |
1206 | for (i = 3; i < DtableSize; i++) | |
1207 | { | |
1208 | register int j; | |
1209 | if ((j = fcntl(i, F_GETFD, 0)) != -1) | |
1210 | (void)fcntl(i, F_SETFD, j|1); | |
1211 | } | |
1ab402f2 | 1212 | |
8381386b EA |
1213 | /* set up the mailer environment */ |
1214 | i = 0; | |
1215 | env[i++] = "AGENT=sendmail"; | |
1216 | for (ep = environ; *ep != NULL; ep++) | |
1217 | { | |
1218 | if (strncmp(*ep, "TZ=", 3) == 0) | |
1219 | env[i++] = *ep; | |
1220 | } | |
1221 | env[i++] = NULL; | |
1222 | ||
f2e44ded | 1223 | /* try to execute the mailer */ |
6acfa498 | 1224 | execve(m->m_mailer, pv, env); |
f62b79ae | 1225 | saveerrno = errno; |
f2e44ded | 1226 | syserr("Cannot exec %s", m->m_mailer); |
55b12947 EA |
1227 | if (m == LocalMailer || transienterror(saveerrno)) |
1228 | _exit(EX_OSERR); | |
f2e44ded EA |
1229 | _exit(EX_UNAVAILABLE); |
1230 | } | |
1231 | ||
1232 | /* | |
1233 | ** Set up return value. | |
1234 | */ | |
1235 | ||
1236 | mci = (MCI *) xalloc(sizeof *mci); | |
3eb4fac4 | 1237 | bzero((char *) mci, sizeof *mci); |
f2e44ded EA |
1238 | mci->mci_mailer = m; |
1239 | mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; | |
3eb4fac4 | 1240 | mci->mci_pid = pid; |
f2e44ded EA |
1241 | (void) close(mpvect[0]); |
1242 | mci->mci_out = fdopen(mpvect[1], "w"); | |
1243 | if (clever) | |
1244 | { | |
1245 | (void) close(rpvect[1]); | |
1246 | mci->mci_in = fdopen(rpvect[0], "r"); | |
1247 | } | |
1248 | else | |
1249 | { | |
1250 | mci->mci_flags |= MCIF_TEMP; | |
1251 | mci->mci_in = NULL; | |
4287d84d | 1252 | } |
b3cbe40f EA |
1253 | } |
1254 | ||
6acfa498 EA |
1255 | /* |
1256 | ** If we are in SMTP opening state, send initial protocol. | |
1257 | */ | |
1258 | ||
1259 | if (clever && mci->mci_state != MCIS_CLOSED) | |
1260 | { | |
1261 | smtpinit(m, mci, e); | |
1262 | } | |
1263 | if (tTd(11, 1)) | |
1264 | { | |
1265 | printf("openmailer: "); | |
1266 | mci_dump(mci); | |
1267 | } | |
1268 | ||
1269 | if (mci->mci_state != MCIS_OPEN) | |
1270 | { | |
1271 | /* couldn't open the mailer */ | |
1272 | rcode = mci->mci_exitstat; | |
1273 | errno = mci->mci_errno; | |
1274 | if (rcode == EX_OK) | |
1275 | { | |
1276 | /* shouldn't happen */ | |
1277 | syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", | |
1278 | rcode, mci->mci_state, firstsig); | |
1279 | rcode = EX_SOFTWARE; | |
1280 | } | |
e78de5de | 1281 | else if (rcode == EX_TEMPFAIL && *curhost != '\0') |
e80c91fc EA |
1282 | { |
1283 | /* try next MX site */ | |
1284 | goto tryhost; | |
1285 | } | |
6acfa498 EA |
1286 | } |
1287 | else if (!clever) | |
1288 | { | |
1289 | /* | |
1290 | ** Format and send message. | |
1291 | */ | |
1292 | ||
1293 | putfromline(mci->mci_out, m, e); | |
1294 | (*e->e_puthdr)(mci->mci_out, m, e); | |
1295 | putline("\n", mci->mci_out, m); | |
2f6a8a78 | 1296 | (*e->e_putbody)(mci->mci_out, m, e, NULL); |
6acfa498 EA |
1297 | |
1298 | /* get the exit status */ | |
1299 | rcode = endmailer(mci, e, pv); | |
1300 | } | |
1301 | else | |
1302 | #ifdef SMTP | |
1303 | { | |
1304 | /* | |
1305 | ** Send the MAIL FROM: protocol | |
1306 | */ | |
1307 | ||
1308 | rcode = smtpmailfrom(m, mci, e); | |
1309 | if (rcode == EX_OK) | |
1310 | { | |
1311 | register char *t = tobuf; | |
1312 | register int i; | |
1313 | ||
1314 | /* send the recipient list */ | |
1315 | tobuf[0] = '\0'; | |
1316 | for (to = tochain; to != NULL; to = to->q_tchain) | |
1317 | { | |
1318 | e->e_to = to->q_paddr; | |
1319 | if ((i = smtprcpt(to, m, mci, e)) != EX_OK) | |
1320 | { | |
1321 | markfailure(e, to, i); | |
1322 | giveresponse(i, m, mci, e); | |
1323 | } | |
1324 | else | |
1325 | { | |
1326 | *t++ = ','; | |
1327 | for (p = to->q_paddr; *p; *t++ = *p++) | |
1328 | continue; | |
1329 | } | |
1330 | } | |
1331 | ||
1332 | /* now send the data */ | |
1333 | if (tobuf[0] == '\0') | |
1334 | { | |
1335 | rcode = EX_OK; | |
1336 | e->e_to = NULL; | |
1337 | if (bitset(MCIF_CACHED, mci->mci_flags)) | |
1338 | smtprset(m, mci, e); | |
1339 | } | |
1340 | else | |
1341 | { | |
1342 | e->e_to = tobuf + 1; | |
1343 | rcode = smtpdata(m, mci, e); | |
1344 | } | |
1345 | ||
1346 | /* now close the connection */ | |
1347 | if (!bitset(MCIF_CACHED, mci->mci_flags)) | |
1348 | smtpquit(m, mci, e); | |
1349 | } | |
1350 | if (rcode != EX_OK && *curhost != '\0') | |
1351 | { | |
1352 | /* try next MX site */ | |
1353 | goto tryhost; | |
1354 | } | |
1355 | } | |
1356 | #else /* not SMTP */ | |
1357 | { | |
1358 | syserr("554 deliver: need SMTP compiled to use clever mailer"); | |
1359 | rcode = EX_CONFIG; | |
1360 | goto give_up; | |
1361 | } | |
1362 | #endif /* SMTP */ | |
1363 | #ifdef NAMED_BIND | |
1364 | if (ConfigLevel < 2) | |
1365 | _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ | |
1366 | #endif | |
1367 | ||
1368 | /* arrange a return receipt if requested */ | |
1369 | if (e->e_receiptto != NULL && bitnset(M_LOCALMAILER, m->m_flags)) | |
1370 | { | |
1371 | e->e_flags |= EF_SENDRECEIPT; | |
1372 | /* do we want to send back more info? */ | |
1373 | } | |
1374 | ||
1375 | /* | |
1376 | ** Do final status disposal. | |
1377 | ** We check for something in tobuf for the SMTP case. | |
1378 | ** If we got a temporary failure, arrange to queue the | |
1379 | ** addressees. | |
1380 | */ | |
1381 | ||
1382 | give_up: | |
1383 | if (tobuf[0] != '\0') | |
1384 | giveresponse(rcode, m, mci, e); | |
1385 | for (to = tochain; to != NULL; to = to->q_tchain) | |
1386 | { | |
1387 | if (rcode != EX_OK) | |
1388 | markfailure(e, to, rcode); | |
1389 | else | |
1390 | { | |
1391 | to->q_flags |= QSENT; | |
1392 | e->e_nsent++; | |
1393 | } | |
1394 | } | |
1395 | ||
1396 | /* | |
1397 | ** Restore state and return. | |
1398 | */ | |
1399 | ||
1400 | errno = 0; | |
1401 | define('g', (char *) NULL, e); | |
1402 | return (rcode); | |
1403 | } | |
1404 | \f/* | |
1405 | ** MARKFAILURE -- mark a failure on a specific address. | |
1406 | ** | |
1407 | ** Parameters: | |
1408 | ** e -- the envelope we are sending. | |
1409 | ** q -- the address to mark. | |
1410 | ** rcode -- the code signifying the particular failure. | |
1411 | ** | |
1412 | ** Returns: | |
1413 | ** none. | |
1414 | ** | |
1415 | ** Side Effects: | |
1416 | ** marks the address (and possibly the envelope) with the | |
1417 | ** failure so that an error will be returned or | |
1418 | ** the message will be queued, as appropriate. | |
1419 | */ | |
1420 | ||
1421 | markfailure(e, q, rcode) | |
1422 | register ENVELOPE *e; | |
1423 | register ADDRESS *q; | |
1424 | int rcode; | |
1425 | { | |
1426 | char buf[MAXLINE]; | |
6acfa498 EA |
1427 | |
1428 | if (rcode == EX_OK) | |
1429 | return; | |
1430 | else if (rcode != EX_TEMPFAIL && rcode != EX_IOERR && rcode != EX_OSERR) | |
1431 | q->q_flags |= QBADADDR; | |
1432 | else if (curtime() > e->e_ctime + TimeOuts.to_q_return) | |
1433 | { | |
1434 | if (!bitset(EF_TIMEOUT, e->e_flags)) | |
1435 | { | |
1436 | (void) sprintf(buf, "Cannot send message for %s", | |
1437 | pintvl(TimeOuts.to_q_return, FALSE)); | |
1438 | if (e->e_message != NULL) | |
1439 | free(e->e_message); | |
1440 | e->e_message = newstr(buf); | |
1441 | message(buf); | |
1442 | } | |
1443 | q->q_flags |= QBADADDR; | |
1444 | e->e_flags |= EF_TIMEOUT; | |
1445 | fprintf(e->e_xfp, "421 %s... Message timed out\n", q->q_paddr); | |
1446 | } | |
1447 | else | |
1448 | { | |
1449 | q->q_flags |= QQUEUEUP; | |
1450 | if (TimeOuts.to_q_warning > 0 && | |
1451 | curtime() > e->e_ctime + TimeOuts.to_q_warning) | |
1452 | { | |
1453 | if (!bitset(EF_WARNING, e->e_flags) && | |
1454 | e->e_class >= 0) | |
1455 | { | |
1456 | (void) sprintf(buf, | |
1457 | "warning: cannot send message for %s", | |
1458 | pintvl(TimeOuts.to_q_warning, FALSE)); | |
1459 | if (e->e_message != NULL) | |
1460 | free(e->e_message); | |
1461 | e->e_message = newstr(buf); | |
1462 | message(buf); | |
1463 | e->e_flags |= EF_WARNING|EF_TIMEOUT; | |
1464 | } | |
1465 | fprintf(e->e_xfp, | |
1466 | "%s... Warning: message still undelivered after %s\n", | |
1467 | q->q_paddr, pintvl(TimeOuts.to_q_warning, FALSE)); | |
1468 | fprintf(e->e_xfp, "Will keep trying until message is %s old\n", | |
1469 | pintvl(TimeOuts.to_q_return, FALSE)); | |
1470 | } | |
1471 | } | |
1472 | } | |
1473 | \f/* | |
1474 | ** ENDMAILER -- Wait for mailer to terminate. | |
1475 | ** | |
1476 | ** We should never get fatal errors (e.g., segmentation | |
1477 | ** violation), so we report those specially. For other | |
1478 | ** errors, we choose a status message (into statmsg), | |
1479 | ** and if it represents an error, we print it. | |
1480 | ** | |
1481 | ** Parameters: | |
1482 | ** pid -- pid of mailer. | |
1483 | ** e -- the current envelope. | |
1484 | ** pv -- the parameter vector that invoked the mailer | |
1485 | ** (for error messages). | |
1486 | ** | |
1487 | ** Returns: | |
1488 | ** exit code of mailer. | |
1489 | ** | |
1490 | ** Side Effects: | |
1491 | ** none. | |
1492 | */ | |
1493 | ||
1494 | endmailer(mci, e, pv) | |
1495 | register MCI *mci; | |
1496 | register ENVELOPE *e; | |
1497 | char **pv; | |
1498 | { | |
1499 | int st; | |
1500 | ||
1501 | /* close any connections */ | |
1502 | if (mci->mci_in != NULL) | |
1503 | (void) xfclose(mci->mci_in, pv[0], "mci_in"); | |
1504 | if (mci->mci_out != NULL) | |
1505 | (void) xfclose(mci->mci_out, pv[0], "mci_out"); | |
1506 | mci->mci_in = mci->mci_out = NULL; | |
1507 | mci->mci_state = MCIS_CLOSED; | |
49086753 | 1508 | |
6acfa498 EA |
1509 | /* in the IPC case there is nothing to wait for */ |
1510 | if (mci->mci_pid == 0) | |
1511 | return (EX_OK); | |
1512 | ||
1513 | /* wait for the mailer process to die and collect status */ | |
1514 | st = waitfor(mci->mci_pid); | |
1515 | if (st == -1) | |
b3cbe40f | 1516 | { |
6acfa498 EA |
1517 | syserr("endmailer %s: wait", pv[0]); |
1518 | return (EX_SOFTWARE); | |
2ae0e0ed | 1519 | } |
6acfa498 EA |
1520 | |
1521 | /* see if it died a horrid death */ | |
1522 | if ((st & 0377) != 0) | |
237bda52 | 1523 | { |
6acfa498 EA |
1524 | syserr("mailer %s died with signal %o", pv[0], st); |
1525 | ||
1526 | /* log the arguments */ | |
1527 | if (e->e_xfp != NULL) | |
1528 | { | |
1529 | register char **av; | |
1530 | ||
1531 | fprintf(e->e_xfp, "Arguments:"); | |
1532 | for (av = pv; *av != NULL; av++) | |
1533 | fprintf(e->e_xfp, " %s", *av); | |
1534 | fprintf(e->e_xfp, "\n"); | |
1535 | } | |
1536 | ||
1537 | ExitStat = EX_TEMPFAIL; | |
1538 | return (EX_TEMPFAIL); | |
237bda52 | 1539 | } |
e6b0a75b | 1540 | |
6acfa498 EA |
1541 | /* normal death -- return status */ |
1542 | st = (st >> 8) & 0377; | |
1543 | return (st); | |
b3cbe40f EA |
1544 | } |
1545 | \f/* | |
1546 | ** GIVERESPONSE -- Interpret an error response from a mailer | |
1547 | ** | |
1548 | ** Parameters: | |
1549 | ** stat -- the status code from the mailer (high byte | |
1550 | ** only; core dumps must have been taken care of | |
1551 | ** already). | |
c0ae0b24 EA |
1552 | ** m -- the mailer info for this mailer. |
1553 | ** mci -- the mailer connection info -- can be NULL if the | |
1554 | ** response is given before the connection is made. | |
1555 | ** e -- the current envelope. | |
b3cbe40f EA |
1556 | ** |
1557 | ** Returns: | |
29871fef | 1558 | ** none. |
b3cbe40f EA |
1559 | ** |
1560 | ** Side Effects: | |
d916f0ca | 1561 | ** Errors may be incremented. |
b3cbe40f | 1562 | ** ExitStat may be set. |
b3cbe40f EA |
1563 | */ |
1564 | ||
c0ae0b24 | 1565 | giveresponse(stat, m, mci, e) |
b3cbe40f | 1566 | int stat; |
7338e3d4 | 1567 | register MAILER *m; |
c0ae0b24 | 1568 | register MCI *mci; |
baa0c390 | 1569 | ENVELOPE *e; |
b3cbe40f | 1570 | { |
c51d6c4c | 1571 | register const char *statmsg; |
b3cbe40f EA |
1572 | extern char *SysExMsg[]; |
1573 | register int i; | |
a0c75a49 KB |
1574 | extern int N_SysEx; |
1575 | #ifdef NAMED_BIND | |
1576 | extern int h_errno; | |
1577 | #endif | |
baa0c390 | 1578 | char buf[MAXLINE]; |
b3cbe40f | 1579 | |
74c5fe7c EA |
1580 | /* |
1581 | ** Compute status message from code. | |
1582 | */ | |
1583 | ||
b3cbe40f | 1584 | i = stat - EX__BASE; |
7338e3d4 | 1585 | if (stat == 0) |
4a101ce5 | 1586 | { |
7338e3d4 | 1587 | statmsg = "250 Sent"; |
988a20e2 | 1588 | if (e->e_statmsg != NULL) |
4a101ce5 | 1589 | { |
988a20e2 | 1590 | (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); |
4a101ce5 EA |
1591 | statmsg = buf; |
1592 | } | |
1593 | } | |
7338e3d4 EA |
1594 | else if (i < 0 || i > N_SysEx) |
1595 | { | |
1596 | (void) sprintf(buf, "554 unknown mailer error %d", stat); | |
1597 | stat = EX_UNAVAILABLE; | |
1598 | statmsg = buf; | |
1599 | } | |
baa0c390 EA |
1600 | else if (stat == EX_TEMPFAIL) |
1601 | { | |
2388926b | 1602 | (void) strcpy(buf, SysExMsg[i] + 1); |
a0c75a49 | 1603 | #ifdef NAMED_BIND |
88d7486c | 1604 | if (h_errno == TRY_AGAIN) |
88d7486c | 1605 | statmsg = errstring(h_errno+MAX_ERRNO); |
46f6ec52 | 1606 | else |
a0c75a49 | 1607 | #endif |
46f6ec52 | 1608 | { |
88d7486c | 1609 | if (errno != 0) |
88d7486c | 1610 | statmsg = errstring(errno); |
88d7486c MAN |
1611 | else |
1612 | { | |
46f6ec52 | 1613 | #ifdef SMTP |
88d7486c | 1614 | extern char SmtpError[]; |
46f6ec52 | 1615 | |
88d7486c | 1616 | statmsg = SmtpError; |
f3d8f6d6 | 1617 | #else /* SMTP */ |
88d7486c | 1618 | statmsg = NULL; |
f3d8f6d6 | 1619 | #endif /* SMTP */ |
88d7486c | 1620 | } |
46f6ec52 EA |
1621 | } |
1622 | if (statmsg != NULL && statmsg[0] != '\0') | |
1623 | { | |
e41c463e | 1624 | (void) strcat(buf, ": "); |
46f6ec52 | 1625 | (void) strcat(buf, statmsg); |
baa0c390 | 1626 | } |
baa0c390 EA |
1627 | statmsg = buf; |
1628 | } | |
b3cbe40f | 1629 | else |
46f6ec52 | 1630 | { |
b3cbe40f | 1631 | statmsg = SysExMsg[i]; |
2388926b EA |
1632 | if (*statmsg++ == ':') |
1633 | { | |
1634 | (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); | |
1635 | statmsg = buf; | |
1636 | } | |
46f6ec52 | 1637 | } |
7338e3d4 EA |
1638 | |
1639 | /* | |
1640 | ** Print the message as appropriate | |
1641 | */ | |
1642 | ||
baa0c390 | 1643 | if (stat == EX_OK || stat == EX_TEMPFAIL) |
75593899 | 1644 | message(&statmsg[4], errstring(errno)); |
b3cbe40f EA |
1645 | else |
1646 | { | |
d916f0ca | 1647 | Errors++; |
75593899 | 1648 | usrerr(statmsg, errstring(errno)); |
b3cbe40f EA |
1649 | } |
1650 | ||
1651 | /* | |
1652 | ** Final cleanup. | |
1653 | ** Log a record of the transaction. Compute the new | |
1654 | ** ExitStat -- if we already had an error, stick with | |
1655 | ** that. | |
1656 | */ | |
1657 | ||
68f7099c | 1658 | if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) |
c0ae0b24 | 1659 | logdelivery(m, mci, &statmsg[4], e); |
96476cab | 1660 | |
ed45aae1 EA |
1661 | if (stat != EX_TEMPFAIL) |
1662 | setstat(stat); | |
baa0c390 EA |
1663 | if (stat != EX_OK) |
1664 | { | |
1665 | if (e->e_message != NULL) | |
1666 | free(e->e_message); | |
1667 | e->e_message = newstr(&statmsg[4]); | |
1668 | } | |
e4602f52 | 1669 | errno = 0; |
a0c75a49 | 1670 | #ifdef NAMED_BIND |
88d7486c | 1671 | h_errno = 0; |
a0c75a49 | 1672 | #endif |
b3cbe40f EA |
1673 | } |
1674 | \f/* | |
fe033a8f EA |
1675 | ** LOGDELIVERY -- log the delivery in the system log |
1676 | ** | |
1677 | ** Parameters: | |
c0ae0b24 EA |
1678 | ** m -- the mailer info. Can be NULL for initial queue. |
1679 | ** mci -- the mailer connection info -- can be NULL if the | |
1680 | ** log is occuring when no connection is active. | |
1681 | ** stat -- the message to print for the status. | |
1682 | ** e -- the current envelope. | |
fe033a8f EA |
1683 | ** |
1684 | ** Returns: | |
1685 | ** none | |
1686 | ** | |
1687 | ** Side Effects: | |
1688 | ** none | |
1689 | */ | |
1690 | ||
c0ae0b24 EA |
1691 | logdelivery(m, mci, stat, e) |
1692 | MAILER *m; | |
1693 | register MCI *mci; | |
fe033a8f | 1694 | char *stat; |
f2e44ded | 1695 | register ENVELOPE *e; |
fe033a8f | 1696 | { |
fc93dffb | 1697 | # ifdef LOG |
c0ae0b24 | 1698 | char *curhost; |
ef71c549 | 1699 | char buf[512]; |
fe033a8f | 1700 | |
4e82a943 | 1701 | (void) sprintf(buf, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); |
c0ae0b24 | 1702 | |
4e82a943 | 1703 | if (m != NULL) |
9b95d94a | 1704 | { |
4e82a943 EA |
1705 | (void) strcat(buf, ", mailer="); |
1706 | (void) strcat(buf, m->m_name); | |
9b95d94a | 1707 | } |
4e82a943 EA |
1708 | |
1709 | if (mci != NULL && mci->mci_host != NULL) | |
9b95d94a | 1710 | { |
9b95d94a | 1711 | # ifdef DAEMON |
3341995c | 1712 | extern SOCKADDR CurHostAddr; |
4e82a943 EA |
1713 | # endif |
1714 | ||
1715 | (void) strcat(buf, ", relay="); | |
1716 | (void) strcat(buf, mci->mci_host); | |
9b95d94a | 1717 | |
4e82a943 EA |
1718 | # ifdef DAEMON |
1719 | (void) strcat(buf, " ("); | |
3341995c | 1720 | (void) strcat(buf, anynet_ntoa(&CurHostAddr)); |
4e82a943 | 1721 | (void) strcat(buf, ")"); |
9b95d94a | 1722 | # endif |
9b95d94a | 1723 | } |
fc93dffb | 1724 | else |
4e82a943 EA |
1725 | { |
1726 | char *p = macvalue('h', e); | |
fc93dffb | 1727 | |
4e82a943 EA |
1728 | if (p != NULL && p[0] != '\0') |
1729 | { | |
1730 | (void) strcat(buf, ", relay="); | |
1731 | (void) strcat(buf, p); | |
1732 | } | |
1733 | } | |
ef71c549 EA |
1734 | |
1735 | syslog(LOG_INFO, "%s: to=%s, %s, stat=%s", | |
1736 | e->e_id, e->e_to, buf, stat); | |
f3d8f6d6 | 1737 | # endif /* LOG */ |
fe033a8f EA |
1738 | } |
1739 | \f/* | |
dd1fe05b | 1740 | ** PUTFROMLINE -- output a UNIX-style from line (or whatever) |
b3cbe40f | 1741 | ** |
3c567393 EA |
1742 | ** then passes the rest of the message through. If we have |
1743 | ** managed to extract a date already, use that; otherwise, | |
1744 | ** use the current date/time. | |
b3cbe40f | 1745 | ** |
a73ae8ac EA |
1746 | ** One of the ugliest hacks seen by human eyes is contained herein: |
1747 | ** UUCP wants those stupid "remote from <host>" lines. Why oh why | |
1748 | ** does a well-meaning programmer such as myself have to deal with | |
1749 | ** this kind of antique garbage???? | |
dd1fe05b | 1750 | ** |
b3cbe40f | 1751 | ** Parameters: |
dd1fe05b EA |
1752 | ** fp -- the file to output to. |
1753 | ** m -- the mailer describing this entry. | |
b3cbe40f EA |
1754 | ** |
1755 | ** Returns: | |
dd1fe05b | 1756 | ** none |
b3cbe40f EA |
1757 | ** |
1758 | ** Side Effects: | |
dd1fe05b | 1759 | ** outputs some text to fp. |
b3cbe40f EA |
1760 | */ |
1761 | ||
f2e44ded | 1762 | putfromline(fp, m, e) |
dd1fe05b EA |
1763 | register FILE *fp; |
1764 | register MAILER *m; | |
f2e44ded | 1765 | ENVELOPE *e; |
b3cbe40f | 1766 | { |
2bee003d | 1767 | char *template = "\201l\n"; |
dd1fe05b | 1768 | char buf[MAXLINE]; |
3c567393 | 1769 | extern char SentDate[]; |
b3cbe40f | 1770 | |
1dbda134 | 1771 | if (bitnset(M_NHDR, m->m_flags)) |
dd1fe05b | 1772 | return; |
74c5fe7c | 1773 | |
884a20cb | 1774 | # ifdef UGLYUUCP |
1dbda134 | 1775 | if (bitnset(M_UGLYUUCP, m->m_flags)) |
79bd7c07 | 1776 | { |
9aecbdbe EA |
1777 | char *bang; |
1778 | char xbuf[MAXLINE]; | |
79bd7c07 | 1779 | |
bc854e30 | 1780 | expand("\201g", buf, &buf[sizeof buf - 1], e); |
f3d8f6d6 | 1781 | bang = strchr(buf, '!'); |
dd1fe05b | 1782 | if (bang == NULL) |
b6edea3d | 1783 | syserr("554 No ! in UUCP! (%s)", buf); |
dd1fe05b | 1784 | else |
7338e3d4 | 1785 | { |
9aecbdbe | 1786 | *bang++ = '\0'; |
2bee003d | 1787 | (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); |
9aecbdbe | 1788 | template = xbuf; |
7338e3d4 | 1789 | } |
79bd7c07 | 1790 | } |
f3d8f6d6 | 1791 | # endif /* UGLYUUCP */ |
f2e44ded | 1792 | expand(template, buf, &buf[sizeof buf - 1], e); |
4db45bf1 | 1793 | putline(buf, fp, m); |
79bd7c07 EA |
1794 | } |
1795 | \f/* | |
6acfa498 | 1796 | ** PUTBODY -- put the body of a message. |
cbdb7357 EA |
1797 | ** |
1798 | ** Parameters: | |
6acfa498 EA |
1799 | ** fp -- file to output onto. |
1800 | ** m -- a mailer descriptor to control output format. | |
1801 | ** e -- the envelope to put out. | |
2f6a8a78 EA |
1802 | ** separator -- if non-NULL, a message separator that must |
1803 | ** not be permitted in the resulting message. | |
cbdb7357 EA |
1804 | ** |
1805 | ** Returns: | |
1806 | ** none. | |
1807 | ** | |
1808 | ** Side Effects: | |
6acfa498 | 1809 | ** The message is written onto fp. |
cbdb7357 EA |
1810 | */ |
1811 | ||
2f6a8a78 | 1812 | putbody(fp, m, e, separator) |
6acfa498 EA |
1813 | FILE *fp; |
1814 | MAILER *m; | |
1815 | register ENVELOPE *e; | |
2f6a8a78 | 1816 | char *separator; |
cbdb7357 | 1817 | { |
6acfa498 | 1818 | char buf[MAXLINE]; |
cbdb7357 | 1819 | |
3c7fe765 | 1820 | /* |
6acfa498 | 1821 | ** Output the body of the message |
3c7fe765 EA |
1822 | */ |
1823 | ||
6acfa498 | 1824 | if (e->e_dfp == NULL) |
7338e3d4 | 1825 | { |
6acfa498 | 1826 | if (e->e_df != NULL) |
78bbbc48 | 1827 | { |
6acfa498 EA |
1828 | e->e_dfp = fopen(e->e_df, "r"); |
1829 | if (e->e_dfp == NULL) | |
1830 | syserr("putbody: Cannot open %s for %s from %s", | |
1831 | e->e_df, e->e_to, e->e_from); | |
78bbbc48 | 1832 | } |
6acfa498 EA |
1833 | else |
1834 | putline("<<< No Message Collected >>>", fp, m); | |
84daea29 | 1835 | } |
6acfa498 | 1836 | if (e->e_dfp != NULL) |
84daea29 | 1837 | { |
6acfa498 EA |
1838 | rewind(e->e_dfp); |
1839 | while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) | |
84daea29 | 1840 | { |
6acfa498 EA |
1841 | if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && |
1842 | strncmp(buf, "From ", 5) == 0) | |
1843 | (void) putc('>', fp); | |
2f6a8a78 EA |
1844 | if (buf[0] == '-' && buf[1] == '-' && separator != NULL) |
1845 | { | |
1846 | /* possible separator */ | |
1847 | int sl = strlen(separator); | |
1848 | ||
1849 | if (strncmp(&buf[2], separator, sl) == 0) | |
1850 | (void) putc(' ', fp); | |
1851 | } | |
6acfa498 | 1852 | putline(buf, fp, m); |
84daea29 | 1853 | } |
84daea29 | 1854 | |
6acfa498 | 1855 | if (ferror(e->e_dfp)) |
bc854e30 | 1856 | { |
6acfa498 EA |
1857 | syserr("putbody: read error"); |
1858 | ExitStat = EX_IOERR; | |
bc854e30 | 1859 | } |
baa2b877 | 1860 | } |
75f95954 | 1861 | |
1537ac22 EA |
1862 | /* some mailers want extra blank line at end of message */ |
1863 | if (bitnset(M_BLANKEND, m->m_flags) && buf[0] != '\0' && buf[0] != '\n') | |
1864 | putline("", fp, m); | |
1865 | ||
6acfa498 EA |
1866 | (void) fflush(fp); |
1867 | if (ferror(fp) && errno != EPIPE) | |
84daea29 | 1868 | { |
6acfa498 EA |
1869 | syserr("putbody: write error"); |
1870 | ExitStat = EX_IOERR; | |
84daea29 | 1871 | } |
6acfa498 | 1872 | errno = 0; |
bc854e30 | 1873 | } |
6acfa498 EA |
1874 | \f/* |
1875 | ** MAILFILE -- Send a message to a file. | |
1876 | ** | |
1877 | ** If the file has the setuid/setgid bits set, but NO execute | |
1878 | ** bits, sendmail will try to become the owner of that file | |
1879 | ** rather than the real user. Obviously, this only works if | |
1880 | ** sendmail runs as root. | |
1881 | ** | |
1882 | ** This could be done as a subordinate mailer, except that it | |
1883 | ** is used implicitly to save messages in ~/dead.letter. We | |
1884 | ** view this as being sufficiently important as to include it | |
1885 | ** here. For example, if the system is dying, we shouldn't have | |
1886 | ** to create another process plus some pipes to save the message. | |
1887 | ** | |
1888 | ** Parameters: | |
1889 | ** filename -- the name of the file to send to. | |
1890 | ** ctladdr -- the controlling address header -- includes | |
1891 | ** the userid/groupid to be when sending. | |
1892 | ** | |
1893 | ** Returns: | |
1894 | ** The exit code associated with the operation. | |
1895 | ** | |
1896 | ** Side Effects: | |
1897 | ** none. | |
1898 | */ | |
bc854e30 | 1899 | |
6acfa498 EA |
1900 | mailfile(filename, ctladdr, e) |
1901 | char *filename; | |
1902 | ADDRESS *ctladdr; | |
bc854e30 | 1903 | register ENVELOPE *e; |
bc854e30 | 1904 | { |
6acfa498 EA |
1905 | register FILE *f; |
1906 | register int pid; | |
1907 | int mode; | |
84daea29 | 1908 | |
831d7357 EA |
1909 | if (tTd(11, 1)) |
1910 | { | |
1911 | printf("mailfile %s\n ctladdr=", filename); | |
1912 | printaddr(ctladdr, FALSE); | |
1913 | } | |
1914 | ||
6acfa498 EA |
1915 | /* |
1916 | ** Fork so we can change permissions here. | |
1917 | ** Note that we MUST use fork, not vfork, because of | |
1918 | ** the complications of calling subroutines, etc. | |
1919 | */ | |
1920 | ||
1921 | DOFORK(fork); | |
1922 | ||
1923 | if (pid < 0) | |
1924 | return (EX_OSERR); | |
1925 | else if (pid == 0) | |
75f95954 | 1926 | { |
6acfa498 EA |
1927 | /* child -- actually write to file */ |
1928 | struct stat stb; | |
75f95954 | 1929 | |
6acfa498 EA |
1930 | (void) signal(SIGINT, SIG_DFL); |
1931 | (void) signal(SIGHUP, SIG_DFL); | |
1932 | (void) signal(SIGTERM, SIG_DFL); | |
1933 | (void) umask(OldUmask); | |
75f95954 | 1934 | |
6acfa498 | 1935 | if (stat(filename, &stb) < 0) |
6f7f4e2c | 1936 | stb.st_mode = FileMode; |
6acfa498 | 1937 | mode = stb.st_mode; |
07800f98 | 1938 | |
6acfa498 EA |
1939 | /* limit the errors to those actually caused in the child */ |
1940 | errno = 0; | |
1941 | ExitStat = EX_OK; | |
07800f98 | 1942 | |
6acfa498 EA |
1943 | if (bitset(0111, stb.st_mode)) |
1944 | exit(EX_CANTCREAT); | |
1945 | if (ctladdr == NULL) | |
1946 | ctladdr = &e->e_from; | |
1947 | else | |
07800f98 | 1948 | { |
6acfa498 EA |
1949 | /* ignore setuid and setgid bits */ |
1950 | mode &= ~(S_ISGID|S_ISUID); | |
07800f98 | 1951 | } |
07800f98 | 1952 | |
6acfa498 EA |
1953 | /* we have to open the dfile BEFORE setuid */ |
1954 | if (e->e_dfp == NULL && e->e_df != NULL) | |
813d8709 | 1955 | { |
6acfa498 EA |
1956 | e->e_dfp = fopen(e->e_df, "r"); |
1957 | if (e->e_dfp == NULL) | |
78bbbc48 | 1958 | { |
6acfa498 EA |
1959 | syserr("mailfile: Cannot open %s for %s from %s", |
1960 | e->e_df, e->e_to, e->e_from); | |
78bbbc48 | 1961 | } |
6acfa498 | 1962 | } |
78bbbc48 | 1963 | |
6acfa498 EA |
1964 | if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) |
1965 | { | |
1966 | if (ctladdr->q_uid == 0) | |
78bbbc48 | 1967 | { |
6acfa498 EA |
1968 | (void) setgid(DefGid); |
1969 | (void) initgroups(DefUser, DefGid); | |
78bbbc48 | 1970 | } |
6acfa498 | 1971 | else |
78bbbc48 | 1972 | { |
6acfa498 EA |
1973 | (void) setgid(ctladdr->q_gid); |
1974 | (void) initgroups(ctladdr->q_ruser ? | |
1975 | ctladdr->q_ruser : ctladdr->q_user, | |
1976 | ctladdr->q_gid); | |
78bbbc48 | 1977 | } |
813d8709 | 1978 | } |
6acfa498 | 1979 | if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) |
4ae3ff58 | 1980 | { |
6acfa498 EA |
1981 | if (ctladdr->q_uid == 0) |
1982 | (void) setuid(DefUid); | |
1983 | else | |
1984 | (void) setuid(ctladdr->q_uid); | |
4ae3ff58 | 1985 | } |
6acfa498 EA |
1986 | FileName = filename; |
1987 | LineNumber = 0; | |
6f7f4e2c | 1988 | f = dfopen(filename, O_WRONLY|O_CREAT|O_APPEND, FileMode); |
6acfa498 | 1989 | if (f == NULL) |
cbdb7357 | 1990 | { |
6acfa498 EA |
1991 | message("554 cannot open"); |
1992 | exit(EX_CANTCREAT); | |
cbdb7357 | 1993 | } |
8dcff118 | 1994 | |
ff186114 EA |
1995 | putfromline(f, FileMailer, e); |
1996 | (*e->e_puthdr)(f, FileMailer, e); | |
1997 | putline("\n", f, FileMailer); | |
2f6a8a78 | 1998 | (*e->e_putbody)(f, FileMailer, e, NULL); |
ff186114 | 1999 | putline("\n", f, FileMailer); |
6acfa498 EA |
2000 | if (ferror(f)) |
2001 | { | |
2002 | message("451 I/O error"); | |
2003 | setstat(EX_IOERR); | |
8dcff118 | 2004 | } |
6acfa498 EA |
2005 | (void) xfclose(f, "mailfile", filename); |
2006 | (void) fflush(stdout); | |
3c7fe765 | 2007 | |
6acfa498 EA |
2008 | /* reset ISUID & ISGID bits for paranoid systems */ |
2009 | (void) chmod(filename, (int) stb.st_mode); | |
2010 | exit(ExitStat); | |
2011 | /*NOTREACHED*/ | |
bc854e30 | 2012 | } |
6acfa498 | 2013 | else |
3c7fe765 | 2014 | { |
6acfa498 EA |
2015 | /* parent -- wait for exit status */ |
2016 | int st; | |
bc854e30 | 2017 | |
6acfa498 EA |
2018 | st = waitfor(pid); |
2019 | if ((st & 0377) != 0) | |
2020 | return (EX_UNAVAILABLE); | |
2021 | else | |
2022 | return ((st >> 8) & 0377); | |
2023 | /*NOTREACHED*/ | |
3c7fe765 EA |
2024 | } |
2025 | } | |
7e70d3c8 EA |
2026 | \f/* |
2027 | ** HOSTSIGNATURE -- return the "signature" for a host. | |
2028 | ** | |
2029 | ** The signature describes how we are going to send this -- it | |
2030 | ** can be just the hostname (for non-Internet hosts) or can be | |
2031 | ** an ordered list of MX hosts. | |
2032 | ** | |
2033 | ** Parameters: | |
2034 | ** m -- the mailer describing this host. | |
2035 | ** host -- the host name. | |
2036 | ** e -- the current envelope. | |
2037 | ** | |
2038 | ** Returns: | |
2039 | ** The signature for this host. | |
2040 | ** | |
2041 | ** Side Effects: | |
2042 | ** Can tweak the symbol table. | |
2043 | */ | |
2044 | ||
2045 | char * | |
2046 | hostsignature(m, host, e) | |
2047 | register MAILER *m; | |
2048 | char *host; | |
2049 | ENVELOPE *e; | |
2050 | { | |
2051 | register char *p; | |
2052 | register STAB *s; | |
2053 | int i; | |
2054 | int len; | |
2055 | #ifdef NAMED_BIND | |
2056 | int nmx; | |
2057 | auto int rcode; | |
db113c28 EA |
2058 | char *hp; |
2059 | char *endp; | |
c8f4bc0b | 2060 | int oldoptions; |
7e70d3c8 | 2061 | char *mxhosts[MAXMXHOSTS + 1]; |
7e70d3c8 EA |
2062 | #endif |
2063 | ||
2064 | /* | |
2065 | ** Check to see if this uses IPC -- if not, it can't have MX records. | |
2066 | */ | |
2067 | ||
2068 | p = m->m_mailer; | |
2069 | if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) | |
2070 | { | |
2071 | /* just an ordinary mailer */ | |
2072 | return host; | |
2073 | } | |
2074 | ||
2075 | /* | |
2076 | ** If it is a numeric address, just return it. | |
2077 | */ | |
2078 | ||
2079 | if (host[0] == '[') | |
2080 | return host; | |
2081 | ||
2082 | /* | |
2083 | ** Look it up in the symbol table. | |
2084 | */ | |
2085 | ||
2086 | s = stab(host, ST_HOSTSIG, ST_ENTER); | |
2087 | if (s->s_hostsig != NULL) | |
2088 | return s->s_hostsig; | |
2089 | ||
2090 | /* | |
2091 | ** Not already there -- create a signature. | |
2092 | */ | |
2093 | ||
2094 | #ifdef NAMED_BIND | |
c8f4bc0b EA |
2095 | if (ConfigLevel < 2) |
2096 | { | |
2097 | oldoptions = _res.options; | |
2098 | _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ | |
2099 | } | |
2100 | ||
db113c28 | 2101 | for (hp = host; hp != NULL; hp = endp) |
7e70d3c8 | 2102 | { |
db113c28 EA |
2103 | endp = strchr(hp, ':'); |
2104 | if (endp != NULL) | |
2105 | *endp = '\0'; | |
7e70d3c8 | 2106 | |
c3577cd6 | 2107 | nmx = getmxrr(hp, mxhosts, TRUE, &rcode); |
7e70d3c8 | 2108 | |
db113c28 EA |
2109 | if (nmx <= 0) |
2110 | { | |
2111 | register MCI *mci; | |
2112 | extern int errno; | |
7e70d3c8 | 2113 | |
db113c28 EA |
2114 | /* update the connection info for this host */ |
2115 | mci = mci_get(hp, m); | |
2116 | mci->mci_exitstat = rcode; | |
2117 | mci->mci_errno = errno; | |
2118 | ||
2119 | /* and return the original host name as the signature */ | |
2120 | nmx = 1; | |
2121 | mxhosts[0] = hp; | |
2122 | } | |
2123 | ||
2124 | len = 0; | |
2125 | for (i = 0; i < nmx; i++) | |
2126 | { | |
2127 | len += strlen(mxhosts[i]) + 1; | |
2128 | } | |
2129 | if (s->s_hostsig != NULL) | |
2130 | len += strlen(s->s_hostsig) + 1; | |
2131 | p = xalloc(len); | |
2132 | if (s->s_hostsig != NULL) | |
2133 | { | |
2134 | (void) strcpy(p, s->s_hostsig); | |
2135 | free(s->s_hostsig); | |
2136 | s->s_hostsig = p; | |
2137 | p += strlen(p); | |
7e70d3c8 | 2138 | *p++ = ':'; |
db113c28 EA |
2139 | } |
2140 | else | |
2141 | s->s_hostsig = p; | |
2142 | for (i = 0; i < nmx; i++) | |
2143 | { | |
2144 | if (i != 0) | |
2145 | *p++ = ':'; | |
2146 | strcpy(p, mxhosts[i]); | |
2147 | p += strlen(p); | |
2148 | } | |
2149 | if (endp != NULL) | |
2150 | *endp++ = ':'; | |
7e70d3c8 EA |
2151 | } |
2152 | makelower(s->s_hostsig); | |
c8f4bc0b EA |
2153 | if (ConfigLevel < 2) |
2154 | _res.options = oldoptions; | |
7e70d3c8 EA |
2155 | #else |
2156 | /* not using BIND -- the signature is just the host name */ | |
2157 | s->s_hostsig = host; | |
2158 | #endif | |
2159 | if (tTd(17, 1)) | |
2160 | printf("hostsignature(%s) = %s\n", host, s->s_hostsig); | |
2161 | return s->s_hostsig; | |
2162 | } |