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