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