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