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