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