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[] = "@(#)readcf.c 5.41 (Berkeley) 07/12/92"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include <sys/stat.h> 15 # include <unistd.h> 16 17 /* 18 ** READCF -- read control file. 19 ** 20 ** This routine reads the control file and builds the internal 21 ** form. 22 ** 23 ** The file is formatted as a sequence of lines, each taken 24 ** atomically. The first character of each line describes how 25 ** the line is to be interpreted. The lines are: 26 ** Dxval Define macro x to have value val. 27 ** Cxword Put word into class x. 28 ** Fxfile [fmt] Read file for lines to put into 29 ** class x. Use scanf string 'fmt' 30 ** or "%s" if not present. Fmt should 31 ** only produce one string-valued result. 32 ** Hname: value Define header with field-name 'name' 33 ** and value as specified; this will be 34 ** macro expanded immediately before 35 ** use. 36 ** Sn Use rewriting set n. 37 ** Rlhs rhs Rewrite addresses that match lhs to 38 ** be rhs. 39 ** Mn arg=val... Define mailer. n is the internal name. 40 ** Args specify mailer parameters. 41 ** Oxvalue Set option x to value. 42 ** Pname=value Set precedence name to value. 43 ** Vversioncode Version level of configuration syntax. 44 ** Kmapname mapclass arguments.... 45 ** Define keyed lookup of a given class. 46 ** Arguments are class dependent. 47 ** 48 ** Parameters: 49 ** cfname -- control file name. 50 ** safe -- TRUE if this is the system config file; 51 ** FALSE otherwise. 52 ** e -- the main envelope. 53 ** 54 ** Returns: 55 ** none. 56 ** 57 ** Side Effects: 58 ** Builds several internal tables. 59 */ 60 61 readcf(cfname, safe, e) 62 char *cfname; 63 bool safe; 64 register ENVELOPE *e; 65 { 66 FILE *cf; 67 int ruleset = 0; 68 char *q; 69 char **pv; 70 struct rewrite *rwp = NULL; 71 char buf[MAXLINE]; 72 register char *p; 73 extern char **prescan(); 74 extern char **copyplist(); 75 struct stat statb; 76 char exbuf[MAXLINE]; 77 char pvpbuf[PSBUFSIZE]; 78 extern char *fgetfolded(); 79 extern char *munchstring(); 80 extern void makemapentry(); 81 82 FileName = cfname; 83 LineNumber = 0; 84 85 cf = fopen(cfname, "r"); 86 if (cf == NULL) 87 { 88 syserr("cannot open"); 89 exit(EX_OSFILE); 90 } 91 92 if (fstat(fileno(cf), &statb) < 0) 93 { 94 syserr("cannot fstat"); 95 exit(EX_OSFILE); 96 } 97 98 if (!S_ISREG(statb.st_mode)) 99 { 100 syserr("not a plain file"); 101 exit(EX_OSFILE); 102 } 103 104 if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 105 { 106 if (OpMode == MD_DAEMON || OpMode == MD_FREEZE) 107 fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 108 FileName); 109 #ifdef LOG 110 if (LogLevel > 0) 111 syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 112 FileName); 113 #endif 114 } 115 116 while (fgetfolded(buf, sizeof buf, cf) != NULL) 117 { 118 if (buf[0] == '#') 119 continue; 120 121 /* map $ into \001 (ASCII SOH) for macro expansion */ 122 for (p = buf; *p != '\0'; p++) 123 { 124 if (*p == '#' && p > buf && ConfigLevel >= 3) 125 { 126 /* this is an on-line comment */ 127 register char *e; 128 129 switch (*--p) 130 { 131 case '\001': 132 /* it's from $# -- let it go through */ 133 p++; 134 break; 135 136 case '\\': 137 /* it's backslash escaped */ 138 (void) strcpy(p, p + 1); 139 break; 140 141 default: 142 /* delete preceeding white space */ 143 while (isspace(*p) && p > buf) 144 p--; 145 if ((e = index(++p, '\n')) != NULL) 146 (void) strcpy(p, e); 147 else 148 p[0] = p[1] = '\0'; 149 break; 150 } 151 continue; 152 } 153 154 if (*p != '$') 155 continue; 156 157 if (p[1] == '$') 158 { 159 /* actual dollar sign.... */ 160 (void) strcpy(p, p + 1); 161 continue; 162 } 163 164 /* convert to macro expansion character */ 165 *p = '\001'; 166 } 167 168 /* interpret this line */ 169 switch (buf[0]) 170 { 171 case '\0': 172 case '#': /* comment */ 173 break; 174 175 case 'R': /* rewriting rule */ 176 for (p = &buf[1]; *p != '\0' && *p != '\t'; p++) 177 continue; 178 179 if (*p == '\0') 180 { 181 syserr("invalid rewrite line \"%s\"", buf); 182 break; 183 } 184 185 /* allocate space for the rule header */ 186 if (rwp == NULL) 187 { 188 RewriteRules[ruleset] = rwp = 189 (struct rewrite *) xalloc(sizeof *rwp); 190 } 191 else 192 { 193 rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 194 rwp = rwp->r_next; 195 } 196 rwp->r_next = NULL; 197 198 /* expand and save the LHS */ 199 *p = '\0'; 200 expand(&buf[1], exbuf, &exbuf[sizeof exbuf], e); 201 rwp->r_lhs = prescan(exbuf, '\t', pvpbuf); 202 if (rwp->r_lhs != NULL) 203 rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 204 205 /* expand and save the RHS */ 206 while (*++p == '\t') 207 continue; 208 q = p; 209 while (*p != '\0' && *p != '\t') 210 p++; 211 *p = '\0'; 212 expand(q, exbuf, &exbuf[sizeof exbuf], e); 213 rwp->r_rhs = prescan(exbuf, '\t', pvpbuf); 214 if (rwp->r_rhs != NULL) 215 rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 216 break; 217 218 case 'S': /* select rewriting set */ 219 ruleset = atoi(&buf[1]); 220 if (ruleset >= MAXRWSETS || ruleset < 0) 221 { 222 syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS); 223 ruleset = 0; 224 } 225 rwp = NULL; 226 break; 227 228 case 'D': /* macro definition */ 229 define(buf[1], newstr(munchstring(&buf[2])), e); 230 break; 231 232 case 'H': /* required header line */ 233 (void) chompheader(&buf[1], TRUE, e); 234 break; 235 236 case 'C': /* word class */ 237 case 'F': /* word class from file */ 238 /* read list of words from argument or file */ 239 if (buf[0] == 'F') 240 { 241 /* read from file */ 242 for (p = &buf[2]; *p != '\0' && !isspace(*p); p++) 243 continue; 244 if (*p == '\0') 245 p = "%s"; 246 else 247 { 248 *p = '\0'; 249 while (isspace(*++p)) 250 continue; 251 } 252 fileclass(buf[1], &buf[2], p, safe); 253 break; 254 } 255 256 /* scan the list of words and set class for all */ 257 for (p = &buf[2]; *p != '\0'; ) 258 { 259 register char *wd; 260 char delim; 261 262 while (*p != '\0' && isspace(*p)) 263 p++; 264 wd = p; 265 while (*p != '\0' && !isspace(*p)) 266 p++; 267 delim = *p; 268 *p = '\0'; 269 if (wd[0] != '\0') 270 setclass(buf[1], wd); 271 *p = delim; 272 } 273 break; 274 275 case 'M': /* define mailer */ 276 makemailer(&buf[1]); 277 break; 278 279 case 'O': /* set option */ 280 setoption(buf[1], &buf[2], safe, FALSE); 281 break; 282 283 case 'P': /* set precedence */ 284 if (NumPriorities >= MAXPRIORITIES) 285 { 286 toomany('P', MAXPRIORITIES); 287 break; 288 } 289 for (p = &buf[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 290 continue; 291 if (*p == '\0') 292 goto badline; 293 *p = '\0'; 294 Priorities[NumPriorities].pri_name = newstr(&buf[1]); 295 Priorities[NumPriorities].pri_val = atoi(++p); 296 NumPriorities++; 297 break; 298 299 case 'T': /* trusted user(s) */ 300 p = &buf[1]; 301 while (*p != '\0') 302 { 303 while (isspace(*p)) 304 p++; 305 q = p; 306 while (*p != '\0' && !isspace(*p)) 307 p++; 308 if (*p != '\0') 309 *p++ = '\0'; 310 if (*q == '\0') 311 continue; 312 for (pv = TrustedUsers; *pv != NULL; pv++) 313 continue; 314 if (pv >= &TrustedUsers[MAXTRUST]) 315 { 316 toomany('T', MAXTRUST); 317 break; 318 } 319 *pv = newstr(q); 320 } 321 break; 322 323 case 'V': /* configuration syntax version */ 324 ConfigLevel = atoi(&buf[1]); 325 break; 326 327 case 'K': 328 makemapentry(&buf[1]); 329 break; 330 331 default: 332 badline: 333 syserr("unknown control line \"%s\"", buf); 334 } 335 } 336 if (ferror(cf)) 337 { 338 syserr("I/O read error", cfname); 339 exit(EX_OSFILE); 340 } 341 fclose(cf); 342 FileName = NULL; 343 } 344 /* 345 ** TOOMANY -- signal too many of some option 346 ** 347 ** Parameters: 348 ** id -- the id of the error line 349 ** maxcnt -- the maximum possible values 350 ** 351 ** Returns: 352 ** none. 353 ** 354 ** Side Effects: 355 ** gives a syserr. 356 */ 357 358 toomany(id, maxcnt) 359 char id; 360 int maxcnt; 361 { 362 syserr("too many %c lines, %d max", id, maxcnt); 363 } 364 /* 365 ** FILECLASS -- read members of a class from a file 366 ** 367 ** Parameters: 368 ** class -- class to define. 369 ** filename -- name of file to read. 370 ** fmt -- scanf string to use for match. 371 ** 372 ** Returns: 373 ** none 374 ** 375 ** Side Effects: 376 ** 377 ** puts all lines in filename that match a scanf into 378 ** the named class. 379 */ 380 381 fileclass(class, filename, fmt, safe) 382 int class; 383 char *filename; 384 char *fmt; 385 bool safe; 386 { 387 FILE *f; 388 struct stat stbuf; 389 char buf[MAXLINE]; 390 391 if (stat(filename, &stbuf) < 0) 392 { 393 syserr("fileclass: cannot stat %s", filename); 394 return; 395 } 396 if (!S_ISREG(stbuf.st_mode)) 397 { 398 syserr("fileclass: %s not a regular file", filename); 399 return; 400 } 401 if (!safe && access(filename, R_OK) < 0) 402 { 403 syserr("fileclass: access denied on %s", filename); 404 return; 405 } 406 f = fopen(filename, "r"); 407 if (f == NULL) 408 { 409 syserr("fileclass: cannot open %s", filename); 410 return; 411 } 412 413 while (fgets(buf, sizeof buf, f) != NULL) 414 { 415 register STAB *s; 416 register char *p; 417 # ifdef SCANF 418 char wordbuf[MAXNAME+1]; 419 420 if (sscanf(buf, fmt, wordbuf) != 1) 421 continue; 422 p = wordbuf; 423 # else SCANF 424 p = buf; 425 # endif SCANF 426 427 /* 428 ** Break up the match into words. 429 */ 430 431 while (*p != '\0') 432 { 433 register char *q; 434 435 /* strip leading spaces */ 436 while (isspace(*p)) 437 p++; 438 if (*p == '\0') 439 break; 440 441 /* find the end of the word */ 442 q = p; 443 while (*p != '\0' && !isspace(*p)) 444 p++; 445 if (*p != '\0') 446 *p++ = '\0'; 447 448 /* enter the word in the symbol table */ 449 s = stab(q, ST_CLASS, ST_ENTER); 450 setbitn(class, s->s_class); 451 } 452 } 453 454 (void) fclose(f); 455 } 456 /* 457 ** MAKEMAILER -- define a new mailer. 458 ** 459 ** Parameters: 460 ** line -- description of mailer. This is in labeled 461 ** fields. The fields are: 462 ** P -- the path to the mailer 463 ** F -- the flags associated with the mailer 464 ** A -- the argv for this mailer 465 ** S -- the sender rewriting set 466 ** R -- the recipient rewriting set 467 ** E -- the eol string 468 ** The first word is the canonical name of the mailer. 469 ** 470 ** Returns: 471 ** none. 472 ** 473 ** Side Effects: 474 ** enters the mailer into the mailer table. 475 */ 476 477 makemailer(line) 478 char *line; 479 { 480 register char *p; 481 register struct mailer *m; 482 register STAB *s; 483 int i; 484 char fcode; 485 extern int NextMailer; 486 extern char **makeargv(); 487 extern char *munchstring(); 488 extern char *DelimChar; 489 extern long atol(); 490 491 /* allocate a mailer and set up defaults */ 492 m = (struct mailer *) xalloc(sizeof *m); 493 bzero((char *) m, sizeof *m); 494 m->m_mno = NextMailer; 495 m->m_eol = "\n"; 496 497 /* collect the mailer name */ 498 for (p = line; *p != '\0' && *p != ',' && !isspace(*p); p++) 499 continue; 500 if (*p != '\0') 501 *p++ = '\0'; 502 m->m_name = newstr(line); 503 504 /* now scan through and assign info from the fields */ 505 while (*p != '\0') 506 { 507 while (*p != '\0' && (*p == ',' || isspace(*p))) 508 p++; 509 510 /* p now points to field code */ 511 fcode = *p; 512 while (*p != '\0' && *p != '=' && *p != ',') 513 p++; 514 if (*p++ != '=') 515 { 516 syserr("mailer %s: `=' expected", m->m_name); 517 return; 518 } 519 while (isspace(*p)) 520 p++; 521 522 /* p now points to the field body */ 523 p = munchstring(p); 524 525 /* install the field into the mailer struct */ 526 switch (fcode) 527 { 528 case 'P': /* pathname */ 529 m->m_mailer = newstr(p); 530 break; 531 532 case 'F': /* flags */ 533 for (; *p != '\0'; p++) 534 if (!isspace(*p)) 535 setbitn(*p, m->m_flags); 536 break; 537 538 case 'S': /* sender rewriting ruleset */ 539 case 'R': /* recipient rewriting ruleset */ 540 i = atoi(p); 541 if (i < 0 || i >= MAXRWSETS) 542 { 543 syserr("invalid rewrite set, %d max", MAXRWSETS); 544 return; 545 } 546 if (fcode == 'S') 547 m->m_s_rwset = i; 548 else 549 m->m_r_rwset = i; 550 break; 551 552 case 'E': /* end of line string */ 553 m->m_eol = newstr(p); 554 break; 555 556 case 'A': /* argument vector */ 557 m->m_argv = makeargv(p); 558 break; 559 560 case 'M': /* maximum message size */ 561 m->m_maxsize = atol(p); 562 break; 563 564 case 'L': /* maximum line length */ 565 m->m_linelimit = atoi(p); 566 break; 567 } 568 569 p = DelimChar; 570 } 571 572 /* do some heuristic cleanup for back compatibility */ 573 if (bitnset(M_LIMITS, m->m_flags)) 574 { 575 if (m->m_linelimit == 0) 576 m->m_linelimit = SMTPLINELIM; 577 if (!bitnset(M_8BITS, m->m_flags)) 578 setbitn(M_7BITS, m->m_flags); 579 } 580 581 /* now store the mailer away */ 582 if (NextMailer >= MAXMAILERS) 583 { 584 syserr("too many mailers defined (%d max)", MAXMAILERS); 585 return; 586 } 587 Mailer[NextMailer++] = m; 588 s = stab(m->m_name, ST_MAILER, ST_ENTER); 589 s->s_mailer = m; 590 } 591 /* 592 ** MUNCHSTRING -- translate a string into internal form. 593 ** 594 ** Parameters: 595 ** p -- the string to munch. 596 ** 597 ** Returns: 598 ** the munched string. 599 ** 600 ** Side Effects: 601 ** Sets "DelimChar" to point to the string that caused us 602 ** to stop. 603 */ 604 605 char * 606 munchstring(p) 607 register char *p; 608 { 609 register char *q; 610 bool backslash = FALSE; 611 bool quotemode = FALSE; 612 static char buf[MAXLINE]; 613 extern char *DelimChar; 614 615 for (q = buf; *p != '\0'; p++) 616 { 617 if (backslash) 618 { 619 /* everything is roughly literal */ 620 backslash = FALSE; 621 switch (*p) 622 { 623 case 'r': /* carriage return */ 624 *q++ = '\r'; 625 continue; 626 627 case 'n': /* newline */ 628 *q++ = '\n'; 629 continue; 630 631 case 'f': /* form feed */ 632 *q++ = '\f'; 633 continue; 634 635 case 'b': /* backspace */ 636 *q++ = '\b'; 637 continue; 638 } 639 *q++ = *p; 640 } 641 else 642 { 643 if (*p == '\\') 644 backslash = TRUE; 645 else if (*p == '"') 646 quotemode = !quotemode; 647 else if (quotemode || *p != ',') 648 *q++ = *p; 649 else 650 break; 651 } 652 } 653 654 DelimChar = p; 655 *q++ = '\0'; 656 return (buf); 657 } 658 /* 659 ** MAKEARGV -- break up a string into words 660 ** 661 ** Parameters: 662 ** p -- the string to break up. 663 ** 664 ** Returns: 665 ** a char **argv (dynamically allocated) 666 ** 667 ** Side Effects: 668 ** munges p. 669 */ 670 671 char ** 672 makeargv(p) 673 register char *p; 674 { 675 char *q; 676 int i; 677 char **avp; 678 char *argv[MAXPV + 1]; 679 680 /* take apart the words */ 681 i = 0; 682 while (*p != '\0' && i < MAXPV) 683 { 684 q = p; 685 while (*p != '\0' && !isspace(*p)) 686 p++; 687 while (isspace(*p)) 688 *p++ = '\0'; 689 argv[i++] = newstr(q); 690 } 691 argv[i++] = NULL; 692 693 /* now make a copy of the argv */ 694 avp = (char **) xalloc(sizeof *avp * i); 695 bcopy((char *) argv, (char *) avp, sizeof *avp * i); 696 697 return (avp); 698 } 699 /* 700 ** PRINTRULES -- print rewrite rules (for debugging) 701 ** 702 ** Parameters: 703 ** none. 704 ** 705 ** Returns: 706 ** none. 707 ** 708 ** Side Effects: 709 ** prints rewrite rules. 710 */ 711 712 printrules() 713 { 714 register struct rewrite *rwp; 715 register int ruleset; 716 717 for (ruleset = 0; ruleset < 10; ruleset++) 718 { 719 if (RewriteRules[ruleset] == NULL) 720 continue; 721 printf("\n----Rule Set %d:", ruleset); 722 723 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 724 { 725 printf("\nLHS:"); 726 printav(rwp->r_lhs); 727 printf("RHS:"); 728 printav(rwp->r_rhs); 729 } 730 } 731 } 732 733 /* 734 ** SETOPTION -- set global processing option 735 ** 736 ** Parameters: 737 ** opt -- option name. 738 ** val -- option value (as a text string). 739 ** safe -- set if this came from a configuration file. 740 ** Some options (if set from the command line) will 741 ** reset the user id to avoid security problems. 742 ** sticky -- if set, don't let other setoptions override 743 ** this value. 744 ** 745 ** Returns: 746 ** none. 747 ** 748 ** Side Effects: 749 ** Sets options as implied by the arguments. 750 */ 751 752 static BITMAP StickyOpt; /* set if option is stuck */ 753 754 setoption(opt, val, safe, sticky) 755 char opt; 756 char *val; 757 bool safe; 758 bool sticky; 759 { 760 extern bool atobool(); 761 extern time_t convtime(); 762 extern int QueueLA; 763 extern int RefuseLA; 764 extern bool trusteduser(); 765 extern char *username(); 766 767 if (tTd(37, 1)) 768 printf("setoption %c=%s", opt, val); 769 770 /* 771 ** See if this option is preset for us. 772 */ 773 774 if (bitnset(opt, StickyOpt)) 775 { 776 if (tTd(37, 1)) 777 printf(" (ignored)\n"); 778 return; 779 } 780 781 /* 782 ** Check to see if this option can be specified by this user. 783 */ 784 785 if (!safe && getuid() == 0) 786 safe = TRUE; 787 if (!safe && index("deiLmorsvC", opt) == NULL) 788 { 789 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 790 { 791 if (tTd(37, 1)) 792 printf(" (unsafe)"); 793 if (getuid() != geteuid()) 794 { 795 if (tTd(37, 1)) 796 printf("(Resetting uid)"); 797 (void) setgid(getgid()); 798 (void) setuid(getuid()); 799 } 800 } 801 } 802 if (tTd(37, 1)) 803 printf("\n"); 804 805 switch (opt) 806 { 807 case '=': /* config file generation level */ 808 ConfigLevel = atoi(val); 809 break; 810 811 case '8': /* allow eight-bit input */ 812 EightBit = atobool(val); 813 break; 814 815 case 'A': /* set default alias file */ 816 if (val[0] == '\0') 817 AliasFile = "aliases"; 818 else 819 AliasFile = newstr(val); 820 break; 821 822 case 'a': /* look N minutes for "@:@" in alias file */ 823 if (val[0] == '\0') 824 SafeAlias = 5; 825 else 826 SafeAlias = atoi(val); 827 break; 828 829 case 'B': /* substitution for blank character */ 830 SpaceSub = val[0]; 831 if (SpaceSub == '\0') 832 SpaceSub = ' '; 833 break; 834 835 case 'c': /* don't connect to "expensive" mailers */ 836 NoConnect = atobool(val); 837 break; 838 839 case 'C': /* checkpoint every N addresses */ 840 CheckpointInterval = atoi(val); 841 break; 842 843 case 'd': /* delivery mode */ 844 switch (*val) 845 { 846 case '\0': 847 SendMode = SM_DELIVER; 848 break; 849 850 case SM_QUEUE: /* queue only */ 851 #ifndef QUEUE 852 syserr("need QUEUE to set -odqueue"); 853 #endif QUEUE 854 /* fall through..... */ 855 856 case SM_DELIVER: /* do everything */ 857 case SM_FORK: /* fork after verification */ 858 SendMode = *val; 859 break; 860 861 default: 862 syserr("Unknown delivery mode %c", *val); 863 exit(EX_USAGE); 864 } 865 break; 866 867 case 'D': /* rebuild alias database as needed */ 868 AutoRebuild = atobool(val); 869 break; 870 871 case 'e': /* set error processing mode */ 872 switch (*val) 873 { 874 case EM_QUIET: /* be silent about it */ 875 case EM_MAIL: /* mail back */ 876 case EM_BERKNET: /* do berknet error processing */ 877 case EM_WRITE: /* write back (or mail) */ 878 HoldErrs = TRUE; 879 /* fall through... */ 880 881 case EM_PRINT: /* print errors normally (default) */ 882 ErrorMode = *val; 883 break; 884 } 885 break; 886 887 case 'F': /* file mode */ 888 FileMode = atooct(val) & 0777; 889 break; 890 891 case 'f': /* save Unix-style From lines on front */ 892 SaveFrom = atobool(val); 893 break; 894 895 case 'G': /* match recipients against GECOS field */ 896 MatchGecos = atobool(val); 897 break; 898 899 case 'g': /* default gid */ 900 DefGid = atoi(val); 901 break; 902 903 case 'H': /* help file */ 904 if (val[0] == '\0') 905 HelpFile = "sendmail.hf"; 906 else 907 HelpFile = newstr(val); 908 break; 909 910 case 'h': /* maximum hop count */ 911 MaxHopCount = atoi(val); 912 break; 913 914 case 'I': /* use internet domain name server */ 915 UseNameServer = atobool(val); 916 break; 917 918 case 'i': /* ignore dot lines in message */ 919 IgnrDot = atobool(val); 920 break; 921 922 case 'k': /* connection cache size */ 923 MaxMciCache = atoi(val); 924 if (MaxMciCache <= 0) 925 MaxMciCache = 1; 926 break; 927 928 case 'K': /* connection cache timeout */ 929 MciCacheTimeout = convtime(val); 930 break; 931 932 case 'L': /* log level */ 933 LogLevel = atoi(val); 934 break; 935 936 case 'M': /* define macro */ 937 define(val[0], newstr(&val[1]), CurEnv); 938 sticky = FALSE; 939 break; 940 941 case 'm': /* send to me too */ 942 MeToo = atobool(val); 943 break; 944 945 case 'n': /* validate RHS in newaliases */ 946 CheckAliases = atobool(val); 947 break; 948 949 case 'o': /* assume old style headers */ 950 if (atobool(val)) 951 CurEnv->e_flags |= EF_OLDSTYLE; 952 else 953 CurEnv->e_flags &= ~EF_OLDSTYLE; 954 break; 955 956 case 'P': /* postmaster copy address for returned mail */ 957 PostMasterCopy = newstr(val); 958 break; 959 960 case 'q': /* slope of queue only function */ 961 QueueFactor = atoi(val); 962 break; 963 964 case 'Q': /* queue directory */ 965 if (val[0] == '\0') 966 QueueDir = "mqueue"; 967 else 968 QueueDir = newstr(val); 969 break; 970 971 case 'r': /* read timeout */ 972 ReadTimeout = convtime(val); 973 break; 974 975 case 'S': /* status file */ 976 if (val[0] == '\0') 977 StatFile = "sendmail.st"; 978 else 979 StatFile = newstr(val); 980 break; 981 982 case 's': /* be super safe, even if expensive */ 983 SuperSafe = atobool(val); 984 break; 985 986 case 'T': /* queue timeout */ 987 TimeOut = convtime(val); 988 break; 989 990 case 't': /* time zone name */ 991 TimeZoneSpec = newstr(val); 992 break; 993 994 case 'U': /* location of user database */ 995 UdbSpec = newstr(val); 996 break; 997 998 case 'u': /* set default uid */ 999 DefUid = atoi(val); 1000 setdefuser(); 1001 break; 1002 1003 case 'v': /* run in verbose mode */ 1004 Verbose = atobool(val); 1005 break; 1006 1007 case 'w': /* we don't have wildcard MX records */ 1008 NoWildcardMX = atobool(val); 1009 break; 1010 1011 case 'x': /* load avg at which to auto-queue msgs */ 1012 QueueLA = atoi(val); 1013 break; 1014 1015 case 'X': /* load avg at which to auto-reject connections */ 1016 RefuseLA = atoi(val); 1017 break; 1018 1019 case 'y': /* work recipient factor */ 1020 WkRecipFact = atoi(val); 1021 break; 1022 1023 case 'Y': /* fork jobs during queue runs */ 1024 ForkQueueRuns = atobool(val); 1025 break; 1026 1027 case 'z': /* work message class factor */ 1028 WkClassFact = atoi(val); 1029 break; 1030 1031 case 'Z': /* work time factor */ 1032 WkTimeFact = atoi(val); 1033 break; 1034 1035 default: 1036 break; 1037 } 1038 if (sticky) 1039 setbitn(opt, StickyOpt); 1040 return; 1041 } 1042 /* 1043 ** SETCLASS -- set a word into a class 1044 ** 1045 ** Parameters: 1046 ** class -- the class to put the word in. 1047 ** word -- the word to enter 1048 ** 1049 ** Returns: 1050 ** none. 1051 ** 1052 ** Side Effects: 1053 ** puts the word into the symbol table. 1054 */ 1055 1056 setclass(class, word) 1057 int class; 1058 char *word; 1059 { 1060 register STAB *s; 1061 1062 s = stab(word, ST_CLASS, ST_ENTER); 1063 setbitn(class, s->s_class); 1064 } 1065 /* 1066 ** MAKEMAPENTRY -- create a map entry 1067 ** 1068 ** Parameters: 1069 ** line -- the config file line 1070 ** 1071 ** Returns: 1072 ** TRUE if it successfully entered the map entry. 1073 ** FALSE otherwise (usually syntax error). 1074 ** 1075 ** Side Effects: 1076 ** Enters the map into the dictionary. 1077 */ 1078 1079 void 1080 makemapentry(line) 1081 char *line; 1082 { 1083 register char *p; 1084 char *mapname; 1085 char *classname; 1086 register STAB *map; 1087 STAB *class; 1088 1089 for (p = line; isspace(*p); p++) 1090 continue; 1091 if (!isalnum(*p)) 1092 { 1093 syserr("readcf: config K line: no map name"); 1094 return; 1095 } 1096 1097 mapname = p; 1098 while (isalnum(*++p)) 1099 continue; 1100 if (*p != '\0') 1101 *p++ = '\0'; 1102 while (isspace(*p)) 1103 p++; 1104 if (!isalnum(*p)) 1105 { 1106 syserr("readcf: config K line, map %s: no map class", mapname); 1107 return; 1108 } 1109 classname = p; 1110 while (isalnum(*++p)) 1111 continue; 1112 if (*p != '\0') 1113 *p++ = '\0'; 1114 while (isspace(*p)) 1115 p++; 1116 1117 /* look up the class */ 1118 class = stab(classname, ST_MAPCLASS, ST_FIND); 1119 if (class == NULL) 1120 { 1121 syserr("readcf: map %s: class %s not available", mapname, classname); 1122 return; 1123 } 1124 1125 /* enter the map */ 1126 map = stab(mapname, ST_MAP, ST_ENTER); 1127 map->s_map.map_class = &class->s_mapclass; 1128 1129 if ((*class->s_mapclass.map_init)(&map->s_map, p)) 1130 map->s_map.map_flags |= MF_VALID; 1131 } 1132