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.5 2000/08/22 22:46:00 gshapiro 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 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", MyHostName); 1019 putline(buf, mci); 1020 1021 /* DSN-Gateway: not relevant since we are not translating */ 1022 1023 /* Received-From-MTA: shows where we got this message from */ 1024 if (RealHostName != NULL) 1025 { 1026 /* XXX use $s for type? */ 1027 if (e->e_parent->e_from.q_mailer == NULL || 1028 (p = e->e_parent->e_from.q_mailer->m_mtatype) == NULL) 1029 p = "dns"; 1030 (void) snprintf(buf, sizeof buf, 1031 "Received-From-MTA: %s; %.800s", 1032 p, RealHostName); 1033 putline(buf, mci); 1034 } 1035 1036 /* Arrival-Date: -- when it arrived here */ 1037 (void) snprintf(buf, sizeof buf, "Arrival-Date: %s", 1038 arpadate(ctime(&e->e_parent->e_ctime))); 1039 putline(buf, mci); 1040 1041 /* 1042 ** Output per-address information. 1043 */ 1044 1045 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 1046 { 1047 register ADDRESS *r; 1048 char *action; 1049 1050 if (QS_IS_BADADDR(q->q_state)) 1051 action = "failed"; 1052 else if (!bitset(QPRIMARY, q->q_flags)) 1053 continue; 1054 else if (bitset(QDELIVERED, q->q_flags)) 1055 { 1056 if (bitset(QEXPANDED, q->q_flags)) 1057 action = "delivered (to mailing list)"; 1058 else 1059 action = "delivered (to mailbox)"; 1060 } 1061 else if (bitset(QRELAYED, q->q_flags)) 1062 action = "relayed (to non-DSN-aware mailer)"; 1063 else if (bitset(QEXPANDED, q->q_flags)) 1064 action = "expanded (to multi-recipient alias)"; 1065 else if (bitset(QDELAYED, q->q_flags)) 1066 action = "delayed"; 1067 else 1068 continue; 1069 1070 putline("", mci); 1071 1072 /* Original-Recipient: -- passed from on high */ 1073 if (q->q_orcpt != NULL) 1074 { 1075 (void) snprintf(buf, sizeof buf, 1076 "Original-Recipient: %.800s", 1077 q->q_orcpt); 1078 putline(buf, mci); 1079 } 1080 1081 /* Final-Recipient: -- the name from the RCPT command */ 1082 p = e->e_parent->e_from.q_mailer->m_addrtype; 1083 if (p == NULL) 1084 p = "rfc822"; 1085 for (r = q; r->q_alias != NULL; r = r->q_alias) 1086 continue; 1087 if (strcasecmp(p, "rfc822") != 0) 1088 { 1089 (void) snprintf(buf, sizeof buf, 1090 "Final-Recipient: %s; %.800s", 1091 r->q_mailer->m_addrtype, 1092 r->q_user); 1093 } 1094 else if (strchr(r->q_user, '@') != NULL) 1095 { 1096 (void) snprintf(buf, sizeof buf, 1097 "Final-Recipient: %s; %.800s", 1098 p, r->q_user); 1099 } 1100 else if (strchr(r->q_paddr, '@') != NULL) 1101 { 1102 char *qp; 1103 bool b; 1104 1105 qp = r->q_paddr; 1106 /* strip brackets from address */ 1107 b = FALSE; 1108 if (*qp == '<') 1109 { 1110 b = qp[strlen(qp) - 1] == '>'; 1111 if (b) 1112 qp[strlen(qp) - 1] = '\0'; 1113 qp++; 1114 } 1115 (void) snprintf(buf, sizeof buf, 1116 "Final-Recipient: %s; %.800s", 1117 p, qp); 1118 /* undo damage */ 1119 if (b) 1120 qp[strlen(qp)] = '>'; 1121 } 1122 else 1123 { 1124 (void) snprintf(buf, sizeof buf, 1125 "Final-Recipient: %s; %.700s@%.100s", 1126 p, r->q_user, MyHostName); 1127 } 1128 putline(buf, mci); 1129 1130 /* X-Actual-Recipient: -- the real problem address */ 1131 if (r != q && q->q_user[0] != '\0') 1132 { 1133 if (q->q_mailer != NULL && 1134 q->q_mailer->m_addrtype != NULL) 1135 p = q->q_mailer->m_addrtype; 1136 else 1137 p = "rfc822"; 1138 1139 if (strcasecmp(p, "rfc822") == 0 && 1140 strchr(q->q_user, '@') == NULL) 1141 { 1142 (void) snprintf(buf, sizeof buf, 1143 "X-Actual-Recipient: %s; %.700s@%.100s", 1144 p, q->q_user, 1145 MyHostName); 1146 } 1147 else 1148 { 1149 (void) snprintf(buf, sizeof buf, 1150 "X-Actual-Recipient: %s; %.800s", 1151 p, q->q_user); 1152 } 1153 putline(buf, mci); 1154 } 1155 1156 /* Action: -- what happened? */ 1157 snprintf(buf, sizeof buf, "Action: %s", action); 1158 putline(buf, mci); 1159 1160 /* Status: -- what _really_ happened? */ 1161 if (q->q_status != NULL) 1162 p = q->q_status; 1163 else if (QS_IS_BADADDR(q->q_state)) 1164 p = "5.0.0"; 1165 else if (QS_IS_QUEUEUP(q->q_state)) 1166 p = "4.0.0"; 1167 else 1168 p = "2.0.0"; 1169 snprintf(buf, sizeof buf, "Status: %s", p); 1170 putline(buf, mci); 1171 1172 /* Remote-MTA: -- who was I talking to? */ 1173 if (q->q_statmta != NULL) 1174 { 1175 if (q->q_mailer == NULL || 1176 (p = q->q_mailer->m_mtatype) == NULL) 1177 p = "dns"; 1178 (void) snprintf(buf, sizeof buf, 1179 "Remote-MTA: %s; %.800s", 1180 p, q->q_statmta); 1181 p = &buf[strlen(buf) - 1]; 1182 if (*p == '.') 1183 *p = '\0'; 1184 putline(buf, mci); 1185 } 1186 1187 /* Diagnostic-Code: -- actual result from other end */ 1188 if (q->q_rstatus != NULL) 1189 { 1190 p = q->q_mailer->m_diagtype; 1191 if (p == NULL) 1192 p = "smtp"; 1193 (void) snprintf(buf, sizeof buf, 1194 "Diagnostic-Code: %s; %.800s", 1195 p, q->q_rstatus); 1196 putline(buf, mci); 1197 } 1198 1199 /* Last-Attempt-Date: -- fine granularity */ 1200 if (q->q_statdate == (time_t) 0L) 1201 q->q_statdate = curtime(); 1202 (void) snprintf(buf, sizeof buf, 1203 "Last-Attempt-Date: %s", 1204 arpadate(ctime(&q->q_statdate))); 1205 putline(buf, mci); 1206 1207 /* Will-Retry-Until: -- for delayed messages only */ 1208 if (QS_IS_QUEUEUP(q->q_state)) 1209 { 1210 time_t xdate; 1211 1212 xdate = e->e_parent->e_ctime + 1213 TimeOuts.to_q_return[e->e_parent->e_timeoutclass]; 1214 snprintf(buf, sizeof buf, 1215 "Will-Retry-Until: %s", 1216 arpadate(ctime(&xdate))); 1217 putline(buf, mci); 1218 } 1219 } 1220 } 1221 #endif /* DSN */ 1222 1223 /* 1224 ** Output text of original message 1225 */ 1226 1227 putline("", mci); 1228 if (bitset(EF_HAS_DF, e->e_parent->e_flags)) 1229 { 1230 sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) && 1231 !bitset(EF_NO_BODY_RETN, e->e_flags); 1232 1233 if (e->e_msgboundary == NULL) 1234 { 1235 if (sendbody) 1236 putline(" ----- Original message follows -----\n", mci); 1237 else 1238 putline(" ----- Message header follows -----\n", mci); 1239 } 1240 else 1241 { 1242 (void) snprintf(buf, sizeof buf, "--%s", 1243 e->e_msgboundary); 1244 1245 putline(buf, mci); 1246 (void) snprintf(buf, sizeof buf, "Content-Type: %s", 1247 sendbody ? "message/rfc822" 1248 : "text/rfc822-headers"); 1249 putline(buf, mci); 1250 1251 p = hvalue("Content-Transfer-Encoding", 1252 e->e_parent->e_header); 1253 if (p != NULL && strcasecmp(p, "binary") != 0) 1254 p = NULL; 1255 if (p == NULL && 1256 bitset(EF_HAS8BIT, e->e_parent->e_flags)) 1257 p = "8bit"; 1258 if (p != NULL) 1259 { 1260 (void) snprintf(buf, sizeof buf, 1261 "Content-Transfer-Encoding: %s", 1262 p); 1263 putline(buf, mci); 1264 } 1265 } 1266 putline("", mci); 1267 save_errno = errno; 1268 putheader(mci, e->e_parent->e_header, e->e_parent, M87F_OUTER); 1269 errno = save_errno; 1270 if (sendbody) 1271 putbody(mci, e->e_parent, e->e_msgboundary); 1272 else if (e->e_msgboundary == NULL) 1273 { 1274 putline("", mci); 1275 putline(" ----- Message body suppressed -----", mci); 1276 } 1277 } 1278 else if (e->e_msgboundary == NULL) 1279 { 1280 putline(" ----- No message was collected -----\n", mci); 1281 } 1282 1283 if (e->e_msgboundary != NULL) 1284 { 1285 putline("", mci); 1286 (void) snprintf(buf, sizeof buf, "--%s--", e->e_msgboundary); 1287 putline(buf, mci); 1288 } 1289 putline("", mci); 1290 (void) fflush(mci->mci_out); 1291 1292 /* 1293 ** Cleanup and exit 1294 */ 1295 1296 if (errno != 0) 1297 syserr("errbody: I/O error"); 1298 } 1299 /* 1300 ** SMTPTODSN -- convert SMTP to DSN status code 1301 ** 1302 ** Parameters: 1303 ** smtpstat -- the smtp status code (e.g., 550). 1304 ** 1305 ** Returns: 1306 ** The DSN version of the status code. 1307 */ 1308 1309 char * 1310 smtptodsn(smtpstat) 1311 int smtpstat; 1312 { 1313 if (smtpstat < 0) 1314 return "4.4.2"; 1315 1316 switch (smtpstat) 1317 { 1318 case 450: /* Req mail action not taken: mailbox unavailable */ 1319 return "4.2.0"; 1320 1321 case 451: /* Req action aborted: local error in processing */ 1322 return "4.3.0"; 1323 1324 case 452: /* Req action not taken: insufficient sys storage */ 1325 return "4.3.1"; 1326 1327 case 500: /* Syntax error, command unrecognized */ 1328 return "5.5.2"; 1329 1330 case 501: /* Syntax error in parameters or arguments */ 1331 return "5.5.4"; 1332 1333 case 502: /* Command not implemented */ 1334 return "5.5.1"; 1335 1336 case 503: /* Bad sequence of commands */ 1337 return "5.5.1"; 1338 1339 case 504: /* Command parameter not implemented */ 1340 return "5.5.4"; 1341 1342 case 550: /* Req mail action not taken: mailbox unavailable */ 1343 return "5.2.0"; 1344 1345 case 551: /* User not local; please try <...> */ 1346 return "5.1.6"; 1347 1348 case 552: /* Req mail action aborted: exceeded storage alloc */ 1349 return "5.2.2"; 1350 1351 case 553: /* Req action not taken: mailbox name not allowed */ 1352 return "5.1.0"; 1353 1354 case 554: /* Transaction failed */ 1355 return "5.0.0"; 1356 } 1357 1358 if ((smtpstat / 100) == 2) 1359 return "2.0.0"; 1360 if ((smtpstat / 100) == 4) 1361 return "4.0.0"; 1362 return "5.0.0"; 1363 } 1364 /* 1365 ** XTEXTIFY -- take regular text and turn it into DSN-style xtext 1366 ** 1367 ** Parameters: 1368 ** t -- the text to convert. 1369 ** taboo -- additional characters that must be encoded. 1370 ** 1371 ** Returns: 1372 ** The xtext-ified version of the same string. 1373 */ 1374 1375 char * 1376 xtextify(t, taboo) 1377 register char *t; 1378 char *taboo; 1379 { 1380 register char *p; 1381 int l; 1382 int nbogus; 1383 static char *bp = NULL; 1384 static int bplen = 0; 1385 1386 if (taboo == NULL) 1387 taboo = ""; 1388 1389 /* figure out how long this xtext will have to be */ 1390 nbogus = l = 0; 1391 for (p = t; *p != '\0'; p++) 1392 { 1393 register int c = (*p & 0xff); 1394 1395 /* ASCII dependence here -- this is the way the spec words it */ 1396 if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' || 1397 strchr(taboo, c) != NULL) 1398 nbogus++; 1399 l++; 1400 } 1401 if (nbogus == 0) 1402 return t; 1403 l += nbogus * 2 + 1; 1404 1405 /* now allocate space if necessary for the new string */ 1406 if (l > bplen) 1407 { 1408 if (bp != NULL) 1409 free(bp); 1410 bp = xalloc(l); 1411 bplen = l; 1412 } 1413 1414 /* ok, copy the text with byte expansion */ 1415 for (p = bp; *t != '\0'; ) 1416 { 1417 register int c = (*t++ & 0xff); 1418 1419 /* ASCII dependence here -- this is the way the spec words it */ 1420 if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' || 1421 strchr(taboo, c) != NULL) 1422 { 1423 *p++ = '+'; 1424 *p++ = "0123456789ABCDEF"[c >> 4]; 1425 *p++ = "0123456789ABCDEF"[c & 0xf]; 1426 } 1427 else 1428 *p++ = c; 1429 } 1430 *p = '\0'; 1431 return bp; 1432 } 1433 /* 1434 ** XUNTEXTIFY -- take xtext and turn it into plain text 1435 ** 1436 ** Parameters: 1437 ** t -- the xtextified text. 1438 ** 1439 ** Returns: 1440 ** The decoded text. No attempt is made to deal with 1441 ** null strings in the resulting text. 1442 */ 1443 1444 char * 1445 xuntextify(t) 1446 register char *t; 1447 { 1448 register char *p; 1449 int l; 1450 static char *bp = NULL; 1451 static int bplen = 0; 1452 1453 /* heuristic -- if no plus sign, just return the input */ 1454 if (strchr(t, '+') == NULL) 1455 return t; 1456 1457 /* xtext is always longer than decoded text */ 1458 l = strlen(t); 1459 if (l > bplen) 1460 { 1461 if (bp != NULL) 1462 free(bp); 1463 bp = xalloc(l); 1464 bplen = l; 1465 } 1466 1467 /* ok, copy the text with byte compression */ 1468 for (p = bp; *t != '\0'; t++) 1469 { 1470 register int c = *t & 0xff; 1471 1472 if (c != '+') 1473 { 1474 *p++ = c; 1475 continue; 1476 } 1477 1478 c = *++t & 0xff; 1479 if (!isascii(c) || !isxdigit(c)) 1480 { 1481 /* error -- first digit is not hex */ 1482 usrerr("bogus xtext: +%c", c); 1483 t--; 1484 continue; 1485 } 1486 if (isdigit(c)) 1487 c -= '0'; 1488 else if (isupper(c)) 1489 c -= 'A' - 10; 1490 else 1491 c -= 'a' - 10; 1492 *p = c << 4; 1493 1494 c = *++t & 0xff; 1495 if (!isascii(c) || !isxdigit(c)) 1496 { 1497 /* error -- second digit is not hex */ 1498 usrerr("bogus xtext: +%x%c", *p >> 4, c); 1499 t--; 1500 continue; 1501 } 1502 if (isdigit(c)) 1503 c -= '0'; 1504 else if (isupper(c)) 1505 c -= 'A' - 10; 1506 else 1507 c -= 'a' - 10; 1508 *p++ |= c; 1509 } 1510 *p = '\0'; 1511 return bp; 1512 } 1513 /* 1514 ** XTEXTOK -- check if a string is legal xtext 1515 ** 1516 ** Xtext is used in Delivery Status Notifications. The spec was 1517 ** taken from RFC 1891, ``SMTP Service Extension for Delivery 1518 ** Status Notifications''. 1519 ** 1520 ** Parameters: 1521 ** s -- the string to check. 1522 ** 1523 ** Returns: 1524 ** TRUE -- if 's' is legal xtext. 1525 ** FALSE -- if it has any illegal characters in it. 1526 */ 1527 1528 bool 1529 xtextok(s) 1530 char *s; 1531 { 1532 int c; 1533 1534 while ((c = *s++) != '\0') 1535 { 1536 if (c == '+') 1537 { 1538 c = *s++; 1539 if (!isascii(c) || !isxdigit(c)) 1540 return FALSE; 1541 c = *s++; 1542 if (!isascii(c) || !isxdigit(c)) 1543 return FALSE; 1544 } 1545 else if (c < '!' || c > '~' || c == '=') 1546 return FALSE; 1547 } 1548 return TRUE; 1549 } 1550 /* 1551 ** PRUNEROUTE -- prune an RFC-822 source route 1552 ** 1553 ** Trims down a source route to the last internet-registered hop. 1554 ** This is encouraged by RFC 1123 section 5.3.3. 1555 ** 1556 ** Parameters: 1557 ** addr -- the address 1558 ** 1559 ** Returns: 1560 ** TRUE -- address was modified 1561 ** FALSE -- address could not be pruned 1562 ** 1563 ** Side Effects: 1564 ** modifies addr in-place 1565 */ 1566 1567 static bool 1568 pruneroute(addr) 1569 char *addr; 1570 { 1571 #if NAMED_BIND 1572 char *start, *at, *comma; 1573 char c; 1574 int rcode; 1575 int i; 1576 char hostbuf[BUFSIZ]; 1577 char *mxhosts[MAXMXHOSTS + 1]; 1578 1579 /* check to see if this is really a route-addr */ 1580 if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>') 1581 return FALSE; 1582 start = strchr(addr, ':'); 1583 at = strrchr(addr, '@'); 1584 if (start == NULL || at == NULL || at < start) 1585 return FALSE; 1586 1587 /* slice off the angle brackets */ 1588 i = strlen(at + 1); 1589 if (i >= (SIZE_T) sizeof hostbuf) 1590 return FALSE; 1591 (void) strlcpy(hostbuf, at + 1, sizeof hostbuf); 1592 hostbuf[i - 1] = '\0'; 1593 1594 while (start) 1595 { 1596 if (getmxrr(hostbuf, mxhosts, NULL, FALSE, &rcode) > 0) 1597 { 1598 (void) strlcpy(addr + 1, start + 1, strlen(addr) - 1); 1599 return TRUE; 1600 } 1601 c = *start; 1602 *start = '\0'; 1603 comma = strrchr(addr, ','); 1604 if (comma != NULL && comma[1] == '@' && 1605 strlen(comma + 2) < (SIZE_T) sizeof hostbuf) 1606 (void) strlcpy(hostbuf, comma + 2, sizeof hostbuf); 1607 else 1608 comma = NULL; 1609 *start = c; 1610 start = comma; 1611 } 1612 #endif /* NAMED_BIND */ 1613 return FALSE; 1614 } 1615