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