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