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