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.92 (Berkeley) 05/25/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 Type */ 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 1369 NULL, '\0', FALSE, 1370 }; 1371 1372 1373 1374 setoption(opt, val, safe, sticky, e) 1375 u_char opt; 1376 char *val; 1377 bool safe; 1378 bool sticky; 1379 register ENVELOPE *e; 1380 { 1381 register char *p; 1382 register struct optioninfo *o; 1383 char *subopt; 1384 extern bool atobool(); 1385 extern time_t convtime(); 1386 extern int QueueLA; 1387 extern int RefuseLA; 1388 extern bool Warn_Q_option; 1389 1390 errno = 0; 1391 if (opt == ' ') 1392 { 1393 /* full word options */ 1394 struct optioninfo *sel; 1395 1396 p = strchr(val, '='); 1397 if (p == NULL) 1398 p = &val[strlen(val)]; 1399 while (*--p == ' ') 1400 continue; 1401 while (*++p == ' ') 1402 *p = '\0'; 1403 if (p == val) 1404 { 1405 syserr("readcf: null option name"); 1406 return; 1407 } 1408 if (*p == '=') 1409 *p++ = '\0'; 1410 while (*p == ' ') 1411 p++; 1412 subopt = strchr(val, '.'); 1413 if (subopt != NULL) 1414 *subopt++ = '\0'; 1415 sel = NULL; 1416 for (o = OptionTab; o->o_name != NULL; o++) 1417 { 1418 if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1419 continue; 1420 if (strlen(o->o_name) == strlen(val)) 1421 { 1422 /* completely specified -- this must be it */ 1423 sel = NULL; 1424 break; 1425 } 1426 if (sel != NULL) 1427 break; 1428 sel = o; 1429 } 1430 if (sel != NULL && o->o_name == NULL) 1431 o = sel; 1432 else if (o->o_name == NULL) 1433 { 1434 syserr("readcf: unknown option name %s", val); 1435 return; 1436 } 1437 else if (sel != NULL) 1438 { 1439 syserr("readcf: ambiguous option name %s (matches %s and %s)", 1440 val, sel->o_name, o->o_name); 1441 return; 1442 } 1443 if (strlen(val) != strlen(o->o_name)) 1444 { 1445 bool oldVerbose = Verbose; 1446 1447 Verbose = TRUE; 1448 message("Option %s used as abbreviation for %s", 1449 val, o->o_name); 1450 Verbose = oldVerbose; 1451 } 1452 opt = o->o_code; 1453 val = p; 1454 } 1455 else 1456 { 1457 for (o = OptionTab; o->o_name != NULL; o++) 1458 { 1459 if (o->o_code == opt) 1460 break; 1461 } 1462 subopt = NULL; 1463 } 1464 1465 if (tTd(37, 1)) 1466 { 1467 printf(isascii(opt) && isprint(opt) ? 1468 "setoption %s (%c).%s=%s" : 1469 "setoption %s (0x%x).%s=%s", 1470 o->o_name == NULL ? "<unknown>" : o->o_name, 1471 opt, 1472 subopt == NULL ? "" : subopt, 1473 val); 1474 } 1475 1476 /* 1477 ** See if this option is preset for us. 1478 */ 1479 1480 if (!sticky && bitnset(opt, StickyOpt)) 1481 { 1482 if (tTd(37, 1)) 1483 printf(" (ignored)\n"); 1484 return; 1485 } 1486 1487 /* 1488 ** Check to see if this option can be specified by this user. 1489 */ 1490 1491 if (!safe && RealUid == 0) 1492 safe = TRUE; 1493 if (!safe && !o->o_safe) 1494 { 1495 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 1496 { 1497 if (tTd(37, 1)) 1498 printf(" (unsafe)"); 1499 if (RealUid != geteuid()) 1500 { 1501 if (tTd(37, 1)) 1502 printf("(Resetting uid)"); 1503 (void) setgid(RealGid); 1504 (void) setuid(RealUid); 1505 } 1506 } 1507 } 1508 if (tTd(37, 1)) 1509 printf("\n"); 1510 1511 switch (opt & 0xff) 1512 { 1513 case '7': /* force seven-bit input */ 1514 SevenBitInput = atobool(val); 1515 break; 1516 1517 #if MIME8TO7 1518 case '8': /* handling of 8-bit input */ 1519 switch (*val) 1520 { 1521 case 'm': /* convert 8-bit, convert MIME */ 1522 MimeMode = MM_CVTMIME|MM_MIME8BIT; 1523 break; 1524 1525 case 'p': /* pass 8 bit, convert MIME */ 1526 MimeMode = MM_CVTMIME|MM_PASS8BIT; 1527 break; 1528 1529 case 's': /* strict adherence */ 1530 MimeMode = MM_CVTMIME; 1531 break; 1532 1533 #if 0 1534 case 'r': /* reject 8-bit, don't convert MIME */ 1535 MimeMode = 0; 1536 break; 1537 1538 case 'j': /* "just send 8" */ 1539 MimeMode = MM_PASS8BIT; 1540 break; 1541 1542 case 'a': /* encode 8 bit if available */ 1543 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1544 break; 1545 1546 case 'c': /* convert 8 bit to MIME, never 7 bit */ 1547 MimeMode = MM_MIME8BIT; 1548 break; 1549 #endif 1550 1551 default: 1552 syserr("Unknown 8-bit mode %c", *val); 1553 exit(EX_USAGE); 1554 } 1555 break; 1556 #endif 1557 1558 case 'A': /* set default alias file */ 1559 if (val[0] == '\0') 1560 setalias("aliases"); 1561 else 1562 setalias(val); 1563 break; 1564 1565 case 'a': /* look N minutes for "@:@" in alias file */ 1566 if (val[0] == '\0') 1567 SafeAlias = 5 * 60; /* five minutes */ 1568 else 1569 SafeAlias = convtime(val, 'm'); 1570 break; 1571 1572 case 'B': /* substitution for blank character */ 1573 SpaceSub = val[0]; 1574 if (SpaceSub == '\0') 1575 SpaceSub = ' '; 1576 break; 1577 1578 case 'b': /* min blocks free on queue fs/max msg size */ 1579 p = strchr(val, '/'); 1580 if (p != NULL) 1581 { 1582 *p++ = '\0'; 1583 MaxMessageSize = atol(p); 1584 } 1585 MinBlocksFree = atol(val); 1586 break; 1587 1588 case 'c': /* don't connect to "expensive" mailers */ 1589 NoConnect = atobool(val); 1590 break; 1591 1592 case 'C': /* checkpoint every N addresses */ 1593 CheckpointInterval = atoi(val); 1594 break; 1595 1596 case 'd': /* delivery mode */ 1597 switch (*val) 1598 { 1599 case '\0': 1600 e->e_sendmode = SM_DELIVER; 1601 break; 1602 1603 case SM_QUEUE: /* queue only */ 1604 #ifndef QUEUE 1605 syserr("need QUEUE to set -odqueue"); 1606 #endif /* QUEUE */ 1607 /* fall through..... */ 1608 1609 case SM_DELIVER: /* do everything */ 1610 case SM_FORK: /* fork after verification */ 1611 e->e_sendmode = *val; 1612 break; 1613 1614 default: 1615 syserr("Unknown delivery mode %c", *val); 1616 exit(EX_USAGE); 1617 } 1618 break; 1619 1620 case 'D': /* rebuild alias database as needed */ 1621 AutoRebuild = atobool(val); 1622 break; 1623 1624 case 'E': /* error message header/header file */ 1625 if (*val != '\0') 1626 ErrMsgFile = newstr(val); 1627 break; 1628 1629 case 'e': /* set error processing mode */ 1630 switch (*val) 1631 { 1632 case EM_QUIET: /* be silent about it */ 1633 case EM_MAIL: /* mail back */ 1634 case EM_BERKNET: /* do berknet error processing */ 1635 case EM_WRITE: /* write back (or mail) */ 1636 case EM_PRINT: /* print errors normally (default) */ 1637 e->e_errormode = *val; 1638 break; 1639 } 1640 break; 1641 1642 case 'F': /* file mode */ 1643 FileMode = atooct(val) & 0777; 1644 break; 1645 1646 case 'f': /* save Unix-style From lines on front */ 1647 SaveFrom = atobool(val); 1648 break; 1649 1650 case 'G': /* match recipients against GECOS field */ 1651 MatchGecos = atobool(val); 1652 break; 1653 1654 case 'g': /* default gid */ 1655 g_opt: 1656 if (isascii(*val) && isdigit(*val)) 1657 DefGid = atoi(val); 1658 else 1659 { 1660 register struct group *gr; 1661 1662 DefGid = -1; 1663 gr = getgrnam(val); 1664 if (gr == NULL) 1665 syserr("readcf: option %c: unknown group %s", 1666 opt, val); 1667 else 1668 DefGid = gr->gr_gid; 1669 } 1670 break; 1671 1672 case 'H': /* help file */ 1673 if (val[0] == '\0') 1674 HelpFile = "sendmail.hf"; 1675 else 1676 HelpFile = newstr(val); 1677 break; 1678 1679 case 'h': /* maximum hop count */ 1680 MaxHopCount = atoi(val); 1681 break; 1682 1683 case 'I': /* use internet domain name server */ 1684 #if NAMED_BIND 1685 for (p = val; *p != 0; ) 1686 { 1687 bool clearmode; 1688 char *q; 1689 struct resolverflags *rfp; 1690 1691 while (*p == ' ') 1692 p++; 1693 if (*p == '\0') 1694 break; 1695 clearmode = FALSE; 1696 if (*p == '-') 1697 clearmode = TRUE; 1698 else if (*p != '+') 1699 p--; 1700 p++; 1701 q = p; 1702 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1703 p++; 1704 if (*p != '\0') 1705 *p++ = '\0'; 1706 if (strcasecmp(q, "HasWildcardMX") == 0) 1707 { 1708 NoMXforCanon = !clearmode; 1709 continue; 1710 } 1711 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 1712 { 1713 if (strcasecmp(q, rfp->rf_name) == 0) 1714 break; 1715 } 1716 if (rfp->rf_name == NULL) 1717 syserr("readcf: I option value %s unrecognized", q); 1718 else if (clearmode) 1719 _res.options &= ~rfp->rf_bits; 1720 else 1721 _res.options |= rfp->rf_bits; 1722 } 1723 if (tTd(8, 2)) 1724 printf("_res.options = %x, HasWildcardMX = %d\n", 1725 _res.options, !NoMXforCanon); 1726 #else 1727 usrerr("name server (I option) specified but BIND not compiled in"); 1728 #endif 1729 break; 1730 1731 case 'i': /* ignore dot lines in message */ 1732 IgnrDot = atobool(val); 1733 break; 1734 1735 case 'j': /* send errors in MIME (RFC 1341) format */ 1736 SendMIMEErrors = atobool(val); 1737 break; 1738 1739 case 'J': /* .forward search path */ 1740 ForwardPath = newstr(val); 1741 break; 1742 1743 case 'k': /* connection cache size */ 1744 MaxMciCache = atoi(val); 1745 if (MaxMciCache < 0) 1746 MaxMciCache = 0; 1747 break; 1748 1749 case 'K': /* connection cache timeout */ 1750 MciCacheTimeout = convtime(val, 'm'); 1751 break; 1752 1753 case 'l': /* use Errors-To: header */ 1754 UseErrorsTo = atobool(val); 1755 break; 1756 1757 case 'L': /* log level */ 1758 if (safe || LogLevel < atoi(val)) 1759 LogLevel = atoi(val); 1760 break; 1761 1762 case 'M': /* define macro */ 1763 p = newstr(&val[1]); 1764 if (!safe) 1765 cleanstrcpy(p, p, MAXNAME); 1766 define(val[0], p, CurEnv); 1767 sticky = FALSE; 1768 break; 1769 1770 case 'm': /* send to me too */ 1771 MeToo = atobool(val); 1772 break; 1773 1774 case 'n': /* validate RHS in newaliases */ 1775 CheckAliases = atobool(val); 1776 break; 1777 1778 /* 'N' available -- was "net name" */ 1779 1780 case 'O': /* daemon options */ 1781 setdaemonoptions(val); 1782 break; 1783 1784 case 'o': /* assume old style headers */ 1785 if (atobool(val)) 1786 CurEnv->e_flags |= EF_OLDSTYLE; 1787 else 1788 CurEnv->e_flags &= ~EF_OLDSTYLE; 1789 break; 1790 1791 case 'p': /* select privacy level */ 1792 p = val; 1793 for (;;) 1794 { 1795 register struct prival *pv; 1796 extern struct prival PrivacyValues[]; 1797 1798 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 1799 p++; 1800 if (*p == '\0') 1801 break; 1802 val = p; 1803 while (isascii(*p) && isalnum(*p)) 1804 p++; 1805 if (*p != '\0') 1806 *p++ = '\0'; 1807 1808 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 1809 { 1810 if (strcasecmp(val, pv->pv_name) == 0) 1811 break; 1812 } 1813 if (pv->pv_name == NULL) 1814 syserr("readcf: Op line: %s unrecognized", val); 1815 PrivacyFlags |= pv->pv_flag; 1816 } 1817 sticky = FALSE; 1818 break; 1819 1820 case 'P': /* postmaster copy address for returned mail */ 1821 PostMasterCopy = newstr(val); 1822 break; 1823 1824 case 'q': /* slope of queue only function */ 1825 QueueFactor = atoi(val); 1826 break; 1827 1828 case 'Q': /* queue directory */ 1829 if (val[0] == '\0') 1830 QueueDir = "mqueue"; 1831 else 1832 QueueDir = newstr(val); 1833 if (RealUid != 0 && !safe) 1834 Warn_Q_option = TRUE; 1835 break; 1836 1837 case 'R': /* don't prune routes */ 1838 DontPruneRoutes = atobool(val); 1839 break; 1840 1841 case 'r': /* read timeout */ 1842 if (subopt == NULL) 1843 inittimeouts(val); 1844 else 1845 settimeout(subopt, val); 1846 break; 1847 1848 case 'S': /* status file */ 1849 if (val[0] == '\0') 1850 StatFile = "sendmail.st"; 1851 else 1852 StatFile = newstr(val); 1853 break; 1854 1855 case 's': /* be super safe, even if expensive */ 1856 SuperSafe = atobool(val); 1857 break; 1858 1859 case 'T': /* queue timeout */ 1860 p = strchr(val, '/'); 1861 if (p != NULL) 1862 { 1863 *p++ = '\0'; 1864 settimeout("queuewarn", p); 1865 } 1866 settimeout("queuereturn", val); 1867 break; 1868 1869 case 't': /* time zone name */ 1870 TimeZoneSpec = newstr(val); 1871 break; 1872 1873 case 'U': /* location of user database */ 1874 UdbSpec = newstr(val); 1875 break; 1876 1877 case 'u': /* set default uid */ 1878 for (p = val; *p != '\0'; p++) 1879 { 1880 if (*p == '.' || *p == '/' || *p == ':') 1881 { 1882 *p++ = '\0'; 1883 break; 1884 } 1885 } 1886 if (isascii(*val) && isdigit(*val)) 1887 DefUid = atoi(val); 1888 else 1889 { 1890 register struct passwd *pw; 1891 1892 DefUid = -1; 1893 pw = sm_getpwnam(val); 1894 if (pw == NULL) 1895 syserr("readcf: option u: unknown user %s", val); 1896 else 1897 { 1898 DefUid = pw->pw_uid; 1899 DefGid = pw->pw_gid; 1900 } 1901 } 1902 setdefuser(); 1903 1904 /* handle the group if it is there */ 1905 if (*p == '\0') 1906 break; 1907 val = p; 1908 goto g_opt; 1909 1910 case 'V': /* fallback MX host */ 1911 FallBackMX = newstr(val); 1912 break; 1913 1914 case 'v': /* run in verbose mode */ 1915 Verbose = atobool(val); 1916 break; 1917 1918 case 'w': /* if we are best MX, try host directly */ 1919 TryNullMXList = atobool(val); 1920 break; 1921 1922 /* 'W' available -- was wizard password */ 1923 1924 case 'x': /* load avg at which to auto-queue msgs */ 1925 QueueLA = atoi(val); 1926 break; 1927 1928 case 'X': /* load avg at which to auto-reject connections */ 1929 RefuseLA = atoi(val); 1930 break; 1931 1932 case 'y': /* work recipient factor */ 1933 WkRecipFact = atoi(val); 1934 break; 1935 1936 case 'Y': /* fork jobs during queue runs */ 1937 ForkQueueRuns = atobool(val); 1938 break; 1939 1940 case 'z': /* work message class factor */ 1941 WkClassFact = atoi(val); 1942 break; 1943 1944 case 'Z': /* work time factor */ 1945 WkTimeFact = atoi(val); 1946 break; 1947 1948 case O_QUEUESORTORD: /* queue sorting order */ 1949 switch (*val) 1950 { 1951 case 'h': /* Host first */ 1952 case 'H': 1953 QueueSortOrder = QS_BYHOST; 1954 break; 1955 1956 case 'p': /* Priority order */ 1957 case 'P': 1958 QueueSortOrder = QS_BYPRIORITY; 1959 break; 1960 1961 default: 1962 syserr("Invalid queue sort order \"%s\"", val); 1963 } 1964 break; 1965 1966 case O_HOSTSFILE: /* pathname of /etc/hosts file */ 1967 HostsFile = newstr(val); 1968 break; 1969 1970 case O_MQA: /* minimum queue age between deliveries */ 1971 MinQueueAge = convtime(val, 'm'); 1972 break; 1973 1974 case O_MHSA: /* maximum age of cached host status */ 1975 MaxHostStatAge = convtime(val, 'm'); 1976 break; 1977 1978 case O_DEFCHARSET: /* default character set for mimefying */ 1979 DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 1980 break; 1981 1982 case O_SSFILE: /* service switch file */ 1983 ServiceSwitchFile = newstr(val); 1984 break; 1985 1986 case O_DIALDELAY: /* delay for dial-on-demand operation */ 1987 DialDelay = convtime(val, 's'); 1988 break; 1989 1990 case O_NORCPTACTION: /* what to do if no recipient */ 1991 if (strcasecmp(val, "none") == 0) 1992 NoRecipientAction = NRA_NO_ACTION; 1993 else if (strcasecmp(val, "add-to") == 0) 1994 NoRecipientAction = NRA_ADD_TO; 1995 else if (strcasecmp(val, "add-apparently-to") == 0) 1996 NoRecipientAction = NRA_ADD_APPARENTLY_TO; 1997 else if (strcasecmp(val, "add-bcc") == 0) 1998 NoRecipientAction = NRA_ADD_BCC; 1999 else if (strcasecmp(val, "add-to-undisclosed") == 0) 2000 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 2001 else 2002 syserr("Invalid NoRecipientAction: %s", val); 2003 2004 case O_SAFEFILEENV: /* chroot() environ for writing to files */ 2005 SafeFileEnv = newstr(val); 2006 break; 2007 2008 case O_MAXMSGSIZE: /* maximum message size */ 2009 MaxMessageSize = atol(p); 2010 break; 2011 2012 case O_COLONOKINADDR: /* old style handling of colon addresses */ 2013 ColonOkInAddr = atobool(p); 2014 break; 2015 2016 default: 2017 if (tTd(37, 1)) 2018 { 2019 if (isascii(opt) && isprint(opt)) 2020 printf("Warning: option %c unknown\n", opt); 2021 else 2022 printf("Warning: option 0x%x unknown\n", opt); 2023 } 2024 break; 2025 } 2026 if (sticky) 2027 setbitn(opt, StickyOpt); 2028 return; 2029 } 2030 /* 2031 ** SETCLASS -- set a string into a class 2032 ** 2033 ** Parameters: 2034 ** class -- the class to put the string in. 2035 ** str -- the string to enter 2036 ** 2037 ** Returns: 2038 ** none. 2039 ** 2040 ** Side Effects: 2041 ** puts the word into the symbol table. 2042 */ 2043 2044 setclass(class, str) 2045 int class; 2046 char *str; 2047 { 2048 register STAB *s; 2049 2050 if (tTd(37, 8)) 2051 printf("setclass(%c, %s)\n", class, str); 2052 s = stab(str, ST_CLASS, ST_ENTER); 2053 setbitn(class, s->s_class); 2054 } 2055 /* 2056 ** MAKEMAPENTRY -- create a map entry 2057 ** 2058 ** Parameters: 2059 ** line -- the config file line 2060 ** 2061 ** Returns: 2062 ** TRUE if it successfully entered the map entry. 2063 ** FALSE otherwise (usually syntax error). 2064 ** 2065 ** Side Effects: 2066 ** Enters the map into the dictionary. 2067 */ 2068 2069 void 2070 makemapentry(line) 2071 char *line; 2072 { 2073 register char *p; 2074 char *mapname; 2075 char *classname; 2076 register STAB *s; 2077 STAB *class; 2078 2079 for (p = line; isascii(*p) && isspace(*p); p++) 2080 continue; 2081 if (!(isascii(*p) && isalnum(*p))) 2082 { 2083 syserr("readcf: config K line: no map name"); 2084 return; 2085 } 2086 2087 mapname = p; 2088 while ((isascii(*++p) && isalnum(*p)) || *p == '.') 2089 continue; 2090 if (*p != '\0') 2091 *p++ = '\0'; 2092 while (isascii(*p) && isspace(*p)) 2093 p++; 2094 if (!(isascii(*p) && isalnum(*p))) 2095 { 2096 syserr("readcf: config K line, map %s: no map class", mapname); 2097 return; 2098 } 2099 classname = p; 2100 while (isascii(*++p) && isalnum(*p)) 2101 continue; 2102 if (*p != '\0') 2103 *p++ = '\0'; 2104 while (isascii(*p) && isspace(*p)) 2105 p++; 2106 2107 /* look up the class */ 2108 class = stab(classname, ST_MAPCLASS, ST_FIND); 2109 if (class == NULL) 2110 { 2111 syserr("readcf: map %s: class %s not available", mapname, classname); 2112 return; 2113 } 2114 2115 /* enter the map */ 2116 s = stab(mapname, ST_MAP, ST_ENTER); 2117 s->s_map.map_class = &class->s_mapclass; 2118 s->s_map.map_mname = newstr(mapname); 2119 2120 if (class->s_mapclass.map_parse(&s->s_map, p)) 2121 s->s_map.map_mflags |= MF_VALID; 2122 2123 if (tTd(37, 5)) 2124 { 2125 printf("map %s, class %s, flags %x, file %s,\n", 2126 s->s_map.map_mname, s->s_map.map_class->map_cname, 2127 s->s_map.map_mflags, 2128 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 2129 printf("\tapp %s, domain %s, rebuild %s\n", 2130 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 2131 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 2132 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 2133 } 2134 } 2135 /* 2136 ** INITTIMEOUTS -- parse and set timeout values 2137 ** 2138 ** Parameters: 2139 ** val -- a pointer to the values. If NULL, do initial 2140 ** settings. 2141 ** 2142 ** Returns: 2143 ** none. 2144 ** 2145 ** Side Effects: 2146 ** Initializes the TimeOuts structure 2147 */ 2148 2149 #define SECONDS 2150 #define MINUTES * 60 2151 #define HOUR * 3600 2152 2153 inittimeouts(val) 2154 register char *val; 2155 { 2156 register char *p; 2157 extern time_t convtime(); 2158 2159 if (val == NULL) 2160 { 2161 TimeOuts.to_initial = (time_t) 5 MINUTES; 2162 TimeOuts.to_helo = (time_t) 5 MINUTES; 2163 TimeOuts.to_mail = (time_t) 10 MINUTES; 2164 TimeOuts.to_rcpt = (time_t) 1 HOUR; 2165 TimeOuts.to_datainit = (time_t) 5 MINUTES; 2166 TimeOuts.to_datablock = (time_t) 1 HOUR; 2167 TimeOuts.to_datafinal = (time_t) 1 HOUR; 2168 TimeOuts.to_rset = (time_t) 5 MINUTES; 2169 TimeOuts.to_quit = (time_t) 2 MINUTES; 2170 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 2171 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2172 #if IDENTPROTO 2173 TimeOuts.to_ident = (time_t) 30 SECONDS; 2174 #else 2175 TimeOuts.to_ident = (time_t) 0 SECONDS; 2176 #endif 2177 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 2178 return; 2179 } 2180 2181 for (;; val = p) 2182 { 2183 while (isascii(*val) && isspace(*val)) 2184 val++; 2185 if (*val == '\0') 2186 break; 2187 for (p = val; *p != '\0' && *p != ','; p++) 2188 continue; 2189 if (*p != '\0') 2190 *p++ = '\0'; 2191 2192 if (isascii(*val) && isdigit(*val)) 2193 { 2194 /* old syntax -- set everything */ 2195 TimeOuts.to_mail = convtime(val, 'm'); 2196 TimeOuts.to_rcpt = TimeOuts.to_mail; 2197 TimeOuts.to_datainit = TimeOuts.to_mail; 2198 TimeOuts.to_datablock = TimeOuts.to_mail; 2199 TimeOuts.to_datafinal = TimeOuts.to_mail; 2200 TimeOuts.to_nextcommand = TimeOuts.to_mail; 2201 continue; 2202 } 2203 else 2204 { 2205 register char *q = strchr(val, ':'); 2206 2207 if (q == NULL && (q = strchr(val, '=')) == NULL) 2208 { 2209 /* syntax error */ 2210 continue; 2211 } 2212 *q++ = '\0'; 2213 settimeout(val, q); 2214 } 2215 } 2216 } 2217 /* 2218 ** SETTIMEOUT -- set an individual timeout 2219 ** 2220 ** Parameters: 2221 ** name -- the name of the timeout. 2222 ** val -- the value of the timeout. 2223 ** 2224 ** Returns: 2225 ** none. 2226 */ 2227 2228 settimeout(name, val) 2229 char *name; 2230 char *val; 2231 { 2232 register char *p; 2233 time_t to; 2234 extern time_t convtime(); 2235 2236 to = convtime(val, 'm'); 2237 p = strchr(name, '.'); 2238 if (p != NULL) 2239 *p++ = '\0'; 2240 2241 if (strcasecmp(name, "initial") == 0) 2242 TimeOuts.to_initial = to; 2243 else if (strcasecmp(name, "mail") == 0) 2244 TimeOuts.to_mail = to; 2245 else if (strcasecmp(name, "rcpt") == 0) 2246 TimeOuts.to_rcpt = to; 2247 else if (strcasecmp(name, "datainit") == 0) 2248 TimeOuts.to_datainit = to; 2249 else if (strcasecmp(name, "datablock") == 0) 2250 TimeOuts.to_datablock = to; 2251 else if (strcasecmp(name, "datafinal") == 0) 2252 TimeOuts.to_datafinal = to; 2253 else if (strcasecmp(name, "command") == 0) 2254 TimeOuts.to_nextcommand = to; 2255 else if (strcasecmp(name, "rset") == 0) 2256 TimeOuts.to_rset = to; 2257 else if (strcasecmp(name, "helo") == 0) 2258 TimeOuts.to_helo = to; 2259 else if (strcasecmp(name, "quit") == 0) 2260 TimeOuts.to_quit = to; 2261 else if (strcasecmp(name, "misc") == 0) 2262 TimeOuts.to_miscshort = to; 2263 else if (strcasecmp(name, "ident") == 0) 2264 TimeOuts.to_ident = to; 2265 else if (strcasecmp(name, "fileopen") == 0) 2266 TimeOuts.to_fileopen = to; 2267 else if (strcasecmp(name, "queuewarn") == 0) 2268 { 2269 to = convtime(val, 'h'); 2270 if (p == NULL || strcmp(p, "*") == 0) 2271 { 2272 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2273 TimeOuts.to_q_warning[TOC_URGENT] = to; 2274 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2275 } 2276 else if (strcasecmp(p, "normal") == 0) 2277 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2278 else if (strcasecmp(p, "urgent") == 0) 2279 TimeOuts.to_q_warning[TOC_URGENT] = to; 2280 else if (strcasecmp(p, "non-urgent") == 0) 2281 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2282 else 2283 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2284 } 2285 else if (strcasecmp(name, "queuereturn") == 0) 2286 { 2287 to = convtime(val, 'd'); 2288 if (p == NULL || strcmp(p, "*") == 0) 2289 { 2290 TimeOuts.to_q_return[TOC_NORMAL] = to; 2291 TimeOuts.to_q_return[TOC_URGENT] = to; 2292 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2293 } 2294 else if (strcasecmp(p, "normal") == 0) 2295 TimeOuts.to_q_return[TOC_NORMAL] = to; 2296 else if (strcasecmp(p, "urgent") == 0) 2297 TimeOuts.to_q_return[TOC_URGENT] = to; 2298 else if (strcasecmp(p, "non-urgent") == 0) 2299 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2300 else 2301 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2302 } 2303 else 2304 syserr("settimeout: invalid timeout %s", name); 2305 } 2306