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 (SM_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 (SM_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; SM_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 (SM_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 (SM_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 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]; /* XREF: see below MSGIDLOGLEN */ 1123 1124 if (bitset(EF_RESPONSE, e->e_flags)) 1125 name = "[RESPONSE]"; 1126 else if ((name = macvalue('_', e)) != NULL) 1127 /* EMPTY */ 1128 ; 1129 else if (RealHostName == NULL) 1130 name = "localhost"; 1131 else if (RealHostName[0] == '[') 1132 name = RealHostName; 1133 else 1134 { 1135 name = hbuf; 1136 (void) sm_snprintf(hbuf, sizeof(hbuf), "%.80s", RealHostName); 1137 if (RealHostAddr.sa.sa_family != 0) 1138 { 1139 p = &hbuf[strlen(hbuf)]; 1140 (void) sm_snprintf(p, SPACELEFT(hbuf, p), 1141 " (%.100s)", 1142 anynet_ntoa(&RealHostAddr)); 1143 } 1144 } 1145 1146 #if (SYSLOG_BUFSIZE) >= 256 1147 sbp = sbuf; 1148 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1149 "from=%.200s, size=%ld, class=%d, nrcpts=%d", 1150 e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 1151 PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts); 1152 sbp += strlen(sbp); 1153 if (msgid != NULL) 1154 { 1155 1156 #ifndef MSGIDLOGLEN 1157 # define MSGIDLOGLEN 100 1158 # define FIRSTLOGLEN 850 1159 # else 1160 # if MSGIDLOGLEN < 100 1161 ERROR MSGIDLOGLEN too short 1162 # endif 1163 /* XREF: this is "sizeof(sbuf)", see above */ 1164 # if MSGIDLOGLEN >= MAXLINE / 2 1165 ERROR MSGIDLOGLEN too long 1166 # endif 1167 1168 /* 850 - 100 for original MSGIDLOGLEN */ 1169 # define FIRSTLOGLEN (750 + MSGIDLOGLEN) 1170 1171 /* check that total length is ok */ 1172 # if FIRSTLOGLEN + 200 >= MAXLINE 1173 ERROR MSGIDLOGLEN too long 1174 # endif 1175 #endif 1176 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1177 ", msgid=%.*s", MSGIDLOGLEN, msgid); 1178 sbp += strlen(sbp); 1179 } 1180 if (e->e_bodytype != NULL) 1181 { 1182 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1183 ", bodytype=%.20s", e->e_bodytype); 1184 sbp += strlen(sbp); 1185 } 1186 p = macvalue('r', e); 1187 if (p != NULL) 1188 { 1189 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1190 ", proto=%.20s", p); 1191 sbp += strlen(sbp); 1192 } 1193 p = macvalue(macid("{daemon_name}"), e); 1194 if (p != NULL) 1195 { 1196 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1197 ", daemon=%.20s", p); 1198 sbp += strlen(sbp); 1199 } 1200 # if _FFR_LOG_MORE1 1201 LOG_MORE(sbuf, sbp); 1202 # if SASL 1203 p = macvalue(macid("{auth_type}"), e); 1204 if (p == NULL || *p == '\0') 1205 p = "NONE"; 1206 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), ", auth=%.20s", p); 1207 sbp += strlen(sbp); 1208 # endif /* SASL */ 1209 # endif /* _FFR_LOG_MORE1 */ 1210 sm_syslog(LOG_INFO, e->e_id, "%.*s, relay=%s", FIRSTLOGLEN, sbuf, name); 1211 1212 #else /* (SYSLOG_BUFSIZE) >= 256 */ 1213 1214 sm_syslog(LOG_INFO, e->e_id, 1215 "from=%s", 1216 e->e_from.q_paddr == NULL ? "<NONE>" 1217 : shortenstring(e->e_from.q_paddr, 1218 83)); 1219 sm_syslog(LOG_INFO, e->e_id, 1220 "size=%ld, class=%ld, nrcpts=%d", 1221 PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts); 1222 if (msgid != NULL) 1223 sm_syslog(LOG_INFO, e->e_id, 1224 "msgid=%s", 1225 shortenstring(msgid, 83)); 1226 sbp = sbuf; 1227 *sbp = '\0'; 1228 if (e->e_bodytype != NULL) 1229 { 1230 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1231 "bodytype=%.20s, ", e->e_bodytype); 1232 sbp += strlen(sbp); 1233 } 1234 p = macvalue('r', e); 1235 if (p != NULL) 1236 { 1237 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), 1238 "proto=%.20s, ", p); 1239 sbp += strlen(sbp); 1240 } 1241 sm_syslog(LOG_INFO, e->e_id, 1242 "%.400srelay=%s", sbuf, name); 1243 #endif /* (SYSLOG_BUFSIZE) >= 256 */ 1244 } 1245 1246 /* 1247 ** PRIENCODE -- encode external priority names into internal values. 1248 ** 1249 ** Parameters: 1250 ** p -- priority in ascii. 1251 ** 1252 ** Returns: 1253 ** priority as a numeric level. 1254 ** 1255 ** Side Effects: 1256 ** none. 1257 */ 1258 1259 static int 1260 priencode(p) 1261 char *p; 1262 { 1263 register int i; 1264 1265 for (i = 0; i < NumPriorities; i++) 1266 { 1267 if (sm_strcasecmp(p, Priorities[i].pri_name) == 0) 1268 return Priorities[i].pri_val; 1269 } 1270 1271 /* unknown priority */ 1272 return 0; 1273 } 1274 1275 /* 1276 ** CRACKADDR -- parse an address and turn it into a macro 1277 ** 1278 ** This doesn't actually parse the address -- it just extracts 1279 ** it and replaces it with "$g". The parse is totally ad hoc 1280 ** and isn't even guaranteed to leave something syntactically 1281 ** identical to what it started with. However, it does leave 1282 ** something semantically identical if possible, else at least 1283 ** syntactically correct. 1284 ** 1285 ** For example, it changes "Real Name <real@example.com> (Comment)" 1286 ** to "Real Name <$g> (Comment)". 1287 ** 1288 ** This algorithm has been cleaned up to handle a wider range 1289 ** of cases -- notably quoted and backslash escaped strings. 1290 ** This modification makes it substantially better at preserving 1291 ** the original syntax. 1292 ** 1293 ** Parameters: 1294 ** addr -- the address to be cracked. 1295 ** e -- the current envelope. 1296 ** 1297 ** Returns: 1298 ** a pointer to the new version. 1299 ** 1300 ** Side Effects: 1301 ** none. 1302 ** 1303 ** Warning: 1304 ** The return value is saved in local storage and should 1305 ** be copied if it is to be reused. 1306 */ 1307 1308 #define SM_HAVE_ROOM ((bp < buflim) && (buflim <= bufend)) 1309 1310 /* 1311 ** Append a character to bp if we have room. 1312 ** If not, punt and return $g. 1313 */ 1314 1315 #define SM_APPEND_CHAR(c) \ 1316 do \ 1317 { \ 1318 if (SM_HAVE_ROOM) \ 1319 *bp++ = (c); \ 1320 else \ 1321 goto returng; \ 1322 } while (0) 1323 1324 #if MAXNAME < 10 1325 ERROR MAXNAME must be at least 10 1326 #endif 1327 1328 char * 1329 crackaddr(addr, e) 1330 register char *addr; 1331 ENVELOPE *e; 1332 { 1333 register char *p; 1334 register char c; 1335 int cmtlev; /* comment level in input string */ 1336 int realcmtlev; /* comment level in output string */ 1337 int anglelev; /* angle level in input string */ 1338 int copylev; /* 0 == in address, >0 copying */ 1339 int bracklev; /* bracket level for IPv6 addr check */ 1340 bool addangle; /* put closing angle in output */ 1341 bool qmode; /* quoting in original string? */ 1342 bool realqmode; /* quoting in output string? */ 1343 bool putgmac = false; /* already wrote $g */ 1344 bool quoteit = false; /* need to quote next character */ 1345 bool gotangle = false; /* found first '<' */ 1346 bool gotcolon = false; /* found a ':' */ 1347 register char *bp; 1348 char *buflim; 1349 char *bufhead; 1350 char *addrhead; 1351 char *bufend; 1352 static char buf[MAXNAME + 1]; 1353 1354 if (tTd(33, 1)) 1355 sm_dprintf("crackaddr(%s)\n", addr); 1356 1357 buflim = bufend = &buf[sizeof(buf) - 1]; 1358 bp = bufhead = buf; 1359 1360 /* skip over leading spaces but preserve them */ 1361 while (*addr != '\0' && SM_ISSPACE(*addr)) 1362 { 1363 SM_APPEND_CHAR(*addr); 1364 addr++; 1365 } 1366 bufhead = bp; 1367 1368 /* 1369 ** Start by assuming we have no angle brackets. This will be 1370 ** adjusted later if we find them. 1371 */ 1372 1373 p = addrhead = addr; 1374 copylev = anglelev = cmtlev = realcmtlev = 0; 1375 bracklev = 0; 1376 qmode = realqmode = addangle = false; 1377 1378 while ((c = *p++) != '\0') 1379 { 1380 /* 1381 ** Try to keep legal syntax using spare buffer space 1382 ** (maintained by buflim). 1383 */ 1384 1385 if (copylev > 0) 1386 SM_APPEND_CHAR(c); 1387 1388 /* check for backslash escapes */ 1389 if (c == '\\') 1390 { 1391 /* arrange to quote the address */ 1392 if (cmtlev <= 0 && !qmode) 1393 quoteit = true; 1394 1395 if ((c = *p++) == '\0') 1396 { 1397 /* too far */ 1398 p--; 1399 goto putg; 1400 } 1401 if (copylev > 0) 1402 SM_APPEND_CHAR(c); 1403 goto putg; 1404 } 1405 1406 /* check for quoted strings */ 1407 if (c == '"' && cmtlev <= 0) 1408 { 1409 qmode = !qmode; 1410 if (copylev > 0 && SM_HAVE_ROOM) 1411 { 1412 if (realqmode) 1413 buflim--; 1414 else 1415 buflim++; 1416 realqmode = !realqmode; 1417 } 1418 continue; 1419 } 1420 if (qmode) 1421 goto putg; 1422 1423 /* check for comments */ 1424 if (c == '(') 1425 { 1426 cmtlev++; 1427 1428 /* allow space for closing paren */ 1429 if (SM_HAVE_ROOM) 1430 { 1431 buflim--; 1432 realcmtlev++; 1433 if (copylev++ <= 0) 1434 { 1435 if (bp != bufhead) 1436 SM_APPEND_CHAR(' '); 1437 SM_APPEND_CHAR(c); 1438 } 1439 } 1440 } 1441 if (cmtlev > 0) 1442 { 1443 if (c == ')') 1444 { 1445 cmtlev--; 1446 copylev--; 1447 if (SM_HAVE_ROOM) 1448 { 1449 realcmtlev--; 1450 buflim++; 1451 } 1452 } 1453 continue; 1454 } 1455 else if (c == ')') 1456 { 1457 /* syntax error: unmatched ) */ 1458 if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead) 1459 bp--; 1460 } 1461 1462 /* count nesting on [ ... ] (for IPv6 domain literals) */ 1463 if (c == '[') 1464 bracklev++; 1465 else if (c == ']') 1466 bracklev--; 1467 1468 /* check for group: list; syntax */ 1469 if (c == ':' && anglelev <= 0 && bracklev <= 0 && 1470 !gotcolon && !ColonOkInAddr) 1471 { 1472 register char *q; 1473 1474 /* 1475 ** Check for DECnet phase IV ``::'' (host::user) 1476 ** or DECnet phase V ``:.'' syntaxes. The latter 1477 ** covers ``user@DEC:.tay.myhost'' and 1478 ** ``DEC:.tay.myhost::user'' syntaxes (bletch). 1479 */ 1480 1481 if (*p == ':' || *p == '.') 1482 { 1483 if (cmtlev <= 0 && !qmode) 1484 quoteit = true; 1485 if (copylev > 0) 1486 { 1487 SM_APPEND_CHAR(c); 1488 SM_APPEND_CHAR(*p); 1489 } 1490 p++; 1491 goto putg; 1492 } 1493 1494 gotcolon = true; 1495 1496 bp = bufhead; 1497 if (quoteit) 1498 { 1499 SM_APPEND_CHAR('"'); 1500 1501 /* back up over the ':' and any spaces */ 1502 --p; 1503 while (p > addr && 1504 isascii(*--p) && isspace(*p)) 1505 continue; 1506 p++; 1507 } 1508 for (q = addrhead; q < p; ) 1509 { 1510 c = *q++; 1511 if (quoteit && c == '"') 1512 SM_APPEND_CHAR('\\'); 1513 SM_APPEND_CHAR(c); 1514 } 1515 if (quoteit) 1516 { 1517 if (bp == &bufhead[1]) 1518 bp--; 1519 else 1520 SM_APPEND_CHAR('"'); 1521 while ((c = *p++) != ':') 1522 SM_APPEND_CHAR(c); 1523 SM_APPEND_CHAR(c); 1524 } 1525 1526 /* any trailing white space is part of group: */ 1527 while (SM_ISSPACE(*p)) 1528 { 1529 SM_APPEND_CHAR(*p); 1530 p++; 1531 } 1532 copylev = 0; 1533 putgmac = quoteit = false; 1534 bufhead = bp; 1535 addrhead = p; 1536 continue; 1537 } 1538 1539 if (c == ';' && copylev <= 0 && !ColonOkInAddr) 1540 SM_APPEND_CHAR(c); 1541 1542 /* check for characters that may have to be quoted */ 1543 if (strchr(MustQuoteChars, c) != NULL) 1544 { 1545 /* 1546 ** If these occur as the phrase part of a <> 1547 ** construct, but are not inside of () or already 1548 ** quoted, they will have to be quoted. Note that 1549 ** now (but don't actually do the quoting). 1550 */ 1551 1552 if (cmtlev <= 0 && !qmode) 1553 quoteit = true; 1554 } 1555 1556 /* check for angle brackets */ 1557 if (c == '<') 1558 { 1559 register char *q; 1560 1561 /* assume first of two angles is bogus */ 1562 if (gotangle) 1563 quoteit = true; 1564 gotangle = true; 1565 1566 /* oops -- have to change our mind */ 1567 anglelev = 1; 1568 if (SM_HAVE_ROOM) 1569 { 1570 if (!addangle) 1571 buflim--; 1572 addangle = true; 1573 } 1574 1575 bp = bufhead; 1576 if (quoteit) 1577 { 1578 SM_APPEND_CHAR('"'); 1579 1580 /* back up over the '<' and any spaces */ 1581 --p; 1582 while (p > addr && 1583 isascii(*--p) && isspace(*p)) 1584 continue; 1585 p++; 1586 } 1587 for (q = addrhead; q < p; ) 1588 { 1589 c = *q++; 1590 if (quoteit && c == '"') 1591 { 1592 SM_APPEND_CHAR('\\'); 1593 SM_APPEND_CHAR(c); 1594 } 1595 else 1596 SM_APPEND_CHAR(c); 1597 } 1598 if (quoteit) 1599 { 1600 if (bp == &buf[1]) 1601 bp--; 1602 else 1603 SM_APPEND_CHAR('"'); 1604 while ((c = *p++) != '<') 1605 SM_APPEND_CHAR(c); 1606 SM_APPEND_CHAR(c); 1607 } 1608 copylev = 0; 1609 putgmac = quoteit = false; 1610 continue; 1611 } 1612 1613 if (c == '>') 1614 { 1615 if (anglelev > 0) 1616 { 1617 anglelev--; 1618 if (SM_HAVE_ROOM) 1619 { 1620 if (addangle) 1621 buflim++; 1622 addangle = false; 1623 } 1624 } 1625 else if (SM_HAVE_ROOM) 1626 { 1627 /* syntax error: unmatched > */ 1628 if (copylev > 0 && bp > bufhead) 1629 bp--; 1630 quoteit = true; 1631 continue; 1632 } 1633 if (copylev++ <= 0) 1634 SM_APPEND_CHAR(c); 1635 continue; 1636 } 1637 1638 /* must be a real address character */ 1639 putg: 1640 if (copylev <= 0 && !putgmac) 1641 { 1642 if (bp > buf && bp[-1] == ')') 1643 SM_APPEND_CHAR(' '); 1644 SM_APPEND_CHAR(MACROEXPAND); 1645 SM_APPEND_CHAR('g'); 1646 putgmac = true; 1647 } 1648 } 1649 1650 /* repair any syntactic damage */ 1651 if (realqmode && bp < bufend) 1652 *bp++ = '"'; 1653 while (realcmtlev-- > 0 && bp < bufend) 1654 *bp++ = ')'; 1655 if (addangle && bp < bufend) 1656 *bp++ = '>'; 1657 *bp = '\0'; 1658 if (bp < bufend) 1659 goto success; 1660 1661 returng: 1662 /* String too long, punt */ 1663 buf[0] = '<'; 1664 buf[1] = MACROEXPAND; 1665 buf[2]= 'g'; 1666 buf[3] = '>'; 1667 buf[4]= '\0'; 1668 sm_syslog(LOG_ALERT, e->e_id, 1669 "Dropped invalid comments from header address"); 1670 1671 success: 1672 if (tTd(33, 1)) 1673 { 1674 sm_dprintf("crackaddr=>`"); 1675 xputs(sm_debug_file(), buf); 1676 sm_dprintf("'\n"); 1677 } 1678 return buf; 1679 } 1680 1681 /* 1682 ** PUTHEADER -- put the header part of a message from the in-core copy 1683 ** 1684 ** Parameters: 1685 ** mci -- the connection information. 1686 ** hdr -- the header to put. 1687 ** e -- envelope to use. 1688 ** flags -- MIME conversion flags. 1689 ** 1690 ** Returns: 1691 ** true iff header part was written successfully 1692 ** 1693 ** Side Effects: 1694 ** none. 1695 */ 1696 1697 bool 1698 putheader(mci, hdr, e, flags) 1699 register MCI *mci; 1700 HDR *hdr; 1701 register ENVELOPE *e; 1702 int flags; 1703 { 1704 register HDR *h; 1705 char buf[SM_MAX(MAXLINE,BUFSIZ)]; 1706 char obuf[MAXLINE]; 1707 1708 if (tTd(34, 1)) 1709 sm_dprintf("--- putheader, mailer = %s ---\n", 1710 mci->mci_mailer->m_name); 1711 1712 /* 1713 ** If we're in MIME mode, we're not really in the header of the 1714 ** message, just the header of one of the parts of the body of 1715 ** the message. Therefore MCIF_INHEADER should not be turned on. 1716 */ 1717 1718 if (!bitset(MCIF_INMIME, mci->mci_flags)) 1719 mci->mci_flags |= MCIF_INHEADER; 1720 1721 for (h = hdr; h != NULL; h = h->h_link) 1722 { 1723 register char *p = h->h_value; 1724 char *q; 1725 1726 if (tTd(34, 11)) 1727 { 1728 sm_dprintf(" %s:", h->h_field); 1729 xputs(sm_debug_file(), p); 1730 } 1731 1732 /* Skip empty headers */ 1733 if (h->h_value == NULL) 1734 continue; 1735 1736 /* heuristic shortening of MIME fields to avoid MUA overflows */ 1737 if (MaxMimeFieldLength > 0 && 1738 wordinclass(h->h_field, 1739 macid("{checkMIMEFieldHeaders}"))) 1740 { 1741 size_t len; 1742 1743 len = fix_mime_header(h, e); 1744 if (len > 0) 1745 { 1746 sm_syslog(LOG_ALERT, e->e_id, 1747 "Truncated MIME %s header due to field size (length = %ld) (possible attack)", 1748 h->h_field, (unsigned long) len); 1749 if (tTd(34, 11)) 1750 sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n", 1751 h->h_field, 1752 (unsigned long) len); 1753 } 1754 } 1755 1756 if (MaxMimeHeaderLength > 0 && 1757 wordinclass(h->h_field, 1758 macid("{checkMIMETextHeaders}"))) 1759 { 1760 size_t len; 1761 1762 len = strlen(h->h_value); 1763 if (len > (size_t) MaxMimeHeaderLength) 1764 { 1765 h->h_value[MaxMimeHeaderLength - 1] = '\0'; 1766 sm_syslog(LOG_ALERT, e->e_id, 1767 "Truncated long MIME %s header (length = %ld) (possible attack)", 1768 h->h_field, (unsigned long) len); 1769 if (tTd(34, 11)) 1770 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1771 h->h_field, 1772 (unsigned long) len); 1773 } 1774 } 1775 1776 if (MaxMimeHeaderLength > 0 && 1777 wordinclass(h->h_field, 1778 macid("{checkMIMEHeaders}"))) 1779 { 1780 size_t len; 1781 1782 len = strlen(h->h_value); 1783 if (shorten_rfc822_string(h->h_value, 1784 MaxMimeHeaderLength)) 1785 { 1786 if (len < MaxMimeHeaderLength) 1787 { 1788 /* we only rebalanced a bogus header */ 1789 sm_syslog(LOG_ALERT, e->e_id, 1790 "Fixed MIME %s header (possible attack)", 1791 h->h_field); 1792 if (tTd(34, 11)) 1793 sm_dprintf(" fixed MIME %s header (possible attack)\n", 1794 h->h_field); 1795 } 1796 else 1797 { 1798 /* we actually shortened header */ 1799 sm_syslog(LOG_ALERT, e->e_id, 1800 "Truncated long MIME %s header (length = %ld) (possible attack)", 1801 h->h_field, 1802 (unsigned long) len); 1803 if (tTd(34, 11)) 1804 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1805 h->h_field, 1806 (unsigned long) len); 1807 } 1808 } 1809 } 1810 1811 /* 1812 ** Suppress Content-Transfer-Encoding: if we are MIMEing 1813 ** and we are potentially converting from 8 bit to 7 bit 1814 ** MIME. If converting, add a new CTE header in 1815 ** mime8to7(). 1816 */ 1817 1818 if (bitset(H_CTE, h->h_flags) && 1819 bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, 1820 mci->mci_flags) && 1821 !bitset(M87F_NO8TO7, flags)) 1822 { 1823 if (tTd(34, 11)) 1824 sm_dprintf(" (skipped (content-transfer-encoding))\n"); 1825 continue; 1826 } 1827 1828 if (bitset(MCIF_INMIME, mci->mci_flags)) 1829 { 1830 if (tTd(34, 11)) 1831 sm_dprintf("\n"); 1832 if (!put_vanilla_header(h, p, mci)) 1833 goto writeerr; 1834 continue; 1835 } 1836 1837 if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 1838 !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) && 1839 (h->h_macro == '\0' || 1840 (q = macvalue(bitidx(h->h_macro), e)) == NULL || 1841 *q == '\0')) 1842 { 1843 if (tTd(34, 11)) 1844 sm_dprintf(" (skipped)\n"); 1845 continue; 1846 } 1847 1848 /* handle Resent-... headers specially */ 1849 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 1850 { 1851 if (tTd(34, 11)) 1852 sm_dprintf(" (skipped (resent))\n"); 1853 continue; 1854 } 1855 1856 /* suppress return receipts if requested */ 1857 if (bitset(H_RECEIPTTO, h->h_flags) && 1858 (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags))) 1859 { 1860 if (tTd(34, 11)) 1861 sm_dprintf(" (skipped (receipt))\n"); 1862 continue; 1863 } 1864 1865 /* macro expand value if generated internally */ 1866 if (bitset(H_DEFAULT, h->h_flags) || 1867 bitset(H_BINDLATE, h->h_flags)) 1868 { 1869 expand(p, buf, sizeof(buf), e); 1870 p = buf; 1871 if (*p == '\0') 1872 { 1873 if (tTd(34, 11)) 1874 sm_dprintf(" (skipped -- null value)\n"); 1875 continue; 1876 } 1877 } 1878 1879 if (bitset(H_BCC, h->h_flags) && !KeepBcc) 1880 { 1881 /* Bcc: field -- either truncate or delete */ 1882 if (bitset(EF_DELETE_BCC, e->e_flags)) 1883 { 1884 if (tTd(34, 11)) 1885 sm_dprintf(" (skipped -- bcc)\n"); 1886 } 1887 else 1888 { 1889 /* no other recipient headers: truncate value */ 1890 (void) sm_strlcpyn(obuf, sizeof(obuf), 2, 1891 h->h_field, ":"); 1892 if (!putline(obuf, mci)) 1893 goto writeerr; 1894 } 1895 continue; 1896 } 1897 1898 if (tTd(34, 11)) 1899 sm_dprintf("\n"); 1900 1901 if (bitset(H_FROM|H_RCPT, h->h_flags)) 1902 { 1903 /* address field */ 1904 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 1905 1906 if (bitset(H_FROM, h->h_flags)) 1907 oldstyle = false; 1908 if (!commaize(h, p, oldstyle, mci, e, 1909 PXLF_HEADER | PXLF_STRIPMQUOTE) 1910 && bitnset(M_xSMTP, mci->mci_mailer->m_flags)) 1911 goto writeerr; 1912 } 1913 else 1914 { 1915 if (!put_vanilla_header(h, p, mci)) 1916 goto writeerr; 1917 } 1918 } 1919 1920 /* 1921 ** If we are converting this to a MIME message, add the 1922 ** MIME headers (but not in MIME mode!). 1923 */ 1924 1925 #if MIME8TO7 1926 if (bitset(MM_MIME8BIT, MimeMode) && 1927 bitset(EF_HAS8BIT, e->e_flags) && 1928 !bitset(EF_DONT_MIME, e->e_flags) && 1929 !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 1930 !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) && 1931 hvalue("MIME-Version", e->e_header) == NULL) 1932 { 1933 if (!putline("MIME-Version: 1.0", mci)) 1934 goto writeerr; 1935 if (hvalue("Content-Type", e->e_header) == NULL) 1936 { 1937 (void) sm_snprintf(obuf, sizeof(obuf), 1938 "Content-Type: text/plain; charset=%s", 1939 defcharset(e)); 1940 if (!putline(obuf, mci)) 1941 goto writeerr; 1942 } 1943 if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL 1944 && !putline("Content-Transfer-Encoding: 8bit", mci)) 1945 goto writeerr; 1946 } 1947 #endif /* MIME8TO7 */ 1948 return true; 1949 1950 writeerr: 1951 return false; 1952 } 1953 1954 /* 1955 ** PUT_VANILLA_HEADER -- output a fairly ordinary header 1956 ** 1957 ** Parameters: 1958 ** h -- the structure describing this header 1959 ** v -- the value of this header 1960 ** mci -- the connection info for output 1961 ** 1962 ** Returns: 1963 ** true iff header was written successfully 1964 */ 1965 1966 static bool 1967 put_vanilla_header(h, v, mci) 1968 HDR *h; 1969 char *v; 1970 MCI *mci; 1971 { 1972 register char *nlp; 1973 register char *obp; 1974 int putflags; 1975 char obuf[MAXLINE + 256]; /* additional length for h_field */ 1976 1977 putflags = PXLF_HEADER | PXLF_STRIPMQUOTE; 1978 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1979 putflags |= PXLF_STRIP8BIT; 1980 (void) sm_snprintf(obuf, sizeof(obuf), "%.200s:", h->h_field); 1981 obp = obuf + strlen(obuf); 1982 while ((nlp = strchr(v, '\n')) != NULL) 1983 { 1984 int l; 1985 1986 l = nlp - v; 1987 1988 /* 1989 ** XXX This is broken for SPACELEFT()==0 1990 ** However, SPACELEFT() is always > 0 unless MAXLINE==1. 1991 */ 1992 1993 if (SPACELEFT(obuf, obp) - 1 < (size_t) l) 1994 l = SPACELEFT(obuf, obp) - 1; 1995 1996 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); 1997 if (!putxline(obuf, strlen(obuf), mci, putflags)) 1998 goto writeerr; 1999 v += l + 1; 2000 obp = obuf; 2001 if (*v != ' ' && *v != '\t') 2002 *obp++ = ' '; 2003 } 2004 2005 /* XXX This is broken for SPACELEFT()==0 */ 2006 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", 2007 (int) (SPACELEFT(obuf, obp) - 1), v); 2008 return putxline(obuf, strlen(obuf), mci, putflags); 2009 2010 writeerr: 2011 return false; 2012 } 2013 2014 /* 2015 ** COMMAIZE -- output a header field, making a comma-translated list. 2016 ** 2017 ** Parameters: 2018 ** h -- the header field to output. 2019 ** p -- the value to put in it. 2020 ** oldstyle -- true if this is an old style header. 2021 ** mci -- the connection information. 2022 ** e -- the envelope containing the message. 2023 ** putflags -- flags for putxline() 2024 ** 2025 ** Returns: 2026 ** true iff header field was written successfully 2027 ** 2028 ** Side Effects: 2029 ** outputs "p" to "mci". 2030 */ 2031 2032 bool 2033 commaize(h, p, oldstyle, mci, e, putflags) 2034 register HDR *h; 2035 register char *p; 2036 bool oldstyle; 2037 register MCI *mci; 2038 register ENVELOPE *e; 2039 int putflags; 2040 { 2041 register char *obp; 2042 int opos, omax, spaces; 2043 bool firstone = true; 2044 char **res; 2045 char obuf[MAXLINE + 3]; 2046 2047 /* 2048 ** Output the address list translated by the 2049 ** mailer and with commas. 2050 */ 2051 2052 if (tTd(14, 2)) 2053 sm_dprintf("commaize(%s:%s)\n", h->h_field, p); 2054 2055 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 2056 putflags |= PXLF_STRIP8BIT; 2057 2058 obp = obuf; 2059 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s:", h->h_field); 2060 /* opos = strlen(obp); instead of the next 3 lines? */ 2061 opos = strlen(h->h_field) + 1; 2062 if (opos > 201) 2063 opos = 201; 2064 obp += opos; 2065 2066 spaces = 0; 2067 while (*p != '\0' && SM_ISSPACE(*p)) 2068 { 2069 ++spaces; 2070 ++p; 2071 } 2072 if (spaces > 0) 2073 { 2074 SM_ASSERT(sizeof(obuf) > opos * 2); 2075 2076 /* 2077 ** Restrict number of spaces to half the length of buffer 2078 ** so the header field body can be put in here too. 2079 ** Note: this is a hack... 2080 */ 2081 2082 if (spaces > sizeof(obuf) / 2) 2083 spaces = sizeof(obuf) / 2; 2084 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%*s", spaces, 2085 ""); 2086 opos += spaces; 2087 obp += spaces; 2088 SM_ASSERT(obp < &obuf[MAXLINE]); 2089 } 2090 2091 omax = mci->mci_mailer->m_linelimit - 2; 2092 if (omax < 0 || omax > 78) 2093 omax = 78; 2094 2095 /* 2096 ** Run through the list of values. 2097 */ 2098 2099 while (*p != '\0') 2100 { 2101 register char *name; 2102 register int c; 2103 char savechar; 2104 int flags; 2105 auto int status; 2106 2107 /* 2108 ** Find the end of the name. New style names 2109 ** end with a comma, old style names end with 2110 ** a space character. However, spaces do not 2111 ** necessarily delimit an old-style name -- at 2112 ** signs mean keep going. 2113 */ 2114 2115 /* find end of name */ 2116 while ((SM_ISSPACE(*p)) || *p == ',') 2117 p++; 2118 name = p; 2119 res = NULL; 2120 for (;;) 2121 { 2122 auto char *oldp; 2123 char pvpbuf[PSBUFSIZE]; 2124 2125 res = prescan(p, oldstyle ? ' ' : ',', pvpbuf, 2126 sizeof(pvpbuf), &oldp, ExtTokenTab, false); 2127 p = oldp; 2128 #if _FFR_IGNORE_BOGUS_ADDR 2129 /* ignore addresses that can't be parsed */ 2130 if (res == NULL) 2131 { 2132 name = p; 2133 continue; 2134 } 2135 #endif /* _FFR_IGNORE_BOGUS_ADDR */ 2136 2137 /* look to see if we have an at sign */ 2138 while (*p != '\0' && SM_ISSPACE(*p)) 2139 p++; 2140 2141 if (*p != '@') 2142 { 2143 p = oldp; 2144 break; 2145 } 2146 ++p; 2147 while (*p != '\0' && SM_ISSPACE(*p)) 2148 p++; 2149 } 2150 /* at the end of one complete name */ 2151 2152 /* strip off trailing white space */ 2153 while (p >= name && 2154 ((SM_ISSPACE(*p)) || *p == ',' || *p == '\0')) 2155 p--; 2156 if (++p == name) 2157 continue; 2158 2159 /* 2160 ** if prescan() failed go a bit backwards; this is a hack, 2161 ** there should be some better error recovery. 2162 */ 2163 2164 if (res == NULL && p > name && 2165 !((SM_ISSPACE(*p)) || *p == ',' || *p == '\0')) 2166 --p; 2167 savechar = *p; 2168 *p = '\0'; 2169 2170 /* translate the name to be relative */ 2171 flags = RF_HEADERADDR|RF_ADDDOMAIN; 2172 if (bitset(H_FROM, h->h_flags)) 2173 flags |= RF_SENDERADDR; 2174 #if USERDB 2175 else if (e->e_from.q_mailer != NULL && 2176 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 2177 { 2178 char *q; 2179 2180 q = udbsender(name, e->e_rpool); 2181 if (q != NULL) 2182 name = q; 2183 } 2184 #endif /* USERDB */ 2185 status = EX_OK; 2186 name = remotename(name, mci->mci_mailer, flags, &status, e); 2187 if (status != EX_OK && bitnset(M_xSMTP, mci->mci_mailer->m_flags)) 2188 { 2189 if (status == EX_TEMPFAIL) 2190 mci->mci_flags |= MCIF_NOTSTICKY; 2191 goto writeerr; 2192 } 2193 if (*name == '\0') 2194 { 2195 *p = savechar; 2196 continue; 2197 } 2198 name = denlstring(name, false, true); 2199 2200 /* output the name with nice formatting */ 2201 opos += strlen(name); 2202 if (!firstone) 2203 opos += 2; 2204 if (opos > omax && !firstone) 2205 { 2206 (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp)); 2207 if (!putxline(obuf, strlen(obuf), mci, putflags)) 2208 goto writeerr; 2209 obp = obuf; 2210 (void) sm_strlcpy(obp, " ", sizeof(obuf)); 2211 opos = strlen(obp); 2212 obp += opos; 2213 opos += strlen(name); 2214 } 2215 else if (!firstone) 2216 { 2217 (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp)); 2218 obp += 2; 2219 } 2220 2221 while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 2222 *obp++ = c; 2223 firstone = false; 2224 *p = savechar; 2225 } 2226 if (obp < &obuf[sizeof(obuf)]) 2227 *obp = '\0'; 2228 else 2229 obuf[sizeof(obuf) - 1] = '\0'; 2230 return putxline(obuf, strlen(obuf), mci, putflags); 2231 2232 writeerr: 2233 return false; 2234 } 2235 2236 /* 2237 ** COPYHEADER -- copy header list 2238 ** 2239 ** This routine is the equivalent of newstr for header lists 2240 ** 2241 ** Parameters: 2242 ** header -- list of header structures to copy. 2243 ** rpool -- resource pool, or NULL 2244 ** 2245 ** Returns: 2246 ** a copy of 'header'. 2247 ** 2248 ** Side Effects: 2249 ** none. 2250 */ 2251 2252 HDR * 2253 copyheader(header, rpool) 2254 register HDR *header; 2255 SM_RPOOL_T *rpool; 2256 { 2257 register HDR *newhdr; 2258 HDR *ret; 2259 register HDR **tail = &ret; 2260 2261 while (header != NULL) 2262 { 2263 newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*newhdr)); 2264 STRUCTCOPY(*header, *newhdr); 2265 *tail = newhdr; 2266 tail = &newhdr->h_link; 2267 header = header->h_link; 2268 } 2269 *tail = NULL; 2270 2271 return ret; 2272 } 2273 2274 /* 2275 ** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header 2276 ** 2277 ** Run through all of the parameters of a MIME header and 2278 ** possibly truncate and rebalance the parameter according 2279 ** to MaxMimeFieldLength. 2280 ** 2281 ** Parameters: 2282 ** h -- the header to truncate/rebalance 2283 ** e -- the current envelope 2284 ** 2285 ** Returns: 2286 ** length of last offending field, 0 if all ok. 2287 ** 2288 ** Side Effects: 2289 ** string modified in place 2290 */ 2291 2292 static size_t 2293 fix_mime_header(h, e) 2294 HDR *h; 2295 ENVELOPE *e; 2296 { 2297 char *begin = h->h_value; 2298 char *end; 2299 size_t len = 0; 2300 size_t retlen = 0; 2301 2302 if (begin == NULL || *begin == '\0') 2303 return 0; 2304 2305 /* Split on each ';' */ 2306 /* find_character() never returns NULL */ 2307 while ((end = find_character(begin, ';')) != NULL) 2308 { 2309 char save = *end; 2310 char *bp; 2311 2312 *end = '\0'; 2313 2314 len = strlen(begin); 2315 2316 /* Shorten individual parameter */ 2317 if (shorten_rfc822_string(begin, MaxMimeFieldLength)) 2318 { 2319 if (len < MaxMimeFieldLength) 2320 { 2321 /* we only rebalanced a bogus field */ 2322 sm_syslog(LOG_ALERT, e->e_id, 2323 "Fixed MIME %s header field (possible attack)", 2324 h->h_field); 2325 if (tTd(34, 11)) 2326 sm_dprintf(" fixed MIME %s header field (possible attack)\n", 2327 h->h_field); 2328 } 2329 else 2330 { 2331 /* we actually shortened the header */ 2332 retlen = len; 2333 } 2334 } 2335 2336 /* Collapse the possibly shortened string with rest */ 2337 bp = begin + strlen(begin); 2338 if (bp != end) 2339 { 2340 char *ep = end; 2341 2342 *end = save; 2343 end = bp; 2344 2345 /* copy character by character due to overlap */ 2346 while (*ep != '\0') 2347 *bp++ = *ep++; 2348 *bp = '\0'; 2349 } 2350 else 2351 *end = save; 2352 if (*end == '\0') 2353 break; 2354 2355 /* Move past ';' */ 2356 begin = end + 1; 2357 } 2358 return retlen; 2359 } 2360