1 /* 2 * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 3 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * By using this file, you agree to the terms and conditions set 8 * forth in the LICENSE file which can be found at the top level of 9 * the sendmail distribution. 10 * 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)savemail.c 8.138 (Berkeley) 6/17/98"; 15 #endif /* not lint */ 16 17 # include "sendmail.h" 18 19 /* 20 ** SAVEMAIL -- Save mail on error 21 ** 22 ** If mailing back errors, mail it back to the originator 23 ** together with an error message; otherwise, just put it in 24 ** dead.letter in the user's home directory (if he exists on 25 ** this machine). 26 ** 27 ** Parameters: 28 ** e -- the envelope containing the message in error. 29 ** sendbody -- if TRUE, also send back the body of the 30 ** message; otherwise just send the header. 31 ** 32 ** Returns: 33 ** none 34 ** 35 ** Side Effects: 36 ** Saves the letter, by writing or mailing it back to the 37 ** sender, or by putting it in dead.letter in her home 38 ** directory. 39 */ 40 41 /* defines for state machine */ 42 # define ESM_REPORT 0 /* report to sender's terminal */ 43 # define ESM_MAIL 1 /* mail back to sender */ 44 # define ESM_QUIET 2 /* messages have already been returned */ 45 # define ESM_DEADLETTER 3 /* save in ~/dead.letter */ 46 # define ESM_POSTMASTER 4 /* return to postmaster */ 47 # define ESM_USRTMP 5 /* save in /usr/tmp/dead.letter */ 48 # define ESM_PANIC 6 /* leave the locked queue/transcript files */ 49 # define ESM_DONE 7 /* the message is successfully delivered */ 50 51 52 void 53 savemail(e, sendbody) 54 register ENVELOPE *e; 55 bool sendbody; 56 { 57 register struct passwd *pw; 58 register FILE *fp; 59 int state; 60 auto ADDRESS *q = NULL; 61 register char *p; 62 MCI mcibuf; 63 int flags; 64 char buf[MAXLINE+1]; 65 extern char *ttypath __P((void)); 66 extern bool writable __P((char *, ADDRESS *, int)); 67 68 if (tTd(6, 1)) 69 { 70 printf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n e_from=", 71 e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id, 72 ExitStat); 73 printaddr(&e->e_from, FALSE); 74 } 75 76 if (e->e_id == NULL) 77 { 78 /* can't return a message with no id */ 79 return; 80 } 81 82 /* 83 ** In the unhappy event we don't know who to return the mail 84 ** to, make someone up. 85 */ 86 87 if (e->e_from.q_paddr == NULL) 88 { 89 e->e_sender = "Postmaster"; 90 if (parseaddr(e->e_sender, &e->e_from, 91 RF_COPYPARSE|RF_SENDERADDR, '\0', NULL, e) == NULL) 92 { 93 syserr("553 Cannot parse Postmaster!"); 94 ExitStat = EX_SOFTWARE; 95 finis(); 96 } 97 } 98 e->e_to = NULL; 99 100 /* 101 ** Basic state machine. 102 ** 103 ** This machine runs through the following states: 104 ** 105 ** ESM_QUIET Errors have already been printed iff the 106 ** sender is local. 107 ** ESM_REPORT Report directly to the sender's terminal. 108 ** ESM_MAIL Mail response to the sender. 109 ** ESM_DEADLETTER Save response in ~/dead.letter. 110 ** ESM_POSTMASTER Mail response to the postmaster. 111 ** ESM_PANIC Save response anywhere possible. 112 */ 113 114 /* determine starting state */ 115 switch (e->e_errormode) 116 { 117 case EM_WRITE: 118 state = ESM_REPORT; 119 break; 120 121 case EM_BERKNET: 122 case EM_MAIL: 123 state = ESM_MAIL; 124 break; 125 126 case EM_PRINT: 127 case '\0': 128 state = ESM_QUIET; 129 break; 130 131 case EM_QUIET: 132 /* no need to return anything at all */ 133 return; 134 135 default: 136 syserr("554 savemail: bogus errormode x%x\n", e->e_errormode); 137 state = ESM_MAIL; 138 break; 139 } 140 141 /* if this is already an error response, send to postmaster */ 142 if (bitset(EF_RESPONSE, e->e_flags)) 143 { 144 if (e->e_parent != NULL && 145 bitset(EF_RESPONSE, e->e_parent->e_flags)) 146 { 147 /* got an error sending a response -- can it */ 148 return; 149 } 150 state = ESM_POSTMASTER; 151 } 152 153 while (state != ESM_DONE) 154 { 155 if (tTd(6, 5)) 156 printf(" state %d\n", state); 157 158 switch (state) 159 { 160 case ESM_QUIET: 161 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags)) 162 state = ESM_DEADLETTER; 163 else 164 state = ESM_MAIL; 165 break; 166 167 case ESM_REPORT: 168 169 /* 170 ** If the user is still logged in on the same terminal, 171 ** then write the error messages back to hir (sic). 172 */ 173 174 p = ttypath(); 175 if (p == NULL || freopen(p, "w", stdout) == NULL) 176 { 177 state = ESM_MAIL; 178 break; 179 } 180 181 expand("\201n", buf, sizeof buf, e); 182 printf("\r\nMessage from %s...\r\n", buf); 183 printf("Errors occurred while sending mail.\r\n"); 184 if (e->e_xfp != NULL) 185 { 186 (void) fflush(e->e_xfp); 187 fp = fopen(queuename(e, 'x'), "r"); 188 } 189 else 190 fp = NULL; 191 if (fp == NULL) 192 { 193 syserr("Cannot open %s", queuename(e, 'x')); 194 printf("Transcript of session is unavailable.\r\n"); 195 } 196 else 197 { 198 printf("Transcript follows:\r\n"); 199 while (fgets(buf, sizeof buf, fp) != NULL && 200 !ferror(stdout)) 201 fputs(buf, stdout); 202 (void) xfclose(fp, "savemail transcript", e->e_id); 203 } 204 printf("Original message will be saved in dead.letter.\r\n"); 205 state = ESM_DEADLETTER; 206 break; 207 208 case ESM_MAIL: 209 /* 210 ** If mailing back, do it. 211 ** Throw away all further output. Don't alias, 212 ** since this could cause loops, e.g., if joe 213 ** mails to joe@x, and for some reason the network 214 ** for @x is down, then the response gets sent to 215 ** joe@x, which gives a response, etc. Also force 216 ** the mail to be delivered even if a version of 217 ** it has already been sent to the sender. 218 ** 219 ** If this is a configuration or local software 220 ** error, send to the local postmaster as well, 221 ** since the originator can't do anything 222 ** about it anyway. Note that this is a full 223 ** copy of the message (intentionally) so that 224 ** the Postmaster can forward things along. 225 */ 226 227 if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE) 228 { 229 (void) sendtolist("postmaster", 230 NULLADDR, &e->e_errorqueue, 0, e); 231 } 232 if (!emptyaddr(&e->e_from)) 233 { 234 char from[TOBUFSIZE]; 235 extern bool pruneroute __P((char *)); 236 237 if (strlen(e->e_from.q_paddr) + 1 > sizeof from) 238 { 239 state = ESM_POSTMASTER; 240 break; 241 } 242 strcpy(from, e->e_from.q_paddr); 243 244 if (!DontPruneRoutes && pruneroute(from)) 245 { 246 ADDRESS *a; 247 248 for (a = e->e_errorqueue; a != NULL; 249 a = a->q_next) 250 { 251 if (sameaddr(a, &e->e_from)) 252 a->q_flags |= QDONTSEND; 253 } 254 } 255 (void) sendtolist(from, NULLADDR, 256 &e->e_errorqueue, 0, e); 257 } 258 259 /* 260 ** Deliver a non-delivery report to the 261 ** Postmaster-designate (not necessarily 262 ** Postmaster). This does not include the 263 ** body of the message, for privacy reasons. 264 ** You really shouldn't need this. 265 */ 266 267 e->e_flags |= EF_PM_NOTIFY; 268 269 /* check to see if there are any good addresses */ 270 for (q = e->e_errorqueue; q != NULL; q = q->q_next) 271 if (!bitset(QBADADDR|QDONTSEND, q->q_flags)) 272 break; 273 if (q == NULL) 274 { 275 /* this is an error-error */ 276 state = ESM_POSTMASTER; 277 break; 278 } 279 if (returntosender(e->e_message, e->e_errorqueue, 280 sendbody ? RTSF_SEND_BODY 281 : RTSF_NO_BODY, 282 e) == 0) 283 { 284 state = ESM_DONE; 285 break; 286 } 287 288 /* didn't work -- return to postmaster */ 289 state = ESM_POSTMASTER; 290 break; 291 292 case ESM_POSTMASTER: 293 /* 294 ** Similar to previous case, but to system postmaster. 295 */ 296 297 q = NULL; 298 if (sendtolist(DoubleBounceAddr, 299 NULLADDR, &q, 0, e) <= 0) 300 { 301 syserr("553 cannot parse %s!", DoubleBounceAddr); 302 ExitStat = EX_SOFTWARE; 303 state = ESM_USRTMP; 304 break; 305 } 306 flags = RTSF_PM_BOUNCE; 307 if (sendbody) 308 flags |= RTSF_SEND_BODY; 309 if (returntosender(e->e_message, q, flags, e) == 0) 310 { 311 state = ESM_DONE; 312 break; 313 } 314 315 /* didn't work -- last resort */ 316 state = ESM_USRTMP; 317 break; 318 319 case ESM_DEADLETTER: 320 /* 321 ** Save the message in dead.letter. 322 ** If we weren't mailing back, and the user is 323 ** local, we should save the message in 324 ** ~/dead.letter so that the poor person doesn't 325 ** have to type it over again -- and we all know 326 ** what poor typists UNIX users are. 327 */ 328 329 p = NULL; 330 if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags)) 331 { 332 if (e->e_from.q_home != NULL) 333 p = e->e_from.q_home; 334 else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL) 335 p = pw->pw_dir; 336 } 337 if (p == NULL || e->e_dfp == NULL) 338 { 339 /* no local directory or no data file */ 340 state = ESM_MAIL; 341 break; 342 } 343 344 /* we have a home directory; write dead.letter */ 345 define('z', p, e); 346 expand("\201z/dead.letter", buf, sizeof buf, e); 347 flags = SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID; 348 if (RealUid == 0) 349 flags |= SFF_ROOTOK; 350 e->e_to = buf; 351 if (mailfile(buf, FileMailer, NULL, flags, e) == EX_OK) 352 { 353 int oldverb = Verbose; 354 355 Verbose = 1; 356 message("Saved message in %s", buf); 357 Verbose = oldverb; 358 state = ESM_DONE; 359 break; 360 } 361 state = ESM_MAIL; 362 break; 363 364 case ESM_USRTMP: 365 /* 366 ** Log the mail in /usr/tmp/dead.letter. 367 */ 368 369 if (e->e_class < 0) 370 { 371 state = ESM_DONE; 372 break; 373 } 374 375 if ((SafeFileEnv != NULL && SafeFileEnv[0] != '\0') || 376 DeadLetterDrop == NULL || DeadLetterDrop[0] == '\0') 377 { 378 state = ESM_PANIC; 379 break; 380 } 381 382 flags = SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT|SFF_MUSTOWN; 383 if (!writable(DeadLetterDrop, NULL, flags) || 384 (fp = safefopen(DeadLetterDrop, O_WRONLY|O_APPEND, 385 FileMode, flags)) == NULL) 386 { 387 state = ESM_PANIC; 388 break; 389 } 390 391 bzero(&mcibuf, sizeof mcibuf); 392 mcibuf.mci_out = fp; 393 mcibuf.mci_mailer = FileMailer; 394 if (bitnset(M_7BITS, FileMailer->m_flags)) 395 mcibuf.mci_flags |= MCIF_7BIT; 396 mcibuf.mci_contentlen = 0; 397 398 putfromline(&mcibuf, e); 399 (*e->e_puthdr)(&mcibuf, e->e_header, e); 400 (*e->e_putbody)(&mcibuf, e, NULL); 401 putline("\n", &mcibuf); 402 (void) fflush(fp); 403 if (ferror(fp)) 404 state = ESM_PANIC; 405 else 406 { 407 int oldverb = Verbose; 408 409 Verbose = 1; 410 message("Saved message in %s", DeadLetterDrop); 411 Verbose = oldverb; 412 if (LogLevel > 3) 413 sm_syslog(LOG_NOTICE, e->e_id, 414 "Saved message in %s", 415 DeadLetterDrop); 416 state = ESM_DONE; 417 } 418 (void) xfclose(fp, "savemail", DeadLetterDrop); 419 break; 420 421 default: 422 syserr("554 savemail: unknown state %d", state); 423 424 /* fall through ... */ 425 426 case ESM_PANIC: 427 /* leave the locked queue & transcript files around */ 428 loseqfile(e, "savemail panic"); 429 syserr("!554 savemail: cannot save rejected email anywhere"); 430 } 431 } 432 } 433 /* 434 ** RETURNTOSENDER -- return a message to the sender with an error. 435 ** 436 ** Parameters: 437 ** msg -- the explanatory message. 438 ** returnq -- the queue of people to send the message to. 439 ** flags -- flags tweaking the operation: 440 ** RTSF_SENDBODY -- include body of message (otherwise 441 ** just send the header). 442 ** RTSF_PMBOUNCE -- this is a postmaster bounce. 443 ** e -- the current envelope. 444 ** 445 ** Returns: 446 ** zero -- if everything went ok. 447 ** else -- some error. 448 ** 449 ** Side Effects: 450 ** Returns the current message to the sender via 451 ** mail. 452 */ 453 454 #define MAXRETURNS 6 /* max depth of returning messages */ 455 #define ERRORFUDGE 100 /* nominal size of error message text */ 456 457 int 458 returntosender(msg, returnq, flags, e) 459 char *msg; 460 ADDRESS *returnq; 461 int flags; 462 register ENVELOPE *e; 463 { 464 register ENVELOPE *ee; 465 ENVELOPE *oldcur = CurEnv; 466 ENVELOPE errenvelope; 467 static int returndepth = 0; 468 register ADDRESS *q; 469 char *p; 470 char buf[MAXNAME + 1]; 471 extern void errbody __P((MCI *, ENVELOPE *, char *)); 472 473 if (returnq == NULL) 474 return (-1); 475 476 if (msg == NULL) 477 msg = "Unable to deliver mail"; 478 479 if (tTd(6, 1)) 480 { 481 printf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%lx, returnq=", 482 msg, returndepth, (u_long) e); 483 printaddr(returnq, TRUE); 484 if (tTd(6, 20)) 485 { 486 printf("Sendq="); 487 printaddr(e->e_sendqueue, TRUE); 488 } 489 } 490 491 if (++returndepth >= MAXRETURNS) 492 { 493 if (returndepth != MAXRETURNS) 494 syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr); 495 /* don't "unrecurse" and fake a clean exit */ 496 /* returndepth--; */ 497 return (0); 498 } 499 500 define('g', e->e_from.q_paddr, e); 501 define('u', NULL, e); 502 503 /* initialize error envelope */ 504 ee = newenvelope(&errenvelope, e); 505 define('a', "\201b", ee); 506 define('r', "internal", ee); 507 define('s', "localhost", ee); 508 define('_', "localhost", ee); 509 ee->e_puthdr = putheader; 510 ee->e_putbody = errbody; 511 ee->e_flags |= EF_RESPONSE|EF_METOO; 512 if (!bitset(EF_OLDSTYLE, e->e_flags)) 513 ee->e_flags &= ~EF_OLDSTYLE; 514 ee->e_sendqueue = returnq; 515 ee->e_msgsize = ERRORFUDGE; 516 if (bitset(RTSF_SEND_BODY, flags)) 517 ee->e_msgsize += e->e_msgsize; 518 else 519 ee->e_flags |= EF_NO_BODY_RETN; 520 initsys(ee); 521 for (q = returnq; q != NULL; q = q->q_next) 522 { 523 if (bitset(QBADADDR, q->q_flags)) 524 continue; 525 526 q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); 527 q->q_flags |= QPINGONFAILURE; 528 529 if (!bitset(QDONTSEND, q->q_flags)) 530 ee->e_nrcpts++; 531 532 if (q->q_alias == NULL) 533 addheader("To", q->q_paddr, &ee->e_header); 534 } 535 536 if (LogLevel > 5) 537 { 538 if (bitset(EF_RESPONSE|EF_WARNING, e->e_flags)) 539 p = "return to sender"; 540 else if (bitset(RTSF_PM_BOUNCE, flags)) 541 p = "postmaster notify"; 542 else 543 p = "DSN"; 544 sm_syslog(LOG_INFO, e->e_id, 545 "%s: %s: %s", 546 ee->e_id, p, shortenstring(msg, MAXSHORTSTR)); 547 } 548 549 if (SendMIMEErrors) 550 { 551 addheader("MIME-Version", "1.0", &ee->e_header); 552 553 (void) snprintf(buf, sizeof buf, "%s.%ld/%.100s", 554 ee->e_id, curtime(), MyHostName); 555 ee->e_msgboundary = newstr(buf); 556 (void) snprintf(buf, sizeof buf, 557 #if DSN 558 "multipart/report; report-type=delivery-status;\n\tboundary=\"%s\"", 559 #else 560 "multipart/mixed; boundary=\"%s\"", 561 #endif 562 ee->e_msgboundary); 563 addheader("Content-Type", buf, &ee->e_header); 564 565 p = hvalue("Content-Transfer-Encoding", e->e_header); 566 if (p != NULL && strcasecmp(p, "binary") != 0) 567 p = NULL; 568 if (p == NULL && bitset(EF_HAS8BIT, e->e_flags)) 569 p = "8bit"; 570 if (p != NULL) 571 addheader("Content-Transfer-Encoding", p, &ee->e_header); 572 } 573 if (strncmp(msg, "Warning:", 8) == 0) 574 { 575 addheader("Subject", msg, &ee->e_header); 576 p = "warning-timeout"; 577 } 578 else if (strncmp(msg, "Postmaster warning:", 19) == 0) 579 { 580 addheader("Subject", msg, &ee->e_header); 581 p = "postmaster-warning"; 582 } 583 else if (strcmp(msg, "Return receipt") == 0) 584 { 585 addheader("Subject", msg, &ee->e_header); 586 p = "return-receipt"; 587 } 588 else if (bitset(RTSF_PM_BOUNCE, flags)) 589 { 590 snprintf(buf, sizeof buf, "Postmaster notify: %.*s", 591 sizeof buf - 20, msg); 592 addheader("Subject", buf, &ee->e_header); 593 p = "postmaster-notification"; 594 } 595 else 596 { 597 snprintf(buf, sizeof buf, "Returned mail: %.*s", 598 sizeof buf - 20, msg); 599 addheader("Subject", buf, &ee->e_header); 600 p = "failure"; 601 } 602 (void) snprintf(buf, sizeof buf, "auto-generated (%s)", p); 603 addheader("Auto-Submitted", buf, &ee->e_header); 604 605 /* fake up an address header for the from person */ 606 expand("\201n", buf, sizeof buf, e); 607 if (parseaddr(buf, &ee->e_from, RF_COPYALL|RF_SENDERADDR, '\0', NULL, e) == NULL) 608 { 609 syserr("553 Can't parse myself!"); 610 ExitStat = EX_SOFTWARE; 611 returndepth--; 612 return (-1); 613 } 614 ee->e_from.q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); 615 ee->e_from.q_flags |= QPINGONFAILURE; 616 ee->e_sender = ee->e_from.q_paddr; 617 618 /* push state into submessage */ 619 CurEnv = ee; 620 define('f', "\201n", ee); 621 define('x', "Mail Delivery Subsystem", ee); 622 eatheader(ee, TRUE); 623 624 /* mark statistics */ 625 markstats(ee, NULLADDR, FALSE); 626 627 /* actually deliver the error message */ 628 sendall(ee, SM_DELIVER); 629 630 /* restore state */ 631 dropenvelope(ee, TRUE); 632 CurEnv = oldcur; 633 returndepth--; 634 635 /* check for delivery errors */ 636 if (ee->e_parent == NULL || !bitset(EF_RESPONSE, ee->e_parent->e_flags)) 637 return 0; 638 for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 639 { 640 if (bitset(QQUEUEUP|QSENT, q->q_flags)) 641 return 0; 642 } 643 return -1; 644 } 645 /* 646 ** ERRBODY -- output the body of an error message. 647 ** 648 ** Typically this is a copy of the transcript plus a copy of the 649 ** original offending message. 650 ** 651 ** Parameters: 652 ** mci -- the mailer connection information. 653 ** e -- the envelope we are working in. 654 ** separator -- any possible MIME separator. 655 ** 656 ** Returns: 657 ** none 658 ** 659 ** Side Effects: 660 ** Outputs the body of an error message. 661 */ 662 663 void 664 errbody(mci, e, separator) 665 register MCI *mci; 666 register ENVELOPE *e; 667 char *separator; 668 { 669 register FILE *xfile; 670 char *p; 671 register ADDRESS *q = NULL; 672 bool printheader; 673 bool sendbody; 674 bool pm_notify; 675 char buf[MAXLINE]; 676 677 if (bitset(MCIF_INHEADER, mci->mci_flags)) 678 { 679 putline("", mci); 680 mci->mci_flags &= ~MCIF_INHEADER; 681 } 682 if (e->e_parent == NULL) 683 { 684 syserr("errbody: null parent"); 685 putline(" ----- Original message lost -----\n", mci); 686 return; 687 } 688 689 /* 690 ** Output MIME header. 691 */ 692 693 if (e->e_msgboundary != NULL) 694 { 695 putline("This is a MIME-encapsulated message", mci); 696 putline("", mci); 697 (void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary); 698 putline(buf, mci); 699 putline("", mci); 700 } 701 702 /* 703 ** Output introductory information. 704 */ 705 706 pm_notify = FALSE; 707 p = hvalue("subject", e->e_header); 708 if (p != NULL && strncmp(p, "Postmaster ", 11) == 0) 709 pm_notify = TRUE; 710 else 711 { 712 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 713 if (bitset(QBADADDR, q->q_flags)) 714 break; 715 } 716 if (!pm_notify && q == NULL && 717 !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags)) 718 { 719 putline(" **********************************************", 720 mci); 721 putline(" ** THIS IS A WARNING MESSAGE ONLY **", 722 mci); 723 putline(" ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **", 724 mci); 725 putline(" **********************************************", 726 mci); 727 putline("", mci); 728 } 729 snprintf(buf, sizeof buf, "The original message was received at %s", 730 arpadate(ctime(&e->e_parent->e_ctime))); 731 putline(buf, mci); 732 expand("from \201_", buf, sizeof buf, e->e_parent); 733 putline(buf, mci); 734 putline("", mci); 735 736 /* 737 ** Output error message header (if specified and available). 738 */ 739 740 if (ErrMsgFile != NULL && !bitset(EF_SENDRECEIPT, e->e_parent->e_flags)) 741 { 742 if (*ErrMsgFile == '/') 743 { 744 int sff = SFF_ROOTOK|SFF_REGONLY; 745 746 if (DontLockReadFiles) 747 sff |= SFF_NOLOCK; 748 if (!bitset(DBS_ERRORHEADERINUNSAFEDIRPATH, DontBlameSendmail)) 749 sff |= SFF_SAFEDIRPATH; 750 xfile = safefopen(ErrMsgFile, O_RDONLY, 0444, sff); 751 if (xfile != NULL) 752 { 753 while (fgets(buf, sizeof buf, xfile) != NULL) 754 { 755 extern void translate_dollars __P((char *)); 756 757 translate_dollars(buf); 758 expand(buf, buf, sizeof buf, e); 759 putline(buf, mci); 760 } 761 (void) fclose(xfile); 762 putline("\n", mci); 763 } 764 } 765 else 766 { 767 expand(ErrMsgFile, buf, sizeof buf, e); 768 putline(buf, mci); 769 putline("", mci); 770 } 771 } 772 773 /* 774 ** Output message introduction 775 */ 776 777 printheader = TRUE; 778 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 779 { 780 if (!bitset(QBADADDR, q->q_flags) || 781 !bitset(QPINGONFAILURE, q->q_flags)) 782 continue; 783 784 if (printheader) 785 { 786 putline(" ----- The following addresses had permanent fatal errors -----", 787 mci); 788 printheader = FALSE; 789 } 790 791 snprintf(buf, sizeof buf, "%s", 792 shortenstring(q->q_paddr, MAXSHORTSTR)); 793 putline(buf, mci); 794 if (q->q_alias != NULL) 795 { 796 snprintf(buf, sizeof buf, " (expanded from: %s)", 797 shortenstring(q->q_alias->q_paddr, MAXSHORTSTR)); 798 putline(buf, mci); 799 } 800 } 801 if (!printheader) 802 putline("", mci); 803 804 printheader = TRUE; 805 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 806 { 807 if (bitset(QBADADDR, q->q_flags) || 808 !bitset(QPRIMARY, q->q_flags) || 809 !bitset(QDELAYED, q->q_flags)) 810 continue; 811 812 if (printheader) 813 { 814 putline(" ----- The following addresses had transient non-fatal errors -----", 815 mci); 816 printheader = FALSE; 817 } 818 819 snprintf(buf, sizeof buf, "%s", 820 shortenstring(q->q_paddr, MAXSHORTSTR)); 821 putline(buf, mci); 822 if (q->q_alias != NULL) 823 { 824 snprintf(buf, sizeof buf, " (expanded from: %s)", 825 shortenstring(q->q_alias->q_paddr, MAXSHORTSTR)); 826 putline(buf, mci); 827 } 828 } 829 if (!printheader) 830 putline("", mci); 831 832 printheader = TRUE; 833 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 834 { 835 if (bitset(QBADADDR, q->q_flags) || 836 !bitset(QPRIMARY, q->q_flags) || 837 bitset(QDELAYED, q->q_flags)) 838 continue; 839 else if (!bitset(QPINGONSUCCESS, q->q_flags)) 840 continue; 841 else if (bitset(QRELAYED, q->q_flags)) 842 p = "relayed to non-DSN-aware mailer"; 843 else if (bitset(QDELIVERED, q->q_flags)) 844 { 845 if (bitset(QEXPANDED, q->q_flags)) 846 p = "successfully delivered to mailing list"; 847 else 848 p = "successfully delivered to mailbox"; 849 } 850 else if (bitset(QEXPANDED, q->q_flags)) 851 p = "expanded by alias"; 852 else 853 continue; 854 855 if (printheader) 856 { 857 putline(" ----- The following addresses had successful delivery notifications -----", 858 mci); 859 printheader = FALSE; 860 } 861 862 snprintf(buf, sizeof buf, "%s (%s)", 863 shortenstring(q->q_paddr, MAXSHORTSTR), p); 864 putline(buf, mci); 865 if (q->q_alias != NULL) 866 { 867 snprintf(buf, sizeof buf, " (expanded from: %s)", 868 shortenstring(q->q_alias->q_paddr, MAXSHORTSTR)); 869 putline(buf, mci); 870 } 871 } 872 if (!printheader) 873 putline("", mci); 874 875 /* 876 ** Output transcript of errors 877 */ 878 879 (void) fflush(stdout); 880 p = queuename(e->e_parent, 'x'); 881 if ((xfile = fopen(p, "r")) == NULL) 882 { 883 syserr("Cannot open %s", p); 884 putline(" ----- Transcript of session is unavailable -----\n", mci); 885 } 886 else 887 { 888 printheader = TRUE; 889 if (e->e_xfp != NULL) 890 (void) fflush(e->e_xfp); 891 while (fgets(buf, sizeof buf, xfile) != NULL) 892 { 893 if (printheader) 894 putline(" ----- Transcript of session follows -----\n", mci); 895 printheader = FALSE; 896 putline(buf, mci); 897 } 898 (void) xfclose(xfile, "errbody xscript", p); 899 } 900 errno = 0; 901 902 #if DSN 903 /* 904 ** Output machine-readable version. 905 */ 906 907 if (e->e_msgboundary != NULL) 908 { 909 putline("", mci); 910 (void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary); 911 putline(buf, mci); 912 putline("Content-Type: message/delivery-status", mci); 913 putline("", mci); 914 915 /* 916 ** Output per-message information. 917 */ 918 919 /* original envelope id from MAIL FROM: line */ 920 if (e->e_parent->e_envid != NULL) 921 { 922 (void) snprintf(buf, sizeof buf, "Original-Envelope-Id: %.800s", 923 xuntextify(e->e_parent->e_envid)); 924 putline(buf, mci); 925 } 926 927 /* Reporting-MTA: is us (required) */ 928 (void) snprintf(buf, sizeof buf, "Reporting-MTA: dns; %.800s", MyHostName); 929 putline(buf, mci); 930 931 /* DSN-Gateway: not relevant since we are not translating */ 932 933 /* Received-From-MTA: shows where we got this message from */ 934 if (RealHostName != NULL) 935 { 936 /* XXX use $s for type? */ 937 if (e->e_parent->e_from.q_mailer == NULL || 938 (p = e->e_parent->e_from.q_mailer->m_mtatype) == NULL) 939 p = "dns"; 940 (void) snprintf(buf, sizeof buf, "Received-From-MTA: %s; %.800s", 941 p, RealHostName); 942 putline(buf, mci); 943 } 944 945 /* Arrival-Date: -- when it arrived here */ 946 (void) snprintf(buf, sizeof buf, "Arrival-Date: %s", 947 arpadate(ctime(&e->e_parent->e_ctime))); 948 putline(buf, mci); 949 950 /* 951 ** Output per-address information. 952 */ 953 954 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 955 { 956 register ADDRESS *r; 957 char *action; 958 959 if (bitset(QBADADDR, q->q_flags)) 960 action = "failed"; 961 else if (!bitset(QPRIMARY, q->q_flags)) 962 continue; 963 else if (bitset(QDELIVERED, q->q_flags)) 964 { 965 if (bitset(QEXPANDED, q->q_flags)) 966 action = "delivered (to mailing list)"; 967 else 968 action = "delivered (to mailbox)"; 969 } 970 else if (bitset(QRELAYED, q->q_flags)) 971 action = "relayed (to non-DSN-aware mailer)"; 972 else if (bitset(QEXPANDED, q->q_flags)) 973 action = "expanded (to multi-recipient alias)"; 974 else if (bitset(QDELAYED, q->q_flags)) 975 action = "delayed"; 976 else 977 continue; 978 979 putline("", mci); 980 981 /* Original-Recipient: -- passed from on high */ 982 if (q->q_orcpt != NULL) 983 { 984 (void) snprintf(buf, sizeof buf, "Original-Recipient: %.800s", 985 q->q_orcpt); 986 putline(buf, mci); 987 } 988 989 /* Final-Recipient: -- the name from the RCPT command */ 990 p = e->e_parent->e_from.q_mailer->m_addrtype; 991 if (p == NULL) 992 p = "rfc822"; 993 for (r = q; r->q_alias != NULL; r = r->q_alias) 994 continue; 995 if (strchr(r->q_user, '@') != NULL) 996 { 997 (void) snprintf(buf, sizeof buf, 998 "Final-Recipient: %s; %.800s", 999 p, r->q_user); 1000 } 1001 else if (strchr(r->q_paddr, '@') != NULL) 1002 { 1003 (void) snprintf(buf, sizeof buf, 1004 "Final-Recipient: %s; %.800s", 1005 p, r->q_paddr); 1006 } 1007 else 1008 { 1009 (void) snprintf(buf, sizeof buf, 1010 "Final-Recipient: %s; %.700s@%.100s", 1011 p, r->q_user, MyHostName); 1012 } 1013 putline(buf, mci); 1014 1015 /* X-Actual-Recipient: -- the real problem address */ 1016 if (r != q && q->q_user[0] != '\0') 1017 { 1018 if (strchr(q->q_user, '@') == NULL) 1019 { 1020 (void) snprintf(buf, sizeof buf, 1021 "X-Actual-Recipient: %s; %.700s@%.100s", 1022 p, q->q_user, MyHostName); 1023 } 1024 else 1025 { 1026 (void) snprintf(buf, sizeof buf, 1027 "X-Actual-Recipient: %s; %.800s", 1028 p, q->q_user); 1029 } 1030 putline(buf, mci); 1031 } 1032 1033 /* Action: -- what happened? */ 1034 snprintf(buf, sizeof buf, "Action: %s", action); 1035 putline(buf, mci); 1036 1037 /* Status: -- what _really_ happened? */ 1038 if (q->q_status != NULL) 1039 p = q->q_status; 1040 else if (bitset(QBADADDR, q->q_flags)) 1041 p = "5.0.0"; 1042 else if (bitset(QQUEUEUP, q->q_flags)) 1043 p = "4.0.0"; 1044 else 1045 p = "2.0.0"; 1046 snprintf(buf, sizeof buf, "Status: %s", p); 1047 putline(buf, mci); 1048 1049 /* Remote-MTA: -- who was I talking to? */ 1050 if (q->q_statmta != NULL) 1051 { 1052 if (q->q_mailer == NULL || 1053 (p = q->q_mailer->m_mtatype) == NULL) 1054 p = "dns"; 1055 (void) snprintf(buf, sizeof buf, 1056 "Remote-MTA: %s; %.800s", 1057 p, q->q_statmta); 1058 p = &buf[strlen(buf) - 1]; 1059 if (*p == '.') 1060 *p = '\0'; 1061 putline(buf, mci); 1062 } 1063 1064 /* Diagnostic-Code: -- actual result from other end */ 1065 if (q->q_rstatus != NULL) 1066 { 1067 p = q->q_mailer->m_diagtype; 1068 if (p == NULL) 1069 p = "smtp"; 1070 (void) snprintf(buf, sizeof buf, 1071 "Diagnostic-Code: %s; %.800s", 1072 p, q->q_rstatus); 1073 putline(buf, mci); 1074 } 1075 1076 /* Last-Attempt-Date: -- fine granularity */ 1077 if (q->q_statdate == (time_t) 0L) 1078 q->q_statdate = curtime(); 1079 (void) snprintf(buf, sizeof buf, 1080 "Last-Attempt-Date: %s", 1081 arpadate(ctime(&q->q_statdate))); 1082 putline(buf, mci); 1083 1084 /* Will-Retry-Until: -- for delayed messages only */ 1085 if (bitset(QQUEUEUP, q->q_flags) && 1086 !bitset(QBADADDR, q->q_flags)) 1087 { 1088 time_t xdate; 1089 1090 xdate = e->e_parent->e_ctime + 1091 TimeOuts.to_q_return[e->e_parent->e_timeoutclass]; 1092 snprintf(buf, sizeof buf, 1093 "Will-Retry-Until: %s", 1094 arpadate(ctime(&xdate))); 1095 putline(buf, mci); 1096 } 1097 } 1098 } 1099 #endif 1100 1101 /* 1102 ** Output text of original message 1103 */ 1104 1105 putline("", mci); 1106 if (bitset(EF_HAS_DF, e->e_parent->e_flags)) 1107 { 1108 sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) && 1109 !bitset(EF_NO_BODY_RETN, e->e_flags); 1110 1111 if (e->e_msgboundary == NULL) 1112 { 1113 if (sendbody) 1114 putline(" ----- Original message follows -----\n", mci); 1115 else 1116 putline(" ----- Message header follows -----\n", mci); 1117 (void) fflush(mci->mci_out); 1118 } 1119 else 1120 { 1121 (void) snprintf(buf, sizeof buf, "--%s", 1122 e->e_msgboundary); 1123 1124 putline(buf, mci); 1125 (void) snprintf(buf, sizeof buf, "Content-Type: %s", 1126 sendbody ? "message/rfc822" 1127 : "text/rfc822-headers"); 1128 putline(buf, mci); 1129 1130 p = hvalue("Content-Transfer-Encoding", e->e_parent->e_header); 1131 if (p != NULL && strcasecmp(p, "binary") != 0) 1132 p = NULL; 1133 if (p == NULL && bitset(EF_HAS8BIT, e->e_parent->e_flags)) 1134 p = "8bit"; 1135 if (p != NULL) 1136 { 1137 (void) snprintf(buf, sizeof buf, "Content-Transfer-Encoding: %s", 1138 p); 1139 putline(buf, mci); 1140 } 1141 } 1142 putline("", mci); 1143 putheader(mci, e->e_parent->e_header, e->e_parent); 1144 if (sendbody) 1145 putbody(mci, e->e_parent, e->e_msgboundary); 1146 else if (e->e_msgboundary == NULL) 1147 { 1148 putline("", mci); 1149 putline(" ----- Message body suppressed -----", mci); 1150 } 1151 } 1152 else if (e->e_msgboundary == NULL) 1153 { 1154 putline(" ----- No message was collected -----\n", mci); 1155 } 1156 1157 if (e->e_msgboundary != NULL) 1158 { 1159 putline("", mci); 1160 (void) snprintf(buf, sizeof buf, "--%s--", e->e_msgboundary); 1161 putline(buf, mci); 1162 } 1163 putline("", mci); 1164 1165 /* 1166 ** Cleanup and exit 1167 */ 1168 1169 if (errno != 0) 1170 syserr("errbody: I/O error"); 1171 } 1172 /* 1173 ** SMTPTODSN -- convert SMTP to DSN status code 1174 ** 1175 ** Parameters: 1176 ** smtpstat -- the smtp status code (e.g., 550). 1177 ** 1178 ** Returns: 1179 ** The DSN version of the status code. 1180 */ 1181 1182 char * 1183 smtptodsn(smtpstat) 1184 int smtpstat; 1185 { 1186 if (smtpstat < 0) 1187 return "4.4.2"; 1188 1189 switch (smtpstat) 1190 { 1191 case 450: /* Req mail action not taken: mailbox unavailable */ 1192 return "4.2.0"; 1193 1194 case 451: /* Req action aborted: local error in processing */ 1195 return "4.3.0"; 1196 1197 case 452: /* Req action not taken: insufficient sys storage */ 1198 return "4.3.1"; 1199 1200 case 500: /* Syntax error, command unrecognized */ 1201 return "5.5.2"; 1202 1203 case 501: /* Syntax error in parameters or arguments */ 1204 return "5.5.4"; 1205 1206 case 502: /* Command not implemented */ 1207 return "5.5.1"; 1208 1209 case 503: /* Bad sequence of commands */ 1210 return "5.5.1"; 1211 1212 case 504: /* Command parameter not implemented */ 1213 return "5.5.4"; 1214 1215 case 550: /* Req mail action not taken: mailbox unavailable */ 1216 return "5.2.0"; 1217 1218 case 551: /* User not local; please try <...> */ 1219 return "5.1.6"; 1220 1221 case 552: /* Req mail action aborted: exceeded storage alloc */ 1222 return "5.2.2"; 1223 1224 case 553: /* Req action not taken: mailbox name not allowed */ 1225 return "5.1.0"; 1226 1227 case 554: /* Transaction failed */ 1228 return "5.0.0"; 1229 } 1230 1231 if ((smtpstat / 100) == 2) 1232 return "2.0.0"; 1233 if ((smtpstat / 100) == 4) 1234 return "4.0.0"; 1235 return "5.0.0"; 1236 } 1237 /* 1238 ** XTEXTIFY -- take regular text and turn it into DSN-style xtext 1239 ** 1240 ** Parameters: 1241 ** t -- the text to convert. 1242 ** taboo -- additional characters that must be encoded. 1243 ** 1244 ** Returns: 1245 ** The xtext-ified version of the same string. 1246 */ 1247 1248 char * 1249 xtextify(t, taboo) 1250 register char *t; 1251 char *taboo; 1252 { 1253 register char *p; 1254 int l; 1255 int nbogus; 1256 static char *bp = NULL; 1257 static int bplen = 0; 1258 1259 if (taboo == NULL) 1260 taboo = ""; 1261 1262 /* figure out how long this xtext will have to be */ 1263 nbogus = l = 0; 1264 for (p = t; *p != '\0'; p++) 1265 { 1266 register int c = (*p & 0xff); 1267 1268 /* ASCII dependence here -- this is the way the spec words it */ 1269 if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' || 1270 strchr(taboo, c) != NULL) 1271 nbogus++; 1272 l++; 1273 } 1274 if (nbogus == 0) 1275 return t; 1276 l += nbogus * 2 + 1; 1277 1278 /* now allocate space if necessary for the new string */ 1279 if (l > bplen) 1280 { 1281 if (bp != NULL) 1282 free(bp); 1283 bp = xalloc(l); 1284 bplen = l; 1285 } 1286 1287 /* ok, copy the text with byte expansion */ 1288 for (p = bp; *t != '\0'; ) 1289 { 1290 register int c = (*t++ & 0xff); 1291 1292 /* ASCII dependence here -- this is the way the spec words it */ 1293 if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' || 1294 strchr(taboo, c) != NULL) 1295 { 1296 *p++ = '+'; 1297 *p++ = "0123456789abcdef"[c >> 4]; 1298 *p++ = "0123456789abcdef"[c & 0xf]; 1299 } 1300 else 1301 *p++ = c; 1302 } 1303 *p = '\0'; 1304 return bp; 1305 } 1306 /* 1307 ** XUNTEXTIFY -- take xtext and turn it into plain text 1308 ** 1309 ** Parameters: 1310 ** t -- the xtextified text. 1311 ** 1312 ** Returns: 1313 ** The decoded text. No attempt is made to deal with 1314 ** null strings in the resulting text. 1315 */ 1316 1317 char * 1318 xuntextify(t) 1319 register char *t; 1320 { 1321 register char *p; 1322 int l; 1323 static char *bp = NULL; 1324 static int bplen = 0; 1325 1326 /* heuristic -- if no plus sign, just return the input */ 1327 if (strchr(t, '+') == NULL) 1328 return t; 1329 1330 /* xtext is always longer than decoded text */ 1331 l = strlen(t); 1332 if (l > bplen) 1333 { 1334 if (bp != NULL) 1335 free(bp); 1336 bp = xalloc(l); 1337 bplen = l; 1338 } 1339 1340 /* ok, copy the text with byte compression */ 1341 for (p = bp; *t != '\0'; t++) 1342 { 1343 register int c = *t & 0xff; 1344 1345 if (c != '+') 1346 { 1347 *p++ = c; 1348 continue; 1349 } 1350 1351 c = *++t & 0xff; 1352 if (!isascii(c) || !isxdigit(c)) 1353 { 1354 /* error -- first digit is not hex */ 1355 usrerr("bogus xtext: +%c", c); 1356 t--; 1357 continue; 1358 } 1359 if (isdigit(c)) 1360 c -= '0'; 1361 else if (isupper(c)) 1362 c -= 'A' - 10; 1363 else 1364 c -= 'a' - 10; 1365 *p = c << 4; 1366 1367 c = *++t & 0xff; 1368 if (!isascii(c) || !isxdigit(c)) 1369 { 1370 /* error -- second digit is not hex */ 1371 usrerr("bogus xtext: +%x%c", *p >> 4, c); 1372 t--; 1373 continue; 1374 } 1375 if (isdigit(c)) 1376 c -= '0'; 1377 else if (isupper(c)) 1378 c -= 'A' - 10; 1379 else 1380 c -= 'a' - 10; 1381 *p++ |= c; 1382 } 1383 *p = '\0'; 1384 return bp; 1385 } 1386 /* 1387 ** XTEXTOK -- check if a string is legal xtext 1388 ** 1389 ** Xtext is used in Delivery Status Notifications. The spec was 1390 ** taken from RFC 1891, ``SMTP Service Extension for Delivery 1391 ** Status Notifications''. 1392 ** 1393 ** Parameters: 1394 ** s -- the string to check. 1395 ** 1396 ** Returns: 1397 ** TRUE -- if 's' is legal xtext. 1398 ** FALSE -- if it has any illegal characters in it. 1399 */ 1400 1401 bool 1402 xtextok(s) 1403 char *s; 1404 { 1405 int c; 1406 1407 while ((c = *s++) != '\0') 1408 { 1409 if (c == '+') 1410 { 1411 c = *s++; 1412 if (!isascii(c) || !isxdigit(c)) 1413 return FALSE; 1414 c = *s++; 1415 if (!isascii(c) || !isxdigit(c)) 1416 return FALSE; 1417 } 1418 else if (c < '!' || c > '~' || c == '=') 1419 return FALSE; 1420 } 1421 return TRUE; 1422 } 1423 /* 1424 ** PRUNEROUTE -- prune an RFC-822 source route 1425 ** 1426 ** Trims down a source route to the last internet-registered hop. 1427 ** This is encouraged by RFC 1123 section 5.3.3. 1428 ** 1429 ** Parameters: 1430 ** addr -- the address 1431 ** 1432 ** Returns: 1433 ** TRUE -- address was modified 1434 ** FALSE -- address could not be pruned 1435 ** 1436 ** Side Effects: 1437 ** modifies addr in-place 1438 */ 1439 1440 bool 1441 pruneroute(addr) 1442 char *addr; 1443 { 1444 #if NAMED_BIND 1445 char *start, *at, *comma; 1446 char c; 1447 int rcode; 1448 int i; 1449 char hostbuf[BUFSIZ]; 1450 char *mxhosts[MAXMXHOSTS + 1]; 1451 1452 /* check to see if this is really a route-addr */ 1453 if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>') 1454 return FALSE; 1455 start = strchr(addr, ':'); 1456 at = strrchr(addr, '@'); 1457 if (start == NULL || at == NULL || at < start) 1458 return FALSE; 1459 1460 /* slice off the angle brackets */ 1461 i = strlen(at + 1); 1462 if (i >= (SIZE_T) sizeof hostbuf) 1463 return FALSE; 1464 strcpy(hostbuf, at + 1); 1465 hostbuf[i - 1] = '\0'; 1466 1467 while (start) 1468 { 1469 if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0) 1470 { 1471 strcpy(addr + 1, start + 1); 1472 return TRUE; 1473 } 1474 c = *start; 1475 *start = '\0'; 1476 comma = strrchr(addr, ','); 1477 if (comma != NULL && comma[1] == '@' && 1478 strlen(comma + 2) < (SIZE_T) sizeof hostbuf) 1479 strcpy(hostbuf, comma + 2); 1480 else 1481 comma = NULL; 1482 *start = c; 1483 start = comma; 1484 } 1485 #endif 1486 return FALSE; 1487 } 1488