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