1 /*
2 * Copyright (c) 1998-2003, 2006, 2012, 2013 Proofpoint, Inc. and its suppliers.
3 * All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14 #include <sendmail.h>
15
16 SM_RCSID("@(#)$Id: savemail.c,v 8.319 2013-11-22 20:51:56 ca Exp $")
17
18 #include <sm/sendmail.h>
19
20 static bool errbody __P((MCI *, ENVELOPE *, char *));
21 static bool pruneroute __P((char *));
22
23 /*
24 ** SAVEMAIL -- Save mail on error
25 **
26 ** If mailing back errors, mail it back to the originator
27 ** together with an error message; otherwise, just put it in
28 ** dead.letter in the user's home directory (if he exists on
29 ** this machine).
30 **
31 ** Parameters:
32 ** e -- the envelope containing the message in error.
33 ** sendbody -- if true, also send back the body of the
34 ** message; otherwise just send the header.
35 **
36 ** Returns:
37 ** true if savemail panic'ed, (i.e., the data file should
38 ** be preserved by dropenvelope())
39 **
40 ** Side Effects:
41 ** Saves the letter, by writing or mailing it back to the
42 ** sender, or by putting it in dead.letter in her home
43 ** directory.
44 */
45
46 /* defines for state machine */
47 #define ESM_REPORT 0 /* report to sender's terminal */
48 #define ESM_MAIL 1 /* mail back to sender */
49 #define ESM_QUIET 2 /* mail has already been returned */
50 #define ESM_DEADLETTER 3 /* save in ~/dead.letter */
51 #define ESM_POSTMASTER 4 /* return to postmaster */
52 #define ESM_DEADLETTERDROP 5 /* save in DeadLetterDrop */
53 #define ESM_PANIC 6 /* call loseqfile() */
54 #define ESM_DONE 7 /* message is successfully delivered */
55
56 bool
savemail(e,sendbody)57 savemail(e, sendbody)
58 register ENVELOPE *e;
59 bool sendbody;
60 {
61 register SM_FILE_T *fp;
62 bool panic = false;
63 int state;
64 auto ADDRESS *q = NULL;
65 register char *p;
66 MCI mcibuf;
67 int flags;
68 long sff;
69 char buf[MAXLINE + 1];
70 char dlbuf[MAXPATHLEN];
71 SM_MBDB_T user;
72
73
74 if (tTd(6, 1))
75 {
76 sm_dprintf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n e_from=",
77 e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id,
78 ExitStat);
79 printaddr(sm_debug_file(), &e->e_from, false);
80 }
81
82 if (e->e_id == NULL)
83 {
84 /* can't return a message with no id */
85 return panic;
86 }
87
88 /*
89 ** In the unhappy event we don't know who to return the mail
90 ** to, make someone up.
91 */
92
93 if (e->e_from.q_paddr == NULL)
94 {
95 e->e_sender = "Postmaster";
96 if (parseaddr(e->e_sender, &e->e_from,
97 RF_COPYPARSE|RF_SENDERADDR,
98 '\0', NULL, e, false) == NULL)
99 {
100 syserr("553 5.3.5 Cannot parse Postmaster!");
101 finis(true, true, EX_SOFTWARE);
102 }
103 }
104 e->e_to = NULL;
105
106 /*
107 ** Basic state machine.
108 **
109 ** This machine runs through the following states:
110 **
111 ** ESM_QUIET Errors have already been printed iff the
112 ** sender is local.
113 ** ESM_REPORT Report directly to the sender's terminal.
114 ** ESM_MAIL Mail response to the sender.
115 ** ESM_DEADLETTER Save response in ~/dead.letter.
116 ** ESM_POSTMASTER Mail response to the postmaster.
117 ** ESM_DEADLETTERDROP
118 ** If DeadLetterDrop set, save it there.
119 ** ESM_PANIC Save response anywhere possible.
120 */
121
122 /* determine starting state */
123 switch (e->e_errormode)
124 {
125 case EM_WRITE:
126 state = ESM_REPORT;
127 break;
128
129 case EM_BERKNET:
130 case EM_MAIL:
131 state = ESM_MAIL;
132 break;
133
134 case EM_PRINT:
135 case '\0':
136 state = ESM_QUIET;
137 break;
138
139 case EM_QUIET:
140 /* no need to return anything at all */
141 return panic;
142
143 default:
144 syserr("554 5.3.0 savemail: bogus errormode x%x",
145 e->e_errormode);
146 state = ESM_MAIL;
147 break;
148 }
149
150 /* if this is already an error response, send to postmaster */
151 if (bitset(EF_RESPONSE, e->e_flags))
152 {
153 if (e->e_parent != NULL &&
154 bitset(EF_RESPONSE, e->e_parent->e_flags))
155 {
156 /* got an error sending a response -- can it */
157 return panic;
158 }
159 state = ESM_POSTMASTER;
160 }
161
162 while (state != ESM_DONE)
163 {
164 if (tTd(6, 5))
165 sm_dprintf(" state %d\n", state);
166
167 switch (state)
168 {
169 case ESM_QUIET:
170 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags))
171 state = ESM_DEADLETTER;
172 else
173 state = ESM_MAIL;
174 break;
175
176 case ESM_REPORT:
177
178 /*
179 ** If the user is still logged in on the same terminal,
180 ** then write the error messages back to hir (sic).
181 */
182
183 #if USE_TTYPATH
184 p = ttypath();
185 #else
186 p = NULL;
187 #endif
188
189 if (p == NULL || sm_io_reopen(SmFtStdio,
190 SM_TIME_DEFAULT,
191 p, SM_IO_WRONLY, NULL,
192 smioout) == NULL)
193 {
194 state = ESM_MAIL;
195 break;
196 }
197
198 expand("\201n", buf, sizeof(buf), e);
199 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
200 "\r\nMessage from %s...\r\n", buf);
201 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
202 "Errors occurred while sending mail.\r\n");
203 if (e->e_xfp != NULL)
204 {
205 (void) bfrewind(e->e_xfp);
206 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
207 "Transcript follows:\r\n");
208 while (sm_io_fgets(e->e_xfp, SM_TIME_DEFAULT,
209 buf, sizeof(buf)) >= 0 &&
210 !sm_io_error(smioout))
211 (void) sm_io_fputs(smioout,
212 SM_TIME_DEFAULT,
213 buf);
214 }
215 else
216 {
217 syserr("Cannot open %s",
218 queuename(e, XSCRPT_LETTER));
219 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
220 "Transcript of session is unavailable.\r\n");
221 }
222 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
223 "Original message will be saved in dead.letter.\r\n");
224 state = ESM_DEADLETTER;
225 break;
226
227 case ESM_MAIL:
228 /*
229 ** If mailing back, do it.
230 ** Throw away all further output. Don't alias,
231 ** since this could cause loops, e.g., if joe
232 ** mails to joe@x, and for some reason the network
233 ** for @x is down, then the response gets sent to
234 ** joe@x, which gives a response, etc. Also force
235 ** the mail to be delivered even if a version of
236 ** it has already been sent to the sender.
237 **
238 ** If this is a configuration or local software
239 ** error, send to the local postmaster as well,
240 ** since the originator can't do anything
241 ** about it anyway. Note that this is a full
242 ** copy of the message (intentionally) so that
243 ** the Postmaster can forward things along.
244 */
245
246 if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE)
247 {
248 (void) sendtolist("postmaster", NULLADDR,
249 &e->e_errorqueue, 0, e);
250 }
251 if (!emptyaddr(&e->e_from))
252 {
253 char from[TOBUFSIZE];
254
255 if (sm_strlcpy(from, e->e_from.q_paddr,
256 sizeof(from)) >= sizeof(from))
257 {
258 state = ESM_POSTMASTER;
259 break;
260 }
261
262 if (!DontPruneRoutes)
263 (void) pruneroute(from);
264
265 (void) sendtolist(from, NULLADDR,
266 &e->e_errorqueue, 0, e);
267 }
268
269 /*
270 ** Deliver a non-delivery report to the
271 ** Postmaster-designate (not necessarily
272 ** Postmaster). This does not include the
273 ** body of the message, for privacy reasons.
274 ** You really shouldn't need this.
275 */
276
277 e->e_flags |= EF_PM_NOTIFY;
278
279 /* check to see if there are any good addresses */
280 for (q = e->e_errorqueue; q != NULL; q = q->q_next)
281 {
282 if (QS_IS_SENDABLE(q->q_state))
283 break;
284 }
285 if (q == NULL)
286 {
287 /* this is an error-error */
288 state = ESM_POSTMASTER;
289 break;
290 }
291 if (returntosender(e->e_message, e->e_errorqueue,
292 sendbody ? RTSF_SEND_BODY
293 : RTSF_NO_BODY,
294 e) == 0)
295 {
296 state = ESM_DONE;
297 break;
298 }
299
300 /* didn't work -- return to postmaster */
301 state = ESM_POSTMASTER;
302 break;
303
304 case ESM_POSTMASTER:
305 /*
306 ** Similar to previous case, but to system postmaster.
307 */
308
309 q = NULL;
310 expand(DoubleBounceAddr, buf, sizeof(buf), e);
311
312 /*
313 ** Just drop it on the floor if DoubleBounceAddr
314 ** expands to an empty string.
315 */
316
317 if (*buf == '\0')
318 {
319 state = ESM_DONE;
320 break;
321 }
322 if (sendtolist(buf, NULLADDR, &q, 0, e) <= 0)
323 {
324 syserr("553 5.3.0 cannot parse %s!", buf);
325 ExitStat = EX_SOFTWARE;
326 state = ESM_DEADLETTERDROP;
327 break;
328 }
329 flags = RTSF_PM_BOUNCE;
330 if (sendbody)
331 flags |= RTSF_SEND_BODY;
332 if (returntosender(e->e_message, q, flags, e) == 0)
333 {
334 state = ESM_DONE;
335 break;
336 }
337
338 /* didn't work -- last resort */
339 state = ESM_DEADLETTERDROP;
340 break;
341
342 case ESM_DEADLETTER:
343 /*
344 ** Save the message in dead.letter.
345 ** If we weren't mailing back, and the user is
346 ** local, we should save the message in
347 ** ~/dead.letter so that the poor person doesn't
348 ** have to type it over again -- and we all know
349 ** what poor typists UNIX users are.
350 */
351
352 p = NULL;
353 if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
354 {
355 if (e->e_from.q_home != NULL)
356 p = e->e_from.q_home;
357 else if (sm_mbdb_lookup(e->e_from.q_user, &user)
358 == EX_OK &&
359 *user.mbdb_homedir != '\0')
360 p = user.mbdb_homedir;
361 }
362 if (p == NULL || e->e_dfp == NULL)
363 {
364 /* no local directory or no data file */
365 state = ESM_MAIL;
366 break;
367 }
368
369 /* we have a home directory; write dead.letter */
370 macdefine(&e->e_macro, A_TEMP, 'z', p);
371
372 /* get the sender for the UnixFromLine */
373 p = macvalue('g', e);
374 macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
375
376 expand("\201z/dead.letter", dlbuf, sizeof(dlbuf), e);
377 sff = SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID;
378 if (RealUid == 0)
379 sff |= SFF_ROOTOK;
380 e->e_to = dlbuf;
381 if (writable(dlbuf, NULL, sff) &&
382 mailfile(dlbuf, FileMailer, NULL, sff, e) == EX_OK)
383 {
384 int oldverb = Verbose;
385
386 if (OpMode != MD_DAEMON && OpMode != MD_SMTP)
387 Verbose = 1;
388 if (Verbose > 0)
389 message("Saved message in %s", dlbuf);
390 Verbose = oldverb;
391 macdefine(&e->e_macro, A_PERM, 'g', p);
392 state = ESM_DONE;
393 break;
394 }
395 macdefine(&e->e_macro, A_PERM, 'g', p);
396 state = ESM_MAIL;
397 break;
398
399 case ESM_DEADLETTERDROP:
400 /*
401 ** Log the mail in DeadLetterDrop file.
402 */
403
404 if (e->e_class < 0)
405 {
406 state = ESM_DONE;
407 break;
408 }
409
410 if ((SafeFileEnv != NULL && SafeFileEnv[0] != '\0') ||
411 DeadLetterDrop == NULL ||
412 DeadLetterDrop[0] == '\0')
413 {
414 state = ESM_PANIC;
415 break;
416 }
417
418 sff = SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT|SFF_MUSTOWN;
419 if (!writable(DeadLetterDrop, NULL, sff) ||
420 (fp = safefopen(DeadLetterDrop, O_WRONLY|O_APPEND,
421 FileMode, sff)) == NULL)
422 {
423 state = ESM_PANIC;
424 break;
425 }
426
427 memset(&mcibuf, '\0', sizeof(mcibuf));
428 mcibuf.mci_out = fp;
429 mcibuf.mci_mailer = FileMailer;
430 if (bitnset(M_7BITS, FileMailer->m_flags))
431 mcibuf.mci_flags |= MCIF_7BIT;
432
433 /* get the sender for the UnixFromLine */
434 p = macvalue('g', e);
435 macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
436
437 if (!putfromline(&mcibuf, e) ||
438 !(*e->e_puthdr)(&mcibuf, e->e_header, e,
439 M87F_OUTER) ||
440 !(*e->e_putbody)(&mcibuf, e, NULL) ||
441 !putline("\n", &mcibuf) ||
442 sm_io_flush(fp, SM_TIME_DEFAULT) == SM_IO_EOF ||
443 sm_io_error(fp) ||
444 sm_io_close(fp, SM_TIME_DEFAULT) < 0)
445 state = ESM_PANIC;
446 else
447 {
448 int oldverb = Verbose;
449
450 if (OpMode != MD_DAEMON && OpMode != MD_SMTP)
451 Verbose = 1;
452 if (Verbose > 0)
453 message("Saved message in %s",
454 DeadLetterDrop);
455 Verbose = oldverb;
456 if (LogLevel > 3)
457 sm_syslog(LOG_NOTICE, e->e_id,
458 "Saved message in %s",
459 DeadLetterDrop);
460 state = ESM_DONE;
461 }
462 macdefine(&e->e_macro, A_PERM, 'g', p);
463 break;
464
465 default:
466 syserr("554 5.3.5 savemail: unknown state %d", state);
467 /* FALLTHROUGH */
468
469 case ESM_PANIC:
470 /* leave the locked queue & transcript files around */
471 loseqfile(e, "savemail panic");
472 panic = true;
473 errno = 0;
474 syserr("554 savemail: cannot save rejected email anywhere");
475 state = ESM_DONE;
476 break;
477 }
478 }
479 return panic;
480 }
481 /*
482 ** RETURNTOSENDER -- return a message to the sender with an error.
483 **
484 ** Parameters:
485 ** msg -- the explanatory message.
486 ** returnq -- the queue of people to send the message to.
487 ** flags -- flags tweaking the operation:
488 ** RTSF_SENDBODY -- include body of message (otherwise
489 ** just send the header).
490 ** RTSF_PMBOUNCE -- this is a postmaster bounce.
491 ** e -- the current envelope.
492 **
493 ** Returns:
494 ** zero -- if everything went ok.
495 ** else -- some error.
496 **
497 ** Side Effects:
498 ** Returns the current message to the sender via mail.
499 */
500
501 #define MAXRETURNS 6 /* max depth of returning messages */
502 #define ERRORFUDGE 1024 /* nominal size of error message text */
503
504 int
returntosender(msg,returnq,flags,e)505 returntosender(msg, returnq, flags, e)
506 char *msg;
507 ADDRESS *returnq;
508 int flags;
509 register ENVELOPE *e;
510 {
511 int ret;
512 register ENVELOPE *ee;
513 ENVELOPE *oldcur = CurEnv;
514 ENVELOPE errenvelope;
515 static int returndepth = 0;
516 register ADDRESS *q;
517 char *p;
518 char buf[MAXNAME + 1]; /* EAI:ok */
519
520 if (returnq == NULL)
521 return -1;
522
523 if (msg == NULL)
524 msg = "Unable to deliver mail";
525
526 if (tTd(6, 1))
527 {
528 sm_dprintf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%p, returnq=",
529 msg, returndepth, (void *)e);
530 printaddr(sm_debug_file(), returnq, true);
531 if (tTd(6, 20))
532 {
533 sm_dprintf("Sendq=");
534 printaddr(sm_debug_file(), e->e_sendqueue, true);
535 }
536 }
537
538 if (++returndepth >= MAXRETURNS)
539 {
540 if (returndepth != MAXRETURNS)
541 syserr("554 5.3.0 returntosender: infinite recursion on %s",
542 returnq->q_paddr);
543 /* don't "unrecurse" and fake a clean exit */
544 /* returndepth--; */
545 return 0;
546 }
547
548 macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
549 macdefine(&e->e_macro, A_PERM, 'u', NULL);
550
551 /* initialize error envelope */
552 ee = newenvelope(&errenvelope, e, sm_rpool_new_x(NULL));
553 macdefine(&ee->e_macro, A_PERM, 'a', "\201b");
554 macdefine(&ee->e_macro, A_PERM, 'r', "");
555 macdefine(&ee->e_macro, A_PERM, 's', "localhost");
556 macdefine(&ee->e_macro, A_PERM, '_', "localhost");
557 clrsessenvelope(ee);
558
559 ee->e_puthdr = putheader;
560 ee->e_putbody = errbody;
561 ee->e_flags |= EF_RESPONSE|EF_METOO;
562 if (!bitset(EF_OLDSTYLE, e->e_flags))
563 ee->e_flags &= ~EF_OLDSTYLE;
564 if (bitset(EF_DONT_MIME, e->e_flags))
565 {
566 ee->e_flags |= EF_DONT_MIME;
567
568 /*
569 ** If we can't convert to MIME and we don't pass
570 ** 8-bit, we can't send the body.
571 */
572
573 if (bitset(EF_HAS8BIT, e->e_flags) &&
574 !bitset(MM_PASS8BIT, MimeMode))
575 flags &= ~RTSF_SEND_BODY;
576 }
577
578 ee->e_sendqueue = returnq;
579 ee->e_msgsize = 0;
580 if (bitset(RTSF_SEND_BODY, flags) &&
581 !bitset(PRIV_NOBODYRETN, PrivacyFlags))
582 ee->e_msgsize = ERRORFUDGE + e->e_msgsize;
583 else
584 ee->e_flags |= EF_NO_BODY_RETN;
585
586 #if _FFR_BOUNCE_QUEUE
587 if (BounceQueue != NOQGRP)
588 ee->e_qgrp = ee->e_dfqgrp = BounceQueue;
589 #endif
590 if (!setnewqueue(ee))
591 {
592 syserr("554 5.3.0 returntosender: cannot select queue for %s",
593 returnq->q_paddr);
594 ExitStat = EX_UNAVAILABLE;
595 returndepth--;
596 return -1;
597 }
598 initsys(ee);
599
600 #if NAMED_BIND
601 _res.retry = TimeOuts.res_retry[RES_TO_FIRST];
602 _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
603 #endif
604 for (q = returnq; q != NULL; q = q->q_next)
605 {
606 if (QS_IS_BADADDR(q->q_state))
607 continue;
608
609 q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
610 q->q_flags |= QPINGONFAILURE;
611
612 if (!QS_IS_DEAD(q->q_state))
613 ee->e_nrcpts++;
614
615 if (q->q_alias == NULL)
616 addheader("To", q->q_paddr, 0, ee, true);
617 }
618
619 if (LogLevel > 5)
620 {
621 if (bitset(EF_RESPONSE, e->e_flags))
622 p = "return to sender";
623 else if (bitset(EF_WARNING, e->e_flags))
624 p = "sender notify";
625 else if (bitset(RTSF_PM_BOUNCE, flags))
626 p = "postmaster notify";
627 else
628 p = "DSN";
629 sm_syslog(LOG_INFO, e->e_id, "%s: %s: %s",
630 ee->e_id, p, shortenstring(msg, MAXSHORTSTR));
631 }
632
633 if (SendMIMEErrors)
634 {
635 addheader("MIME-Version", "1.0", 0, ee, true);
636 (void) sm_snprintf(buf, sizeof(buf), "%s.%ld/%.100s",
637 ee->e_id, (long)curtime(), MyHostName);
638 ee->e_msgboundary = sm_rpool_strdup_x(ee->e_rpool, buf);
639 (void) sm_snprintf(buf, sizeof(buf),
640 #if DSN
641 "multipart/report; report-type=delivery-status;\n\tboundary=\"%s\"",
642 #else
643 "multipart/mixed; boundary=\"%s\"",
644 #endif
645 ee->e_msgboundary);
646 addheader("Content-Type", buf, 0, ee, true);
647
648 p = hvalue("Content-Transfer-Encoding", e->e_header);
649 if (p != NULL && sm_strcasecmp(p, "binary") != 0)
650 p = NULL;
651 if (p == NULL && bitset(EF_HAS8BIT, e->e_flags))
652 p = "8bit";
653 if (p != NULL)
654 addheader("Content-Transfer-Encoding", p, 0, ee, true);
655 }
656 if (strncmp(msg, "Warning:", 8) == 0)
657 {
658 addheader("Subject", msg, 0, ee, true);
659 p = "warning-timeout";
660 }
661 else if (strncmp(msg, "Postmaster warning:", 19) == 0)
662 {
663 addheader("Subject", msg, 0, ee, true);
664 p = "postmaster-warning";
665 }
666 else if (strcmp(msg, "Return receipt") == 0)
667 {
668 addheader("Subject", msg, 0, ee, true);
669 p = "return-receipt";
670 }
671 else if (bitset(RTSF_PM_BOUNCE, flags))
672 {
673 (void) sm_snprintf(buf, sizeof(buf),
674 "Postmaster notify: see transcript for details");
675 addheader("Subject", buf, 0, ee, true);
676 p = "postmaster-notification";
677 }
678 else
679 {
680 (void) sm_snprintf(buf, sizeof(buf),
681 "Returned mail: see transcript for details");
682 addheader("Subject", buf, 0, ee, true);
683 p = "failure";
684 }
685 (void) sm_snprintf(buf, sizeof(buf), "auto-generated (%s)", p);
686 addheader("Auto-Submitted", buf, 0, ee, true);
687
688 /* fake up an address header for the from person */
689 expand("\201n", buf, sizeof(buf), e);
690 /* XXX buf must be [i] */
691 if (parseaddr(buf, &ee->e_from,
692 RF_COPYALL|RF_SENDERADDR, '\0', NULL, e, false) == NULL)
693 {
694 syserr("553 5.3.5 Can't parse myself!");
695 ExitStat = EX_SOFTWARE;
696 returndepth--;
697 return -1;
698 }
699 ee->e_from.q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
700 ee->e_from.q_flags |= QPINGONFAILURE;
701 ee->e_sender = ee->e_from.q_paddr;
702
703 #if USE_EAI
704 /* always? when is this really needed? */
705 if (e->e_smtputf8)
706 ee->e_smtputf8 = true;
707 #endif
708
709 /* push state into submessage */
710 CurEnv = ee;
711 macdefine(&ee->e_macro, A_PERM, 'f', "\201n");
712 macdefine(&ee->e_macro, A_PERM, 'x', "Mail Delivery Subsystem");
713 eatheader(ee, true, true);
714
715 /* mark statistics */
716 markstats(ee, NULLADDR, STATS_NORMAL);
717
718 #if _FFR_BOUNCE_QUEUE
719 if (BounceQueue == NOQGRP)
720 {
721 #endif
722 /* actually deliver the error message */
723 sendall(ee, SM_DELIVER);
724 #if _FFR_BOUNCE_QUEUE
725 }
726 #endif
727 (void) dropenvelope(ee, true, false);
728
729 /* check for delivery errors */
730 ret = -1;
731 if (ee->e_parent == NULL ||
732 !bitset(EF_RESPONSE, ee->e_parent->e_flags))
733 {
734 ret = 0;
735 }
736 else
737 {
738 for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
739 {
740 if (QS_IS_ATTEMPTED(q->q_state))
741 {
742 ret = 0;
743 break;
744 }
745 }
746 }
747
748 /* restore state */
749 sm_rpool_free(ee->e_rpool);
750 CurEnv = oldcur;
751 returndepth--;
752
753 return ret;
754 }
755
756
757 /*
758 ** DSNTYPENAME -- Returns the DSN name of the addrtype for this address
759 **
760 ** Sendmail's addrtypes are largely in different universes, and
761 ** 'fred' may be a valid address in different addrtype
762 ** universes.
763 **
764 ** EAI extends the rfc822 universe rather than introduce a new
765 ** universe. Because of that, sendmail uses the rfc822 addrtype,
766 ** but names it utf-8 when the EAI DSN extension requires that.
767 **
768 ** Parameters:
769 ** addrtype -- address type
770 ** addr -- the address
771 **
772 ** Returns:
773 ** type for DSN
774 **
775 */
776
777 static const char *dsntypename __P((const char *, const char *));
778
779 static const char *
dsntypename(addrtype,addr)780 dsntypename(addrtype, addr)
781 const char *addrtype;
782 const char *addr;
783 {
784 if (sm_strcasecmp(addrtype, "rfc822") != 0)
785 return addrtype;
786 #if USE_EAI
787 if (!addr_is_ascii(addr))
788 return "utf-8";
789 #endif
790 return "rfc822";
791 }
792
793
794 /*
795 ** ERRBODY -- output the body of an error message.
796 **
797 ** Typically this is a copy of the transcript plus a copy of the
798 ** original offending message.
799 **
800 ** Parameters:
801 ** mci -- the mailer connection information.
802 ** e -- the envelope we are working in.
803 ** separator -- any possible MIME separator (unused).
804 **
805 ** Returns:
806 ** true iff body was written successfully
807 **
808 ** Side Effects:
809 ** Outputs the body of an error message.
810 */
811
812 /* ARGSUSED2 */
813 static bool
errbody(mci,e,separator)814 errbody(mci, e, separator)
815 register MCI *mci;
816 register ENVELOPE *e;
817 char *separator;
818 {
819 bool printheader;
820 bool sendbody;
821 bool pm_notify;
822 int save_errno;
823 register SM_FILE_T *xfile;
824 char *p;
825 register ADDRESS *q = NULL;
826 char actual[MAXLINE];
827 char buf[MAXLINE];
828
829 if (bitset(MCIF_INHEADER, mci->mci_flags))
830 {
831 if (!putline("", mci))
832 goto writeerr;
833 mci->mci_flags &= ~MCIF_INHEADER;
834 }
835 if (e->e_parent == NULL)
836 {
837 syserr("errbody: null parent");
838 if (!putline(" ----- Original message lost -----\n", mci))
839 goto writeerr;
840 return true;
841 }
842
843 /*
844 ** Output MIME header.
845 */
846
847 if (e->e_msgboundary != NULL)
848 {
849 (void) sm_strlcpyn(buf, sizeof(buf), 2, "--", e->e_msgboundary);
850 if (!putline("This is a MIME-encapsulated message", mci) ||
851 !putline("", mci) ||
852 !putline(buf, mci) ||
853 !putline("", mci))
854 goto writeerr;
855 }
856
857 /*
858 ** Output introductory information.
859 */
860
861 pm_notify = false;
862 p = hvalue("subject", e->e_header);
863 if (p != NULL && strncmp(p, "Postmaster ", 11) == 0)
864 pm_notify = true;
865 else
866 {
867 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
868 {
869 if (QS_IS_BADADDR(q->q_state))
870 break;
871 }
872 }
873 if (!pm_notify && q == NULL &&
874 !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags))
875 {
876 if (!putline(" **********************************************",
877 mci) ||
878 !putline(" ** THIS IS A WARNING MESSAGE ONLY **",
879 mci) ||
880 !putline(" ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **",
881 mci) ||
882 !putline(" **********************************************",
883 mci) ||
884 !putline("", mci))
885 goto writeerr;
886 }
887 (void) sm_snprintf(buf, sizeof(buf),
888 "The original message was received at %s",
889 arpadate(ctime(&e->e_parent->e_ctime)));
890 if (!putline(buf, mci))
891 goto writeerr;
892 expand("from \201_", buf, sizeof(buf), e->e_parent);
893 if (!putline(buf, mci))
894 goto writeerr;
895
896 /* include id in postmaster copies */
897 if (pm_notify && e->e_parent->e_id != NULL)
898 {
899 (void) sm_strlcpyn(buf, sizeof(buf), 2, "with id ",
900 e->e_parent->e_id);
901 if (!putline(buf, mci))
902 goto writeerr;
903 }
904 if (!putline("", mci))
905 goto writeerr;
906
907 /*
908 ** Output error message header (if specified and available).
909 */
910
911 if (ErrMsgFile != NULL &&
912 !bitset(EF_SENDRECEIPT, e->e_parent->e_flags))
913 {
914 if (*ErrMsgFile == '/')
915 {
916 long sff = SFF_ROOTOK|SFF_REGONLY;
917
918 if (DontLockReadFiles)
919 sff |= SFF_NOLOCK;
920 if (!bitnset(DBS_ERRORHEADERINUNSAFEDIRPATH,
921 DontBlameSendmail))
922 sff |= SFF_SAFEDIRPATH;
923 xfile = safefopen(ErrMsgFile, O_RDONLY, 0444, sff);
924 if (xfile != NULL)
925 {
926 while (sm_io_fgets(xfile, SM_TIME_DEFAULT, buf,
927 sizeof(buf)) >= 0)
928 {
929 int lbs;
930 bool putok;
931 char *lbp;
932
933 lbs = sizeof(buf);
934 lbp = translate_dollars(buf, buf, &lbs);
935 expand(lbp, lbp, lbs, e);
936 putok = putline(lbp, mci);
937 if (lbp != buf)
938 sm_free(lbp);
939 if (!putok)
940 goto writeerr;
941 }
942 (void) sm_io_close(xfile, SM_TIME_DEFAULT);
943 if (!putline("\n", mci))
944 goto writeerr;
945 }
946 }
947 else
948 {
949 expand(ErrMsgFile, buf, sizeof(buf), e);
950 if (!putline(buf, mci) || !putline("", mci))
951 goto writeerr;
952 }
953 }
954
955 /*
956 ** Output message introduction
957 */
958
959 /* permanent fatal errors */
960 printheader = true;
961 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
962 {
963 if (!QS_IS_BADADDR(q->q_state) ||
964 !bitset(QPINGONFAILURE, q->q_flags))
965 continue;
966
967 if (printheader)
968 {
969 if (!putline(" ----- The following addresses had permanent fatal errors -----",
970 mci))
971 goto writeerr;
972 printheader = false;
973 }
974
975 (void) sm_strlcpy(buf, shortenstring(q->q_paddr, MAXSHORTSTR),
976 sizeof(buf));
977 if (!putline(buf, mci))
978 goto writeerr;
979 if (q->q_rstatus != NULL)
980 {
981 (void) sm_snprintf(buf, sizeof(buf),
982 " (reason: %s)",
983 shortenstring(exitstat(q->q_rstatus),
984 MAXSHORTSTR));
985 if (!putline(buf, mci))
986 goto writeerr;
987 }
988 if (q->q_alias != NULL)
989 {
990 (void) sm_snprintf(buf, sizeof(buf),
991 " (expanded from: %s)",
992 shortenstring(q->q_alias->q_paddr,
993 MAXSHORTSTR));
994 if (!putline(buf, mci))
995 goto writeerr;
996 }
997 }
998 if (!printheader && !putline("", mci))
999 goto writeerr;
1000
1001 /* transient non-fatal errors */
1002 printheader = true;
1003 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
1004 {
1005 if (QS_IS_BADADDR(q->q_state) ||
1006 !bitset(QPRIMARY, q->q_flags) ||
1007 !bitset(QBYNDELAY, q->q_flags) ||
1008 !bitset(QDELAYED, q->q_flags))
1009 continue;
1010
1011 if (printheader)
1012 {
1013 if (!putline(" ----- The following addresses had transient non-fatal errors -----",
1014 mci))
1015 goto writeerr;
1016 printheader = false;
1017 }
1018
1019 (void) sm_strlcpy(buf, shortenstring(q->q_paddr, MAXSHORTSTR),
1020 sizeof(buf));
1021 if (!putline(buf, mci))
1022 goto writeerr;
1023 if (q->q_alias != NULL)
1024 {
1025 (void) sm_snprintf(buf, sizeof(buf),
1026 " (expanded from: %s)",
1027 shortenstring(q->q_alias->q_paddr,
1028 MAXSHORTSTR));
1029 if (!putline(buf, mci))
1030 goto writeerr;
1031 }
1032 }
1033 if (!printheader && !putline("", mci))
1034 goto writeerr;
1035
1036 /* successful delivery notifications */
1037 printheader = true;
1038 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
1039 {
1040 if (QS_IS_BADADDR(q->q_state) ||
1041 !bitset(QPRIMARY, q->q_flags) ||
1042 bitset(QBYNDELAY, q->q_flags) ||
1043 bitset(QDELAYED, q->q_flags))
1044 continue;
1045 else if (bitset(QBYNRELAY, q->q_flags))
1046 p = "Deliver-By notify: relayed";
1047 else if (bitset(QBYTRACE, q->q_flags))
1048 p = "Deliver-By trace: relayed";
1049 else if (!bitset(QPINGONSUCCESS, q->q_flags))
1050 continue;
1051 else if (bitset(QRELAYED, q->q_flags))
1052 p = "relayed to non-DSN-aware mailer";
1053 else if (bitset(QDELIVERED, q->q_flags))
1054 {
1055 if (bitset(QEXPANDED, q->q_flags))
1056 p = "successfully delivered to mailing list";
1057 else
1058 p = "successfully delivered to mailbox";
1059 }
1060 else if (bitset(QEXPANDED, q->q_flags))
1061 p = "expanded by alias";
1062 else
1063 continue;
1064
1065 if (printheader)
1066 {
1067 if (!putline(" ----- The following addresses had successful delivery notifications -----",
1068 mci))
1069 goto writeerr;
1070 printheader = false;
1071 }
1072
1073 (void) sm_snprintf(buf, sizeof(buf), "%s (%s)",
1074 shortenstring(q->q_paddr, MAXSHORTSTR), p);
1075 if (!putline(buf, mci))
1076 goto writeerr;
1077 if (q->q_alias != NULL)
1078 {
1079 (void) sm_snprintf(buf, sizeof(buf),
1080 " (expanded from: %s)",
1081 shortenstring(q->q_alias->q_paddr,
1082 MAXSHORTSTR));
1083 if (!putline(buf, mci))
1084 goto writeerr;
1085 }
1086 }
1087 if (!printheader && !putline("", mci))
1088 goto writeerr;
1089
1090 /*
1091 ** Output transcript of errors
1092 */
1093
1094 (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
1095 if (e->e_parent->e_xfp == NULL)
1096 {
1097 if (!putline(" ----- Transcript of session is unavailable -----\n",
1098 mci))
1099 goto writeerr;
1100 }
1101 else
1102 {
1103 int blen;
1104
1105 printheader = true;
1106 (void) bfrewind(e->e_parent->e_xfp);
1107 if (e->e_xfp != NULL)
1108 (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
1109 while ((blen = sm_io_fgets(e->e_parent->e_xfp, SM_TIME_DEFAULT,
1110 buf, sizeof(buf))) >= 0)
1111 {
1112 if (printheader && !putline(" ----- Transcript of session follows -----\n",
1113 mci))
1114 goto writeerr;
1115 printheader = false;
1116 if (!putxline(buf, blen, mci, PXLF_MAPFROM))
1117 goto writeerr;
1118 }
1119 }
1120 errno = 0;
1121
1122 #if DSN
1123 /*
1124 ** Output machine-readable version.
1125 */
1126
1127 if (e->e_msgboundary != NULL)
1128 {
1129 (void) sm_strlcpyn(buf, sizeof(buf), 2, "--", e->e_msgboundary);
1130 if (!putline("", mci) ||
1131 !putline(buf, mci) ||
1132 !putline(
1133 # if USE_EAI
1134 e->e_parent->e_smtputf8
1135 ? "Content-Type: message/global-delivery-status"
1136 :
1137 # endif
1138 "Content-Type: message/delivery-status", mci) ||
1139 !putline("", mci))
1140 goto writeerr;
1141
1142 /*
1143 ** Output per-message information.
1144 */
1145
1146 /* original envelope id from MAIL FROM: line */
1147 if (e->e_parent->e_envid != NULL)
1148 {
1149 (void) sm_snprintf(buf, sizeof(buf),
1150 "Original-Envelope-Id: %.800s",
1151 xuntextify(e->e_parent->e_envid));
1152 if (!putline(buf, mci))
1153 goto writeerr;
1154 }
1155
1156 /* Reporting-MTA: is us (required) */
1157 (void) sm_snprintf(buf, sizeof(buf),
1158 "Reporting-MTA: dns; %.800s", MyHostName);
1159 if (!putline(buf, mci))
1160 goto writeerr;
1161
1162 /* DSN-Gateway: not relevant since we are not translating */
1163
1164 /* Received-From-MTA: shows where we got this message from */
1165 if (RealHostName != NULL)
1166 {
1167 /* XXX use $s for type? */
1168 if (e->e_parent->e_from.q_mailer == NULL ||
1169 (p = e->e_parent->e_from.q_mailer->m_mtatype) == NULL)
1170 p = "dns";
1171 (void) sm_snprintf(buf, sizeof(buf),
1172 "Received-From-MTA: %s; %.800s",
1173 p, RealHostName);
1174 if (!putline(buf, mci))
1175 goto writeerr;
1176 }
1177
1178 /* Arrival-Date: -- when it arrived here */
1179 (void) sm_strlcpyn(buf, sizeof(buf), 2, "Arrival-Date: ",
1180 arpadate(ctime(&e->e_parent->e_ctime)));
1181 if (!putline(buf, mci))
1182 goto writeerr;
1183
1184 /* Deliver-By-Date: -- when it should have been delivered */
1185 if (IS_DLVR_BY(e->e_parent))
1186 {
1187 time_t dbyd;
1188
1189 dbyd = e->e_parent->e_ctime + e->e_parent->e_deliver_by;
1190 (void) sm_strlcpyn(buf, sizeof(buf), 2,
1191 "Deliver-By-Date: ",
1192 arpadate(ctime(&dbyd)));
1193 if (!putline(buf, mci))
1194 goto writeerr;
1195 }
1196
1197 /*
1198 ** Output per-address information.
1199 */
1200
1201 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
1202 {
1203 char *action;
1204
1205 if (QS_IS_BADADDR(q->q_state))
1206 {
1207 /* RFC 1891, 6.2.6 (b) */
1208 if (bitset(QHASNOTIFY, q->q_flags) &&
1209 !bitset(QPINGONFAILURE, q->q_flags))
1210 continue;
1211 action = "failed";
1212 }
1213 else if (!bitset(QPRIMARY, q->q_flags))
1214 continue;
1215 else if (bitset(QDELIVERED, q->q_flags))
1216 {
1217 if (bitset(QEXPANDED, q->q_flags))
1218 action = "delivered (to mailing list)";
1219 else
1220 action = "delivered (to mailbox)";
1221 }
1222 else if (bitset(QRELAYED, q->q_flags))
1223 action = "relayed (to non-DSN-aware mailer)";
1224 else if (bitset(QEXPANDED, q->q_flags))
1225 action = "expanded (to multi-recipient alias)";
1226 else if (bitset(QDELAYED, q->q_flags))
1227 action = "delayed";
1228 else if (bitset(QBYTRACE, q->q_flags))
1229 action = "relayed (Deliver-By trace mode)";
1230 else if (bitset(QBYNDELAY, q->q_flags))
1231 action = "delayed (Deliver-By notify mode)";
1232 else if (bitset(QBYNRELAY, q->q_flags))
1233 action = "relayed (Deliver-By notify mode)";
1234 else
1235 continue;
1236
1237 if (!putline("", mci))
1238 goto writeerr;
1239
1240 /* Original-Recipient: -- passed from on high */
1241 if (q->q_orcpt != NULL)
1242 {
1243 p = strchr(q->q_orcpt, ';');
1244
1245 /*
1246 ** p == NULL shouldn't happen due to
1247 ** check in srvrsmtp.c
1248 ** we could log an error in this case.
1249 */
1250
1251 if (p != NULL)
1252 {
1253 *p = '\0';
1254 (void) sm_snprintf(buf, sizeof(buf),
1255 "Original-Recipient: %.100s;%.700s",
1256 q->q_orcpt, xuntextify(p + 1));
1257 *p = ';';
1258 if (!putline(buf, mci))
1259 goto writeerr;
1260 }
1261 }
1262
1263 /* Figure out actual recipient */
1264 actual[0] = '\0';
1265 if (q->q_user[0] != '\0')
1266 {
1267 if (q->q_mailer != NULL &&
1268 q->q_mailer->m_addrtype != NULL)
1269 p = q->q_mailer->m_addrtype;
1270 else
1271 p = "rfc822";
1272
1273 if (SM_STRCASEEQ(p, "rfc822") &&
1274 strchr(q->q_user, '@') == NULL)
1275 {
1276 (void) sm_snprintf(actual,
1277 sizeof(actual),
1278 "%s; %.700s@%.100s",
1279 dsntypename(p, q->q_user),
1280 q->q_user,
1281 MyHostName);
1282 }
1283 else
1284 {
1285 (void) sm_snprintf(actual,
1286 sizeof(actual),
1287 "%s; %.800s",
1288 dsntypename(p, q->q_user),
1289 q->q_user);
1290 }
1291 }
1292
1293 /* Final-Recipient: -- the name from the RCPT command */
1294 if (q->q_finalrcpt == NULL)
1295 {
1296 /* should never happen */
1297 sm_syslog(LOG_ERR, e->e_id,
1298 "returntosender: q_finalrcpt is NULL");
1299
1300 /* try to fall back to the actual recipient */
1301 if (actual[0] != '\0')
1302 q->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool,
1303 actual);
1304 }
1305
1306 # if USE_EAI
1307 if (sm_strncasecmp("rfc822;", q->q_finalrcpt, 7) == 0 &&
1308 !addr_is_ascii(q->q_user))
1309 {
1310 char *a;
1311 char utf8rcpt[1024];
1312
1313 a = strchr(q->q_finalrcpt, ';');
1314 while(*a == ';' || *a == ' ')
1315 a++;
1316 sm_snprintf(utf8rcpt, sizeof(utf8rcpt),
1317 "utf-8; %.800s", a);
1318 q->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool,
1319 utf8rcpt);
1320 }
1321 # endif /* USE_EAI */
1322
1323 if (q->q_finalrcpt != NULL)
1324 {
1325 (void) sm_snprintf(buf, sizeof(buf),
1326 "Final-Recipient: %s",
1327 q->q_finalrcpt);
1328 if (!putline(buf, mci))
1329 goto writeerr;
1330 }
1331
1332 /* X-Actual-Recipient: -- the real problem address */
1333 if (actual[0] != '\0' &&
1334 q->q_finalrcpt != NULL &&
1335 !bitset(PRIV_NOACTUALRECIPIENT, PrivacyFlags) &&
1336 strcmp(actual, q->q_finalrcpt) != 0)
1337 {
1338 (void) sm_snprintf(buf, sizeof(buf),
1339 "X-Actual-Recipient: %s",
1340 actual);
1341 if (!putline(buf, mci))
1342 goto writeerr;
1343 }
1344
1345 /* Action: -- what happened? */
1346 (void) sm_strlcpyn(buf, sizeof(buf), 2, "Action: ",
1347 action);
1348 if (!putline(buf, mci))
1349 goto writeerr;
1350
1351 /* Status: -- what _really_ happened? */
1352 if (q->q_status != NULL)
1353 p = q->q_status;
1354 else if (QS_IS_BADADDR(q->q_state))
1355 p = "5.0.0";
1356 else if (QS_IS_QUEUEUP(q->q_state))
1357 p = "4.0.0";
1358 else
1359 p = "2.0.0";
1360 (void) sm_strlcpyn(buf, sizeof(buf), 2, "Status: ", p);
1361 if (!putline(buf, mci))
1362 goto writeerr;
1363
1364 /* Remote-MTA: -- who was I talking to? */
1365 if (q->q_statmta != NULL)
1366 {
1367 if (q->q_mailer == NULL ||
1368 (p = q->q_mailer->m_mtatype) == NULL)
1369 p = "dns";
1370 (void) sm_snprintf(buf, sizeof(buf),
1371 "Remote-MTA: %s; %.800s",
1372 p, q->q_statmta);
1373 p = &buf[strlen(buf) - 1];
1374 if (*p == '.')
1375 *p = '\0';
1376 if (!putline(buf, mci))
1377 goto writeerr;
1378 }
1379
1380 /* Diagnostic-Code: -- actual result from other end */
1381 if (q->q_rstatus != NULL)
1382 {
1383 if (q->q_mailer == NULL ||
1384 (p = q->q_mailer->m_diagtype) == NULL)
1385 p = "smtp";
1386 (void) sm_snprintf(buf, sizeof(buf),
1387 "Diagnostic-Code: %s; %.800s",
1388 p, q->q_rstatus);
1389 if (!putline(buf, mci))
1390 goto writeerr;
1391 }
1392
1393 /* Last-Attempt-Date: -- fine granularity */
1394 if (q->q_statdate == (time_t) 0L)
1395 q->q_statdate = curtime();
1396 (void) sm_strlcpyn(buf, sizeof(buf), 2,
1397 "Last-Attempt-Date: ",
1398 arpadate(ctime(&q->q_statdate)));
1399 if (!putline(buf, mci))
1400 goto writeerr;
1401
1402 /* Will-Retry-Until: -- for delayed messages only */
1403 if (QS_IS_QUEUEUP(q->q_state))
1404 {
1405 time_t xdate;
1406
1407 xdate = e->e_parent->e_ctime +
1408 TimeOuts.to_q_return[e->e_parent->e_timeoutclass];
1409 (void) sm_strlcpyn(buf, sizeof(buf), 2,
1410 "Will-Retry-Until: ",
1411 arpadate(ctime(&xdate)));
1412 if (!putline(buf, mci))
1413 goto writeerr;
1414 }
1415 }
1416 }
1417 #endif /* DSN */
1418
1419 /*
1420 ** Output text of original message
1421 */
1422
1423 if (!putline("", mci))
1424 goto writeerr;
1425 if (bitset(EF_HAS_DF, e->e_parent->e_flags))
1426 {
1427 sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) &&
1428 !bitset(EF_NO_BODY_RETN, e->e_flags);
1429
1430 if (e->e_msgboundary == NULL)
1431 {
1432 if (!putline(
1433 sendbody
1434 ? " ----- Original message follows -----\n"
1435 : " ----- Message header follows -----\n",
1436 mci))
1437 {
1438 goto writeerr;
1439 }
1440 }
1441 else
1442 {
1443 (void) sm_strlcpyn(buf, sizeof(buf), 2, "--",
1444 e->e_msgboundary);
1445
1446 if (!putline(buf, mci))
1447 goto writeerr;
1448 #if USE_EAI
1449 if (e->e_parent->e_smtputf8)
1450 (void) sm_strlcpyn(buf, sizeof(buf), 2,
1451 "Content-Type: message/global",
1452 sendbody ? "" : "-headers");
1453 else
1454 #endif /* USE_EAI */
1455 /* "else" in #if code above */
1456 {
1457 (void) sm_strlcpyn(buf, sizeof(buf), 2,
1458 "Content-Type: ",
1459 sendbody ? "message/rfc822"
1460 : "text/rfc822-headers");
1461 }
1462 if (!putline(buf, mci))
1463 goto writeerr;
1464
1465 p = hvalue("Content-Transfer-Encoding",
1466 e->e_parent->e_header);
1467 if (p != NULL && sm_strcasecmp(p, "binary") != 0)
1468 p = NULL;
1469 if (p == NULL &&
1470 bitset(EF_HAS8BIT, e->e_parent->e_flags))
1471 p = "8bit";
1472 if (p != NULL)
1473 {
1474 (void) sm_snprintf(buf, sizeof(buf),
1475 "Content-Transfer-Encoding: %s",
1476 p);
1477 if (!putline(buf, mci))
1478 goto writeerr;
1479 }
1480 }
1481 if (!putline("", mci))
1482 goto writeerr;
1483 save_errno = errno;
1484 if (!putheader(mci, e->e_parent->e_header, e->e_parent,
1485 M87F_OUTER))
1486 goto writeerr;
1487 errno = save_errno;
1488 if (sendbody)
1489 {
1490 if (!putbody(mci, e->e_parent, e->e_msgboundary))
1491 goto writeerr;
1492 }
1493 else if (e->e_msgboundary == NULL)
1494 {
1495 if (!putline("", mci) ||
1496 !putline(" ----- Message body suppressed -----",
1497 mci))
1498 {
1499 goto writeerr;
1500 }
1501 }
1502 }
1503 else if (e->e_msgboundary == NULL)
1504 {
1505 if (!putline(" ----- No message was collected -----\n", mci))
1506 goto writeerr;
1507 }
1508
1509 if (e->e_msgboundary != NULL)
1510 {
1511 (void) sm_strlcpyn(buf, sizeof(buf), 3, "--", e->e_msgboundary,
1512 "--");
1513 if (!putline("", mci) || !putline(buf, mci))
1514 goto writeerr;
1515 }
1516 if (!putline("", mci) ||
1517 sm_io_flush(mci->mci_out, SM_TIME_DEFAULT) == SM_IO_EOF)
1518 goto writeerr;
1519
1520 /*
1521 ** Cleanup and exit
1522 */
1523
1524 if (errno != 0)
1525 {
1526 writeerr:
1527 syserr("errbody: I/O error");
1528 return false;
1529 }
1530 return true;
1531 }
1532
1533 /*
1534 ** SMTPTODSN -- convert SMTP to DSN status code
1535 **
1536 ** Parameters:
1537 ** smtpstat -- the smtp status code (e.g., 550).
1538 **
1539 ** Returns:
1540 ** The DSN version of the status code.
1541 **
1542 ** Storage Management:
1543 ** smtptodsn() returns a pointer to a character string literal,
1544 ** which will remain valid forever, and thus does not need to
1545 ** be copied. Current code relies on this property.
1546 */
1547
1548 char *
smtptodsn(smtpstat)1549 smtptodsn(smtpstat)
1550 int smtpstat;
1551 {
1552 if (smtpstat < 0)
1553 return "4.4.2";
1554
1555 switch (smtpstat)
1556 {
1557 case 450: /* Req mail action not taken: mailbox unavailable */
1558 return "4.2.0";
1559
1560 case 451: /* Req action aborted: local error in processing */
1561 return "4.3.0";
1562
1563 case 452: /* Req action not taken: insufficient sys storage */
1564 return "4.3.1";
1565
1566 case 500: /* Syntax error, command unrecognized */
1567 return "5.5.2";
1568
1569 case 501: /* Syntax error in parameters or arguments */
1570 return "5.5.4";
1571
1572 case 502: /* Command not implemented */
1573 return "5.5.1";
1574
1575 case 503: /* Bad sequence of commands */
1576 return "5.5.1";
1577
1578 case 504: /* Command parameter not implemented */
1579 return "5.5.4";
1580
1581 case 550: /* Req mail action not taken: mailbox unavailable */
1582 return "5.2.0";
1583
1584 case 551: /* User not local; please try <...> */
1585 return "5.1.6";
1586
1587 case 552: /* Req mail action aborted: exceeded storage alloc */
1588 return "5.2.2";
1589
1590 case 553: /* Req action not taken: mailbox name not allowed */
1591 return "5.1.0";
1592
1593 case 554: /* Transaction failed */
1594 return "5.0.0";
1595 }
1596
1597 if (REPLYTYPE(smtpstat) == 2)
1598 return "2.0.0";
1599 if (REPLYTYPE(smtpstat) == 4)
1600 return "4.0.0";
1601 return "5.0.0";
1602 }
1603 /*
1604 ** XTEXTIFY -- take regular text and turn it into DSN-style xtext
1605 **
1606 ** Parameters:
1607 ** t -- the text to convert.
1608 ** taboo -- additional characters that must be encoded.
1609 **
1610 ** Returns:
1611 ** The xtext-ified version of the same string.
1612 */
1613
1614 char *
xtextify(t,taboo)1615 xtextify(t, taboo)
1616 register char *t;
1617 char *taboo;
1618 {
1619 register char *p;
1620 int l;
1621 int nbogus;
1622 static char *bp = NULL;
1623 static int bplen = 0;
1624
1625 if (taboo == NULL)
1626 taboo = "";
1627
1628 /* figure out how long this xtext will have to be */
1629 nbogus = l = 0;
1630 for (p = t; *p != '\0'; p++)
1631 {
1632 register int c = (*p & 0xff);
1633
1634 /* ASCII dependence here -- this is the way the spec words it */
1635 if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
1636 strchr(taboo, c) != NULL)
1637 nbogus++;
1638 l++;
1639 }
1640 if (nbogus < 0)
1641 {
1642 /* since nbogus is ssize_t and wrapped, 2 * size_t would wrap */
1643 syserr("!xtextify string too long");
1644 }
1645 if (nbogus == 0)
1646 return t;
1647 l += nbogus * 2 + 1;
1648
1649 /* now allocate space if necessary for the new string */
1650 if (l > bplen)
1651 {
1652 if (bp != NULL)
1653 sm_free(bp); /* XXX */
1654 bp = sm_pmalloc_x(l);
1655 bplen = l;
1656 }
1657
1658 /* ok, copy the text with byte expansion */
1659 for (p = bp; *t != '\0'; )
1660 {
1661 register int c = (*t++ & 0xff);
1662
1663 /* ASCII dependence here -- this is the way the spec words it */
1664 if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
1665 strchr(taboo, c) != NULL)
1666 {
1667 *p++ = '+';
1668 *p++ = "0123456789ABCDEF"[c >> 4];
1669 *p++ = "0123456789ABCDEF"[c & 0xf];
1670 }
1671 else
1672 *p++ = c;
1673 }
1674 *p = '\0';
1675 return bp;
1676 }
1677 /*
1678 ** XUNTEXTIFY -- take xtext and turn it into plain text
1679 **
1680 ** Parameters:
1681 ** t -- the xtextified text.
1682 **
1683 ** Returns:
1684 ** The decoded text. No attempt is made to deal with
1685 ** null strings in the resulting text.
1686 */
1687
1688 char *
xuntextify(t)1689 xuntextify(t)
1690 register char *t;
1691 {
1692 register char *p;
1693 int l;
1694 static char *bp = NULL;
1695 static int bplen = 0;
1696
1697 /* heuristic -- if no plus sign, just return the input */
1698 if (strchr(t, '+') == NULL)
1699 return t;
1700
1701 /* xtext is always longer than decoded text */
1702 l = strlen(t);
1703 if (l > bplen)
1704 {
1705 if (bp != NULL)
1706 sm_free(bp); /* XXX */
1707 bp = xalloc(l);
1708 bplen = l;
1709 }
1710
1711 /* ok, copy the text with byte compression */
1712 for (p = bp; *t != '\0'; t++)
1713 {
1714 register int c = *t & 0xff;
1715
1716 if (c != '+')
1717 {
1718 *p++ = c;
1719 continue;
1720 }
1721
1722 c = *++t & 0xff;
1723 if (!isascii(c) || !isxdigit(c))
1724 {
1725 /* error -- first digit is not hex */
1726 usrerr("bogus xtext: +%c", c);
1727 t--;
1728 continue;
1729 }
1730 if (isdigit(c))
1731 c -= '0';
1732 else if (isupper(c))
1733 c -= 'A' - 10;
1734 else
1735 c -= 'a' - 10;
1736 *p = c << 4;
1737
1738 c = *++t & 0xff;
1739 if (!isascii(c) || !isxdigit(c))
1740 {
1741 /* error -- second digit is not hex */
1742 usrerr("bogus xtext: +%x%c", *p >> 4, c);
1743 t--;
1744 continue;
1745 }
1746 if (isdigit(c))
1747 c -= '0';
1748 else if (isupper(c))
1749 c -= 'A' - 10;
1750 else
1751 c -= 'a' - 10;
1752 *p++ |= c;
1753 }
1754 *p = '\0';
1755 return bp;
1756 }
1757 /*
1758 ** XTEXTOK -- check if a string is legal xtext
1759 **
1760 ** Xtext is used in Delivery Status Notifications. The spec was
1761 ** taken from RFC 1891, ``SMTP Service Extension for Delivery
1762 ** Status Notifications''.
1763 **
1764 ** Parameters:
1765 ** s -- the string to check.
1766 **
1767 ** Returns:
1768 ** true -- if 's' is legal xtext.
1769 ** false -- if it has any illegal characters in it.
1770 */
1771
1772 bool
xtextok(s)1773 xtextok(s)
1774 char *s;
1775 {
1776 int c;
1777
1778 while ((c = *s++) != '\0')
1779 {
1780 if (c == '+')
1781 {
1782 c = *s++;
1783 if (!isascii(c) || !isxdigit(c))
1784 return false;
1785 c = *s++;
1786 if (!isascii(c) || !isxdigit(c))
1787 return false;
1788 }
1789 else if (c < '!' || c > '~' || c == '=')
1790 return false;
1791 }
1792 return true;
1793 }
1794
1795 /*
1796 ** ISATOM -- check if a string is an "atom"
1797 **
1798 ** Parameters:
1799 ** s -- the string to check.
1800 **
1801 ** Returns:
1802 ** true -- iff s is an atom
1803 */
1804
1805 bool
isatom(s)1806 isatom(s)
1807 const char *s;
1808 {
1809 int c;
1810
1811 if (SM_IS_EMPTY(s))
1812 return false;
1813 while ((c = *s++) != '\0')
1814 {
1815 if (strchr("()<>@,;:\\.[]\"", c) != NULL)
1816 return false;
1817 if (c < '!' || c > '~')
1818 return false;
1819 }
1820 return true;
1821 }
1822 /*
1823 ** PRUNEROUTE -- prune an RFC-822 source route
1824 **
1825 ** Trims down a source route to the last internet-registered hop.
1826 ** This is encouraged by RFC 1123 section 5.3.3.
1827 **
1828 ** Parameters:
1829 ** addr -- the address
1830 **
1831 ** Returns:
1832 ** true -- address was modified
1833 ** false -- address could not be pruned
1834 **
1835 ** Side Effects:
1836 ** modifies addr in-place
1837 */
1838
1839 static bool
pruneroute(addr)1840 pruneroute(addr)
1841 char *addr;
1842 {
1843 #if NAMED_BIND
1844 char *start, *at, *comma;
1845 char c;
1846 int braclev;
1847 int rcode;
1848 int i;
1849 char hostbuf[BUFSIZ];
1850 char *mxhosts[MAXMXHOSTS + 1];
1851
1852 /* check to see if this is really a route-addr */
1853 if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
1854 return false;
1855
1856 /*
1857 ** Can't simply find the first ':' is the address might be in the
1858 ** form: "<@[IPv6:::1]:user@host>" and the first ':' in inside
1859 ** the IPv6 address.
1860 */
1861
1862 start = addr;
1863 braclev = 0;
1864 while (*start != '\0')
1865 {
1866 if (*start == ':' && braclev <= 0)
1867 break;
1868 else if (*start == '[')
1869 braclev++;
1870 else if (*start == ']' && braclev > 0)
1871 braclev--;
1872 start++;
1873 }
1874 if (braclev > 0 || *start != ':')
1875 return false;
1876
1877 at = strrchr(addr, '@');
1878 if (at == NULL || at < start)
1879 return false;
1880
1881 /* slice off the angle brackets */
1882 i = strlen(at + 1);
1883 if (i >= sizeof(hostbuf))
1884 return false;
1885 (void) sm_strlcpy(hostbuf, at + 1, sizeof(hostbuf));
1886 hostbuf[i - 1] = '\0';
1887
1888 while (start != NULL)
1889 {
1890 if (getmxrr(hostbuf, mxhosts, NULL, TRYFALLBACK, &rcode, NULL,
1891 -1, NULL) > 0)
1892 {
1893 (void) sm_strlcpy(addr + 1, start + 1,
1894 strlen(addr) - 1);
1895 return true;
1896 }
1897 c = *start;
1898 *start = '\0';
1899 comma = strrchr(addr, ',');
1900 if (comma != NULL && comma[1] == '@' &&
1901 strlen(comma + 2) < sizeof(hostbuf))
1902 (void) sm_strlcpy(hostbuf, comma + 2, sizeof(hostbuf));
1903 else
1904 comma = NULL;
1905 *start = c;
1906 start = comma;
1907 }
1908 #endif /* NAMED_BIND */
1909 return false;
1910 }
1911