1 /* 2 * Copyright (c) 1998-2004, 2006 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 #pragma ident "%Z%%M% %I% %E% SMI" 15 16 #include <sendmail.h> 17 18 SM_RCSID("@(#)$Id: headers.c,v 8.290 2006/02/25 02:16:52 ca Exp $") 19 20 static HDR *allocheader __P((char *, char *, int, SM_RPOOL_T *)); 21 static size_t fix_mime_header __P((HDR *, ENVELOPE *)); 22 static int priencode __P((char *)); 23 static bool put_vanilla_header __P((HDR *, char *, MCI *)); 24 25 /* 26 ** SETUPHEADERS -- initialize headers in symbol table 27 ** 28 ** Parameters: 29 ** none 30 ** 31 ** Returns: 32 ** none 33 */ 34 35 void 36 setupheaders() 37 { 38 struct hdrinfo *hi; 39 STAB *s; 40 41 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 42 { 43 s = stab(hi->hi_field, ST_HEADER, ST_ENTER); 44 s->s_header.hi_flags = hi->hi_flags; 45 s->s_header.hi_ruleset = NULL; 46 } 47 } 48 /* 49 ** CHOMPHEADER -- process and save a header line. 50 ** 51 ** Called by collect, readcf, and readqf to deal with header lines. 52 ** 53 ** Parameters: 54 ** line -- header as a text line. 55 ** pflag -- flags for chompheader() (from sendmail.h) 56 ** hdrp -- a pointer to the place to save the header. 57 ** e -- the envelope including this header. 58 ** 59 ** Returns: 60 ** flags for this header. 61 ** 62 ** Side Effects: 63 ** The header is saved on the header list. 64 ** Contents of 'line' are destroyed. 65 */ 66 67 static struct hdrinfo NormalHeader = { NULL, 0, NULL }; 68 69 unsigned long 70 chompheader(line, pflag, hdrp, e) 71 char *line; 72 int pflag; 73 HDR **hdrp; 74 register ENVELOPE *e; 75 { 76 unsigned char mid = '\0'; 77 register char *p; 78 register HDR *h; 79 HDR **hp; 80 char *fname; 81 char *fvalue; 82 bool cond = false; 83 bool dropfrom; 84 bool headeronly; 85 STAB *s; 86 struct hdrinfo *hi; 87 bool nullheader = false; 88 BITMAP256 mopts; 89 90 if (tTd(31, 6)) 91 { 92 sm_dprintf("chompheader: "); 93 xputs(sm_debug_file(), line); 94 sm_dprintf("\n"); 95 } 96 97 headeronly = hdrp != NULL; 98 if (!headeronly) 99 hdrp = &e->e_header; 100 101 /* strip off options */ 102 clrbitmap(mopts); 103 p = line; 104 if (!bitset(pflag, CHHDR_USER) && *p == '?') 105 { 106 int c; 107 register char *q; 108 109 q = strchr(++p, '?'); 110 if (q == NULL) 111 goto hse; 112 113 *q = '\0'; 114 c = *p & 0377; 115 116 /* possibly macro conditional */ 117 if (c == MACROEXPAND) 118 { 119 /* catch ?$? */ 120 if (*++p == '\0') 121 { 122 *q = '?'; 123 goto hse; 124 } 125 126 mid = (unsigned char) *p++; 127 128 /* catch ?$abc? */ 129 if (*p != '\0') 130 { 131 *q = '?'; 132 goto hse; 133 } 134 } 135 else if (*p == '$') 136 { 137 /* catch ?$? */ 138 if (*++p == '\0') 139 { 140 *q = '?'; 141 goto hse; 142 } 143 144 mid = (unsigned char) macid(p); 145 if (bitset(0200, mid)) 146 { 147 p += strlen(macname(mid)) + 2; 148 SM_ASSERT(p <= q); 149 } 150 else 151 p++; 152 153 /* catch ?$abc? */ 154 if (*p != '\0') 155 { 156 *q = '?'; 157 goto hse; 158 } 159 } 160 else 161 { 162 while (*p != '\0') 163 { 164 if (!isascii(*p)) 165 { 166 *q = '?'; 167 goto hse; 168 } 169 170 setbitn(bitidx(*p), mopts); 171 cond = true; 172 p++; 173 } 174 } 175 p = q + 1; 176 } 177 178 /* find canonical name */ 179 fname = p; 180 while (isascii(*p) && isgraph(*p) && *p != ':') 181 p++; 182 fvalue = p; 183 while (isascii(*p) && isspace(*p)) 184 p++; 185 if (*p++ != ':' || fname == fvalue) 186 { 187 hse: 188 syserr("553 5.3.0 header syntax error, line \"%s\"", line); 189 return 0; 190 } 191 *fvalue = '\0'; 192 193 /* strip field value on front */ 194 if (*p == ' ') 195 p++; 196 fvalue = p; 197 198 /* if the field is null, go ahead and use the default */ 199 while (isascii(*p) && isspace(*p)) 200 p++; 201 if (*p == '\0') 202 nullheader = true; 203 204 /* security scan: long field names are end-of-header */ 205 if (strlen(fname) > 100) 206 return H_EOH; 207 208 /* check to see if it represents a ruleset call */ 209 if (bitset(pflag, CHHDR_DEF)) 210 { 211 char hbuf[50]; 212 213 (void) expand(fvalue, hbuf, sizeof hbuf, e); 214 for (p = hbuf; isascii(*p) && isspace(*p); ) 215 p++; 216 if ((*p++ & 0377) == CALLSUBR) 217 { 218 auto char *endp; 219 bool strc; 220 221 strc = *p == '+'; /* strip comments? */ 222 if (strc) 223 ++p; 224 if (strtorwset(p, &endp, ST_ENTER) > 0) 225 { 226 *endp = '\0'; 227 s = stab(fname, ST_HEADER, ST_ENTER); 228 if (LogLevel > 9 && 229 s->s_header.hi_ruleset != NULL) 230 sm_syslog(LOG_WARNING, NOQID, 231 "Warning: redefined ruleset for header=%s, old=%s, new=%s", 232 fname, 233 s->s_header.hi_ruleset, p); 234 s->s_header.hi_ruleset = newstr(p); 235 if (!strc) 236 s->s_header.hi_flags |= H_STRIPCOMM; 237 } 238 return 0; 239 } 240 } 241 242 /* see if it is a known type */ 243 s = stab(fname, ST_HEADER, ST_FIND); 244 if (s != NULL) 245 hi = &s->s_header; 246 else 247 hi = &NormalHeader; 248 249 if (tTd(31, 9)) 250 { 251 if (s == NULL) 252 sm_dprintf("no header flags match\n"); 253 else 254 sm_dprintf("header match, flags=%lx, ruleset=%s\n", 255 hi->hi_flags, 256 hi->hi_ruleset == NULL ? "<NULL>" 257 : hi->hi_ruleset); 258 } 259 260 /* see if this is a resent message */ 261 if (!bitset(pflag, CHHDR_DEF) && !headeronly && 262 bitset(H_RESENT, hi->hi_flags)) 263 e->e_flags |= EF_RESENT; 264 265 /* if this is an Errors-To: header keep track of it now */ 266 if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly && 267 bitset(H_ERRORSTO, hi->hi_flags)) 268 (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 269 270 /* if this means "end of header" quit now */ 271 if (!headeronly && bitset(H_EOH, hi->hi_flags)) 272 return hi->hi_flags; 273 274 /* 275 ** Horrible hack to work around problem with Lotus Notes SMTP 276 ** mail gateway, which generates From: headers with newlines in 277 ** them and the <address> on the second line. Although this is 278 ** legal RFC 822, many MUAs don't handle this properly and thus 279 ** never find the actual address. 280 */ 281 282 if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader) 283 { 284 while ((p = strchr(fvalue, '\n')) != NULL) 285 *p = ' '; 286 } 287 288 /* 289 ** If there is a check ruleset, verify it against the header. 290 */ 291 292 if (bitset(pflag, CHHDR_CHECK)) 293 { 294 int rscheckflags; 295 char *rs; 296 297 rscheckflags = RSF_COUNT; 298 if (!bitset(hi->hi_flags, H_FROM|H_RCPT)) 299 rscheckflags |= RSF_UNSTRUCTURED; 300 301 /* no ruleset? look for default */ 302 rs = hi->hi_ruleset; 303 if (rs == NULL) 304 { 305 s = stab("*", ST_HEADER, ST_FIND); 306 if (s != NULL) 307 { 308 rs = (&s->s_header)->hi_ruleset; 309 if (bitset((&s->s_header)->hi_flags, 310 H_STRIPCOMM)) 311 rscheckflags |= RSF_RMCOMM; 312 } 313 } 314 else if (bitset(hi->hi_flags, H_STRIPCOMM)) 315 rscheckflags |= RSF_RMCOMM; 316 if (rs != NULL) 317 { 318 int l, k; 319 char qval[MAXNAME]; 320 321 l = 0; 322 qval[l++] = '"'; 323 324 /* - 3 to avoid problems with " at the end */ 325 /* should be sizeof(qval), not MAXNAME */ 326 for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++) 327 { 328 switch (fvalue[k]) 329 { 330 /* XXX other control chars? */ 331 case '\011': /* ht */ 332 case '\012': /* nl */ 333 case '\013': /* vt */ 334 case '\014': /* np */ 335 case '\015': /* cr */ 336 qval[l++] = ' '; 337 break; 338 case '"': 339 qval[l++] = '\\'; 340 /* FALLTHROUGH */ 341 default: 342 qval[l++] = fvalue[k]; 343 break; 344 } 345 } 346 qval[l++] = '"'; 347 qval[l] = '\0'; 348 k += strlen(fvalue + k); 349 if (k >= MAXNAME) 350 { 351 if (LogLevel > 9) 352 sm_syslog(LOG_WARNING, e->e_id, 353 "Warning: truncated header '%s' before check with '%s' len=%d max=%d", 354 fname, rs, k, MAXNAME - 1); 355 } 356 macdefine(&e->e_macro, A_TEMP, 357 macid("{currHeader}"), qval); 358 macdefine(&e->e_macro, A_TEMP, 359 macid("{hdr_name}"), fname); 360 361 (void) sm_snprintf(qval, sizeof qval, "%d", k); 362 macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval); 363 #if _FFR_HDR_TYPE 364 if (bitset(H_FROM, hi->hi_flags)) 365 macdefine(&e->e_macro, A_PERM, 366 macid("{addr_type}"), "h s"); 367 else if (bitset(H_RCPT, hi->hi_flags)) 368 macdefine(&e->e_macro, A_PERM, 369 macid("{addr_type}"), "h r"); 370 else 371 #endif /* _FFR_HDR_TYPE */ 372 macdefine(&e->e_macro, A_PERM, 373 macid("{addr_type}"), "h"); 374 (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3, 375 NULL, e->e_id); 376 } 377 } 378 379 /* 380 ** Drop explicit From: if same as what we would generate. 381 ** This is to make MH (which doesn't always give a full name) 382 ** insert the full name information in all circumstances. 383 */ 384 385 dropfrom = false; 386 p = "resent-from"; 387 if (!bitset(EF_RESENT, e->e_flags)) 388 p += 7; 389 if (!bitset(pflag, CHHDR_DEF) && !headeronly && 390 !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0) 391 { 392 if (tTd(31, 2)) 393 { 394 sm_dprintf("comparing header from (%s) against default (%s or %s)\n", 395 fvalue, e->e_from.q_paddr, e->e_from.q_user); 396 } 397 if (e->e_from.q_paddr != NULL && 398 e->e_from.q_mailer != NULL && 399 bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && 400 (strcmp(fvalue, e->e_from.q_paddr) == 0 || 401 strcmp(fvalue, e->e_from.q_user) == 0)) 402 dropfrom = true; 403 } 404 405 /* delete default value for this header */ 406 for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 407 { 408 if (sm_strcasecmp(fname, h->h_field) == 0 && 409 !bitset(H_USER, h->h_flags) && 410 !bitset(H_FORCE, h->h_flags)) 411 { 412 if (nullheader) 413 { 414 /* user-supplied value was null */ 415 return 0; 416 } 417 if (dropfrom) 418 { 419 /* make this look like the user entered it */ 420 h->h_flags |= H_USER; 421 return hi->hi_flags; 422 } 423 h->h_value = NULL; 424 if (!cond) 425 { 426 /* copy conditions from default case */ 427 memmove((char *) mopts, (char *) h->h_mflags, 428 sizeof mopts); 429 } 430 h->h_macro = mid; 431 } 432 } 433 434 /* create a new node */ 435 h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h); 436 h->h_field = sm_rpool_strdup_x(e->e_rpool, fname); 437 h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue); 438 h->h_link = NULL; 439 memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts); 440 h->h_macro = mid; 441 *hp = h; 442 h->h_flags = hi->hi_flags; 443 if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE)) 444 h->h_flags |= H_USER; 445 446 /* strip EOH flag if parsing MIME headers */ 447 if (headeronly) 448 h->h_flags &= ~H_EOH; 449 if (bitset(pflag, CHHDR_DEF)) 450 h->h_flags |= H_DEFAULT; 451 if (cond || mid != '\0') 452 h->h_flags |= H_CHECK; 453 454 /* hack to see if this is a new format message */ 455 if (!bitset(pflag, CHHDR_DEF) && !headeronly && 456 bitset(H_RCPT|H_FROM, h->h_flags) && 457 (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 458 strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 459 { 460 e->e_flags &= ~EF_OLDSTYLE; 461 } 462 463 return h->h_flags; 464 } 465 /* 466 ** ALLOCHEADER -- allocate a header entry 467 ** 468 ** Parameters: 469 ** field -- the name of the header field. 470 ** value -- the value of the field. 471 ** flags -- flags to add to h_flags. 472 ** rp -- resource pool for allocations 473 ** 474 ** Returns: 475 ** Pointer to a newly allocated and populated HDR. 476 */ 477 478 static HDR * 479 allocheader(field, value, flags, rp) 480 char *field; 481 char *value; 482 int flags; 483 SM_RPOOL_T *rp; 484 { 485 HDR *h; 486 STAB *s; 487 488 /* find info struct */ 489 s = stab(field, ST_HEADER, ST_FIND); 490 491 /* allocate space for new header */ 492 h = (HDR *) sm_rpool_malloc_x(rp, sizeof *h); 493 h->h_field = field; 494 h->h_value = sm_rpool_strdup_x(rp, value); 495 h->h_flags = flags; 496 if (s != NULL) 497 h->h_flags |= s->s_header.hi_flags; 498 clrbitmap(h->h_mflags); 499 h->h_macro = '\0'; 500 501 return h; 502 } 503 /* 504 ** ADDHEADER -- add a header entry to the end of the queue. 505 ** 506 ** This bypasses the special checking of chompheader. 507 ** 508 ** Parameters: 509 ** field -- the name of the header field. 510 ** value -- the value of the field. 511 ** flags -- flags to add to h_flags. 512 ** e -- envelope. 513 ** 514 ** Returns: 515 ** none. 516 ** 517 ** Side Effects: 518 ** adds the field on the list of headers for this envelope. 519 */ 520 521 void 522 addheader(field, value, flags, e) 523 char *field; 524 char *value; 525 int flags; 526 ENVELOPE *e; 527 { 528 register HDR *h; 529 HDR **hp; 530 HDR **hdrlist = &e->e_header; 531 532 /* find current place in list -- keep back pointer? */ 533 for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 534 { 535 if (sm_strcasecmp(field, h->h_field) == 0) 536 break; 537 } 538 539 /* allocate space for new header */ 540 h = allocheader(field, value, flags, e->e_rpool); 541 h->h_link = *hp; 542 *hp = h; 543 } 544 /* 545 ** INSHEADER -- insert a header entry at the specified index 546 ** 547 ** This bypasses the special checking of chompheader. 548 ** 549 ** Parameters: 550 ** idx -- index into the header list at which to insert 551 ** field -- the name of the header field. 552 ** value -- the value of the field. 553 ** flags -- flags to add to h_flags. 554 ** e -- envelope. 555 ** 556 ** Returns: 557 ** none. 558 ** 559 ** Side Effects: 560 ** inserts the field on the list of headers for this envelope. 561 */ 562 563 void 564 insheader(idx, field, value, flags, e) 565 int idx; 566 char *field; 567 char *value; 568 int flags; 569 ENVELOPE *e; 570 { 571 HDR *h, *srch, *last = NULL; 572 573 /* allocate space for new header */ 574 h = allocheader(field, value, flags, e->e_rpool); 575 576 /* find insertion position */ 577 for (srch = e->e_header; srch != NULL && idx > 0; 578 srch = srch->h_link, idx--) 579 last = srch; 580 581 if (e->e_header == NULL) 582 { 583 e->e_header = h; 584 h->h_link = NULL; 585 } 586 else if (srch == NULL) 587 { 588 SM_ASSERT(last != NULL); 589 last->h_link = h; 590 h->h_link = NULL; 591 } 592 else 593 { 594 h->h_link = srch->h_link; 595 srch->h_link = h; 596 } 597 } 598 /* 599 ** HVALUE -- return value of a header. 600 ** 601 ** Only "real" fields (i.e., ones that have not been supplied 602 ** as a default) are used. 603 ** 604 ** Parameters: 605 ** field -- the field name. 606 ** header -- the header list. 607 ** 608 ** Returns: 609 ** pointer to the value part. 610 ** NULL if not found. 611 ** 612 ** Side Effects: 613 ** none. 614 */ 615 616 char * 617 hvalue(field, header) 618 char *field; 619 HDR *header; 620 { 621 register HDR *h; 622 623 for (h = header; h != NULL; h = h->h_link) 624 { 625 if (!bitset(H_DEFAULT, h->h_flags) && 626 sm_strcasecmp(h->h_field, field) == 0) 627 return h->h_value; 628 } 629 return NULL; 630 } 631 /* 632 ** ISHEADER -- predicate telling if argument is a header. 633 ** 634 ** A line is a header if it has a single word followed by 635 ** optional white space followed by a colon. 636 ** 637 ** Header fields beginning with two dashes, although technically 638 ** permitted by RFC822, are automatically rejected in order 639 ** to make MIME work out. Without this we could have a technically 640 ** legal header such as ``--"foo:bar"'' that would also be a legal 641 ** MIME separator. 642 ** 643 ** Parameters: 644 ** h -- string to check for possible headerness. 645 ** 646 ** Returns: 647 ** true if h is a header. 648 ** false otherwise. 649 ** 650 ** Side Effects: 651 ** none. 652 */ 653 654 bool 655 isheader(h) 656 char *h; 657 { 658 register char *s = h; 659 660 if (s[0] == '-' && s[1] == '-') 661 return false; 662 663 while (*s > ' ' && *s != ':' && *s != '\0') 664 s++; 665 666 if (h == s) 667 return false; 668 669 /* following technically violates RFC822 */ 670 while (isascii(*s) && isspace(*s)) 671 s++; 672 673 return (*s == ':'); 674 } 675 /* 676 ** EATHEADER -- run through the stored header and extract info. 677 ** 678 ** Parameters: 679 ** e -- the envelope to process. 680 ** full -- if set, do full processing (e.g., compute 681 ** message priority). This should not be set 682 ** when reading a queue file because some info 683 ** needed to compute the priority is wrong. 684 ** log -- call logsender()? 685 ** 686 ** Returns: 687 ** none. 688 ** 689 ** Side Effects: 690 ** Sets a bunch of global variables from information 691 ** in the collected header. 692 */ 693 694 void 695 eatheader(e, full, log) 696 register ENVELOPE *e; 697 bool full; 698 bool log; 699 { 700 register HDR *h; 701 register char *p; 702 int hopcnt = 0; 703 char buf[MAXLINE]; 704 705 /* 706 ** Set up macros for possible expansion in headers. 707 */ 708 709 macdefine(&e->e_macro, A_PERM, 'f', e->e_sender); 710 macdefine(&e->e_macro, A_PERM, 'g', e->e_sender); 711 if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 712 macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt); 713 else 714 macdefine(&e->e_macro, A_PERM, 'u', NULL); 715 716 /* full name of from person */ 717 p = hvalue("full-name", e->e_header); 718 if (p != NULL) 719 { 720 if (!rfc822_string(p)) 721 { 722 /* 723 ** Quote a full name with special characters 724 ** as a comment so crackaddr() doesn't destroy 725 ** the name portion of the address. 726 */ 727 728 p = addquotes(p, e->e_rpool); 729 } 730 macdefine(&e->e_macro, A_PERM, 'x', p); 731 } 732 733 if (tTd(32, 1)) 734 sm_dprintf("----- collected header -----\n"); 735 e->e_msgid = NULL; 736 for (h = e->e_header; h != NULL; h = h->h_link) 737 { 738 if (tTd(32, 1)) 739 sm_dprintf("%s: ", h->h_field); 740 if (h->h_value == NULL) 741 { 742 if (tTd(32, 1)) 743 sm_dprintf("<NULL>\n"); 744 continue; 745 } 746 747 /* do early binding */ 748 if (bitset(H_DEFAULT, h->h_flags) && 749 !bitset(H_BINDLATE, h->h_flags)) 750 { 751 if (tTd(32, 1)) 752 { 753 sm_dprintf("("); 754 xputs(sm_debug_file(), h->h_value); 755 sm_dprintf(") "); 756 } 757 expand(h->h_value, buf, sizeof buf, e); 758 if (buf[0] != '\0') 759 { 760 if (bitset(H_FROM, h->h_flags)) 761 expand(crackaddr(buf, e), 762 buf, sizeof buf, e); 763 h->h_value = sm_rpool_strdup_x(e->e_rpool, buf); 764 h->h_flags &= ~H_DEFAULT; 765 } 766 } 767 if (tTd(32, 1)) 768 { 769 xputs(sm_debug_file(), h->h_value); 770 sm_dprintf("\n"); 771 } 772 773 /* count the number of times it has been processed */ 774 if (bitset(H_TRACE, h->h_flags)) 775 hopcnt++; 776 777 /* send to this person if we so desire */ 778 if (GrabTo && bitset(H_RCPT, h->h_flags) && 779 !bitset(H_DEFAULT, h->h_flags) && 780 (!bitset(EF_RESENT, e->e_flags) || 781 bitset(H_RESENT, h->h_flags))) 782 { 783 #if 0 784 int saveflags = e->e_flags; 785 #endif /* 0 */ 786 787 (void) sendtolist(denlstring(h->h_value, true, false), 788 NULLADDR, &e->e_sendqueue, 0, e); 789 790 #if 0 791 /* 792 ** Change functionality so a fatal error on an 793 ** address doesn't affect the entire envelope. 794 */ 795 796 /* delete fatal errors generated by this address */ 797 if (!bitset(EF_FATALERRS, saveflags)) 798 e->e_flags &= ~EF_FATALERRS; 799 #endif /* 0 */ 800 } 801 802 /* save the message-id for logging */ 803 p = "resent-message-id"; 804 if (!bitset(EF_RESENT, e->e_flags)) 805 p += 7; 806 if (sm_strcasecmp(h->h_field, p) == 0) 807 { 808 e->e_msgid = h->h_value; 809 while (isascii(*e->e_msgid) && isspace(*e->e_msgid)) 810 e->e_msgid++; 811 macdefine(&e->e_macro, A_PERM, macid("{msg_id}"), 812 e->e_msgid); 813 } 814 } 815 if (tTd(32, 1)) 816 sm_dprintf("----------------------------\n"); 817 818 /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 819 if (OpMode == MD_VERIFY) 820 return; 821 822 /* store hop count */ 823 if (hopcnt > e->e_hopcount) 824 { 825 e->e_hopcount = hopcnt; 826 (void) sm_snprintf(buf, sizeof buf, "%d", e->e_hopcount); 827 macdefine(&e->e_macro, A_TEMP, 'c', buf); 828 } 829 830 /* message priority */ 831 p = hvalue("precedence", e->e_header); 832 if (p != NULL) 833 e->e_class = priencode(p); 834 if (e->e_class < 0) 835 e->e_timeoutclass = TOC_NONURGENT; 836 else if (e->e_class > 0) 837 e->e_timeoutclass = TOC_URGENT; 838 if (full) 839 { 840 e->e_msgpriority = e->e_msgsize 841 - e->e_class * WkClassFact 842 + e->e_nrcpts * WkRecipFact; 843 } 844 845 /* check for DSN to properly set e_timeoutclass */ 846 p = hvalue("content-type", e->e_header); 847 if (p != NULL) 848 { 849 bool oldsupr; 850 char **pvp; 851 char pvpbuf[MAXLINE]; 852 extern unsigned char MimeTokenTab[256]; 853 854 /* tokenize header */ 855 oldsupr = SuprErrs; 856 SuprErrs = true; 857 pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, 858 MimeTokenTab, false); 859 SuprErrs = oldsupr; 860 861 /* Check if multipart/report */ 862 if (pvp != NULL && pvp[0] != NULL && 863 pvp[1] != NULL && pvp[2] != NULL && 864 sm_strcasecmp(*pvp++, "multipart") == 0 && 865 strcmp(*pvp++, "/") == 0 && 866 sm_strcasecmp(*pvp++, "report") == 0) 867 { 868 /* Look for report-type=delivery-status */ 869 while (*pvp != NULL) 870 { 871 /* skip to semicolon separator */ 872 while (*pvp != NULL && strcmp(*pvp, ";") != 0) 873 pvp++; 874 875 /* skip semicolon */ 876 if (*pvp++ == NULL || *pvp == NULL) 877 break; 878 879 /* look for report-type */ 880 if (sm_strcasecmp(*pvp++, "report-type") != 0) 881 continue; 882 883 /* skip equal */ 884 if (*pvp == NULL || strcmp(*pvp, "=") != 0) 885 continue; 886 887 /* check value */ 888 if (*++pvp != NULL && 889 sm_strcasecmp(*pvp, 890 "delivery-status") == 0) 891 e->e_timeoutclass = TOC_DSN; 892 893 /* found report-type, no need to continue */ 894 break; 895 } 896 } 897 } 898 899 /* message timeout priority */ 900 p = hvalue("priority", e->e_header); 901 if (p != NULL) 902 { 903 /* (this should be in the configuration file) */ 904 if (sm_strcasecmp(p, "urgent") == 0) 905 e->e_timeoutclass = TOC_URGENT; 906 else if (sm_strcasecmp(p, "normal") == 0) 907 e->e_timeoutclass = TOC_NORMAL; 908 else if (sm_strcasecmp(p, "non-urgent") == 0) 909 e->e_timeoutclass = TOC_NONURGENT; 910 else if (bitset(EF_RESPONSE, e->e_flags)) 911 e->e_timeoutclass = TOC_DSN; 912 } 913 else if (bitset(EF_RESPONSE, e->e_flags)) 914 e->e_timeoutclass = TOC_DSN; 915 916 /* date message originated */ 917 p = hvalue("posted-date", e->e_header); 918 if (p == NULL) 919 p = hvalue("date", e->e_header); 920 if (p != NULL) 921 macdefine(&e->e_macro, A_PERM, 'a', p); 922 923 /* check to see if this is a MIME message */ 924 if ((e->e_bodytype != NULL && 925 sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) || 926 hvalue("MIME-Version", e->e_header) != NULL) 927 { 928 e->e_flags |= EF_IS_MIME; 929 if (HasEightBits) 930 e->e_bodytype = "8BITMIME"; 931 } 932 else if ((p = hvalue("Content-Type", e->e_header)) != NULL) 933 { 934 /* this may be an RFC 1049 message */ 935 p = strpbrk(p, ";/"); 936 if (p == NULL || *p == ';') 937 { 938 /* yep, it is */ 939 e->e_flags |= EF_DONT_MIME; 940 } 941 } 942 943 /* 944 ** From person in antiquated ARPANET mode 945 ** required by UK Grey Book e-mail gateways (sigh) 946 */ 947 948 if (OpMode == MD_ARPAFTP) 949 { 950 register struct hdrinfo *hi; 951 952 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 953 { 954 if (bitset(H_FROM, hi->hi_flags) && 955 (!bitset(H_RESENT, hi->hi_flags) || 956 bitset(EF_RESENT, e->e_flags)) && 957 (p = hvalue(hi->hi_field, e->e_header)) != NULL) 958 break; 959 } 960 if (hi->hi_field != NULL) 961 { 962 if (tTd(32, 2)) 963 sm_dprintf("eatheader: setsender(*%s == %s)\n", 964 hi->hi_field, p); 965 setsender(p, e, NULL, '\0', true); 966 } 967 } 968 969 /* 970 ** Log collection information. 971 */ 972 973 if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 974 { 975 logsender(e, e->e_msgid); 976 e->e_flags &= ~EF_LOGSENDER; 977 } 978 } 979 /* 980 ** LOGSENDER -- log sender information 981 ** 982 ** Parameters: 983 ** e -- the envelope to log 984 ** msgid -- the message id 985 ** 986 ** Returns: 987 ** none 988 */ 989 990 void 991 logsender(e, msgid) 992 register ENVELOPE *e; 993 char *msgid; 994 { 995 char *name; 996 register char *sbp; 997 register char *p; 998 char hbuf[MAXNAME + 1]; 999 char sbuf[MAXLINE + 1]; 1000 char mbuf[MAXNAME + 1]; 1001 1002 /* don't allow newlines in the message-id */ 1003 /* XXX do we still need this? sm_syslog() replaces control chars */ 1004 if (msgid != NULL) 1005 { 1006 size_t l; 1007 1008 l = strlen(msgid); 1009 if (l > sizeof mbuf - 1) 1010 l = sizeof mbuf - 1; 1011 memmove(mbuf, msgid, l); 1012 mbuf[l] = '\0'; 1013 p = mbuf; 1014 while ((p = strchr(p, '\n')) != NULL) 1015 *p++ = ' '; 1016 } 1017 1018 if (bitset(EF_RESPONSE, e->e_flags)) 1019 name = "[RESPONSE]"; 1020 else if ((name = macvalue('_', e)) != NULL) 1021 /* EMPTY */ 1022 ; 1023 else if (RealHostName == NULL) 1024 name = "localhost"; 1025 else if (RealHostName[0] == '[') 1026 name = RealHostName; 1027 else 1028 { 1029 name = hbuf; 1030 (void) sm_snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName); 1031 if (RealHostAddr.sa.sa_family != 0) 1032 { 1033 p = &hbuf[strlen(hbuf)]; 1034 (void) sm_snprintf(p, SPACELEFT(hbuf, p), 1035 " (%.100s)", 1036 anynet_ntoa(&RealHostAddr)); 1037 } 1038 } 1039 1040 /* some versions of syslog only take 5 printf args */ 1041 #if (SYSLOG_BUFSIZE) >= 256 1042 sbp = sbuf; 1043 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1044 "from=%.200s, size=%ld, class=%d, nrcpts=%d", 1045 e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 1046 e->e_msgsize, e->e_class, e->e_nrcpts); 1047 sbp += strlen(sbp); 1048 if (msgid != NULL) 1049 { 1050 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1051 ", msgid=%.100s", mbuf); 1052 sbp += strlen(sbp); 1053 } 1054 if (e->e_bodytype != NULL) 1055 { 1056 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1057 ", bodytype=%.20s", e->e_bodytype); 1058 sbp += strlen(sbp); 1059 } 1060 p = macvalue('r', e); 1061 if (p != NULL) 1062 { 1063 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1064 ", proto=%.20s", p); 1065 sbp += strlen(sbp); 1066 } 1067 p = macvalue(macid("{daemon_name}"), e); 1068 if (p != NULL) 1069 { 1070 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1071 ", daemon=%.20s", p); 1072 sbp += strlen(sbp); 1073 } 1074 sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name); 1075 1076 #else /* (SYSLOG_BUFSIZE) >= 256 */ 1077 1078 sm_syslog(LOG_INFO, e->e_id, 1079 "from=%s", 1080 e->e_from.q_paddr == NULL ? "<NONE>" 1081 : shortenstring(e->e_from.q_paddr, 1082 83)); 1083 sm_syslog(LOG_INFO, e->e_id, 1084 "size=%ld, class=%ld, nrcpts=%d", 1085 e->e_msgsize, e->e_class, e->e_nrcpts); 1086 if (msgid != NULL) 1087 sm_syslog(LOG_INFO, e->e_id, 1088 "msgid=%s", 1089 shortenstring(mbuf, 83)); 1090 sbp = sbuf; 1091 *sbp = '\0'; 1092 if (e->e_bodytype != NULL) 1093 { 1094 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1095 "bodytype=%.20s, ", e->e_bodytype); 1096 sbp += strlen(sbp); 1097 } 1098 p = macvalue('r', e); 1099 if (p != NULL) 1100 { 1101 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1102 "proto=%.20s, ", p); 1103 sbp += strlen(sbp); 1104 } 1105 sm_syslog(LOG_INFO, e->e_id, 1106 "%.400srelay=%s", sbuf, name); 1107 #endif /* (SYSLOG_BUFSIZE) >= 256 */ 1108 } 1109 /* 1110 ** PRIENCODE -- encode external priority names into internal values. 1111 ** 1112 ** Parameters: 1113 ** p -- priority in ascii. 1114 ** 1115 ** Returns: 1116 ** priority as a numeric level. 1117 ** 1118 ** Side Effects: 1119 ** none. 1120 */ 1121 1122 static int 1123 priencode(p) 1124 char *p; 1125 { 1126 register int i; 1127 1128 for (i = 0; i < NumPriorities; i++) 1129 { 1130 if (sm_strcasecmp(p, Priorities[i].pri_name) == 0) 1131 return Priorities[i].pri_val; 1132 } 1133 1134 /* unknown priority */ 1135 return 0; 1136 } 1137 /* 1138 ** CRACKADDR -- parse an address and turn it into a macro 1139 ** 1140 ** This doesn't actually parse the address -- it just extracts 1141 ** it and replaces it with "$g". The parse is totally ad hoc 1142 ** and isn't even guaranteed to leave something syntactically 1143 ** identical to what it started with. However, it does leave 1144 ** something semantically identical if possible, else at least 1145 ** syntactically correct. 1146 ** 1147 ** For example, it changes "Real Name <real@example.com> (Comment)" 1148 ** to "Real Name <$g> (Comment)". 1149 ** 1150 ** This algorithm has been cleaned up to handle a wider range 1151 ** of cases -- notably quoted and backslash escaped strings. 1152 ** This modification makes it substantially better at preserving 1153 ** the original syntax. 1154 ** 1155 ** Parameters: 1156 ** addr -- the address to be cracked. 1157 ** e -- the current envelope. 1158 ** 1159 ** Returns: 1160 ** a pointer to the new version. 1161 ** 1162 ** Side Effects: 1163 ** none. 1164 ** 1165 ** Warning: 1166 ** The return value is saved in local storage and should 1167 ** be copied if it is to be reused. 1168 */ 1169 1170 #define SM_HAVE_ROOM ((bp < buflim) && (buflim <= bufend)) 1171 1172 /* 1173 ** Append a character to bp if we have room. 1174 ** If not, punt and return $g. 1175 */ 1176 1177 #define SM_APPEND_CHAR(c) \ 1178 do \ 1179 { \ 1180 if (SM_HAVE_ROOM) \ 1181 *bp++ = (c); \ 1182 else \ 1183 goto returng; \ 1184 } while (0) 1185 1186 #if MAXNAME < 10 1187 ERROR MAXNAME must be at least 10 1188 #endif /* MAXNAME < 10 */ 1189 1190 char * 1191 crackaddr(addr, e) 1192 register char *addr; 1193 ENVELOPE *e; 1194 { 1195 register char *p; 1196 register char c; 1197 int cmtlev; /* comment level in input string */ 1198 int realcmtlev; /* comment level in output string */ 1199 int anglelev; /* angle level in input string */ 1200 int copylev; /* 0 == in address, >0 copying */ 1201 int bracklev; /* bracket level for IPv6 addr check */ 1202 bool addangle; /* put closing angle in output */ 1203 bool qmode; /* quoting in original string? */ 1204 bool realqmode; /* quoting in output string? */ 1205 bool putgmac = false; /* already wrote $g */ 1206 bool quoteit = false; /* need to quote next character */ 1207 bool gotangle = false; /* found first '<' */ 1208 bool gotcolon = false; /* found a ':' */ 1209 register char *bp; 1210 char *buflim; 1211 char *bufhead; 1212 char *addrhead; 1213 char *bufend; 1214 static char buf[MAXNAME + 1]; 1215 1216 if (tTd(33, 1)) 1217 sm_dprintf("crackaddr(%s)\n", addr); 1218 1219 /* strip leading spaces */ 1220 while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 1221 addr++; 1222 1223 /* 1224 ** Start by assuming we have no angle brackets. This will be 1225 ** adjusted later if we find them. 1226 */ 1227 1228 buflim = bufend = &buf[sizeof(buf) - 1]; 1229 bp = bufhead = buf; 1230 p = addrhead = addr; 1231 copylev = anglelev = cmtlev = realcmtlev = 0; 1232 bracklev = 0; 1233 qmode = realqmode = addangle = false; 1234 1235 while ((c = *p++) != '\0') 1236 { 1237 /* 1238 ** Try to keep legal syntax using spare buffer space 1239 ** (maintained by buflim). 1240 */ 1241 1242 if (copylev > 0) 1243 SM_APPEND_CHAR(c); 1244 1245 /* check for backslash escapes */ 1246 if (c == '\\') 1247 { 1248 /* arrange to quote the address */ 1249 if (cmtlev <= 0 && !qmode) 1250 quoteit = true; 1251 1252 if ((c = *p++) == '\0') 1253 { 1254 /* too far */ 1255 p--; 1256 goto putg; 1257 } 1258 if (copylev > 0) 1259 SM_APPEND_CHAR(c); 1260 goto putg; 1261 } 1262 1263 /* check for quoted strings */ 1264 if (c == '"' && cmtlev <= 0) 1265 { 1266 qmode = !qmode; 1267 if (copylev > 0 && SM_HAVE_ROOM) 1268 { 1269 if (realqmode) 1270 buflim--; 1271 else 1272 buflim++; 1273 realqmode = !realqmode; 1274 } 1275 continue; 1276 } 1277 if (qmode) 1278 goto putg; 1279 1280 /* check for comments */ 1281 if (c == '(') 1282 { 1283 cmtlev++; 1284 1285 /* allow space for closing paren */ 1286 if (SM_HAVE_ROOM) 1287 { 1288 buflim--; 1289 realcmtlev++; 1290 if (copylev++ <= 0) 1291 { 1292 if (bp != bufhead) 1293 SM_APPEND_CHAR(' '); 1294 SM_APPEND_CHAR(c); 1295 } 1296 } 1297 } 1298 if (cmtlev > 0) 1299 { 1300 if (c == ')') 1301 { 1302 cmtlev--; 1303 copylev--; 1304 if (SM_HAVE_ROOM) 1305 { 1306 realcmtlev--; 1307 buflim++; 1308 } 1309 } 1310 continue; 1311 } 1312 else if (c == ')') 1313 { 1314 /* syntax error: unmatched ) */ 1315 if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead) 1316 bp--; 1317 } 1318 1319 /* count nesting on [ ... ] (for IPv6 domain literals) */ 1320 if (c == '[') 1321 bracklev++; 1322 else if (c == ']') 1323 bracklev--; 1324 1325 /* check for group: list; syntax */ 1326 if (c == ':' && anglelev <= 0 && bracklev <= 0 && 1327 !gotcolon && !ColonOkInAddr) 1328 { 1329 register char *q; 1330 1331 /* 1332 ** Check for DECnet phase IV ``::'' (host::user) 1333 ** or DECnet phase V ``:.'' syntaxes. The latter 1334 ** covers ``user@DEC:.tay.myhost'' and 1335 ** ``DEC:.tay.myhost::user'' syntaxes (bletch). 1336 */ 1337 1338 if (*p == ':' || *p == '.') 1339 { 1340 if (cmtlev <= 0 && !qmode) 1341 quoteit = true; 1342 if (copylev > 0) 1343 { 1344 SM_APPEND_CHAR(c); 1345 SM_APPEND_CHAR(*p); 1346 } 1347 p++; 1348 goto putg; 1349 } 1350 1351 gotcolon = true; 1352 1353 bp = bufhead; 1354 if (quoteit) 1355 { 1356 SM_APPEND_CHAR('"'); 1357 1358 /* back up over the ':' and any spaces */ 1359 --p; 1360 while (p > addr && 1361 isascii(*--p) && isspace(*p)) 1362 continue; 1363 p++; 1364 } 1365 for (q = addrhead; q < p; ) 1366 { 1367 c = *q++; 1368 if (quoteit && c == '"') 1369 SM_APPEND_CHAR('\\'); 1370 SM_APPEND_CHAR(c); 1371 } 1372 if (quoteit) 1373 { 1374 if (bp == &bufhead[1]) 1375 bp--; 1376 else 1377 SM_APPEND_CHAR('"'); 1378 while ((c = *p++) != ':') 1379 SM_APPEND_CHAR(c); 1380 SM_APPEND_CHAR(c); 1381 } 1382 1383 /* any trailing white space is part of group: */ 1384 while (isascii(*p) && isspace(*p)) 1385 { 1386 SM_APPEND_CHAR(*p); 1387 p++; 1388 } 1389 copylev = 0; 1390 putgmac = quoteit = false; 1391 bufhead = bp; 1392 addrhead = p; 1393 continue; 1394 } 1395 1396 if (c == ';' && copylev <= 0 && !ColonOkInAddr) 1397 SM_APPEND_CHAR(c); 1398 1399 /* check for characters that may have to be quoted */ 1400 if (strchr(MustQuoteChars, c) != NULL) 1401 { 1402 /* 1403 ** If these occur as the phrase part of a <> 1404 ** construct, but are not inside of () or already 1405 ** quoted, they will have to be quoted. Note that 1406 ** now (but don't actually do the quoting). 1407 */ 1408 1409 if (cmtlev <= 0 && !qmode) 1410 quoteit = true; 1411 } 1412 1413 /* check for angle brackets */ 1414 if (c == '<') 1415 { 1416 register char *q; 1417 1418 /* assume first of two angles is bogus */ 1419 if (gotangle) 1420 quoteit = true; 1421 gotangle = true; 1422 1423 /* oops -- have to change our mind */ 1424 anglelev = 1; 1425 if (SM_HAVE_ROOM) 1426 { 1427 if (!addangle) 1428 buflim--; 1429 addangle = true; 1430 } 1431 1432 bp = bufhead; 1433 if (quoteit) 1434 { 1435 SM_APPEND_CHAR('"'); 1436 1437 /* back up over the '<' and any spaces */ 1438 --p; 1439 while (p > addr && 1440 isascii(*--p) && isspace(*p)) 1441 continue; 1442 p++; 1443 } 1444 for (q = addrhead; q < p; ) 1445 { 1446 c = *q++; 1447 if (quoteit && c == '"') 1448 { 1449 SM_APPEND_CHAR('\\'); 1450 SM_APPEND_CHAR(c); 1451 } 1452 else 1453 SM_APPEND_CHAR(c); 1454 } 1455 if (quoteit) 1456 { 1457 if (bp == &buf[1]) 1458 bp--; 1459 else 1460 SM_APPEND_CHAR('"'); 1461 while ((c = *p++) != '<') 1462 SM_APPEND_CHAR(c); 1463 SM_APPEND_CHAR(c); 1464 } 1465 copylev = 0; 1466 putgmac = quoteit = false; 1467 continue; 1468 } 1469 1470 if (c == '>') 1471 { 1472 if (anglelev > 0) 1473 { 1474 anglelev--; 1475 if (SM_HAVE_ROOM) 1476 { 1477 if (addangle) 1478 buflim++; 1479 addangle = false; 1480 } 1481 } 1482 else if (SM_HAVE_ROOM) 1483 { 1484 /* syntax error: unmatched > */ 1485 if (copylev > 0 && bp > bufhead) 1486 bp--; 1487 quoteit = true; 1488 continue; 1489 } 1490 if (copylev++ <= 0) 1491 SM_APPEND_CHAR(c); 1492 continue; 1493 } 1494 1495 /* must be a real address character */ 1496 putg: 1497 if (copylev <= 0 && !putgmac) 1498 { 1499 if (bp > buf && bp[-1] == ')') 1500 SM_APPEND_CHAR(' '); 1501 SM_APPEND_CHAR(MACROEXPAND); 1502 SM_APPEND_CHAR('g'); 1503 putgmac = true; 1504 } 1505 } 1506 1507 /* repair any syntactic damage */ 1508 if (realqmode && bp < bufend) 1509 *bp++ = '"'; 1510 while (realcmtlev-- > 0 && bp < bufend) 1511 *bp++ = ')'; 1512 if (addangle && bp < bufend) 1513 *bp++ = '>'; 1514 *bp = '\0'; 1515 if (bp < bufend) 1516 goto success; 1517 1518 returng: 1519 /* String too long, punt */ 1520 buf[0] = '<'; 1521 buf[1] = MACROEXPAND; 1522 buf[2]= 'g'; 1523 buf[3] = '>'; 1524 buf[4]= '\0'; 1525 sm_syslog(LOG_ALERT, e->e_id, 1526 "Dropped invalid comments from header address"); 1527 1528 success: 1529 if (tTd(33, 1)) 1530 { 1531 sm_dprintf("crackaddr=>`"); 1532 xputs(sm_debug_file(), buf); 1533 sm_dprintf("'\n"); 1534 } 1535 return buf; 1536 } 1537 /* 1538 ** PUTHEADER -- put the header part of a message from the in-core copy 1539 ** 1540 ** Parameters: 1541 ** mci -- the connection information. 1542 ** hdr -- the header to put. 1543 ** e -- envelope to use. 1544 ** flags -- MIME conversion flags. 1545 ** 1546 ** Returns: 1547 ** success 1548 ** 1549 ** Side Effects: 1550 ** none. 1551 */ 1552 1553 bool 1554 putheader(mci, hdr, e, flags) 1555 register MCI *mci; 1556 HDR *hdr; 1557 register ENVELOPE *e; 1558 int flags; 1559 { 1560 register HDR *h; 1561 char buf[SM_MAX(MAXLINE,BUFSIZ)]; 1562 char obuf[MAXLINE]; 1563 1564 if (tTd(34, 1)) 1565 sm_dprintf("--- putheader, mailer = %s ---\n", 1566 mci->mci_mailer->m_name); 1567 1568 /* 1569 ** If we're in MIME mode, we're not really in the header of the 1570 ** message, just the header of one of the parts of the body of 1571 ** the message. Therefore MCIF_INHEADER should not be turned on. 1572 */ 1573 1574 if (!bitset(MCIF_INMIME, mci->mci_flags)) 1575 mci->mci_flags |= MCIF_INHEADER; 1576 1577 for (h = hdr; h != NULL; h = h->h_link) 1578 { 1579 register char *p = h->h_value; 1580 char *q; 1581 1582 if (tTd(34, 11)) 1583 { 1584 sm_dprintf(" %s: ", h->h_field); 1585 xputs(sm_debug_file(), p); 1586 } 1587 1588 /* Skip empty headers */ 1589 if (h->h_value == NULL) 1590 continue; 1591 1592 /* heuristic shortening of MIME fields to avoid MUA overflows */ 1593 if (MaxMimeFieldLength > 0 && 1594 wordinclass(h->h_field, 1595 macid("{checkMIMEFieldHeaders}"))) 1596 { 1597 size_t len; 1598 1599 len = fix_mime_header(h, e); 1600 if (len > 0) 1601 { 1602 sm_syslog(LOG_ALERT, e->e_id, 1603 "Truncated MIME %s header due to field size (length = %ld) (possible attack)", 1604 h->h_field, (unsigned long) len); 1605 if (tTd(34, 11)) 1606 sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n", 1607 h->h_field, 1608 (unsigned long) len); 1609 } 1610 } 1611 1612 if (MaxMimeHeaderLength > 0 && 1613 wordinclass(h->h_field, 1614 macid("{checkMIMETextHeaders}"))) 1615 { 1616 size_t len; 1617 1618 len = strlen(h->h_value); 1619 if (len > (size_t) MaxMimeHeaderLength) 1620 { 1621 h->h_value[MaxMimeHeaderLength - 1] = '\0'; 1622 sm_syslog(LOG_ALERT, e->e_id, 1623 "Truncated long MIME %s header (length = %ld) (possible attack)", 1624 h->h_field, (unsigned long) len); 1625 if (tTd(34, 11)) 1626 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1627 h->h_field, 1628 (unsigned long) len); 1629 } 1630 } 1631 1632 if (MaxMimeHeaderLength > 0 && 1633 wordinclass(h->h_field, 1634 macid("{checkMIMEHeaders}"))) 1635 { 1636 size_t len; 1637 1638 len = strlen(h->h_value); 1639 if (shorten_rfc822_string(h->h_value, 1640 MaxMimeHeaderLength)) 1641 { 1642 if (len < MaxMimeHeaderLength) 1643 { 1644 /* we only rebalanced a bogus header */ 1645 sm_syslog(LOG_ALERT, e->e_id, 1646 "Fixed MIME %s header (possible attack)", 1647 h->h_field); 1648 if (tTd(34, 11)) 1649 sm_dprintf(" fixed MIME %s header (possible attack)\n", 1650 h->h_field); 1651 } 1652 else 1653 { 1654 /* we actually shortened header */ 1655 sm_syslog(LOG_ALERT, e->e_id, 1656 "Truncated long MIME %s header (length = %ld) (possible attack)", 1657 h->h_field, 1658 (unsigned long) len); 1659 if (tTd(34, 11)) 1660 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1661 h->h_field, 1662 (unsigned long) len); 1663 } 1664 } 1665 } 1666 1667 /* 1668 ** Suppress Content-Transfer-Encoding: if we are MIMEing 1669 ** and we are potentially converting from 8 bit to 7 bit 1670 ** MIME. If converting, add a new CTE header in 1671 ** mime8to7(). 1672 */ 1673 1674 if (bitset(H_CTE, h->h_flags) && 1675 bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, 1676 mci->mci_flags) && 1677 !bitset(M87F_NO8TO7, flags)) 1678 { 1679 if (tTd(34, 11)) 1680 sm_dprintf(" (skipped (content-transfer-encoding))\n"); 1681 continue; 1682 } 1683 1684 if (bitset(MCIF_INMIME, mci->mci_flags)) 1685 { 1686 if (tTd(34, 11)) 1687 sm_dprintf("\n"); 1688 if (!put_vanilla_header(h, p, mci)) 1689 goto writeerr; 1690 continue; 1691 } 1692 1693 if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 1694 !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) && 1695 (h->h_macro == '\0' || 1696 (q = macvalue(bitidx(h->h_macro), e)) == NULL || 1697 *q == '\0')) 1698 { 1699 if (tTd(34, 11)) 1700 sm_dprintf(" (skipped)\n"); 1701 continue; 1702 } 1703 1704 /* handle Resent-... headers specially */ 1705 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 1706 { 1707 if (tTd(34, 11)) 1708 sm_dprintf(" (skipped (resent))\n"); 1709 continue; 1710 } 1711 1712 /* suppress return receipts if requested */ 1713 if (bitset(H_RECEIPTTO, h->h_flags) && 1714 (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags))) 1715 { 1716 if (tTd(34, 11)) 1717 sm_dprintf(" (skipped (receipt))\n"); 1718 continue; 1719 } 1720 1721 /* macro expand value if generated internally */ 1722 if (bitset(H_DEFAULT, h->h_flags) || 1723 bitset(H_BINDLATE, h->h_flags)) 1724 { 1725 expand(p, buf, sizeof buf, e); 1726 p = buf; 1727 if (*p == '\0') 1728 { 1729 if (tTd(34, 11)) 1730 sm_dprintf(" (skipped -- null value)\n"); 1731 continue; 1732 } 1733 } 1734 1735 if (bitset(H_BCC, h->h_flags)) 1736 { 1737 /* Bcc: field -- either truncate or delete */ 1738 if (bitset(EF_DELETE_BCC, e->e_flags)) 1739 { 1740 if (tTd(34, 11)) 1741 sm_dprintf(" (skipped -- bcc)\n"); 1742 } 1743 else 1744 { 1745 /* no other recipient headers: truncate value */ 1746 (void) sm_strlcpyn(obuf, sizeof obuf, 2, 1747 h->h_field, ":"); 1748 if (!putline(obuf, mci)) 1749 goto writeerr; 1750 } 1751 continue; 1752 } 1753 1754 if (tTd(34, 11)) 1755 sm_dprintf("\n"); 1756 1757 if (bitset(H_FROM|H_RCPT, h->h_flags)) 1758 { 1759 /* address field */ 1760 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 1761 1762 if (bitset(H_FROM, h->h_flags)) 1763 oldstyle = false; 1764 commaize(h, p, oldstyle, mci, e); 1765 } 1766 else 1767 { 1768 if (!put_vanilla_header(h, p, mci)) 1769 goto writeerr; 1770 } 1771 } 1772 1773 /* 1774 ** If we are converting this to a MIME message, add the 1775 ** MIME headers (but not in MIME mode!). 1776 */ 1777 1778 #if MIME8TO7 1779 if (bitset(MM_MIME8BIT, MimeMode) && 1780 bitset(EF_HAS8BIT, e->e_flags) && 1781 !bitset(EF_DONT_MIME, e->e_flags) && 1782 !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 1783 !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) && 1784 hvalue("MIME-Version", e->e_header) == NULL) 1785 { 1786 if (!putline("MIME-Version: 1.0", mci)) 1787 goto writeerr; 1788 if (hvalue("Content-Type", e->e_header) == NULL) 1789 { 1790 (void) sm_snprintf(obuf, sizeof obuf, 1791 "Content-Type: text/plain; charset=%s", 1792 defcharset(e)); 1793 if (!putline(obuf, mci)) 1794 goto writeerr; 1795 } 1796 if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL 1797 && !putline("Content-Transfer-Encoding: 8bit", mci)) 1798 goto writeerr; 1799 } 1800 #endif /* MIME8TO7 */ 1801 return true; 1802 1803 writeerr: 1804 return false; 1805 } 1806 /* 1807 ** PUT_VANILLA_HEADER -- output a fairly ordinary header 1808 ** 1809 ** Parameters: 1810 ** h -- the structure describing this header 1811 ** v -- the value of this header 1812 ** mci -- the connection info for output 1813 ** 1814 ** Returns: 1815 ** success 1816 */ 1817 1818 static bool 1819 put_vanilla_header(h, v, mci) 1820 HDR *h; 1821 char *v; 1822 MCI *mci; 1823 { 1824 register char *nlp; 1825 register char *obp; 1826 int putflags; 1827 char obuf[MAXLINE + 256]; /* additional length for h_field */ 1828 1829 putflags = PXLF_HEADER; 1830 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1831 putflags |= PXLF_STRIP8BIT; 1832 (void) sm_snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field); 1833 obp = obuf + strlen(obuf); 1834 while ((nlp = strchr(v, '\n')) != NULL) 1835 { 1836 int l; 1837 1838 l = nlp - v; 1839 1840 /* 1841 ** XXX This is broken for SPACELEFT()==0 1842 ** However, SPACELEFT() is always > 0 unless MAXLINE==1. 1843 */ 1844 1845 if (SPACELEFT(obuf, obp) - 1 < (size_t) l) 1846 l = SPACELEFT(obuf, obp) - 1; 1847 1848 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); 1849 if (!putxline(obuf, strlen(obuf), mci, putflags)) 1850 goto writeerr; 1851 v += l + 1; 1852 obp = obuf; 1853 if (*v != ' ' && *v != '\t') 1854 *obp++ = ' '; 1855 } 1856 1857 /* XXX This is broken for SPACELEFT()==0 */ 1858 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", 1859 (int) (SPACELEFT(obuf, obp) - 1), v); 1860 return putxline(obuf, strlen(obuf), mci, putflags); 1861 1862 writeerr: 1863 return false; 1864 } 1865 /* 1866 ** COMMAIZE -- output a header field, making a comma-translated list. 1867 ** 1868 ** Parameters: 1869 ** h -- the header field to output. 1870 ** p -- the value to put in it. 1871 ** oldstyle -- true if this is an old style header. 1872 ** mci -- the connection information. 1873 ** e -- the envelope containing the message. 1874 ** 1875 ** Returns: 1876 ** success 1877 ** 1878 ** Side Effects: 1879 ** outputs "p" to file "fp". 1880 */ 1881 1882 bool 1883 commaize(h, p, oldstyle, mci, e) 1884 register HDR *h; 1885 register char *p; 1886 bool oldstyle; 1887 register MCI *mci; 1888 register ENVELOPE *e; 1889 { 1890 register char *obp; 1891 int opos; 1892 int omax; 1893 bool firstone = true; 1894 int putflags = PXLF_HEADER; 1895 char **res; 1896 char obuf[MAXLINE + 3]; 1897 1898 /* 1899 ** Output the address list translated by the 1900 ** mailer and with commas. 1901 */ 1902 1903 if (tTd(14, 2)) 1904 sm_dprintf("commaize(%s: %s)\n", h->h_field, p); 1905 1906 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1907 putflags |= PXLF_STRIP8BIT; 1908 1909 obp = obuf; 1910 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", 1911 h->h_field); 1912 1913 /* opos = strlen(obp); */ 1914 opos = strlen(h->h_field) + 2; 1915 if (opos > 202) 1916 opos = 202; 1917 obp += opos; 1918 omax = mci->mci_mailer->m_linelimit - 2; 1919 if (omax < 0 || omax > 78) 1920 omax = 78; 1921 1922 /* 1923 ** Run through the list of values. 1924 */ 1925 1926 while (*p != '\0') 1927 { 1928 register char *name; 1929 register int c; 1930 char savechar; 1931 int flags; 1932 auto int status; 1933 1934 /* 1935 ** Find the end of the name. New style names 1936 ** end with a comma, old style names end with 1937 ** a space character. However, spaces do not 1938 ** necessarily delimit an old-style name -- at 1939 ** signs mean keep going. 1940 */ 1941 1942 /* find end of name */ 1943 while ((isascii(*p) && isspace(*p)) || *p == ',') 1944 p++; 1945 name = p; 1946 res = NULL; 1947 for (;;) 1948 { 1949 auto char *oldp; 1950 char pvpbuf[PSBUFSIZE]; 1951 1952 res = prescan(p, oldstyle ? ' ' : ',', pvpbuf, 1953 sizeof pvpbuf, &oldp, NULL, false); 1954 p = oldp; 1955 #if _FFR_IGNORE_BOGUS_ADDR 1956 /* ignore addresses that can't be parsed */ 1957 if (res == NULL) 1958 { 1959 name = p; 1960 continue; 1961 } 1962 #endif /* _FFR_IGNORE_BOGUS_ADDR */ 1963 1964 /* look to see if we have an at sign */ 1965 while (*p != '\0' && isascii(*p) && isspace(*p)) 1966 p++; 1967 1968 if (*p != '@') 1969 { 1970 p = oldp; 1971 break; 1972 } 1973 ++p; 1974 while (*p != '\0' && isascii(*p) && isspace(*p)) 1975 p++; 1976 } 1977 /* at the end of one complete name */ 1978 1979 /* strip off trailing white space */ 1980 while (p >= name && 1981 ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 1982 p--; 1983 if (++p == name) 1984 continue; 1985 1986 /* 1987 ** if prescan() failed go a bit backwards; this is a hack, 1988 ** there should be some better error recovery. 1989 */ 1990 1991 if (res == NULL && p > name && 1992 !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 1993 --p; 1994 savechar = *p; 1995 *p = '\0'; 1996 1997 /* translate the name to be relative */ 1998 flags = RF_HEADERADDR|RF_ADDDOMAIN; 1999 if (bitset(H_FROM, h->h_flags)) 2000 flags |= RF_SENDERADDR; 2001 #if USERDB 2002 else if (e->e_from.q_mailer != NULL && 2003 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 2004 { 2005 char *q; 2006 2007 q = udbsender(name, e->e_rpool); 2008 if (q != NULL) 2009 name = q; 2010 } 2011 #endif /* USERDB */ 2012 status = EX_OK; 2013 name = remotename(name, mci->mci_mailer, flags, &status, e); 2014 if (*name == '\0') 2015 { 2016 *p = savechar; 2017 continue; 2018 } 2019 name = denlstring(name, false, true); 2020 2021 /* output the name with nice formatting */ 2022 opos += strlen(name); 2023 if (!firstone) 2024 opos += 2; 2025 if (opos > omax && !firstone) 2026 { 2027 (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp)); 2028 if (!putxline(obuf, strlen(obuf), mci, putflags)) 2029 goto writeerr; 2030 obp = obuf; 2031 (void) sm_strlcpy(obp, " ", sizeof obuf); 2032 opos = strlen(obp); 2033 obp += opos; 2034 opos += strlen(name); 2035 } 2036 else if (!firstone) 2037 { 2038 (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp)); 2039 obp += 2; 2040 } 2041 2042 while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 2043 *obp++ = c; 2044 firstone = false; 2045 *p = savechar; 2046 } 2047 if (obp < &obuf[sizeof obuf]) 2048 *obp = '\0'; 2049 else 2050 obuf[sizeof obuf - 1] = '\0'; 2051 return putxline(obuf, strlen(obuf), mci, putflags); 2052 2053 writeerr: 2054 return false; 2055 } 2056 2057 /* 2058 ** COPYHEADER -- copy header list 2059 ** 2060 ** This routine is the equivalent of newstr for header lists 2061 ** 2062 ** Parameters: 2063 ** header -- list of header structures to copy. 2064 ** rpool -- resource pool, or NULL 2065 ** 2066 ** Returns: 2067 ** a copy of 'header'. 2068 ** 2069 ** Side Effects: 2070 ** none. 2071 */ 2072 2073 HDR * 2074 copyheader(header, rpool) 2075 register HDR *header; 2076 SM_RPOOL_T *rpool; 2077 { 2078 register HDR *newhdr; 2079 HDR *ret; 2080 register HDR **tail = &ret; 2081 2082 while (header != NULL) 2083 { 2084 newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof *newhdr); 2085 STRUCTCOPY(*header, *newhdr); 2086 *tail = newhdr; 2087 tail = &newhdr->h_link; 2088 header = header->h_link; 2089 } 2090 *tail = NULL; 2091 2092 return ret; 2093 } 2094 /* 2095 ** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header 2096 ** 2097 ** Run through all of the parameters of a MIME header and 2098 ** possibly truncate and rebalance the parameter according 2099 ** to MaxMimeFieldLength. 2100 ** 2101 ** Parameters: 2102 ** h -- the header to truncate/rebalance 2103 ** e -- the current envelope 2104 ** 2105 ** Returns: 2106 ** length of last offending field, 0 if all ok. 2107 ** 2108 ** Side Effects: 2109 ** string modified in place 2110 */ 2111 2112 static size_t 2113 fix_mime_header(h, e) 2114 HDR *h; 2115 ENVELOPE *e; 2116 { 2117 char *begin = h->h_value; 2118 char *end; 2119 size_t len = 0; 2120 size_t retlen = 0; 2121 2122 if (begin == NULL || *begin == '\0') 2123 return 0; 2124 2125 /* Split on each ';' */ 2126 /* find_character() never returns NULL */ 2127 while ((end = find_character(begin, ';')) != NULL) 2128 { 2129 char save = *end; 2130 char *bp; 2131 2132 *end = '\0'; 2133 2134 len = strlen(begin); 2135 2136 /* Shorten individual parameter */ 2137 if (shorten_rfc822_string(begin, MaxMimeFieldLength)) 2138 { 2139 if (len < MaxMimeFieldLength) 2140 { 2141 /* we only rebalanced a bogus field */ 2142 sm_syslog(LOG_ALERT, e->e_id, 2143 "Fixed MIME %s header field (possible attack)", 2144 h->h_field); 2145 if (tTd(34, 11)) 2146 sm_dprintf(" fixed MIME %s header field (possible attack)\n", 2147 h->h_field); 2148 } 2149 else 2150 { 2151 /* we actually shortened the header */ 2152 retlen = len; 2153 } 2154 } 2155 2156 /* Collapse the possibly shortened string with rest */ 2157 bp = begin + strlen(begin); 2158 if (bp != end) 2159 { 2160 char *ep = end; 2161 2162 *end = save; 2163 end = bp; 2164 2165 /* copy character by character due to overlap */ 2166 while (*ep != '\0') 2167 *bp++ = *ep++; 2168 *bp = '\0'; 2169 } 2170 else 2171 *end = save; 2172 if (*end == '\0') 2173 break; 2174 2175 /* Move past ';' */ 2176 begin = end + 1; 2177 } 2178 return retlen; 2179 } 2180