1 /* 2 * Copyright (c) 1983, 1995 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.94 (Berkeley) 05/27/95"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include <grp.h> 15 #if NAMED_BIND 16 # include <resolv.h> 17 #endif 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 arg=val... Define mailer. n is the internal name. 42 ** Args specify mailer parameters. 43 ** Oxvalue Set option x to value. 44 ** Pname=value Set precedence name to value. 45 ** Vversioncode[/vendorcode] 46 ** Version level/vendor name of 47 ** configuration syntax. 48 ** Kmapname mapclass arguments.... 49 ** Define keyed lookup of a given class. 50 ** Arguments are class dependent. 51 ** Eenvar=value Set the environment value to the given value. 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_INITALIAS) 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, sizeof exbuf, e); 225 rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 226 sizeof pvpbuf, NULL, 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, sizeof exbuf, e); 313 rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 314 sizeof pvpbuf, NULL, 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, NULL, 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, 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 537 /* 538 ** Do heuristic tweaking for back compatibility. 539 */ 540 541 if (ConfigLevel >= 5) 542 { 543 /* level 5 configs have short name in $w */ 544 p = macvalue('w', e); 545 if (p != NULL && (p = strchr(p, '.')) != NULL) 546 *p = '\0'; 547 } 548 if (ConfigLevel >= 6) 549 { 550 ColonOkInAddr = FALSE; 551 } 552 553 /* 554 ** Look for vendor code. 555 */ 556 557 if (*ep++ == '/') 558 { 559 /* extract vendor code */ 560 for (p = ep; isascii(*p) && isalpha(*p); ) 561 p++; 562 *p = '\0'; 563 564 if (!setvendor(ep)) 565 syserr("invalid V line vendor code: \"%s\"", 566 ep); 567 } 568 break; 569 570 case 'K': 571 makemapentry(&bp[1]); 572 break; 573 574 case 'E': 575 p = strchr(bp, '='); 576 if (p != NULL) 577 *p++ = '\0'; 578 setuserenv(&bp[1], p); 579 break; 580 581 default: 582 badline: 583 syserr("unknown control line \"%s\"", bp); 584 } 585 if (bp != buf) 586 free(bp); 587 } 588 if (ferror(cf)) 589 { 590 syserr("I/O read error", cfname); 591 exit(EX_OSFILE); 592 } 593 fclose(cf); 594 FileName = NULL; 595 596 /* initialize host maps from local service tables */ 597 inithostmaps(); 598 599 /* determine if we need to do special name-server frotz */ 600 { 601 int nmaps; 602 char *maptype[MAXMAPSTACK]; 603 short mapreturn[MAXMAPACTIONS]; 604 605 nmaps = switch_map_find("hosts", maptype, mapreturn); 606 UseNameServer = FALSE; 607 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 608 { 609 register int mapno; 610 611 for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 612 { 613 if (strcmp(maptype[mapno], "dns") == 0) 614 UseNameServer = TRUE; 615 } 616 } 617 618 #ifdef HESIOD 619 nmaps = switch_map_find("passwd", maptype, mapreturn); 620 UseHesiod = FALSE; 621 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 622 { 623 register int mapno; 624 625 for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 626 { 627 if (strcmp(maptype[mapno], "hesiod") == 0) 628 UseHesiod = TRUE; 629 } 630 } 631 #endif 632 } 633 } 634 /* 635 ** TOOMANY -- signal too many of some option 636 ** 637 ** Parameters: 638 ** id -- the id of the error line 639 ** maxcnt -- the maximum possible values 640 ** 641 ** Returns: 642 ** none. 643 ** 644 ** Side Effects: 645 ** gives a syserr. 646 */ 647 648 toomany(id, maxcnt) 649 char id; 650 int maxcnt; 651 { 652 syserr("too many %c lines, %d max", id, maxcnt); 653 } 654 /* 655 ** FILECLASS -- read members of a class from a file 656 ** 657 ** Parameters: 658 ** class -- class to define. 659 ** filename -- name of file to read. 660 ** fmt -- scanf string to use for match. 661 ** safe -- if set, this is a safe read. 662 ** optional -- if set, it is not an error for the file to 663 ** not exist. 664 ** 665 ** Returns: 666 ** none 667 ** 668 ** Side Effects: 669 ** 670 ** puts all lines in filename that match a scanf into 671 ** the named class. 672 */ 673 674 fileclass(class, filename, fmt, safe, optional) 675 int class; 676 char *filename; 677 char *fmt; 678 bool safe; 679 bool optional; 680 { 681 FILE *f; 682 int sff; 683 int pid; 684 register char *p; 685 char buf[MAXLINE]; 686 687 if (tTd(37, 2)) 688 printf("fileclass(%s, fmt=%s)\n", filename, fmt); 689 690 if (filename[0] == '|') 691 { 692 auto int fd; 693 int i; 694 char *argv[MAXPV + 1]; 695 696 i = 0; 697 for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t")) 698 { 699 if (i >= MAXPV) 700 break; 701 argv[i++] = p; 702 } 703 argv[i] = NULL; 704 pid = prog_open(argv, &fd, CurEnv); 705 if (pid < 0) 706 f = NULL; 707 else 708 f = fdopen(fd, "r"); 709 } 710 else 711 { 712 pid = -1; 713 sff = SFF_REGONLY; 714 if (safe) 715 sff |= SFF_OPENASROOT; 716 f = safefopen(filename, O_RDONLY, 0, sff); 717 } 718 if (f == NULL) 719 { 720 if (!optional) 721 syserr("fileclass: cannot open %s", filename); 722 return; 723 } 724 725 while (fgets(buf, sizeof buf, f) != NULL) 726 { 727 register STAB *s; 728 register char *p; 729 # ifdef SCANF 730 char wordbuf[MAXNAME+1]; 731 732 if (sscanf(buf, fmt, wordbuf) != 1) 733 continue; 734 p = wordbuf; 735 # else /* SCANF */ 736 p = buf; 737 # endif /* SCANF */ 738 739 /* 740 ** Break up the match into words. 741 */ 742 743 while (*p != '\0') 744 { 745 register char *q; 746 747 /* strip leading spaces */ 748 while (isascii(*p) && isspace(*p)) 749 p++; 750 if (*p == '\0') 751 break; 752 753 /* find the end of the word */ 754 q = p; 755 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 756 p++; 757 if (*p != '\0') 758 *p++ = '\0'; 759 760 /* enter the word in the symbol table */ 761 setclass(class, q); 762 } 763 } 764 765 (void) fclose(f); 766 if (pid > 0) 767 (void) waitfor(pid); 768 } 769 /* 770 ** MAKEMAILER -- define a new mailer. 771 ** 772 ** Parameters: 773 ** line -- description of mailer. This is in labeled 774 ** fields. The fields are: 775 ** A -- the argv for this mailer 776 ** C -- the character set for MIME conversions 777 ** D -- the directory to run in 778 ** E -- the eol string 779 ** F -- the flags associated with the mailer 780 ** L -- the maximum line length 781 ** M -- the maximum message size 782 ** N -- the niceness at which to run 783 ** P -- the path to the mailer 784 ** R -- the recipient rewriting set 785 ** S -- the sender rewriting set 786 ** T -- the mailer type (for DSNs) 787 ** U -- the uid to run as 788 ** The first word is the canonical name of the mailer. 789 ** 790 ** Returns: 791 ** none. 792 ** 793 ** Side Effects: 794 ** enters the mailer into the mailer table. 795 */ 796 797 makemailer(line) 798 char *line; 799 { 800 register char *p; 801 register struct mailer *m; 802 register STAB *s; 803 int i; 804 char fcode; 805 auto char *endp; 806 extern int NextMailer; 807 extern char **makeargv(); 808 extern char *munchstring(); 809 810 /* allocate a mailer and set up defaults */ 811 m = (struct mailer *) xalloc(sizeof *m); 812 bzero((char *) m, sizeof *m); 813 m->m_eol = "\n"; 814 m->m_uid = m->m_gid = 0; 815 816 /* collect the mailer name */ 817 for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 818 continue; 819 if (*p != '\0') 820 *p++ = '\0'; 821 m->m_name = newstr(line); 822 823 /* now scan through and assign info from the fields */ 824 while (*p != '\0') 825 { 826 auto char *delimptr; 827 828 while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 829 p++; 830 831 /* p now points to field code */ 832 fcode = *p; 833 while (*p != '\0' && *p != '=' && *p != ',') 834 p++; 835 if (*p++ != '=') 836 { 837 syserr("mailer %s: `=' expected", m->m_name); 838 return; 839 } 840 while (isascii(*p) && isspace(*p)) 841 p++; 842 843 /* p now points to the field body */ 844 p = munchstring(p, &delimptr); 845 846 /* install the field into the mailer struct */ 847 switch (fcode) 848 { 849 case 'P': /* pathname */ 850 m->m_mailer = newstr(p); 851 break; 852 853 case 'F': /* flags */ 854 for (; *p != '\0'; p++) 855 if (!(isascii(*p) && isspace(*p))) 856 setbitn(*p, m->m_flags); 857 break; 858 859 case 'S': /* sender rewriting ruleset */ 860 case 'R': /* recipient rewriting ruleset */ 861 i = strtol(p, &endp, 10); 862 if (i < 0 || i >= MAXRWSETS) 863 { 864 syserr("invalid rewrite set, %d max", MAXRWSETS); 865 return; 866 } 867 if (fcode == 'S') 868 m->m_sh_rwset = m->m_se_rwset = i; 869 else 870 m->m_rh_rwset = m->m_re_rwset = i; 871 872 p = endp; 873 if (*p++ == '/') 874 { 875 i = strtol(p, NULL, 10); 876 if (i < 0 || i >= MAXRWSETS) 877 { 878 syserr("invalid rewrite set, %d max", 879 MAXRWSETS); 880 return; 881 } 882 if (fcode == 'S') 883 m->m_sh_rwset = i; 884 else 885 m->m_rh_rwset = i; 886 } 887 break; 888 889 case 'E': /* end of line string */ 890 m->m_eol = newstr(p); 891 break; 892 893 case 'A': /* argument vector */ 894 m->m_argv = makeargv(p); 895 break; 896 897 case 'M': /* maximum message size */ 898 m->m_maxsize = atol(p); 899 break; 900 901 case 'L': /* maximum line length */ 902 m->m_linelimit = atoi(p); 903 break; 904 905 case 'N': /* run niceness */ 906 m->m_nice = atoi(p); 907 break; 908 909 case 'D': /* working directory */ 910 m->m_execdir = newstr(p); 911 break; 912 913 case 'C': /* default charset */ 914 m->m_defcharset = newstr(p); 915 break; 916 917 case 'T': /* MTA-Name/Address/Diagnostic types */ 918 m->m_mtatype = newstr(p); 919 p = strchr(m->m_mtatype, '/'); 920 if (p != NULL) 921 { 922 *p++ = '\0'; 923 if (*p == '\0') 924 p = NULL; 925 } 926 if (p == NULL) 927 m->m_addrtype = m->m_mtatype; 928 else 929 { 930 m->m_addrtype = p; 931 p = strchr(p, '/'); 932 } 933 if (p != NULL) 934 { 935 *p++ = '\0'; 936 if (*p == '\0') 937 p = NULL; 938 } 939 if (p == NULL) 940 m->m_diagtype = m->m_mtatype; 941 else 942 m->m_diagtype = p; 943 break; 944 945 case 'U': /* user id */ 946 if (isascii(*p) && !isdigit(*p)) 947 { 948 char *q = p; 949 struct passwd *pw; 950 951 while (isascii(*p) && isalnum(*p)) 952 p++; 953 while (isascii(*p) && isspace(*p)) 954 *p++ = '\0'; 955 if (*p != '\0') 956 *p++ = '\0'; 957 pw = sm_getpwnam(q); 958 if (pw == NULL) 959 syserr("readcf: mailer U= flag: unknown user %s", q); 960 else 961 { 962 m->m_uid = pw->pw_uid; 963 m->m_gid = pw->pw_gid; 964 } 965 } 966 else 967 { 968 auto char *q; 969 970 m->m_uid = strtol(p, &q, 0); 971 p = q; 972 } 973 while (isascii(*p) && isspace(*p)) 974 p++; 975 if (*p == '\0') 976 break; 977 if (isascii(*p) && !isdigit(*p)) 978 { 979 char *q = p; 980 struct group *gr; 981 982 while (isascii(*p) && isalnum(*p)) 983 p++; 984 *p++ = '\0'; 985 gr = getgrnam(q); 986 if (gr == NULL) 987 syserr("readcf: mailer U= flag: unknown group %s", q); 988 else 989 m->m_gid = gr->gr_gid; 990 } 991 else 992 { 993 m->m_gid = strtol(p, NULL, 0); 994 } 995 break; 996 } 997 998 p = delimptr; 999 } 1000 1001 /* do some rationality checking */ 1002 if (m->m_argv == NULL) 1003 { 1004 syserr("M%s: A= argument required", m->m_name); 1005 return; 1006 } 1007 if (m->m_mailer == NULL) 1008 { 1009 syserr("M%s: P= argument required", m->m_name); 1010 return; 1011 } 1012 1013 if (NextMailer >= MAXMAILERS) 1014 { 1015 syserr("too many mailers defined (%d max)", MAXMAILERS); 1016 return; 1017 } 1018 1019 /* do some heuristic cleanup for back compatibility */ 1020 if (bitnset(M_LIMITS, m->m_flags)) 1021 { 1022 if (m->m_linelimit == 0) 1023 m->m_linelimit = SMTPLINELIM; 1024 if (ConfigLevel < 2) 1025 setbitn(M_7BITS, m->m_flags); 1026 } 1027 1028 if (ConfigLevel < 6 && 1029 (strcmp(m->m_mailer, "[IPC]") == 0 || 1030 strcmp(m->m_mailer, "[TCP]") == 0)) 1031 { 1032 if (m->m_mtatype == NULL) 1033 m->m_mtatype = "dns"; 1034 if (m->m_addrtype == NULL) 1035 m->m_addrtype = "rfc822"; 1036 if (m->m_diagtype == NULL) 1037 m->m_diagtype = "smtp"; 1038 } 1039 1040 /* enter the mailer into the symbol table */ 1041 s = stab(m->m_name, ST_MAILER, ST_ENTER); 1042 if (s->s_mailer != NULL) 1043 { 1044 i = s->s_mailer->m_mno; 1045 free(s->s_mailer); 1046 } 1047 else 1048 { 1049 i = NextMailer++; 1050 } 1051 Mailer[i] = s->s_mailer = m; 1052 m->m_mno = i; 1053 } 1054 /* 1055 ** MUNCHSTRING -- translate a string into internal form. 1056 ** 1057 ** Parameters: 1058 ** p -- the string to munch. 1059 ** delimptr -- if non-NULL, set to the pointer of the 1060 ** field delimiter character. 1061 ** 1062 ** Returns: 1063 ** the munched string. 1064 */ 1065 1066 char * 1067 munchstring(p, delimptr) 1068 register char *p; 1069 char **delimptr; 1070 { 1071 register char *q; 1072 bool backslash = FALSE; 1073 bool quotemode = FALSE; 1074 static char buf[MAXLINE]; 1075 1076 for (q = buf; *p != '\0'; p++) 1077 { 1078 if (backslash) 1079 { 1080 /* everything is roughly literal */ 1081 backslash = FALSE; 1082 switch (*p) 1083 { 1084 case 'r': /* carriage return */ 1085 *q++ = '\r'; 1086 continue; 1087 1088 case 'n': /* newline */ 1089 *q++ = '\n'; 1090 continue; 1091 1092 case 'f': /* form feed */ 1093 *q++ = '\f'; 1094 continue; 1095 1096 case 'b': /* backspace */ 1097 *q++ = '\b'; 1098 continue; 1099 } 1100 *q++ = *p; 1101 } 1102 else 1103 { 1104 if (*p == '\\') 1105 backslash = TRUE; 1106 else if (*p == '"') 1107 quotemode = !quotemode; 1108 else if (quotemode || *p != ',') 1109 *q++ = *p; 1110 else 1111 break; 1112 } 1113 } 1114 1115 if (delimptr != NULL) 1116 *delimptr = p; 1117 *q++ = '\0'; 1118 return (buf); 1119 } 1120 /* 1121 ** MAKEARGV -- break up a string into words 1122 ** 1123 ** Parameters: 1124 ** p -- the string to break up. 1125 ** 1126 ** Returns: 1127 ** a char **argv (dynamically allocated) 1128 ** 1129 ** Side Effects: 1130 ** munges p. 1131 */ 1132 1133 char ** 1134 makeargv(p) 1135 register char *p; 1136 { 1137 char *q; 1138 int i; 1139 char **avp; 1140 char *argv[MAXPV + 1]; 1141 1142 /* take apart the words */ 1143 i = 0; 1144 while (*p != '\0' && i < MAXPV) 1145 { 1146 q = p; 1147 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1148 p++; 1149 while (isascii(*p) && isspace(*p)) 1150 *p++ = '\0'; 1151 argv[i++] = newstr(q); 1152 } 1153 argv[i++] = NULL; 1154 1155 /* now make a copy of the argv */ 1156 avp = (char **) xalloc(sizeof *avp * i); 1157 bcopy((char *) argv, (char *) avp, sizeof *avp * i); 1158 1159 return (avp); 1160 } 1161 /* 1162 ** PRINTRULES -- print rewrite rules (for debugging) 1163 ** 1164 ** Parameters: 1165 ** none. 1166 ** 1167 ** Returns: 1168 ** none. 1169 ** 1170 ** Side Effects: 1171 ** prints rewrite rules. 1172 */ 1173 1174 printrules() 1175 { 1176 register struct rewrite *rwp; 1177 register int ruleset; 1178 1179 for (ruleset = 0; ruleset < 10; ruleset++) 1180 { 1181 if (RewriteRules[ruleset] == NULL) 1182 continue; 1183 printf("\n----Rule Set %d:", ruleset); 1184 1185 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 1186 { 1187 printf("\nLHS:"); 1188 printav(rwp->r_lhs); 1189 printf("RHS:"); 1190 printav(rwp->r_rhs); 1191 } 1192 } 1193 } 1194 /* 1195 ** PRINTMAILER -- print mailer structure (for debugging) 1196 ** 1197 ** Parameters: 1198 ** m -- the mailer to print 1199 ** 1200 ** Returns: 1201 ** none. 1202 */ 1203 1204 printmailer(m) 1205 register MAILER *m; 1206 { 1207 int j; 1208 1209 printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 1210 m->m_mno, m->m_name, 1211 m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 1212 m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 1213 m->m_uid, m->m_gid); 1214 for (j = '\0'; j <= '\177'; j++) 1215 if (bitnset(j, m->m_flags)) 1216 (void) putchar(j); 1217 printf(" L=%d E=", m->m_linelimit); 1218 xputs(m->m_eol); 1219 if (m->m_defcharset != NULL) 1220 printf(" C=%s", m->m_defcharset); 1221 printf(" T=%s/%s/%s", 1222 m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 1223 m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 1224 m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 1225 if (m->m_argv != NULL) 1226 { 1227 char **a = m->m_argv; 1228 1229 printf(" A="); 1230 while (*a != NULL) 1231 { 1232 if (a != m->m_argv) 1233 printf(" "); 1234 xputs(*a++); 1235 } 1236 } 1237 printf("\n"); 1238 } 1239 /* 1240 ** SETOPTION -- set global processing option 1241 ** 1242 ** Parameters: 1243 ** opt -- option name. 1244 ** val -- option value (as a text string). 1245 ** safe -- set if this came from a configuration file. 1246 ** Some options (if set from the command line) will 1247 ** reset the user id to avoid security problems. 1248 ** sticky -- if set, don't let other setoptions override 1249 ** this value. 1250 ** e -- the main envelope. 1251 ** 1252 ** Returns: 1253 ** none. 1254 ** 1255 ** Side Effects: 1256 ** Sets options as implied by the arguments. 1257 */ 1258 1259 static BITMAP StickyOpt; /* set if option is stuck */ 1260 1261 1262 #if NAMED_BIND 1263 1264 struct resolverflags 1265 { 1266 char *rf_name; /* name of the flag */ 1267 long rf_bits; /* bits to set/clear */ 1268 } ResolverFlags[] = 1269 { 1270 "debug", RES_DEBUG, 1271 "aaonly", RES_AAONLY, 1272 "usevc", RES_USEVC, 1273 "primary", RES_PRIMARY, 1274 "igntc", RES_IGNTC, 1275 "recurse", RES_RECURSE, 1276 "defnames", RES_DEFNAMES, 1277 "stayopen", RES_STAYOPEN, 1278 "dnsrch", RES_DNSRCH, 1279 "true", 0, /* to avoid error on old syntax */ 1280 NULL, 0 1281 }; 1282 1283 #endif 1284 1285 struct optioninfo 1286 { 1287 char *o_name; /* long name of option */ 1288 u_char o_code; /* short name of option */ 1289 bool o_safe; /* safe for random people to use */ 1290 } OptionTab[] = 1291 { 1292 "SevenBitInput", '7', TRUE, 1293 #if MIME8TO7 1294 "EightBitMode", '8', TRUE, 1295 #endif 1296 "AliasFile", 'A', FALSE, 1297 "AliasWait", 'a', FALSE, 1298 "BlankSub", 'B', FALSE, 1299 "MinFreeBlocks", 'b', TRUE, 1300 "CheckpointInterval", 'C', TRUE, 1301 "HoldExpensive", 'c', FALSE, 1302 "AutoRebuildAliases", 'D', FALSE, 1303 "DeliveryMode", 'd', TRUE, 1304 "ErrorHeader", 'E', FALSE, 1305 "ErrorMode", 'e', TRUE, 1306 "TempFileMode", 'F', FALSE, 1307 "SaveFromLine", 'f', FALSE, 1308 "MatchGECOS", 'G', FALSE, 1309 "HelpFile", 'H', FALSE, 1310 "MaxHopCount", 'h', FALSE, 1311 "ResolverOptions", 'I', FALSE, 1312 "IgnoreDots", 'i', TRUE, 1313 "ForwardPath", 'J', FALSE, 1314 "SendMimeErrors", 'j', TRUE, 1315 "ConnectionCacheSize", 'k', FALSE, 1316 "ConnectionCacheTimeout", 'K', FALSE, 1317 "UseErrorsTo", 'l', FALSE, 1318 "LogLevel", 'L', FALSE, 1319 "MeToo", 'm', TRUE, 1320 "CheckAliases", 'n', FALSE, 1321 "OldStyleHeaders", 'o', TRUE, 1322 "DaemonPortOptions", 'O', FALSE, 1323 "PrivacyOptions", 'p', TRUE, 1324 "PostmasterCopy", 'P', FALSE, 1325 "QueueFactor", 'q', FALSE, 1326 "QueueDirectory", 'Q', FALSE, 1327 "DontPruneRoutes", 'R', FALSE, 1328 "Timeout", 'r', TRUE, 1329 "StatusFile", 'S', FALSE, 1330 "SuperSafe", 's', TRUE, 1331 "QueueTimeout", 'T', FALSE, 1332 "TimeZoneSpec", 't', FALSE, 1333 "UserDatabaseSpec", 'U', FALSE, 1334 "DefaultUser", 'u', FALSE, 1335 "FallbackMXhost", 'V', FALSE, 1336 "Verbose", 'v', TRUE, 1337 "TryNullMXList", 'w', TRUE, 1338 "QueueLA", 'x', FALSE, 1339 "RefuseLA", 'X', FALSE, 1340 "RecipientFactor", 'y', FALSE, 1341 "ForkEachJob", 'Y', FALSE, 1342 "ClassFactor", 'z', FALSE, 1343 "RetryFactor", 'Z', FALSE, 1344 #define O_QUEUESORTORD 0x81 1345 "QueueSortOrder", O_QUEUESORTORD, TRUE, 1346 #define O_HOSTSFILE 0x82 1347 "HostsFile", O_HOSTSFILE, FALSE, 1348 #define O_MQA 0x83 1349 "MinQueueAge", O_MQA, TRUE, 1350 #define O_MHSA 0x84 1351 /* 1352 "MaxHostStatAge", O_MHSA, TRUE, 1353 */ 1354 #define O_DEFCHARSET 0x85 1355 "DefaultCharSet", O_DEFCHARSET, TRUE, 1356 #define O_SSFILE 0x86 1357 "ServiceSwitchFile", O_SSFILE, FALSE, 1358 #define O_DIALDELAY 0x87 1359 "DialDelay", O_DIALDELAY, TRUE, 1360 #define O_NORCPTACTION 0x88 1361 "NoRecipientAction", O_NORCPTACTION, TRUE, 1362 #define O_SAFEFILEENV 0x89 1363 "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 1364 #define O_MAXMSGSIZE 0x8a 1365 "MaxMessageSize", O_MAXMSGSIZE, FALSE, 1366 #define O_COLONOKINADDR 0x8b 1367 "ColonOkInAddr", O_COLONOKINADDR, TRUE, 1368 #define O_MAXQUEUERUN 0x8c 1369 "MaxQueueRunSize", O_MAXQUEUERUN, TRUE, 1370 1371 NULL, '\0', FALSE, 1372 }; 1373 1374 1375 1376 setoption(opt, val, safe, sticky, e) 1377 u_char opt; 1378 char *val; 1379 bool safe; 1380 bool sticky; 1381 register ENVELOPE *e; 1382 { 1383 register char *p; 1384 register struct optioninfo *o; 1385 char *subopt; 1386 extern bool atobool(); 1387 extern time_t convtime(); 1388 extern int QueueLA; 1389 extern int RefuseLA; 1390 extern bool Warn_Q_option; 1391 1392 errno = 0; 1393 if (opt == ' ') 1394 { 1395 /* full word options */ 1396 struct optioninfo *sel; 1397 1398 p = strchr(val, '='); 1399 if (p == NULL) 1400 p = &val[strlen(val)]; 1401 while (*--p == ' ') 1402 continue; 1403 while (*++p == ' ') 1404 *p = '\0'; 1405 if (p == val) 1406 { 1407 syserr("readcf: null option name"); 1408 return; 1409 } 1410 if (*p == '=') 1411 *p++ = '\0'; 1412 while (*p == ' ') 1413 p++; 1414 subopt = strchr(val, '.'); 1415 if (subopt != NULL) 1416 *subopt++ = '\0'; 1417 sel = NULL; 1418 for (o = OptionTab; o->o_name != NULL; o++) 1419 { 1420 if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1421 continue; 1422 if (strlen(o->o_name) == strlen(val)) 1423 { 1424 /* completely specified -- this must be it */ 1425 sel = NULL; 1426 break; 1427 } 1428 if (sel != NULL) 1429 break; 1430 sel = o; 1431 } 1432 if (sel != NULL && o->o_name == NULL) 1433 o = sel; 1434 else if (o->o_name == NULL) 1435 { 1436 syserr("readcf: unknown option name %s", val); 1437 return; 1438 } 1439 else if (sel != NULL) 1440 { 1441 syserr("readcf: ambiguous option name %s (matches %s and %s)", 1442 val, sel->o_name, o->o_name); 1443 return; 1444 } 1445 if (strlen(val) != strlen(o->o_name)) 1446 { 1447 bool oldVerbose = Verbose; 1448 1449 Verbose = TRUE; 1450 message("Option %s used as abbreviation for %s", 1451 val, o->o_name); 1452 Verbose = oldVerbose; 1453 } 1454 opt = o->o_code; 1455 val = p; 1456 } 1457 else 1458 { 1459 for (o = OptionTab; o->o_name != NULL; o++) 1460 { 1461 if (o->o_code == opt) 1462 break; 1463 } 1464 subopt = NULL; 1465 } 1466 1467 if (tTd(37, 1)) 1468 { 1469 printf(isascii(opt) && isprint(opt) ? 1470 "setoption %s (%c).%s=%s" : 1471 "setoption %s (0x%x).%s=%s", 1472 o->o_name == NULL ? "<unknown>" : o->o_name, 1473 opt, 1474 subopt == NULL ? "" : subopt, 1475 val); 1476 } 1477 1478 /* 1479 ** See if this option is preset for us. 1480 */ 1481 1482 if (!sticky && bitnset(opt, StickyOpt)) 1483 { 1484 if (tTd(37, 1)) 1485 printf(" (ignored)\n"); 1486 return; 1487 } 1488 1489 /* 1490 ** Check to see if this option can be specified by this user. 1491 */ 1492 1493 if (!safe && RealUid == 0) 1494 safe = TRUE; 1495 if (!safe && !o->o_safe) 1496 { 1497 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 1498 { 1499 if (tTd(37, 1)) 1500 printf(" (unsafe)"); 1501 if (RealUid != geteuid()) 1502 { 1503 if (tTd(37, 1)) 1504 printf("(Resetting uid)"); 1505 (void) setgid(RealGid); 1506 (void) setuid(RealUid); 1507 } 1508 } 1509 } 1510 if (tTd(37, 1)) 1511 printf("\n"); 1512 1513 switch (opt & 0xff) 1514 { 1515 case '7': /* force seven-bit input */ 1516 SevenBitInput = atobool(val); 1517 break; 1518 1519 #if MIME8TO7 1520 case '8': /* handling of 8-bit input */ 1521 switch (*val) 1522 { 1523 case 'm': /* convert 8-bit, convert MIME */ 1524 MimeMode = MM_CVTMIME|MM_MIME8BIT; 1525 break; 1526 1527 case 'p': /* pass 8 bit, convert MIME */ 1528 MimeMode = MM_CVTMIME|MM_PASS8BIT; 1529 break; 1530 1531 case 's': /* strict adherence */ 1532 MimeMode = MM_CVTMIME; 1533 break; 1534 1535 #if 0 1536 case 'r': /* reject 8-bit, don't convert MIME */ 1537 MimeMode = 0; 1538 break; 1539 1540 case 'j': /* "just send 8" */ 1541 MimeMode = MM_PASS8BIT; 1542 break; 1543 1544 case 'a': /* encode 8 bit if available */ 1545 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1546 break; 1547 1548 case 'c': /* convert 8 bit to MIME, never 7 bit */ 1549 MimeMode = MM_MIME8BIT; 1550 break; 1551 #endif 1552 1553 default: 1554 syserr("Unknown 8-bit mode %c", *val); 1555 exit(EX_USAGE); 1556 } 1557 break; 1558 #endif 1559 1560 case 'A': /* set default alias file */ 1561 if (val[0] == '\0') 1562 setalias("aliases"); 1563 else 1564 setalias(val); 1565 break; 1566 1567 case 'a': /* look N minutes for "@:@" in alias file */ 1568 if (val[0] == '\0') 1569 SafeAlias = 5 * 60; /* five minutes */ 1570 else 1571 SafeAlias = convtime(val, 'm'); 1572 break; 1573 1574 case 'B': /* substitution for blank character */ 1575 SpaceSub = val[0]; 1576 if (SpaceSub == '\0') 1577 SpaceSub = ' '; 1578 break; 1579 1580 case 'b': /* min blocks free on queue fs/max msg size */ 1581 p = strchr(val, '/'); 1582 if (p != NULL) 1583 { 1584 *p++ = '\0'; 1585 MaxMessageSize = atol(p); 1586 } 1587 MinBlocksFree = atol(val); 1588 break; 1589 1590 case 'c': /* don't connect to "expensive" mailers */ 1591 NoConnect = atobool(val); 1592 break; 1593 1594 case 'C': /* checkpoint every N addresses */ 1595 CheckpointInterval = atoi(val); 1596 break; 1597 1598 case 'd': /* delivery mode */ 1599 switch (*val) 1600 { 1601 case '\0': 1602 e->e_sendmode = SM_DELIVER; 1603 break; 1604 1605 case SM_QUEUE: /* queue only */ 1606 #ifndef QUEUE 1607 syserr("need QUEUE to set -odqueue"); 1608 #endif /* QUEUE */ 1609 /* fall through..... */ 1610 1611 case SM_DELIVER: /* do everything */ 1612 case SM_FORK: /* fork after verification */ 1613 e->e_sendmode = *val; 1614 break; 1615 1616 default: 1617 syserr("Unknown delivery mode %c", *val); 1618 exit(EX_USAGE); 1619 } 1620 break; 1621 1622 case 'D': /* rebuild alias database as needed */ 1623 AutoRebuild = atobool(val); 1624 break; 1625 1626 case 'E': /* error message header/header file */ 1627 if (*val != '\0') 1628 ErrMsgFile = newstr(val); 1629 break; 1630 1631 case 'e': /* set error processing mode */ 1632 switch (*val) 1633 { 1634 case EM_QUIET: /* be silent about it */ 1635 case EM_MAIL: /* mail back */ 1636 case EM_BERKNET: /* do berknet error processing */ 1637 case EM_WRITE: /* write back (or mail) */ 1638 case EM_PRINT: /* print errors normally (default) */ 1639 e->e_errormode = *val; 1640 break; 1641 } 1642 break; 1643 1644 case 'F': /* file mode */ 1645 FileMode = atooct(val) & 0777; 1646 break; 1647 1648 case 'f': /* save Unix-style From lines on front */ 1649 SaveFrom = atobool(val); 1650 break; 1651 1652 case 'G': /* match recipients against GECOS field */ 1653 MatchGecos = atobool(val); 1654 break; 1655 1656 case 'g': /* default gid */ 1657 g_opt: 1658 if (isascii(*val) && isdigit(*val)) 1659 DefGid = atoi(val); 1660 else 1661 { 1662 register struct group *gr; 1663 1664 DefGid = -1; 1665 gr = getgrnam(val); 1666 if (gr == NULL) 1667 syserr("readcf: option %c: unknown group %s", 1668 opt, val); 1669 else 1670 DefGid = gr->gr_gid; 1671 } 1672 break; 1673 1674 case 'H': /* help file */ 1675 if (val[0] == '\0') 1676 HelpFile = "sendmail.hf"; 1677 else 1678 HelpFile = newstr(val); 1679 break; 1680 1681 case 'h': /* maximum hop count */ 1682 MaxHopCount = atoi(val); 1683 break; 1684 1685 case 'I': /* use internet domain name server */ 1686 #if NAMED_BIND 1687 for (p = val; *p != 0; ) 1688 { 1689 bool clearmode; 1690 char *q; 1691 struct resolverflags *rfp; 1692 1693 while (*p == ' ') 1694 p++; 1695 if (*p == '\0') 1696 break; 1697 clearmode = FALSE; 1698 if (*p == '-') 1699 clearmode = TRUE; 1700 else if (*p != '+') 1701 p--; 1702 p++; 1703 q = p; 1704 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1705 p++; 1706 if (*p != '\0') 1707 *p++ = '\0'; 1708 if (strcasecmp(q, "HasWildcardMX") == 0) 1709 { 1710 NoMXforCanon = !clearmode; 1711 continue; 1712 } 1713 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 1714 { 1715 if (strcasecmp(q, rfp->rf_name) == 0) 1716 break; 1717 } 1718 if (rfp->rf_name == NULL) 1719 syserr("readcf: I option value %s unrecognized", q); 1720 else if (clearmode) 1721 _res.options &= ~rfp->rf_bits; 1722 else 1723 _res.options |= rfp->rf_bits; 1724 } 1725 if (tTd(8, 2)) 1726 printf("_res.options = %x, HasWildcardMX = %d\n", 1727 _res.options, !NoMXforCanon); 1728 #else 1729 usrerr("name server (I option) specified but BIND not compiled in"); 1730 #endif 1731 break; 1732 1733 case 'i': /* ignore dot lines in message */ 1734 IgnrDot = atobool(val); 1735 break; 1736 1737 case 'j': /* send errors in MIME (RFC 1341) format */ 1738 SendMIMEErrors = atobool(val); 1739 break; 1740 1741 case 'J': /* .forward search path */ 1742 ForwardPath = newstr(val); 1743 break; 1744 1745 case 'k': /* connection cache size */ 1746 MaxMciCache = atoi(val); 1747 if (MaxMciCache < 0) 1748 MaxMciCache = 0; 1749 break; 1750 1751 case 'K': /* connection cache timeout */ 1752 MciCacheTimeout = convtime(val, 'm'); 1753 break; 1754 1755 case 'l': /* use Errors-To: header */ 1756 UseErrorsTo = atobool(val); 1757 break; 1758 1759 case 'L': /* log level */ 1760 if (safe || LogLevel < atoi(val)) 1761 LogLevel = atoi(val); 1762 break; 1763 1764 case 'M': /* define macro */ 1765 p = newstr(&val[1]); 1766 if (!safe) 1767 cleanstrcpy(p, p, MAXNAME); 1768 define(val[0], p, CurEnv); 1769 sticky = FALSE; 1770 break; 1771 1772 case 'm': /* send to me too */ 1773 MeToo = atobool(val); 1774 break; 1775 1776 case 'n': /* validate RHS in newaliases */ 1777 CheckAliases = atobool(val); 1778 break; 1779 1780 /* 'N' available -- was "net name" */ 1781 1782 case 'O': /* daemon options */ 1783 setdaemonoptions(val); 1784 break; 1785 1786 case 'o': /* assume old style headers */ 1787 if (atobool(val)) 1788 CurEnv->e_flags |= EF_OLDSTYLE; 1789 else 1790 CurEnv->e_flags &= ~EF_OLDSTYLE; 1791 break; 1792 1793 case 'p': /* select privacy level */ 1794 p = val; 1795 for (;;) 1796 { 1797 register struct prival *pv; 1798 extern struct prival PrivacyValues[]; 1799 1800 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 1801 p++; 1802 if (*p == '\0') 1803 break; 1804 val = p; 1805 while (isascii(*p) && isalnum(*p)) 1806 p++; 1807 if (*p != '\0') 1808 *p++ = '\0'; 1809 1810 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 1811 { 1812 if (strcasecmp(val, pv->pv_name) == 0) 1813 break; 1814 } 1815 if (pv->pv_name == NULL) 1816 syserr("readcf: Op line: %s unrecognized", val); 1817 PrivacyFlags |= pv->pv_flag; 1818 } 1819 sticky = FALSE; 1820 break; 1821 1822 case 'P': /* postmaster copy address for returned mail */ 1823 PostMasterCopy = newstr(val); 1824 break; 1825 1826 case 'q': /* slope of queue only function */ 1827 QueueFactor = atoi(val); 1828 break; 1829 1830 case 'Q': /* queue directory */ 1831 if (val[0] == '\0') 1832 QueueDir = "mqueue"; 1833 else 1834 QueueDir = newstr(val); 1835 if (RealUid != 0 && !safe) 1836 Warn_Q_option = TRUE; 1837 break; 1838 1839 case 'R': /* don't prune routes */ 1840 DontPruneRoutes = atobool(val); 1841 break; 1842 1843 case 'r': /* read timeout */ 1844 if (subopt == NULL) 1845 inittimeouts(val); 1846 else 1847 settimeout(subopt, val); 1848 break; 1849 1850 case 'S': /* status file */ 1851 if (val[0] == '\0') 1852 StatFile = "sendmail.st"; 1853 else 1854 StatFile = newstr(val); 1855 break; 1856 1857 case 's': /* be super safe, even if expensive */ 1858 SuperSafe = atobool(val); 1859 break; 1860 1861 case 'T': /* queue timeout */ 1862 p = strchr(val, '/'); 1863 if (p != NULL) 1864 { 1865 *p++ = '\0'; 1866 settimeout("queuewarn", p); 1867 } 1868 settimeout("queuereturn", val); 1869 break; 1870 1871 case 't': /* time zone name */ 1872 TimeZoneSpec = newstr(val); 1873 break; 1874 1875 case 'U': /* location of user database */ 1876 UdbSpec = newstr(val); 1877 break; 1878 1879 case 'u': /* set default uid */ 1880 for (p = val; *p != '\0'; p++) 1881 { 1882 if (*p == '.' || *p == '/' || *p == ':') 1883 { 1884 *p++ = '\0'; 1885 break; 1886 } 1887 } 1888 if (isascii(*val) && isdigit(*val)) 1889 DefUid = atoi(val); 1890 else 1891 { 1892 register struct passwd *pw; 1893 1894 DefUid = -1; 1895 pw = sm_getpwnam(val); 1896 if (pw == NULL) 1897 syserr("readcf: option u: unknown user %s", val); 1898 else 1899 { 1900 DefUid = pw->pw_uid; 1901 DefGid = pw->pw_gid; 1902 } 1903 } 1904 setdefuser(); 1905 1906 /* handle the group if it is there */ 1907 if (*p == '\0') 1908 break; 1909 val = p; 1910 goto g_opt; 1911 1912 case 'V': /* fallback MX host */ 1913 FallBackMX = newstr(val); 1914 break; 1915 1916 case 'v': /* run in verbose mode */ 1917 Verbose = atobool(val); 1918 break; 1919 1920 case 'w': /* if we are best MX, try host directly */ 1921 TryNullMXList = atobool(val); 1922 break; 1923 1924 /* 'W' available -- was wizard password */ 1925 1926 case 'x': /* load avg at which to auto-queue msgs */ 1927 QueueLA = atoi(val); 1928 break; 1929 1930 case 'X': /* load avg at which to auto-reject connections */ 1931 RefuseLA = atoi(val); 1932 break; 1933 1934 case 'y': /* work recipient factor */ 1935 WkRecipFact = atoi(val); 1936 break; 1937 1938 case 'Y': /* fork jobs during queue runs */ 1939 ForkQueueRuns = atobool(val); 1940 break; 1941 1942 case 'z': /* work message class factor */ 1943 WkClassFact = atoi(val); 1944 break; 1945 1946 case 'Z': /* work time factor */ 1947 WkTimeFact = atoi(val); 1948 break; 1949 1950 case O_QUEUESORTORD: /* queue sorting order */ 1951 switch (*val) 1952 { 1953 case 'h': /* Host first */ 1954 case 'H': 1955 QueueSortOrder = QS_BYHOST; 1956 break; 1957 1958 case 'p': /* Priority order */ 1959 case 'P': 1960 QueueSortOrder = QS_BYPRIORITY; 1961 break; 1962 1963 default: 1964 syserr("Invalid queue sort order \"%s\"", val); 1965 } 1966 break; 1967 1968 case O_HOSTSFILE: /* pathname of /etc/hosts file */ 1969 HostsFile = newstr(val); 1970 break; 1971 1972 case O_MQA: /* minimum queue age between deliveries */ 1973 MinQueueAge = convtime(val, 'm'); 1974 break; 1975 1976 case O_MHSA: /* maximum age of cached host status */ 1977 MaxHostStatAge = convtime(val, 'm'); 1978 break; 1979 1980 case O_DEFCHARSET: /* default character set for mimefying */ 1981 DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 1982 break; 1983 1984 case O_SSFILE: /* service switch file */ 1985 ServiceSwitchFile = newstr(val); 1986 break; 1987 1988 case O_DIALDELAY: /* delay for dial-on-demand operation */ 1989 DialDelay = convtime(val, 's'); 1990 break; 1991 1992 case O_NORCPTACTION: /* what to do if no recipient */ 1993 if (strcasecmp(val, "none") == 0) 1994 NoRecipientAction = NRA_NO_ACTION; 1995 else if (strcasecmp(val, "add-to") == 0) 1996 NoRecipientAction = NRA_ADD_TO; 1997 else if (strcasecmp(val, "add-apparently-to") == 0) 1998 NoRecipientAction = NRA_ADD_APPARENTLY_TO; 1999 else if (strcasecmp(val, "add-bcc") == 0) 2000 NoRecipientAction = NRA_ADD_BCC; 2001 else if (strcasecmp(val, "add-to-undisclosed") == 0) 2002 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 2003 else 2004 syserr("Invalid NoRecipientAction: %s", val); 2005 2006 case O_SAFEFILEENV: /* chroot() environ for writing to files */ 2007 SafeFileEnv = newstr(val); 2008 break; 2009 2010 case O_MAXMSGSIZE: /* maximum message size */ 2011 MaxMessageSize = atol(p); 2012 break; 2013 2014 case O_COLONOKINADDR: /* old style handling of colon addresses */ 2015 ColonOkInAddr = atobool(p); 2016 break; 2017 2018 case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 2019 MaxQueueRun = atol(p); 2020 break; 2021 2022 default: 2023 if (tTd(37, 1)) 2024 { 2025 if (isascii(opt) && isprint(opt)) 2026 printf("Warning: option %c unknown\n", opt); 2027 else 2028 printf("Warning: option 0x%x unknown\n", opt); 2029 } 2030 break; 2031 } 2032 if (sticky) 2033 setbitn(opt, StickyOpt); 2034 return; 2035 } 2036 /* 2037 ** SETCLASS -- set a string into a class 2038 ** 2039 ** Parameters: 2040 ** class -- the class to put the string in. 2041 ** str -- the string to enter 2042 ** 2043 ** Returns: 2044 ** none. 2045 ** 2046 ** Side Effects: 2047 ** puts the word into the symbol table. 2048 */ 2049 2050 setclass(class, str) 2051 int class; 2052 char *str; 2053 { 2054 register STAB *s; 2055 2056 if (tTd(37, 8)) 2057 printf("setclass(%c, %s)\n", class, str); 2058 s = stab(str, ST_CLASS, ST_ENTER); 2059 setbitn(class, s->s_class); 2060 } 2061 /* 2062 ** MAKEMAPENTRY -- create a map entry 2063 ** 2064 ** Parameters: 2065 ** line -- the config file line 2066 ** 2067 ** Returns: 2068 ** TRUE if it successfully entered the map entry. 2069 ** FALSE otherwise (usually syntax error). 2070 ** 2071 ** Side Effects: 2072 ** Enters the map into the dictionary. 2073 */ 2074 2075 void 2076 makemapentry(line) 2077 char *line; 2078 { 2079 register char *p; 2080 char *mapname; 2081 char *classname; 2082 register STAB *s; 2083 STAB *class; 2084 2085 for (p = line; isascii(*p) && isspace(*p); p++) 2086 continue; 2087 if (!(isascii(*p) && isalnum(*p))) 2088 { 2089 syserr("readcf: config K line: no map name"); 2090 return; 2091 } 2092 2093 mapname = p; 2094 while ((isascii(*++p) && isalnum(*p)) || *p == '.') 2095 continue; 2096 if (*p != '\0') 2097 *p++ = '\0'; 2098 while (isascii(*p) && isspace(*p)) 2099 p++; 2100 if (!(isascii(*p) && isalnum(*p))) 2101 { 2102 syserr("readcf: config K line, map %s: no map class", mapname); 2103 return; 2104 } 2105 classname = p; 2106 while (isascii(*++p) && isalnum(*p)) 2107 continue; 2108 if (*p != '\0') 2109 *p++ = '\0'; 2110 while (isascii(*p) && isspace(*p)) 2111 p++; 2112 2113 /* look up the class */ 2114 class = stab(classname, ST_MAPCLASS, ST_FIND); 2115 if (class == NULL) 2116 { 2117 syserr("readcf: map %s: class %s not available", mapname, classname); 2118 return; 2119 } 2120 2121 /* enter the map */ 2122 s = stab(mapname, ST_MAP, ST_ENTER); 2123 s->s_map.map_class = &class->s_mapclass; 2124 s->s_map.map_mname = newstr(mapname); 2125 2126 if (class->s_mapclass.map_parse(&s->s_map, p)) 2127 s->s_map.map_mflags |= MF_VALID; 2128 2129 if (tTd(37, 5)) 2130 { 2131 printf("map %s, class %s, flags %x, file %s,\n", 2132 s->s_map.map_mname, s->s_map.map_class->map_cname, 2133 s->s_map.map_mflags, 2134 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 2135 printf("\tapp %s, domain %s, rebuild %s\n", 2136 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 2137 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 2138 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 2139 } 2140 } 2141 /* 2142 ** INITTIMEOUTS -- parse and set timeout values 2143 ** 2144 ** Parameters: 2145 ** val -- a pointer to the values. If NULL, do initial 2146 ** settings. 2147 ** 2148 ** Returns: 2149 ** none. 2150 ** 2151 ** Side Effects: 2152 ** Initializes the TimeOuts structure 2153 */ 2154 2155 #define SECONDS 2156 #define MINUTES * 60 2157 #define HOUR * 3600 2158 2159 inittimeouts(val) 2160 register char *val; 2161 { 2162 register char *p; 2163 extern time_t convtime(); 2164 2165 if (val == NULL) 2166 { 2167 TimeOuts.to_initial = (time_t) 5 MINUTES; 2168 TimeOuts.to_helo = (time_t) 5 MINUTES; 2169 TimeOuts.to_mail = (time_t) 10 MINUTES; 2170 TimeOuts.to_rcpt = (time_t) 1 HOUR; 2171 TimeOuts.to_datainit = (time_t) 5 MINUTES; 2172 TimeOuts.to_datablock = (time_t) 1 HOUR; 2173 TimeOuts.to_datafinal = (time_t) 1 HOUR; 2174 TimeOuts.to_rset = (time_t) 5 MINUTES; 2175 TimeOuts.to_quit = (time_t) 2 MINUTES; 2176 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 2177 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2178 #if IDENTPROTO 2179 TimeOuts.to_ident = (time_t) 30 SECONDS; 2180 #else 2181 TimeOuts.to_ident = (time_t) 0 SECONDS; 2182 #endif 2183 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 2184 return; 2185 } 2186 2187 for (;; val = p) 2188 { 2189 while (isascii(*val) && isspace(*val)) 2190 val++; 2191 if (*val == '\0') 2192 break; 2193 for (p = val; *p != '\0' && *p != ','; p++) 2194 continue; 2195 if (*p != '\0') 2196 *p++ = '\0'; 2197 2198 if (isascii(*val) && isdigit(*val)) 2199 { 2200 /* old syntax -- set everything */ 2201 TimeOuts.to_mail = convtime(val, 'm'); 2202 TimeOuts.to_rcpt = TimeOuts.to_mail; 2203 TimeOuts.to_datainit = TimeOuts.to_mail; 2204 TimeOuts.to_datablock = TimeOuts.to_mail; 2205 TimeOuts.to_datafinal = TimeOuts.to_mail; 2206 TimeOuts.to_nextcommand = TimeOuts.to_mail; 2207 continue; 2208 } 2209 else 2210 { 2211 register char *q = strchr(val, ':'); 2212 2213 if (q == NULL && (q = strchr(val, '=')) == NULL) 2214 { 2215 /* syntax error */ 2216 continue; 2217 } 2218 *q++ = '\0'; 2219 settimeout(val, q); 2220 } 2221 } 2222 } 2223 /* 2224 ** SETTIMEOUT -- set an individual timeout 2225 ** 2226 ** Parameters: 2227 ** name -- the name of the timeout. 2228 ** val -- the value of the timeout. 2229 ** 2230 ** Returns: 2231 ** none. 2232 */ 2233 2234 settimeout(name, val) 2235 char *name; 2236 char *val; 2237 { 2238 register char *p; 2239 time_t to; 2240 extern time_t convtime(); 2241 2242 to = convtime(val, 'm'); 2243 p = strchr(name, '.'); 2244 if (p != NULL) 2245 *p++ = '\0'; 2246 2247 if (strcasecmp(name, "initial") == 0) 2248 TimeOuts.to_initial = to; 2249 else if (strcasecmp(name, "mail") == 0) 2250 TimeOuts.to_mail = to; 2251 else if (strcasecmp(name, "rcpt") == 0) 2252 TimeOuts.to_rcpt = to; 2253 else if (strcasecmp(name, "datainit") == 0) 2254 TimeOuts.to_datainit = to; 2255 else if (strcasecmp(name, "datablock") == 0) 2256 TimeOuts.to_datablock = to; 2257 else if (strcasecmp(name, "datafinal") == 0) 2258 TimeOuts.to_datafinal = to; 2259 else if (strcasecmp(name, "command") == 0) 2260 TimeOuts.to_nextcommand = to; 2261 else if (strcasecmp(name, "rset") == 0) 2262 TimeOuts.to_rset = to; 2263 else if (strcasecmp(name, "helo") == 0) 2264 TimeOuts.to_helo = to; 2265 else if (strcasecmp(name, "quit") == 0) 2266 TimeOuts.to_quit = to; 2267 else if (strcasecmp(name, "misc") == 0) 2268 TimeOuts.to_miscshort = to; 2269 else if (strcasecmp(name, "ident") == 0) 2270 TimeOuts.to_ident = to; 2271 else if (strcasecmp(name, "fileopen") == 0) 2272 TimeOuts.to_fileopen = to; 2273 else if (strcasecmp(name, "queuewarn") == 0) 2274 { 2275 to = convtime(val, 'h'); 2276 if (p == NULL || strcmp(p, "*") == 0) 2277 { 2278 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2279 TimeOuts.to_q_warning[TOC_URGENT] = to; 2280 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2281 } 2282 else if (strcasecmp(p, "normal") == 0) 2283 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2284 else if (strcasecmp(p, "urgent") == 0) 2285 TimeOuts.to_q_warning[TOC_URGENT] = to; 2286 else if (strcasecmp(p, "non-urgent") == 0) 2287 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2288 else 2289 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2290 } 2291 else if (strcasecmp(name, "queuereturn") == 0) 2292 { 2293 to = convtime(val, 'd'); 2294 if (p == NULL || strcmp(p, "*") == 0) 2295 { 2296 TimeOuts.to_q_return[TOC_NORMAL] = to; 2297 TimeOuts.to_q_return[TOC_URGENT] = to; 2298 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2299 } 2300 else if (strcasecmp(p, "normal") == 0) 2301 TimeOuts.to_q_return[TOC_NORMAL] = to; 2302 else if (strcasecmp(p, "urgent") == 0) 2303 TimeOuts.to_q_return[TOC_URGENT] = to; 2304 else if (strcasecmp(p, "non-urgent") == 0) 2305 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2306 else 2307 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2308 } 2309 else 2310 syserr("settimeout: invalid timeout %s", name); 2311 } 2312