1 /* 2 * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 3 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * By using this file, you agree to the terms and conditions set 8 * forth in the LICENSE file which can be found at the top level of 9 * the sendmail distribution. 10 * 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)readcf.c 8.238 (Berkeley) 1/28/1999"; 15 #endif /* not lint */ 16 17 # include "sendmail.h" 18 # include <grp.h> 19 #if NAMED_BIND 20 # include <resolv.h> 21 #endif 22 23 /* 24 ** READCF -- read configuration file. 25 ** 26 ** This routine reads the configuration file and builds the internal 27 ** form. 28 ** 29 ** The file is formatted as a sequence of lines, each taken 30 ** atomically. The first character of each line describes how 31 ** the line is to be interpreted. The lines are: 32 ** Dxval Define macro x to have value val. 33 ** Cxword Put word into class x. 34 ** Fxfile [fmt] Read file for lines to put into 35 ** class x. Use scanf string 'fmt' 36 ** or "%s" if not present. Fmt should 37 ** only produce one string-valued result. 38 ** Hname: value Define header with field-name 'name' 39 ** and value as specified; this will be 40 ** macro expanded immediately before 41 ** use. 42 ** Sn Use rewriting set n. 43 ** Rlhs rhs Rewrite addresses that match lhs to 44 ** be rhs. 45 ** Mn arg=val... Define mailer. n is the internal name. 46 ** Args specify mailer parameters. 47 ** Oxvalue Set option x to value. 48 ** Pname=value Set precedence name to value. 49 ** Vversioncode[/vendorcode] 50 ** Version level/vendor name of 51 ** configuration syntax. 52 ** Kmapname mapclass arguments.... 53 ** Define keyed lookup of a given class. 54 ** Arguments are class dependent. 55 ** Eenvar=value Set the environment value to the given value. 56 ** 57 ** Parameters: 58 ** cfname -- configuration file name. 59 ** safe -- TRUE if this is the system config file; 60 ** FALSE otherwise. 61 ** e -- the main envelope. 62 ** 63 ** Returns: 64 ** none. 65 ** 66 ** Side Effects: 67 ** Builds several internal tables. 68 */ 69 70 void 71 readcf(cfname, safe, e) 72 char *cfname; 73 bool safe; 74 register ENVELOPE *e; 75 { 76 FILE *cf; 77 int ruleset = 0; 78 char *q; 79 struct rewrite *rwp = NULL; 80 char *bp; 81 auto char *ep; 82 int nfuzzy; 83 char *file; 84 bool optional; 85 int mid; 86 register char *p; 87 int sff = SFF_OPENASROOT; 88 struct stat statb; 89 char buf[MAXLINE]; 90 char exbuf[MAXLINE]; 91 char pvpbuf[MAXLINE + MAXATOM]; 92 static char *null_list[1] = { NULL }; 93 extern char **copyplist __P((char **, bool)); 94 extern char *munchstring __P((char *, char **, int)); 95 extern void fileclass __P((int, char *, char *, bool, bool)); 96 extern void toomany __P((int, int)); 97 extern void translate_dollars __P((char *)); 98 extern void inithostmaps __P((void)); 99 100 FileName = cfname; 101 LineNumber = 0; 102 103 if (DontLockReadFiles) 104 sff |= SFF_NOLOCK; 105 cf = safefopen(cfname, O_RDONLY, 0444, sff); 106 if (cf == NULL) 107 { 108 syserr("cannot open"); 109 finis(FALSE, EX_OSFILE); 110 } 111 112 if (fstat(fileno(cf), &statb) < 0) 113 { 114 syserr("cannot fstat"); 115 finis(FALSE, EX_OSFILE); 116 } 117 118 if (!S_ISREG(statb.st_mode)) 119 { 120 syserr("not a plain file"); 121 finis(FALSE, EX_OSFILE); 122 } 123 124 if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 125 { 126 if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS) 127 fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 128 FileName); 129 if (LogLevel > 0) 130 sm_syslog(LOG_CRIT, NOQID, 131 "%s: WARNING: dangerous write permissions", 132 FileName); 133 } 134 135 #ifdef XLA 136 xla_zero(); 137 #endif 138 139 while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 140 { 141 if (bp[0] == '#') 142 { 143 if (bp != buf) 144 free(bp); 145 continue; 146 } 147 148 /* do macro expansion mappings */ 149 translate_dollars(bp); 150 151 /* interpret this line */ 152 errno = 0; 153 switch (bp[0]) 154 { 155 case '\0': 156 case '#': /* comment */ 157 break; 158 159 case 'R': /* rewriting rule */ 160 for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 161 continue; 162 163 if (*p == '\0') 164 { 165 syserr("invalid rewrite line \"%s\" (tab expected)", bp); 166 break; 167 } 168 169 /* allocate space for the rule header */ 170 if (rwp == NULL) 171 { 172 RewriteRules[ruleset] = rwp = 173 (struct rewrite *) xalloc(sizeof *rwp); 174 } 175 else 176 { 177 rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 178 rwp = rwp->r_next; 179 } 180 rwp->r_next = NULL; 181 182 /* expand and save the LHS */ 183 *p = '\0'; 184 expand(&bp[1], exbuf, sizeof exbuf, e); 185 rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 186 sizeof pvpbuf, NULL, NULL); 187 nfuzzy = 0; 188 if (rwp->r_lhs != NULL) 189 { 190 register char **ap; 191 192 rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 193 194 /* count the number of fuzzy matches in LHS */ 195 for (ap = rwp->r_lhs; *ap != NULL; ap++) 196 { 197 char *botch; 198 199 botch = NULL; 200 switch (**ap & 0377) 201 { 202 case MATCHZANY: 203 case MATCHANY: 204 case MATCHONE: 205 case MATCHCLASS: 206 case MATCHNCLASS: 207 nfuzzy++; 208 break; 209 210 case MATCHREPL: 211 botch = "$0-$9"; 212 break; 213 214 case CANONUSER: 215 botch = "$:"; 216 break; 217 218 case CALLSUBR: 219 botch = "$>"; 220 break; 221 222 case CONDIF: 223 botch = "$?"; 224 break; 225 226 case CONDFI: 227 botch = "$."; 228 break; 229 230 case HOSTBEGIN: 231 botch = "$["; 232 break; 233 234 case HOSTEND: 235 botch = "$]"; 236 break; 237 238 case LOOKUPBEGIN: 239 botch = "$("; 240 break; 241 242 case LOOKUPEND: 243 botch = "$)"; 244 break; 245 } 246 if (botch != NULL) 247 syserr("Inappropriate use of %s on LHS", 248 botch); 249 } 250 } 251 else 252 { 253 syserr("R line: null LHS"); 254 rwp->r_lhs = null_list; 255 } 256 257 /* expand and save the RHS */ 258 while (*++p == '\t') 259 continue; 260 q = p; 261 while (*p != '\0' && *p != '\t') 262 p++; 263 *p = '\0'; 264 expand(q, exbuf, sizeof exbuf, e); 265 rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 266 sizeof pvpbuf, NULL, NULL); 267 if (rwp->r_rhs != NULL) 268 { 269 register char **ap; 270 271 rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 272 273 /* check no out-of-bounds replacements */ 274 nfuzzy += '0'; 275 for (ap = rwp->r_rhs; *ap != NULL; ap++) 276 { 277 char *botch; 278 279 botch = NULL; 280 switch (**ap & 0377) 281 { 282 case MATCHREPL: 283 if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 284 { 285 syserr("replacement $%c out of bounds", 286 (*ap)[1]); 287 } 288 break; 289 290 case MATCHZANY: 291 botch = "$*"; 292 break; 293 294 case MATCHANY: 295 botch = "$+"; 296 break; 297 298 case MATCHONE: 299 botch = "$-"; 300 break; 301 302 case MATCHCLASS: 303 botch = "$="; 304 break; 305 306 case MATCHNCLASS: 307 botch = "$~"; 308 break; 309 } 310 if (botch != NULL) 311 syserr("Inappropriate use of %s on RHS", 312 botch); 313 } 314 } 315 else 316 { 317 syserr("R line: null RHS"); 318 rwp->r_rhs = null_list; 319 } 320 break; 321 322 case 'S': /* select rewriting set */ 323 expand(&bp[1], exbuf, sizeof exbuf, e); 324 ruleset = strtorwset(exbuf, NULL, ST_ENTER); 325 if (ruleset < 0) 326 break; 327 rwp = RewriteRules[ruleset]; 328 if (rwp != NULL) 329 { 330 if (OpMode == MD_TEST || tTd(37, 1)) 331 printf("WARNING: Ruleset %s has multiple definitions\n", 332 &bp[1]); 333 while (rwp->r_next != NULL) 334 rwp = rwp->r_next; 335 } 336 break; 337 338 case 'D': /* macro definition */ 339 mid = macid(&bp[1], &ep); 340 p = munchstring(ep, NULL, '\0'); 341 define(mid, newstr(p), e); 342 break; 343 344 case 'H': /* required header line */ 345 (void) chompheader(&bp[1], TRUE, NULL, e); 346 break; 347 348 case 'C': /* word class */ 349 case 'T': /* trusted user (set class `t') */ 350 if (bp[0] == 'C') 351 { 352 mid = macid(&bp[1], &ep); 353 expand(ep, exbuf, sizeof exbuf, e); 354 p = exbuf; 355 } 356 else 357 { 358 mid = 't'; 359 p = &bp[1]; 360 } 361 while (*p != '\0') 362 { 363 register char *wd; 364 char delim; 365 366 while (*p != '\0' && isascii(*p) && isspace(*p)) 367 p++; 368 wd = p; 369 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 370 p++; 371 delim = *p; 372 *p = '\0'; 373 if (wd[0] != '\0') 374 setclass(mid, wd); 375 *p = delim; 376 } 377 break; 378 379 case 'F': /* word class from file */ 380 mid = macid(&bp[1], &ep); 381 for (p = ep; isascii(*p) && isspace(*p); ) 382 p++; 383 if (p[0] == '-' && p[1] == 'o') 384 { 385 optional = TRUE; 386 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 387 p++; 388 while (isascii(*p) && isspace(*p)) 389 p++; 390 } 391 else 392 optional = FALSE; 393 file = p; 394 if (*file == '|') 395 p = "%s"; 396 else 397 { 398 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 399 p++; 400 if (*p == '\0') 401 p = "%s"; 402 else 403 { 404 *p = '\0'; 405 while (isascii(*++p) && isspace(*p)) 406 continue; 407 } 408 } 409 fileclass(mid, file, p, safe, optional); 410 break; 411 412 #ifdef XLA 413 case 'L': /* extended load average description */ 414 xla_init(&bp[1]); 415 break; 416 #endif 417 418 #if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) 419 case 'L': /* lookup macro */ 420 case 'G': /* lookup class */ 421 /* reserved for Sun -- NIS+ database lookup */ 422 if (VendorCode != VENDOR_SUN) 423 goto badline; 424 sun_lg_config_line(bp, e); 425 break; 426 #endif 427 428 case 'M': /* define mailer */ 429 makemailer(&bp[1]); 430 break; 431 432 case 'O': /* set option */ 433 setoption(bp[1], &bp[2], safe, FALSE, e); 434 break; 435 436 case 'P': /* set precedence */ 437 if (NumPriorities >= MAXPRIORITIES) 438 { 439 toomany('P', MAXPRIORITIES); 440 break; 441 } 442 for (p = &bp[1]; *p != '\0' && *p != '='; p++) 443 continue; 444 if (*p == '\0') 445 goto badline; 446 *p = '\0'; 447 Priorities[NumPriorities].pri_name = newstr(&bp[1]); 448 Priorities[NumPriorities].pri_val = atoi(++p); 449 NumPriorities++; 450 break; 451 452 case 'V': /* configuration syntax version */ 453 for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 454 continue; 455 if (!isascii(*p) || !isdigit(*p)) 456 { 457 syserr("invalid argument to V line: \"%.20s\"", 458 &bp[1]); 459 break; 460 } 461 ConfigLevel = strtol(p, &ep, 10); 462 463 /* 464 ** Do heuristic tweaking for back compatibility. 465 */ 466 467 if (ConfigLevel >= 5) 468 { 469 /* level 5 configs have short name in $w */ 470 p = macvalue('w', e); 471 if (p != NULL && (p = strchr(p, '.')) != NULL) 472 *p = '\0'; 473 define('w', macvalue('w', e), e); 474 } 475 if (ConfigLevel >= 6) 476 { 477 ColonOkInAddr = FALSE; 478 } 479 480 /* 481 ** Look for vendor code. 482 */ 483 484 if (*ep++ == '/') 485 { 486 extern bool setvendor __P((char *)); 487 488 /* extract vendor code */ 489 for (p = ep; isascii(*p) && isalpha(*p); ) 490 p++; 491 *p = '\0'; 492 493 if (!setvendor(ep)) 494 syserr("invalid V line vendor code: \"%s\"", 495 ep); 496 } 497 break; 498 499 case 'K': 500 expand(&bp[1], exbuf, sizeof exbuf, e); 501 (void) makemapentry(exbuf); 502 break; 503 504 case 'E': 505 p = strchr(bp, '='); 506 if (p != NULL) 507 *p++ = '\0'; 508 setuserenv(&bp[1], p); 509 break; 510 511 default: 512 badline: 513 syserr("unknown configuration line \"%s\"", bp); 514 } 515 if (bp != buf) 516 free(bp); 517 } 518 if (ferror(cf)) 519 { 520 syserr("I/O read error"); 521 finis(FALSE, EX_OSFILE); 522 } 523 fclose(cf); 524 FileName = NULL; 525 526 /* initialize host maps from local service tables */ 527 inithostmaps(); 528 529 /* determine if we need to do special name-server frotz */ 530 { 531 int nmaps; 532 char *maptype[MAXMAPSTACK]; 533 short mapreturn[MAXMAPACTIONS]; 534 535 nmaps = switch_map_find("hosts", maptype, mapreturn); 536 UseNameServer = FALSE; 537 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 538 { 539 register int mapno; 540 541 for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 542 { 543 if (strcmp(maptype[mapno], "dns") == 0) 544 UseNameServer = TRUE; 545 } 546 } 547 548 #ifdef HESIOD 549 nmaps = switch_map_find("passwd", maptype, mapreturn); 550 UseHesiod = FALSE; 551 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 552 { 553 register int mapno; 554 555 for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 556 { 557 if (strcmp(maptype[mapno], "hesiod") == 0) 558 UseHesiod = TRUE; 559 } 560 } 561 #endif 562 } 563 } 564 /* 565 ** TRANSLATE_DOLLARS -- convert $x into internal form 566 ** 567 ** Actually does all appropriate pre-processing of a config line 568 ** to turn it into internal form. 569 ** 570 ** Parameters: 571 ** bp -- the buffer to translate. 572 ** 573 ** Returns: 574 ** None. The buffer is translated in place. Since the 575 ** translations always make the buffer shorter, this is 576 ** safe without a size parameter. 577 */ 578 579 void 580 translate_dollars(bp) 581 char *bp; 582 { 583 register char *p; 584 auto char *ep; 585 586 for (p = bp; *p != '\0'; p++) 587 { 588 if (*p == '#' && p > bp && ConfigLevel >= 3) 589 { 590 /* this is an on-line comment */ 591 register char *e; 592 593 switch (*--p & 0377) 594 { 595 case MACROEXPAND: 596 /* it's from $# -- let it go through */ 597 p++; 598 break; 599 600 case '\\': 601 /* it's backslash escaped */ 602 (void) strcpy(p, p + 1); 603 break; 604 605 default: 606 /* delete preceeding white space */ 607 while (isascii(*p) && isspace(*p) && 608 *p != '\n' && p > bp) 609 p--; 610 if ((e = strchr(++p, '\n')) != NULL) 611 (void) strcpy(p, e); 612 else 613 *p-- = '\0'; 614 break; 615 } 616 continue; 617 } 618 619 if (*p != '$' || p[1] == '\0') 620 continue; 621 622 if (p[1] == '$') 623 { 624 /* actual dollar sign.... */ 625 (void) strcpy(p, p + 1); 626 continue; 627 } 628 629 /* convert to macro expansion character */ 630 *p++ = MACROEXPAND; 631 632 /* special handling for $=, $~, $&, and $? */ 633 if (*p == '=' || *p == '~' || *p == '&' || *p == '?') 634 p++; 635 636 /* convert macro name to code */ 637 *p = macid(p, &ep); 638 if (ep != p) 639 strcpy(p + 1, ep); 640 } 641 642 /* strip trailing white space from the line */ 643 while (--p > bp && isascii(*p) && isspace(*p)) 644 *p = '\0'; 645 } 646 /* 647 ** TOOMANY -- signal too many of some option 648 ** 649 ** Parameters: 650 ** id -- the id of the error line 651 ** maxcnt -- the maximum possible values 652 ** 653 ** Returns: 654 ** none. 655 ** 656 ** Side Effects: 657 ** gives a syserr. 658 */ 659 660 void 661 toomany(id, maxcnt) 662 int id; 663 int maxcnt; 664 { 665 syserr("too many %c lines, %d max", id, maxcnt); 666 } 667 /* 668 ** FILECLASS -- read members of a class from a file 669 ** 670 ** Parameters: 671 ** class -- class to define. 672 ** filename -- name of file to read. 673 ** fmt -- scanf string to use for match. 674 ** safe -- if set, this is a safe read. 675 ** optional -- if set, it is not an error for the file to 676 ** not exist. 677 ** 678 ** Returns: 679 ** none 680 ** 681 ** Side Effects: 682 ** 683 ** puts all lines in filename that match a scanf into 684 ** the named class. 685 */ 686 687 void 688 fileclass(class, filename, fmt, safe, optional) 689 int class; 690 char *filename; 691 char *fmt; 692 bool safe; 693 bool optional; 694 { 695 FILE *f; 696 int sff; 697 pid_t pid; 698 register char *p; 699 char buf[MAXLINE]; 700 701 if (tTd(37, 2)) 702 printf("fileclass(%s, fmt=%s)\n", filename, fmt); 703 704 if (filename[0] == '|') 705 { 706 auto int fd; 707 int i; 708 char *argv[MAXPV + 1]; 709 710 i = 0; 711 for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t")) 712 { 713 if (i >= MAXPV) 714 break; 715 argv[i++] = p; 716 } 717 argv[i] = NULL; 718 pid = prog_open(argv, &fd, CurEnv); 719 if (pid < 0) 720 f = NULL; 721 else 722 f = fdopen(fd, "r"); 723 } 724 else 725 { 726 pid = -1; 727 sff = SFF_REGONLY; 728 if (!bitset(DBS_CLASSFILEINUNSAFEDIRPATH, DontBlameSendmail)) 729 sff |= SFF_SAFEDIRPATH; 730 if (!bitset(DBS_LINKEDCLASSFILEINWRITABLEDIR, DontBlameSendmail)) 731 sff |= SFF_NOWLINK; 732 if (safe) 733 sff |= SFF_OPENASROOT; 734 if (DontLockReadFiles) 735 sff |= SFF_NOLOCK; 736 f = safefopen(filename, O_RDONLY, 0, sff); 737 } 738 if (f == NULL) 739 { 740 if (!optional) 741 syserr("fileclass: cannot open %s", filename); 742 return; 743 } 744 745 while (fgets(buf, sizeof buf, f) != NULL) 746 { 747 register char *p; 748 # if SCANF 749 char wordbuf[MAXLINE + 1]; 750 # endif 751 752 if (buf[0] == '#') 753 continue; 754 # if SCANF 755 if (sscanf(buf, fmt, wordbuf) != 1) 756 continue; 757 p = wordbuf; 758 # else /* SCANF */ 759 p = buf; 760 # endif /* SCANF */ 761 762 /* 763 ** Break up the match into words. 764 */ 765 766 while (*p != '\0') 767 { 768 register char *q; 769 770 /* strip leading spaces */ 771 while (isascii(*p) && isspace(*p)) 772 p++; 773 if (*p == '\0') 774 break; 775 776 /* find the end of the word */ 777 q = p; 778 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 779 p++; 780 if (*p != '\0') 781 *p++ = '\0'; 782 783 /* enter the word in the symbol table */ 784 setclass(class, q); 785 } 786 } 787 788 (void) fclose(f); 789 if (pid > 0) 790 (void) waitfor(pid); 791 } 792 /* 793 ** MAKEMAILER -- define a new mailer. 794 ** 795 ** Parameters: 796 ** line -- description of mailer. This is in labeled 797 ** fields. The fields are: 798 ** A -- the argv for this mailer 799 ** C -- the character set for MIME conversions 800 ** D -- the directory to run in 801 ** E -- the eol string 802 ** F -- the flags associated with the mailer 803 ** L -- the maximum line length 804 ** M -- the maximum message size 805 ** N -- the niceness at which to run 806 ** P -- the path to the mailer 807 ** R -- the recipient rewriting set 808 ** S -- the sender rewriting set 809 ** T -- the mailer type (for DSNs) 810 ** U -- the uid to run as 811 ** The first word is the canonical name of the mailer. 812 ** 813 ** Returns: 814 ** none. 815 ** 816 ** Side Effects: 817 ** enters the mailer into the mailer table. 818 */ 819 820 void 821 makemailer(line) 822 char *line; 823 { 824 register char *p; 825 register struct mailer *m; 826 register STAB *s; 827 int i; 828 char fcode; 829 auto char *endp; 830 extern int NextMailer; 831 extern char **makeargv __P((char *)); 832 extern char *munchstring __P((char *, char **, int)); 833 834 /* allocate a mailer and set up defaults */ 835 m = (struct mailer *) xalloc(sizeof *m); 836 bzero((char *) m, sizeof *m); 837 838 /* collect the mailer name */ 839 for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 840 continue; 841 if (*p != '\0') 842 *p++ = '\0'; 843 if (line[0] == '\0') 844 syserr("name required for mailer"); 845 m->m_name = newstr(line); 846 847 /* now scan through and assign info from the fields */ 848 while (*p != '\0') 849 { 850 auto char *delimptr; 851 852 while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 853 p++; 854 855 /* p now points to field code */ 856 fcode = *p; 857 while (*p != '\0' && *p != '=' && *p != ',') 858 p++; 859 if (*p++ != '=') 860 { 861 syserr("mailer %s: `=' expected", m->m_name); 862 return; 863 } 864 while (isascii(*p) && isspace(*p)) 865 p++; 866 867 /* p now points to the field body */ 868 p = munchstring(p, &delimptr, ','); 869 870 /* install the field into the mailer struct */ 871 switch (fcode) 872 { 873 case 'P': /* pathname */ 874 if (*p == '\0') 875 syserr("mailer %s: empty path name", m->m_name); 876 m->m_mailer = newstr(p); 877 break; 878 879 case 'F': /* flags */ 880 for (; *p != '\0'; p++) 881 if (!(isascii(*p) && isspace(*p))) 882 setbitn(*p, m->m_flags); 883 break; 884 885 case 'S': /* sender rewriting ruleset */ 886 case 'R': /* recipient rewriting ruleset */ 887 i = strtorwset(p, &endp, ST_ENTER); 888 if (i < 0) 889 return; 890 if (fcode == 'S') 891 m->m_sh_rwset = m->m_se_rwset = i; 892 else 893 m->m_rh_rwset = m->m_re_rwset = i; 894 895 p = endp; 896 if (*p++ == '/') 897 { 898 i = strtorwset(p, NULL, ST_ENTER); 899 if (i < 0) 900 return; 901 if (fcode == 'S') 902 m->m_sh_rwset = i; 903 else 904 m->m_rh_rwset = i; 905 } 906 break; 907 908 case 'E': /* end of line string */ 909 if (*p == '\0') 910 syserr("mailer %s: null end-of-line string", 911 m->m_name); 912 m->m_eol = newstr(p); 913 break; 914 915 case 'A': /* argument vector */ 916 if (*p == '\0') 917 syserr("mailer %s: null argument vector", 918 m->m_name); 919 m->m_argv = makeargv(p); 920 break; 921 922 case 'M': /* maximum message size */ 923 m->m_maxsize = atol(p); 924 break; 925 926 case 'L': /* maximum line length */ 927 m->m_linelimit = atoi(p); 928 if (m->m_linelimit < 0) 929 m->m_linelimit = 0; 930 break; 931 932 case 'N': /* run niceness */ 933 m->m_nice = atoi(p); 934 break; 935 936 case 'D': /* working directory */ 937 if (*p == '\0') 938 syserr("mailer %s: null working directory", 939 m->m_name); 940 m->m_execdir = newstr(p); 941 break; 942 943 case 'C': /* default charset */ 944 if (*p == '\0') 945 syserr("mailer %s: null charset", m->m_name); 946 m->m_defcharset = newstr(p); 947 break; 948 949 case 'T': /* MTA-Name/Address/Diagnostic types */ 950 /* extract MTA name type; default to "dns" */ 951 m->m_mtatype = newstr(p); 952 p = strchr(m->m_mtatype, '/'); 953 if (p != NULL) 954 { 955 *p++ = '\0'; 956 if (*p == '\0') 957 p = NULL; 958 } 959 if (*m->m_mtatype == '\0') 960 m->m_mtatype = "dns"; 961 962 /* extract address type; default to "rfc822" */ 963 m->m_addrtype = p; 964 if (p != NULL) 965 p = strchr(p, '/'); 966 if (p != NULL) 967 { 968 *p++ = '\0'; 969 if (*p == '\0') 970 p = NULL; 971 } 972 if (m->m_addrtype == NULL || *m->m_addrtype == '\0') 973 m->m_addrtype = "rfc822"; 974 975 /* extract diagnostic type; default to "smtp" */ 976 m->m_diagtype = p; 977 if (m->m_diagtype == NULL || *m->m_diagtype == '\0') 978 m->m_diagtype = "smtp"; 979 break; 980 981 case 'U': /* user id */ 982 if (isascii(*p) && !isdigit(*p)) 983 { 984 char *q = p; 985 struct passwd *pw; 986 987 while (*p != '\0' && isascii(*p) && 988 (isalnum(*p) || strchr("-_", *p) != NULL)) 989 p++; 990 while (isascii(*p) && isspace(*p)) 991 *p++ = '\0'; 992 if (*p != '\0') 993 *p++ = '\0'; 994 if (*q == '\0') 995 syserr("mailer %s: null user name", 996 m->m_name); 997 pw = sm_getpwnam(q); 998 if (pw == NULL) 999 syserr("readcf: mailer U= flag: unknown user %s", q); 1000 else 1001 { 1002 m->m_uid = pw->pw_uid; 1003 m->m_gid = pw->pw_gid; 1004 } 1005 } 1006 else 1007 { 1008 auto char *q; 1009 1010 m->m_uid = strtol(p, &q, 0); 1011 p = q; 1012 while (isascii(*p) && isspace(*p)) 1013 p++; 1014 if (*p != '\0') 1015 p++; 1016 } 1017 while (isascii(*p) && isspace(*p)) 1018 p++; 1019 if (*p == '\0') 1020 break; 1021 if (isascii(*p) && !isdigit(*p)) 1022 { 1023 char *q = p; 1024 struct group *gr; 1025 1026 while (isascii(*p) && isalnum(*p)) 1027 p++; 1028 *p++ = '\0'; 1029 if (*q == '\0') 1030 syserr("mailer %s: null group name", 1031 m->m_name); 1032 gr = getgrnam(q); 1033 if (gr == NULL) 1034 syserr("readcf: mailer U= flag: unknown group %s", q); 1035 else 1036 m->m_gid = gr->gr_gid; 1037 } 1038 else 1039 { 1040 m->m_gid = strtol(p, NULL, 0); 1041 } 1042 break; 1043 } 1044 1045 p = delimptr; 1046 } 1047 1048 /* do some rationality checking */ 1049 if (m->m_argv == NULL) 1050 { 1051 syserr("M%s: A= argument required", m->m_name); 1052 return; 1053 } 1054 if (m->m_mailer == NULL) 1055 { 1056 syserr("M%s: P= argument required", m->m_name); 1057 return; 1058 } 1059 1060 if (NextMailer >= MAXMAILERS) 1061 { 1062 syserr("too many mailers defined (%d max)", MAXMAILERS); 1063 return; 1064 } 1065 1066 /* do some heuristic cleanup for back compatibility */ 1067 if (bitnset(M_LIMITS, m->m_flags)) 1068 { 1069 if (m->m_linelimit == 0) 1070 m->m_linelimit = SMTPLINELIM; 1071 if (ConfigLevel < 2) 1072 setbitn(M_7BITS, m->m_flags); 1073 } 1074 1075 if (strcmp(m->m_mailer, "[IPC]") == 0 || 1076 strcmp(m->m_mailer, "[TCP]") == 0) 1077 { 1078 if (m->m_mtatype == NULL) 1079 m->m_mtatype = "dns"; 1080 if (m->m_addrtype == NULL) 1081 m->m_addrtype = "rfc822"; 1082 if (m->m_diagtype == NULL) 1083 m->m_diagtype = "smtp"; 1084 } 1085 1086 if (strcmp(m->m_mailer, "[FILE]") == 0) 1087 { 1088 /* Use the second argument for filename */ 1089 if (m->m_argv[0] == NULL || m->m_argv[1] == NULL || 1090 m->m_argv[2] != NULL) 1091 { 1092 syserr("M%s: too %s parameters for [FILE] mailer", 1093 m->m_name, 1094 (m->m_argv[0] == NULL || 1095 m->m_argv[1] == NULL) ? "few" : "many"); 1096 } 1097 else if (strcmp(m->m_argv[0], "FILE") != 0) 1098 { 1099 syserr("M%s: first argument in [FILE] mailer must be FILE", 1100 m->m_name); 1101 } 1102 } 1103 1104 if (m->m_eol == NULL) 1105 { 1106 char **pp; 1107 1108 /* default for SMTP is \r\n; use \n for local delivery */ 1109 for (pp = m->m_argv; *pp != NULL; pp++) 1110 { 1111 char *p; 1112 1113 for (p = *pp; *p != '\0'; ) 1114 { 1115 if ((*p++ & 0377) == MACROEXPAND && *p == 'u') 1116 break; 1117 } 1118 if (*p != '\0') 1119 break; 1120 } 1121 if (*pp == NULL) 1122 m->m_eol = "\r\n"; 1123 else 1124 m->m_eol = "\n"; 1125 } 1126 1127 /* enter the mailer into the symbol table */ 1128 s = stab(m->m_name, ST_MAILER, ST_ENTER); 1129 if (s->s_mailer != NULL) 1130 { 1131 i = s->s_mailer->m_mno; 1132 free(s->s_mailer); 1133 } 1134 else 1135 { 1136 i = NextMailer++; 1137 } 1138 Mailer[i] = s->s_mailer = m; 1139 m->m_mno = i; 1140 } 1141 /* 1142 ** MUNCHSTRING -- translate a string into internal form. 1143 ** 1144 ** Parameters: 1145 ** p -- the string to munch. 1146 ** delimptr -- if non-NULL, set to the pointer of the 1147 ** field delimiter character. 1148 ** delim -- the delimiter for the field. 1149 ** 1150 ** Returns: 1151 ** the munched string. 1152 */ 1153 1154 char * 1155 munchstring(p, delimptr, delim) 1156 register char *p; 1157 char **delimptr; 1158 int delim; 1159 { 1160 register char *q; 1161 bool backslash = FALSE; 1162 bool quotemode = FALSE; 1163 static char buf[MAXLINE]; 1164 1165 for (q = buf; *p != '\0' && q < &buf[sizeof buf - 1]; p++) 1166 { 1167 if (backslash) 1168 { 1169 /* everything is roughly literal */ 1170 backslash = FALSE; 1171 switch (*p) 1172 { 1173 case 'r': /* carriage return */ 1174 *q++ = '\r'; 1175 continue; 1176 1177 case 'n': /* newline */ 1178 *q++ = '\n'; 1179 continue; 1180 1181 case 'f': /* form feed */ 1182 *q++ = '\f'; 1183 continue; 1184 1185 case 'b': /* backspace */ 1186 *q++ = '\b'; 1187 continue; 1188 } 1189 *q++ = *p; 1190 } 1191 else 1192 { 1193 if (*p == '\\') 1194 backslash = TRUE; 1195 else if (*p == '"') 1196 quotemode = !quotemode; 1197 else if (quotemode || *p != delim) 1198 *q++ = *p; 1199 else 1200 break; 1201 } 1202 } 1203 1204 if (delimptr != NULL) 1205 *delimptr = p; 1206 *q++ = '\0'; 1207 return (buf); 1208 } 1209 /* 1210 ** MAKEARGV -- break up a string into words 1211 ** 1212 ** Parameters: 1213 ** p -- the string to break up. 1214 ** 1215 ** Returns: 1216 ** a char **argv (dynamically allocated) 1217 ** 1218 ** Side Effects: 1219 ** munges p. 1220 */ 1221 1222 char ** 1223 makeargv(p) 1224 register char *p; 1225 { 1226 char *q; 1227 int i; 1228 char **avp; 1229 char *argv[MAXPV + 1]; 1230 1231 /* take apart the words */ 1232 i = 0; 1233 while (*p != '\0' && i < MAXPV) 1234 { 1235 q = p; 1236 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1237 p++; 1238 while (isascii(*p) && isspace(*p)) 1239 *p++ = '\0'; 1240 argv[i++] = newstr(q); 1241 } 1242 argv[i++] = NULL; 1243 1244 /* now make a copy of the argv */ 1245 avp = (char **) xalloc(sizeof *avp * i); 1246 bcopy((char *) argv, (char *) avp, sizeof *avp * i); 1247 1248 return (avp); 1249 } 1250 /* 1251 ** PRINTRULES -- print rewrite rules (for debugging) 1252 ** 1253 ** Parameters: 1254 ** none. 1255 ** 1256 ** Returns: 1257 ** none. 1258 ** 1259 ** Side Effects: 1260 ** prints rewrite rules. 1261 */ 1262 1263 void 1264 printrules() 1265 { 1266 register struct rewrite *rwp; 1267 register int ruleset; 1268 1269 for (ruleset = 0; ruleset < 10; ruleset++) 1270 { 1271 if (RewriteRules[ruleset] == NULL) 1272 continue; 1273 printf("\n----Rule Set %d:", ruleset); 1274 1275 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 1276 { 1277 printf("\nLHS:"); 1278 printav(rwp->r_lhs); 1279 printf("RHS:"); 1280 printav(rwp->r_rhs); 1281 } 1282 } 1283 } 1284 /* 1285 ** PRINTMAILER -- print mailer structure (for debugging) 1286 ** 1287 ** Parameters: 1288 ** m -- the mailer to print 1289 ** 1290 ** Returns: 1291 ** none. 1292 */ 1293 1294 void 1295 printmailer(m) 1296 register MAILER *m; 1297 { 1298 int j; 1299 1300 printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 1301 m->m_mno, m->m_name, 1302 m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 1303 m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 1304 (int) m->m_uid, (int) m->m_gid); 1305 for (j = '\0'; j <= '\177'; j++) 1306 if (bitnset(j, m->m_flags)) 1307 (void) putchar(j); 1308 printf(" L=%d E=", m->m_linelimit); 1309 xputs(m->m_eol); 1310 if (m->m_defcharset != NULL) 1311 printf(" C=%s", m->m_defcharset); 1312 printf(" T=%s/%s/%s", 1313 m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 1314 m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 1315 m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 1316 if (m->m_argv != NULL) 1317 { 1318 char **a = m->m_argv; 1319 1320 printf(" A="); 1321 while (*a != NULL) 1322 { 1323 if (a != m->m_argv) 1324 printf(" "); 1325 xputs(*a++); 1326 } 1327 } 1328 printf("\n"); 1329 } 1330 /* 1331 ** SETOPTION -- set global processing option 1332 ** 1333 ** Parameters: 1334 ** opt -- option name. 1335 ** val -- option value (as a text string). 1336 ** safe -- set if this came from a configuration file. 1337 ** Some options (if set from the command line) will 1338 ** reset the user id to avoid security problems. 1339 ** sticky -- if set, don't let other setoptions override 1340 ** this value. 1341 ** e -- the main envelope. 1342 ** 1343 ** Returns: 1344 ** none. 1345 ** 1346 ** Side Effects: 1347 ** Sets options as implied by the arguments. 1348 */ 1349 1350 static BITMAP StickyOpt; /* set if option is stuck */ 1351 extern void settimeout __P((char *, char *)); 1352 1353 1354 #if NAMED_BIND 1355 1356 struct resolverflags 1357 { 1358 char *rf_name; /* name of the flag */ 1359 long rf_bits; /* bits to set/clear */ 1360 } ResolverFlags[] = 1361 { 1362 { "debug", RES_DEBUG }, 1363 { "aaonly", RES_AAONLY }, 1364 { "usevc", RES_USEVC }, 1365 { "primary", RES_PRIMARY }, 1366 { "igntc", RES_IGNTC }, 1367 { "recurse", RES_RECURSE }, 1368 { "defnames", RES_DEFNAMES }, 1369 { "stayopen", RES_STAYOPEN }, 1370 { "dnsrch", RES_DNSRCH }, 1371 { "true", 0 }, /* avoid error on old syntax */ 1372 { NULL, 0 } 1373 }; 1374 1375 #endif 1376 1377 struct optioninfo 1378 { 1379 char *o_name; /* long name of option */ 1380 u_char o_code; /* short name of option */ 1381 bool o_safe; /* safe for random people to use */ 1382 } OptionTab[] = 1383 { 1384 { "SevenBitInput", '7', TRUE }, 1385 #if MIME8TO7 1386 { "EightBitMode", '8', TRUE }, 1387 #endif 1388 { "AliasFile", 'A', FALSE }, 1389 { "AliasWait", 'a', FALSE }, 1390 { "BlankSub", 'B', FALSE }, 1391 { "MinFreeBlocks", 'b', TRUE }, 1392 { "CheckpointInterval", 'C', TRUE }, 1393 { "HoldExpensive", 'c', FALSE }, 1394 { "AutoRebuildAliases", 'D', FALSE }, 1395 { "DeliveryMode", 'd', TRUE }, 1396 { "ErrorHeader", 'E', FALSE }, 1397 { "ErrorMode", 'e', TRUE }, 1398 { "TempFileMode", 'F', FALSE }, 1399 { "SaveFromLine", 'f', FALSE }, 1400 { "MatchGECOS", 'G', FALSE }, 1401 { "HelpFile", 'H', FALSE }, 1402 { "MaxHopCount", 'h', FALSE }, 1403 { "ResolverOptions", 'I', FALSE }, 1404 { "IgnoreDots", 'i', TRUE }, 1405 { "ForwardPath", 'J', FALSE }, 1406 { "SendMimeErrors", 'j', TRUE }, 1407 { "ConnectionCacheSize", 'k', FALSE }, 1408 { "ConnectionCacheTimeout", 'K', FALSE }, 1409 { "UseErrorsTo", 'l', FALSE }, 1410 { "LogLevel", 'L', TRUE }, 1411 { "MeToo", 'm', TRUE }, 1412 { "CheckAliases", 'n', FALSE }, 1413 { "OldStyleHeaders", 'o', TRUE }, 1414 { "DaemonPortOptions", 'O', FALSE }, 1415 { "PrivacyOptions", 'p', TRUE }, 1416 { "PostmasterCopy", 'P', FALSE }, 1417 { "QueueFactor", 'q', FALSE }, 1418 { "QueueDirectory", 'Q', FALSE }, 1419 { "DontPruneRoutes", 'R', FALSE }, 1420 { "Timeout", 'r', FALSE }, 1421 { "StatusFile", 'S', FALSE }, 1422 { "SuperSafe", 's', TRUE }, 1423 { "QueueTimeout", 'T', FALSE }, 1424 { "TimeZoneSpec", 't', FALSE }, 1425 { "UserDatabaseSpec", 'U', FALSE }, 1426 { "DefaultUser", 'u', FALSE }, 1427 { "FallbackMXhost", 'V', FALSE }, 1428 { "Verbose", 'v', TRUE }, 1429 { "TryNullMXList", 'w', FALSE }, 1430 { "QueueLA", 'x', FALSE }, 1431 { "RefuseLA", 'X', FALSE }, 1432 { "RecipientFactor", 'y', FALSE }, 1433 { "ForkEachJob", 'Y', FALSE }, 1434 { "ClassFactor", 'z', FALSE }, 1435 { "RetryFactor", 'Z', FALSE }, 1436 #define O_QUEUESORTORD 0x81 1437 { "QueueSortOrder", O_QUEUESORTORD, TRUE }, 1438 #define O_HOSTSFILE 0x82 1439 { "HostsFile", O_HOSTSFILE, FALSE }, 1440 #define O_MQA 0x83 1441 { "MinQueueAge", O_MQA, TRUE }, 1442 #define O_DEFCHARSET 0x85 1443 { "DefaultCharSet", O_DEFCHARSET, TRUE }, 1444 #define O_SSFILE 0x86 1445 { "ServiceSwitchFile", O_SSFILE, FALSE }, 1446 #define O_DIALDELAY 0x87 1447 { "DialDelay", O_DIALDELAY, TRUE }, 1448 #define O_NORCPTACTION 0x88 1449 { "NoRecipientAction", O_NORCPTACTION, TRUE }, 1450 #define O_SAFEFILEENV 0x89 1451 { "SafeFileEnvironment", O_SAFEFILEENV, FALSE }, 1452 #define O_MAXMSGSIZE 0x8a 1453 { "MaxMessageSize", O_MAXMSGSIZE, FALSE }, 1454 #define O_COLONOKINADDR 0x8b 1455 { "ColonOkInAddr", O_COLONOKINADDR, TRUE }, 1456 #define O_MAXQUEUERUN 0x8c 1457 { "MaxQueueRunSize", O_MAXQUEUERUN, TRUE }, 1458 #define O_MAXCHILDREN 0x8d 1459 { "MaxDaemonChildren", O_MAXCHILDREN, FALSE }, 1460 #define O_KEEPCNAMES 0x8e 1461 { "DontExpandCnames", O_KEEPCNAMES, FALSE }, 1462 #define O_MUSTQUOTE 0x8f 1463 { "MustQuoteChars", O_MUSTQUOTE, FALSE }, 1464 #define O_SMTPGREETING 0x90 1465 { "SmtpGreetingMessage", O_SMTPGREETING, FALSE }, 1466 #define O_UNIXFROM 0x91 1467 { "UnixFromLine", O_UNIXFROM, FALSE }, 1468 #define O_OPCHARS 0x92 1469 { "OperatorChars", O_OPCHARS, FALSE }, 1470 #define O_DONTINITGRPS 0x93 1471 { "DontInitGroups", O_DONTINITGRPS, FALSE }, 1472 #define O_SLFH 0x94 1473 { "SingleLineFromHeader", O_SLFH, TRUE }, 1474 #define O_ABH 0x95 1475 { "AllowBogusHELO", O_ABH, TRUE }, 1476 #define O_CONNTHROT 0x97 1477 { "ConnectionRateThrottle", O_CONNTHROT, FALSE }, 1478 #define O_UGW 0x99 1479 { "UnsafeGroupWrites", O_UGW, FALSE }, 1480 #define O_DBLBOUNCE 0x9a 1481 { "DoubleBounceAddress", O_DBLBOUNCE, FALSE }, 1482 #define O_HSDIR 0x9b 1483 { "HostStatusDirectory", O_HSDIR, FALSE }, 1484 #define O_SINGTHREAD 0x9c 1485 { "SingleThreadDelivery", O_SINGTHREAD, FALSE }, 1486 #define O_RUNASUSER 0x9d 1487 { "RunAsUser", O_RUNASUSER, FALSE }, 1488 #if _FFR_DSN_RRT_OPTION 1489 #define O_DSN_RRT 0x9e 1490 { "RrtImpliesDsn", O_DSN_RRT, FALSE }, 1491 #endif 1492 #if _FFR_PIDFILE_OPTION 1493 #define O_PIDFILE 0x9f 1494 { "PidFile", O_PIDFILE, FALSE }, 1495 #endif 1496 #define O_DONTBLAMESENDMAIL 0xa0 1497 { "DontBlameSendmail", O_DONTBLAMESENDMAIL, FALSE }, 1498 #define O_DPI 0xa1 1499 { "DontProbeInterfaces", O_DPI, FALSE }, 1500 #define O_MAXRCPT 0xa2 1501 { "MaxRecipientsPerMessage", O_MAXRCPT, FALSE }, 1502 #if _FFR_DEADLETTERDROP_OPTION 1503 #define O_DEADLETTER 0xa3 1504 { "DeadLetterDrop", O_DEADLETTER, FALSE }, 1505 #endif 1506 #if _FFR_DONTLOCKFILESFORREAD_OPTION 1507 #define O_DONTLOCK 0xa4 1508 { "DontLockFilesForRead", O_DONTLOCK, FALSE }, 1509 #endif 1510 #if _FFR_MAXALIASRECURSION_OPTION 1511 #define O_MAXALIASRCSN 0xa5 1512 { "MaxAliasRecursion", O_MAXALIASRCSN, FALSE }, 1513 #endif 1514 #if _FFR_CONNECTONLYTO_OPTION 1515 #define O_CNCTONLYTO 0xa6 1516 { "ConnectOnlyTo", O_CNCTONLYTO, FALSE }, 1517 #endif 1518 #if _FFR_TRUSTED_USER 1519 #define O_TRUSTUSER 0xa7 1520 { "TrustedUser", O_TRUSTUSER, FALSE }, 1521 #endif 1522 #if _FFR_MAX_MIME_HEADER_LENGTH 1523 #define O_MAXMIMEHDRLEN 0xa8 1524 { "MaxMimeHeaderLength", O_MAXMIMEHDRLEN, FALSE }, 1525 #endif 1526 #if _FFR_CONTROL_SOCKET 1527 #define O_CONTROLSOCKET 0xa9 1528 { "ControlSocketName", O_CONTROLSOCKET, FALSE }, 1529 #endif 1530 #if _FFR_MAX_HEADERS_LENGTH 1531 #define O_MAXHDRSLEN 0xaa 1532 { "MaxHeadersLength", O_MAXHDRSLEN, FALSE }, 1533 #endif 1534 { NULL, '\0', FALSE } 1535 }; 1536 1537 1538 1539 void 1540 setoption(opt, val, safe, sticky, e) 1541 int opt; 1542 char *val; 1543 bool safe; 1544 bool sticky; 1545 register ENVELOPE *e; 1546 { 1547 register char *p; 1548 register struct optioninfo *o; 1549 char *subopt; 1550 int mid; 1551 bool can_setuid = RunAsUid == 0; 1552 auto char *ep; 1553 char buf[50]; 1554 extern bool atobool __P((char *)); 1555 extern time_t convtime __P((char *, char)); 1556 extern int QueueLA; 1557 extern int RefuseLA; 1558 extern bool Warn_Q_option; 1559 extern void setalias __P((char *)); 1560 extern int atooct __P((char *)); 1561 extern void setdefuser __P((void)); 1562 extern void setdaemonoptions __P((char *)); 1563 1564 errno = 0; 1565 if (opt == ' ') 1566 { 1567 /* full word options */ 1568 struct optioninfo *sel; 1569 1570 p = strchr(val, '='); 1571 if (p == NULL) 1572 p = &val[strlen(val)]; 1573 while (*--p == ' ') 1574 continue; 1575 while (*++p == ' ') 1576 *p = '\0'; 1577 if (p == val) 1578 { 1579 syserr("readcf: null option name"); 1580 return; 1581 } 1582 if (*p == '=') 1583 *p++ = '\0'; 1584 while (*p == ' ') 1585 p++; 1586 subopt = strchr(val, '.'); 1587 if (subopt != NULL) 1588 *subopt++ = '\0'; 1589 sel = NULL; 1590 for (o = OptionTab; o->o_name != NULL; o++) 1591 { 1592 if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1593 continue; 1594 if (strlen(o->o_name) == strlen(val)) 1595 { 1596 /* completely specified -- this must be it */ 1597 sel = NULL; 1598 break; 1599 } 1600 if (sel != NULL) 1601 break; 1602 sel = o; 1603 } 1604 if (sel != NULL && o->o_name == NULL) 1605 o = sel; 1606 else if (o->o_name == NULL) 1607 { 1608 syserr("readcf: unknown option name %s", val); 1609 return; 1610 } 1611 else if (sel != NULL) 1612 { 1613 syserr("readcf: ambiguous option name %s (matches %s and %s)", 1614 val, sel->o_name, o->o_name); 1615 return; 1616 } 1617 if (strlen(val) != strlen(o->o_name)) 1618 { 1619 int oldVerbose = Verbose; 1620 1621 Verbose = 1; 1622 message("Option %s used as abbreviation for %s", 1623 val, o->o_name); 1624 Verbose = oldVerbose; 1625 } 1626 opt = o->o_code; 1627 val = p; 1628 } 1629 else 1630 { 1631 for (o = OptionTab; o->o_name != NULL; o++) 1632 { 1633 if (o->o_code == opt) 1634 break; 1635 } 1636 subopt = NULL; 1637 } 1638 1639 if (tTd(37, 1)) 1640 { 1641 printf(isascii(opt) && isprint(opt) ? 1642 "setoption %s (%c).%s=" : 1643 "setoption %s (0x%x).%s=", 1644 o->o_name == NULL ? "<unknown>" : o->o_name, 1645 opt, 1646 subopt == NULL ? "" : subopt); 1647 xputs(val); 1648 } 1649 1650 /* 1651 ** See if this option is preset for us. 1652 */ 1653 1654 if (!sticky && bitnset(opt, StickyOpt)) 1655 { 1656 if (tTd(37, 1)) 1657 printf(" (ignored)\n"); 1658 return; 1659 } 1660 1661 /* 1662 ** Check to see if this option can be specified by this user. 1663 */ 1664 1665 if (!safe && RealUid == 0) 1666 safe = TRUE; 1667 if (!safe && !o->o_safe) 1668 { 1669 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 1670 { 1671 if (tTd(37, 1)) 1672 printf(" (unsafe)"); 1673 (void) drop_privileges(TRUE); 1674 } 1675 } 1676 if (tTd(37, 1)) 1677 printf("\n"); 1678 1679 switch (opt & 0xff) 1680 { 1681 case '7': /* force seven-bit input */ 1682 SevenBitInput = atobool(val); 1683 break; 1684 1685 #if MIME8TO7 1686 case '8': /* handling of 8-bit input */ 1687 switch (*val) 1688 { 1689 case 'm': /* convert 8-bit, convert MIME */ 1690 MimeMode = MM_CVTMIME|MM_MIME8BIT; 1691 break; 1692 1693 case 'p': /* pass 8 bit, convert MIME */ 1694 MimeMode = MM_CVTMIME|MM_PASS8BIT; 1695 break; 1696 1697 case 's': /* strict adherence */ 1698 MimeMode = MM_CVTMIME; 1699 break; 1700 1701 #if 0 1702 case 'r': /* reject 8-bit, don't convert MIME */ 1703 MimeMode = 0; 1704 break; 1705 1706 case 'j': /* "just send 8" */ 1707 MimeMode = MM_PASS8BIT; 1708 break; 1709 1710 case 'a': /* encode 8 bit if available */ 1711 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1712 break; 1713 1714 case 'c': /* convert 8 bit to MIME, never 7 bit */ 1715 MimeMode = MM_MIME8BIT; 1716 break; 1717 #endif 1718 1719 default: 1720 syserr("Unknown 8-bit mode %c", *val); 1721 finis(FALSE, EX_USAGE); 1722 } 1723 break; 1724 #endif 1725 1726 case 'A': /* set default alias file */ 1727 if (val[0] == '\0') 1728 setalias("aliases"); 1729 else 1730 setalias(val); 1731 break; 1732 1733 case 'a': /* look N minutes for "@:@" in alias file */ 1734 if (val[0] == '\0') 1735 SafeAlias = 5 * 60; /* five minutes */ 1736 else 1737 SafeAlias = convtime(val, 'm'); 1738 break; 1739 1740 case 'B': /* substitution for blank character */ 1741 SpaceSub = val[0]; 1742 if (SpaceSub == '\0') 1743 SpaceSub = ' '; 1744 break; 1745 1746 case 'b': /* min blocks free on queue fs/max msg size */ 1747 p = strchr(val, '/'); 1748 if (p != NULL) 1749 { 1750 *p++ = '\0'; 1751 MaxMessageSize = atol(p); 1752 } 1753 MinBlocksFree = atol(val); 1754 break; 1755 1756 case 'c': /* don't connect to "expensive" mailers */ 1757 NoConnect = atobool(val); 1758 break; 1759 1760 case 'C': /* checkpoint every N addresses */ 1761 CheckpointInterval = atoi(val); 1762 break; 1763 1764 case 'd': /* delivery mode */ 1765 switch (*val) 1766 { 1767 case '\0': 1768 e->e_sendmode = SM_DELIVER; 1769 break; 1770 1771 case SM_QUEUE: /* queue only */ 1772 case SM_DEFER: /* queue only and defer map lookups */ 1773 #if !QUEUE 1774 syserr("need QUEUE to set -odqueue or -oddefer"); 1775 #endif /* QUEUE */ 1776 /* fall through..... */ 1777 1778 case SM_DELIVER: /* do everything */ 1779 case SM_FORK: /* fork after verification */ 1780 e->e_sendmode = *val; 1781 break; 1782 1783 default: 1784 syserr("Unknown delivery mode %c", *val); 1785 finis(FALSE, EX_USAGE); 1786 } 1787 buf[0] = (char)e->e_sendmode; 1788 buf[1] = '\0'; 1789 define(macid("{deliveryMode}", NULL), newstr(buf), e); 1790 break; 1791 1792 case 'D': /* rebuild alias database as needed */ 1793 AutoRebuild = atobool(val); 1794 break; 1795 1796 case 'E': /* error message header/header file */ 1797 if (*val != '\0') 1798 ErrMsgFile = newstr(val); 1799 break; 1800 1801 case 'e': /* set error processing mode */ 1802 switch (*val) 1803 { 1804 case EM_QUIET: /* be silent about it */ 1805 case EM_MAIL: /* mail back */ 1806 case EM_BERKNET: /* do berknet error processing */ 1807 case EM_WRITE: /* write back (or mail) */ 1808 case EM_PRINT: /* print errors normally (default) */ 1809 e->e_errormode = *val; 1810 break; 1811 } 1812 break; 1813 1814 case 'F': /* file mode */ 1815 FileMode = atooct(val) & 0777; 1816 break; 1817 1818 case 'f': /* save Unix-style From lines on front */ 1819 SaveFrom = atobool(val); 1820 break; 1821 1822 case 'G': /* match recipients against GECOS field */ 1823 MatchGecos = atobool(val); 1824 break; 1825 1826 case 'g': /* default gid */ 1827 g_opt: 1828 if (isascii(*val) && isdigit(*val)) 1829 DefGid = atoi(val); 1830 else 1831 { 1832 register struct group *gr; 1833 1834 DefGid = -1; 1835 gr = getgrnam(val); 1836 if (gr == NULL) 1837 syserr("readcf: option %c: unknown group %s", 1838 opt, val); 1839 else 1840 DefGid = gr->gr_gid; 1841 } 1842 break; 1843 1844 case 'H': /* help file */ 1845 if (val[0] == '\0') 1846 HelpFile = "sendmail.hf"; 1847 else 1848 HelpFile = newstr(val); 1849 break; 1850 1851 case 'h': /* maximum hop count */ 1852 MaxHopCount = atoi(val); 1853 break; 1854 1855 case 'I': /* use internet domain name server */ 1856 #if NAMED_BIND 1857 for (p = val; *p != 0; ) 1858 { 1859 bool clearmode; 1860 char *q; 1861 struct resolverflags *rfp; 1862 1863 while (*p == ' ') 1864 p++; 1865 if (*p == '\0') 1866 break; 1867 clearmode = FALSE; 1868 if (*p == '-') 1869 clearmode = TRUE; 1870 else if (*p != '+') 1871 p--; 1872 p++; 1873 q = p; 1874 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1875 p++; 1876 if (*p != '\0') 1877 *p++ = '\0'; 1878 if (strcasecmp(q, "HasWildcardMX") == 0) 1879 { 1880 HasWildcardMX = !clearmode; 1881 continue; 1882 } 1883 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 1884 { 1885 if (strcasecmp(q, rfp->rf_name) == 0) 1886 break; 1887 } 1888 if (rfp->rf_name == NULL) 1889 syserr("readcf: I option value %s unrecognized", q); 1890 else if (clearmode) 1891 _res.options &= ~rfp->rf_bits; 1892 else 1893 _res.options |= rfp->rf_bits; 1894 } 1895 if (tTd(8, 2)) 1896 printf("_res.options = %x, HasWildcardMX = %d\n", 1897 (u_int) _res.options, HasWildcardMX); 1898 #else 1899 usrerr("name server (I option) specified but BIND not compiled in"); 1900 #endif 1901 break; 1902 1903 case 'i': /* ignore dot lines in message */ 1904 IgnrDot = atobool(val); 1905 break; 1906 1907 case 'j': /* send errors in MIME (RFC 1341) format */ 1908 SendMIMEErrors = atobool(val); 1909 break; 1910 1911 case 'J': /* .forward search path */ 1912 ForwardPath = newstr(val); 1913 break; 1914 1915 case 'k': /* connection cache size */ 1916 MaxMciCache = atoi(val); 1917 if (MaxMciCache < 0) 1918 MaxMciCache = 0; 1919 break; 1920 1921 case 'K': /* connection cache timeout */ 1922 MciCacheTimeout = convtime(val, 'm'); 1923 break; 1924 1925 case 'l': /* use Errors-To: header */ 1926 UseErrorsTo = atobool(val); 1927 break; 1928 1929 case 'L': /* log level */ 1930 if (safe || LogLevel < atoi(val)) 1931 LogLevel = atoi(val); 1932 break; 1933 1934 case 'M': /* define macro */ 1935 mid = macid(val, &ep); 1936 p = newstr(ep); 1937 if (!safe) 1938 cleanstrcpy(p, p, MAXNAME); 1939 define(mid, p, CurEnv); 1940 sticky = FALSE; 1941 break; 1942 1943 case 'm': /* send to me too */ 1944 MeToo = atobool(val); 1945 break; 1946 1947 case 'n': /* validate RHS in newaliases */ 1948 CheckAliases = atobool(val); 1949 break; 1950 1951 /* 'N' available -- was "net name" */ 1952 1953 case 'O': /* daemon options */ 1954 #if DAEMON 1955 setdaemonoptions(val); 1956 #else 1957 syserr("DaemonPortOptions (O option) set but DAEMON not compiled in"); 1958 #endif 1959 break; 1960 1961 case 'o': /* assume old style headers */ 1962 if (atobool(val)) 1963 CurEnv->e_flags |= EF_OLDSTYLE; 1964 else 1965 CurEnv->e_flags &= ~EF_OLDSTYLE; 1966 break; 1967 1968 case 'p': /* select privacy level */ 1969 p = val; 1970 for (;;) 1971 { 1972 register struct prival *pv; 1973 extern struct prival PrivacyValues[]; 1974 1975 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 1976 p++; 1977 if (*p == '\0') 1978 break; 1979 val = p; 1980 while (isascii(*p) && isalnum(*p)) 1981 p++; 1982 if (*p != '\0') 1983 *p++ = '\0'; 1984 1985 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 1986 { 1987 if (strcasecmp(val, pv->pv_name) == 0) 1988 break; 1989 } 1990 if (pv->pv_name == NULL) 1991 syserr("readcf: Op line: %s unrecognized", val); 1992 PrivacyFlags |= pv->pv_flag; 1993 } 1994 sticky = FALSE; 1995 break; 1996 1997 case 'P': /* postmaster copy address for returned mail */ 1998 PostMasterCopy = newstr(val); 1999 break; 2000 2001 case 'q': /* slope of queue only function */ 2002 QueueFactor = atoi(val); 2003 break; 2004 2005 case 'Q': /* queue directory */ 2006 if (val[0] == '\0') 2007 QueueDir = "mqueue"; 2008 else 2009 QueueDir = newstr(val); 2010 if (RealUid != 0 && !safe) 2011 Warn_Q_option = TRUE; 2012 break; 2013 2014 case 'R': /* don't prune routes */ 2015 DontPruneRoutes = atobool(val); 2016 break; 2017 2018 case 'r': /* read timeout */ 2019 if (subopt == NULL) 2020 inittimeouts(val); 2021 else 2022 settimeout(subopt, val); 2023 break; 2024 2025 case 'S': /* status file */ 2026 if (val[0] == '\0') 2027 StatFile = "sendmail.st"; 2028 else 2029 StatFile = newstr(val); 2030 break; 2031 2032 case 's': /* be super safe, even if expensive */ 2033 SuperSafe = atobool(val); 2034 break; 2035 2036 case 'T': /* queue timeout */ 2037 p = strchr(val, '/'); 2038 if (p != NULL) 2039 { 2040 *p++ = '\0'; 2041 settimeout("queuewarn", p); 2042 } 2043 settimeout("queuereturn", val); 2044 break; 2045 2046 case 't': /* time zone name */ 2047 TimeZoneSpec = newstr(val); 2048 break; 2049 2050 case 'U': /* location of user database */ 2051 UdbSpec = newstr(val); 2052 break; 2053 2054 case 'u': /* set default uid */ 2055 for (p = val; *p != '\0'; p++) 2056 { 2057 if (*p == '.' || *p == '/' || *p == ':') 2058 { 2059 *p++ = '\0'; 2060 break; 2061 } 2062 } 2063 if (isascii(*val) && isdigit(*val)) 2064 { 2065 DefUid = atoi(val); 2066 setdefuser(); 2067 } 2068 else 2069 { 2070 register struct passwd *pw; 2071 2072 DefUid = -1; 2073 pw = sm_getpwnam(val); 2074 if (pw == NULL) 2075 syserr("readcf: option u: unknown user %s", val); 2076 else 2077 { 2078 DefUid = pw->pw_uid; 2079 DefGid = pw->pw_gid; 2080 DefUser = newstr(pw->pw_name); 2081 } 2082 } 2083 2084 #ifdef UID_MAX 2085 if (DefUid > UID_MAX) 2086 { 2087 syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored", 2088 DefUid, UID_MAX); 2089 } 2090 #endif 2091 2092 /* handle the group if it is there */ 2093 if (*p == '\0') 2094 break; 2095 val = p; 2096 goto g_opt; 2097 2098 case 'V': /* fallback MX host */ 2099 if (val[0] != '\0') 2100 FallBackMX = newstr(val); 2101 break; 2102 2103 case 'v': /* run in verbose mode */ 2104 Verbose = atobool(val) ? 1 : 0; 2105 break; 2106 2107 case 'w': /* if we are best MX, try host directly */ 2108 TryNullMXList = atobool(val); 2109 break; 2110 2111 /* 'W' available -- was wizard password */ 2112 2113 case 'x': /* load avg at which to auto-queue msgs */ 2114 QueueLA = atoi(val); 2115 break; 2116 2117 case 'X': /* load avg at which to auto-reject connections */ 2118 RefuseLA = atoi(val); 2119 break; 2120 2121 case 'y': /* work recipient factor */ 2122 WkRecipFact = atoi(val); 2123 break; 2124 2125 case 'Y': /* fork jobs during queue runs */ 2126 ForkQueueRuns = atobool(val); 2127 break; 2128 2129 case 'z': /* work message class factor */ 2130 WkClassFact = atoi(val); 2131 break; 2132 2133 case 'Z': /* work time factor */ 2134 WkTimeFact = atoi(val); 2135 break; 2136 2137 case O_QUEUESORTORD: /* queue sorting order */ 2138 switch (*val) 2139 { 2140 case 'h': /* Host first */ 2141 case 'H': 2142 QueueSortOrder = QS_BYHOST; 2143 break; 2144 2145 case 'p': /* Priority order */ 2146 case 'P': 2147 QueueSortOrder = QS_BYPRIORITY; 2148 break; 2149 2150 case 't': /* Submission time */ 2151 case 'T': 2152 QueueSortOrder = QS_BYTIME; 2153 break; 2154 2155 default: 2156 syserr("Invalid queue sort order \"%s\"", val); 2157 } 2158 break; 2159 2160 case O_HOSTSFILE: /* pathname of /etc/hosts file */ 2161 HostsFile = newstr(val); 2162 break; 2163 2164 case O_MQA: /* minimum queue age between deliveries */ 2165 MinQueueAge = convtime(val, 'm'); 2166 break; 2167 2168 case O_DEFCHARSET: /* default character set for mimefying */ 2169 DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 2170 break; 2171 2172 case O_SSFILE: /* service switch file */ 2173 ServiceSwitchFile = newstr(val); 2174 break; 2175 2176 case O_DIALDELAY: /* delay for dial-on-demand operation */ 2177 DialDelay = convtime(val, 's'); 2178 break; 2179 2180 case O_NORCPTACTION: /* what to do if no recipient */ 2181 if (strcasecmp(val, "none") == 0) 2182 NoRecipientAction = NRA_NO_ACTION; 2183 else if (strcasecmp(val, "add-to") == 0) 2184 NoRecipientAction = NRA_ADD_TO; 2185 else if (strcasecmp(val, "add-apparently-to") == 0) 2186 NoRecipientAction = NRA_ADD_APPARENTLY_TO; 2187 else if (strcasecmp(val, "add-bcc") == 0) 2188 NoRecipientAction = NRA_ADD_BCC; 2189 else if (strcasecmp(val, "add-to-undisclosed") == 0) 2190 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 2191 else 2192 syserr("Invalid NoRecipientAction: %s", val); 2193 break; 2194 2195 case O_SAFEFILEENV: /* chroot() environ for writing to files */ 2196 SafeFileEnv = newstr(val); 2197 break; 2198 2199 case O_MAXMSGSIZE: /* maximum message size */ 2200 MaxMessageSize = atol(val); 2201 break; 2202 2203 case O_COLONOKINADDR: /* old style handling of colon addresses */ 2204 ColonOkInAddr = atobool(val); 2205 break; 2206 2207 case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 2208 MaxQueueRun = atol(val); 2209 break; 2210 2211 case O_MAXCHILDREN: /* max # of children of daemon */ 2212 MaxChildren = atoi(val); 2213 break; 2214 2215 case O_KEEPCNAMES: /* don't expand CNAME records */ 2216 DontExpandCnames = atobool(val); 2217 break; 2218 2219 case O_MUSTQUOTE: /* must quote these characters in phrases */ 2220 strcpy(buf, "@,;:\\()[]"); 2221 if (strlen(val) < (SIZE_T) sizeof buf - 10) 2222 strcat(buf, val); 2223 MustQuoteChars = newstr(buf); 2224 break; 2225 2226 case O_SMTPGREETING: /* SMTP greeting message (old $e macro) */ 2227 SmtpGreeting = newstr(munchstring(val, NULL, '\0')); 2228 break; 2229 2230 case O_UNIXFROM: /* UNIX From_ line (old $l macro) */ 2231 UnixFromLine = newstr(munchstring(val, NULL, '\0')); 2232 break; 2233 2234 case O_OPCHARS: /* operator characters (old $o macro) */ 2235 OperatorChars = newstr(munchstring(val, NULL, '\0')); 2236 break; 2237 2238 case O_DONTINITGRPS: /* don't call initgroups(3) */ 2239 DontInitGroups = atobool(val); 2240 break; 2241 2242 case O_SLFH: /* make sure from fits on one line */ 2243 SingleLineFromHeader = atobool(val); 2244 break; 2245 2246 case O_ABH: /* allow HELO commands with syntax errors */ 2247 AllowBogusHELO = atobool(val); 2248 break; 2249 2250 case O_CONNTHROT: /* connection rate throttle */ 2251 ConnRateThrottle = atoi(val); 2252 break; 2253 2254 case O_UGW: /* group writable files are unsafe */ 2255 if (!atobool(val)) 2256 DontBlameSendmail |= DBS_GROUPWRITABLEFORWARDFILESAFE|DBS_GROUPWRITABLEINCLUDEFILESAFE; 2257 break; 2258 2259 case O_DBLBOUNCE: /* address to which to send double bounces */ 2260 if (val[0] != '\0') 2261 DoubleBounceAddr = newstr(val); 2262 else 2263 syserr("readcf: option DoubleBounceAddress: value required"); 2264 break; 2265 2266 case O_HSDIR: /* persistent host status directory */ 2267 if (val[0] != '\0') 2268 HostStatDir = newstr(val); 2269 break; 2270 2271 case O_SINGTHREAD: /* single thread deliveries (requires hsdir) */ 2272 SingleThreadDelivery = atobool(val); 2273 break; 2274 2275 case O_RUNASUSER: /* run bulk of code as this user */ 2276 for (p = val; *p != '\0'; p++) 2277 { 2278 if (*p == '.' || *p == '/' || *p == ':') 2279 { 2280 *p++ = '\0'; 2281 break; 2282 } 2283 } 2284 if (isascii(*val) && isdigit(*val)) 2285 { 2286 if (can_setuid) 2287 RunAsUid = atoi(val); 2288 } 2289 else 2290 { 2291 register struct passwd *pw; 2292 2293 pw = sm_getpwnam(val); 2294 if (pw == NULL) 2295 syserr("readcf: option RunAsUser: unknown user %s", val); 2296 else if (can_setuid) 2297 { 2298 if (*p == '\0') 2299 RunAsUserName = newstr(val); 2300 RunAsUid = pw->pw_uid; 2301 RunAsGid = pw->pw_gid; 2302 } 2303 } 2304 #ifdef UID_MAX 2305 if (RunAsUid > UID_MAX) 2306 { 2307 syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored", 2308 RunAsUid, UID_MAX); 2309 } 2310 #endif 2311 if (*p != '\0') 2312 { 2313 if (isascii(*p) && isdigit(*p)) 2314 { 2315 if (can_setuid) 2316 RunAsGid = atoi(p); 2317 } 2318 else 2319 { 2320 register struct group *gr; 2321 2322 gr = getgrnam(p); 2323 if (gr == NULL) 2324 syserr("readcf: option RunAsUser: unknown group %s", 2325 p); 2326 else if (can_setuid) 2327 RunAsGid = gr->gr_gid; 2328 } 2329 } 2330 if (tTd(47, 5)) 2331 printf("readcf: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid); 2332 break; 2333 2334 #if _FFR_DSN_RRT_OPTION 2335 case O_DSN_RRT: 2336 RrtImpliesDsn = atobool(val); 2337 break; 2338 #endif 2339 2340 #if _FFR_PIDFILE_OPTION 2341 case O_PIDFILE: 2342 free(PidFile); 2343 PidFile = newstr(val); 2344 break; 2345 #endif 2346 2347 case O_DONTBLAMESENDMAIL: 2348 p = val; 2349 for (;;) 2350 { 2351 register struct dbsval *dbs; 2352 extern struct dbsval DontBlameSendmailValues[]; 2353 2354 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 2355 p++; 2356 if (*p == '\0') 2357 break; 2358 val = p; 2359 while (isascii(*p) && isalnum(*p)) 2360 p++; 2361 if (*p != '\0') 2362 *p++ = '\0'; 2363 2364 for (dbs = DontBlameSendmailValues; 2365 dbs->dbs_name != NULL; dbs++) 2366 { 2367 if (strcasecmp(val, dbs->dbs_name) == 0) 2368 break; 2369 } 2370 if (dbs->dbs_name == NULL) 2371 syserr("readcf: DontBlameSendmail option: %s unrecognized", val); 2372 else if (dbs->dbs_flag == DBS_SAFE) 2373 DontBlameSendmail = DBS_SAFE; 2374 else 2375 DontBlameSendmail |= dbs->dbs_flag; 2376 } 2377 sticky = FALSE; 2378 break; 2379 2380 case O_DPI: 2381 DontProbeInterfaces = atobool(val); 2382 break; 2383 2384 case O_MAXRCPT: 2385 MaxRcptPerMsg = atoi(val); 2386 break; 2387 2388 #if _FFR_DEADLETTERDROP_OPTION 2389 case O_DEADLETTER: 2390 if (DeadLetterDrop != NULL) 2391 free(DeadLetterDrop); 2392 DeadLetterDrop = newstr(val); 2393 break; 2394 #endif 2395 2396 #if _FFR_DONTLOCKFILESFORREAD_OPTION 2397 case O_DONTLOCK: 2398 DontLockReadFiles = atobool(val); 2399 break; 2400 #endif 2401 2402 #if _FFR_MAXALIASRECURSION_OPTION 2403 case O_MAXALIASRCSN: 2404 MaxAliasRecursion = atoi(val); 2405 break; 2406 #endif 2407 2408 #if _FFR_CONNECTONLYTO_OPTION 2409 case O_CNCTONLYTO: 2410 /* XXX should probably use gethostbyname */ 2411 ConnectOnlyTo = inet_addr(val); 2412 break; 2413 #endif 2414 2415 #if _FFR_TRUSTED_USER 2416 case O_TRUSTUSER: 2417 if (isascii(*val) && isdigit(*val)) 2418 TrustedUid = atoi(val); 2419 else 2420 { 2421 register struct passwd *pw; 2422 2423 TrustedUid = 0; 2424 pw = sm_getpwnam(val); 2425 if (pw == NULL) 2426 syserr("readcf: option TrustedUser: unknown user %s", val); 2427 else 2428 TrustedUid = pw->pw_uid; 2429 } 2430 2431 #ifdef UID_MAX 2432 if (TrustedUid > UID_MAX) 2433 { 2434 syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)", 2435 TrustedUid, UID_MAX); 2436 TrustedUid = 0; 2437 } 2438 #endif 2439 break; 2440 #endif 2441 2442 #if _FFR_MAX_MIME_HEADER_LENGTH 2443 case O_MAXMIMEHDRLEN: 2444 p = strchr(val, '/'); 2445 if (p != NULL) 2446 *p++ = '\0'; 2447 MaxMimeHeaderLength = atoi(val); 2448 if (p != NULL && *p != '\0') 2449 MaxMimeFieldLength = atoi(p); 2450 else 2451 MaxMimeFieldLength = MaxMimeHeaderLength / 2; 2452 2453 if (MaxMimeHeaderLength < 0) 2454 MaxMimeHeaderLength = 0; 2455 else if (MaxMimeHeaderLength < 128) 2456 printf("Warning: MaxMimeHeaderLength: header length limit set lower than 128\n"); 2457 2458 if (MaxMimeFieldLength < 0) 2459 MaxMimeFieldLength = 0; 2460 else if (MaxMimeFieldLength < 40) 2461 printf("Warning: MaxMimeHeaderLength: field length limit set lower than 40\n"); 2462 break; 2463 #endif 2464 2465 #if _FFR_CONTROL_SOCKET 2466 case O_CONTROLSOCKET: 2467 if (ControlSocketName != NULL) 2468 free(ControlSocketName); 2469 ControlSocketName = newstr(val); 2470 break; 2471 #endif 2472 2473 #if _FFR_MAX_HEADERS_LENGTH 2474 case O_MAXHDRSLEN: 2475 MaxHeadersLength = atoi(val); 2476 2477 if (MaxHeadersLength > 0 && 2478 MaxHeadersLength < (MAXHDRSLEN / 2)) 2479 printf("Warning: MaxHeadersLength: headers length limit set lower than %d\n", MAXHDRSLEN); 2480 break; 2481 #endif 2482 2483 default: 2484 if (tTd(37, 1)) 2485 { 2486 if (isascii(opt) && isprint(opt)) 2487 printf("Warning: option %c unknown\n", opt); 2488 else 2489 printf("Warning: option 0x%x unknown\n", opt); 2490 } 2491 break; 2492 } 2493 if (sticky) 2494 setbitn(opt, StickyOpt); 2495 } 2496 /* 2497 ** SETCLASS -- set a string into a class 2498 ** 2499 ** Parameters: 2500 ** class -- the class to put the string in. 2501 ** str -- the string to enter 2502 ** 2503 ** Returns: 2504 ** none. 2505 ** 2506 ** Side Effects: 2507 ** puts the word into the symbol table. 2508 */ 2509 2510 void 2511 setclass(class, str) 2512 int class; 2513 char *str; 2514 { 2515 register STAB *s; 2516 2517 if (tTd(37, 8)) 2518 printf("setclass(%s, %s)\n", macname(class), str); 2519 s = stab(str, ST_CLASS, ST_ENTER); 2520 setbitn(class, s->s_class); 2521 } 2522 /* 2523 ** MAKEMAPENTRY -- create a map entry 2524 ** 2525 ** Parameters: 2526 ** line -- the config file line 2527 ** 2528 ** Returns: 2529 ** A pointer to the map that has been created. 2530 ** NULL if there was a syntax error. 2531 ** 2532 ** Side Effects: 2533 ** Enters the map into the dictionary. 2534 */ 2535 2536 MAP * 2537 makemapentry(line) 2538 char *line; 2539 { 2540 register char *p; 2541 char *mapname; 2542 char *classname; 2543 register STAB *s; 2544 STAB *class; 2545 2546 for (p = line; isascii(*p) && isspace(*p); p++) 2547 continue; 2548 if (!(isascii(*p) && isalnum(*p))) 2549 { 2550 syserr("readcf: config K line: no map name"); 2551 return NULL; 2552 } 2553 2554 mapname = p; 2555 while ((isascii(*++p) && isalnum(*p)) || *p == '_' || *p == '.') 2556 continue; 2557 if (*p != '\0') 2558 *p++ = '\0'; 2559 while (isascii(*p) && isspace(*p)) 2560 p++; 2561 if (!(isascii(*p) && isalnum(*p))) 2562 { 2563 syserr("readcf: config K line, map %s: no map class", mapname); 2564 return NULL; 2565 } 2566 classname = p; 2567 while (isascii(*++p) && isalnum(*p)) 2568 continue; 2569 if (*p != '\0') 2570 *p++ = '\0'; 2571 while (isascii(*p) && isspace(*p)) 2572 p++; 2573 2574 /* look up the class */ 2575 class = stab(classname, ST_MAPCLASS, ST_FIND); 2576 if (class == NULL) 2577 { 2578 syserr("readcf: map %s: class %s not available", mapname, classname); 2579 return NULL; 2580 } 2581 2582 /* enter the map */ 2583 s = stab(mapname, ST_MAP, ST_ENTER); 2584 s->s_map.map_class = &class->s_mapclass; 2585 s->s_map.map_mname = newstr(mapname); 2586 2587 if (class->s_mapclass.map_parse(&s->s_map, p)) 2588 s->s_map.map_mflags |= MF_VALID; 2589 2590 if (tTd(37, 5)) 2591 { 2592 printf("map %s, class %s, flags %lx, file %s,\n", 2593 s->s_map.map_mname, s->s_map.map_class->map_cname, 2594 s->s_map.map_mflags, 2595 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 2596 printf("\tapp %s, domain %s, rebuild %s\n", 2597 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 2598 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 2599 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 2600 } 2601 2602 return &s->s_map; 2603 } 2604 /* 2605 ** STRTORWSET -- convert string to rewriting set number 2606 ** 2607 ** Parameters: 2608 ** p -- the pointer to the string to decode. 2609 ** endp -- if set, store the trailing delimiter here. 2610 ** stabmode -- ST_ENTER to create this entry, ST_FIND if 2611 ** it must already exist. 2612 ** 2613 ** Returns: 2614 ** The appropriate ruleset number. 2615 ** -1 if it is not valid (error already printed) 2616 */ 2617 2618 int 2619 strtorwset(p, endp, stabmode) 2620 char *p; 2621 char **endp; 2622 int stabmode; 2623 { 2624 int ruleset; 2625 static int nextruleset = MAXRWSETS; 2626 2627 while (isascii(*p) && isspace(*p)) 2628 p++; 2629 if (!isascii(*p)) 2630 { 2631 syserr("invalid ruleset name: \"%.20s\"", p); 2632 return -1; 2633 } 2634 if (isdigit(*p)) 2635 { 2636 ruleset = strtol(p, endp, 10); 2637 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 2638 { 2639 syserr("bad ruleset %d (%d max)", 2640 ruleset, MAXRWSETS / 2); 2641 ruleset = -1; 2642 } 2643 } 2644 else 2645 { 2646 STAB *s; 2647 char delim; 2648 char *q; 2649 2650 q = p; 2651 while (*p != '\0' && isascii(*p) && 2652 (isalnum(*p) || *p == '_')) 2653 p++; 2654 if (q == p || !(isascii(*q) && isalpha(*q))) 2655 { 2656 /* no valid characters */ 2657 syserr("invalid ruleset name: \"%.20s\"", q); 2658 return -1; 2659 } 2660 while (isascii(*p) && isspace(*p)) 2661 *p++ = '\0'; 2662 delim = *p; 2663 if (delim != '\0') 2664 *p = '\0'; 2665 s = stab(q, ST_RULESET, stabmode); 2666 if (delim != '\0') 2667 *p = delim; 2668 2669 if (s == NULL) 2670 return -1; 2671 2672 if (stabmode == ST_ENTER && delim == '=') 2673 { 2674 while (isascii(*++p) && isspace(*p)) 2675 continue; 2676 if (!(isascii(*p) && isdigit(*p))) 2677 { 2678 syserr("bad ruleset definition \"%s\" (number required after `=')", q); 2679 ruleset = -1; 2680 } 2681 else 2682 { 2683 ruleset = strtol(p, endp, 10); 2684 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 2685 { 2686 syserr("bad ruleset number %d in \"%s\" (%d max)", 2687 ruleset, q, MAXRWSETS / 2); 2688 ruleset = -1; 2689 } 2690 } 2691 } 2692 else 2693 { 2694 if (endp != NULL) 2695 *endp = p; 2696 if (s->s_ruleset > 0) 2697 ruleset = s->s_ruleset; 2698 else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 2699 { 2700 syserr("%s: too many named rulesets (%d max)", 2701 q, MAXRWSETS / 2); 2702 ruleset = -1; 2703 } 2704 } 2705 if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset) 2706 { 2707 syserr("%s: ruleset changed value (old %d, new %d)", 2708 q, s->s_ruleset, ruleset); 2709 ruleset = s->s_ruleset; 2710 } 2711 else if (ruleset > 0) 2712 { 2713 s->s_ruleset = ruleset; 2714 } 2715 } 2716 return ruleset; 2717 } 2718 /* 2719 ** INITTIMEOUTS -- parse and set timeout values 2720 ** 2721 ** Parameters: 2722 ** val -- a pointer to the values. If NULL, do initial 2723 ** settings. 2724 ** 2725 ** Returns: 2726 ** none. 2727 ** 2728 ** Side Effects: 2729 ** Initializes the TimeOuts structure 2730 */ 2731 2732 #define SECONDS 2733 #define MINUTES * 60 2734 #define HOUR * 3600 2735 2736 void 2737 inittimeouts(val) 2738 register char *val; 2739 { 2740 register char *p; 2741 extern time_t convtime __P((char *, char)); 2742 2743 if (tTd(37, 2)) 2744 printf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val); 2745 if (val == NULL) 2746 { 2747 TimeOuts.to_connect = (time_t) 0 SECONDS; 2748 TimeOuts.to_initial = (time_t) 5 MINUTES; 2749 TimeOuts.to_helo = (time_t) 5 MINUTES; 2750 TimeOuts.to_mail = (time_t) 10 MINUTES; 2751 TimeOuts.to_rcpt = (time_t) 1 HOUR; 2752 TimeOuts.to_datainit = (time_t) 5 MINUTES; 2753 TimeOuts.to_datablock = (time_t) 1 HOUR; 2754 TimeOuts.to_datafinal = (time_t) 1 HOUR; 2755 TimeOuts.to_rset = (time_t) 5 MINUTES; 2756 TimeOuts.to_quit = (time_t) 2 MINUTES; 2757 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 2758 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2759 #if IDENTPROTO 2760 TimeOuts.to_ident = (time_t) 30 SECONDS; 2761 #else 2762 TimeOuts.to_ident = (time_t) 0 SECONDS; 2763 #endif 2764 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 2765 if (tTd(37, 5)) 2766 { 2767 printf("Timeouts:\n"); 2768 printf(" connect = %ld\n", (long)TimeOuts.to_connect); 2769 printf(" initial = %ld\n", (long)TimeOuts.to_initial); 2770 printf(" helo = %ld\n", (long)TimeOuts.to_helo); 2771 printf(" mail = %ld\n", (long)TimeOuts.to_mail); 2772 printf(" rcpt = %ld\n", (long)TimeOuts.to_rcpt); 2773 printf(" datainit = %ld\n", (long)TimeOuts.to_datainit); 2774 printf(" datablock = %ld\n", (long)TimeOuts.to_datablock); 2775 printf(" datafinal = %ld\n", (long)TimeOuts.to_datafinal); 2776 printf(" rset = %ld\n", (long)TimeOuts.to_rset); 2777 printf(" quit = %ld\n", (long)TimeOuts.to_quit); 2778 printf(" nextcommand = %ld\n", (long)TimeOuts.to_nextcommand); 2779 printf(" miscshort = %ld\n", (long)TimeOuts.to_miscshort); 2780 printf(" ident = %ld\n", (long)TimeOuts.to_ident); 2781 printf(" fileopen = %ld\n", (long)TimeOuts.to_fileopen); 2782 } 2783 return; 2784 } 2785 2786 for (;; val = p) 2787 { 2788 while (isascii(*val) && isspace(*val)) 2789 val++; 2790 if (*val == '\0') 2791 break; 2792 for (p = val; *p != '\0' && *p != ','; p++) 2793 continue; 2794 if (*p != '\0') 2795 *p++ = '\0'; 2796 2797 if (isascii(*val) && isdigit(*val)) 2798 { 2799 /* old syntax -- set everything */ 2800 TimeOuts.to_mail = convtime(val, 'm'); 2801 TimeOuts.to_rcpt = TimeOuts.to_mail; 2802 TimeOuts.to_datainit = TimeOuts.to_mail; 2803 TimeOuts.to_datablock = TimeOuts.to_mail; 2804 TimeOuts.to_datafinal = TimeOuts.to_mail; 2805 TimeOuts.to_nextcommand = TimeOuts.to_mail; 2806 continue; 2807 } 2808 else 2809 { 2810 register char *q = strchr(val, ':'); 2811 2812 if (q == NULL && (q = strchr(val, '=')) == NULL) 2813 { 2814 /* syntax error */ 2815 continue; 2816 } 2817 *q++ = '\0'; 2818 settimeout(val, q); 2819 } 2820 } 2821 } 2822 /* 2823 ** SETTIMEOUT -- set an individual timeout 2824 ** 2825 ** Parameters: 2826 ** name -- the name of the timeout. 2827 ** val -- the value of the timeout. 2828 ** 2829 ** Returns: 2830 ** none. 2831 */ 2832 2833 void 2834 settimeout(name, val) 2835 char *name; 2836 char *val; 2837 { 2838 register char *p; 2839 time_t to; 2840 extern time_t convtime __P((char *, char)); 2841 2842 if (tTd(37, 2)) 2843 printf("settimeout(%s = %s)\n", name, val); 2844 2845 to = convtime(val, 'm'); 2846 p = strchr(name, '.'); 2847 if (p != NULL) 2848 *p++ = '\0'; 2849 2850 if (strcasecmp(name, "initial") == 0) 2851 TimeOuts.to_initial = to; 2852 else if (strcasecmp(name, "mail") == 0) 2853 TimeOuts.to_mail = to; 2854 else if (strcasecmp(name, "rcpt") == 0) 2855 TimeOuts.to_rcpt = to; 2856 else if (strcasecmp(name, "datainit") == 0) 2857 TimeOuts.to_datainit = to; 2858 else if (strcasecmp(name, "datablock") == 0) 2859 TimeOuts.to_datablock = to; 2860 else if (strcasecmp(name, "datafinal") == 0) 2861 TimeOuts.to_datafinal = to; 2862 else if (strcasecmp(name, "command") == 0) 2863 TimeOuts.to_nextcommand = to; 2864 else if (strcasecmp(name, "rset") == 0) 2865 TimeOuts.to_rset = to; 2866 else if (strcasecmp(name, "helo") == 0) 2867 TimeOuts.to_helo = to; 2868 else if (strcasecmp(name, "quit") == 0) 2869 TimeOuts.to_quit = to; 2870 else if (strcasecmp(name, "misc") == 0) 2871 TimeOuts.to_miscshort = to; 2872 else if (strcasecmp(name, "ident") == 0) 2873 TimeOuts.to_ident = to; 2874 else if (strcasecmp(name, "fileopen") == 0) 2875 TimeOuts.to_fileopen = to; 2876 else if (strcasecmp(name, "connect") == 0) 2877 TimeOuts.to_connect = to; 2878 else if (strcasecmp(name, "iconnect") == 0) 2879 TimeOuts.to_iconnect = to; 2880 else if (strcasecmp(name, "queuewarn") == 0) 2881 { 2882 to = convtime(val, 'h'); 2883 if (p == NULL || strcmp(p, "*") == 0) 2884 { 2885 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2886 TimeOuts.to_q_warning[TOC_URGENT] = to; 2887 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2888 } 2889 else if (strcasecmp(p, "normal") == 0) 2890 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2891 else if (strcasecmp(p, "urgent") == 0) 2892 TimeOuts.to_q_warning[TOC_URGENT] = to; 2893 else if (strcasecmp(p, "non-urgent") == 0) 2894 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2895 else 2896 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2897 } 2898 else if (strcasecmp(name, "queuereturn") == 0) 2899 { 2900 to = convtime(val, 'd'); 2901 if (p == NULL || strcmp(p, "*") == 0) 2902 { 2903 TimeOuts.to_q_return[TOC_NORMAL] = to; 2904 TimeOuts.to_q_return[TOC_URGENT] = to; 2905 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2906 } 2907 else if (strcasecmp(p, "normal") == 0) 2908 TimeOuts.to_q_return[TOC_NORMAL] = to; 2909 else if (strcasecmp(p, "urgent") == 0) 2910 TimeOuts.to_q_return[TOC_URGENT] = to; 2911 else if (strcasecmp(p, "non-urgent") == 0) 2912 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2913 else 2914 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2915 } 2916 else if (strcasecmp(name, "hoststatus") == 0) 2917 MciInfoTimeout = convtime(val, 'm'); 2918 else 2919 syserr("settimeout: invalid timeout %s", name); 2920 } 2921