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