1 /* 2 * Copyright (c) 1998-2006, 2008, 2009 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 * 12 */ 13 14 #include <sendmail.h> 15 #include <sm/sendmail.h> 16 17 SM_RCSID("@(#)$Id: readcf.c,v 8.674 2009/10/26 17:47:00 ca Exp $") 18 19 #if NETINET || NETINET6 20 # include <arpa/inet.h> 21 #endif /* NETINET || NETINET6 */ 22 23 #define SECONDS 24 #define MINUTES * 60 25 #define HOUR * 3600 26 #define HOURS HOUR 27 28 static void fileclass __P((int, char *, char *, bool, bool, bool)); 29 static char **makeargv __P((char *)); 30 static void settimeout __P((char *, char *, bool)); 31 static void toomany __P((int, int)); 32 static char *extrquotstr __P((char *, char **, char *, bool *)); 33 static void parse_class_words __P((int, char *)); 34 35 /* 36 ** READCF -- read configuration file. 37 ** 38 ** This routine reads the configuration file and builds the internal 39 ** form. 40 ** 41 ** The file is formatted as a sequence of lines, each taken 42 ** atomically. The first character of each line describes how 43 ** the line is to be interpreted. The lines are: 44 ** Dxval Define macro x to have value val. 45 ** Cxword Put word into class x. 46 ** Fxfile [fmt] Read file for lines to put into 47 ** class x. Use scanf string 'fmt' 48 ** or "%s" if not present. Fmt should 49 ** only produce one string-valued result. 50 ** Hname: value Define header with field-name 'name' 51 ** and value as specified; this will be 52 ** macro expanded immediately before 53 ** use. 54 ** Sn Use rewriting set n. 55 ** Rlhs rhs Rewrite addresses that match lhs to 56 ** be rhs. 57 ** Mn arg=val... Define mailer. n is the internal name. 58 ** Args specify mailer parameters. 59 ** Oxvalue Set option x to value. 60 ** O option value Set option (long name) to value. 61 ** Pname=value Set precedence name to value. 62 ** Qn arg=val... Define queue groups. n is the internal name. 63 ** Args specify queue parameters. 64 ** Vversioncode[/vendorcode] 65 ** Version level/vendor name of 66 ** configuration syntax. 67 ** Kmapname mapclass arguments.... 68 ** Define keyed lookup of a given class. 69 ** Arguments are class dependent. 70 ** Eenvar=value Set the environment value to the given value. 71 ** 72 ** Parameters: 73 ** cfname -- configuration file name. 74 ** safe -- true if this is the system config file; 75 ** false otherwise. 76 ** e -- the main envelope. 77 ** 78 ** Returns: 79 ** none. 80 ** 81 ** Side Effects: 82 ** Builds several internal tables. 83 */ 84 85 void 86 readcf(cfname, safe, e) 87 char *cfname; 88 bool safe; 89 register ENVELOPE *e; 90 { 91 SM_FILE_T *cf; 92 int ruleset = -1; 93 char *q; 94 struct rewrite *rwp = NULL; 95 char *bp; 96 auto char *ep; 97 int nfuzzy; 98 char *file; 99 bool optional; 100 bool ok; 101 bool ismap; 102 int mid; 103 register char *p; 104 long sff = SFF_OPENASROOT; 105 struct stat statb; 106 char buf[MAXLINE]; 107 int bufsize; 108 char exbuf[MAXLINE]; 109 char pvpbuf[MAXLINE + MAXATOM]; 110 static char *null_list[1] = { NULL }; 111 extern unsigned char TokTypeNoC[]; 112 113 FileName = cfname; 114 LineNumber = 0; 115 116 #if STARTTLS 117 Srv_SSL_Options = Clt_SSL_Options = SSL_OP_ALL; 118 #endif /* STARTTLS */ 119 if (DontLockReadFiles) 120 sff |= SFF_NOLOCK; 121 cf = safefopen(cfname, O_RDONLY, 0444, sff); 122 if (cf == NULL) 123 { 124 syserr("cannot open"); 125 finis(false, true, EX_OSFILE); 126 } 127 128 if (fstat(sm_io_getinfo(cf, SM_IO_WHAT_FD, NULL), &statb) < 0) 129 { 130 syserr("cannot fstat"); 131 finis(false, true, EX_OSFILE); 132 } 133 134 if (!S_ISREG(statb.st_mode)) 135 { 136 syserr("not a plain file"); 137 finis(false, true, EX_OSFILE); 138 } 139 140 if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 141 { 142 if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS || OpMode == MD_CHECKCONFIG) 143 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 144 "%s: WARNING: dangerous write permissions\n", 145 FileName); 146 if (LogLevel > 0) 147 sm_syslog(LOG_CRIT, NOQID, 148 "%s: WARNING: dangerous write permissions", 149 FileName); 150 } 151 152 #if XLA 153 xla_zero(); 154 #endif /* XLA */ 155 156 while (bufsize = sizeof(buf), 157 (bp = fgetfolded(buf, &bufsize, cf)) != NULL) 158 { 159 char *nbp; 160 161 if (bp[0] == '#') 162 { 163 if (bp != buf) 164 sm_free(bp); /* XXX */ 165 continue; 166 } 167 168 /* do macro expansion mappings */ 169 nbp = translate_dollars(bp, bp, &bufsize); 170 if (nbp != bp && bp != buf) 171 sm_free(bp); 172 bp = nbp; 173 174 /* interpret this line */ 175 errno = 0; 176 switch (bp[0]) 177 { 178 case '\0': 179 case '#': /* comment */ 180 break; 181 182 case 'R': /* rewriting rule */ 183 if (ruleset < 0) 184 { 185 syserr("missing valid ruleset for \"%s\"", bp); 186 break; 187 } 188 for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 189 continue; 190 191 if (*p == '\0') 192 { 193 syserr("invalid rewrite line \"%s\" (tab expected)", bp); 194 break; 195 } 196 197 /* allocate space for the rule header */ 198 if (rwp == NULL) 199 { 200 RewriteRules[ruleset] = rwp = 201 (struct rewrite *) xalloc(sizeof(*rwp)); 202 } 203 else 204 { 205 rwp->r_next = (struct rewrite *) xalloc(sizeof(*rwp)); 206 rwp = rwp->r_next; 207 } 208 rwp->r_next = NULL; 209 210 /* expand and save the LHS */ 211 *p = '\0'; 212 expand(&bp[1], exbuf, sizeof(exbuf), e); 213 rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 214 sizeof(pvpbuf), NULL, 215 ConfigLevel >= 9 ? TokTypeNoC : IntTokenTab, 216 true); 217 nfuzzy = 0; 218 if (rwp->r_lhs != NULL) 219 { 220 register char **ap; 221 222 rwp->r_lhs = copyplist(rwp->r_lhs, true, NULL); 223 224 /* count the number of fuzzy matches in LHS */ 225 for (ap = rwp->r_lhs; *ap != NULL; ap++) 226 { 227 char *botch; 228 229 botch = NULL; 230 switch (ap[0][0] & 0377) 231 { 232 case MATCHZANY: 233 case MATCHANY: 234 case MATCHONE: 235 case MATCHCLASS: 236 case MATCHNCLASS: 237 nfuzzy++; 238 break; 239 240 case MATCHREPL: 241 botch = "$1-$9"; 242 break; 243 244 case CANONUSER: 245 botch = "$:"; 246 break; 247 248 case CALLSUBR: 249 botch = "$>"; 250 break; 251 252 case CONDIF: 253 botch = "$?"; 254 break; 255 256 case CONDFI: 257 botch = "$."; 258 break; 259 260 case HOSTBEGIN: 261 botch = "$["; 262 break; 263 264 case HOSTEND: 265 botch = "$]"; 266 break; 267 268 case LOOKUPBEGIN: 269 botch = "$("; 270 break; 271 272 case LOOKUPEND: 273 botch = "$)"; 274 break; 275 } 276 if (botch != NULL) 277 syserr("Inappropriate use of %s on LHS", 278 botch); 279 } 280 rwp->r_line = LineNumber; 281 } 282 else 283 { 284 syserr("R line: null LHS"); 285 rwp->r_lhs = null_list; 286 } 287 if (nfuzzy > MAXMATCH) 288 { 289 syserr("R line: too many wildcards"); 290 rwp->r_lhs = null_list; 291 } 292 293 /* expand and save the RHS */ 294 while (*++p == '\t') 295 continue; 296 q = p; 297 while (*p != '\0' && *p != '\t') 298 p++; 299 *p = '\0'; 300 expand(q, exbuf, sizeof(exbuf), e); 301 rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 302 sizeof(pvpbuf), NULL, 303 ConfigLevel >= 9 ? TokTypeNoC : IntTokenTab, 304 true); 305 if (rwp->r_rhs != NULL) 306 { 307 register char **ap; 308 int args, endtoken; 309 #if _FFR_EXTRA_MAP_CHECK 310 int nexttoken; 311 #endif /* _FFR_EXTRA_MAP_CHECK */ 312 bool inmap; 313 314 rwp->r_rhs = copyplist(rwp->r_rhs, true, NULL); 315 316 /* check no out-of-bounds replacements */ 317 nfuzzy += '0'; 318 inmap = false; 319 args = 0; 320 endtoken = 0; 321 for (ap = rwp->r_rhs; *ap != NULL; ap++) 322 { 323 char *botch; 324 325 botch = NULL; 326 switch (ap[0][0] & 0377) 327 { 328 case MATCHREPL: 329 if (ap[0][1] <= '0' || 330 ap[0][1] > nfuzzy) 331 { 332 syserr("replacement $%c out of bounds", 333 ap[0][1]); 334 } 335 break; 336 337 case MATCHZANY: 338 botch = "$*"; 339 break; 340 341 case MATCHANY: 342 botch = "$+"; 343 break; 344 345 case MATCHONE: 346 botch = "$-"; 347 break; 348 349 case MATCHCLASS: 350 botch = "$="; 351 break; 352 353 case MATCHNCLASS: 354 botch = "$~"; 355 break; 356 357 case CANONHOST: 358 if (!inmap) 359 break; 360 if (++args >= MAX_MAP_ARGS) 361 syserr("too many arguments for map lookup"); 362 break; 363 364 case HOSTBEGIN: 365 endtoken = HOSTEND; 366 /* FALLTHROUGH */ 367 case LOOKUPBEGIN: 368 /* see above... */ 369 if ((ap[0][0] & 0377) == LOOKUPBEGIN) 370 endtoken = LOOKUPEND; 371 if (inmap) 372 syserr("cannot nest map lookups"); 373 inmap = true; 374 args = 0; 375 #if _FFR_EXTRA_MAP_CHECK 376 if (ap[1] == NULL) 377 { 378 syserr("syntax error in map lookup"); 379 break; 380 } 381 nexttoken = ap[1][0] & 0377; 382 if (nexttoken == CANONHOST || 383 nexttoken == CANONUSER || 384 nexttoken == endtoken)) 385 { 386 syserr("missing map name for lookup"); 387 break; 388 } 389 if (ap[2] == NULL) 390 { 391 syserr("syntax error in map lookup"); 392 break; 393 } 394 if (ap[0][0] == HOSTBEGIN) 395 break; 396 nexttoken = ap[2][0] & 0377; 397 if (nexttoken == CANONHOST || 398 nexttoken == CANONUSER || 399 nexttoken == endtoken) 400 { 401 syserr("missing key name for lookup"); 402 break; 403 } 404 #endif /* _FFR_EXTRA_MAP_CHECK */ 405 break; 406 407 case HOSTEND: 408 case LOOKUPEND: 409 if ((ap[0][0] & 0377) != endtoken) 410 break; 411 inmap = false; 412 endtoken = 0; 413 break; 414 415 416 #if 0 417 /* 418 ** This doesn't work yet as there are maps defined *after* the cf 419 ** is read such as host, user, and alias. So for now, it's removed. 420 ** When it comes back, the RELEASE_NOTES entry will be: 421 ** Emit warnings for unknown maps when reading the .cf file. Based on 422 ** patch from Robert Harker of Harker Systems. 423 */ 424 425 case LOOKUPBEGIN: 426 /* 427 ** Got a database lookup, 428 ** check if map is defined. 429 */ 430 431 ep = ap[1]; 432 if ((ep[0] & 0377) != MACRODEXPAND && 433 stab(ep, ST_MAP, ST_FIND) == NULL) 434 { 435 (void) sm_io_fprintf(smioout, 436 SM_TIME_DEFAULT, 437 "Warning: %s: line %d: map %s not found\n", 438 FileName, 439 LineNumber, 440 ep); 441 } 442 break; 443 #endif /* 0 */ 444 } 445 if (botch != NULL) 446 syserr("Inappropriate use of %s on RHS", 447 botch); 448 } 449 if (inmap) 450 syserr("missing map closing token"); 451 } 452 else 453 { 454 syserr("R line: null RHS"); 455 rwp->r_rhs = null_list; 456 } 457 break; 458 459 case 'S': /* select rewriting set */ 460 expand(&bp[1], exbuf, sizeof(exbuf), e); 461 ruleset = strtorwset(exbuf, NULL, ST_ENTER); 462 if (ruleset < 0) 463 break; 464 465 rwp = RewriteRules[ruleset]; 466 if (rwp != NULL) 467 { 468 if (OpMode == MD_TEST || OpMode == MD_CHECKCONFIG) 469 (void) sm_io_fprintf(smioout, 470 SM_TIME_DEFAULT, 471 "WARNING: Ruleset %s has multiple definitions\n", 472 &bp[1]); 473 if (tTd(37, 1)) 474 sm_dprintf("WARNING: Ruleset %s has multiple definitions\n", 475 &bp[1]); 476 while (rwp->r_next != NULL) 477 rwp = rwp->r_next; 478 } 479 break; 480 481 case 'D': /* macro definition */ 482 mid = macid_parse(&bp[1], &ep); 483 if (mid == 0) 484 break; 485 p = munchstring(ep, NULL, '\0'); 486 macdefine(&e->e_macro, A_TEMP, mid, p); 487 break; 488 489 case 'H': /* required header line */ 490 (void) chompheader(&bp[1], CHHDR_DEF, NULL, e); 491 break; 492 493 case 'C': /* word class */ 494 case 'T': /* trusted user (set class `t') */ 495 if (bp[0] == 'C') 496 { 497 mid = macid_parse(&bp[1], &ep); 498 if (mid == 0) 499 break; 500 expand(ep, exbuf, sizeof(exbuf), e); 501 p = exbuf; 502 } 503 else 504 { 505 mid = 't'; 506 p = &bp[1]; 507 } 508 while (*p != '\0') 509 { 510 register char *wd; 511 char delim; 512 513 while (*p != '\0' && isascii(*p) && isspace(*p)) 514 p++; 515 wd = p; 516 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 517 p++; 518 delim = *p; 519 *p = '\0'; 520 if (wd[0] != '\0') 521 setclass(mid, wd); 522 *p = delim; 523 } 524 break; 525 526 case 'F': /* word class from file */ 527 mid = macid_parse(&bp[1], &ep); 528 if (mid == 0) 529 break; 530 for (p = ep; isascii(*p) && isspace(*p); ) 531 p++; 532 if (p[0] == '-' && p[1] == 'o') 533 { 534 optional = true; 535 while (*p != '\0' && 536 !(isascii(*p) && isspace(*p))) 537 p++; 538 while (isascii(*p) && isspace(*p)) 539 p++; 540 } 541 else 542 optional = false; 543 544 /* check if [key]@map:spec */ 545 ismap = false; 546 if (!SM_IS_DIR_DELIM(*p) && 547 *p != '|' && 548 (q = strchr(p, '@')) != NULL) 549 { 550 q++; 551 552 /* look for @LDAP or @map: in string */ 553 if (strcmp(q, "LDAP") == 0 || 554 (*q != ':' && 555 strchr(q, ':') != NULL)) 556 ismap = true; 557 } 558 559 if (ismap) 560 { 561 /* use entire spec */ 562 file = p; 563 } 564 else 565 { 566 file = extrquotstr(p, &q, " ", &ok); 567 if (!ok) 568 { 569 syserr("illegal filename '%s'", p); 570 break; 571 } 572 } 573 574 if (*file == '|' || ismap) 575 p = "%s"; 576 else 577 { 578 p = q; 579 if (*p == '\0') 580 p = "%s"; 581 else 582 { 583 *p = '\0'; 584 while (isascii(*++p) && isspace(*p)) 585 continue; 586 } 587 } 588 fileclass(mid, file, p, ismap, safe, optional); 589 break; 590 591 #if XLA 592 case 'L': /* extended load average description */ 593 xla_init(&bp[1]); 594 break; 595 #endif /* XLA */ 596 597 #if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) 598 case 'L': /* lookup macro */ 599 case 'G': /* lookup class */ 600 /* reserved for Sun -- NIS+ database lookup */ 601 if (VendorCode != VENDOR_SUN) 602 goto badline; 603 sun_lg_config_line(bp, e); 604 break; 605 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) */ 606 607 case 'M': /* define mailer */ 608 makemailer(&bp[1]); 609 break; 610 611 case 'O': /* set option */ 612 setoption(bp[1], &bp[2], safe, false, e); 613 break; 614 615 case 'P': /* set precedence */ 616 if (NumPriorities >= MAXPRIORITIES) 617 { 618 toomany('P', MAXPRIORITIES); 619 break; 620 } 621 for (p = &bp[1]; *p != '\0' && *p != '='; p++) 622 continue; 623 if (*p == '\0') 624 goto badline; 625 *p = '\0'; 626 Priorities[NumPriorities].pri_name = newstr(&bp[1]); 627 Priorities[NumPriorities].pri_val = atoi(++p); 628 NumPriorities++; 629 break; 630 631 case 'Q': /* define queue */ 632 makequeue(&bp[1], true); 633 break; 634 635 case 'V': /* configuration syntax version */ 636 for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 637 continue; 638 if (!isascii(*p) || !isdigit(*p)) 639 { 640 syserr("invalid argument to V line: \"%.20s\"", 641 &bp[1]); 642 break; 643 } 644 ConfigLevel = strtol(p, &ep, 10); 645 646 /* 647 ** Do heuristic tweaking for back compatibility. 648 */ 649 650 if (ConfigLevel >= 5) 651 { 652 /* level 5 configs have short name in $w */ 653 p = macvalue('w', e); 654 if (p != NULL && (p = strchr(p, '.')) != NULL) 655 { 656 *p = '\0'; 657 macdefine(&e->e_macro, A_TEMP, 'w', 658 macvalue('w', e)); 659 } 660 } 661 if (ConfigLevel >= 6) 662 { 663 ColonOkInAddr = false; 664 } 665 666 /* 667 ** Look for vendor code. 668 */ 669 670 if (*ep++ == '/') 671 { 672 /* extract vendor code */ 673 for (p = ep; isascii(*p) && isalpha(*p); ) 674 p++; 675 *p = '\0'; 676 677 if (!setvendor(ep)) 678 syserr("invalid V line vendor code: \"%s\"", 679 ep); 680 } 681 break; 682 683 case 'K': 684 expand(&bp[1], exbuf, sizeof(exbuf), e); 685 (void) makemapentry(exbuf); 686 break; 687 688 case 'E': 689 p = strchr(bp, '='); 690 if (p != NULL) 691 *p++ = '\0'; 692 sm_setuserenv(&bp[1], p); 693 break; 694 695 case 'X': /* mail filter */ 696 #if MILTER 697 milter_setup(&bp[1]); 698 #else /* MILTER */ 699 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 700 "Warning: Filter usage ('X') requires Milter support (-DMILTER)\n"); 701 #endif /* MILTER */ 702 break; 703 704 default: 705 badline: 706 syserr("unknown configuration line \"%s\"", bp); 707 } 708 if (bp != buf) 709 sm_free(bp); /* XXX */ 710 } 711 if (sm_io_error(cf)) 712 { 713 syserr("I/O read error"); 714 finis(false, true, EX_OSFILE); 715 } 716 (void) sm_io_close(cf, SM_TIME_DEFAULT); 717 FileName = NULL; 718 719 /* initialize host maps from local service tables */ 720 inithostmaps(); 721 722 /* initialize daemon (if not defined yet) */ 723 initdaemon(); 724 725 /* determine if we need to do special name-server frotz */ 726 { 727 int nmaps; 728 char *maptype[MAXMAPSTACK]; 729 short mapreturn[MAXMAPACTIONS]; 730 731 nmaps = switch_map_find("hosts", maptype, mapreturn); 732 UseNameServer = false; 733 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 734 { 735 register int mapno; 736 737 for (mapno = 0; mapno < nmaps && !UseNameServer; 738 mapno++) 739 { 740 if (strcmp(maptype[mapno], "dns") == 0) 741 UseNameServer = true; 742 } 743 } 744 } 745 } 746 747 /* 748 ** TRANSLATE_DOLLARS -- convert $x into internal form 749 ** 750 ** Actually does all appropriate pre-processing of a config line 751 ** to turn it into internal form. 752 ** 753 ** Parameters: 754 ** ibp -- the buffer to translate. 755 ** obp -- where to put the translation; may be the same as obp 756 ** bsp -- a pointer to the size of obp; will be updated if 757 ** the buffer needs to be replaced. 758 ** 759 ** Returns: 760 ** The buffer pointer; may differ from obp if the expansion 761 ** is larger then *bsp, in which case this will point to 762 ** malloc()ed memory which must be free()d by the caller. 763 */ 764 765 char * 766 translate_dollars(ibp, obp, bsp) 767 char *ibp; 768 char *obp; 769 int *bsp; 770 { 771 register char *p; 772 auto char *ep; 773 char *bp; 774 775 if (tTd(37, 53)) 776 { 777 sm_dprintf("translate_dollars("); 778 xputs(sm_debug_file(), ibp); 779 sm_dprintf(")\n"); 780 } 781 782 bp = quote_internal_chars(ibp, obp, bsp); 783 784 for (p = bp; *p != '\0'; p++) 785 { 786 if (*p == '#' && p > bp && ConfigLevel >= 3) 787 { 788 register char *e; 789 790 switch (*--p & 0377) 791 { 792 case MACROEXPAND: 793 /* it's from $# -- let it go through */ 794 p++; 795 break; 796 797 case '\\': 798 /* it's backslash escaped */ 799 (void) sm_strlcpy(p, p + 1, strlen(p)); 800 break; 801 802 default: 803 /* delete leading white space */ 804 while (isascii(*p) && isspace(*p) && 805 *p != '\n' && p > bp) 806 { 807 p--; 808 } 809 if ((e = strchr(++p, '\n')) != NULL) 810 (void) sm_strlcpy(p, e, strlen(p)); 811 else 812 *p-- = '\0'; 813 break; 814 } 815 continue; 816 } 817 818 if (*p != '$' || p[1] == '\0') 819 continue; 820 821 if (p[1] == '$') 822 { 823 /* actual dollar sign.... */ 824 (void) sm_strlcpy(p, p + 1, strlen(p)); 825 continue; 826 } 827 828 /* convert to macro expansion character */ 829 *p++ = MACROEXPAND; 830 831 /* special handling for $=, $~, $&, and $? */ 832 if (*p == '=' || *p == '~' || *p == '&' || *p == '?') 833 p++; 834 835 /* convert macro name to code */ 836 *p = macid_parse(p, &ep); 837 if (ep != p + 1) 838 (void) sm_strlcpy(p + 1, ep, strlen(p + 1)); 839 } 840 841 /* strip trailing white space from the line */ 842 while (--p > bp && isascii(*p) && isspace(*p)) 843 *p = '\0'; 844 845 if (tTd(37, 53)) 846 { 847 sm_dprintf(" translate_dollars => "); 848 xputs(sm_debug_file(), bp); 849 sm_dprintf("\n"); 850 } 851 852 return bp; 853 } 854 /* 855 ** TOOMANY -- signal too many of some option 856 ** 857 ** Parameters: 858 ** id -- the id of the error line 859 ** maxcnt -- the maximum possible values 860 ** 861 ** Returns: 862 ** none. 863 ** 864 ** Side Effects: 865 ** gives a syserr. 866 */ 867 868 static void 869 toomany(id, maxcnt) 870 int id; 871 int maxcnt; 872 { 873 syserr("too many %c lines, %d max", id, maxcnt); 874 } 875 /* 876 ** FILECLASS -- read members of a class from a file 877 ** 878 ** Parameters: 879 ** class -- class to define. 880 ** filename -- name of file to read. 881 ** fmt -- scanf string to use for match. 882 ** ismap -- if set, this is a map lookup. 883 ** safe -- if set, this is a safe read. 884 ** optional -- if set, it is not an error for the file to 885 ** not exist. 886 ** 887 ** Returns: 888 ** none 889 ** 890 ** Side Effects: 891 ** puts all lines in filename that match a scanf into 892 ** the named class. 893 */ 894 895 /* 896 ** Break up the match into words and add to class. 897 */ 898 899 static void 900 parse_class_words(class, line) 901 int class; 902 char *line; 903 { 904 while (line != NULL && *line != '\0') 905 { 906 register char *q; 907 908 /* strip leading spaces */ 909 while (isascii(*line) && isspace(*line)) 910 line++; 911 if (*line == '\0') 912 break; 913 914 /* find the end of the word */ 915 q = line; 916 while (*line != '\0' && !(isascii(*line) && isspace(*line))) 917 line++; 918 if (*line != '\0') 919 *line++ = '\0'; 920 921 /* enter the word in the symbol table */ 922 setclass(class, q); 923 } 924 } 925 926 static void 927 fileclass(class, filename, fmt, ismap, safe, optional) 928 int class; 929 char *filename; 930 char *fmt; 931 bool ismap; 932 bool safe; 933 bool optional; 934 { 935 SM_FILE_T *f; 936 long sff; 937 pid_t pid; 938 register char *p; 939 char buf[MAXLINE]; 940 941 if (tTd(37, 2)) 942 sm_dprintf("fileclass(%s, fmt=%s)\n", filename, fmt); 943 944 if (*filename == '\0') 945 { 946 syserr("fileclass: missing file name"); 947 return; 948 } 949 else if (ismap) 950 { 951 int status = 0; 952 char *key; 953 char *mn; 954 char *cl, *spec; 955 STAB *mapclass; 956 MAP map; 957 958 mn = newstr(macname(class)); 959 960 key = filename; 961 962 /* skip past key */ 963 if ((p = strchr(filename, '@')) == NULL) 964 { 965 /* should not happen */ 966 syserr("fileclass: bogus map specification"); 967 sm_free(mn); 968 return; 969 } 970 971 /* skip past '@' */ 972 *p++ = '\0'; 973 cl = p; 974 975 #if LDAPMAP 976 if (strcmp(cl, "LDAP") == 0) 977 { 978 int n; 979 char *lc; 980 char jbuf[MAXHOSTNAMELEN]; 981 char lcbuf[MAXLINE]; 982 983 /* Get $j */ 984 expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope); 985 if (jbuf[0] == '\0') 986 { 987 (void) sm_strlcpy(jbuf, "localhost", 988 sizeof(jbuf)); 989 } 990 991 /* impose the default schema */ 992 lc = macvalue(macid("{sendmailMTACluster}"), CurEnv); 993 if (lc == NULL) 994 lc = ""; 995 else 996 { 997 expand(lc, lcbuf, sizeof(lcbuf), CurEnv); 998 lc = lcbuf; 999 } 1000 1001 cl = "ldap"; 1002 n = sm_snprintf(buf, sizeof(buf), 1003 "-k (&(objectClass=sendmailMTAClass)(sendmailMTAClassName=%s)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))) -v sendmailMTAClassValue,sendmailMTAClassSearch:FILTER:sendmailMTAClass,sendmailMTAClassURL:URL:sendmailMTAClass", 1004 mn, lc, jbuf); 1005 if (n >= sizeof(buf)) 1006 { 1007 syserr("fileclass: F{%s}: Default LDAP string too long", 1008 mn); 1009 sm_free(mn); 1010 return; 1011 } 1012 spec = buf; 1013 } 1014 else 1015 #endif /* LDAPMAP */ 1016 { 1017 if ((spec = strchr(cl, ':')) == NULL) 1018 { 1019 syserr("fileclass: F{%s}: missing map class", 1020 mn); 1021 sm_free(mn); 1022 return; 1023 } 1024 *spec++ ='\0'; 1025 } 1026 1027 /* set up map structure */ 1028 mapclass = stab(cl, ST_MAPCLASS, ST_FIND); 1029 if (mapclass == NULL) 1030 { 1031 syserr("fileclass: F{%s}: class %s not available", 1032 mn, cl); 1033 sm_free(mn); 1034 return; 1035 } 1036 memset(&map, '\0', sizeof(map)); 1037 map.map_class = &mapclass->s_mapclass; 1038 map.map_mname = mn; 1039 map.map_mflags |= MF_FILECLASS; 1040 1041 if (tTd(37, 5)) 1042 sm_dprintf("fileclass: F{%s}: map class %s, key %s, spec %s\n", 1043 mn, cl, key, spec); 1044 1045 1046 /* parse map spec */ 1047 if (!map.map_class->map_parse(&map, spec)) 1048 { 1049 /* map_parse() showed the error already */ 1050 sm_free(mn); 1051 return; 1052 } 1053 map.map_mflags |= MF_VALID; 1054 1055 /* open map */ 1056 if (map.map_class->map_open(&map, O_RDONLY)) 1057 { 1058 map.map_mflags |= MF_OPEN; 1059 map.map_pid = getpid(); 1060 } 1061 else 1062 { 1063 if (!optional && 1064 !bitset(MF_OPTIONAL, map.map_mflags)) 1065 syserr("fileclass: F{%s}: map open failed", 1066 mn); 1067 sm_free(mn); 1068 return; 1069 } 1070 1071 /* lookup */ 1072 p = (*map.map_class->map_lookup)(&map, key, NULL, &status); 1073 if (status != EX_OK && status != EX_NOTFOUND) 1074 { 1075 if (!optional) 1076 syserr("fileclass: F{%s}: map lookup failed", 1077 mn); 1078 p = NULL; 1079 } 1080 1081 /* use the results */ 1082 if (p != NULL) 1083 parse_class_words(class, p); 1084 1085 /* close map */ 1086 map.map_mflags |= MF_CLOSING; 1087 map.map_class->map_close(&map); 1088 map.map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 1089 sm_free(mn); 1090 return; 1091 } 1092 else if (filename[0] == '|') 1093 { 1094 auto int fd; 1095 int i; 1096 char *argv[MAXPV + 1]; 1097 1098 i = 0; 1099 for (p = strtok(&filename[1], " \t"); 1100 p != NULL && i < MAXPV; 1101 p = strtok(NULL, " \t")) 1102 argv[i++] = p; 1103 argv[i] = NULL; 1104 pid = prog_open(argv, &fd, CurEnv); 1105 if (pid < 0) 1106 f = NULL; 1107 else 1108 f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 1109 (void *) &fd, SM_IO_RDONLY, NULL); 1110 } 1111 else 1112 { 1113 pid = -1; 1114 sff = SFF_REGONLY; 1115 if (!bitnset(DBS_CLASSFILEINUNSAFEDIRPATH, DontBlameSendmail)) 1116 sff |= SFF_SAFEDIRPATH; 1117 if (!bitnset(DBS_LINKEDCLASSFILEINWRITABLEDIR, 1118 DontBlameSendmail)) 1119 sff |= SFF_NOWLINK; 1120 if (safe) 1121 sff |= SFF_OPENASROOT; 1122 else if (RealUid == 0) 1123 sff |= SFF_ROOTOK; 1124 if (DontLockReadFiles) 1125 sff |= SFF_NOLOCK; 1126 f = safefopen(filename, O_RDONLY, 0, sff); 1127 } 1128 if (f == NULL) 1129 { 1130 if (!optional) 1131 syserr("fileclass: cannot open '%s'", filename); 1132 return; 1133 } 1134 1135 while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL) 1136 { 1137 #if SCANF 1138 char wordbuf[MAXLINE + 1]; 1139 #endif /* SCANF */ 1140 1141 if (buf[0] == '#') 1142 continue; 1143 #if SCANF 1144 if (sm_io_sscanf(buf, fmt, wordbuf) != 1) 1145 continue; 1146 p = wordbuf; 1147 #else /* SCANF */ 1148 p = buf; 1149 #endif /* SCANF */ 1150 1151 parse_class_words(class, p); 1152 1153 /* 1154 ** If anything else is added here, 1155 ** check if the '@' map case above 1156 ** needs the code as well. 1157 */ 1158 } 1159 1160 (void) sm_io_close(f, SM_TIME_DEFAULT); 1161 if (pid > 0) 1162 (void) waitfor(pid); 1163 } 1164 /* 1165 ** MAKEMAILER -- define a new mailer. 1166 ** 1167 ** Parameters: 1168 ** line -- description of mailer. This is in labeled 1169 ** fields. The fields are: 1170 ** A -- the argv for this mailer 1171 ** C -- the character set for MIME conversions 1172 ** D -- the directory to run in 1173 ** E -- the eol string 1174 ** F -- the flags associated with the mailer 1175 ** L -- the maximum line length 1176 ** M -- the maximum message size 1177 ** N -- the niceness at which to run 1178 ** P -- the path to the mailer 1179 ** Q -- the queue group for the mailer 1180 ** R -- the recipient rewriting set 1181 ** S -- the sender rewriting set 1182 ** T -- the mailer type (for DSNs) 1183 ** U -- the uid to run as 1184 ** W -- the time to wait at the end 1185 ** m -- maximum messages per connection 1186 ** r -- maximum number of recipients per message 1187 ** / -- new root directory 1188 ** The first word is the canonical name of the mailer. 1189 ** 1190 ** Returns: 1191 ** none. 1192 ** 1193 ** Side Effects: 1194 ** enters the mailer into the mailer table. 1195 */ 1196 1197 void 1198 makemailer(line) 1199 char *line; 1200 { 1201 register char *p; 1202 register struct mailer *m; 1203 register STAB *s; 1204 int i; 1205 char fcode; 1206 auto char *endp; 1207 static int nextmailer = 0; /* "free" index into Mailer struct */ 1208 1209 /* allocate a mailer and set up defaults */ 1210 m = (struct mailer *) xalloc(sizeof(*m)); 1211 memset((char *) m, '\0', sizeof(*m)); 1212 errno = 0; /* avoid bogus error text */ 1213 1214 /* collect the mailer name */ 1215 for (p = line; 1216 *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); 1217 p++) 1218 continue; 1219 if (*p != '\0') 1220 *p++ = '\0'; 1221 if (line[0] == '\0') 1222 { 1223 syserr("name required for mailer"); 1224 return; 1225 } 1226 m->m_name = newstr(line); 1227 m->m_qgrp = NOQGRP; 1228 m->m_uid = NO_UID; 1229 m->m_gid = NO_GID; 1230 1231 /* now scan through and assign info from the fields */ 1232 while (*p != '\0') 1233 { 1234 auto char *delimptr; 1235 1236 while (*p != '\0' && 1237 (*p == ',' || (isascii(*p) && isspace(*p)))) 1238 p++; 1239 1240 /* p now points to field code */ 1241 fcode = *p; 1242 while (*p != '\0' && *p != '=' && *p != ',') 1243 p++; 1244 if (*p++ != '=') 1245 { 1246 syserr("mailer %s: `=' expected", m->m_name); 1247 return; 1248 } 1249 while (isascii(*p) && isspace(*p)) 1250 p++; 1251 1252 /* p now points to the field body */ 1253 p = munchstring(p, &delimptr, ','); 1254 1255 /* install the field into the mailer struct */ 1256 switch (fcode) 1257 { 1258 case 'P': /* pathname */ 1259 if (*p != '\0') /* error is issued below */ 1260 m->m_mailer = newstr(p); 1261 break; 1262 1263 case 'F': /* flags */ 1264 for (; *p != '\0'; p++) 1265 { 1266 if (!(isascii(*p) && isspace(*p))) 1267 { 1268 #if _FFR_DEPRECATE_MAILER_FLAG_I 1269 if (*p == M_INTERNAL) 1270 sm_syslog(LOG_WARNING, NOQID, 1271 "WARNING: mailer=%s, flag=%c deprecated", 1272 m->m_name, *p); 1273 #endif /* _FFR_DEPRECATE_MAILER_FLAG_I */ 1274 setbitn(bitidx(*p), m->m_flags); 1275 } 1276 } 1277 break; 1278 1279 case 'S': /* sender rewriting ruleset */ 1280 case 'R': /* recipient rewriting ruleset */ 1281 i = strtorwset(p, &endp, ST_ENTER); 1282 if (i < 0) 1283 return; 1284 if (fcode == 'S') 1285 m->m_sh_rwset = m->m_se_rwset = i; 1286 else 1287 m->m_rh_rwset = m->m_re_rwset = i; 1288 1289 p = endp; 1290 if (*p++ == '/') 1291 { 1292 i = strtorwset(p, NULL, ST_ENTER); 1293 if (i < 0) 1294 return; 1295 if (fcode == 'S') 1296 m->m_sh_rwset = i; 1297 else 1298 m->m_rh_rwset = i; 1299 } 1300 break; 1301 1302 case 'E': /* end of line string */ 1303 if (*p == '\0') 1304 syserr("mailer %s: null end-of-line string", 1305 m->m_name); 1306 else 1307 m->m_eol = newstr(p); 1308 break; 1309 1310 case 'A': /* argument vector */ 1311 if (*p != '\0') /* error is issued below */ 1312 m->m_argv = makeargv(p); 1313 break; 1314 1315 case 'M': /* maximum message size */ 1316 m->m_maxsize = atol(p); 1317 break; 1318 1319 case 'm': /* maximum messages per connection */ 1320 m->m_maxdeliveries = atoi(p); 1321 break; 1322 1323 case 'r': /* max recipient per envelope */ 1324 m->m_maxrcpt = atoi(p); 1325 break; 1326 1327 case 'L': /* maximum line length */ 1328 m->m_linelimit = atoi(p); 1329 if (m->m_linelimit < 0) 1330 m->m_linelimit = 0; 1331 break; 1332 1333 case 'N': /* run niceness */ 1334 m->m_nice = atoi(p); 1335 break; 1336 1337 case 'D': /* working directory */ 1338 if (*p == '\0') 1339 syserr("mailer %s: null working directory", 1340 m->m_name); 1341 else 1342 m->m_execdir = newstr(p); 1343 break; 1344 1345 case 'C': /* default charset */ 1346 if (*p == '\0') 1347 syserr("mailer %s: null charset", m->m_name); 1348 else 1349 m->m_defcharset = newstr(p); 1350 break; 1351 1352 case 'Q': /* queue for this mailer */ 1353 if (*p == '\0') 1354 { 1355 syserr("mailer %s: null queue", m->m_name); 1356 break; 1357 } 1358 s = stab(p, ST_QUEUE, ST_FIND); 1359 if (s == NULL) 1360 syserr("mailer %s: unknown queue %s", 1361 m->m_name, p); 1362 else 1363 m->m_qgrp = s->s_quegrp->qg_index; 1364 break; 1365 1366 case 'T': /* MTA-Name/Address/Diagnostic types */ 1367 /* extract MTA name type; default to "dns" */ 1368 m->m_mtatype = newstr(p); 1369 p = strchr(m->m_mtatype, '/'); 1370 if (p != NULL) 1371 { 1372 *p++ = '\0'; 1373 if (*p == '\0') 1374 p = NULL; 1375 } 1376 if (*m->m_mtatype == '\0') 1377 m->m_mtatype = "dns"; 1378 1379 /* extract address type; default to "rfc822" */ 1380 m->m_addrtype = p; 1381 if (p != NULL) 1382 p = strchr(p, '/'); 1383 if (p != NULL) 1384 { 1385 *p++ = '\0'; 1386 if (*p == '\0') 1387 p = NULL; 1388 } 1389 if (m->m_addrtype == NULL || *m->m_addrtype == '\0') 1390 m->m_addrtype = "rfc822"; 1391 1392 /* extract diagnostic type; default to "smtp" */ 1393 m->m_diagtype = p; 1394 if (m->m_diagtype == NULL || *m->m_diagtype == '\0') 1395 m->m_diagtype = "smtp"; 1396 break; 1397 1398 case 'U': /* user id */ 1399 if (isascii(*p) && !isdigit(*p)) 1400 { 1401 char *q = p; 1402 struct passwd *pw; 1403 1404 while (*p != '\0' && isascii(*p) && 1405 (isalnum(*p) || strchr("-_", *p) != NULL)) 1406 p++; 1407 while (isascii(*p) && isspace(*p)) 1408 *p++ = '\0'; 1409 if (*p != '\0') 1410 *p++ = '\0'; 1411 if (*q == '\0') 1412 { 1413 syserr("mailer %s: null user name", 1414 m->m_name); 1415 break; 1416 } 1417 pw = sm_getpwnam(q); 1418 if (pw == NULL) 1419 { 1420 syserr("readcf: mailer U= flag: unknown user %s", q); 1421 break; 1422 } 1423 else 1424 { 1425 m->m_uid = pw->pw_uid; 1426 m->m_gid = pw->pw_gid; 1427 } 1428 } 1429 else 1430 { 1431 auto char *q; 1432 1433 m->m_uid = strtol(p, &q, 0); 1434 p = q; 1435 while (isascii(*p) && isspace(*p)) 1436 p++; 1437 if (*p != '\0') 1438 p++; 1439 } 1440 while (isascii(*p) && isspace(*p)) 1441 p++; 1442 if (*p == '\0') 1443 break; 1444 if (isascii(*p) && !isdigit(*p)) 1445 { 1446 char *q = p; 1447 struct group *gr; 1448 1449 while (isascii(*p) && isalnum(*p)) 1450 p++; 1451 *p++ = '\0'; 1452 if (*q == '\0') 1453 { 1454 syserr("mailer %s: null group name", 1455 m->m_name); 1456 break; 1457 } 1458 gr = getgrnam(q); 1459 if (gr == NULL) 1460 { 1461 syserr("readcf: mailer U= flag: unknown group %s", q); 1462 break; 1463 } 1464 else 1465 m->m_gid = gr->gr_gid; 1466 } 1467 else 1468 { 1469 m->m_gid = strtol(p, NULL, 0); 1470 } 1471 break; 1472 1473 case 'W': /* wait timeout */ 1474 m->m_wait = convtime(p, 's'); 1475 break; 1476 1477 case '/': /* new root directory */ 1478 if (*p == '\0') 1479 syserr("mailer %s: null root directory", 1480 m->m_name); 1481 else 1482 m->m_rootdir = newstr(p); 1483 break; 1484 1485 default: 1486 syserr("M%s: unknown mailer equate %c=", 1487 m->m_name, fcode); 1488 break; 1489 } 1490 1491 p = delimptr; 1492 } 1493 1494 #if !HASRRESVPORT 1495 if (bitnset(M_SECURE_PORT, m->m_flags)) 1496 { 1497 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1498 "M%s: Warning: F=%c set on system that doesn't support rresvport()\n", 1499 m->m_name, M_SECURE_PORT); 1500 } 1501 #endif /* !HASRRESVPORT */ 1502 1503 #if !HASNICE 1504 if (m->m_nice != 0) 1505 { 1506 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1507 "M%s: Warning: N= set on system that doesn't support nice()\n", 1508 m->m_name); 1509 } 1510 #endif /* !HASNICE */ 1511 1512 /* do some rationality checking */ 1513 if (m->m_argv == NULL) 1514 { 1515 syserr("M%s: A= argument required", m->m_name); 1516 return; 1517 } 1518 if (m->m_mailer == NULL) 1519 { 1520 syserr("M%s: P= argument required", m->m_name); 1521 return; 1522 } 1523 1524 if (nextmailer >= MAXMAILERS) 1525 { 1526 syserr("too many mailers defined (%d max)", MAXMAILERS); 1527 return; 1528 } 1529 1530 if (m->m_maxrcpt <= 0) 1531 m->m_maxrcpt = DEFAULT_MAX_RCPT; 1532 1533 /* do some heuristic cleanup for back compatibility */ 1534 if (bitnset(M_LIMITS, m->m_flags)) 1535 { 1536 if (m->m_linelimit == 0) 1537 m->m_linelimit = SMTPLINELIM; 1538 if (ConfigLevel < 2) 1539 setbitn(M_7BITS, m->m_flags); 1540 } 1541 1542 if (strcmp(m->m_mailer, "[TCP]") == 0) 1543 { 1544 syserr("M%s: P=[TCP] must be replaced by P=[IPC]", m->m_name); 1545 return; 1546 } 1547 1548 if (strcmp(m->m_mailer, "[IPC]") == 0) 1549 { 1550 /* Use the second argument for host or path to socket */ 1551 if (m->m_argv[0] == NULL || m->m_argv[1] == NULL || 1552 m->m_argv[1][0] == '\0') 1553 { 1554 syserr("M%s: too few parameters for %s mailer", 1555 m->m_name, m->m_mailer); 1556 return; 1557 } 1558 if (strcmp(m->m_argv[0], "TCP") != 0 1559 #if NETUNIX 1560 && strcmp(m->m_argv[0], "FILE") != 0 1561 #endif /* NETUNIX */ 1562 ) 1563 { 1564 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1565 "M%s: Warning: first argument in %s mailer must be %s\n", 1566 m->m_name, m->m_mailer, 1567 #if NETUNIX 1568 "TCP or FILE" 1569 #else /* NETUNIX */ 1570 "TCP" 1571 #endif /* NETUNIX */ 1572 ); 1573 } 1574 if (m->m_mtatype == NULL) 1575 m->m_mtatype = "dns"; 1576 if (m->m_addrtype == NULL) 1577 m->m_addrtype = "rfc822"; 1578 if (m->m_diagtype == NULL) 1579 { 1580 if (m->m_argv[0] != NULL && 1581 strcmp(m->m_argv[0], "FILE") == 0) 1582 m->m_diagtype = "x-unix"; 1583 else 1584 m->m_diagtype = "smtp"; 1585 } 1586 } 1587 else if (strcmp(m->m_mailer, "[FILE]") == 0) 1588 { 1589 /* Use the second argument for filename */ 1590 if (m->m_argv[0] == NULL || m->m_argv[1] == NULL || 1591 m->m_argv[2] != NULL) 1592 { 1593 syserr("M%s: too %s parameters for [FILE] mailer", 1594 m->m_name, 1595 (m->m_argv[0] == NULL || 1596 m->m_argv[1] == NULL) ? "few" : "many"); 1597 return; 1598 } 1599 else if (strcmp(m->m_argv[0], "FILE") != 0) 1600 { 1601 syserr("M%s: first argument in [FILE] mailer must be FILE", 1602 m->m_name); 1603 return; 1604 } 1605 } 1606 1607 if (m->m_eol == NULL) 1608 { 1609 char **pp; 1610 1611 /* default for SMTP is \r\n; use \n for local delivery */ 1612 for (pp = m->m_argv; *pp != NULL; pp++) 1613 { 1614 for (p = *pp; *p != '\0'; ) 1615 { 1616 if ((*p++ & 0377) == MACROEXPAND && *p == 'u') 1617 break; 1618 } 1619 if (*p != '\0') 1620 break; 1621 } 1622 if (*pp == NULL) 1623 m->m_eol = "\r\n"; 1624 else 1625 m->m_eol = "\n"; 1626 } 1627 1628 /* enter the mailer into the symbol table */ 1629 s = stab(m->m_name, ST_MAILER, ST_ENTER); 1630 if (s->s_mailer != NULL) 1631 { 1632 i = s->s_mailer->m_mno; 1633 sm_free(s->s_mailer); /* XXX */ 1634 } 1635 else 1636 { 1637 i = nextmailer++; 1638 } 1639 Mailer[i] = s->s_mailer = m; 1640 m->m_mno = i; 1641 } 1642 /* 1643 ** MUNCHSTRING -- translate a string into internal form. 1644 ** 1645 ** Parameters: 1646 ** p -- the string to munch. 1647 ** delimptr -- if non-NULL, set to the pointer of the 1648 ** field delimiter character. 1649 ** delim -- the delimiter for the field. 1650 ** 1651 ** Returns: 1652 ** the munched string. 1653 ** 1654 ** Side Effects: 1655 ** the munched string is a local static buffer. 1656 ** it must be copied before the function is called again. 1657 */ 1658 1659 char * 1660 munchstring(p, delimptr, delim) 1661 register char *p; 1662 char **delimptr; 1663 int delim; 1664 { 1665 register char *q; 1666 bool backslash = false; 1667 bool quotemode = false; 1668 static char buf[MAXLINE]; 1669 1670 for (q = buf; *p != '\0' && q < &buf[sizeof(buf) - 1]; p++) 1671 { 1672 if (backslash) 1673 { 1674 /* everything is roughly literal */ 1675 backslash = false; 1676 switch (*p) 1677 { 1678 case 'r': /* carriage return */ 1679 *q++ = '\r'; 1680 continue; 1681 1682 case 'n': /* newline */ 1683 *q++ = '\n'; 1684 continue; 1685 1686 case 'f': /* form feed */ 1687 *q++ = '\f'; 1688 continue; 1689 1690 case 'b': /* backspace */ 1691 *q++ = '\b'; 1692 continue; 1693 } 1694 *q++ = *p; 1695 } 1696 else 1697 { 1698 if (*p == '\\') 1699 backslash = true; 1700 else if (*p == '"') 1701 quotemode = !quotemode; 1702 else if (quotemode || *p != delim) 1703 *q++ = *p; 1704 else 1705 break; 1706 } 1707 } 1708 1709 if (delimptr != NULL) 1710 *delimptr = p; 1711 *q++ = '\0'; 1712 return buf; 1713 } 1714 /* 1715 ** EXTRQUOTSTR -- extract a (quoted) string. 1716 ** 1717 ** This routine deals with quoted (") strings and escaped 1718 ** spaces (\\ ). 1719 ** 1720 ** Parameters: 1721 ** p -- source string. 1722 ** delimptr -- if non-NULL, set to the pointer of the 1723 ** field delimiter character. 1724 ** delimbuf -- delimiters for the field. 1725 ** st -- if non-NULL, store the return value (whether the 1726 ** string was correctly quoted) here. 1727 ** 1728 ** Returns: 1729 ** the extracted string. 1730 ** 1731 ** Side Effects: 1732 ** the returned string is a local static buffer. 1733 ** it must be copied before the function is called again. 1734 */ 1735 1736 static char * 1737 extrquotstr(p, delimptr, delimbuf, st) 1738 register char *p; 1739 char **delimptr; 1740 char *delimbuf; 1741 bool *st; 1742 { 1743 register char *q; 1744 bool backslash = false; 1745 bool quotemode = false; 1746 static char buf[MAXLINE]; 1747 1748 for (q = buf; *p != '\0' && q < &buf[sizeof(buf) - 1]; p++) 1749 { 1750 if (backslash) 1751 { 1752 backslash = false; 1753 if (*p != ' ') 1754 *q++ = '\\'; 1755 } 1756 if (*p == '\\') 1757 backslash = true; 1758 else if (*p == '"') 1759 quotemode = !quotemode; 1760 else if (quotemode || 1761 strchr(delimbuf, (int) *p) == NULL) 1762 *q++ = *p; 1763 else 1764 break; 1765 } 1766 1767 if (delimptr != NULL) 1768 *delimptr = p; 1769 *q++ = '\0'; 1770 if (st != NULL) 1771 *st = !(quotemode || backslash); 1772 return buf; 1773 } 1774 /* 1775 ** MAKEARGV -- break up a string into words 1776 ** 1777 ** Parameters: 1778 ** p -- the string to break up. 1779 ** 1780 ** Returns: 1781 ** a char **argv (dynamically allocated) 1782 ** 1783 ** Side Effects: 1784 ** munges p. 1785 */ 1786 1787 static char ** 1788 makeargv(p) 1789 register char *p; 1790 { 1791 char *q; 1792 int i; 1793 char **avp; 1794 char *argv[MAXPV + 1]; 1795 1796 /* take apart the words */ 1797 i = 0; 1798 while (*p != '\0' && i < MAXPV) 1799 { 1800 q = p; 1801 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1802 p++; 1803 while (isascii(*p) && isspace(*p)) 1804 *p++ = '\0'; 1805 argv[i++] = newstr(q); 1806 } 1807 argv[i++] = NULL; 1808 1809 /* now make a copy of the argv */ 1810 avp = (char **) xalloc(sizeof(*avp) * i); 1811 memmove((char *) avp, (char *) argv, sizeof(*avp) * i); 1812 1813 return avp; 1814 } 1815 /* 1816 ** PRINTRULES -- print rewrite rules (for debugging) 1817 ** 1818 ** Parameters: 1819 ** none. 1820 ** 1821 ** Returns: 1822 ** none. 1823 ** 1824 ** Side Effects: 1825 ** prints rewrite rules. 1826 */ 1827 1828 void 1829 printrules() 1830 { 1831 register struct rewrite *rwp; 1832 register int ruleset; 1833 1834 for (ruleset = 0; ruleset < 10; ruleset++) 1835 { 1836 if (RewriteRules[ruleset] == NULL) 1837 continue; 1838 sm_dprintf("\n----Rule Set %d:", ruleset); 1839 1840 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 1841 { 1842 sm_dprintf("\nLHS:"); 1843 printav(sm_debug_file(), rwp->r_lhs); 1844 sm_dprintf("RHS:"); 1845 printav(sm_debug_file(), rwp->r_rhs); 1846 } 1847 } 1848 } 1849 /* 1850 ** PRINTMAILER -- print mailer structure (for debugging) 1851 ** 1852 ** Parameters: 1853 ** fp -- output file 1854 ** m -- the mailer to print 1855 ** 1856 ** Returns: 1857 ** none. 1858 */ 1859 1860 void 1861 printmailer(fp, m) 1862 SM_FILE_T *fp; 1863 register MAILER *m; 1864 { 1865 int j; 1866 1867 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 1868 "mailer %d (%s): P=%s S=", m->m_mno, m->m_name, 1869 m->m_mailer); 1870 if (RuleSetNames[m->m_se_rwset] == NULL) 1871 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d/", 1872 m->m_se_rwset); 1873 else 1874 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s/", 1875 RuleSetNames[m->m_se_rwset]); 1876 if (RuleSetNames[m->m_sh_rwset] == NULL) 1877 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d R=", 1878 m->m_sh_rwset); 1879 else 1880 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s R=", 1881 RuleSetNames[m->m_sh_rwset]); 1882 if (RuleSetNames[m->m_re_rwset] == NULL) 1883 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d/", 1884 m->m_re_rwset); 1885 else 1886 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s/", 1887 RuleSetNames[m->m_re_rwset]); 1888 if (RuleSetNames[m->m_rh_rwset] == NULL) 1889 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d ", 1890 m->m_rh_rwset); 1891 else 1892 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s ", 1893 RuleSetNames[m->m_rh_rwset]); 1894 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "M=%ld U=%d:%d F=", 1895 m->m_maxsize, (int) m->m_uid, (int) m->m_gid); 1896 for (j = '\0'; j <= '\177'; j++) 1897 if (bitnset(j, m->m_flags)) 1898 (void) sm_io_putc(fp, SM_TIME_DEFAULT, j); 1899 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " L=%d E=", 1900 m->m_linelimit); 1901 xputs(fp, m->m_eol); 1902 if (m->m_defcharset != NULL) 1903 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " C=%s", 1904 m->m_defcharset); 1905 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " T=%s/%s/%s", 1906 m->m_mtatype == NULL 1907 ? "<undefined>" : m->m_mtatype, 1908 m->m_addrtype == NULL 1909 ? "<undefined>" : m->m_addrtype, 1910 m->m_diagtype == NULL 1911 ? "<undefined>" : m->m_diagtype); 1912 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " r=%d", m->m_maxrcpt); 1913 if (m->m_argv != NULL) 1914 { 1915 char **a = m->m_argv; 1916 1917 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " A="); 1918 while (*a != NULL) 1919 { 1920 if (a != m->m_argv) 1921 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 1922 " "); 1923 xputs(fp, *a++); 1924 } 1925 } 1926 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\n"); 1927 } 1928 /* 1929 ** SETOPTION -- set global processing option 1930 ** 1931 ** Parameters: 1932 ** opt -- option name. 1933 ** val -- option value (as a text string). 1934 ** safe -- set if this came from a configuration file. 1935 ** Some options (if set from the command line) will 1936 ** reset the user id to avoid security problems. 1937 ** sticky -- if set, don't let other setoptions override 1938 ** this value. 1939 ** e -- the main envelope. 1940 ** 1941 ** Returns: 1942 ** none. 1943 ** 1944 ** Side Effects: 1945 ** Sets options as implied by the arguments. 1946 */ 1947 1948 static BITMAP256 StickyOpt; /* set if option is stuck */ 1949 1950 #if NAMED_BIND 1951 1952 static struct resolverflags 1953 { 1954 char *rf_name; /* name of the flag */ 1955 long rf_bits; /* bits to set/clear */ 1956 } ResolverFlags[] = 1957 { 1958 { "debug", RES_DEBUG }, 1959 { "aaonly", RES_AAONLY }, 1960 { "usevc", RES_USEVC }, 1961 { "primary", RES_PRIMARY }, 1962 { "igntc", RES_IGNTC }, 1963 { "recurse", RES_RECURSE }, 1964 { "defnames", RES_DEFNAMES }, 1965 { "stayopen", RES_STAYOPEN }, 1966 { "dnsrch", RES_DNSRCH }, 1967 # ifdef RES_USE_INET6 1968 { "use_inet6", RES_USE_INET6 }, 1969 # endif /* RES_USE_INET6 */ 1970 { "true", 0 }, /* avoid error on old syntax */ 1971 { NULL, 0 } 1972 }; 1973 1974 #endif /* NAMED_BIND */ 1975 1976 #define OI_NONE 0 /* no special treatment */ 1977 #define OI_SAFE 0x0001 /* safe for random people to use */ 1978 #define OI_SUBOPT 0x0002 /* option has suboptions */ 1979 1980 static struct optioninfo 1981 { 1982 char *o_name; /* long name of option */ 1983 unsigned char o_code; /* short name of option */ 1984 unsigned short o_flags; /* option flags */ 1985 } OptionTab[] = 1986 { 1987 #if defined(SUN_EXTENSIONS) && defined(REMOTE_MODE) 1988 { "RemoteMode", '>', OI_NONE }, 1989 #endif /* defined(SUN_EXTENSIONS) && defined(REMOTE_MODE) */ 1990 { "SevenBitInput", '7', OI_SAFE }, 1991 { "EightBitMode", '8', OI_SAFE }, 1992 { "AliasFile", 'A', OI_NONE }, 1993 { "AliasWait", 'a', OI_NONE }, 1994 { "BlankSub", 'B', OI_NONE }, 1995 { "MinFreeBlocks", 'b', OI_SAFE }, 1996 { "CheckpointInterval", 'C', OI_SAFE }, 1997 { "HoldExpensive", 'c', OI_NONE }, 1998 { "DeliveryMode", 'd', OI_SAFE }, 1999 { "ErrorHeader", 'E', OI_NONE }, 2000 { "ErrorMode", 'e', OI_SAFE }, 2001 { "TempFileMode", 'F', OI_NONE }, 2002 { "SaveFromLine", 'f', OI_NONE }, 2003 { "MatchGECOS", 'G', OI_NONE }, 2004 2005 /* no long name, just here to avoid problems in setoption */ 2006 { "", 'g', OI_NONE }, 2007 { "HelpFile", 'H', OI_NONE }, 2008 { "MaxHopCount", 'h', OI_NONE }, 2009 { "ResolverOptions", 'I', OI_NONE }, 2010 { "IgnoreDots", 'i', OI_SAFE }, 2011 { "ForwardPath", 'J', OI_NONE }, 2012 { "SendMimeErrors", 'j', OI_SAFE }, 2013 { "ConnectionCacheSize", 'k', OI_NONE }, 2014 { "ConnectionCacheTimeout", 'K', OI_NONE }, 2015 { "UseErrorsTo", 'l', OI_NONE }, 2016 { "LogLevel", 'L', OI_SAFE }, 2017 { "MeToo", 'm', OI_SAFE }, 2018 2019 /* no long name, just here to avoid problems in setoption */ 2020 { "", 'M', OI_NONE }, 2021 { "CheckAliases", 'n', OI_NONE }, 2022 { "OldStyleHeaders", 'o', OI_SAFE }, 2023 { "DaemonPortOptions", 'O', OI_NONE }, 2024 { "PrivacyOptions", 'p', OI_SAFE }, 2025 { "PostmasterCopy", 'P', OI_NONE }, 2026 { "QueueFactor", 'q', OI_NONE }, 2027 { "QueueDirectory", 'Q', OI_NONE }, 2028 { "DontPruneRoutes", 'R', OI_NONE }, 2029 { "Timeout", 'r', OI_SUBOPT }, 2030 { "StatusFile", 'S', OI_NONE }, 2031 { "SuperSafe", 's', OI_SAFE }, 2032 { "QueueTimeout", 'T', OI_NONE }, 2033 { "TimeZoneSpec", 't', OI_NONE }, 2034 { "UserDatabaseSpec", 'U', OI_NONE }, 2035 { "DefaultUser", 'u', OI_NONE }, 2036 { "FallbackMXhost", 'V', OI_NONE }, 2037 { "Verbose", 'v', OI_SAFE }, 2038 { "TryNullMXList", 'w', OI_NONE }, 2039 { "QueueLA", 'x', OI_NONE }, 2040 { "RefuseLA", 'X', OI_NONE }, 2041 { "RecipientFactor", 'y', OI_NONE }, 2042 { "ForkEachJob", 'Y', OI_NONE }, 2043 { "ClassFactor", 'z', OI_NONE }, 2044 { "RetryFactor", 'Z', OI_NONE }, 2045 #define O_QUEUESORTORD 0x81 2046 { "QueueSortOrder", O_QUEUESORTORD, OI_SAFE }, 2047 #define O_HOSTSFILE 0x82 2048 { "HostsFile", O_HOSTSFILE, OI_NONE }, 2049 #define O_MQA 0x83 2050 { "MinQueueAge", O_MQA, OI_SAFE }, 2051 #define O_DEFCHARSET 0x85 2052 { "DefaultCharSet", O_DEFCHARSET, OI_SAFE }, 2053 #define O_SSFILE 0x86 2054 { "ServiceSwitchFile", O_SSFILE, OI_NONE }, 2055 #define O_DIALDELAY 0x87 2056 { "DialDelay", O_DIALDELAY, OI_SAFE }, 2057 #define O_NORCPTACTION 0x88 2058 { "NoRecipientAction", O_NORCPTACTION, OI_SAFE }, 2059 #define O_SAFEFILEENV 0x89 2060 { "SafeFileEnvironment", O_SAFEFILEENV, OI_NONE }, 2061 #define O_MAXMSGSIZE 0x8a 2062 { "MaxMessageSize", O_MAXMSGSIZE, OI_NONE }, 2063 #define O_COLONOKINADDR 0x8b 2064 { "ColonOkInAddr", O_COLONOKINADDR, OI_SAFE }, 2065 #define O_MAXQUEUERUN 0x8c 2066 { "MaxQueueRunSize", O_MAXQUEUERUN, OI_SAFE }, 2067 #define O_MAXCHILDREN 0x8d 2068 { "MaxDaemonChildren", O_MAXCHILDREN, OI_NONE }, 2069 #define O_KEEPCNAMES 0x8e 2070 { "DontExpandCnames", O_KEEPCNAMES, OI_NONE }, 2071 #define O_MUSTQUOTE 0x8f 2072 { "MustQuoteChars", O_MUSTQUOTE, OI_NONE }, 2073 #define O_SMTPGREETING 0x90 2074 { "SmtpGreetingMessage", O_SMTPGREETING, OI_NONE }, 2075 #define O_UNIXFROM 0x91 2076 { "UnixFromLine", O_UNIXFROM, OI_NONE }, 2077 #define O_OPCHARS 0x92 2078 { "OperatorChars", O_OPCHARS, OI_NONE }, 2079 #define O_DONTINITGRPS 0x93 2080 { "DontInitGroups", O_DONTINITGRPS, OI_NONE }, 2081 #define O_SLFH 0x94 2082 { "SingleLineFromHeader", O_SLFH, OI_SAFE }, 2083 #define O_ABH 0x95 2084 { "AllowBogusHELO", O_ABH, OI_SAFE }, 2085 #define O_CONNTHROT 0x97 2086 { "ConnectionRateThrottle", O_CONNTHROT, OI_NONE }, 2087 #define O_UGW 0x99 2088 { "UnsafeGroupWrites", O_UGW, OI_NONE }, 2089 #define O_DBLBOUNCE 0x9a 2090 { "DoubleBounceAddress", O_DBLBOUNCE, OI_NONE }, 2091 #define O_HSDIR 0x9b 2092 { "HostStatusDirectory", O_HSDIR, OI_NONE }, 2093 #define O_SINGTHREAD 0x9c 2094 { "SingleThreadDelivery", O_SINGTHREAD, OI_NONE }, 2095 #define O_RUNASUSER 0x9d 2096 { "RunAsUser", O_RUNASUSER, OI_NONE }, 2097 #define O_DSN_RRT 0x9e 2098 { "RrtImpliesDsn", O_DSN_RRT, OI_NONE }, 2099 #define O_PIDFILE 0x9f 2100 { "PidFile", O_PIDFILE, OI_NONE }, 2101 #define O_DONTBLAMESENDMAIL 0xa0 2102 { "DontBlameSendmail", O_DONTBLAMESENDMAIL, OI_NONE }, 2103 #define O_DPI 0xa1 2104 { "DontProbeInterfaces", O_DPI, OI_NONE }, 2105 #define O_MAXRCPT 0xa2 2106 { "MaxRecipientsPerMessage", O_MAXRCPT, OI_SAFE }, 2107 #define O_DEADLETTER 0xa3 2108 { "DeadLetterDrop", O_DEADLETTER, OI_NONE }, 2109 #if _FFR_DONTLOCKFILESFORREAD_OPTION 2110 # define O_DONTLOCK 0xa4 2111 { "DontLockFilesForRead", O_DONTLOCK, OI_NONE }, 2112 #endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */ 2113 #define O_MAXALIASRCSN 0xa5 2114 { "MaxAliasRecursion", O_MAXALIASRCSN, OI_NONE }, 2115 #define O_CNCTONLYTO 0xa6 2116 { "ConnectOnlyTo", O_CNCTONLYTO, OI_NONE }, 2117 #define O_TRUSTUSER 0xa7 2118 { "TrustedUser", O_TRUSTUSER, OI_NONE }, 2119 #define O_MAXMIMEHDRLEN 0xa8 2120 { "MaxMimeHeaderLength", O_MAXMIMEHDRLEN, OI_NONE }, 2121 #define O_CONTROLSOCKET 0xa9 2122 { "ControlSocketName", O_CONTROLSOCKET, OI_NONE }, 2123 #define O_MAXHDRSLEN 0xaa 2124 { "MaxHeadersLength", O_MAXHDRSLEN, OI_NONE }, 2125 #if _FFR_MAX_FORWARD_ENTRIES 2126 # define O_MAXFORWARD 0xab 2127 { "MaxForwardEntries", O_MAXFORWARD, OI_NONE }, 2128 #endif /* _FFR_MAX_FORWARD_ENTRIES */ 2129 #define O_PROCTITLEPREFIX 0xac 2130 { "ProcessTitlePrefix", O_PROCTITLEPREFIX, OI_NONE }, 2131 #define O_SASLINFO 0xad 2132 #if _FFR_ALLOW_SASLINFO 2133 { "DefaultAuthInfo", O_SASLINFO, OI_SAFE }, 2134 #else /* _FFR_ALLOW_SASLINFO */ 2135 { "DefaultAuthInfo", O_SASLINFO, OI_NONE }, 2136 #endif /* _FFR_ALLOW_SASLINFO */ 2137 #define O_SASLMECH 0xae 2138 { "AuthMechanisms", O_SASLMECH, OI_NONE }, 2139 #define O_CLIENTPORT 0xaf 2140 { "ClientPortOptions", O_CLIENTPORT, OI_NONE }, 2141 #define O_DF_BUFSIZE 0xb0 2142 { "DataFileBufferSize", O_DF_BUFSIZE, OI_NONE }, 2143 #define O_XF_BUFSIZE 0xb1 2144 { "XscriptFileBufferSize", O_XF_BUFSIZE, OI_NONE }, 2145 #define O_LDAPDEFAULTSPEC 0xb2 2146 { "LDAPDefaultSpec", O_LDAPDEFAULTSPEC, OI_NONE }, 2147 #define O_SRVCERTFILE 0xb4 2148 { "ServerCertFile", O_SRVCERTFILE, OI_NONE }, 2149 #define O_SRVKEYFILE 0xb5 2150 { "ServerKeyFile", O_SRVKEYFILE, OI_NONE }, 2151 #define O_CLTCERTFILE 0xb6 2152 { "ClientCertFile", O_CLTCERTFILE, OI_NONE }, 2153 #define O_CLTKEYFILE 0xb7 2154 { "ClientKeyFile", O_CLTKEYFILE, OI_NONE }, 2155 #define O_CACERTFILE 0xb8 2156 { "CACertFile", O_CACERTFILE, OI_NONE }, 2157 #define O_CACERTPATH 0xb9 2158 { "CACertPath", O_CACERTPATH, OI_NONE }, 2159 #define O_DHPARAMS 0xba 2160 { "DHParameters", O_DHPARAMS, OI_NONE }, 2161 #define O_INPUTMILTER 0xbb 2162 { "InputMailFilters", O_INPUTMILTER, OI_NONE }, 2163 #define O_MILTER 0xbc 2164 { "Milter", O_MILTER, OI_SUBOPT }, 2165 #define O_SASLOPTS 0xbd 2166 { "AuthOptions", O_SASLOPTS, OI_NONE }, 2167 #define O_QUEUE_FILE_MODE 0xbe 2168 { "QueueFileMode", O_QUEUE_FILE_MODE, OI_NONE }, 2169 #if _FFR_TLS_1 2170 # define O_DHPARAMS5 0xbf 2171 { "DHParameters512", O_DHPARAMS5, OI_NONE }, 2172 # define O_CIPHERLIST 0xc0 2173 { "CipherList", O_CIPHERLIST, OI_NONE }, 2174 #endif /* _FFR_TLS_1 */ 2175 #define O_RANDFILE 0xc1 2176 { "RandFile", O_RANDFILE, OI_NONE }, 2177 #define O_TLS_SRV_OPTS 0xc2 2178 { "TLSSrvOptions", O_TLS_SRV_OPTS, OI_NONE }, 2179 #define O_RCPTTHROT 0xc3 2180 { "BadRcptThrottle", O_RCPTTHROT, OI_SAFE }, 2181 #define O_DLVR_MIN 0xc4 2182 { "DeliverByMin", O_DLVR_MIN, OI_NONE }, 2183 #define O_MAXQUEUECHILDREN 0xc5 2184 { "MaxQueueChildren", O_MAXQUEUECHILDREN, OI_NONE }, 2185 #define O_MAXRUNNERSPERQUEUE 0xc6 2186 { "MaxRunnersPerQueue", O_MAXRUNNERSPERQUEUE, OI_NONE }, 2187 #define O_DIRECTSUBMODIFIERS 0xc7 2188 { "DirectSubmissionModifiers", O_DIRECTSUBMODIFIERS, OI_NONE }, 2189 #define O_NICEQUEUERUN 0xc8 2190 { "NiceQueueRun", O_NICEQUEUERUN, OI_NONE }, 2191 #define O_SHMKEY 0xc9 2192 { "SharedMemoryKey", O_SHMKEY, OI_NONE }, 2193 #define O_SASLBITS 0xca 2194 { "AuthMaxBits", O_SASLBITS, OI_NONE }, 2195 #define O_MBDB 0xcb 2196 { "MailboxDatabase", O_MBDB, OI_NONE }, 2197 #define O_MSQ 0xcc 2198 { "UseMSP", O_MSQ, OI_NONE }, 2199 #define O_DELAY_LA 0xcd 2200 { "DelayLA", O_DELAY_LA, OI_NONE }, 2201 #define O_FASTSPLIT 0xce 2202 { "FastSplit", O_FASTSPLIT, OI_NONE }, 2203 #define O_SOFTBOUNCE 0xcf 2204 { "SoftBounce", O_SOFTBOUNCE, OI_NONE }, 2205 #define O_SHMKEYFILE 0xd0 2206 { "SharedMemoryKeyFile", O_SHMKEYFILE, OI_NONE }, 2207 #define O_REJECTLOGINTERVAL 0xd1 2208 { "RejectLogInterval", O_REJECTLOGINTERVAL, OI_NONE }, 2209 #define O_REQUIRES_DIR_FSYNC 0xd2 2210 { "RequiresDirfsync", O_REQUIRES_DIR_FSYNC, OI_NONE }, 2211 #define O_CONNECTION_RATE_WINDOW_SIZE 0xd3 2212 { "ConnectionRateWindowSize", O_CONNECTION_RATE_WINDOW_SIZE, OI_NONE }, 2213 #define O_CRLFILE 0xd4 2214 { "CRLFile", O_CRLFILE, OI_NONE }, 2215 #define O_FALLBACKSMARTHOST 0xd5 2216 { "FallbackSmartHost", O_FALLBACKSMARTHOST, OI_NONE }, 2217 #define O_SASLREALM 0xd6 2218 { "AuthRealm", O_SASLREALM, OI_NONE }, 2219 #if _FFR_CRLPATH 2220 # define O_CRLPATH 0xd7 2221 { "CRLPath", O_CRLPATH, OI_NONE }, 2222 #endif /* _FFR_CRLPATH */ 2223 #define O_HELONAME 0xd8 2224 { "HeloName", O_HELONAME, OI_NONE }, 2225 #if _FFR_MEMSTAT 2226 # define O_REFUSELOWMEM 0xd9 2227 { "RefuseLowMem", O_REFUSELOWMEM, OI_NONE }, 2228 # define O_QUEUELOWMEM 0xda 2229 { "QueueLowMem", O_QUEUELOWMEM, OI_NONE }, 2230 # define O_MEMRESOURCE 0xdb 2231 { "MemoryResource", O_MEMRESOURCE, OI_NONE }, 2232 #endif /* _FFR_MEMSTAT */ 2233 #define O_MAXNOOPCOMMANDS 0xdc 2234 { "MaxNOOPCommands", O_MAXNOOPCOMMANDS, OI_NONE }, 2235 #if _FFR_MSG_ACCEPT 2236 # define O_MSG_ACCEPT 0xdd 2237 { "MessageAccept", O_MSG_ACCEPT, OI_NONE }, 2238 #endif /* _FFR_MSG_ACCEPT */ 2239 #if _FFR_QUEUE_RUN_PARANOIA 2240 # define O_CHK_Q_RUNNERS 0xde 2241 { "CheckQueueRunners", O_CHK_Q_RUNNERS, OI_NONE }, 2242 #endif /* _FFR_QUEUE_RUN_PARANOIA */ 2243 #if _FFR_EIGHT_BIT_ADDR_OK 2244 # if !ALLOW_255 2245 # ERROR FFR_EIGHT_BIT_ADDR_OK requires _ALLOW_255 2246 # endif /* !ALLOW_255 */ 2247 # define O_EIGHT_BIT_ADDR_OK 0xdf 2248 { "EightBitAddrOK", O_EIGHT_BIT_ADDR_OK, OI_NONE }, 2249 #endif /* _FFR_EIGHT_BIT_ADDR_OK */ 2250 #if _FFR_ADDR_TYPE_MODES 2251 # define O_ADDR_TYPE_MODES 0xe0 2252 { "AddrTypeModes", O_ADDR_TYPE_MODES, OI_NONE }, 2253 #endif /* _FFR_ADDR_TYPE_MODES */ 2254 #if _FFR_BADRCPT_SHUTDOWN 2255 # define O_RCPTSHUTD 0xe1 2256 { "BadRcptShutdown", O_RCPTSHUTD, OI_SAFE }, 2257 # define O_RCPTSHUTDG 0xe2 2258 { "BadRcptShutdownGood", O_RCPTSHUTDG, OI_SAFE }, 2259 #endif /* _FFR_BADRCPT_SHUTDOWN */ 2260 #if STARTTLS && _FFR_TLS_1 2261 # define O_SRV_SSL_OPTIONS 0xe3 2262 { "ServerSSLOptions", O_SRV_SSL_OPTIONS, OI_NONE }, 2263 # define O_CLT_SSL_OPTIONS 0xe4 2264 { "ClientSSLOptions", O_CLT_SSL_OPTIONS, OI_NONE }, 2265 #endif /* STARTTLS && _FFR_TLS_1 */ 2266 #if _FFR_EXPDELAY 2267 # define O_MAX_QUEUE_AGE 0xe5 2268 { "MaxQueueAge", O_MAX_QUEUE_AGE, OI_NONE }, 2269 #endif /* _FFR_EXPDELAY */ 2270 #if _FFR_RCPTTHROTDELAY 2271 # define O_RCPTTHROTDELAY 0xe6 2272 { "BadRcptThrottleDelay", O_RCPTTHROTDELAY, OI_SAFE }, 2273 #endif /* _FFR_RCPTTHROTDELAY */ 2274 2275 { NULL, '\0', OI_NONE } 2276 }; 2277 2278 #if STARTTLS && _FFR_TLS_1 2279 static struct ssl_options 2280 { 2281 const char *sslopt_name; /* name of the flag */ 2282 long sslopt_bits; /* bits to set/clear */ 2283 } SSL_Option[] = 2284 { 2285 /* these are turned on by default */ 2286 #ifdef SSL_OP_MICROSOFT_SESS_ID_BUG 2287 { "SSL_OP_MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG }, 2288 #endif /* SSL_OP_MICROSOFT_SESS_ID_BUG */ 2289 #ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG 2290 { "SSL_OP_NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG }, 2291 #endif /* SSL_OP_NETSCAPE_CHALLENGE_BUG */ 2292 #ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 2293 { "SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG }, 2294 #endif /* SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG */ 2295 #ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 2296 { "SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG }, 2297 #endif /* SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG */ 2298 #ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 2299 { "SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER }, 2300 #endif /* SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER */ 2301 #ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING 2302 { "SSL_OP_MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING }, 2303 #endif /* SSL_OP_MSIE_SSLV2_RSA_PADDING */ 2304 #ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG 2305 { "SSL_OP_SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG }, 2306 #endif /* SSL_OP_SSLEAY_080_CLIENT_DH_BUG */ 2307 #ifdef SSL_OP_TLS_D5_BUG 2308 { "SSL_OP_TLS_D5_BUG", SSL_OP_TLS_D5_BUG }, 2309 #endif /* SSL_OP_TLS_D5_BUG */ 2310 #ifdef SSL_OP_TLS_BLOCK_PADDING_BUG 2311 { "SSL_OP_TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG }, 2312 #endif /* SSL_OP_TLS_BLOCK_PADDING_BUG */ 2313 #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 2314 { "SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS }, 2315 #endif /* SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */ 2316 { "SSL_OP_ALL", SSL_OP_ALL }, 2317 #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 2318 { "SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION }, 2319 #endif /* SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION */ 2320 #ifdef SSL_OP_EPHEMERAL_RSA 2321 { "SSL_OP_EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA }, 2322 #endif /* SSL_OP_EPHEMERAL_RSA */ 2323 #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE 2324 { "SSL_OP_CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE }, 2325 #endif /* SSL_OP_CIPHER_SERVER_PREFERENCE */ 2326 #ifdef SSL_OP_TLS_ROLLBACK_BUG 2327 { "SSL_OP_TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG }, 2328 #endif /* SSL_OP_TLS_ROLLBACK_BUG */ 2329 #ifdef SSL_OP_NO_SSLv2 2330 { "SSL_OP_NO_SSLv2", SSL_OP_NO_SSLv2 }, 2331 #endif /* SSL_OP_NO_SSLv2 */ 2332 #ifdef SSL_OP_NO_SSLv3 2333 { "SSL_OP_NO_SSLv3", SSL_OP_NO_SSLv3 }, 2334 #endif /* SSL_OP_NO_SSLv3 */ 2335 #ifdef SSL_OP_NO_TLSv1 2336 { "SSL_OP_NO_TLSv1", SSL_OP_NO_TLSv1 }, 2337 #endif /* SSL_OP_NO_TLSv1 */ 2338 #ifdef SSL_OP_PKCS1_CHECK_1 2339 { "SSL_OP_PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1 }, 2340 #endif /* SSL_OP_PKCS1_CHECK_1 */ 2341 #ifdef SSL_OP_PKCS1_CHECK_2 2342 { "SSL_OP_PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2 }, 2343 #endif /* SSL_OP_PKCS1_CHECK_2 */ 2344 #ifdef SSL_OP_NETSCAPE_CA_DN_BUG 2345 { "SSL_OP_NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG }, 2346 #endif /* SSL_OP_NETSCAPE_CA_DN_BUG */ 2347 #ifdef SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 2348 { "SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG }, 2349 #endif /* SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG */ 2350 { NULL, 0 } 2351 }; 2352 #endif /* STARTTLS && _FFR_TLS_1 */ 2353 2354 2355 # define CANONIFY(val) 2356 2357 # define SET_OPT_DEFAULT(opt, val) opt = val 2358 2359 /* set a string option by expanding the value and assigning it */ 2360 /* WARNING this belongs ONLY into a case statement! */ 2361 #define SET_STRING_EXP(str) \ 2362 expand(val, exbuf, sizeof(exbuf), e); \ 2363 newval = sm_pstrdup_x(exbuf); \ 2364 if (str != NULL) \ 2365 sm_free(str); \ 2366 CANONIFY(newval); \ 2367 str = newval; \ 2368 break 2369 2370 #define OPTNAME o->o_name == NULL ? "<unknown>" : o->o_name 2371 2372 void 2373 setoption(opt, val, safe, sticky, e) 2374 int opt; 2375 char *val; 2376 bool safe; 2377 bool sticky; 2378 register ENVELOPE *e; 2379 { 2380 register char *p; 2381 register struct optioninfo *o; 2382 char *subopt; 2383 int mid; 2384 bool can_setuid = RunAsUid == 0; 2385 auto char *ep; 2386 char buf[50]; 2387 extern bool Warn_Q_option; 2388 #if _FFR_ALLOW_SASLINFO 2389 extern unsigned int SubmitMode; 2390 #endif /* _FFR_ALLOW_SASLINFO */ 2391 #if STARTTLS || SM_CONF_SHM 2392 char *newval; 2393 char exbuf[MAXLINE]; 2394 #endif /* STARTTLS || SM_CONF_SHM */ 2395 #if STARTTLS && _FFR_TLS_1 2396 long *pssloptions = NULL; 2397 #endif /* STARTTLS && _FFR_TLS_1 */ 2398 2399 errno = 0; 2400 if (opt == ' ') 2401 { 2402 /* full word options */ 2403 struct optioninfo *sel; 2404 2405 p = strchr(val, '='); 2406 if (p == NULL) 2407 p = &val[strlen(val)]; 2408 while (*--p == ' ') 2409 continue; 2410 while (*++p == ' ') 2411 *p = '\0'; 2412 if (p == val) 2413 { 2414 syserr("readcf: null option name"); 2415 return; 2416 } 2417 if (*p == '=') 2418 *p++ = '\0'; 2419 while (*p == ' ') 2420 p++; 2421 subopt = strchr(val, '.'); 2422 if (subopt != NULL) 2423 *subopt++ = '\0'; 2424 sel = NULL; 2425 for (o = OptionTab; o->o_name != NULL; o++) 2426 { 2427 if (sm_strncasecmp(o->o_name, val, strlen(val)) != 0) 2428 continue; 2429 if (strlen(o->o_name) == strlen(val)) 2430 { 2431 /* completely specified -- this must be it */ 2432 sel = NULL; 2433 break; 2434 } 2435 if (sel != NULL) 2436 break; 2437 sel = o; 2438 } 2439 if (sel != NULL && o->o_name == NULL) 2440 o = sel; 2441 else if (o->o_name == NULL) 2442 { 2443 syserr("readcf: unknown option name %s", val); 2444 return; 2445 } 2446 else if (sel != NULL) 2447 { 2448 syserr("readcf: ambiguous option name %s (matches %s and %s)", 2449 val, sel->o_name, o->o_name); 2450 return; 2451 } 2452 if (strlen(val) != strlen(o->o_name)) 2453 { 2454 int oldVerbose = Verbose; 2455 2456 Verbose = 1; 2457 message("Option %s used as abbreviation for %s", 2458 val, o->o_name); 2459 Verbose = oldVerbose; 2460 } 2461 opt = o->o_code; 2462 val = p; 2463 } 2464 else 2465 { 2466 for (o = OptionTab; o->o_name != NULL; o++) 2467 { 2468 if (o->o_code == opt) 2469 break; 2470 } 2471 if (o->o_name == NULL) 2472 { 2473 syserr("readcf: unknown option name 0x%x", opt & 0xff); 2474 return; 2475 } 2476 subopt = NULL; 2477 } 2478 2479 if (subopt != NULL && !bitset(OI_SUBOPT, o->o_flags)) 2480 { 2481 if (tTd(37, 1)) 2482 sm_dprintf("setoption: %s does not support suboptions, ignoring .%s\n", 2483 OPTNAME, subopt); 2484 subopt = NULL; 2485 } 2486 2487 if (tTd(37, 1)) 2488 { 2489 sm_dprintf(isascii(opt) && isprint(opt) ? 2490 "setoption %s (%c)%s%s=" : 2491 "setoption %s (0x%x)%s%s=", 2492 OPTNAME, opt, subopt == NULL ? "" : ".", 2493 subopt == NULL ? "" : subopt); 2494 xputs(sm_debug_file(), val); 2495 } 2496 2497 /* 2498 ** See if this option is preset for us. 2499 */ 2500 2501 if (!sticky && bitnset(opt, StickyOpt)) 2502 { 2503 if (tTd(37, 1)) 2504 sm_dprintf(" (ignored)\n"); 2505 return; 2506 } 2507 2508 /* 2509 ** Check to see if this option can be specified by this user. 2510 */ 2511 2512 if (!safe && RealUid == 0) 2513 safe = true; 2514 if (!safe && !bitset(OI_SAFE, o->o_flags)) 2515 { 2516 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 2517 { 2518 int dp; 2519 2520 if (tTd(37, 1)) 2521 sm_dprintf(" (unsafe)"); 2522 dp = drop_privileges(true); 2523 setstat(dp); 2524 } 2525 } 2526 if (tTd(37, 1)) 2527 sm_dprintf("\n"); 2528 2529 switch (opt & 0xff) 2530 { 2531 case '7': /* force seven-bit input */ 2532 SevenBitInput = atobool(val); 2533 break; 2534 2535 case '8': /* handling of 8-bit input */ 2536 #if MIME8TO7 2537 switch (*val) 2538 { 2539 case 'p': /* pass 8 bit, convert MIME */ 2540 MimeMode = MM_CVTMIME|MM_PASS8BIT; 2541 break; 2542 2543 case 'm': /* convert 8-bit, convert MIME */ 2544 MimeMode = MM_CVTMIME|MM_MIME8BIT; 2545 break; 2546 2547 case 's': /* strict adherence */ 2548 MimeMode = MM_CVTMIME; 2549 break; 2550 2551 # if 0 2552 case 'r': /* reject 8-bit, don't convert MIME */ 2553 MimeMode = 0; 2554 break; 2555 2556 case 'j': /* "just send 8" */ 2557 MimeMode = MM_PASS8BIT; 2558 break; 2559 2560 case 'a': /* encode 8 bit if available */ 2561 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 2562 break; 2563 2564 case 'c': /* convert 8 bit to MIME, never 7 bit */ 2565 MimeMode = MM_MIME8BIT; 2566 break; 2567 # endif /* 0 */ 2568 2569 default: 2570 syserr("Unknown 8-bit mode %c", *val); 2571 finis(false, true, EX_USAGE); 2572 } 2573 #else /* MIME8TO7 */ 2574 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 2575 "Warning: Option: %s requires MIME8TO7 support\n", 2576 OPTNAME); 2577 #endif /* MIME8TO7 */ 2578 break; 2579 2580 case 'A': /* set default alias file */ 2581 if (val[0] == '\0') 2582 { 2583 char *al; 2584 2585 SET_OPT_DEFAULT(al, "aliases"); 2586 setalias(al); 2587 } 2588 else 2589 setalias(val); 2590 break; 2591 2592 case 'a': /* look N minutes for "@:@" in alias file */ 2593 if (val[0] == '\0') 2594 SafeAlias = 5 MINUTES; 2595 else 2596 SafeAlias = convtime(val, 'm'); 2597 break; 2598 2599 case 'B': /* substitution for blank character */ 2600 SpaceSub = val[0]; 2601 if (SpaceSub == '\0') 2602 SpaceSub = ' '; 2603 break; 2604 2605 case 'b': /* min blocks free on queue fs/max msg size */ 2606 p = strchr(val, '/'); 2607 if (p != NULL) 2608 { 2609 *p++ = '\0'; 2610 MaxMessageSize = atol(p); 2611 } 2612 MinBlocksFree = atol(val); 2613 break; 2614 2615 case 'c': /* don't connect to "expensive" mailers */ 2616 NoConnect = atobool(val); 2617 break; 2618 2619 case 'C': /* checkpoint every N addresses */ 2620 if (safe || CheckpointInterval > atoi(val)) 2621 CheckpointInterval = atoi(val); 2622 break; 2623 2624 case 'd': /* delivery mode */ 2625 switch (*val) 2626 { 2627 case '\0': 2628 set_delivery_mode(SM_DELIVER, e); 2629 break; 2630 2631 case SM_QUEUE: /* queue only */ 2632 case SM_DEFER: /* queue only and defer map lookups */ 2633 case SM_DELIVER: /* do everything */ 2634 case SM_FORK: /* fork after verification */ 2635 #if _FFR_DM_ONE 2636 /* deliver first TA in background, then queue */ 2637 case SM_DM_ONE: 2638 #endif /* _FFR_DM_ONE */ 2639 set_delivery_mode(*val, e); 2640 break; 2641 2642 default: 2643 syserr("Unknown delivery mode %c", *val); 2644 finis(false, true, EX_USAGE); 2645 } 2646 break; 2647 2648 case 'E': /* error message header/header file */ 2649 if (*val != '\0') 2650 ErrMsgFile = newstr(val); 2651 break; 2652 2653 case 'e': /* set error processing mode */ 2654 switch (*val) 2655 { 2656 case EM_QUIET: /* be silent about it */ 2657 case EM_MAIL: /* mail back */ 2658 case EM_BERKNET: /* do berknet error processing */ 2659 case EM_WRITE: /* write back (or mail) */ 2660 case EM_PRINT: /* print errors normally (default) */ 2661 e->e_errormode = *val; 2662 break; 2663 } 2664 break; 2665 2666 case 'F': /* file mode */ 2667 FileMode = atooct(val) & 0777; 2668 break; 2669 2670 case 'f': /* save Unix-style From lines on front */ 2671 SaveFrom = atobool(val); 2672 break; 2673 2674 case 'G': /* match recipients against GECOS field */ 2675 MatchGecos = atobool(val); 2676 break; 2677 2678 case 'g': /* default gid */ 2679 g_opt: 2680 if (isascii(*val) && isdigit(*val)) 2681 DefGid = atoi(val); 2682 else 2683 { 2684 register struct group *gr; 2685 2686 DefGid = -1; 2687 gr = getgrnam(val); 2688 if (gr == NULL) 2689 syserr("readcf: option %c: unknown group %s", 2690 opt, val); 2691 else 2692 DefGid = gr->gr_gid; 2693 } 2694 break; 2695 2696 case 'H': /* help file */ 2697 if (val[0] == '\0') 2698 { 2699 SET_OPT_DEFAULT(HelpFile, "helpfile"); 2700 } 2701 else 2702 { 2703 CANONIFY(val); 2704 HelpFile = newstr(val); 2705 } 2706 break; 2707 2708 case 'h': /* maximum hop count */ 2709 MaxHopCount = atoi(val); 2710 break; 2711 2712 case 'I': /* use internet domain name server */ 2713 #if NAMED_BIND 2714 for (p = val; *p != 0; ) 2715 { 2716 bool clearmode; 2717 char *q; 2718 struct resolverflags *rfp; 2719 2720 while (*p == ' ') 2721 p++; 2722 if (*p == '\0') 2723 break; 2724 clearmode = false; 2725 if (*p == '-') 2726 clearmode = true; 2727 else if (*p != '+') 2728 p--; 2729 p++; 2730 q = p; 2731 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2732 p++; 2733 if (*p != '\0') 2734 *p++ = '\0'; 2735 if (sm_strcasecmp(q, "HasWildcardMX") == 0) 2736 { 2737 HasWildcardMX = !clearmode; 2738 continue; 2739 } 2740 if (sm_strcasecmp(q, "WorkAroundBrokenAAAA") == 0) 2741 { 2742 WorkAroundBrokenAAAA = !clearmode; 2743 continue; 2744 } 2745 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 2746 { 2747 if (sm_strcasecmp(q, rfp->rf_name) == 0) 2748 break; 2749 } 2750 if (rfp->rf_name == NULL) 2751 syserr("readcf: I option value %s unrecognized", q); 2752 else if (clearmode) 2753 _res.options &= ~rfp->rf_bits; 2754 else 2755 _res.options |= rfp->rf_bits; 2756 } 2757 if (tTd(8, 2)) 2758 sm_dprintf("_res.options = %x, HasWildcardMX = %d\n", 2759 (unsigned int) _res.options, HasWildcardMX); 2760 #else /* NAMED_BIND */ 2761 usrerr("name server (I option) specified but BIND not compiled in"); 2762 #endif /* NAMED_BIND */ 2763 break; 2764 2765 case 'i': /* ignore dot lines in message */ 2766 IgnrDot = atobool(val); 2767 break; 2768 2769 case 'j': /* send errors in MIME (RFC 1341) format */ 2770 SendMIMEErrors = atobool(val); 2771 break; 2772 2773 case 'J': /* .forward search path */ 2774 CANONIFY(val); 2775 ForwardPath = newstr(val); 2776 break; 2777 2778 case 'k': /* connection cache size */ 2779 MaxMciCache = atoi(val); 2780 if (MaxMciCache < 0) 2781 MaxMciCache = 0; 2782 break; 2783 2784 case 'K': /* connection cache timeout */ 2785 MciCacheTimeout = convtime(val, 'm'); 2786 break; 2787 2788 case 'l': /* use Errors-To: header */ 2789 UseErrorsTo = atobool(val); 2790 break; 2791 2792 case 'L': /* log level */ 2793 if (safe || LogLevel < atoi(val)) 2794 LogLevel = atoi(val); 2795 break; 2796 2797 case 'M': /* define macro */ 2798 sticky = false; 2799 mid = macid_parse(val, &ep); 2800 if (mid == 0) 2801 break; 2802 p = newstr(ep); 2803 if (!safe) 2804 cleanstrcpy(p, p, strlen(p) + 1); 2805 macdefine(&CurEnv->e_macro, A_TEMP, mid, p); 2806 break; 2807 2808 case 'm': /* send to me too */ 2809 MeToo = atobool(val); 2810 break; 2811 2812 case 'n': /* validate RHS in newaliases */ 2813 CheckAliases = atobool(val); 2814 break; 2815 2816 /* 'N' available -- was "net name" */ 2817 2818 case 'O': /* daemon options */ 2819 if (!setdaemonoptions(val)) 2820 syserr("too many daemons defined (%d max)", MAXDAEMONS); 2821 break; 2822 2823 case 'o': /* assume old style headers */ 2824 if (atobool(val)) 2825 CurEnv->e_flags |= EF_OLDSTYLE; 2826 else 2827 CurEnv->e_flags &= ~EF_OLDSTYLE; 2828 break; 2829 2830 case 'p': /* select privacy level */ 2831 p = val; 2832 for (;;) 2833 { 2834 register struct prival *pv; 2835 extern struct prival PrivacyValues[]; 2836 2837 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 2838 p++; 2839 if (*p == '\0') 2840 break; 2841 val = p; 2842 while (isascii(*p) && isalnum(*p)) 2843 p++; 2844 if (*p != '\0') 2845 *p++ = '\0'; 2846 2847 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 2848 { 2849 if (sm_strcasecmp(val, pv->pv_name) == 0) 2850 break; 2851 } 2852 if (pv->pv_name == NULL) 2853 syserr("readcf: Op line: %s unrecognized", val); 2854 else 2855 PrivacyFlags |= pv->pv_flag; 2856 } 2857 sticky = false; 2858 break; 2859 2860 case 'P': /* postmaster copy address for returned mail */ 2861 PostMasterCopy = newstr(val); 2862 break; 2863 2864 case 'q': /* slope of queue only function */ 2865 QueueFactor = atoi(val); 2866 break; 2867 2868 case 'Q': /* queue directory */ 2869 if (val[0] == '\0') 2870 { 2871 QueueDir = "mqueue"; 2872 } 2873 else 2874 { 2875 QueueDir = newstr(val); 2876 } 2877 if (RealUid != 0 && !safe) 2878 Warn_Q_option = true; 2879 break; 2880 2881 case 'R': /* don't prune routes */ 2882 DontPruneRoutes = atobool(val); 2883 break; 2884 2885 case 'r': /* read timeout */ 2886 if (subopt == NULL) 2887 inittimeouts(val, sticky); 2888 else 2889 settimeout(subopt, val, sticky); 2890 break; 2891 2892 case 'S': /* status file */ 2893 if (val[0] == '\0') 2894 { 2895 SET_OPT_DEFAULT(StatFile, "statistics"); 2896 } 2897 else 2898 { 2899 CANONIFY(val); 2900 StatFile = newstr(val); 2901 } 2902 break; 2903 2904 case 's': /* be super safe, even if expensive */ 2905 if (tolower(*val) == 'i') 2906 SuperSafe = SAFE_INTERACTIVE; 2907 else if (tolower(*val) == 'p') 2908 #if MILTER 2909 SuperSafe = SAFE_REALLY_POSTMILTER; 2910 #else /* MILTER */ 2911 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 2912 "Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n"); 2913 #endif /* MILTER */ 2914 else 2915 SuperSafe = atobool(val) ? SAFE_REALLY : SAFE_NO; 2916 break; 2917 2918 case 'T': /* queue timeout */ 2919 p = strchr(val, '/'); 2920 if (p != NULL) 2921 { 2922 *p++ = '\0'; 2923 settimeout("queuewarn", p, sticky); 2924 } 2925 settimeout("queuereturn", val, sticky); 2926 break; 2927 2928 case 't': /* time zone name */ 2929 TimeZoneSpec = newstr(val); 2930 break; 2931 2932 case 'U': /* location of user database */ 2933 UdbSpec = newstr(val); 2934 break; 2935 2936 case 'u': /* set default uid */ 2937 for (p = val; *p != '\0'; p++) 2938 { 2939 # if _FFR_DOTTED_USERNAMES 2940 if (*p == '/' || *p == ':') 2941 # else /* _FFR_DOTTED_USERNAMES */ 2942 if (*p == '.' || *p == '/' || *p == ':') 2943 # endif /* _FFR_DOTTED_USERNAMES */ 2944 { 2945 *p++ = '\0'; 2946 break; 2947 } 2948 } 2949 if (isascii(*val) && isdigit(*val)) 2950 { 2951 DefUid = atoi(val); 2952 setdefuser(); 2953 } 2954 else 2955 { 2956 register struct passwd *pw; 2957 2958 DefUid = -1; 2959 pw = sm_getpwnam(val); 2960 if (pw == NULL) 2961 { 2962 syserr("readcf: option u: unknown user %s", val); 2963 break; 2964 } 2965 else 2966 { 2967 DefUid = pw->pw_uid; 2968 DefGid = pw->pw_gid; 2969 DefUser = newstr(pw->pw_name); 2970 } 2971 } 2972 2973 # ifdef UID_MAX 2974 if (DefUid > UID_MAX) 2975 { 2976 syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored", 2977 (long)DefUid, (long)UID_MAX); 2978 break; 2979 } 2980 # endif /* UID_MAX */ 2981 2982 /* handle the group if it is there */ 2983 if (*p == '\0') 2984 break; 2985 val = p; 2986 goto g_opt; 2987 2988 case 'V': /* fallback MX host */ 2989 if (val[0] != '\0') 2990 FallbackMX = newstr(val); 2991 break; 2992 2993 case 'v': /* run in verbose mode */ 2994 Verbose = atobool(val) ? 1 : 0; 2995 break; 2996 2997 case 'w': /* if we are best MX, try host directly */ 2998 TryNullMXList = atobool(val); 2999 break; 3000 3001 /* 'W' available -- was wizard password */ 3002 3003 case 'x': /* load avg at which to auto-queue msgs */ 3004 QueueLA = atoi(val); 3005 break; 3006 3007 case 'X': /* load avg at which to auto-reject connections */ 3008 RefuseLA = atoi(val); 3009 break; 3010 3011 case O_DELAY_LA: /* load avg at which to delay connections */ 3012 DelayLA = atoi(val); 3013 break; 3014 3015 case 'y': /* work recipient factor */ 3016 WkRecipFact = atoi(val); 3017 break; 3018 3019 case 'Y': /* fork jobs during queue runs */ 3020 ForkQueueRuns = atobool(val); 3021 break; 3022 3023 case 'z': /* work message class factor */ 3024 WkClassFact = atoi(val); 3025 break; 3026 3027 case 'Z': /* work time factor */ 3028 WkTimeFact = atoi(val); 3029 break; 3030 3031 3032 #if _FFR_QUEUE_GROUP_SORTORDER 3033 /* coordinate this with makequeue() */ 3034 #endif /* _FFR_QUEUE_GROUP_SORTORDER */ 3035 case O_QUEUESORTORD: /* queue sorting order */ 3036 switch (*val) 3037 { 3038 case 'f': /* File Name */ 3039 case 'F': 3040 QueueSortOrder = QSO_BYFILENAME; 3041 break; 3042 3043 case 'h': /* Host first */ 3044 case 'H': 3045 QueueSortOrder = QSO_BYHOST; 3046 break; 3047 3048 case 'm': /* Modification time */ 3049 case 'M': 3050 QueueSortOrder = QSO_BYMODTIME; 3051 break; 3052 3053 case 'p': /* Priority order */ 3054 case 'P': 3055 QueueSortOrder = QSO_BYPRIORITY; 3056 break; 3057 3058 case 't': /* Submission time */ 3059 case 'T': 3060 QueueSortOrder = QSO_BYTIME; 3061 break; 3062 3063 case 'r': /* Random */ 3064 case 'R': 3065 QueueSortOrder = QSO_RANDOM; 3066 break; 3067 3068 #if _FFR_RHS 3069 case 's': /* Shuffled host name */ 3070 case 'S': 3071 QueueSortOrder = QSO_BYSHUFFLE; 3072 break; 3073 #endif /* _FFR_RHS */ 3074 3075 case 'n': /* none */ 3076 case 'N': 3077 QueueSortOrder = QSO_NONE; 3078 break; 3079 3080 default: 3081 syserr("Invalid queue sort order \"%s\"", val); 3082 } 3083 break; 3084 3085 case O_HOSTSFILE: /* pathname of /etc/hosts file */ 3086 CANONIFY(val); 3087 HostsFile = newstr(val); 3088 break; 3089 3090 case O_MQA: /* minimum queue age between deliveries */ 3091 MinQueueAge = convtime(val, 'm'); 3092 break; 3093 3094 #if _FFR_EXPDELAY 3095 case O_MAX_QUEUE_AGE: 3096 MaxQueueAge = convtime(val, 'm'); 3097 break; 3098 #endif /* _FFR_EXPDELAY */ 3099 3100 case O_DEFCHARSET: /* default character set for mimefying */ 3101 DefaultCharSet = newstr(denlstring(val, true, true)); 3102 break; 3103 3104 case O_SSFILE: /* service switch file */ 3105 CANONIFY(val); 3106 ServiceSwitchFile = newstr(val); 3107 break; 3108 3109 case O_DIALDELAY: /* delay for dial-on-demand operation */ 3110 DialDelay = convtime(val, 's'); 3111 break; 3112 3113 case O_NORCPTACTION: /* what to do if no recipient */ 3114 if (sm_strcasecmp(val, "none") == 0) 3115 NoRecipientAction = NRA_NO_ACTION; 3116 else if (sm_strcasecmp(val, "add-to") == 0) 3117 NoRecipientAction = NRA_ADD_TO; 3118 else if (sm_strcasecmp(val, "add-apparently-to") == 0) 3119 NoRecipientAction = NRA_ADD_APPARENTLY_TO; 3120 else if (sm_strcasecmp(val, "add-bcc") == 0) 3121 NoRecipientAction = NRA_ADD_BCC; 3122 else if (sm_strcasecmp(val, "add-to-undisclosed") == 0) 3123 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 3124 else 3125 syserr("Invalid NoRecipientAction: %s", val); 3126 break; 3127 3128 case O_SAFEFILEENV: /* chroot() environ for writing to files */ 3129 if (*val == '\0') 3130 break; 3131 3132 /* strip trailing slashes */ 3133 p = val + strlen(val) - 1; 3134 while (p >= val && *p == '/') 3135 *p-- = '\0'; 3136 3137 if (*val == '\0') 3138 break; 3139 3140 SafeFileEnv = newstr(val); 3141 break; 3142 3143 case O_MAXMSGSIZE: /* maximum message size */ 3144 MaxMessageSize = atol(val); 3145 break; 3146 3147 case O_COLONOKINADDR: /* old style handling of colon addresses */ 3148 ColonOkInAddr = atobool(val); 3149 break; 3150 3151 case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 3152 MaxQueueRun = atoi(val); 3153 break; 3154 3155 case O_MAXCHILDREN: /* max # of children of daemon */ 3156 MaxChildren = atoi(val); 3157 break; 3158 3159 case O_MAXQUEUECHILDREN: /* max # of children of daemon */ 3160 MaxQueueChildren = atoi(val); 3161 break; 3162 3163 case O_MAXRUNNERSPERQUEUE: /* max # runners in a queue group */ 3164 MaxRunnersPerQueue = atoi(val); 3165 break; 3166 3167 case O_NICEQUEUERUN: /* nice queue runs */ 3168 #if !HASNICE 3169 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3170 "Warning: NiceQueueRun set on system that doesn't support nice()\n"); 3171 #endif /* !HASNICE */ 3172 3173 /* XXX do we want to check the range? > 0 ? */ 3174 NiceQueueRun = atoi(val); 3175 break; 3176 3177 case O_SHMKEY: /* shared memory key */ 3178 #if SM_CONF_SHM 3179 ShmKey = atol(val); 3180 #else /* SM_CONF_SHM */ 3181 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3182 "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n", 3183 OPTNAME); 3184 #endif /* SM_CONF_SHM */ 3185 break; 3186 3187 case O_SHMKEYFILE: /* shared memory key file */ 3188 #if SM_CONF_SHM 3189 SET_STRING_EXP(ShmKeyFile); 3190 #else /* SM_CONF_SHM */ 3191 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3192 "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n", 3193 OPTNAME); 3194 break; 3195 #endif /* SM_CONF_SHM */ 3196 3197 #if _FFR_MAX_FORWARD_ENTRIES 3198 case O_MAXFORWARD: /* max # of forward entries */ 3199 MaxForwardEntries = atoi(val); 3200 break; 3201 #endif /* _FFR_MAX_FORWARD_ENTRIES */ 3202 3203 case O_KEEPCNAMES: /* don't expand CNAME records */ 3204 DontExpandCnames = atobool(val); 3205 break; 3206 3207 case O_MUSTQUOTE: /* must quote these characters in phrases */ 3208 (void) sm_strlcpy(buf, "@,;:\\()[]", sizeof(buf)); 3209 if (strlen(val) < sizeof(buf) - 10) 3210 (void) sm_strlcat(buf, val, sizeof(buf)); 3211 else 3212 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3213 "Warning: MustQuoteChars too long, ignored.\n"); 3214 MustQuoteChars = newstr(buf); 3215 break; 3216 3217 case O_SMTPGREETING: /* SMTP greeting message (old $e macro) */ 3218 SmtpGreeting = newstr(munchstring(val, NULL, '\0')); 3219 break; 3220 3221 case O_UNIXFROM: /* UNIX From_ line (old $l macro) */ 3222 UnixFromLine = newstr(munchstring(val, NULL, '\0')); 3223 break; 3224 3225 case O_OPCHARS: /* operator characters (old $o macro) */ 3226 if (OperatorChars != NULL) 3227 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3228 "Warning: OperatorChars is being redefined.\n It should only be set before ruleset definitions.\n"); 3229 OperatorChars = newstr(munchstring(val, NULL, '\0')); 3230 break; 3231 3232 case O_DONTINITGRPS: /* don't call initgroups(3) */ 3233 DontInitGroups = atobool(val); 3234 break; 3235 3236 case O_SLFH: /* make sure from fits on one line */ 3237 SingleLineFromHeader = atobool(val); 3238 break; 3239 3240 case O_ABH: /* allow HELO commands with syntax errors */ 3241 AllowBogusHELO = atobool(val); 3242 break; 3243 3244 case O_CONNTHROT: /* connection rate throttle */ 3245 ConnRateThrottle = atoi(val); 3246 break; 3247 3248 case O_UGW: /* group writable files are unsafe */ 3249 if (!atobool(val)) 3250 { 3251 setbitn(DBS_GROUPWRITABLEFORWARDFILESAFE, 3252 DontBlameSendmail); 3253 setbitn(DBS_GROUPWRITABLEINCLUDEFILESAFE, 3254 DontBlameSendmail); 3255 } 3256 break; 3257 3258 case O_DBLBOUNCE: /* address to which to send double bounces */ 3259 DoubleBounceAddr = newstr(val); 3260 break; 3261 3262 case O_HSDIR: /* persistent host status directory */ 3263 if (val[0] != '\0') 3264 { 3265 CANONIFY(val); 3266 HostStatDir = newstr(val); 3267 } 3268 break; 3269 3270 case O_SINGTHREAD: /* single thread deliveries (requires hsdir) */ 3271 SingleThreadDelivery = atobool(val); 3272 break; 3273 3274 case O_RUNASUSER: /* run bulk of code as this user */ 3275 for (p = val; *p != '\0'; p++) 3276 { 3277 # if _FFR_DOTTED_USERNAMES 3278 if (*p == '/' || *p == ':') 3279 # else /* _FFR_DOTTED_USERNAMES */ 3280 if (*p == '.' || *p == '/' || *p == ':') 3281 # endif /* _FFR_DOTTED_USERNAMES */ 3282 { 3283 *p++ = '\0'; 3284 break; 3285 } 3286 } 3287 if (isascii(*val) && isdigit(*val)) 3288 { 3289 if (can_setuid) 3290 RunAsUid = atoi(val); 3291 } 3292 else 3293 { 3294 register struct passwd *pw; 3295 3296 pw = sm_getpwnam(val); 3297 if (pw == NULL) 3298 { 3299 syserr("readcf: option RunAsUser: unknown user %s", val); 3300 break; 3301 } 3302 else if (can_setuid) 3303 { 3304 if (*p == '\0') 3305 RunAsUserName = newstr(val); 3306 RunAsUid = pw->pw_uid; 3307 RunAsGid = pw->pw_gid; 3308 } 3309 else if (EffGid == pw->pw_gid) 3310 RunAsGid = pw->pw_gid; 3311 else if (UseMSP && *p == '\0') 3312 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3313 "WARNING: RunAsUser for MSP ignored, check group ids (egid=%d, want=%d)\n", 3314 (int) EffGid, 3315 (int) pw->pw_gid); 3316 } 3317 # ifdef UID_MAX 3318 if (RunAsUid > UID_MAX) 3319 { 3320 syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored", 3321 (long) RunAsUid, (long) UID_MAX); 3322 break; 3323 } 3324 # endif /* UID_MAX */ 3325 if (*p != '\0') 3326 { 3327 if (isascii(*p) && isdigit(*p)) 3328 { 3329 gid_t runasgid; 3330 3331 runasgid = (gid_t) atoi(p); 3332 if (can_setuid || EffGid == runasgid) 3333 RunAsGid = runasgid; 3334 else if (UseMSP) 3335 (void) sm_io_fprintf(smioout, 3336 SM_TIME_DEFAULT, 3337 "WARNING: RunAsUser for MSP ignored, check group ids (egid=%d, want=%d)\n", 3338 (int) EffGid, 3339 (int) runasgid); 3340 } 3341 else 3342 { 3343 register struct group *gr; 3344 3345 gr = getgrnam(p); 3346 if (gr == NULL) 3347 syserr("readcf: option RunAsUser: unknown group %s", 3348 p); 3349 else if (can_setuid || EffGid == gr->gr_gid) 3350 RunAsGid = gr->gr_gid; 3351 else if (UseMSP) 3352 (void) sm_io_fprintf(smioout, 3353 SM_TIME_DEFAULT, 3354 "WARNING: RunAsUser for MSP ignored, check group ids (egid=%d, want=%d)\n", 3355 (int) EffGid, 3356 (int) gr->gr_gid); 3357 } 3358 } 3359 if (tTd(47, 5)) 3360 sm_dprintf("readcf: RunAsUser = %d:%d\n", 3361 (int) RunAsUid, (int) RunAsGid); 3362 break; 3363 3364 case O_DSN_RRT: 3365 RrtImpliesDsn = atobool(val); 3366 break; 3367 3368 case O_PIDFILE: 3369 PSTRSET(PidFile, val); 3370 break; 3371 3372 case O_DONTBLAMESENDMAIL: 3373 p = val; 3374 for (;;) 3375 { 3376 register struct dbsval *dbs; 3377 extern struct dbsval DontBlameSendmailValues[]; 3378 3379 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 3380 p++; 3381 if (*p == '\0') 3382 break; 3383 val = p; 3384 while (isascii(*p) && isalnum(*p)) 3385 p++; 3386 if (*p != '\0') 3387 *p++ = '\0'; 3388 3389 for (dbs = DontBlameSendmailValues; 3390 dbs->dbs_name != NULL; dbs++) 3391 { 3392 if (sm_strcasecmp(val, dbs->dbs_name) == 0) 3393 break; 3394 } 3395 if (dbs->dbs_name == NULL) 3396 syserr("readcf: DontBlameSendmail option: %s unrecognized", val); 3397 else if (dbs->dbs_flag == DBS_SAFE) 3398 clrbitmap(DontBlameSendmail); 3399 else 3400 setbitn(dbs->dbs_flag, DontBlameSendmail); 3401 } 3402 sticky = false; 3403 break; 3404 3405 case O_DPI: 3406 if (sm_strcasecmp(val, "loopback") == 0) 3407 DontProbeInterfaces = DPI_SKIPLOOPBACK; 3408 else if (atobool(val)) 3409 DontProbeInterfaces = DPI_PROBENONE; 3410 else 3411 DontProbeInterfaces = DPI_PROBEALL; 3412 break; 3413 3414 case O_MAXRCPT: 3415 MaxRcptPerMsg = atoi(val); 3416 break; 3417 3418 case O_RCPTTHROT: 3419 BadRcptThrottle = atoi(val); 3420 break; 3421 3422 #if _FFR_RCPTTHROTDELAY 3423 case O_RCPTTHROTDELAY: 3424 BadRcptThrottleDelay = atoi(val); 3425 break; 3426 #endif /* _FFR_RCPTTHROTDELAY */ 3427 3428 case O_DEADLETTER: 3429 CANONIFY(val); 3430 PSTRSET(DeadLetterDrop, val); 3431 break; 3432 3433 #if _FFR_DONTLOCKFILESFORREAD_OPTION 3434 case O_DONTLOCK: 3435 DontLockReadFiles = atobool(val); 3436 break; 3437 #endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */ 3438 3439 case O_MAXALIASRCSN: 3440 MaxAliasRecursion = atoi(val); 3441 break; 3442 3443 case O_CNCTONLYTO: 3444 /* XXX should probably use gethostbyname */ 3445 #if NETINET || NETINET6 3446 ConnectOnlyTo.sa.sa_family = AF_UNSPEC; 3447 # if NETINET6 3448 if (anynet_pton(AF_INET6, val, 3449 &ConnectOnlyTo.sin6.sin6_addr) != 1) 3450 ConnectOnlyTo.sa.sa_family = AF_INET6; 3451 else 3452 # endif /* NETINET6 */ 3453 # if NETINET 3454 { 3455 ConnectOnlyTo.sin.sin_addr.s_addr = inet_addr(val); 3456 if (ConnectOnlyTo.sin.sin_addr.s_addr != INADDR_NONE) 3457 ConnectOnlyTo.sa.sa_family = AF_INET; 3458 } 3459 3460 # endif /* NETINET */ 3461 if (ConnectOnlyTo.sa.sa_family == AF_UNSPEC) 3462 { 3463 syserr("readcf: option ConnectOnlyTo: invalid IP address %s", 3464 val); 3465 break; 3466 } 3467 #endif /* NETINET || NETINET6 */ 3468 break; 3469 3470 case O_TRUSTUSER: 3471 # if !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING) 3472 if (!UseMSP) 3473 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3474 "readcf: option TrustedUser may cause problems on systems\n which do not support fchown() if UseMSP is not set.\n"); 3475 # endif /* !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING) */ 3476 if (isascii(*val) && isdigit(*val)) 3477 TrustedUid = atoi(val); 3478 else 3479 { 3480 register struct passwd *pw; 3481 3482 TrustedUid = 0; 3483 pw = sm_getpwnam(val); 3484 if (pw == NULL) 3485 { 3486 syserr("readcf: option TrustedUser: unknown user %s", val); 3487 break; 3488 } 3489 else 3490 TrustedUid = pw->pw_uid; 3491 } 3492 3493 # ifdef UID_MAX 3494 if (TrustedUid > UID_MAX) 3495 { 3496 syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)", 3497 (long) TrustedUid, (long) UID_MAX); 3498 TrustedUid = 0; 3499 } 3500 # endif /* UID_MAX */ 3501 break; 3502 3503 case O_MAXMIMEHDRLEN: 3504 p = strchr(val, '/'); 3505 if (p != NULL) 3506 *p++ = '\0'; 3507 MaxMimeHeaderLength = atoi(val); 3508 if (p != NULL && *p != '\0') 3509 MaxMimeFieldLength = atoi(p); 3510 else 3511 MaxMimeFieldLength = MaxMimeHeaderLength / 2; 3512 3513 if (MaxMimeHeaderLength <= 0) 3514 MaxMimeHeaderLength = 0; 3515 else if (MaxMimeHeaderLength < 128) 3516 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3517 "Warning: MaxMimeHeaderLength: header length limit set lower than 128\n"); 3518 3519 if (MaxMimeFieldLength <= 0) 3520 MaxMimeFieldLength = 0; 3521 else if (MaxMimeFieldLength < 40) 3522 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3523 "Warning: MaxMimeHeaderLength: field length limit set lower than 40\n"); 3524 3525 /* 3526 ** Headers field values now include leading space, so let's 3527 ** adjust the values to be "backward compatible". 3528 */ 3529 3530 if (MaxMimeHeaderLength > 0) 3531 MaxMimeHeaderLength++; 3532 if (MaxMimeFieldLength > 0) 3533 MaxMimeFieldLength++; 3534 break; 3535 3536 case O_CONTROLSOCKET: 3537 PSTRSET(ControlSocketName, val); 3538 break; 3539 3540 case O_MAXHDRSLEN: 3541 MaxHeadersLength = atoi(val); 3542 3543 if (MaxHeadersLength > 0 && 3544 MaxHeadersLength < (MAXHDRSLEN / 2)) 3545 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3546 "Warning: MaxHeadersLength: headers length limit set lower than %d\n", 3547 (MAXHDRSLEN / 2)); 3548 break; 3549 3550 case O_PROCTITLEPREFIX: 3551 PSTRSET(ProcTitlePrefix, val); 3552 break; 3553 3554 #if SASL 3555 case O_SASLINFO: 3556 # if _FFR_ALLOW_SASLINFO 3557 /* 3558 ** Allow users to select their own authinfo file 3559 ** under certain circumstances, otherwise just ignore 3560 ** the option. If the option isn't ignored, several 3561 ** commands don't work very well, e.g., mailq. 3562 ** However, this is not a "perfect" solution. 3563 ** If mail is queued, the authentication info 3564 ** will not be used in subsequent delivery attempts. 3565 ** If we really want to support this, then it has 3566 ** to be stored in the queue file. 3567 */ 3568 if (!bitset(SUBMIT_MSA, SubmitMode) && RealUid != 0 && 3569 RunAsUid != RealUid) 3570 break; 3571 # endif /* _FFR_ALLOW_SASLINFO */ 3572 PSTRSET(SASLInfo, val); 3573 break; 3574 3575 case O_SASLMECH: 3576 if (AuthMechanisms != NULL) 3577 sm_free(AuthMechanisms); /* XXX */ 3578 if (*val != '\0') 3579 AuthMechanisms = newstr(val); 3580 else 3581 AuthMechanisms = NULL; 3582 break; 3583 3584 case O_SASLREALM: 3585 if (AuthRealm != NULL) 3586 sm_free(AuthRealm); 3587 if (*val != '\0') 3588 AuthRealm = newstr(val); 3589 else 3590 AuthRealm = NULL; 3591 break; 3592 3593 case O_SASLOPTS: 3594 while (val != NULL && *val != '\0') 3595 { 3596 switch (*val) 3597 { 3598 case 'A': 3599 SASLOpts |= SASL_AUTH_AUTH; 3600 break; 3601 3602 case 'a': 3603 SASLOpts |= SASL_SEC_NOACTIVE; 3604 break; 3605 3606 case 'c': 3607 SASLOpts |= SASL_SEC_PASS_CREDENTIALS; 3608 break; 3609 3610 case 'd': 3611 SASLOpts |= SASL_SEC_NODICTIONARY; 3612 break; 3613 3614 case 'f': 3615 SASLOpts |= SASL_SEC_FORWARD_SECRECY; 3616 break; 3617 3618 # if SASL >= 20101 3619 case 'm': 3620 SASLOpts |= SASL_SEC_MUTUAL_AUTH; 3621 break; 3622 # endif /* SASL >= 20101 */ 3623 3624 case 'p': 3625 SASLOpts |= SASL_SEC_NOPLAINTEXT; 3626 break; 3627 3628 case 'y': 3629 SASLOpts |= SASL_SEC_NOANONYMOUS; 3630 break; 3631 3632 case ' ': /* ignore */ 3633 case '\t': /* ignore */ 3634 case ',': /* ignore */ 3635 break; 3636 3637 default: 3638 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3639 "Warning: Option: %s unknown parameter '%c'\n", 3640 OPTNAME, 3641 (isascii(*val) && 3642 isprint(*val)) 3643 ? *val : '?'); 3644 break; 3645 } 3646 ++val; 3647 val = strpbrk(val, ", \t"); 3648 if (val != NULL) 3649 ++val; 3650 } 3651 break; 3652 3653 case O_SASLBITS: 3654 MaxSLBits = atoi(val); 3655 break; 3656 3657 #else /* SASL */ 3658 case O_SASLINFO: 3659 case O_SASLMECH: 3660 case O_SASLREALM: 3661 case O_SASLOPTS: 3662 case O_SASLBITS: 3663 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3664 "Warning: Option: %s requires SASL support (-DSASL)\n", 3665 OPTNAME); 3666 break; 3667 #endif /* SASL */ 3668 3669 #if STARTTLS 3670 case O_SRVCERTFILE: 3671 SET_STRING_EXP(SrvCertFile); 3672 case O_SRVKEYFILE: 3673 SET_STRING_EXP(SrvKeyFile); 3674 case O_CLTCERTFILE: 3675 SET_STRING_EXP(CltCertFile); 3676 case O_CLTKEYFILE: 3677 SET_STRING_EXP(CltKeyFile); 3678 case O_CACERTFILE: 3679 SET_STRING_EXP(CACertFile); 3680 case O_CACERTPATH: 3681 SET_STRING_EXP(CACertPath); 3682 case O_DHPARAMS: 3683 SET_STRING_EXP(DHParams); 3684 # if _FFR_TLS_1 3685 case O_DHPARAMS5: 3686 SET_STRING_EXP(DHParams5); 3687 case O_CIPHERLIST: 3688 SET_STRING_EXP(CipherList); 3689 case O_SRV_SSL_OPTIONS: 3690 pssloptions = &Srv_SSL_Options; 3691 case O_CLT_SSL_OPTIONS: 3692 if (pssloptions == NULL) 3693 pssloptions = &Clt_SSL_Options; 3694 for (p = val; *p != 0; ) 3695 { 3696 bool clearmode; 3697 char *q; 3698 struct ssl_options *sslopts; 3699 3700 while (*p == ' ') 3701 p++; 3702 if (*p == '\0') 3703 break; 3704 clearmode = false; 3705 if (*p == '-' || *p == '+') 3706 clearmode = *p++ == '-'; 3707 q = p; 3708 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 3709 p++; 3710 if (*p != '\0') 3711 *p++ = '\0'; 3712 for (sslopts = SSL_Option; 3713 sslopts->sslopt_name != NULL; sslopts++) 3714 { 3715 if (sm_strcasecmp(q, sslopts->sslopt_name) == 0) 3716 break; 3717 } 3718 if (sslopts->sslopt_name == NULL) 3719 { 3720 errno = 0; 3721 syserr("readcf: %s option value %s unrecognized", 3722 o->o_name, q); 3723 } 3724 else if (clearmode) 3725 *pssloptions &= ~sslopts->sslopt_bits; 3726 else 3727 *pssloptions |= sslopts->sslopt_bits; 3728 } 3729 pssloptions = NULL; 3730 break; 3731 3732 # endif /* _FFR_TLS_1 */ 3733 3734 case O_CRLFILE: 3735 # if OPENSSL_VERSION_NUMBER > 0x00907000L 3736 SET_STRING_EXP(CRLFile); 3737 # else /* OPENSSL_VERSION_NUMBER > 0x00907000L */ 3738 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3739 "Warning: Option: %s requires at least OpenSSL 0.9.7\n", 3740 OPTNAME); 3741 break; 3742 # endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ 3743 3744 # if _FFR_CRLPATH 3745 case O_CRLPATH: 3746 # if OPENSSL_VERSION_NUMBER > 0x00907000L 3747 SET_STRING_EXP(CRLPath); 3748 # else /* OPENSSL_VERSION_NUMBER > 0x00907000L */ 3749 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3750 "Warning: Option: %s requires at least OpenSSL 0.9.7\n", 3751 OPTNAME); 3752 break; 3753 # endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ 3754 # endif /* _FFR_CRLPATH */ 3755 3756 /* 3757 ** XXX How about options per daemon/client instead of globally? 3758 ** This doesn't work well for some options, e.g., no server cert, 3759 ** but fine for others. 3760 ** 3761 ** XXX Some people may want different certs per server. 3762 ** 3763 ** See also srvfeatures() 3764 */ 3765 3766 case O_TLS_SRV_OPTS: 3767 while (val != NULL && *val != '\0') 3768 { 3769 switch (*val) 3770 { 3771 case 'V': 3772 TLS_Srv_Opts |= TLS_I_NO_VRFY; 3773 break; 3774 # if _FFR_TLS_1 3775 /* 3776 ** Server without a cert? That works only if 3777 ** AnonDH is enabled as cipher, which is not in the 3778 ** default list. Hence the CipherList option must 3779 ** be available. Moreover: which clients support this 3780 ** besides sendmail with this setting? 3781 */ 3782 3783 case 'C': 3784 TLS_Srv_Opts &= ~TLS_I_SRV_CERT; 3785 break; 3786 # endif /* _FFR_TLS_1 */ 3787 case ' ': /* ignore */ 3788 case '\t': /* ignore */ 3789 case ',': /* ignore */ 3790 break; 3791 default: 3792 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3793 "Warning: Option: %s unknown parameter '%c'\n", 3794 OPTNAME, 3795 (isascii(*val) && 3796 isprint(*val)) 3797 ? *val : '?'); 3798 break; 3799 } 3800 ++val; 3801 val = strpbrk(val, ", \t"); 3802 if (val != NULL) 3803 ++val; 3804 } 3805 break; 3806 3807 case O_RANDFILE: 3808 PSTRSET(RandFile, val); 3809 break; 3810 3811 #else /* STARTTLS */ 3812 case O_SRVCERTFILE: 3813 case O_SRVKEYFILE: 3814 case O_CLTCERTFILE: 3815 case O_CLTKEYFILE: 3816 case O_CACERTFILE: 3817 case O_CACERTPATH: 3818 case O_DHPARAMS: 3819 # if _FFR_TLS_1 3820 case O_DHPARAMS5: 3821 case O_CIPHERLIST: 3822 # endif /* _FFR_TLS_1 */ 3823 case O_CRLFILE: 3824 # if _FFR_CRLPATH 3825 case O_CRLPATH: 3826 # endif /* _FFR_CRLPATH */ 3827 case O_RANDFILE: 3828 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3829 "Warning: Option: %s requires TLS support\n", 3830 OPTNAME); 3831 break; 3832 3833 #endif /* STARTTLS */ 3834 3835 case O_CLIENTPORT: 3836 setclientoptions(val); 3837 break; 3838 3839 case O_DF_BUFSIZE: 3840 DataFileBufferSize = atoi(val); 3841 break; 3842 3843 case O_XF_BUFSIZE: 3844 XscriptFileBufferSize = atoi(val); 3845 break; 3846 3847 case O_LDAPDEFAULTSPEC: 3848 #if LDAPMAP 3849 ldapmap_set_defaults(val); 3850 #else /* LDAPMAP */ 3851 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3852 "Warning: Option: %s requires LDAP support (-DLDAPMAP)\n", 3853 OPTNAME); 3854 #endif /* LDAPMAP */ 3855 break; 3856 3857 case O_INPUTMILTER: 3858 #if MILTER 3859 InputFilterList = newstr(val); 3860 #else /* MILTER */ 3861 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3862 "Warning: Option: %s requires Milter support (-DMILTER)\n", 3863 OPTNAME); 3864 #endif /* MILTER */ 3865 break; 3866 3867 case O_MILTER: 3868 #if MILTER 3869 milter_set_option(subopt, val, sticky); 3870 #else /* MILTER */ 3871 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3872 "Warning: Option: %s requires Milter support (-DMILTER)\n", 3873 OPTNAME); 3874 #endif /* MILTER */ 3875 break; 3876 3877 case O_QUEUE_FILE_MODE: /* queue file mode */ 3878 QueueFileMode = atooct(val) & 0777; 3879 break; 3880 3881 case O_DLVR_MIN: /* deliver by minimum time */ 3882 DeliverByMin = convtime(val, 's'); 3883 break; 3884 3885 /* modifiers {daemon_flags} for direct submissions */ 3886 case O_DIRECTSUBMODIFIERS: 3887 { 3888 BITMAP256 m; /* ignored */ 3889 extern ENVELOPE BlankEnvelope; 3890 3891 macdefine(&BlankEnvelope.e_macro, A_PERM, 3892 macid("{daemon_flags}"), 3893 getmodifiers(val, m)); 3894 } 3895 break; 3896 3897 case O_FASTSPLIT: 3898 FastSplit = atoi(val); 3899 break; 3900 3901 case O_MBDB: 3902 Mbdb = newstr(val); 3903 break; 3904 3905 case O_MSQ: 3906 UseMSP = atobool(val); 3907 break; 3908 3909 case O_SOFTBOUNCE: 3910 SoftBounce = atobool(val); 3911 break; 3912 3913 case O_REJECTLOGINTERVAL: /* time btwn log msgs while refusing */ 3914 RejectLogInterval = convtime(val, 'h'); 3915 break; 3916 3917 case O_REQUIRES_DIR_FSYNC: 3918 #if REQUIRES_DIR_FSYNC 3919 RequiresDirfsync = atobool(val); 3920 #else /* REQUIRES_DIR_FSYNC */ 3921 /* silently ignored... required for cf file option */ 3922 #endif /* REQUIRES_DIR_FSYNC */ 3923 break; 3924 3925 case O_CONNECTION_RATE_WINDOW_SIZE: 3926 ConnectionRateWindowSize = convtime(val, 's'); 3927 break; 3928 3929 case O_FALLBACKSMARTHOST: /* fallback smart host */ 3930 if (val[0] != '\0') 3931 FallbackSmartHost = newstr(val); 3932 break; 3933 3934 case O_HELONAME: 3935 HeloName = newstr(val); 3936 break; 3937 3938 #if _FFR_MEMSTAT 3939 case O_REFUSELOWMEM: 3940 RefuseLowMem = atoi(val); 3941 break; 3942 case O_QUEUELOWMEM: 3943 QueueLowMem = atoi(val); 3944 break; 3945 case O_MEMRESOURCE: 3946 MemoryResource = newstr(val); 3947 break; 3948 #endif /* _FFR_MEMSTAT */ 3949 3950 case O_MAXNOOPCOMMANDS: 3951 MaxNOOPCommands = atoi(val); 3952 break; 3953 3954 #if _FFR_MSG_ACCEPT 3955 case O_MSG_ACCEPT: 3956 MessageAccept = newstr(val); 3957 break; 3958 #endif /* _FFR_MSG_ACCEPT */ 3959 3960 #if _FFR_QUEUE_RUN_PARANOIA 3961 case O_CHK_Q_RUNNERS: 3962 CheckQueueRunners = atoi(val); 3963 break; 3964 #endif /* _FFR_QUEUE_RUN_PARANOIA */ 3965 3966 #if _FFR_EIGHT_BIT_ADDR_OK 3967 case O_EIGHT_BIT_ADDR_OK: 3968 EightBitAddrOK = atobool(val); 3969 break; 3970 #endif /* _FFR_EIGHT_BIT_ADDR_OK */ 3971 3972 #if _FFR_ADDR_TYPE_MODES 3973 case O_ADDR_TYPE_MODES: 3974 AddrTypeModes = atobool(val); 3975 break; 3976 #endif /* _FFR_ADDR_TYPE_MODES */ 3977 3978 #if _FFR_BADRCPT_SHUTDOWN 3979 case O_RCPTSHUTD: 3980 BadRcptShutdown = atoi(val); 3981 break; 3982 3983 case O_RCPTSHUTDG: 3984 BadRcptShutdownGood = atoi(val); 3985 break; 3986 #endif /* _FFR_BADRCPT_SHUTDOWN */ 3987 3988 default: 3989 if (tTd(37, 1)) 3990 { 3991 if (isascii(opt) && isprint(opt)) 3992 sm_dprintf("Warning: option %c unknown\n", opt); 3993 else 3994 sm_dprintf("Warning: option 0x%x unknown\n", opt); 3995 } 3996 break; 3997 } 3998 3999 /* 4000 ** Options with suboptions are responsible for taking care 4001 ** of sticky-ness (e.g., that a command line setting is kept 4002 ** when reading in the sendmail.cf file). This has to be done 4003 ** when the suboptions are parsed since each suboption must be 4004 ** sticky, not the root option. 4005 */ 4006 4007 if (sticky && !bitset(OI_SUBOPT, o->o_flags)) 4008 setbitn(opt, StickyOpt); 4009 } 4010 /* 4011 ** SETCLASS -- set a string into a class 4012 ** 4013 ** Parameters: 4014 ** class -- the class to put the string in. 4015 ** str -- the string to enter 4016 ** 4017 ** Returns: 4018 ** none. 4019 ** 4020 ** Side Effects: 4021 ** puts the word into the symbol table. 4022 */ 4023 4024 void 4025 setclass(class, str) 4026 int class; 4027 char *str; 4028 { 4029 register STAB *s; 4030 4031 if ((str[0] & 0377) == MATCHCLASS) 4032 { 4033 int mid; 4034 4035 str++; 4036 mid = macid(str); 4037 if (mid == 0) 4038 return; 4039 4040 if (tTd(37, 8)) 4041 sm_dprintf("setclass(%s, $=%s)\n", 4042 macname(class), macname(mid)); 4043 copy_class(mid, class); 4044 } 4045 else 4046 { 4047 if (tTd(37, 8)) 4048 sm_dprintf("setclass(%s, %s)\n", macname(class), str); 4049 4050 s = stab(str, ST_CLASS, ST_ENTER); 4051 setbitn(bitidx(class), s->s_class); 4052 } 4053 } 4054 /* 4055 ** MAKEMAPENTRY -- create a map entry 4056 ** 4057 ** Parameters: 4058 ** line -- the config file line 4059 ** 4060 ** Returns: 4061 ** A pointer to the map that has been created. 4062 ** NULL if there was a syntax error. 4063 ** 4064 ** Side Effects: 4065 ** Enters the map into the dictionary. 4066 */ 4067 4068 MAP * 4069 makemapentry(line) 4070 char *line; 4071 { 4072 register char *p; 4073 char *mapname; 4074 char *classname; 4075 register STAB *s; 4076 STAB *class; 4077 4078 for (p = line; isascii(*p) && isspace(*p); p++) 4079 continue; 4080 if (!(isascii(*p) && isalnum(*p))) 4081 { 4082 syserr("readcf: config K line: no map name"); 4083 return NULL; 4084 } 4085 4086 mapname = p; 4087 while ((isascii(*++p) && isalnum(*p)) || *p == '_' || *p == '.') 4088 continue; 4089 if (*p != '\0') 4090 *p++ = '\0'; 4091 while (isascii(*p) && isspace(*p)) 4092 p++; 4093 if (!(isascii(*p) && isalnum(*p))) 4094 { 4095 syserr("readcf: config K line, map %s: no map class", mapname); 4096 return NULL; 4097 } 4098 classname = p; 4099 while (isascii(*++p) && isalnum(*p)) 4100 continue; 4101 if (*p != '\0') 4102 *p++ = '\0'; 4103 while (isascii(*p) && isspace(*p)) 4104 p++; 4105 4106 /* look up the class */ 4107 class = stab(classname, ST_MAPCLASS, ST_FIND); 4108 if (class == NULL) 4109 { 4110 syserr("readcf: map %s: class %s not available", mapname, 4111 classname); 4112 return NULL; 4113 } 4114 4115 /* enter the map */ 4116 s = stab(mapname, ST_MAP, ST_ENTER); 4117 s->s_map.map_class = &class->s_mapclass; 4118 s->s_map.map_mname = newstr(mapname); 4119 4120 if (class->s_mapclass.map_parse(&s->s_map, p)) 4121 s->s_map.map_mflags |= MF_VALID; 4122 4123 if (tTd(37, 5)) 4124 { 4125 sm_dprintf("map %s, class %s, flags %lx, file %s,\n", 4126 s->s_map.map_mname, s->s_map.map_class->map_cname, 4127 s->s_map.map_mflags, s->s_map.map_file); 4128 sm_dprintf("\tapp %s, domain %s, rebuild %s\n", 4129 s->s_map.map_app, s->s_map.map_domain, 4130 s->s_map.map_rebuild); 4131 } 4132 return &s->s_map; 4133 } 4134 /* 4135 ** STRTORWSET -- convert string to rewriting set number 4136 ** 4137 ** Parameters: 4138 ** p -- the pointer to the string to decode. 4139 ** endp -- if set, store the trailing delimiter here. 4140 ** stabmode -- ST_ENTER to create this entry, ST_FIND if 4141 ** it must already exist. 4142 ** 4143 ** Returns: 4144 ** The appropriate ruleset number. 4145 ** -1 if it is not valid (error already printed) 4146 */ 4147 4148 int 4149 strtorwset(p, endp, stabmode) 4150 char *p; 4151 char **endp; 4152 int stabmode; 4153 { 4154 int ruleset; 4155 static int nextruleset = MAXRWSETS; 4156 4157 while (isascii(*p) && isspace(*p)) 4158 p++; 4159 if (!isascii(*p)) 4160 { 4161 syserr("invalid ruleset name: \"%.20s\"", p); 4162 return -1; 4163 } 4164 if (isdigit(*p)) 4165 { 4166 ruleset = strtol(p, endp, 10); 4167 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 4168 { 4169 syserr("bad ruleset %d (%d max)", 4170 ruleset, MAXRWSETS / 2); 4171 ruleset = -1; 4172 } 4173 } 4174 else 4175 { 4176 STAB *s; 4177 char delim; 4178 char *q = NULL; 4179 4180 q = p; 4181 while (*p != '\0' && isascii(*p) && (isalnum(*p) || *p == '_')) 4182 p++; 4183 if (q == p || !(isascii(*q) && isalpha(*q))) 4184 { 4185 /* no valid characters */ 4186 syserr("invalid ruleset name: \"%.20s\"", q); 4187 return -1; 4188 } 4189 while (isascii(*p) && isspace(*p)) 4190 *p++ = '\0'; 4191 delim = *p; 4192 if (delim != '\0') 4193 *p = '\0'; 4194 s = stab(q, ST_RULESET, stabmode); 4195 if (delim != '\0') 4196 *p = delim; 4197 4198 if (s == NULL) 4199 return -1; 4200 4201 if (stabmode == ST_ENTER && delim == '=') 4202 { 4203 while (isascii(*++p) && isspace(*p)) 4204 continue; 4205 if (!(isascii(*p) && isdigit(*p))) 4206 { 4207 syserr("bad ruleset definition \"%s\" (number required after `=')", q); 4208 ruleset = -1; 4209 } 4210 else 4211 { 4212 ruleset = strtol(p, endp, 10); 4213 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 4214 { 4215 syserr("bad ruleset number %d in \"%s\" (%d max)", 4216 ruleset, q, MAXRWSETS / 2); 4217 ruleset = -1; 4218 } 4219 } 4220 } 4221 else 4222 { 4223 if (endp != NULL) 4224 *endp = p; 4225 if (s->s_ruleset >= 0) 4226 ruleset = s->s_ruleset; 4227 else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 4228 { 4229 syserr("%s: too many named rulesets (%d max)", 4230 q, MAXRWSETS / 2); 4231 ruleset = -1; 4232 } 4233 } 4234 if (s->s_ruleset >= 0 && 4235 ruleset >= 0 && 4236 ruleset != s->s_ruleset) 4237 { 4238 syserr("%s: ruleset changed value (old %d, new %d)", 4239 q, s->s_ruleset, ruleset); 4240 ruleset = s->s_ruleset; 4241 } 4242 else if (ruleset >= 0) 4243 { 4244 s->s_ruleset = ruleset; 4245 } 4246 if (stabmode == ST_ENTER && ruleset >= 0) 4247 { 4248 char *h = NULL; 4249 4250 if (RuleSetNames[ruleset] != NULL) 4251 sm_free(RuleSetNames[ruleset]); /* XXX */ 4252 if (delim != '\0' && (h = strchr(q, delim)) != NULL) 4253 *h = '\0'; 4254 RuleSetNames[ruleset] = newstr(q); 4255 if (delim == '/' && h != NULL) 4256 *h = delim; /* put back delim */ 4257 } 4258 } 4259 return ruleset; 4260 } 4261 /* 4262 ** SETTIMEOUT -- set an individual timeout 4263 ** 4264 ** Parameters: 4265 ** name -- the name of the timeout. 4266 ** val -- the value of the timeout. 4267 ** sticky -- if set, don't let other setoptions override 4268 ** this value. 4269 ** 4270 ** Returns: 4271 ** none. 4272 */ 4273 4274 /* set if Timeout sub-option is stuck */ 4275 static BITMAP256 StickyTimeoutOpt; 4276 4277 static struct timeoutinfo 4278 { 4279 char *to_name; /* long name of timeout */ 4280 unsigned char to_code; /* code for option */ 4281 } TimeOutTab[] = 4282 { 4283 #define TO_INITIAL 0x01 4284 { "initial", TO_INITIAL }, 4285 #define TO_MAIL 0x02 4286 { "mail", TO_MAIL }, 4287 #define TO_RCPT 0x03 4288 { "rcpt", TO_RCPT }, 4289 #define TO_DATAINIT 0x04 4290 { "datainit", TO_DATAINIT }, 4291 #define TO_DATABLOCK 0x05 4292 { "datablock", TO_DATABLOCK }, 4293 #define TO_DATAFINAL 0x06 4294 { "datafinal", TO_DATAFINAL }, 4295 #define TO_COMMAND 0x07 4296 { "command", TO_COMMAND }, 4297 #define TO_RSET 0x08 4298 { "rset", TO_RSET }, 4299 #define TO_HELO 0x09 4300 { "helo", TO_HELO }, 4301 #define TO_QUIT 0x0A 4302 { "quit", TO_QUIT }, 4303 #define TO_MISC 0x0B 4304 { "misc", TO_MISC }, 4305 #define TO_IDENT 0x0C 4306 { "ident", TO_IDENT }, 4307 #define TO_FILEOPEN 0x0D 4308 { "fileopen", TO_FILEOPEN }, 4309 #define TO_CONNECT 0x0E 4310 { "connect", TO_CONNECT }, 4311 #define TO_ICONNECT 0x0F 4312 { "iconnect", TO_ICONNECT }, 4313 #define TO_QUEUEWARN 0x10 4314 { "queuewarn", TO_QUEUEWARN }, 4315 { "queuewarn.*", TO_QUEUEWARN }, 4316 #define TO_QUEUEWARN_NORMAL 0x11 4317 { "queuewarn.normal", TO_QUEUEWARN_NORMAL }, 4318 #define TO_QUEUEWARN_URGENT 0x12 4319 { "queuewarn.urgent", TO_QUEUEWARN_URGENT }, 4320 #define TO_QUEUEWARN_NON_URGENT 0x13 4321 { "queuewarn.non-urgent", TO_QUEUEWARN_NON_URGENT }, 4322 #define TO_QUEUERETURN 0x14 4323 { "queuereturn", TO_QUEUERETURN }, 4324 { "queuereturn.*", TO_QUEUERETURN }, 4325 #define TO_QUEUERETURN_NORMAL 0x15 4326 { "queuereturn.normal", TO_QUEUERETURN_NORMAL }, 4327 #define TO_QUEUERETURN_URGENT 0x16 4328 { "queuereturn.urgent", TO_QUEUERETURN_URGENT }, 4329 #define TO_QUEUERETURN_NON_URGENT 0x17 4330 { "queuereturn.non-urgent", TO_QUEUERETURN_NON_URGENT }, 4331 #define TO_HOSTSTATUS 0x18 4332 { "hoststatus", TO_HOSTSTATUS }, 4333 #define TO_RESOLVER_RETRANS 0x19 4334 { "resolver.retrans", TO_RESOLVER_RETRANS }, 4335 #define TO_RESOLVER_RETRANS_NORMAL 0x1A 4336 { "resolver.retrans.normal", TO_RESOLVER_RETRANS_NORMAL }, 4337 #define TO_RESOLVER_RETRANS_FIRST 0x1B 4338 { "resolver.retrans.first", TO_RESOLVER_RETRANS_FIRST }, 4339 #define TO_RESOLVER_RETRY 0x1C 4340 { "resolver.retry", TO_RESOLVER_RETRY }, 4341 #define TO_RESOLVER_RETRY_NORMAL 0x1D 4342 { "resolver.retry.normal", TO_RESOLVER_RETRY_NORMAL }, 4343 #define TO_RESOLVER_RETRY_FIRST 0x1E 4344 { "resolver.retry.first", TO_RESOLVER_RETRY_FIRST }, 4345 #define TO_CONTROL 0x1F 4346 { "control", TO_CONTROL }, 4347 #define TO_LHLO 0x20 4348 { "lhlo", TO_LHLO }, 4349 #define TO_AUTH 0x21 4350 { "auth", TO_AUTH }, 4351 #define TO_STARTTLS 0x22 4352 { "starttls", TO_STARTTLS }, 4353 #define TO_ACONNECT 0x23 4354 { "aconnect", TO_ACONNECT }, 4355 #define TO_QUEUEWARN_DSN 0x24 4356 { "queuewarn.dsn", TO_QUEUEWARN_DSN }, 4357 #define TO_QUEUERETURN_DSN 0x25 4358 { "queuereturn.dsn", TO_QUEUERETURN_DSN }, 4359 { NULL, 0 }, 4360 }; 4361 4362 4363 static void 4364 settimeout(name, val, sticky) 4365 char *name; 4366 char *val; 4367 bool sticky; 4368 { 4369 register struct timeoutinfo *to; 4370 int i, addopts; 4371 time_t toval; 4372 4373 if (tTd(37, 2)) 4374 sm_dprintf("settimeout(%s = %s)", name, val); 4375 4376 for (to = TimeOutTab; to->to_name != NULL; to++) 4377 { 4378 if (sm_strcasecmp(to->to_name, name) == 0) 4379 break; 4380 } 4381 4382 if (to->to_name == NULL) 4383 { 4384 errno = 0; /* avoid bogus error text */ 4385 syserr("settimeout: invalid timeout %s", name); 4386 return; 4387 } 4388 4389 /* 4390 ** See if this option is preset for us. 4391 */ 4392 4393 if (!sticky && bitnset(to->to_code, StickyTimeoutOpt)) 4394 { 4395 if (tTd(37, 2)) 4396 sm_dprintf(" (ignored)\n"); 4397 return; 4398 } 4399 4400 if (tTd(37, 2)) 4401 sm_dprintf("\n"); 4402 4403 toval = convtime(val, 'm'); 4404 addopts = 0; 4405 4406 switch (to->to_code) 4407 { 4408 case TO_INITIAL: 4409 TimeOuts.to_initial = toval; 4410 break; 4411 4412 case TO_MAIL: 4413 TimeOuts.to_mail = toval; 4414 break; 4415 4416 case TO_RCPT: 4417 TimeOuts.to_rcpt = toval; 4418 break; 4419 4420 case TO_DATAINIT: 4421 TimeOuts.to_datainit = toval; 4422 break; 4423 4424 case TO_DATABLOCK: 4425 TimeOuts.to_datablock = toval; 4426 break; 4427 4428 case TO_DATAFINAL: 4429 TimeOuts.to_datafinal = toval; 4430 break; 4431 4432 case TO_COMMAND: 4433 TimeOuts.to_nextcommand = toval; 4434 break; 4435 4436 case TO_RSET: 4437 TimeOuts.to_rset = toval; 4438 break; 4439 4440 case TO_HELO: 4441 TimeOuts.to_helo = toval; 4442 break; 4443 4444 case TO_QUIT: 4445 TimeOuts.to_quit = toval; 4446 break; 4447 4448 case TO_MISC: 4449 TimeOuts.to_miscshort = toval; 4450 break; 4451 4452 case TO_IDENT: 4453 TimeOuts.to_ident = toval; 4454 break; 4455 4456 case TO_FILEOPEN: 4457 TimeOuts.to_fileopen = toval; 4458 break; 4459 4460 case TO_CONNECT: 4461 TimeOuts.to_connect = toval; 4462 break; 4463 4464 case TO_ICONNECT: 4465 TimeOuts.to_iconnect = toval; 4466 break; 4467 4468 case TO_ACONNECT: 4469 TimeOuts.to_aconnect = toval; 4470 break; 4471 4472 case TO_QUEUEWARN: 4473 toval = convtime(val, 'h'); 4474 TimeOuts.to_q_warning[TOC_NORMAL] = toval; 4475 TimeOuts.to_q_warning[TOC_URGENT] = toval; 4476 TimeOuts.to_q_warning[TOC_NONURGENT] = toval; 4477 TimeOuts.to_q_warning[TOC_DSN] = toval; 4478 addopts = 2; 4479 break; 4480 4481 case TO_QUEUEWARN_NORMAL: 4482 toval = convtime(val, 'h'); 4483 TimeOuts.to_q_warning[TOC_NORMAL] = toval; 4484 break; 4485 4486 case TO_QUEUEWARN_URGENT: 4487 toval = convtime(val, 'h'); 4488 TimeOuts.to_q_warning[TOC_URGENT] = toval; 4489 break; 4490 4491 case TO_QUEUEWARN_NON_URGENT: 4492 toval = convtime(val, 'h'); 4493 TimeOuts.to_q_warning[TOC_NONURGENT] = toval; 4494 break; 4495 4496 case TO_QUEUEWARN_DSN: 4497 toval = convtime(val, 'h'); 4498 TimeOuts.to_q_warning[TOC_DSN] = toval; 4499 break; 4500 4501 case TO_QUEUERETURN: 4502 toval = convtime(val, 'd'); 4503 TimeOuts.to_q_return[TOC_NORMAL] = toval; 4504 TimeOuts.to_q_return[TOC_URGENT] = toval; 4505 TimeOuts.to_q_return[TOC_NONURGENT] = toval; 4506 TimeOuts.to_q_return[TOC_DSN] = toval; 4507 addopts = 2; 4508 break; 4509 4510 case TO_QUEUERETURN_NORMAL: 4511 toval = convtime(val, 'd'); 4512 TimeOuts.to_q_return[TOC_NORMAL] = toval; 4513 break; 4514 4515 case TO_QUEUERETURN_URGENT: 4516 toval = convtime(val, 'd'); 4517 TimeOuts.to_q_return[TOC_URGENT] = toval; 4518 break; 4519 4520 case TO_QUEUERETURN_NON_URGENT: 4521 toval = convtime(val, 'd'); 4522 TimeOuts.to_q_return[TOC_NONURGENT] = toval; 4523 break; 4524 4525 case TO_QUEUERETURN_DSN: 4526 toval = convtime(val, 'd'); 4527 TimeOuts.to_q_return[TOC_DSN] = toval; 4528 break; 4529 4530 case TO_HOSTSTATUS: 4531 MciInfoTimeout = toval; 4532 break; 4533 4534 case TO_RESOLVER_RETRANS: 4535 toval = convtime(val, 's'); 4536 TimeOuts.res_retrans[RES_TO_DEFAULT] = toval; 4537 TimeOuts.res_retrans[RES_TO_FIRST] = toval; 4538 TimeOuts.res_retrans[RES_TO_NORMAL] = toval; 4539 addopts = 2; 4540 break; 4541 4542 case TO_RESOLVER_RETRY: 4543 i = atoi(val); 4544 TimeOuts.res_retry[RES_TO_DEFAULT] = i; 4545 TimeOuts.res_retry[RES_TO_FIRST] = i; 4546 TimeOuts.res_retry[RES_TO_NORMAL] = i; 4547 addopts = 2; 4548 break; 4549 4550 case TO_RESOLVER_RETRANS_NORMAL: 4551 TimeOuts.res_retrans[RES_TO_NORMAL] = convtime(val, 's'); 4552 break; 4553 4554 case TO_RESOLVER_RETRY_NORMAL: 4555 TimeOuts.res_retry[RES_TO_NORMAL] = atoi(val); 4556 break; 4557 4558 case TO_RESOLVER_RETRANS_FIRST: 4559 TimeOuts.res_retrans[RES_TO_FIRST] = convtime(val, 's'); 4560 break; 4561 4562 case TO_RESOLVER_RETRY_FIRST: 4563 TimeOuts.res_retry[RES_TO_FIRST] = atoi(val); 4564 break; 4565 4566 case TO_CONTROL: 4567 TimeOuts.to_control = toval; 4568 break; 4569 4570 case TO_LHLO: 4571 TimeOuts.to_lhlo = toval; 4572 break; 4573 4574 #if SASL 4575 case TO_AUTH: 4576 TimeOuts.to_auth = toval; 4577 break; 4578 #endif /* SASL */ 4579 4580 #if STARTTLS 4581 case TO_STARTTLS: 4582 TimeOuts.to_starttls = toval; 4583 break; 4584 #endif /* STARTTLS */ 4585 4586 default: 4587 syserr("settimeout: invalid timeout %s", name); 4588 break; 4589 } 4590 4591 if (sticky) 4592 { 4593 for (i = 0; i <= addopts; i++) 4594 setbitn(to->to_code + i, StickyTimeoutOpt); 4595 } 4596 } 4597 /* 4598 ** INITTIMEOUTS -- parse and set timeout values 4599 ** 4600 ** Parameters: 4601 ** val -- a pointer to the values. If NULL, do initial 4602 ** settings. 4603 ** sticky -- if set, don't let other setoptions override 4604 ** this suboption value. 4605 ** 4606 ** Returns: 4607 ** none. 4608 ** 4609 ** Side Effects: 4610 ** Initializes the TimeOuts structure 4611 */ 4612 4613 void 4614 inittimeouts(val, sticky) 4615 register char *val; 4616 bool sticky; 4617 { 4618 register char *p; 4619 4620 if (tTd(37, 2)) 4621 sm_dprintf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val); 4622 if (val == NULL) 4623 { 4624 TimeOuts.to_connect = (time_t) 0 SECONDS; 4625 TimeOuts.to_aconnect = (time_t) 0 SECONDS; 4626 TimeOuts.to_iconnect = (time_t) 0 SECONDS; 4627 TimeOuts.to_initial = (time_t) 5 MINUTES; 4628 TimeOuts.to_helo = (time_t) 5 MINUTES; 4629 TimeOuts.to_mail = (time_t) 10 MINUTES; 4630 TimeOuts.to_rcpt = (time_t) 1 HOUR; 4631 TimeOuts.to_datainit = (time_t) 5 MINUTES; 4632 TimeOuts.to_datablock = (time_t) 1 HOUR; 4633 TimeOuts.to_datafinal = (time_t) 1 HOUR; 4634 TimeOuts.to_rset = (time_t) 5 MINUTES; 4635 TimeOuts.to_quit = (time_t) 2 MINUTES; 4636 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 4637 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 4638 #if IDENTPROTO 4639 TimeOuts.to_ident = (time_t) 5 SECONDS; 4640 #else /* IDENTPROTO */ 4641 TimeOuts.to_ident = (time_t) 0 SECONDS; 4642 #endif /* IDENTPROTO */ 4643 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 4644 TimeOuts.to_control = (time_t) 2 MINUTES; 4645 TimeOuts.to_lhlo = (time_t) 2 MINUTES; 4646 #if SASL 4647 TimeOuts.to_auth = (time_t) 10 MINUTES; 4648 #endif /* SASL */ 4649 #if STARTTLS 4650 TimeOuts.to_starttls = (time_t) 1 HOUR; 4651 #endif /* STARTTLS */ 4652 if (tTd(37, 5)) 4653 { 4654 sm_dprintf("Timeouts:\n"); 4655 sm_dprintf(" connect = %ld\n", 4656 (long) TimeOuts.to_connect); 4657 sm_dprintf(" aconnect = %ld\n", 4658 (long) TimeOuts.to_aconnect); 4659 sm_dprintf(" initial = %ld\n", 4660 (long) TimeOuts.to_initial); 4661 sm_dprintf(" helo = %ld\n", (long) TimeOuts.to_helo); 4662 sm_dprintf(" mail = %ld\n", (long) TimeOuts.to_mail); 4663 sm_dprintf(" rcpt = %ld\n", (long) TimeOuts.to_rcpt); 4664 sm_dprintf(" datainit = %ld\n", 4665 (long) TimeOuts.to_datainit); 4666 sm_dprintf(" datablock = %ld\n", 4667 (long) TimeOuts.to_datablock); 4668 sm_dprintf(" datafinal = %ld\n", 4669 (long) TimeOuts.to_datafinal); 4670 sm_dprintf(" rset = %ld\n", (long) TimeOuts.to_rset); 4671 sm_dprintf(" quit = %ld\n", (long) TimeOuts.to_quit); 4672 sm_dprintf(" nextcommand = %ld\n", 4673 (long) TimeOuts.to_nextcommand); 4674 sm_dprintf(" miscshort = %ld\n", 4675 (long) TimeOuts.to_miscshort); 4676 sm_dprintf(" ident = %ld\n", (long) TimeOuts.to_ident); 4677 sm_dprintf(" fileopen = %ld\n", 4678 (long) TimeOuts.to_fileopen); 4679 sm_dprintf(" lhlo = %ld\n", 4680 (long) TimeOuts.to_lhlo); 4681 sm_dprintf(" control = %ld\n", 4682 (long) TimeOuts.to_control); 4683 } 4684 return; 4685 } 4686 4687 for (;; val = p) 4688 { 4689 while (isascii(*val) && isspace(*val)) 4690 val++; 4691 if (*val == '\0') 4692 break; 4693 for (p = val; *p != '\0' && *p != ','; p++) 4694 continue; 4695 if (*p != '\0') 4696 *p++ = '\0'; 4697 4698 if (isascii(*val) && isdigit(*val)) 4699 { 4700 /* old syntax -- set everything */ 4701 TimeOuts.to_mail = convtime(val, 'm'); 4702 TimeOuts.to_rcpt = TimeOuts.to_mail; 4703 TimeOuts.to_datainit = TimeOuts.to_mail; 4704 TimeOuts.to_datablock = TimeOuts.to_mail; 4705 TimeOuts.to_datafinal = TimeOuts.to_mail; 4706 TimeOuts.to_nextcommand = TimeOuts.to_mail; 4707 if (sticky) 4708 { 4709 setbitn(TO_MAIL, StickyTimeoutOpt); 4710 setbitn(TO_RCPT, StickyTimeoutOpt); 4711 setbitn(TO_DATAINIT, StickyTimeoutOpt); 4712 setbitn(TO_DATABLOCK, StickyTimeoutOpt); 4713 setbitn(TO_DATAFINAL, StickyTimeoutOpt); 4714 setbitn(TO_COMMAND, StickyTimeoutOpt); 4715 } 4716 continue; 4717 } 4718 else 4719 { 4720 register char *q = strchr(val, ':'); 4721 4722 if (q == NULL && (q = strchr(val, '=')) == NULL) 4723 { 4724 /* syntax error */ 4725 continue; 4726 } 4727 *q++ = '\0'; 4728 settimeout(val, q, sticky); 4729 } 4730 } 4731 } 4732