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