1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)readcf.c 8.68 (Berkeley) 02/20/95"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include <pwd.h> 15 # include <grp.h> 16 #if NAMED_BIND 17 # include <resolv.h> 18 #endif 19 20 /* 21 ** READCF -- read control file. 22 ** 23 ** This routine reads the control file and builds the internal 24 ** form. 25 ** 26 ** The file is formatted as a sequence of lines, each taken 27 ** atomically. The first character of each line describes how 28 ** the line is to be interpreted. The lines are: 29 ** Dxval Define macro x to have value val. 30 ** Cxword Put word into class x. 31 ** Fxfile [fmt] Read file for lines to put into 32 ** class x. Use scanf string 'fmt' 33 ** or "%s" if not present. Fmt should 34 ** only produce one string-valued result. 35 ** Hname: value Define header with field-name 'name' 36 ** and value as specified; this will be 37 ** macro expanded immediately before 38 ** use. 39 ** Sn Use rewriting set n. 40 ** Rlhs rhs Rewrite addresses that match lhs to 41 ** be rhs. 42 ** Mn arg=val... Define mailer. n is the internal name. 43 ** Args specify mailer parameters. 44 ** Oxvalue Set option x to value. 45 ** Pname=value Set precedence name to value. 46 ** Vversioncode[/vendorcode] 47 ** Version level/vendor name of 48 ** configuration syntax. 49 ** Kmapname mapclass arguments.... 50 ** Define keyed lookup of a given class. 51 ** Arguments are class dependent. 52 ** 53 ** Parameters: 54 ** cfname -- control file name. 55 ** safe -- TRUE if this is the system config file; 56 ** FALSE otherwise. 57 ** e -- the main envelope. 58 ** 59 ** Returns: 60 ** none. 61 ** 62 ** Side Effects: 63 ** Builds several internal tables. 64 */ 65 66 readcf(cfname, safe, e) 67 char *cfname; 68 bool safe; 69 register ENVELOPE *e; 70 { 71 FILE *cf; 72 int ruleset = 0; 73 int nextruleset = MAXRWSETS; 74 char *q; 75 struct rewrite *rwp = NULL; 76 char *bp; 77 auto char *ep; 78 int nfuzzy; 79 char *file; 80 bool optional; 81 int mid; 82 char buf[MAXLINE]; 83 register char *p; 84 extern char **copyplist(); 85 struct stat statb; 86 char exbuf[MAXLINE]; 87 char pvpbuf[MAXLINE + MAXATOM]; 88 static char *null_list[1] = { NULL }; 89 extern char *munchstring(); 90 extern void makemapentry(); 91 92 FileName = cfname; 93 LineNumber = 0; 94 95 cf = fopen(cfname, "r"); 96 if (cf == NULL) 97 { 98 syserr("cannot open"); 99 exit(EX_OSFILE); 100 } 101 102 if (fstat(fileno(cf), &statb) < 0) 103 { 104 syserr("cannot fstat"); 105 exit(EX_OSFILE); 106 } 107 108 if (!S_ISREG(statb.st_mode)) 109 { 110 syserr("not a plain file"); 111 exit(EX_OSFILE); 112 } 113 114 if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 115 { 116 if (OpMode == MD_DAEMON || OpMode == MD_FREEZE) 117 fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 118 FileName); 119 #ifdef LOG 120 if (LogLevel > 0) 121 syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 122 FileName); 123 #endif 124 } 125 126 #ifdef XLA 127 xla_zero(); 128 #endif 129 130 while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 131 { 132 if (bp[0] == '#') 133 { 134 if (bp != buf) 135 free(bp); 136 continue; 137 } 138 139 /* do macro expansion mappings */ 140 for (p = bp; *p != '\0'; p++) 141 { 142 if (*p == '#' && p > bp && ConfigLevel >= 3) 143 { 144 /* this is an on-line comment */ 145 register char *e; 146 147 switch (*--p & 0377) 148 { 149 case MACROEXPAND: 150 /* it's from $# -- let it go through */ 151 p++; 152 break; 153 154 case '\\': 155 /* it's backslash escaped */ 156 (void) strcpy(p, p + 1); 157 break; 158 159 default: 160 /* delete preceeding white space */ 161 while (isascii(*p) && isspace(*p) && p > bp) 162 p--; 163 if ((e = strchr(++p, '\n')) != NULL) 164 (void) strcpy(p, e); 165 else 166 p[0] = p[1] = '\0'; 167 break; 168 } 169 continue; 170 } 171 172 if (*p != '$' || p[1] == '\0') 173 continue; 174 175 if (p[1] == '$') 176 { 177 /* actual dollar sign.... */ 178 (void) strcpy(p, p + 1); 179 continue; 180 } 181 182 /* convert to macro expansion character */ 183 *p++ = MACROEXPAND; 184 185 /* convert macro name to code */ 186 *p = macid(p, &ep); 187 if (ep != p) 188 strcpy(p + 1, ep); 189 } 190 191 /* interpret this line */ 192 errno = 0; 193 switch (bp[0]) 194 { 195 case '\0': 196 case '#': /* comment */ 197 break; 198 199 case 'R': /* rewriting rule */ 200 for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 201 continue; 202 203 if (*p == '\0') 204 { 205 syserr("invalid rewrite line \"%s\" (tab expected)", bp); 206 break; 207 } 208 209 /* allocate space for the rule header */ 210 if (rwp == NULL) 211 { 212 RewriteRules[ruleset] = rwp = 213 (struct rewrite *) xalloc(sizeof *rwp); 214 } 215 else 216 { 217 rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 218 rwp = rwp->r_next; 219 } 220 rwp->r_next = NULL; 221 222 /* expand and save the LHS */ 223 *p = '\0'; 224 expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e); 225 rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 226 sizeof pvpbuf, NULL); 227 nfuzzy = 0; 228 if (rwp->r_lhs != NULL) 229 { 230 register char **ap; 231 232 rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 233 234 /* count the number of fuzzy matches in LHS */ 235 for (ap = rwp->r_lhs; *ap != NULL; ap++) 236 { 237 char *botch; 238 239 botch = NULL; 240 switch (**ap & 0377) 241 { 242 case MATCHZANY: 243 case MATCHANY: 244 case MATCHONE: 245 case MATCHCLASS: 246 case MATCHNCLASS: 247 nfuzzy++; 248 break; 249 250 case MATCHREPL: 251 botch = "$0-$9"; 252 break; 253 254 case CANONNET: 255 botch = "$#"; 256 break; 257 258 case CANONUSER: 259 botch = "$:"; 260 break; 261 262 case CALLSUBR: 263 botch = "$>"; 264 break; 265 266 case CONDIF: 267 botch = "$?"; 268 break; 269 270 case CONDELSE: 271 botch = "$|"; 272 break; 273 274 case CONDFI: 275 botch = "$."; 276 break; 277 278 case HOSTBEGIN: 279 botch = "$["; 280 break; 281 282 case HOSTEND: 283 botch = "$]"; 284 break; 285 286 case LOOKUPBEGIN: 287 botch = "$("; 288 break; 289 290 case LOOKUPEND: 291 botch = "$)"; 292 break; 293 } 294 if (botch != NULL) 295 syserr("Inappropriate use of %s on LHS", 296 botch); 297 } 298 } 299 else 300 { 301 syserr("R line: null LHS"); 302 rwp->r_lhs = null_list; 303 } 304 305 /* expand and save the RHS */ 306 while (*++p == '\t') 307 continue; 308 q = p; 309 while (*p != '\0' && *p != '\t') 310 p++; 311 *p = '\0'; 312 expand(q, exbuf, &exbuf[sizeof exbuf], e); 313 rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 314 sizeof pvpbuf, NULL); 315 if (rwp->r_rhs != NULL) 316 { 317 register char **ap; 318 319 rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 320 321 /* check no out-of-bounds replacements */ 322 nfuzzy += '0'; 323 for (ap = rwp->r_rhs; *ap != NULL; ap++) 324 { 325 char *botch; 326 327 botch = NULL; 328 switch (**ap & 0377) 329 { 330 case MATCHREPL: 331 if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 332 { 333 syserr("replacement $%c out of bounds", 334 (*ap)[1]); 335 } 336 break; 337 338 case MATCHZANY: 339 botch = "$*"; 340 break; 341 342 case MATCHANY: 343 botch = "$+"; 344 break; 345 346 case MATCHONE: 347 botch = "$-"; 348 break; 349 350 case MATCHCLASS: 351 botch = "$="; 352 break; 353 354 case MATCHNCLASS: 355 botch = "$~"; 356 break; 357 } 358 if (botch != NULL) 359 syserr("Inappropriate use of %s on RHS", 360 botch); 361 } 362 } 363 else 364 { 365 syserr("R line: null RHS"); 366 rwp->r_rhs = null_list; 367 } 368 break; 369 370 case 'S': /* select rewriting set */ 371 for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 372 continue; 373 if (!isascii(*p)) 374 { 375 syserr("invalid argument to S line: \"%.20s\"", 376 &bp[1]); 377 break; 378 } 379 if (isdigit(*p)) 380 { 381 ruleset = atoi(p); 382 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 383 { 384 syserr("bad ruleset %d (%d max)", 385 ruleset, MAXRWSETS / 2); 386 ruleset = 0; 387 } 388 } 389 else 390 { 391 STAB *s; 392 char delim; 393 394 q = p; 395 while (*p != '\0' && isascii(*p) && 396 (isalnum(*p) || strchr("-_$", *p) != NULL)) 397 p++; 398 while (isascii(*p) && isspace(*p)) 399 *p++ = '\0'; 400 delim = *p; 401 if (delim != '\0') 402 *p++ = '\0'; 403 s = stab(q, ST_RULESET, ST_ENTER); 404 if (s->s_ruleset != 0) 405 ruleset = s->s_ruleset; 406 else if (delim == '=') 407 { 408 ruleset = atoi(p); 409 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 410 { 411 syserr("bad ruleset %s = %d (%d max)", 412 q, ruleset, MAXRWSETS / 2); 413 ruleset = 0; 414 } 415 } 416 else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 417 { 418 syserr("%s: too many named rulesets (%d max)", 419 q, MAXRWSETS / 2); 420 ruleset = 0; 421 } 422 s->s_ruleset = ruleset; 423 } 424 rwp = NULL; 425 break; 426 427 case 'D': /* macro definition */ 428 mid = macid(&bp[1], &ep); 429 p = munchstring(ep, NULL); 430 define(mid, newstr(p), e); 431 break; 432 433 case 'H': /* required header line */ 434 (void) chompheader(&bp[1], TRUE, e); 435 break; 436 437 case 'C': /* word class */ 438 case 'T': /* trusted user (set class `t') */ 439 if (bp[0] == 'C') 440 { 441 mid = macid(&bp[1], &ep); 442 expand(ep, exbuf, &exbuf[sizeof exbuf], e); 443 p = exbuf; 444 } 445 else 446 { 447 mid = 't'; 448 p = &bp[1]; 449 } 450 while (*p != '\0') 451 { 452 register char *wd; 453 char delim; 454 455 while (*p != '\0' && isascii(*p) && isspace(*p)) 456 p++; 457 wd = p; 458 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 459 p++; 460 delim = *p; 461 *p = '\0'; 462 if (wd[0] != '\0') 463 setclass(mid, wd); 464 *p = delim; 465 } 466 break; 467 468 case 'F': /* word class from file */ 469 mid = macid(&bp[1], &ep); 470 for (p = ep; isascii(*p) && isspace(*p); ) 471 p++; 472 if (p[0] == '-' && p[1] == 'o') 473 { 474 optional = TRUE; 475 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 476 p++; 477 while (isascii(*p) && isspace(*p)) 478 p++; 479 } 480 else 481 optional = FALSE; 482 file = p; 483 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 484 p++; 485 if (*p == '\0') 486 p = "%s"; 487 else 488 { 489 *p = '\0'; 490 while (isascii(*++p) && isspace(*p)) 491 continue; 492 } 493 fileclass(bp[1], file, p, safe, optional); 494 break; 495 496 #ifdef XLA 497 case 'L': /* extended load average description */ 498 xla_init(&bp[1]); 499 break; 500 #endif 501 502 case 'M': /* define mailer */ 503 makemailer(&bp[1]); 504 break; 505 506 case 'O': /* set option */ 507 setoption(bp[1], &bp[2], safe, FALSE, e); 508 break; 509 510 case 'P': /* set precedence */ 511 if (NumPriorities >= MAXPRIORITIES) 512 { 513 toomany('P', MAXPRIORITIES); 514 break; 515 } 516 for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 517 continue; 518 if (*p == '\0') 519 goto badline; 520 *p = '\0'; 521 Priorities[NumPriorities].pri_name = newstr(&bp[1]); 522 Priorities[NumPriorities].pri_val = atoi(++p); 523 NumPriorities++; 524 break; 525 526 case 'V': /* configuration syntax version */ 527 for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 528 continue; 529 if (!isascii(*p) || !isdigit(*p)) 530 { 531 syserr("invalid argument to V line: \"%.20s\"", 532 &bp[1]); 533 break; 534 } 535 ConfigLevel = strtol(p, &ep, 10); 536 if (ConfigLevel >= 5) 537 { 538 /* level 5 configs have short name in $w */ 539 p = macvalue('w', e); 540 if (p != NULL && (p = strchr(p, '.')) != NULL) 541 *p = '\0'; 542 } 543 if (*ep++ == '/') 544 { 545 /* extract vendor code */ 546 for (p = ep; isascii(*p) && isalpha(*p); ) 547 p++; 548 *p = '\0'; 549 550 if (!setvendor(ep)) 551 syserr("invalid V line vendor code: \"%s\"", 552 ep); 553 } 554 break; 555 556 case 'K': 557 makemapentry(&bp[1]); 558 break; 559 560 default: 561 badline: 562 syserr("unknown control line \"%s\"", bp); 563 } 564 if (bp != buf) 565 free(bp); 566 } 567 if (ferror(cf)) 568 { 569 syserr("I/O read error", cfname); 570 exit(EX_OSFILE); 571 } 572 fclose(cf); 573 FileName = NULL; 574 575 /* initialize host maps from local service tables */ 576 inithostmaps(); 577 578 /* determine if we need to do special name-server frotz */ 579 { 580 int nmaps; 581 char *maptype[MAXMAPSTACK]; 582 short mapreturn[MAXMAPACTIONS]; 583 584 nmaps = switch_map_find("hosts", maptype, mapreturn); 585 UseNameServer = FALSE; 586 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 587 { 588 register int mapno; 589 590 for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 591 { 592 if (strcmp(maptype[mapno], "dns") == 0) 593 UseNameServer = TRUE; 594 } 595 } 596 597 #ifdef HESIOD 598 nmaps = switch_map_find("passwd", maptype, mapreturn); 599 UseHesiod = FALSE; 600 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 601 { 602 register int mapno; 603 604 for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 605 { 606 if (strcmp(maptype[mapno], "hesiod") == 0) 607 UseHesiod = TRUE; 608 } 609 } 610 #endif 611 } 612 } 613 /* 614 ** TOOMANY -- signal too many of some option 615 ** 616 ** Parameters: 617 ** id -- the id of the error line 618 ** maxcnt -- the maximum possible values 619 ** 620 ** Returns: 621 ** none. 622 ** 623 ** Side Effects: 624 ** gives a syserr. 625 */ 626 627 toomany(id, maxcnt) 628 char id; 629 int maxcnt; 630 { 631 syserr("too many %c lines, %d max", id, maxcnt); 632 } 633 /* 634 ** FILECLASS -- read members of a class from a file 635 ** 636 ** Parameters: 637 ** class -- class to define. 638 ** filename -- name of file to read. 639 ** fmt -- scanf string to use for match. 640 ** safe -- if set, this is a safe read. 641 ** optional -- if set, it is not an error for the file to 642 ** not exist. 643 ** 644 ** Returns: 645 ** none 646 ** 647 ** Side Effects: 648 ** 649 ** puts all lines in filename that match a scanf into 650 ** the named class. 651 */ 652 653 fileclass(class, filename, fmt, safe, optional) 654 int class; 655 char *filename; 656 char *fmt; 657 bool safe; 658 bool optional; 659 { 660 FILE *f; 661 struct stat stbuf; 662 char buf[MAXLINE]; 663 664 if (tTd(37, 2)) 665 printf("fileclass(%s, fmt=%s)\n", filename, fmt); 666 667 if (filename[0] == '|') 668 { 669 syserr("fileclass: pipes (F%c%s) not supported due to security problems", 670 class, filename); 671 return; 672 } 673 if (stat(filename, &stbuf) < 0) 674 { 675 if (tTd(37, 2)) 676 printf(" cannot stat (%s)\n", errstring(errno)); 677 if (!optional) 678 syserr("fileclass: cannot stat %s", filename); 679 return; 680 } 681 if (!S_ISREG(stbuf.st_mode)) 682 { 683 syserr("fileclass: %s not a regular file", filename); 684 return; 685 } 686 if (!safe && access(filename, R_OK) < 0) 687 { 688 syserr("fileclass: access denied on %s", filename); 689 return; 690 } 691 f = fopen(filename, "r"); 692 if (f == NULL) 693 { 694 syserr("fileclass: cannot open %s", filename); 695 return; 696 } 697 698 while (fgets(buf, sizeof buf, f) != NULL) 699 { 700 register STAB *s; 701 register char *p; 702 # ifdef SCANF 703 char wordbuf[MAXNAME+1]; 704 705 if (sscanf(buf, fmt, wordbuf) != 1) 706 continue; 707 p = wordbuf; 708 # else /* SCANF */ 709 p = buf; 710 # endif /* SCANF */ 711 712 /* 713 ** Break up the match into words. 714 */ 715 716 while (*p != '\0') 717 { 718 register char *q; 719 720 /* strip leading spaces */ 721 while (isascii(*p) && isspace(*p)) 722 p++; 723 if (*p == '\0') 724 break; 725 726 /* find the end of the word */ 727 q = p; 728 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 729 p++; 730 if (*p != '\0') 731 *p++ = '\0'; 732 733 /* enter the word in the symbol table */ 734 setclass(class, q); 735 } 736 } 737 738 (void) fclose(f); 739 } 740 /* 741 ** MAKEMAILER -- define a new mailer. 742 ** 743 ** Parameters: 744 ** line -- description of mailer. This is in labeled 745 ** fields. The fields are: 746 ** A -- the argv for this mailer 747 ** C -- the character set for MIME conversions 748 ** D -- the directory to run in 749 ** E -- the eol string 750 ** F -- the flags associated with the mailer 751 ** L -- the maximum line length 752 ** M -- the maximum message size 753 ** P -- the path to the mailer 754 ** R -- the recipient rewriting set 755 ** S -- the sender rewriting set 756 ** T -- the mailer type (for DSNs) 757 ** U -- the uid to run as 758 ** The first word is the canonical name of the mailer. 759 ** 760 ** Returns: 761 ** none. 762 ** 763 ** Side Effects: 764 ** enters the mailer into the mailer table. 765 */ 766 767 makemailer(line) 768 char *line; 769 { 770 register char *p; 771 register struct mailer *m; 772 register STAB *s; 773 int i; 774 char fcode; 775 auto char *endp; 776 extern int NextMailer; 777 extern char **makeargv(); 778 extern char *munchstring(); 779 extern long atol(); 780 781 /* allocate a mailer and set up defaults */ 782 m = (struct mailer *) xalloc(sizeof *m); 783 bzero((char *) m, sizeof *m); 784 m->m_eol = "\n"; 785 m->m_uid = m->m_gid = 0; 786 787 /* collect the mailer name */ 788 for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 789 continue; 790 if (*p != '\0') 791 *p++ = '\0'; 792 m->m_name = newstr(line); 793 794 /* now scan through and assign info from the fields */ 795 while (*p != '\0') 796 { 797 auto char *delimptr; 798 799 while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 800 p++; 801 802 /* p now points to field code */ 803 fcode = *p; 804 while (*p != '\0' && *p != '=' && *p != ',') 805 p++; 806 if (*p++ != '=') 807 { 808 syserr("mailer %s: `=' expected", m->m_name); 809 return; 810 } 811 while (isascii(*p) && isspace(*p)) 812 p++; 813 814 /* p now points to the field body */ 815 p = munchstring(p, &delimptr); 816 817 /* install the field into the mailer struct */ 818 switch (fcode) 819 { 820 case 'P': /* pathname */ 821 m->m_mailer = newstr(p); 822 break; 823 824 case 'F': /* flags */ 825 for (; *p != '\0'; p++) 826 if (!(isascii(*p) && isspace(*p))) 827 setbitn(*p, m->m_flags); 828 break; 829 830 case 'S': /* sender rewriting ruleset */ 831 case 'R': /* recipient rewriting ruleset */ 832 i = strtol(p, &endp, 10); 833 if (i < 0 || i >= MAXRWSETS) 834 { 835 syserr("invalid rewrite set, %d max", MAXRWSETS); 836 return; 837 } 838 if (fcode == 'S') 839 m->m_sh_rwset = m->m_se_rwset = i; 840 else 841 m->m_rh_rwset = m->m_re_rwset = i; 842 843 p = endp; 844 if (*p++ == '/') 845 { 846 i = strtol(p, NULL, 10); 847 if (i < 0 || i >= MAXRWSETS) 848 { 849 syserr("invalid rewrite set, %d max", 850 MAXRWSETS); 851 return; 852 } 853 if (fcode == 'S') 854 m->m_sh_rwset = i; 855 else 856 m->m_rh_rwset = i; 857 } 858 break; 859 860 case 'E': /* end of line string */ 861 m->m_eol = newstr(p); 862 break; 863 864 case 'A': /* argument vector */ 865 m->m_argv = makeargv(p); 866 break; 867 868 case 'M': /* maximum message size */ 869 m->m_maxsize = atol(p); 870 break; 871 872 case 'L': /* maximum line length */ 873 m->m_linelimit = atoi(p); 874 break; 875 876 case 'D': /* working directory */ 877 m->m_execdir = newstr(p); 878 break; 879 880 case 'C': /* default charset */ 881 m->m_defcharset = newstr(p); 882 break; 883 884 case 'T': /* MTA Type */ 885 m->m_mtatype = newstr(p); 886 p = strchr(m->m_mtatype, '/'); 887 if (p != NULL) 888 { 889 *p++ = '\0'; 890 if (*p == '\0') 891 p = NULL; 892 } 893 if (p == NULL) 894 m->m_addrtype = m->m_mtatype; 895 else 896 { 897 m->m_addrtype = p; 898 p = strchr(p, '/'); 899 } 900 if (p != NULL) 901 { 902 *p++ = '\0'; 903 if (*p == '\0') 904 p = NULL; 905 } 906 if (p == NULL) 907 m->m_diagtype = m->m_mtatype; 908 else 909 m->m_diagtype = p; 910 break; 911 912 case 'U': /* user id */ 913 if (isascii(*p) && !isdigit(*p)) 914 { 915 char *q = p; 916 struct passwd *pw; 917 918 while (isascii(*p) && isalnum(*p)) 919 p++; 920 while (isascii(*p) && isspace(*p)) 921 *p++ = '\0'; 922 if (*p != '\0') 923 *p++ = '\0'; 924 pw = getpwnam(q); 925 if (pw == NULL) 926 syserr("readcf: mailer U= flag: unknown user %s", q); 927 else 928 { 929 m->m_uid = pw->pw_uid; 930 m->m_gid = pw->pw_gid; 931 } 932 } 933 else 934 { 935 auto char *q; 936 937 m->m_uid = strtol(p, &q, 0); 938 p = q; 939 } 940 while (isascii(*p) && isspace(*p)) 941 p++; 942 if (*p == '\0') 943 break; 944 if (isascii(*p) && !isdigit(*p)) 945 { 946 char *q = p; 947 struct group *gr; 948 949 while (isascii(*p) && isalnum(*p)) 950 p++; 951 *p++ = '\0'; 952 gr = getgrnam(q); 953 if (gr == NULL) 954 syserr("readcf: mailer U= flag: unknown group %s", q); 955 else 956 m->m_gid = gr->gr_gid; 957 } 958 else 959 { 960 m->m_gid = strtol(p, NULL, 0); 961 } 962 break; 963 } 964 965 p = delimptr; 966 } 967 968 /* do some rationality checking */ 969 if (m->m_argv == NULL) 970 { 971 syserr("M%s: A= argument required", m->m_name); 972 return; 973 } 974 if (m->m_mailer == NULL) 975 { 976 syserr("M%s: P= argument required", m->m_name); 977 return; 978 } 979 980 if (NextMailer >= MAXMAILERS) 981 { 982 syserr("too many mailers defined (%d max)", MAXMAILERS); 983 return; 984 } 985 986 /* do some heuristic cleanup for back compatibility */ 987 if (bitnset(M_LIMITS, m->m_flags)) 988 { 989 if (m->m_linelimit == 0) 990 m->m_linelimit = SMTPLINELIM; 991 if (ConfigLevel < 2) 992 setbitn(M_7BITS, m->m_flags); 993 } 994 995 if (ConfigLevel < 6 && 996 (strcmp(m->m_mailer, "[IPC]") == 0 || 997 strcmp(m->m_mailer, "[TCP]") == 0)) 998 { 999 if (m->m_mtatype == NULL) 1000 m->m_mtatype = "dns"; 1001 if (m->m_addrtype == NULL) 1002 m->m_addrtype = "rfc822"; 1003 if (m->m_diagtype == NULL) 1004 m->m_diagtype = "smtp"; 1005 } 1006 1007 /* enter the mailer into the symbol table */ 1008 s = stab(m->m_name, ST_MAILER, ST_ENTER); 1009 if (s->s_mailer != NULL) 1010 { 1011 i = s->s_mailer->m_mno; 1012 free(s->s_mailer); 1013 } 1014 else 1015 { 1016 i = NextMailer++; 1017 } 1018 Mailer[i] = s->s_mailer = m; 1019 m->m_mno = i; 1020 } 1021 /* 1022 ** MUNCHSTRING -- translate a string into internal form. 1023 ** 1024 ** Parameters: 1025 ** p -- the string to munch. 1026 ** delimptr -- if non-NULL, set to the pointer of the 1027 ** field delimiter character. 1028 ** 1029 ** Returns: 1030 ** the munched string. 1031 */ 1032 1033 char * 1034 munchstring(p, delimptr) 1035 register char *p; 1036 char **delimptr; 1037 { 1038 register char *q; 1039 bool backslash = FALSE; 1040 bool quotemode = FALSE; 1041 static char buf[MAXLINE]; 1042 1043 for (q = buf; *p != '\0'; p++) 1044 { 1045 if (backslash) 1046 { 1047 /* everything is roughly literal */ 1048 backslash = FALSE; 1049 switch (*p) 1050 { 1051 case 'r': /* carriage return */ 1052 *q++ = '\r'; 1053 continue; 1054 1055 case 'n': /* newline */ 1056 *q++ = '\n'; 1057 continue; 1058 1059 case 'f': /* form feed */ 1060 *q++ = '\f'; 1061 continue; 1062 1063 case 'b': /* backspace */ 1064 *q++ = '\b'; 1065 continue; 1066 } 1067 *q++ = *p; 1068 } 1069 else 1070 { 1071 if (*p == '\\') 1072 backslash = TRUE; 1073 else if (*p == '"') 1074 quotemode = !quotemode; 1075 else if (quotemode || *p != ',') 1076 *q++ = *p; 1077 else 1078 break; 1079 } 1080 } 1081 1082 if (delimptr != NULL) 1083 *delimptr = p; 1084 *q++ = '\0'; 1085 return (buf); 1086 } 1087 /* 1088 ** MAKEARGV -- break up a string into words 1089 ** 1090 ** Parameters: 1091 ** p -- the string to break up. 1092 ** 1093 ** Returns: 1094 ** a char **argv (dynamically allocated) 1095 ** 1096 ** Side Effects: 1097 ** munges p. 1098 */ 1099 1100 char ** 1101 makeargv(p) 1102 register char *p; 1103 { 1104 char *q; 1105 int i; 1106 char **avp; 1107 char *argv[MAXPV + 1]; 1108 1109 /* take apart the words */ 1110 i = 0; 1111 while (*p != '\0' && i < MAXPV) 1112 { 1113 q = p; 1114 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1115 p++; 1116 while (isascii(*p) && isspace(*p)) 1117 *p++ = '\0'; 1118 argv[i++] = newstr(q); 1119 } 1120 argv[i++] = NULL; 1121 1122 /* now make a copy of the argv */ 1123 avp = (char **) xalloc(sizeof *avp * i); 1124 bcopy((char *) argv, (char *) avp, sizeof *avp * i); 1125 1126 return (avp); 1127 } 1128 /* 1129 ** PRINTRULES -- print rewrite rules (for debugging) 1130 ** 1131 ** Parameters: 1132 ** none. 1133 ** 1134 ** Returns: 1135 ** none. 1136 ** 1137 ** Side Effects: 1138 ** prints rewrite rules. 1139 */ 1140 1141 printrules() 1142 { 1143 register struct rewrite *rwp; 1144 register int ruleset; 1145 1146 for (ruleset = 0; ruleset < 10; ruleset++) 1147 { 1148 if (RewriteRules[ruleset] == NULL) 1149 continue; 1150 printf("\n----Rule Set %d:", ruleset); 1151 1152 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 1153 { 1154 printf("\nLHS:"); 1155 printav(rwp->r_lhs); 1156 printf("RHS:"); 1157 printav(rwp->r_rhs); 1158 } 1159 } 1160 } 1161 /* 1162 ** PRINTMAILER -- print mailer structure (for debugging) 1163 ** 1164 ** Parameters: 1165 ** m -- the mailer to print 1166 ** 1167 ** Returns: 1168 ** none. 1169 */ 1170 1171 printmailer(m) 1172 register MAILER *m; 1173 { 1174 int j; 1175 1176 printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 1177 m->m_mno, m->m_name, 1178 m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 1179 m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 1180 m->m_uid, m->m_gid); 1181 for (j = '\0'; j <= '\177'; j++) 1182 if (bitnset(j, m->m_flags)) 1183 (void) putchar(j); 1184 printf(" L=%d E=", m->m_linelimit); 1185 xputs(m->m_eol); 1186 if (m->m_defcharset != NULL) 1187 printf(" C=%s", m->m_defcharset); 1188 printf(" T=%s/%s/%s", 1189 m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 1190 m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 1191 m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 1192 if (m->m_argv != NULL) 1193 { 1194 char **a = m->m_argv; 1195 1196 printf(" A="); 1197 while (*a != NULL) 1198 { 1199 if (a != m->m_argv) 1200 printf(" "); 1201 xputs(*a++); 1202 } 1203 } 1204 printf("\n"); 1205 } 1206 /* 1207 ** SETOPTION -- set global processing option 1208 ** 1209 ** Parameters: 1210 ** opt -- option name. 1211 ** val -- option value (as a text string). 1212 ** safe -- set if this came from a configuration file. 1213 ** Some options (if set from the command line) will 1214 ** reset the user id to avoid security problems. 1215 ** sticky -- if set, don't let other setoptions override 1216 ** this value. 1217 ** e -- the main envelope. 1218 ** 1219 ** Returns: 1220 ** none. 1221 ** 1222 ** Side Effects: 1223 ** Sets options as implied by the arguments. 1224 */ 1225 1226 static BITMAP StickyOpt; /* set if option is stuck */ 1227 1228 1229 #if NAMED_BIND 1230 1231 struct resolverflags 1232 { 1233 char *rf_name; /* name of the flag */ 1234 long rf_bits; /* bits to set/clear */ 1235 } ResolverFlags[] = 1236 { 1237 "debug", RES_DEBUG, 1238 "aaonly", RES_AAONLY, 1239 "usevc", RES_USEVC, 1240 "primary", RES_PRIMARY, 1241 "igntc", RES_IGNTC, 1242 "recurse", RES_RECURSE, 1243 "defnames", RES_DEFNAMES, 1244 "stayopen", RES_STAYOPEN, 1245 "dnsrch", RES_DNSRCH, 1246 "true", 0, /* to avoid error on old syntax */ 1247 NULL, 0 1248 }; 1249 1250 #endif 1251 1252 struct optioninfo 1253 { 1254 char *o_name; /* long name of option */ 1255 u_char o_code; /* short name of option */ 1256 bool o_safe; /* safe for random people to use */ 1257 } OptionTab[] = 1258 { 1259 "SevenBitInput", '7', TRUE, 1260 "EightBitMode", '8', TRUE, 1261 "AliasFile", 'A', FALSE, 1262 "AliasWait", 'a', FALSE, 1263 "BlankSub", 'B', FALSE, 1264 "MinFreeBlocks", 'b', TRUE, 1265 "CheckpointInterval", 'C', TRUE, 1266 "HoldExpensive", 'c', FALSE, 1267 "AutoRebuildAliases", 'D', FALSE, 1268 "DeliveryMode", 'd', TRUE, 1269 "ErrorHeader", 'E', FALSE, 1270 "ErrorMode", 'e', TRUE, 1271 "TempFileMode", 'F', FALSE, 1272 "SaveFromLine", 'f', FALSE, 1273 "MatchGECOS", 'G', FALSE, 1274 "HelpFile", 'H', FALSE, 1275 "MaxHopCount", 'h', FALSE, 1276 "NameServerOptions", 'I', FALSE, 1277 "IgnoreDots", 'i', TRUE, 1278 "ForwardPath", 'J', FALSE, 1279 "SendMimeErrors", 'j', TRUE, 1280 "ConnectionCacheSize", 'k', FALSE, 1281 "ConnectionCacheTimeout", 'K', FALSE, 1282 "UseErrorsTo", 'l', FALSE, 1283 "LogLevel", 'L', FALSE, 1284 "MeToo", 'm', TRUE, 1285 "CheckAliases", 'n', FALSE, 1286 "OldStyleHeaders", 'o', TRUE, 1287 "DaemonPortOptions", 'O', FALSE, 1288 "PrivacyOptions", 'p', TRUE, 1289 "PostmasterCopy", 'P', FALSE, 1290 "QueueFactor", 'q', FALSE, 1291 "QueueDirectory", 'Q', FALSE, 1292 "DontPruneRoutes", 'R', FALSE, 1293 "Timeout", 'r', TRUE, 1294 "StatusFile", 'S', FALSE, 1295 "SuperSafe", 's', TRUE, 1296 "QueueTimeout", 'T', FALSE, 1297 "TimeZoneSpec", 't', FALSE, 1298 "UserDatabaseSpec", 'U', FALSE, 1299 "DefaultUser", 'u', FALSE, 1300 "FallbackMXhost", 'V', FALSE, 1301 "Verbose", 'v', TRUE, 1302 "TryNullMXList", 'w', TRUE, 1303 "QueueLA", 'x', FALSE, 1304 "RefuseLA", 'X', FALSE, 1305 "RecipientFactor", 'y', FALSE, 1306 "ForkQueueRuns", 'Y', FALSE, 1307 "ClassFactor", 'z', FALSE, 1308 "TimeFactor", 'Z', FALSE, 1309 #define O_BSP 0x80 1310 "BrokenSmtpPeers", O_BSP, TRUE, 1311 #define O_QUEUESORTORD 0x81 1312 "QueueSortOrder", O_QUEUESORTORD, TRUE, 1313 #define O_MQA 0x83 1314 "MinQueueAge", O_MQA, TRUE, 1315 #define O_MHSA 0x84 1316 /* 1317 "MaxHostStatAge", O_MHSA, TRUE, 1318 */ 1319 #define O_DEFCHARSET 0x85 1320 "DefaultCharSet", O_DEFCHARSET, TRUE, 1321 #define O_SSFILE 0x86 1322 "ServiceSwitchFile", O_SSFILE, FALSE, 1323 #define O_DIALDELAY 0x87 1324 "DialDelay", O_DIALDELAY, TRUE, 1325 1326 NULL, '\0', FALSE, 1327 }; 1328 1329 1330 1331 setoption(opt, val, safe, sticky, e) 1332 u_char opt; 1333 char *val; 1334 bool safe; 1335 bool sticky; 1336 register ENVELOPE *e; 1337 { 1338 register char *p; 1339 register struct optioninfo *o; 1340 char *subopt; 1341 extern bool atobool(); 1342 extern time_t convtime(); 1343 extern int QueueLA; 1344 extern int RefuseLA; 1345 extern bool Warn_Q_option; 1346 1347 errno = 0; 1348 if (opt == ' ') 1349 { 1350 /* full word options */ 1351 struct optioninfo *sel; 1352 1353 p = strchr(val, '='); 1354 if (p == NULL) 1355 p = &val[strlen(val)]; 1356 while (*--p == ' ') 1357 continue; 1358 while (*++p == ' ') 1359 *p = '\0'; 1360 if (p == val) 1361 { 1362 syserr("readcf: null option name"); 1363 return; 1364 } 1365 if (*p == '=') 1366 *p++ = '\0'; 1367 while (*p == ' ') 1368 p++; 1369 subopt = strchr(val, '.'); 1370 if (subopt != NULL) 1371 *subopt++ = '\0'; 1372 sel = NULL; 1373 for (o = OptionTab; o->o_name != NULL; o++) 1374 { 1375 if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1376 continue; 1377 if (strlen(o->o_name) == strlen(val)) 1378 { 1379 /* completely specified -- this must be it */ 1380 sel = NULL; 1381 break; 1382 } 1383 if (sel != NULL) 1384 break; 1385 sel = o; 1386 } 1387 if (sel != NULL && o->o_name == NULL) 1388 o = sel; 1389 else if (o->o_name == NULL) 1390 { 1391 syserr("readcf: unknown option name %s", val); 1392 return; 1393 } 1394 else if (sel != NULL) 1395 { 1396 syserr("readcf: ambiguous option name %s (matches %s and %s)", 1397 val, sel->o_name, o->o_name); 1398 return; 1399 } 1400 if (strlen(val) != strlen(o->o_name)) 1401 { 1402 bool oldVerbose = Verbose; 1403 1404 Verbose = TRUE; 1405 message("Option %s used as abbreviation for %s", 1406 val, o->o_name); 1407 Verbose = oldVerbose; 1408 } 1409 opt = o->o_code; 1410 val = p; 1411 } 1412 else 1413 { 1414 for (o = OptionTab; o->o_name != NULL; o++) 1415 { 1416 if (o->o_code == opt) 1417 break; 1418 } 1419 subopt = NULL; 1420 } 1421 1422 if (tTd(37, 1)) 1423 { 1424 printf(isascii(opt) && isprint(opt) ? 1425 "setoption %s (%c).%s=%s" : 1426 "setoption %s (0x%x).%s=%s", 1427 o->o_name == NULL ? "<unknown>" : o->o_name, 1428 opt, 1429 subopt == NULL ? "" : subopt, 1430 val); 1431 } 1432 1433 /* 1434 ** See if this option is preset for us. 1435 */ 1436 1437 if (!sticky && bitnset(opt, StickyOpt)) 1438 { 1439 if (tTd(37, 1)) 1440 printf(" (ignored)\n"); 1441 return; 1442 } 1443 1444 /* 1445 ** Check to see if this option can be specified by this user. 1446 */ 1447 1448 if (!safe && RealUid == 0) 1449 safe = TRUE; 1450 if (!safe && !o->o_safe) 1451 { 1452 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 1453 { 1454 if (tTd(37, 1)) 1455 printf(" (unsafe)"); 1456 if (RealUid != geteuid()) 1457 { 1458 if (tTd(37, 1)) 1459 printf("(Resetting uid)"); 1460 (void) setgid(RealGid); 1461 (void) setuid(RealUid); 1462 } 1463 } 1464 } 1465 if (tTd(37, 1)) 1466 printf("\n"); 1467 1468 switch (opt & 0xff) 1469 { 1470 case '7': /* force seven-bit input */ 1471 SevenBitInput = atobool(val); 1472 break; 1473 1474 case '8': /* handling of 8-bit input */ 1475 switch (*val) 1476 { 1477 case 'r': /* reject 8-bit, don't convert MIME */ 1478 MimeMode = 0; 1479 break; 1480 1481 case 'm': /* convert 8-bit, convert MIME */ 1482 MimeMode = MM_CVTMIME|MM_MIME8BIT; 1483 break; 1484 1485 case 'j': /* "just send 8" */ 1486 MimeMode = MM_PASS8BIT; 1487 break; 1488 1489 case 'p': /* pass 8 bit, convert MIME */ 1490 MimeMode = MM_PASS8BIT|MM_CVTMIME; 1491 break; 1492 1493 case 's': /* strict adherence */ 1494 MimeMode = MM_CVTMIME; 1495 break; 1496 1497 case 'a': /* encode 8 bit if available */ 1498 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1499 break; 1500 1501 case 'c': /* convert 8 bit to MIME, never 7 bit */ 1502 MimeMode = MM_MIME8BIT; 1503 break; 1504 1505 default: 1506 syserr("Unknown 8-bit mode %c", *val); 1507 exit(EX_USAGE); 1508 } 1509 break; 1510 1511 case 'A': /* set default alias file */ 1512 if (val[0] == '\0') 1513 setalias("aliases"); 1514 else 1515 setalias(val); 1516 break; 1517 1518 case 'a': /* look N minutes for "@:@" in alias file */ 1519 if (val[0] == '\0') 1520 SafeAlias = 5 * 60; /* five minutes */ 1521 else 1522 SafeAlias = convtime(val, 'm'); 1523 break; 1524 1525 case 'B': /* substitution for blank character */ 1526 SpaceSub = val[0]; 1527 if (SpaceSub == '\0') 1528 SpaceSub = ' '; 1529 break; 1530 1531 case 'b': /* min blocks free on queue fs/max msg size */ 1532 p = strchr(val, '/'); 1533 if (p != NULL) 1534 { 1535 *p++ = '\0'; 1536 MaxMessageSize = atol(p); 1537 } 1538 MinBlocksFree = atol(val); 1539 break; 1540 1541 case 'c': /* don't connect to "expensive" mailers */ 1542 NoConnect = atobool(val); 1543 break; 1544 1545 case 'C': /* checkpoint every N addresses */ 1546 CheckpointInterval = atoi(val); 1547 break; 1548 1549 case 'd': /* delivery mode */ 1550 switch (*val) 1551 { 1552 case '\0': 1553 e->e_sendmode = SM_DELIVER; 1554 break; 1555 1556 case SM_QUEUE: /* queue only */ 1557 #ifndef QUEUE 1558 syserr("need QUEUE to set -odqueue"); 1559 #endif /* QUEUE */ 1560 /* fall through..... */ 1561 1562 case SM_DELIVER: /* do everything */ 1563 case SM_FORK: /* fork after verification */ 1564 e->e_sendmode = *val; 1565 break; 1566 1567 default: 1568 syserr("Unknown delivery mode %c", *val); 1569 exit(EX_USAGE); 1570 } 1571 break; 1572 1573 case 'D': /* rebuild alias database as needed */ 1574 AutoRebuild = atobool(val); 1575 break; 1576 1577 case 'E': /* error message header/header file */ 1578 if (*val != '\0') 1579 ErrMsgFile = newstr(val); 1580 break; 1581 1582 case 'e': /* set error processing mode */ 1583 switch (*val) 1584 { 1585 case EM_QUIET: /* be silent about it */ 1586 case EM_MAIL: /* mail back */ 1587 case EM_BERKNET: /* do berknet error processing */ 1588 case EM_WRITE: /* write back (or mail) */ 1589 case EM_PRINT: /* print errors normally (default) */ 1590 e->e_errormode = *val; 1591 break; 1592 } 1593 break; 1594 1595 case 'F': /* file mode */ 1596 FileMode = atooct(val) & 0777; 1597 break; 1598 1599 case 'f': /* save Unix-style From lines on front */ 1600 SaveFrom = atobool(val); 1601 break; 1602 1603 case 'G': /* match recipients against GECOS field */ 1604 MatchGecos = atobool(val); 1605 break; 1606 1607 case 'g': /* default gid */ 1608 g_opt: 1609 if (isascii(*val) && isdigit(*val)) 1610 DefGid = atoi(val); 1611 else 1612 { 1613 register struct group *gr; 1614 1615 DefGid = -1; 1616 gr = getgrnam(val); 1617 if (gr == NULL) 1618 syserr("readcf: option %c: unknown group %s", 1619 opt, val); 1620 else 1621 DefGid = gr->gr_gid; 1622 } 1623 break; 1624 1625 case 'H': /* help file */ 1626 if (val[0] == '\0') 1627 HelpFile = "sendmail.hf"; 1628 else 1629 HelpFile = newstr(val); 1630 break; 1631 1632 case 'h': /* maximum hop count */ 1633 MaxHopCount = atoi(val); 1634 break; 1635 1636 case 'I': /* use internet domain name server */ 1637 #if NAMED_BIND 1638 for (p = val; *p != 0; ) 1639 { 1640 bool clearmode; 1641 char *q; 1642 struct resolverflags *rfp; 1643 1644 while (*p == ' ') 1645 p++; 1646 if (*p == '\0') 1647 break; 1648 clearmode = FALSE; 1649 if (*p == '-') 1650 clearmode = TRUE; 1651 else if (*p != '+') 1652 p--; 1653 p++; 1654 q = p; 1655 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1656 p++; 1657 if (*p != '\0') 1658 *p++ = '\0'; 1659 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 1660 { 1661 if (strcasecmp(q, rfp->rf_name) == 0) 1662 break; 1663 } 1664 if (rfp->rf_name == NULL) 1665 syserr("readcf: I option value %s unrecognized", q); 1666 else if (clearmode) 1667 _res.options &= ~rfp->rf_bits; 1668 else 1669 _res.options |= rfp->rf_bits; 1670 } 1671 if (tTd(8, 2)) 1672 printf("_res.options = %x\n", _res.options); 1673 #else 1674 usrerr("name server (I option) specified but BIND not compiled in"); 1675 #endif 1676 break; 1677 1678 case 'i': /* ignore dot lines in message */ 1679 IgnrDot = atobool(val); 1680 break; 1681 1682 case 'j': /* send errors in MIME (RFC 1341) format */ 1683 SendMIMEErrors = atobool(val); 1684 break; 1685 1686 case 'J': /* .forward search path */ 1687 ForwardPath = newstr(val); 1688 break; 1689 1690 case 'k': /* connection cache size */ 1691 MaxMciCache = atoi(val); 1692 if (MaxMciCache < 0) 1693 MaxMciCache = 0; 1694 break; 1695 1696 case 'K': /* connection cache timeout */ 1697 MciCacheTimeout = convtime(val, 'm'); 1698 break; 1699 1700 case 'l': /* use Errors-To: header */ 1701 UseErrorsTo = atobool(val); 1702 break; 1703 1704 case 'L': /* log level */ 1705 if (safe || LogLevel < atoi(val)) 1706 LogLevel = atoi(val); 1707 break; 1708 1709 case 'M': /* define macro */ 1710 p = newstr(&val[1]); 1711 if (!safe) 1712 cleanstrcpy(p, p, MAXNAME); 1713 define(val[0], p, CurEnv); 1714 sticky = FALSE; 1715 break; 1716 1717 case 'm': /* send to me too */ 1718 MeToo = atobool(val); 1719 break; 1720 1721 case 'n': /* validate RHS in newaliases */ 1722 CheckAliases = atobool(val); 1723 break; 1724 1725 /* 'N' available -- was "net name" */ 1726 1727 case 'O': /* daemon options */ 1728 setdaemonoptions(val); 1729 break; 1730 1731 case 'o': /* assume old style headers */ 1732 if (atobool(val)) 1733 CurEnv->e_flags |= EF_OLDSTYLE; 1734 else 1735 CurEnv->e_flags &= ~EF_OLDSTYLE; 1736 break; 1737 1738 case 'p': /* select privacy level */ 1739 p = val; 1740 for (;;) 1741 { 1742 register struct prival *pv; 1743 extern struct prival PrivacyValues[]; 1744 1745 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 1746 p++; 1747 if (*p == '\0') 1748 break; 1749 val = p; 1750 while (isascii(*p) && isalnum(*p)) 1751 p++; 1752 if (*p != '\0') 1753 *p++ = '\0'; 1754 1755 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 1756 { 1757 if (strcasecmp(val, pv->pv_name) == 0) 1758 break; 1759 } 1760 if (pv->pv_name == NULL) 1761 syserr("readcf: Op line: %s unrecognized", val); 1762 PrivacyFlags |= pv->pv_flag; 1763 } 1764 break; 1765 1766 case 'P': /* postmaster copy address for returned mail */ 1767 PostMasterCopy = newstr(val); 1768 break; 1769 1770 case 'q': /* slope of queue only function */ 1771 QueueFactor = atoi(val); 1772 break; 1773 1774 case 'Q': /* queue directory */ 1775 if (val[0] == '\0') 1776 QueueDir = "mqueue"; 1777 else 1778 QueueDir = newstr(val); 1779 if (RealUid != 0 && !safe) 1780 Warn_Q_option = TRUE; 1781 break; 1782 1783 case 'R': /* don't prune routes */ 1784 DontPruneRoutes = atobool(val); 1785 break; 1786 1787 case 'r': /* read timeout */ 1788 if (subopt == NULL) 1789 inittimeouts(val); 1790 else 1791 settimeout(subopt, val); 1792 break; 1793 1794 case 'S': /* status file */ 1795 if (val[0] == '\0') 1796 StatFile = "sendmail.st"; 1797 else 1798 StatFile = newstr(val); 1799 break; 1800 1801 case 's': /* be super safe, even if expensive */ 1802 SuperSafe = atobool(val); 1803 break; 1804 1805 case 'T': /* queue timeout */ 1806 p = strchr(val, '/'); 1807 if (p != NULL) 1808 { 1809 *p++ = '\0'; 1810 settimeout("queuewarn", p); 1811 } 1812 settimeout("queuereturn", val); 1813 break; 1814 1815 case 't': /* time zone name */ 1816 TimeZoneSpec = newstr(val); 1817 break; 1818 1819 case 'U': /* location of user database */ 1820 UdbSpec = newstr(val); 1821 break; 1822 1823 case 'u': /* set default uid */ 1824 for (p = val; *p != '\0'; p++) 1825 { 1826 if (*p == '.' || *p == '/' || *p == ':') 1827 { 1828 *p++ = '\0'; 1829 break; 1830 } 1831 } 1832 if (isascii(*val) && isdigit(*val)) 1833 DefUid = atoi(val); 1834 else 1835 { 1836 register struct passwd *pw; 1837 1838 DefUid = -1; 1839 pw = getpwnam(val); 1840 if (pw == NULL) 1841 syserr("readcf: option u: unknown user %s", val); 1842 else 1843 { 1844 DefUid = pw->pw_uid; 1845 DefGid = pw->pw_gid; 1846 } 1847 } 1848 setdefuser(); 1849 1850 /* handle the group if it is there */ 1851 if (*p == '\0') 1852 break; 1853 val = p; 1854 goto g_opt; 1855 1856 case 'V': /* fallback MX host */ 1857 FallBackMX = newstr(val); 1858 break; 1859 1860 case 'v': /* run in verbose mode */ 1861 Verbose = atobool(val); 1862 break; 1863 1864 case 'w': /* if we are best MX, try host directly */ 1865 TryNullMXList = atobool(val); 1866 break; 1867 1868 /* 'W' available -- was wizard password */ 1869 1870 case 'x': /* load avg at which to auto-queue msgs */ 1871 QueueLA = atoi(val); 1872 break; 1873 1874 case 'X': /* load avg at which to auto-reject connections */ 1875 RefuseLA = atoi(val); 1876 break; 1877 1878 case 'y': /* work recipient factor */ 1879 WkRecipFact = atoi(val); 1880 break; 1881 1882 case 'Y': /* fork jobs during queue runs */ 1883 ForkQueueRuns = atobool(val); 1884 break; 1885 1886 case 'z': /* work message class factor */ 1887 WkClassFact = atoi(val); 1888 break; 1889 1890 case 'Z': /* work time factor */ 1891 WkTimeFact = atoi(val); 1892 break; 1893 1894 case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 1895 BrokenSmtpPeers = atobool(val); 1896 break; 1897 1898 case O_QUEUESORTORD: /* queue sorting order */ 1899 switch (*val) 1900 { 1901 case 'h': /* Host first */ 1902 case 'H': 1903 QueueSortOrder = QS_BYHOST; 1904 break; 1905 1906 case 'p': /* Priority order */ 1907 case 'P': 1908 QueueSortOrder = QS_BYPRIORITY; 1909 break; 1910 1911 default: 1912 syserr("Invalid queue sort order \"%s\"", val); 1913 } 1914 break; 1915 1916 case O_MQA: /* minimum queue age between deliveries */ 1917 MinQueueAge = convtime(val, 'm'); 1918 break; 1919 1920 case O_MHSA: /* maximum age of cached host status */ 1921 MaxHostStatAge = convtime(val, 'm'); 1922 break; 1923 1924 case O_DEFCHARSET: /* default character set for mimefying */ 1925 DefaultCharSet = newstr(denlstring(val)); 1926 break; 1927 1928 case O_SSFILE: /* service switch file */ 1929 ServiceSwitchFile = newstr(val); 1930 break; 1931 1932 case O_DIALDELAY: /* delay for dial-on-demand operation */ 1933 DialDelay = convtime(val, 's'); 1934 break; 1935 1936 default: 1937 if (tTd(37, 1)) 1938 { 1939 if (isascii(opt) && isprint(opt)) 1940 printf("Warning: option %c unknown\n", opt); 1941 else 1942 printf("Warning: option 0x%x unknown\n", opt); 1943 } 1944 break; 1945 } 1946 if (sticky) 1947 setbitn(opt, StickyOpt); 1948 return; 1949 } 1950 /* 1951 ** SETCLASS -- set a string into a class 1952 ** 1953 ** Parameters: 1954 ** class -- the class to put the string in. 1955 ** str -- the string to enter 1956 ** 1957 ** Returns: 1958 ** none. 1959 ** 1960 ** Side Effects: 1961 ** puts the word into the symbol table. 1962 */ 1963 1964 setclass(class, str) 1965 int class; 1966 char *str; 1967 { 1968 register STAB *s; 1969 1970 if (tTd(37, 8)) 1971 printf("setclass(%c, %s)\n", class, str); 1972 s = stab(str, ST_CLASS, ST_ENTER); 1973 setbitn(class, s->s_class); 1974 } 1975 /* 1976 ** MAKEMAPENTRY -- create a map entry 1977 ** 1978 ** Parameters: 1979 ** line -- the config file line 1980 ** 1981 ** Returns: 1982 ** TRUE if it successfully entered the map entry. 1983 ** FALSE otherwise (usually syntax error). 1984 ** 1985 ** Side Effects: 1986 ** Enters the map into the dictionary. 1987 */ 1988 1989 void 1990 makemapentry(line) 1991 char *line; 1992 { 1993 register char *p; 1994 char *mapname; 1995 char *classname; 1996 register STAB *s; 1997 STAB *class; 1998 1999 for (p = line; isascii(*p) && isspace(*p); p++) 2000 continue; 2001 if (!(isascii(*p) && isalnum(*p))) 2002 { 2003 syserr("readcf: config K line: no map name"); 2004 return; 2005 } 2006 2007 mapname = p; 2008 while ((isascii(*++p) && isalnum(*p)) || *p == '.') 2009 continue; 2010 if (*p != '\0') 2011 *p++ = '\0'; 2012 while (isascii(*p) && isspace(*p)) 2013 p++; 2014 if (!(isascii(*p) && isalnum(*p))) 2015 { 2016 syserr("readcf: config K line, map %s: no map class", mapname); 2017 return; 2018 } 2019 classname = p; 2020 while (isascii(*++p) && isalnum(*p)) 2021 continue; 2022 if (*p != '\0') 2023 *p++ = '\0'; 2024 while (isascii(*p) && isspace(*p)) 2025 p++; 2026 2027 /* look up the class */ 2028 class = stab(classname, ST_MAPCLASS, ST_FIND); 2029 if (class == NULL) 2030 { 2031 syserr("readcf: map %s: class %s not available", mapname, classname); 2032 return; 2033 } 2034 2035 /* enter the map */ 2036 s = stab(mapname, ST_MAP, ST_ENTER); 2037 s->s_map.map_class = &class->s_mapclass; 2038 s->s_map.map_mname = newstr(mapname); 2039 2040 if (class->s_mapclass.map_parse(&s->s_map, p)) 2041 s->s_map.map_mflags |= MF_VALID; 2042 2043 if (tTd(37, 5)) 2044 { 2045 printf("map %s, class %s, flags %x, file %s,\n", 2046 s->s_map.map_mname, s->s_map.map_class->map_cname, 2047 s->s_map.map_mflags, 2048 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 2049 printf("\tapp %s, domain %s, rebuild %s\n", 2050 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 2051 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 2052 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 2053 } 2054 } 2055 /* 2056 ** INITTIMEOUTS -- parse and set timeout values 2057 ** 2058 ** Parameters: 2059 ** val -- a pointer to the values. If NULL, do initial 2060 ** settings. 2061 ** 2062 ** Returns: 2063 ** none. 2064 ** 2065 ** Side Effects: 2066 ** Initializes the TimeOuts structure 2067 */ 2068 2069 #define SECONDS 2070 #define MINUTES * 60 2071 #define HOUR * 3600 2072 2073 inittimeouts(val) 2074 register char *val; 2075 { 2076 register char *p; 2077 extern time_t convtime(); 2078 2079 if (val == NULL) 2080 { 2081 TimeOuts.to_initial = (time_t) 5 MINUTES; 2082 TimeOuts.to_helo = (time_t) 5 MINUTES; 2083 TimeOuts.to_mail = (time_t) 10 MINUTES; 2084 TimeOuts.to_rcpt = (time_t) 1 HOUR; 2085 TimeOuts.to_datainit = (time_t) 5 MINUTES; 2086 TimeOuts.to_datablock = (time_t) 1 HOUR; 2087 TimeOuts.to_datafinal = (time_t) 1 HOUR; 2088 TimeOuts.to_rset = (time_t) 5 MINUTES; 2089 TimeOuts.to_quit = (time_t) 2 MINUTES; 2090 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 2091 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2092 #if IDENTPROTO 2093 TimeOuts.to_ident = (time_t) 30 SECONDS; 2094 #else 2095 TimeOuts.to_ident = (time_t) 0 SECONDS; 2096 #endif 2097 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 2098 return; 2099 } 2100 2101 for (;; val = p) 2102 { 2103 while (isascii(*val) && isspace(*val)) 2104 val++; 2105 if (*val == '\0') 2106 break; 2107 for (p = val; *p != '\0' && *p != ','; p++) 2108 continue; 2109 if (*p != '\0') 2110 *p++ = '\0'; 2111 2112 if (isascii(*val) && isdigit(*val)) 2113 { 2114 /* old syntax -- set everything */ 2115 TimeOuts.to_mail = convtime(val, 'm'); 2116 TimeOuts.to_rcpt = TimeOuts.to_mail; 2117 TimeOuts.to_datainit = TimeOuts.to_mail; 2118 TimeOuts.to_datablock = TimeOuts.to_mail; 2119 TimeOuts.to_datafinal = TimeOuts.to_mail; 2120 TimeOuts.to_nextcommand = TimeOuts.to_mail; 2121 continue; 2122 } 2123 else 2124 { 2125 register char *q = strchr(val, ':'); 2126 2127 if (q == NULL && (q = strchr(val, '=')) == NULL) 2128 { 2129 /* syntax error */ 2130 continue; 2131 } 2132 *q++ = '\0'; 2133 settimeout(val, q); 2134 } 2135 } 2136 } 2137 /* 2138 ** SETTIMEOUT -- set an individual timeout 2139 ** 2140 ** Parameters: 2141 ** name -- the name of the timeout. 2142 ** val -- the value of the timeout. 2143 ** 2144 ** Returns: 2145 ** none. 2146 */ 2147 2148 settimeout(name, val) 2149 char *name; 2150 char *val; 2151 { 2152 register char *p; 2153 time_t to; 2154 extern time_t convtime(); 2155 2156 to = convtime(val, 'm'); 2157 p = strchr(name, '.'); 2158 if (p != NULL) 2159 *p++ = '\0'; 2160 2161 if (strcasecmp(name, "initial") == 0) 2162 TimeOuts.to_initial = to; 2163 else if (strcasecmp(name, "mail") == 0) 2164 TimeOuts.to_mail = to; 2165 else if (strcasecmp(name, "rcpt") == 0) 2166 TimeOuts.to_rcpt = to; 2167 else if (strcasecmp(name, "datainit") == 0) 2168 TimeOuts.to_datainit = to; 2169 else if (strcasecmp(name, "datablock") == 0) 2170 TimeOuts.to_datablock = to; 2171 else if (strcasecmp(name, "datafinal") == 0) 2172 TimeOuts.to_datafinal = to; 2173 else if (strcasecmp(name, "command") == 0) 2174 TimeOuts.to_nextcommand = to; 2175 else if (strcasecmp(name, "rset") == 0) 2176 TimeOuts.to_rset = to; 2177 else if (strcasecmp(name, "helo") == 0) 2178 TimeOuts.to_helo = to; 2179 else if (strcasecmp(name, "quit") == 0) 2180 TimeOuts.to_quit = to; 2181 else if (strcasecmp(name, "misc") == 0) 2182 TimeOuts.to_miscshort = to; 2183 else if (strcasecmp(name, "ident") == 0) 2184 TimeOuts.to_ident = to; 2185 else if (strcasecmp(name, "fileopen") == 0) 2186 TimeOuts.to_fileopen = to; 2187 else if (strcasecmp(name, "queuewarn") == 0) 2188 { 2189 to = convtime(val, 'h'); 2190 if (p == NULL || strcmp(p, "*") == 0) 2191 { 2192 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2193 TimeOuts.to_q_warning[TOC_URGENT] = to; 2194 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2195 } 2196 else if (strcasecmp(p, "normal") == 0) 2197 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2198 else if (strcasecmp(p, "urgent") == 0) 2199 TimeOuts.to_q_warning[TOC_URGENT] = to; 2200 else if (strcasecmp(p, "non-urgent") == 0) 2201 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2202 else 2203 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2204 } 2205 else if (strcasecmp(name, "queuereturn") == 0) 2206 { 2207 to = convtime(val, 'd'); 2208 if (p == NULL || strcmp(p, "*") == 0) 2209 { 2210 TimeOuts.to_q_return[TOC_NORMAL] = to; 2211 TimeOuts.to_q_return[TOC_URGENT] = to; 2212 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2213 } 2214 else if (strcasecmp(p, "normal") == 0) 2215 TimeOuts.to_q_return[TOC_NORMAL] = to; 2216 else if (strcasecmp(p, "urgent") == 0) 2217 TimeOuts.to_q_return[TOC_URGENT] = to; 2218 else if (strcasecmp(p, "non-urgent") == 0) 2219 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2220 else 2221 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2222 } 2223 else 2224 syserr("settimeout: invalid timeout %s", name); 2225 } 2226