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