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[] = "@(#)readcf.c 5.1 (Berkeley) 06/07/85"; 13 #endif not lint 14 15 # include "sendmail.h" 16 17 SCCSID(@(#)readcf.c 5.1 06/07/85); 18 19 /* 20 ** READCF -- read control file. 21 ** 22 ** This routine reads the control file and builds the internal 23 ** form. 24 ** 25 ** The file is formatted as a sequence of lines, each taken 26 ** atomically. The first character of each line describes how 27 ** the line is to be interpreted. The lines are: 28 ** Dxval Define macro x to have value val. 29 ** Cxword Put word into class x. 30 ** Fxfile [fmt] Read file for lines to put into 31 ** class x. Use scanf string 'fmt' 32 ** or "%s" if not present. Fmt should 33 ** only produce one string-valued result. 34 ** Hname: value Define header with field-name 'name' 35 ** and value as specified; this will be 36 ** macro expanded immediately before 37 ** use. 38 ** Sn Use rewriting set n. 39 ** Rlhs rhs Rewrite addresses that match lhs to 40 ** be rhs. 41 ** Mn p f s r a Define mailer. n - internal name, 42 ** p - pathname, f - flags, s - rewriting 43 ** ruleset for sender, s - rewriting ruleset 44 ** for recipients, a - argument vector. 45 ** Oxvalue Set option x to value. 46 ** Pname=value Set precedence name to value. 47 ** 48 ** Parameters: 49 ** cfname -- control file name. 50 ** 51 ** Returns: 52 ** none. 53 ** 54 ** Side Effects: 55 ** Builds several internal tables. 56 */ 57 58 readcf(cfname) 59 char *cfname; 60 { 61 FILE *cf; 62 int ruleset = 0; 63 char *q; 64 char **pv; 65 struct rewrite *rwp = NULL; 66 char buf[MAXLINE]; 67 register char *p; 68 extern char **prescan(); 69 extern char **copyplist(); 70 char exbuf[MAXLINE]; 71 char pvpbuf[PSBUFSIZE]; 72 extern char *fgetfolded(); 73 extern char *munchstring(); 74 75 cf = fopen(cfname, "r"); 76 if (cf == NULL) 77 { 78 syserr("cannot open %s", cfname); 79 exit(EX_OSFILE); 80 } 81 82 FileName = cfname; 83 LineNumber = 0; 84 while (fgetfolded(buf, sizeof buf, cf) != NULL) 85 { 86 /* map $ into \001 (ASCII SOH) for macro expansion */ 87 for (p = buf; *p != '\0'; p++) 88 { 89 if (*p != '$') 90 continue; 91 92 if (p[1] == '$') 93 { 94 /* actual dollar sign.... */ 95 strcpy(p, p + 1); 96 continue; 97 } 98 99 /* convert to macro expansion character */ 100 *p = '\001'; 101 } 102 103 /* interpret this line */ 104 switch (buf[0]) 105 { 106 case '\0': 107 case '#': /* comment */ 108 break; 109 110 case 'R': /* rewriting rule */ 111 for (p = &buf[1]; *p != '\0' && *p != '\t'; p++) 112 continue; 113 114 if (*p == '\0') 115 { 116 syserr("invalid rewrite line \"%s\"", buf); 117 break; 118 } 119 120 /* allocate space for the rule header */ 121 if (rwp == NULL) 122 { 123 RewriteRules[ruleset] = rwp = 124 (struct rewrite *) xalloc(sizeof *rwp); 125 } 126 else 127 { 128 rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 129 rwp = rwp->r_next; 130 } 131 rwp->r_next = NULL; 132 133 /* expand and save the LHS */ 134 *p = '\0'; 135 expand(&buf[1], exbuf, &exbuf[sizeof exbuf], CurEnv); 136 rwp->r_lhs = prescan(exbuf, '\t', pvpbuf); 137 if (rwp->r_lhs != NULL) 138 rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 139 140 /* expand and save the RHS */ 141 while (*++p == '\t') 142 continue; 143 q = p; 144 while (*p != '\0' && *p != '\t') 145 p++; 146 *p = '\0'; 147 expand(q, exbuf, &exbuf[sizeof exbuf], CurEnv); 148 rwp->r_rhs = prescan(exbuf, '\t', pvpbuf); 149 if (rwp->r_rhs != NULL) 150 rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 151 break; 152 153 case 'S': /* select rewriting set */ 154 ruleset = atoi(&buf[1]); 155 if (ruleset >= MAXRWSETS || ruleset < 0) 156 { 157 syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS); 158 ruleset = 0; 159 } 160 rwp = NULL; 161 break; 162 163 case 'D': /* macro definition */ 164 define(buf[1], newstr(munchstring(&buf[2])), CurEnv); 165 break; 166 167 case 'H': /* required header line */ 168 (void) chompheader(&buf[1], TRUE); 169 break; 170 171 case 'C': /* word class */ 172 case 'F': /* word class from file */ 173 /* read list of words from argument or file */ 174 if (buf[0] == 'F') 175 { 176 /* read from file */ 177 for (p = &buf[2]; *p != '\0' && !isspace(*p); p++) 178 continue; 179 if (*p == '\0') 180 p = "%s"; 181 else 182 { 183 *p = '\0'; 184 while (isspace(*++p)) 185 continue; 186 } 187 fileclass(buf[1], &buf[2], p); 188 break; 189 } 190 191 /* scan the list of words and set class for all */ 192 for (p = &buf[2]; *p != '\0'; ) 193 { 194 register char *wd; 195 char delim; 196 197 while (*p != '\0' && isspace(*p)) 198 p++; 199 wd = p; 200 while (*p != '\0' && !isspace(*p)) 201 p++; 202 delim = *p; 203 *p = '\0'; 204 if (wd[0] != '\0') 205 setclass(buf[1], wd); 206 *p = delim; 207 } 208 break; 209 210 case 'M': /* define mailer */ 211 makemailer(&buf[1]); 212 break; 213 214 case 'O': /* set option */ 215 setoption(buf[1], &buf[2], TRUE, FALSE); 216 break; 217 218 case 'P': /* set precedence */ 219 if (NumPriorities >= MAXPRIORITIES) 220 { 221 toomany('P', MAXPRIORITIES); 222 break; 223 } 224 for (p = &buf[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 225 continue; 226 if (*p == '\0') 227 goto badline; 228 *p = '\0'; 229 Priorities[NumPriorities].pri_name = newstr(&buf[1]); 230 Priorities[NumPriorities].pri_val = atoi(++p); 231 NumPriorities++; 232 break; 233 234 case 'T': /* trusted user(s) */ 235 p = &buf[1]; 236 while (*p != '\0') 237 { 238 while (isspace(*p)) 239 p++; 240 q = p; 241 while (*p != '\0' && !isspace(*p)) 242 p++; 243 if (*p != '\0') 244 *p++ = '\0'; 245 if (*q == '\0') 246 continue; 247 for (pv = TrustedUsers; *pv != NULL; pv++) 248 continue; 249 if (pv >= &TrustedUsers[MAXTRUST]) 250 { 251 toomany('T', MAXTRUST); 252 break; 253 } 254 *pv = newstr(q); 255 } 256 break; 257 258 default: 259 badline: 260 syserr("unknown control line \"%s\"", buf); 261 } 262 } 263 FileName = NULL; 264 } 265 /* 266 ** TOOMANY -- signal too many of some option 267 ** 268 ** Parameters: 269 ** id -- the id of the error line 270 ** maxcnt -- the maximum possible values 271 ** 272 ** Returns: 273 ** none. 274 ** 275 ** Side Effects: 276 ** gives a syserr. 277 */ 278 279 toomany(id, maxcnt) 280 char id; 281 int maxcnt; 282 { 283 syserr("too many %c lines, %d max", id, maxcnt); 284 } 285 /* 286 ** FILECLASS -- read members of a class from a file 287 ** 288 ** Parameters: 289 ** class -- class to define. 290 ** filename -- name of file to read. 291 ** fmt -- scanf string to use for match. 292 ** 293 ** Returns: 294 ** none 295 ** 296 ** Side Effects: 297 ** 298 ** puts all lines in filename that match a scanf into 299 ** the named class. 300 */ 301 302 fileclass(class, filename, fmt) 303 int class; 304 char *filename; 305 char *fmt; 306 { 307 register FILE *f; 308 char buf[MAXLINE]; 309 310 f = fopen(filename, "r"); 311 if (f == NULL) 312 { 313 syserr("cannot open %s", filename); 314 return; 315 } 316 317 while (fgets(buf, sizeof buf, f) != NULL) 318 { 319 register STAB *s; 320 char wordbuf[MAXNAME+1]; 321 322 if (sscanf(buf, fmt, wordbuf) != 1) 323 continue; 324 s = stab(wordbuf, ST_CLASS, ST_ENTER); 325 setbitn(class, s->s_class); 326 } 327 328 (void) fclose(f); 329 } 330 /* 331 ** MAKEMAILER -- define a new mailer. 332 ** 333 ** Parameters: 334 ** line -- description of mailer. This is in labeled 335 ** fields. The fields are: 336 ** P -- the path to the mailer 337 ** F -- the flags associated with the mailer 338 ** A -- the argv for this mailer 339 ** S -- the sender rewriting set 340 ** R -- the recipient rewriting set 341 ** E -- the eol string 342 ** The first word is the canonical name of the mailer. 343 ** 344 ** Returns: 345 ** none. 346 ** 347 ** Side Effects: 348 ** enters the mailer into the mailer table. 349 */ 350 351 makemailer(line) 352 char *line; 353 { 354 register char *p; 355 register struct mailer *m; 356 register STAB *s; 357 int i; 358 char fcode; 359 extern int NextMailer; 360 extern char **makeargv(); 361 extern char *munchstring(); 362 extern char *DelimChar; 363 extern long atol(); 364 365 /* allocate a mailer and set up defaults */ 366 m = (struct mailer *) xalloc(sizeof *m); 367 bzero((char *) m, sizeof *m); 368 m->m_mno = NextMailer; 369 m->m_eol = "\n"; 370 371 /* collect the mailer name */ 372 for (p = line; *p != '\0' && *p != ',' && !isspace(*p); p++) 373 continue; 374 if (*p != '\0') 375 *p++ = '\0'; 376 m->m_name = newstr(line); 377 378 /* now scan through and assign info from the fields */ 379 while (*p != '\0') 380 { 381 while (*p != '\0' && (*p == ',' || isspace(*p))) 382 p++; 383 384 /* p now points to field code */ 385 fcode = *p; 386 while (*p != '\0' && *p != '=' && *p != ',') 387 p++; 388 if (*p++ != '=') 389 { 390 syserr("`=' expected"); 391 return; 392 } 393 while (isspace(*p)) 394 p++; 395 396 /* p now points to the field body */ 397 p = munchstring(p); 398 399 /* install the field into the mailer struct */ 400 switch (fcode) 401 { 402 case 'P': /* pathname */ 403 m->m_mailer = newstr(p); 404 break; 405 406 case 'F': /* flags */ 407 for (; *p != '\0'; p++) 408 setbitn(*p, m->m_flags); 409 break; 410 411 case 'S': /* sender rewriting ruleset */ 412 case 'R': /* recipient rewriting ruleset */ 413 i = atoi(p); 414 if (i < 0 || i >= MAXRWSETS) 415 { 416 syserr("invalid rewrite set, %d max", MAXRWSETS); 417 return; 418 } 419 if (fcode == 'S') 420 m->m_s_rwset = i; 421 else 422 m->m_r_rwset = i; 423 break; 424 425 case 'E': /* end of line string */ 426 m->m_eol = newstr(p); 427 break; 428 429 case 'A': /* argument vector */ 430 m->m_argv = makeargv(p); 431 break; 432 433 case 'M': /* maximum message size */ 434 m->m_maxsize = atol(p); 435 break; 436 } 437 438 p = DelimChar; 439 } 440 441 /* now store the mailer away */ 442 if (NextMailer >= MAXMAILERS) 443 { 444 syserr("too many mailers defined (%d max)", MAXMAILERS); 445 return; 446 } 447 Mailer[NextMailer++] = m; 448 s = stab(m->m_name, ST_MAILER, ST_ENTER); 449 s->s_mailer = m; 450 } 451 /* 452 ** MUNCHSTRING -- translate a string into internal form. 453 ** 454 ** Parameters: 455 ** p -- the string to munch. 456 ** 457 ** Returns: 458 ** the munched string. 459 ** 460 ** Side Effects: 461 ** Sets "DelimChar" to point to the string that caused us 462 ** to stop. 463 */ 464 465 char * 466 munchstring(p) 467 register char *p; 468 { 469 register char *q; 470 bool backslash = FALSE; 471 bool quotemode = FALSE; 472 static char buf[MAXLINE]; 473 extern char *DelimChar; 474 475 for (q = buf; *p != '\0'; p++) 476 { 477 if (backslash) 478 { 479 /* everything is roughly literal */ 480 backslash = FALSE; 481 switch (*p) 482 { 483 case 'r': /* carriage return */ 484 *q++ = '\r'; 485 continue; 486 487 case 'n': /* newline */ 488 *q++ = '\n'; 489 continue; 490 491 case 'f': /* form feed */ 492 *q++ = '\f'; 493 continue; 494 495 case 'b': /* backspace */ 496 *q++ = '\b'; 497 continue; 498 } 499 *q++ = *p; 500 } 501 else 502 { 503 if (*p == '\\') 504 backslash = TRUE; 505 else if (*p == '"') 506 quotemode = !quotemode; 507 else if (quotemode || *p != ',') 508 *q++ = *p; 509 else 510 break; 511 } 512 } 513 514 DelimChar = p; 515 *q++ = '\0'; 516 return (buf); 517 } 518 /* 519 ** MAKEARGV -- break up a string into words 520 ** 521 ** Parameters: 522 ** p -- the string to break up. 523 ** 524 ** Returns: 525 ** a char **argv (dynamically allocated) 526 ** 527 ** Side Effects: 528 ** munges p. 529 */ 530 531 char ** 532 makeargv(p) 533 register char *p; 534 { 535 char *q; 536 int i; 537 char **avp; 538 char *argv[MAXPV + 1]; 539 540 /* take apart the words */ 541 i = 0; 542 while (*p != '\0' && i < MAXPV) 543 { 544 q = p; 545 while (*p != '\0' && !isspace(*p)) 546 p++; 547 while (isspace(*p)) 548 *p++ = '\0'; 549 argv[i++] = newstr(q); 550 } 551 argv[i++] = NULL; 552 553 /* now make a copy of the argv */ 554 avp = (char **) xalloc(sizeof *avp * i); 555 bcopy((char *) argv, (char *) avp, sizeof *avp * i); 556 557 return (avp); 558 } 559 /* 560 ** PRINTRULES -- print rewrite rules (for debugging) 561 ** 562 ** Parameters: 563 ** none. 564 ** 565 ** Returns: 566 ** none. 567 ** 568 ** Side Effects: 569 ** prints rewrite rules. 570 */ 571 572 # ifdef DEBUG 573 574 printrules() 575 { 576 register struct rewrite *rwp; 577 register int ruleset; 578 579 for (ruleset = 0; ruleset < 10; ruleset++) 580 { 581 if (RewriteRules[ruleset] == NULL) 582 continue; 583 printf("\n----Rule Set %d:", ruleset); 584 585 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 586 { 587 printf("\nLHS:"); 588 printav(rwp->r_lhs); 589 printf("RHS:"); 590 printav(rwp->r_rhs); 591 } 592 } 593 } 594 595 # endif DEBUG 596 /* 597 ** SETOPTION -- set global processing option 598 ** 599 ** Parameters: 600 ** opt -- option name. 601 ** val -- option value (as a text string). 602 ** safe -- set if this came from a configuration file. 603 ** Some options (if set from the command line) will 604 ** reset the user id to avoid security problems. 605 ** sticky -- if set, don't let other setoptions override 606 ** this value. 607 ** 608 ** Returns: 609 ** none. 610 ** 611 ** Side Effects: 612 ** Sets options as implied by the arguments. 613 */ 614 615 static BITMAP StickyOpt; /* set if option is stuck */ 616 extern char *WizWord; /* the stored wizard password */ 617 extern char *NetName; /* name of home (local) network */ 618 619 setoption(opt, val, safe, sticky) 620 char opt; 621 char *val; 622 bool safe; 623 bool sticky; 624 { 625 extern bool atobool(); 626 extern time_t convtime(); 627 extern int QueueLA; 628 extern int RefuseLA; 629 extern bool trusteduser(); 630 extern char *username(); 631 632 # ifdef DEBUG 633 if (tTd(37, 1)) 634 printf("setoption %c=%s", opt, val); 635 # endif DEBUG 636 637 /* 638 ** See if this option is preset for us. 639 */ 640 641 if (bitnset(opt, StickyOpt)) 642 { 643 # ifdef DEBUG 644 if (tTd(37, 1)) 645 printf(" (ignored)\n"); 646 # endif DEBUG 647 return; 648 } 649 650 /* 651 ** Check to see if this option can be specified by this user. 652 */ 653 654 if (!safe && getruid()) 655 safe = TRUE; 656 if (!safe && index("deiLmorsv", opt) == NULL) 657 { 658 # ifdef DEBUG 659 if (tTd(37, 1)) 660 printf(" (unsafe)"); 661 # endif DEBUG 662 if (getruid() != geteuid()) 663 { 664 printf("(Resetting uid)\n"); 665 setgid(getgid()); 666 setuid(getuid()); 667 } 668 } 669 #ifdef DEBUG 670 else if (tTd(37, 1)) 671 printf("\n"); 672 #endif DEBUG 673 674 switch (opt) 675 { 676 case 'A': /* set default alias file */ 677 if (val[0] == '\0') 678 AliasFile = "aliases"; 679 else 680 AliasFile = newstr(val); 681 break; 682 683 case 'a': /* look N minutes for "@:@" in alias file */ 684 if (val[0] == '\0') 685 SafeAlias = 5; 686 else 687 SafeAlias = atoi(val); 688 break; 689 690 case 'B': /* substitution for blank character */ 691 SpaceSub = val[0]; 692 if (SpaceSub == '\0') 693 SpaceSub = ' '; 694 break; 695 696 case 'c': /* don't connect to "expensive" mailers */ 697 NoConnect = atobool(val); 698 break; 699 700 case 'd': /* delivery mode */ 701 switch (*val) 702 { 703 case '\0': 704 SendMode = SM_DELIVER; 705 break; 706 707 case SM_QUEUE: /* queue only */ 708 #ifndef QUEUE 709 syserr("need QUEUE to set -odqueue"); 710 #endif QUEUE 711 /* fall through..... */ 712 713 case SM_DELIVER: /* do everything */ 714 case SM_FORK: /* fork after verification */ 715 SendMode = *val; 716 break; 717 718 default: 719 syserr("Unknown delivery mode %c", *val); 720 exit(EX_USAGE); 721 } 722 break; 723 724 case 'D': /* rebuild alias database as needed */ 725 AutoRebuild = atobool(val); 726 break; 727 728 case 'e': /* set error processing mode */ 729 switch (*val) 730 { 731 case EM_QUIET: /* be silent about it */ 732 case EM_MAIL: /* mail back */ 733 case EM_BERKNET: /* do berknet error processing */ 734 case EM_WRITE: /* write back (or mail) */ 735 HoldErrs = TRUE; 736 /* fall through... */ 737 738 case EM_PRINT: /* print errors normally (default) */ 739 ErrorMode = *val; 740 break; 741 } 742 break; 743 744 case 'F': /* file mode */ 745 FileMode = atooct(val) & 0777; 746 break; 747 748 case 'f': /* save Unix-style From lines on front */ 749 SaveFrom = atobool(val); 750 break; 751 752 case 'g': /* default gid */ 753 DefGid = atoi(val); 754 break; 755 756 case 'H': /* help file */ 757 if (val[0] == '\0') 758 HelpFile = "sendmail.hf"; 759 else 760 HelpFile = newstr(val); 761 break; 762 763 case 'i': /* ignore dot lines in message */ 764 IgnrDot = atobool(val); 765 break; 766 767 case 'L': /* log level */ 768 LogLevel = atoi(val); 769 break; 770 771 case 'M': /* define macro */ 772 define(val[0], newstr(&val[1]), CurEnv); 773 sticky = FALSE; 774 break; 775 776 case 'm': /* send to me too */ 777 MeToo = atobool(val); 778 break; 779 780 # ifdef DAEMON 781 case 'N': /* home (local?) network name */ 782 NetName = newstr(val); 783 break; 784 # endif DAEMON 785 786 case 'o': /* assume old style headers */ 787 if (atobool(val)) 788 CurEnv->e_flags |= EF_OLDSTYLE; 789 else 790 CurEnv->e_flags &= ~EF_OLDSTYLE; 791 break; 792 793 case 'Q': /* queue directory */ 794 if (val[0] == '\0') 795 QueueDir = "mqueue"; 796 else 797 QueueDir = newstr(val); 798 break; 799 800 case 'r': /* read timeout */ 801 ReadTimeout = convtime(val); 802 break; 803 804 case 'S': /* status file */ 805 if (val[0] == '\0') 806 StatFile = "sendmail.st"; 807 else 808 StatFile = newstr(val); 809 break; 810 811 case 's': /* be super safe, even if expensive */ 812 SuperSafe = atobool(val); 813 break; 814 815 case 'T': /* queue timeout */ 816 TimeOut = convtime(val); 817 break; 818 819 case 't': /* time zone name */ 820 # ifdef V6 821 StdTimezone = newstr(val); 822 DstTimezone = index(StdTimeZone, ','); 823 if (DstTimezone == NULL) 824 syserr("bad time zone spec"); 825 else 826 *DstTimezone++ = '\0'; 827 # endif V6 828 break; 829 830 case 'u': /* set default uid */ 831 DefUid = atoi(val); 832 break; 833 834 case 'v': /* run in verbose mode */ 835 Verbose = atobool(val); 836 break; 837 838 # ifdef DEBUG 839 case 'W': /* set the wizards password */ 840 WizWord = newstr(val); 841 break; 842 # endif DEBUG 843 844 case 'x': /* load avg at which to auto-queue msgs */ 845 QueueLA = atoi(val); 846 break; 847 848 case 'X': /* load avg at which to auto-reject connections */ 849 RefuseLA = atoi(val); 850 break; 851 852 default: 853 break; 854 } 855 if (sticky) 856 setbitn(opt, StickyOpt); 857 return; 858 } 859 /* 860 ** SETCLASS -- set a word into a class 861 ** 862 ** Parameters: 863 ** class -- the class to put the word in. 864 ** word -- the word to enter 865 ** 866 ** Returns: 867 ** none. 868 ** 869 ** Side Effects: 870 ** puts the word into the symbol table. 871 */ 872 873 setclass(class, word) 874 int class; 875 char *word; 876 { 877 register STAB *s; 878 879 s = stab(word, ST_CLASS, ST_ENTER); 880 setbitn(class, s->s_class); 881 } 882