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