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