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