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