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