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