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