1 /* 2 ** Sendmail 3 ** Copyright (c) 1983 Eric P. Allman 4 ** Berkeley, California 5 ** 6 ** Copyright (c) 1983 Regents of the University of California. 7 ** All rights reserved. The Berkeley software License Agreement 8 ** specifies the terms and conditions for redistribution. 9 */ 10 11 #ifndef lint 12 static char SccsId[] = "@(#)headers.c 5.1 (Berkeley) 06/07/85"; 13 #endif not lint 14 15 # include <errno.h> 16 # include "sendmail.h" 17 18 SCCSID(@(#)headers.c 5.1 06/07/85); 19 20 /* 21 ** CHOMPHEADER -- process and save a header line. 22 ** 23 ** Called by collect and by readcf to deal with header lines. 24 ** 25 ** Parameters: 26 ** line -- header as a text line. 27 ** def -- if set, this is a default value. 28 ** 29 ** Returns: 30 ** flags for this header. 31 ** 32 ** Side Effects: 33 ** The header is saved on the header list. 34 ** Contents of 'line' are destroyed. 35 */ 36 37 chompheader(line, def) 38 char *line; 39 bool def; 40 { 41 register char *p; 42 register HDR *h; 43 HDR **hp; 44 char *fname; 45 char *fvalue; 46 struct hdrinfo *hi; 47 bool cond = FALSE; 48 BITMAP mopts; 49 extern char *crackaddr(); 50 51 # ifdef DEBUG 52 if (tTd(31, 6)) 53 printf("chompheader: %s\n", line); 54 # endif DEBUG 55 56 /* strip off options */ 57 clrbitmap(mopts); 58 p = line; 59 if (*p == '?') 60 { 61 /* have some */ 62 register char *q = index(p + 1, *p); 63 64 if (q != NULL) 65 { 66 *q++ = '\0'; 67 while (*++p != '\0') 68 setbitn(*p, mopts); 69 p = q; 70 } 71 else 72 syserr("chompheader: syntax error, line \"%s\"", line); 73 cond = TRUE; 74 } 75 76 /* find canonical name */ 77 fname = p; 78 p = index(p, ':'); 79 if (p == NULL) 80 { 81 syserr("chompheader: syntax error, line \"%s\"", line); 82 return (0); 83 } 84 fvalue = &p[1]; 85 while (isspace(*--p)) 86 continue; 87 *++p = '\0'; 88 makelower(fname); 89 90 /* strip field value on front */ 91 if (*fvalue == ' ') 92 fvalue++; 93 94 /* see if it is a known type */ 95 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 96 { 97 if (strcmp(hi->hi_field, fname) == 0) 98 break; 99 } 100 101 /* see if this is a resent message */ 102 if (!def && bitset(H_RESENT, hi->hi_flags)) 103 CurEnv->e_flags |= EF_RESENT; 104 105 /* if this means "end of header" quit now */ 106 if (bitset(H_EOH, hi->hi_flags)) 107 return (hi->hi_flags); 108 109 /* drop explicit From: if same as what we would generate -- for MH */ 110 p = "resent-from"; 111 if (!bitset(EF_RESENT, CurEnv->e_flags)) 112 p += 7; 113 if (!def && !QueueRun && strcmp(fname, p) == 0) 114 { 115 ADDRESS fromaddr; 116 117 if (strcmp(fvalue, CurEnv->e_from.q_paddr) == 0) 118 return (hi->hi_flags); 119 } 120 121 /* delete default value for this header */ 122 for (hp = &CurEnv->e_header; (h = *hp) != NULL; hp = &h->h_link) 123 { 124 if (strcmp(fname, h->h_field) == 0 && 125 bitset(H_DEFAULT, h->h_flags) && 126 !bitset(H_FORCE, h->h_flags)) 127 h->h_value = NULL; 128 } 129 130 /* create a new node */ 131 h = (HDR *) xalloc(sizeof *h); 132 h->h_field = newstr(fname); 133 h->h_value = NULL; 134 h->h_link = NULL; 135 bcopy(mopts, h->h_mflags, sizeof mopts); 136 *hp = h; 137 h->h_flags = hi->hi_flags; 138 if (def) 139 h->h_flags |= H_DEFAULT; 140 if (cond) 141 h->h_flags |= H_CHECK; 142 if (h->h_value != NULL) 143 free((char *) h->h_value); 144 h->h_value = newstr(fvalue); 145 146 /* hack to see if this is a new format message */ 147 if (!def && bitset(H_RCPT|H_FROM, h->h_flags) && 148 (index(fvalue, ',') != NULL || index(fvalue, '(') != NULL || 149 index(fvalue, '<') != NULL || index(fvalue, ';') != NULL)) 150 { 151 CurEnv->e_flags &= ~EF_OLDSTYLE; 152 } 153 154 return (h->h_flags); 155 } 156 /* 157 ** ADDHEADER -- add a header entry to the end of the queue. 158 ** 159 ** This bypasses the special checking of chompheader. 160 ** 161 ** Parameters: 162 ** field -- the name of the header field. 163 ** value -- the value of the field. It must be lower-cased. 164 ** e -- the envelope to add them to. 165 ** 166 ** Returns: 167 ** none. 168 ** 169 ** Side Effects: 170 ** adds the field on the list of headers for this envelope. 171 */ 172 173 addheader(field, value, e) 174 char *field; 175 char *value; 176 ENVELOPE *e; 177 { 178 register HDR *h; 179 register struct hdrinfo *hi; 180 HDR **hp; 181 182 /* find info struct */ 183 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 184 { 185 if (strcmp(field, hi->hi_field) == 0) 186 break; 187 } 188 189 /* find current place in list -- keep back pointer? */ 190 for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 191 { 192 if (strcmp(field, h->h_field) == 0) 193 break; 194 } 195 196 /* allocate space for new header */ 197 h = (HDR *) xalloc(sizeof *h); 198 h->h_field = field; 199 h->h_value = newstr(value); 200 h->h_link = *hp; 201 h->h_flags = hi->hi_flags | H_DEFAULT; 202 clrbitmap(h->h_mflags); 203 *hp = h; 204 } 205 /* 206 ** HVALUE -- return value of a header. 207 ** 208 ** Only "real" fields (i.e., ones that have not been supplied 209 ** as a default) are used. 210 ** 211 ** Parameters: 212 ** field -- the field name. 213 ** 214 ** Returns: 215 ** pointer to the value part. 216 ** NULL if not found. 217 ** 218 ** Side Effects: 219 ** none. 220 */ 221 222 char * 223 hvalue(field) 224 char *field; 225 { 226 register HDR *h; 227 228 for (h = CurEnv->e_header; h != NULL; h = h->h_link) 229 { 230 if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0) 231 return (h->h_value); 232 } 233 return (NULL); 234 } 235 /* 236 ** ISHEADER -- predicate telling if argument is a header. 237 ** 238 ** A line is a header if it has a single word followed by 239 ** optional white space followed by a colon. 240 ** 241 ** Parameters: 242 ** s -- string to check for possible headerness. 243 ** 244 ** Returns: 245 ** TRUE if s is a header. 246 ** FALSE otherwise. 247 ** 248 ** Side Effects: 249 ** none. 250 */ 251 252 bool 253 isheader(s) 254 register char *s; 255 { 256 while (*s > ' ' && *s != ':' && *s != '\0') 257 s++; 258 259 /* following technically violates RFC822 */ 260 while (isspace(*s)) 261 s++; 262 263 return (*s == ':'); 264 } 265 /* 266 ** EATHEADER -- run through the stored header and extract info. 267 ** 268 ** Parameters: 269 ** e -- the envelope to process. 270 ** 271 ** Returns: 272 ** none. 273 ** 274 ** Side Effects: 275 ** Sets a bunch of global variables from information 276 ** in the collected header. 277 ** Aborts the message if the hop count is exceeded. 278 */ 279 280 eatheader(e) 281 register ENVELOPE *e; 282 { 283 register HDR *h; 284 register char *p; 285 int hopcnt = 0; 286 287 #ifdef DEBUG 288 if (tTd(32, 1)) 289 printf("----- collected header -----\n"); 290 #endif DEBUG 291 for (h = e->e_header; h != NULL; h = h->h_link) 292 { 293 #ifdef DEBUG 294 extern char *capitalize(); 295 296 if (tTd(32, 1)) 297 printf("%s: %s\n", capitalize(h->h_field), h->h_value); 298 #endif DEBUG 299 /* count the number of times it has been processed */ 300 if (bitset(H_TRACE, h->h_flags)) 301 hopcnt++; 302 303 /* send to this person if we so desire */ 304 if (GrabTo && bitset(H_RCPT, h->h_flags) && 305 !bitset(H_DEFAULT, h->h_flags) && 306 (!bitset(EF_RESENT, CurEnv->e_flags) || bitset(H_RESENT, h->h_flags))) 307 { 308 sendtolist(h->h_value, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 309 } 310 311 /* log the message-id */ 312 #ifdef LOG 313 if (!QueueRun && LogLevel > 8 && h->h_value != NULL && 314 strcmp(h->h_field, "message-id") == 0) 315 { 316 char buf[MAXNAME]; 317 318 p = h->h_value; 319 if (bitset(H_DEFAULT, h->h_flags)) 320 { 321 expand(p, buf, &buf[sizeof buf], e); 322 p = buf; 323 } 324 syslog(LOG_INFO, "%s: message-id=%s", e->e_id, p); 325 } 326 #endif LOG 327 } 328 #ifdef DEBUG 329 if (tTd(32, 1)) 330 printf("----------------------------\n"); 331 #endif DEBUG 332 333 /* store hop count */ 334 if (hopcnt > e->e_hopcount) 335 e->e_hopcount = hopcnt; 336 337 /* message priority */ 338 p = hvalue("precedence"); 339 if (p != NULL) 340 e->e_class = priencode(p); 341 if (!QueueRun) 342 e->e_msgpriority = e->e_msgsize + e->e_ctime - e->e_class * WKPRIFACT; 343 344 /* return receipt to */ 345 p = hvalue("return-receipt-to"); 346 if (p != NULL) 347 e->e_receiptto = p; 348 349 /* errors to */ 350 p = hvalue("errors-to"); 351 if (p != NULL) 352 sendtolist(p, (ADDRESS *) NULL, &e->e_errorqueue); 353 354 /* from person */ 355 if (OpMode == MD_ARPAFTP) 356 { 357 register struct hdrinfo *hi = HdrInfo; 358 359 for (p = NULL; p == NULL && hi->hi_field != NULL; hi++) 360 { 361 if (bitset(H_FROM, hi->hi_flags)) 362 p = hvalue(hi->hi_field); 363 } 364 if (p != NULL) 365 setsender(p); 366 } 367 368 /* full name of from person */ 369 p = hvalue("full-name"); 370 if (p != NULL) 371 define('x', p, e); 372 373 /* date message originated */ 374 p = hvalue("posted-date"); 375 if (p == NULL) 376 p = hvalue("date"); 377 if (p != NULL) 378 { 379 define('a', p, e); 380 /* we don't have a good way to do canonical conversion .... 381 define('d', newstr(arpatounix(p)), e); 382 .... so we will ignore the problem for the time being */ 383 } 384 385 /* 386 ** Log collection information. 387 */ 388 389 # ifdef LOG 390 if (!QueueRun && LogLevel > 1) 391 { 392 syslog(LOG_INFO, "%s: from=%s, size=%ld, class=%d\n", 393 CurEnv->e_id, CurEnv->e_from.q_paddr, CurEnv->e_msgsize, 394 CurEnv->e_class); 395 } 396 # endif LOG 397 } 398 /* 399 ** PRIENCODE -- encode external priority names into internal values. 400 ** 401 ** Parameters: 402 ** p -- priority in ascii. 403 ** 404 ** Returns: 405 ** priority as a numeric level. 406 ** 407 ** Side Effects: 408 ** none. 409 */ 410 411 priencode(p) 412 char *p; 413 { 414 register int i; 415 extern bool sameword(); 416 417 for (i = 0; i < NumPriorities; i++) 418 { 419 if (sameword(p, Priorities[i].pri_name)) 420 return (Priorities[i].pri_val); 421 } 422 423 /* unknown priority */ 424 return (0); 425 } 426 /* 427 ** CRACKADDR -- parse an address and turn it into a macro 428 ** 429 ** This doesn't actually parse the address -- it just extracts 430 ** it and replaces it with "$g". The parse is totally ad hoc 431 ** and isn't even guaranteed to leave something syntactically 432 ** identical to what it started with. However, it does leave 433 ** something semantically identical. 434 ** 435 ** The process is kind of strange. There are a number of 436 ** interesting cases: 437 ** 1. comment <address> comment ==> comment <$g> comment 438 ** 2. address ==> address 439 ** 3. address (comment) ==> $g (comment) 440 ** 4. (comment) address ==> (comment) $g 441 ** And then there are the hard cases.... 442 ** 5. add (comment) ress ==> $g (comment) 443 ** 6. comment <address (comment)> ==> comment <$g (comment)> 444 ** 7. .... etc .... 445 ** 446 ** Parameters: 447 ** addr -- the address to be cracked. 448 ** 449 ** Returns: 450 ** a pointer to the new version. 451 ** 452 ** Side Effects: 453 ** none. 454 ** 455 ** Warning: 456 ** The return value is saved in local storage and should 457 ** be copied if it is to be reused. 458 */ 459 460 char * 461 crackaddr(addr) 462 register char *addr; 463 { 464 register char *p; 465 register int i; 466 static char buf[MAXNAME]; 467 char *rhs; 468 bool gotaddr; 469 register char *bp; 470 471 # ifdef DEBUG 472 if (tTd(33, 1)) 473 printf("crackaddr(%s)\n", addr); 474 # endif DEBUG 475 476 strcpy(buf, ""); 477 rhs = NULL; 478 479 /* strip leading spaces */ 480 while (*addr != '\0' && isspace(*addr)) 481 addr++; 482 483 /* 484 ** See if we have anything in angle brackets. If so, that is 485 ** the address part, and the rest is the comment. 486 */ 487 488 p = index(addr, '<'); 489 if (p != NULL) 490 { 491 /* copy the beginning of the addr field to the buffer */ 492 *p = '\0'; 493 strcpy(buf, addr); 494 strcat(buf, "<"); 495 *p++ = '<'; 496 497 /* skip spaces */ 498 while (isspace(*p)) 499 p++; 500 501 /* find the matching right angle bracket */ 502 addr = p; 503 for (i = 0; *p != '\0'; p++) 504 { 505 switch (*p) 506 { 507 case '<': 508 i++; 509 break; 510 511 case '>': 512 i--; 513 break; 514 } 515 if (i < 0) 516 break; 517 } 518 519 /* p now points to the closing quote (or a null byte) */ 520 if (*p != '\0') 521 { 522 /* make rhs point to the extra stuff at the end */ 523 rhs = p; 524 *p++ = '\0'; 525 } 526 } 527 528 /* 529 ** Now parse the real address part. "addr" points to the (null 530 ** terminated) version of what we are inerested in; rhs points 531 ** to the extra stuff at the end of the line, if any. 532 */ 533 534 p = addr; 535 536 /* now strip out comments */ 537 bp = &buf[strlen(buf)]; 538 gotaddr = FALSE; 539 for (; *p != '\0'; p++) 540 { 541 if (*p == '(') 542 { 543 /* copy to matching close paren */ 544 *bp++ = *p++; 545 for (i = 0; *p != '\0'; p++) 546 { 547 *bp++ = *p; 548 switch (*p) 549 { 550 case '(': 551 i++; 552 break; 553 554 case ')': 555 i--; 556 break; 557 } 558 if (i < 0) 559 break; 560 } 561 continue; 562 } 563 564 /* 565 ** If this is the first "real" character we have seen, 566 ** then we put the "$g" in the buffer now. 567 */ 568 569 if (isspace(*p)) 570 *bp++ = *p; 571 else if (!gotaddr) 572 { 573 strcpy(bp, "\001g"); 574 bp += 2; 575 gotaddr = TRUE; 576 } 577 } 578 579 /* hack, hack.... strip trailing blanks */ 580 do 581 { 582 *bp-- = '\0'; 583 } while (isspace(*bp)); 584 bp++; 585 586 /* put any right hand side back on */ 587 if (rhs != NULL) 588 { 589 *rhs = '>'; 590 strcpy(bp, rhs); 591 } 592 593 # ifdef DEBUG 594 if (tTd(33, 1)) 595 printf("crackaddr=>`%s'\n", buf); 596 # endif DEBUG 597 598 return (buf); 599 } 600 /* 601 ** PUTHEADER -- put the header part of a message from the in-core copy 602 ** 603 ** Parameters: 604 ** fp -- file to put it on. 605 ** m -- mailer to use. 606 ** e -- envelope to use. 607 ** 608 ** Returns: 609 ** none. 610 ** 611 ** Side Effects: 612 ** none. 613 */ 614 615 putheader(fp, m, e) 616 register FILE *fp; 617 register MAILER *m; 618 register ENVELOPE *e; 619 { 620 char buf[BUFSIZ]; 621 register HDR *h; 622 extern char *arpadate(); 623 extern char *capitalize(); 624 char obuf[MAXLINE]; 625 626 for (h = e->e_header; h != NULL; h = h->h_link) 627 { 628 register char *p; 629 extern bool bitintersect(); 630 631 if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 632 !bitintersect(h->h_mflags, m->m_flags)) 633 continue; 634 635 /* handle Resent-... headers specially */ 636 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 637 continue; 638 639 p = h->h_value; 640 if (bitset(H_DEFAULT, h->h_flags)) 641 { 642 /* macro expand value if generated internally */ 643 expand(p, buf, &buf[sizeof buf], e); 644 p = buf; 645 if (p == NULL || *p == '\0') 646 continue; 647 } 648 649 if (bitset(H_FROM|H_RCPT, h->h_flags)) 650 { 651 /* address field */ 652 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 653 654 if (bitset(H_FROM, h->h_flags)) 655 oldstyle = FALSE; 656 commaize(h, p, fp, oldstyle, m); 657 } 658 else 659 { 660 /* vanilla header line */ 661 register char *nlp; 662 663 (void) sprintf(obuf, "%s: ", capitalize(h->h_field)); 664 while ((nlp = index(p, '\n')) != NULL) 665 { 666 *nlp = '\0'; 667 (void) strcat(obuf, p); 668 *nlp = '\n'; 669 putline(obuf, fp, m); 670 p = ++nlp; 671 obuf[0] = '\0'; 672 } 673 (void) strcat(obuf, p); 674 putline(obuf, fp, m); 675 } 676 } 677 } 678 /* 679 ** COMMAIZE -- output a header field, making a comma-translated list. 680 ** 681 ** Parameters: 682 ** h -- the header field to output. 683 ** p -- the value to put in it. 684 ** fp -- file to put it to. 685 ** oldstyle -- TRUE if this is an old style header. 686 ** m -- a pointer to the mailer descriptor. If NULL, 687 ** don't transform the name at all. 688 ** 689 ** Returns: 690 ** none. 691 ** 692 ** Side Effects: 693 ** outputs "p" to file "fp". 694 */ 695 696 commaize(h, p, fp, oldstyle, m) 697 register HDR *h; 698 register char *p; 699 FILE *fp; 700 bool oldstyle; 701 register MAILER *m; 702 { 703 register char *obp; 704 int opos; 705 bool firstone = TRUE; 706 char obuf[MAXLINE + 3]; 707 708 /* 709 ** Output the address list translated by the 710 ** mailer and with commas. 711 */ 712 713 # ifdef DEBUG 714 if (tTd(14, 2)) 715 printf("commaize(%s: %s)\n", h->h_field, p); 716 # endif DEBUG 717 718 obp = obuf; 719 (void) sprintf(obp, "%s: ", capitalize(h->h_field)); 720 opos = strlen(h->h_field) + 2; 721 obp += opos; 722 723 /* 724 ** Run through the list of values. 725 */ 726 727 while (*p != '\0') 728 { 729 register char *name; 730 char savechar; 731 extern char *remotename(); 732 extern char *DelimChar; /* defined in prescan */ 733 734 /* 735 ** Find the end of the name. New style names 736 ** end with a comma, old style names end with 737 ** a space character. However, spaces do not 738 ** necessarily delimit an old-style name -- at 739 ** signs mean keep going. 740 */ 741 742 /* find end of name */ 743 while (isspace(*p) || *p == ',') 744 p++; 745 name = p; 746 for (;;) 747 { 748 char *oldp; 749 char pvpbuf[PSBUFSIZE]; 750 extern bool isatword(); 751 extern char **prescan(); 752 753 (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf); 754 p = DelimChar; 755 756 /* look to see if we have an at sign */ 757 oldp = p; 758 while (*p != '\0' && isspace(*p)) 759 p++; 760 761 if (*p != '@' && !isatword(p)) 762 { 763 p = oldp; 764 break; 765 } 766 p += *p == '@' ? 1 : 2; 767 while (*p != '\0' && isspace(*p)) 768 p++; 769 } 770 /* at the end of one complete name */ 771 772 /* strip off trailing white space */ 773 while (p >= name && (isspace(*p) || *p == ',' || *p == '\0')) 774 p--; 775 if (++p == name) 776 continue; 777 savechar = *p; 778 *p = '\0'; 779 780 /* translate the name to be relative */ 781 name = remotename(name, m, bitset(H_FROM, h->h_flags), FALSE); 782 if (*name == '\0') 783 { 784 *p = savechar; 785 continue; 786 } 787 788 /* output the name with nice formatting */ 789 opos += qstrlen(name); 790 if (!firstone) 791 opos += 2; 792 if (opos > 78 && !firstone) 793 { 794 (void) strcpy(obp, ",\n"); 795 putline(obuf, fp, m); 796 obp = obuf; 797 (void) sprintf(obp, " "); 798 opos = strlen(obp); 799 obp += opos; 800 opos += qstrlen(name); 801 } 802 else if (!firstone) 803 { 804 (void) sprintf(obp, ", "); 805 obp += 2; 806 } 807 808 /* strip off quote bits as we output */ 809 while (*name != '\0' && obp < &obuf[MAXLINE]) 810 { 811 if (bitset(0200, *name)) 812 *obp++ = '\\'; 813 *obp++ = *name++ & ~0200; 814 } 815 firstone = FALSE; 816 *p = savechar; 817 } 818 (void) strcpy(obp, "\n"); 819 putline(obuf, fp, m); 820 } 821 /* 822 ** ISATWORD -- tell if the word we are pointing to is "at". 823 ** 824 ** Parameters: 825 ** p -- word to check. 826 ** 827 ** Returns: 828 ** TRUE -- if p is the word at. 829 ** FALSE -- otherwise. 830 ** 831 ** Side Effects: 832 ** none. 833 */ 834 835 bool 836 isatword(p) 837 register char *p; 838 { 839 extern char lower(); 840 841 if (lower(p[0]) == 'a' && lower(p[1]) == 't' && 842 p[2] != '\0' && isspace(p[2])) 843 return (TRUE); 844 return (FALSE); 845 } 846