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