1 /* 2 * Copyright (c) 1998-2006 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.651 2006/03/02 19:17:09 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 sm_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 #if _FFR_MEMSTAT 2197 # define O_REFUSELOWMEM 0xd9 2198 { "RefuseLowMem", O_REFUSELOWMEM, OI_NONE }, 2199 # define O_QUEUELOWMEM 0xda 2200 { "QueueLowMem", O_QUEUELOWMEM, OI_NONE }, 2201 # define O_MEMRESOURCE 0xdb 2202 { "MemoryResource", O_MEMRESOURCE, OI_NONE }, 2203 #endif /* _FFR_MEMSTAT */ 2204 #if _FFR_MAXNOOPCOMMANDS 2205 # define O_MAXNOOPCOMMANDS 0xdc 2206 { "MaxNOOPCommands", O_MAXNOOPCOMMANDS, OI_NONE }, 2207 #endif /* _FFR_MAXNOOPCOMMANDS */ 2208 #if _FFR_MSG_ACCEPT 2209 # define O_MSG_ACCEPT 0xdd 2210 { "MessageAccept", O_MSG_ACCEPT, OI_NONE }, 2211 #endif /* _FFR_MSG_ACCEPT */ 2212 #if _FFR_QUEUE_RUN_PARANOIA 2213 # define O_CHK_Q_RUNNERS 0xde 2214 { "CheckQueueRunners", O_CHK_Q_RUNNERS, OI_NONE }, 2215 #endif /* _FFR_QUEUE_RUN_PARANOIA */ 2216 2217 { NULL, '\0', OI_NONE } 2218 }; 2219 2220 # define CANONIFY(val) 2221 2222 # define SET_OPT_DEFAULT(opt, val) opt = val 2223 2224 /* set a string option by expanding the value and assigning it */ 2225 /* WARNING this belongs ONLY into a case statement! */ 2226 #define SET_STRING_EXP(str) \ 2227 expand(val, exbuf, sizeof exbuf, e); \ 2228 newval = sm_pstrdup_x(exbuf); \ 2229 if (str != NULL) \ 2230 sm_free(str); \ 2231 CANONIFY(newval); \ 2232 str = newval; \ 2233 break 2234 2235 #define OPTNAME o->o_name == NULL ? "<unknown>" : o->o_name 2236 2237 void 2238 setoption(opt, val, safe, sticky, e) 2239 int opt; 2240 char *val; 2241 bool safe; 2242 bool sticky; 2243 register ENVELOPE *e; 2244 { 2245 register char *p; 2246 register struct optioninfo *o; 2247 char *subopt; 2248 int mid; 2249 bool can_setuid = RunAsUid == 0; 2250 auto char *ep; 2251 char buf[50]; 2252 extern bool Warn_Q_option; 2253 #if _FFR_ALLOW_SASLINFO 2254 extern unsigned int SubmitMode; 2255 #endif /* _FFR_ALLOW_SASLINFO */ 2256 #if STARTTLS || (_FFR_SELECT_SHM && SM_CONF_SHM) 2257 char *newval; 2258 char exbuf[MAXLINE]; 2259 #endif /* STARTTLS || (_FFR_SELECT_SHM && SM_CONF_SHM) */ 2260 2261 errno = 0; 2262 if (opt == ' ') 2263 { 2264 /* full word options */ 2265 struct optioninfo *sel; 2266 2267 p = strchr(val, '='); 2268 if (p == NULL) 2269 p = &val[strlen(val)]; 2270 while (*--p == ' ') 2271 continue; 2272 while (*++p == ' ') 2273 *p = '\0'; 2274 if (p == val) 2275 { 2276 syserr("readcf: null option name"); 2277 return; 2278 } 2279 if (*p == '=') 2280 *p++ = '\0'; 2281 while (*p == ' ') 2282 p++; 2283 subopt = strchr(val, '.'); 2284 if (subopt != NULL) 2285 *subopt++ = '\0'; 2286 sel = NULL; 2287 for (o = OptionTab; o->o_name != NULL; o++) 2288 { 2289 if (sm_strncasecmp(o->o_name, val, strlen(val)) != 0) 2290 continue; 2291 if (strlen(o->o_name) == strlen(val)) 2292 { 2293 /* completely specified -- this must be it */ 2294 sel = NULL; 2295 break; 2296 } 2297 if (sel != NULL) 2298 break; 2299 sel = o; 2300 } 2301 if (sel != NULL && o->o_name == NULL) 2302 o = sel; 2303 else if (o->o_name == NULL) 2304 { 2305 syserr("readcf: unknown option name %s", val); 2306 return; 2307 } 2308 else if (sel != NULL) 2309 { 2310 syserr("readcf: ambiguous option name %s (matches %s and %s)", 2311 val, sel->o_name, o->o_name); 2312 return; 2313 } 2314 if (strlen(val) != strlen(o->o_name)) 2315 { 2316 int oldVerbose = Verbose; 2317 2318 Verbose = 1; 2319 message("Option %s used as abbreviation for %s", 2320 val, o->o_name); 2321 Verbose = oldVerbose; 2322 } 2323 opt = o->o_code; 2324 val = p; 2325 } 2326 else 2327 { 2328 for (o = OptionTab; o->o_name != NULL; o++) 2329 { 2330 if (o->o_code == opt) 2331 break; 2332 } 2333 if (o->o_name == NULL) 2334 { 2335 syserr("readcf: unknown option name 0x%x", opt & 0xff); 2336 return; 2337 } 2338 subopt = NULL; 2339 } 2340 2341 if (subopt != NULL && !bitset(OI_SUBOPT, o->o_flags)) 2342 { 2343 if (tTd(37, 1)) 2344 sm_dprintf("setoption: %s does not support suboptions, ignoring .%s\n", 2345 OPTNAME, subopt); 2346 subopt = NULL; 2347 } 2348 2349 if (tTd(37, 1)) 2350 { 2351 sm_dprintf(isascii(opt) && isprint(opt) ? 2352 "setoption %s (%c)%s%s=" : 2353 "setoption %s (0x%x)%s%s=", 2354 OPTNAME, opt, subopt == NULL ? "" : ".", 2355 subopt == NULL ? "" : subopt); 2356 xputs(sm_debug_file(), val); 2357 } 2358 2359 /* 2360 ** See if this option is preset for us. 2361 */ 2362 2363 if (!sticky && bitnset(opt, StickyOpt)) 2364 { 2365 if (tTd(37, 1)) 2366 sm_dprintf(" (ignored)\n"); 2367 return; 2368 } 2369 2370 /* 2371 ** Check to see if this option can be specified by this user. 2372 */ 2373 2374 if (!safe && RealUid == 0) 2375 safe = true; 2376 if (!safe && !bitset(OI_SAFE, o->o_flags)) 2377 { 2378 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 2379 { 2380 int dp; 2381 2382 if (tTd(37, 1)) 2383 sm_dprintf(" (unsafe)"); 2384 dp = drop_privileges(true); 2385 setstat(dp); 2386 } 2387 } 2388 if (tTd(37, 1)) 2389 sm_dprintf("\n"); 2390 2391 switch (opt & 0xff) 2392 { 2393 case '7': /* force seven-bit input */ 2394 SevenBitInput = atobool(val); 2395 break; 2396 2397 case '8': /* handling of 8-bit input */ 2398 #if MIME8TO7 2399 switch (*val) 2400 { 2401 case 'p': /* pass 8 bit, convert MIME */ 2402 MimeMode = MM_CVTMIME|MM_PASS8BIT; 2403 break; 2404 2405 case 'm': /* convert 8-bit, convert MIME */ 2406 MimeMode = MM_CVTMIME|MM_MIME8BIT; 2407 break; 2408 2409 case 's': /* strict adherence */ 2410 MimeMode = MM_CVTMIME; 2411 break; 2412 2413 # if 0 2414 case 'r': /* reject 8-bit, don't convert MIME */ 2415 MimeMode = 0; 2416 break; 2417 2418 case 'j': /* "just send 8" */ 2419 MimeMode = MM_PASS8BIT; 2420 break; 2421 2422 case 'a': /* encode 8 bit if available */ 2423 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 2424 break; 2425 2426 case 'c': /* convert 8 bit to MIME, never 7 bit */ 2427 MimeMode = MM_MIME8BIT; 2428 break; 2429 # endif /* 0 */ 2430 2431 default: 2432 syserr("Unknown 8-bit mode %c", *val); 2433 finis(false, true, EX_USAGE); 2434 } 2435 #else /* MIME8TO7 */ 2436 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 2437 "Warning: Option: %s requires MIME8TO7 support\n", 2438 OPTNAME); 2439 #endif /* MIME8TO7 */ 2440 break; 2441 2442 case 'A': /* set default alias file */ 2443 if (val[0] == '\0') 2444 { 2445 char *al; 2446 2447 SET_OPT_DEFAULT(al, "aliases"); 2448 setalias(al); 2449 } 2450 else 2451 setalias(val); 2452 break; 2453 2454 case 'a': /* look N minutes for "@:@" in alias file */ 2455 if (val[0] == '\0') 2456 SafeAlias = 5 MINUTES; 2457 else 2458 SafeAlias = convtime(val, 'm'); 2459 break; 2460 2461 case 'B': /* substitution for blank character */ 2462 SpaceSub = val[0]; 2463 if (SpaceSub == '\0') 2464 SpaceSub = ' '; 2465 break; 2466 2467 case 'b': /* min blocks free on queue fs/max msg size */ 2468 p = strchr(val, '/'); 2469 if (p != NULL) 2470 { 2471 *p++ = '\0'; 2472 MaxMessageSize = atol(p); 2473 } 2474 MinBlocksFree = atol(val); 2475 break; 2476 2477 case 'c': /* don't connect to "expensive" mailers */ 2478 NoConnect = atobool(val); 2479 break; 2480 2481 case 'C': /* checkpoint every N addresses */ 2482 if (safe || CheckpointInterval > atoi(val)) 2483 CheckpointInterval = atoi(val); 2484 break; 2485 2486 case 'd': /* delivery mode */ 2487 switch (*val) 2488 { 2489 case '\0': 2490 set_delivery_mode(SM_DELIVER, e); 2491 break; 2492 2493 case SM_QUEUE: /* queue only */ 2494 case SM_DEFER: /* queue only and defer map lookups */ 2495 case SM_DELIVER: /* do everything */ 2496 case SM_FORK: /* fork after verification */ 2497 #if _FFR_DM_ONE 2498 /* deliver first TA in background, then queue */ 2499 case SM_DM_ONE: 2500 #endif /* _FFR_DM_ONE */ 2501 set_delivery_mode(*val, e); 2502 break; 2503 2504 default: 2505 syserr("Unknown delivery mode %c", *val); 2506 finis(false, true, EX_USAGE); 2507 } 2508 break; 2509 2510 case 'E': /* error message header/header file */ 2511 if (*val != '\0') 2512 ErrMsgFile = newstr(val); 2513 break; 2514 2515 case 'e': /* set error processing mode */ 2516 switch (*val) 2517 { 2518 case EM_QUIET: /* be silent about it */ 2519 case EM_MAIL: /* mail back */ 2520 case EM_BERKNET: /* do berknet error processing */ 2521 case EM_WRITE: /* write back (or mail) */ 2522 case EM_PRINT: /* print errors normally (default) */ 2523 e->e_errormode = *val; 2524 break; 2525 } 2526 break; 2527 2528 case 'F': /* file mode */ 2529 FileMode = atooct(val) & 0777; 2530 break; 2531 2532 case 'f': /* save Unix-style From lines on front */ 2533 SaveFrom = atobool(val); 2534 break; 2535 2536 case 'G': /* match recipients against GECOS field */ 2537 MatchGecos = atobool(val); 2538 break; 2539 2540 case 'g': /* default gid */ 2541 g_opt: 2542 if (isascii(*val) && isdigit(*val)) 2543 DefGid = atoi(val); 2544 else 2545 { 2546 register struct group *gr; 2547 2548 DefGid = -1; 2549 gr = getgrnam(val); 2550 if (gr == NULL) 2551 syserr("readcf: option %c: unknown group %s", 2552 opt, val); 2553 else 2554 DefGid = gr->gr_gid; 2555 } 2556 break; 2557 2558 case 'H': /* help file */ 2559 if (val[0] == '\0') 2560 { 2561 SET_OPT_DEFAULT(HelpFile, "helpfile"); 2562 } 2563 else 2564 { 2565 CANONIFY(val); 2566 HelpFile = newstr(val); 2567 } 2568 break; 2569 2570 case 'h': /* maximum hop count */ 2571 MaxHopCount = atoi(val); 2572 break; 2573 2574 case 'I': /* use internet domain name server */ 2575 #if NAMED_BIND 2576 for (p = val; *p != 0; ) 2577 { 2578 bool clearmode; 2579 char *q; 2580 struct resolverflags *rfp; 2581 2582 while (*p == ' ') 2583 p++; 2584 if (*p == '\0') 2585 break; 2586 clearmode = false; 2587 if (*p == '-') 2588 clearmode = true; 2589 else if (*p != '+') 2590 p--; 2591 p++; 2592 q = p; 2593 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2594 p++; 2595 if (*p != '\0') 2596 *p++ = '\0'; 2597 if (sm_strcasecmp(q, "HasWildcardMX") == 0) 2598 { 2599 HasWildcardMX = !clearmode; 2600 continue; 2601 } 2602 if (sm_strcasecmp(q, "WorkAroundBrokenAAAA") == 0) 2603 { 2604 WorkAroundBrokenAAAA = !clearmode; 2605 continue; 2606 } 2607 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 2608 { 2609 if (sm_strcasecmp(q, rfp->rf_name) == 0) 2610 break; 2611 } 2612 if (rfp->rf_name == NULL) 2613 syserr("readcf: I option value %s unrecognized", q); 2614 else if (clearmode) 2615 _res.options &= ~rfp->rf_bits; 2616 else 2617 _res.options |= rfp->rf_bits; 2618 } 2619 if (tTd(8, 2)) 2620 sm_dprintf("_res.options = %x, HasWildcardMX = %d\n", 2621 (unsigned int) _res.options, HasWildcardMX); 2622 #else /* NAMED_BIND */ 2623 usrerr("name server (I option) specified but BIND not compiled in"); 2624 #endif /* NAMED_BIND */ 2625 break; 2626 2627 case 'i': /* ignore dot lines in message */ 2628 IgnrDot = atobool(val); 2629 break; 2630 2631 case 'j': /* send errors in MIME (RFC 1341) format */ 2632 SendMIMEErrors = atobool(val); 2633 break; 2634 2635 case 'J': /* .forward search path */ 2636 CANONIFY(val); 2637 ForwardPath = newstr(val); 2638 break; 2639 2640 case 'k': /* connection cache size */ 2641 MaxMciCache = atoi(val); 2642 if (MaxMciCache < 0) 2643 MaxMciCache = 0; 2644 break; 2645 2646 case 'K': /* connection cache timeout */ 2647 MciCacheTimeout = convtime(val, 'm'); 2648 break; 2649 2650 case 'l': /* use Errors-To: header */ 2651 UseErrorsTo = atobool(val); 2652 break; 2653 2654 case 'L': /* log level */ 2655 if (safe || LogLevel < atoi(val)) 2656 LogLevel = atoi(val); 2657 break; 2658 2659 case 'M': /* define macro */ 2660 sticky = false; 2661 mid = macid_parse(val, &ep); 2662 if (mid == 0) 2663 break; 2664 p = newstr(ep); 2665 if (!safe) 2666 cleanstrcpy(p, p, strlen(p) + 1); 2667 macdefine(&CurEnv->e_macro, A_TEMP, mid, p); 2668 break; 2669 2670 case 'm': /* send to me too */ 2671 MeToo = atobool(val); 2672 break; 2673 2674 case 'n': /* validate RHS in newaliases */ 2675 CheckAliases = atobool(val); 2676 break; 2677 2678 /* 'N' available -- was "net name" */ 2679 2680 case 'O': /* daemon options */ 2681 if (!setdaemonoptions(val)) 2682 syserr("too many daemons defined (%d max)", MAXDAEMONS); 2683 break; 2684 2685 case 'o': /* assume old style headers */ 2686 if (atobool(val)) 2687 CurEnv->e_flags |= EF_OLDSTYLE; 2688 else 2689 CurEnv->e_flags &= ~EF_OLDSTYLE; 2690 break; 2691 2692 case 'p': /* select privacy level */ 2693 p = val; 2694 for (;;) 2695 { 2696 register struct prival *pv; 2697 extern struct prival PrivacyValues[]; 2698 2699 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 2700 p++; 2701 if (*p == '\0') 2702 break; 2703 val = p; 2704 while (isascii(*p) && isalnum(*p)) 2705 p++; 2706 if (*p != '\0') 2707 *p++ = '\0'; 2708 2709 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 2710 { 2711 if (sm_strcasecmp(val, pv->pv_name) == 0) 2712 break; 2713 } 2714 if (pv->pv_name == NULL) 2715 syserr("readcf: Op line: %s unrecognized", val); 2716 else 2717 PrivacyFlags |= pv->pv_flag; 2718 } 2719 sticky = false; 2720 break; 2721 2722 case 'P': /* postmaster copy address for returned mail */ 2723 PostMasterCopy = newstr(val); 2724 break; 2725 2726 case 'q': /* slope of queue only function */ 2727 QueueFactor = atoi(val); 2728 break; 2729 2730 case 'Q': /* queue directory */ 2731 if (val[0] == '\0') 2732 { 2733 QueueDir = "mqueue"; 2734 } 2735 else 2736 { 2737 QueueDir = newstr(val); 2738 } 2739 if (RealUid != 0 && !safe) 2740 Warn_Q_option = true; 2741 break; 2742 2743 case 'R': /* don't prune routes */ 2744 DontPruneRoutes = atobool(val); 2745 break; 2746 2747 case 'r': /* read timeout */ 2748 if (subopt == NULL) 2749 inittimeouts(val, sticky); 2750 else 2751 settimeout(subopt, val, sticky); 2752 break; 2753 2754 case 'S': /* status file */ 2755 if (val[0] == '\0') 2756 { 2757 SET_OPT_DEFAULT(StatFile, "statistics"); 2758 } 2759 else 2760 { 2761 CANONIFY(val); 2762 StatFile = newstr(val); 2763 } 2764 break; 2765 2766 case 's': /* be super safe, even if expensive */ 2767 if (tolower(*val) == 'i') 2768 SuperSafe = SAFE_INTERACTIVE; 2769 else if (tolower(*val) == 'p') 2770 #if MILTER 2771 SuperSafe = SAFE_REALLY_POSTMILTER; 2772 #else /* MILTER */ 2773 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 2774 "Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n"); 2775 #endif /* MILTER */ 2776 else 2777 SuperSafe = atobool(val) ? SAFE_REALLY : SAFE_NO; 2778 break; 2779 2780 case 'T': /* queue timeout */ 2781 p = strchr(val, '/'); 2782 if (p != NULL) 2783 { 2784 *p++ = '\0'; 2785 settimeout("queuewarn", p, sticky); 2786 } 2787 settimeout("queuereturn", val, sticky); 2788 break; 2789 2790 case 't': /* time zone name */ 2791 TimeZoneSpec = newstr(val); 2792 break; 2793 2794 case 'U': /* location of user database */ 2795 UdbSpec = newstr(val); 2796 break; 2797 2798 case 'u': /* set default uid */ 2799 for (p = val; *p != '\0'; p++) 2800 { 2801 # if _FFR_DOTTED_USERNAMES 2802 if (*p == '/' || *p == ':') 2803 # else /* _FFR_DOTTED_USERNAMES */ 2804 if (*p == '.' || *p == '/' || *p == ':') 2805 # endif /* _FFR_DOTTED_USERNAMES */ 2806 { 2807 *p++ = '\0'; 2808 break; 2809 } 2810 } 2811 if (isascii(*val) && isdigit(*val)) 2812 { 2813 DefUid = atoi(val); 2814 setdefuser(); 2815 } 2816 else 2817 { 2818 register struct passwd *pw; 2819 2820 DefUid = -1; 2821 pw = sm_getpwnam(val); 2822 if (pw == NULL) 2823 { 2824 syserr("readcf: option u: unknown user %s", val); 2825 break; 2826 } 2827 else 2828 { 2829 DefUid = pw->pw_uid; 2830 DefGid = pw->pw_gid; 2831 DefUser = newstr(pw->pw_name); 2832 } 2833 } 2834 2835 # ifdef UID_MAX 2836 if (DefUid > UID_MAX) 2837 { 2838 syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored", 2839 (long)DefUid, (long)UID_MAX); 2840 break; 2841 } 2842 # endif /* UID_MAX */ 2843 2844 /* handle the group if it is there */ 2845 if (*p == '\0') 2846 break; 2847 val = p; 2848 goto g_opt; 2849 2850 case 'V': /* fallback MX host */ 2851 if (val[0] != '\0') 2852 FallbackMX = newstr(val); 2853 break; 2854 2855 case 'v': /* run in verbose mode */ 2856 Verbose = atobool(val) ? 1 : 0; 2857 break; 2858 2859 case 'w': /* if we are best MX, try host directly */ 2860 TryNullMXList = atobool(val); 2861 break; 2862 2863 /* 'W' available -- was wizard password */ 2864 2865 case 'x': /* load avg at which to auto-queue msgs */ 2866 QueueLA = atoi(val); 2867 break; 2868 2869 case 'X': /* load avg at which to auto-reject connections */ 2870 RefuseLA = atoi(val); 2871 break; 2872 2873 case O_DELAY_LA: /* load avg at which to delay connections */ 2874 DelayLA = atoi(val); 2875 break; 2876 2877 case 'y': /* work recipient factor */ 2878 WkRecipFact = atoi(val); 2879 break; 2880 2881 case 'Y': /* fork jobs during queue runs */ 2882 ForkQueueRuns = atobool(val); 2883 break; 2884 2885 case 'z': /* work message class factor */ 2886 WkClassFact = atoi(val); 2887 break; 2888 2889 case 'Z': /* work time factor */ 2890 WkTimeFact = atoi(val); 2891 break; 2892 2893 2894 #if _FFR_QUEUE_GROUP_SORTORDER 2895 /* coordinate this with makequeue() */ 2896 #endif /* _FFR_QUEUE_GROUP_SORTORDER */ 2897 case O_QUEUESORTORD: /* queue sorting order */ 2898 switch (*val) 2899 { 2900 case 'f': /* File Name */ 2901 case 'F': 2902 QueueSortOrder = QSO_BYFILENAME; 2903 break; 2904 2905 case 'h': /* Host first */ 2906 case 'H': 2907 QueueSortOrder = QSO_BYHOST; 2908 break; 2909 2910 case 'm': /* Modification time */ 2911 case 'M': 2912 QueueSortOrder = QSO_BYMODTIME; 2913 break; 2914 2915 case 'p': /* Priority order */ 2916 case 'P': 2917 QueueSortOrder = QSO_BYPRIORITY; 2918 break; 2919 2920 case 't': /* Submission time */ 2921 case 'T': 2922 QueueSortOrder = QSO_BYTIME; 2923 break; 2924 2925 case 'r': /* Random */ 2926 case 'R': 2927 QueueSortOrder = QSO_RANDOM; 2928 break; 2929 2930 #if _FFR_RHS 2931 case 's': /* Shuffled host name */ 2932 case 'S': 2933 QueueSortOrder = QSO_BYSHUFFLE; 2934 break; 2935 #endif /* _FFR_RHS */ 2936 2937 case 'n': /* none */ 2938 case 'N': 2939 QueueSortOrder = QSO_NONE; 2940 break; 2941 2942 default: 2943 syserr("Invalid queue sort order \"%s\"", val); 2944 } 2945 break; 2946 2947 case O_HOSTSFILE: /* pathname of /etc/hosts file */ 2948 CANONIFY(val); 2949 HostsFile = newstr(val); 2950 break; 2951 2952 case O_MQA: /* minimum queue age between deliveries */ 2953 MinQueueAge = convtime(val, 'm'); 2954 break; 2955 2956 case O_DEFCHARSET: /* default character set for mimefying */ 2957 DefaultCharSet = newstr(denlstring(val, true, true)); 2958 break; 2959 2960 case O_SSFILE: /* service switch file */ 2961 CANONIFY(val); 2962 ServiceSwitchFile = newstr(val); 2963 break; 2964 2965 case O_DIALDELAY: /* delay for dial-on-demand operation */ 2966 DialDelay = convtime(val, 's'); 2967 break; 2968 2969 case O_NORCPTACTION: /* what to do if no recipient */ 2970 if (sm_strcasecmp(val, "none") == 0) 2971 NoRecipientAction = NRA_NO_ACTION; 2972 else if (sm_strcasecmp(val, "add-to") == 0) 2973 NoRecipientAction = NRA_ADD_TO; 2974 else if (sm_strcasecmp(val, "add-apparently-to") == 0) 2975 NoRecipientAction = NRA_ADD_APPARENTLY_TO; 2976 else if (sm_strcasecmp(val, "add-bcc") == 0) 2977 NoRecipientAction = NRA_ADD_BCC; 2978 else if (sm_strcasecmp(val, "add-to-undisclosed") == 0) 2979 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 2980 else 2981 syserr("Invalid NoRecipientAction: %s", val); 2982 break; 2983 2984 case O_SAFEFILEENV: /* chroot() environ for writing to files */ 2985 if (*val == '\0') 2986 break; 2987 2988 /* strip trailing slashes */ 2989 p = val + strlen(val) - 1; 2990 while (p >= val && *p == '/') 2991 *p-- = '\0'; 2992 2993 if (*val == '\0') 2994 break; 2995 2996 SafeFileEnv = newstr(val); 2997 break; 2998 2999 case O_MAXMSGSIZE: /* maximum message size */ 3000 MaxMessageSize = atol(val); 3001 break; 3002 3003 case O_COLONOKINADDR: /* old style handling of colon addresses */ 3004 ColonOkInAddr = atobool(val); 3005 break; 3006 3007 case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 3008 MaxQueueRun = atoi(val); 3009 break; 3010 3011 case O_MAXCHILDREN: /* max # of children of daemon */ 3012 MaxChildren = atoi(val); 3013 break; 3014 3015 case O_MAXQUEUECHILDREN: /* max # of children of daemon */ 3016 MaxQueueChildren = atoi(val); 3017 break; 3018 3019 case O_MAXRUNNERSPERQUEUE: /* max # runners in a queue group */ 3020 MaxRunnersPerQueue = atoi(val); 3021 break; 3022 3023 case O_NICEQUEUERUN: /* nice queue runs */ 3024 #if !HASNICE 3025 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3026 "Warning: NiceQueueRun set on system that doesn't support nice()\n"); 3027 #endif /* !HASNICE */ 3028 3029 /* XXX do we want to check the range? > 0 ? */ 3030 NiceQueueRun = atoi(val); 3031 break; 3032 3033 case O_SHMKEY: /* shared memory key */ 3034 #if SM_CONF_SHM 3035 ShmKey = atol(val); 3036 #else /* SM_CONF_SHM */ 3037 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3038 "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n", 3039 OPTNAME); 3040 #endif /* SM_CONF_SHM */ 3041 break; 3042 3043 #if _FFR_SELECT_SHM 3044 case O_SHMKEYFILE: /* shared memory key file */ 3045 # if SM_CONF_SHM 3046 SET_STRING_EXP(ShmKeyFile); 3047 # else /* SM_CONF_SHM */ 3048 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3049 "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n", 3050 OPTNAME); 3051 break; 3052 # endif /* SM_CONF_SHM */ 3053 #endif /* _FFR_SELECT_SHM */ 3054 3055 #if _FFR_MAX_FORWARD_ENTRIES 3056 case O_MAXFORWARD: /* max # of forward entries */ 3057 MaxForwardEntries = atoi(val); 3058 break; 3059 #endif /* _FFR_MAX_FORWARD_ENTRIES */ 3060 3061 case O_KEEPCNAMES: /* don't expand CNAME records */ 3062 DontExpandCnames = atobool(val); 3063 break; 3064 3065 case O_MUSTQUOTE: /* must quote these characters in phrases */ 3066 (void) sm_strlcpy(buf, "@,;:\\()[]", sizeof buf); 3067 if (strlen(val) < sizeof buf - 10) 3068 (void) sm_strlcat(buf, val, sizeof buf); 3069 else 3070 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3071 "Warning: MustQuoteChars too long, ignored.\n"); 3072 MustQuoteChars = newstr(buf); 3073 break; 3074 3075 case O_SMTPGREETING: /* SMTP greeting message (old $e macro) */ 3076 SmtpGreeting = newstr(munchstring(val, NULL, '\0')); 3077 break; 3078 3079 case O_UNIXFROM: /* UNIX From_ line (old $l macro) */ 3080 UnixFromLine = newstr(munchstring(val, NULL, '\0')); 3081 break; 3082 3083 case O_OPCHARS: /* operator characters (old $o macro) */ 3084 if (OperatorChars != NULL) 3085 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3086 "Warning: OperatorChars is being redefined.\n It should only be set before ruleset definitions.\n"); 3087 OperatorChars = newstr(munchstring(val, NULL, '\0')); 3088 break; 3089 3090 case O_DONTINITGRPS: /* don't call initgroups(3) */ 3091 DontInitGroups = atobool(val); 3092 break; 3093 3094 case O_SLFH: /* make sure from fits on one line */ 3095 SingleLineFromHeader = atobool(val); 3096 break; 3097 3098 case O_ABH: /* allow HELO commands with syntax errors */ 3099 AllowBogusHELO = atobool(val); 3100 break; 3101 3102 case O_CONNTHROT: /* connection rate throttle */ 3103 ConnRateThrottle = atoi(val); 3104 break; 3105 3106 case O_UGW: /* group writable files are unsafe */ 3107 if (!atobool(val)) 3108 { 3109 setbitn(DBS_GROUPWRITABLEFORWARDFILESAFE, 3110 DontBlameSendmail); 3111 setbitn(DBS_GROUPWRITABLEINCLUDEFILESAFE, 3112 DontBlameSendmail); 3113 } 3114 break; 3115 3116 case O_DBLBOUNCE: /* address to which to send double bounces */ 3117 DoubleBounceAddr = newstr(val); 3118 break; 3119 3120 case O_HSDIR: /* persistent host status directory */ 3121 if (val[0] != '\0') 3122 { 3123 CANONIFY(val); 3124 HostStatDir = newstr(val); 3125 } 3126 break; 3127 3128 case O_SINGTHREAD: /* single thread deliveries (requires hsdir) */ 3129 SingleThreadDelivery = atobool(val); 3130 break; 3131 3132 case O_RUNASUSER: /* run bulk of code as this user */ 3133 for (p = val; *p != '\0'; p++) 3134 { 3135 # if _FFR_DOTTED_USERNAMES 3136 if (*p == '/' || *p == ':') 3137 # else /* _FFR_DOTTED_USERNAMES */ 3138 if (*p == '.' || *p == '/' || *p == ':') 3139 # endif /* _FFR_DOTTED_USERNAMES */ 3140 { 3141 *p++ = '\0'; 3142 break; 3143 } 3144 } 3145 if (isascii(*val) && isdigit(*val)) 3146 { 3147 if (can_setuid) 3148 RunAsUid = atoi(val); 3149 } 3150 else 3151 { 3152 register struct passwd *pw; 3153 3154 pw = sm_getpwnam(val); 3155 if (pw == NULL) 3156 { 3157 syserr("readcf: option RunAsUser: unknown user %s", val); 3158 break; 3159 } 3160 else if (can_setuid) 3161 { 3162 if (*p == '\0') 3163 RunAsUserName = newstr(val); 3164 RunAsUid = pw->pw_uid; 3165 RunAsGid = pw->pw_gid; 3166 } 3167 else if (EffGid == pw->pw_gid) 3168 RunAsGid = pw->pw_gid; 3169 else if (UseMSP && *p == '\0') 3170 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3171 "WARNING: RunAsUser for MSP ignored, check group ids (egid=%d, want=%d)\n", 3172 (int) EffGid, 3173 (int) pw->pw_gid); 3174 } 3175 # ifdef UID_MAX 3176 if (RunAsUid > UID_MAX) 3177 { 3178 syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored", 3179 (long) RunAsUid, (long) UID_MAX); 3180 break; 3181 } 3182 # endif /* UID_MAX */ 3183 if (*p != '\0') 3184 { 3185 if (isascii(*p) && isdigit(*p)) 3186 { 3187 gid_t runasgid; 3188 3189 runasgid = (gid_t) atoi(p); 3190 if (can_setuid || EffGid == runasgid) 3191 RunAsGid = runasgid; 3192 else if (UseMSP) 3193 (void) sm_io_fprintf(smioout, 3194 SM_TIME_DEFAULT, 3195 "WARNING: RunAsUser for MSP ignored, check group ids (egid=%d, want=%d)\n", 3196 (int) EffGid, 3197 (int) runasgid); 3198 } 3199 else 3200 { 3201 register struct group *gr; 3202 3203 gr = getgrnam(p); 3204 if (gr == NULL) 3205 syserr("readcf: option RunAsUser: unknown group %s", 3206 p); 3207 else if (can_setuid || EffGid == gr->gr_gid) 3208 RunAsGid = gr->gr_gid; 3209 else if (UseMSP) 3210 (void) sm_io_fprintf(smioout, 3211 SM_TIME_DEFAULT, 3212 "WARNING: RunAsUser for MSP ignored, check group ids (egid=%d, want=%d)\n", 3213 (int) EffGid, 3214 (int) gr->gr_gid); 3215 } 3216 } 3217 if (tTd(47, 5)) 3218 sm_dprintf("readcf: RunAsUser = %d:%d\n", 3219 (int) RunAsUid, (int) RunAsGid); 3220 break; 3221 3222 case O_DSN_RRT: 3223 RrtImpliesDsn = atobool(val); 3224 break; 3225 3226 case O_PIDFILE: 3227 PSTRSET(PidFile, val); 3228 break; 3229 3230 case O_DONTBLAMESENDMAIL: 3231 p = val; 3232 for (;;) 3233 { 3234 register struct dbsval *dbs; 3235 extern struct dbsval DontBlameSendmailValues[]; 3236 3237 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 3238 p++; 3239 if (*p == '\0') 3240 break; 3241 val = p; 3242 while (isascii(*p) && isalnum(*p)) 3243 p++; 3244 if (*p != '\0') 3245 *p++ = '\0'; 3246 3247 for (dbs = DontBlameSendmailValues; 3248 dbs->dbs_name != NULL; dbs++) 3249 { 3250 if (sm_strcasecmp(val, dbs->dbs_name) == 0) 3251 break; 3252 } 3253 if (dbs->dbs_name == NULL) 3254 syserr("readcf: DontBlameSendmail option: %s unrecognized", val); 3255 else if (dbs->dbs_flag == DBS_SAFE) 3256 clrbitmap(DontBlameSendmail); 3257 else 3258 setbitn(dbs->dbs_flag, DontBlameSendmail); 3259 } 3260 sticky = false; 3261 break; 3262 3263 case O_DPI: 3264 if (sm_strcasecmp(val, "loopback") == 0) 3265 DontProbeInterfaces = DPI_SKIPLOOPBACK; 3266 else if (atobool(val)) 3267 DontProbeInterfaces = DPI_PROBENONE; 3268 else 3269 DontProbeInterfaces = DPI_PROBEALL; 3270 break; 3271 3272 case O_MAXRCPT: 3273 MaxRcptPerMsg = atoi(val); 3274 break; 3275 3276 case O_RCPTTHROT: 3277 BadRcptThrottle = atoi(val); 3278 break; 3279 3280 case O_DEADLETTER: 3281 CANONIFY(val); 3282 PSTRSET(DeadLetterDrop, val); 3283 break; 3284 3285 #if _FFR_DONTLOCKFILESFORREAD_OPTION 3286 case O_DONTLOCK: 3287 DontLockReadFiles = atobool(val); 3288 break; 3289 #endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */ 3290 3291 case O_MAXALIASRCSN: 3292 MaxAliasRecursion = atoi(val); 3293 break; 3294 3295 case O_CNCTONLYTO: 3296 /* XXX should probably use gethostbyname */ 3297 #if NETINET || NETINET6 3298 ConnectOnlyTo.sa.sa_family = AF_UNSPEC; 3299 # if NETINET6 3300 if (anynet_pton(AF_INET6, val, 3301 &ConnectOnlyTo.sin6.sin6_addr) != 1) 3302 ConnectOnlyTo.sa.sa_family = AF_INET6; 3303 else 3304 # endif /* NETINET6 */ 3305 # if NETINET 3306 { 3307 ConnectOnlyTo.sin.sin_addr.s_addr = inet_addr(val); 3308 if (ConnectOnlyTo.sin.sin_addr.s_addr != INADDR_NONE) 3309 ConnectOnlyTo.sa.sa_family = AF_INET; 3310 } 3311 3312 # endif /* NETINET */ 3313 if (ConnectOnlyTo.sa.sa_family == AF_UNSPEC) 3314 { 3315 syserr("readcf: option ConnectOnlyTo: invalid IP address %s", 3316 val); 3317 break; 3318 } 3319 #endif /* NETINET || NETINET6 */ 3320 break; 3321 3322 case O_TRUSTUSER: 3323 # if !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING) 3324 if (!UseMSP) 3325 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3326 "readcf: option TrustedUser may cause problems on systems\n which do not support fchown() if UseMSP is not set.\n"); 3327 # endif /* !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING) */ 3328 if (isascii(*val) && isdigit(*val)) 3329 TrustedUid = atoi(val); 3330 else 3331 { 3332 register struct passwd *pw; 3333 3334 TrustedUid = 0; 3335 pw = sm_getpwnam(val); 3336 if (pw == NULL) 3337 { 3338 syserr("readcf: option TrustedUser: unknown user %s", val); 3339 break; 3340 } 3341 else 3342 TrustedUid = pw->pw_uid; 3343 } 3344 3345 # ifdef UID_MAX 3346 if (TrustedUid > UID_MAX) 3347 { 3348 syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)", 3349 (long) TrustedUid, (long) UID_MAX); 3350 TrustedUid = 0; 3351 } 3352 # endif /* UID_MAX */ 3353 break; 3354 3355 case O_MAXMIMEHDRLEN: 3356 p = strchr(val, '/'); 3357 if (p != NULL) 3358 *p++ = '\0'; 3359 MaxMimeHeaderLength = atoi(val); 3360 if (p != NULL && *p != '\0') 3361 MaxMimeFieldLength = atoi(p); 3362 else 3363 MaxMimeFieldLength = MaxMimeHeaderLength / 2; 3364 3365 if (MaxMimeHeaderLength <= 0) 3366 MaxMimeHeaderLength = 0; 3367 else if (MaxMimeHeaderLength < 128) 3368 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3369 "Warning: MaxMimeHeaderLength: header length limit set lower than 128\n"); 3370 3371 if (MaxMimeFieldLength <= 0) 3372 MaxMimeFieldLength = 0; 3373 else if (MaxMimeFieldLength < 40) 3374 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3375 "Warning: MaxMimeHeaderLength: field length limit set lower than 40\n"); 3376 break; 3377 3378 case O_CONTROLSOCKET: 3379 PSTRSET(ControlSocketName, val); 3380 break; 3381 3382 case O_MAXHDRSLEN: 3383 MaxHeadersLength = atoi(val); 3384 3385 if (MaxHeadersLength > 0 && 3386 MaxHeadersLength < (MAXHDRSLEN / 2)) 3387 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3388 "Warning: MaxHeadersLength: headers length limit set lower than %d\n", 3389 (MAXHDRSLEN / 2)); 3390 break; 3391 3392 case O_PROCTITLEPREFIX: 3393 PSTRSET(ProcTitlePrefix, val); 3394 break; 3395 3396 #if SASL 3397 case O_SASLINFO: 3398 # if _FFR_ALLOW_SASLINFO 3399 /* 3400 ** Allow users to select their own authinfo file 3401 ** under certain circumstances, otherwise just ignore 3402 ** the option. If the option isn't ignored, several 3403 ** commands don't work very well, e.g., mailq. 3404 ** However, this is not a "perfect" solution. 3405 ** If mail is queued, the authentication info 3406 ** will not be used in subsequent delivery attempts. 3407 ** If we really want to support this, then it has 3408 ** to be stored in the queue file. 3409 */ 3410 if (!bitset(SUBMIT_MSA, SubmitMode) && RealUid != 0 && 3411 RunAsUid != RealUid) 3412 break; 3413 # endif /* _FFR_ALLOW_SASLINFO */ 3414 PSTRSET(SASLInfo, val); 3415 break; 3416 3417 case O_SASLMECH: 3418 if (AuthMechanisms != NULL) 3419 sm_free(AuthMechanisms); /* XXX */ 3420 if (*val != '\0') 3421 AuthMechanisms = newstr(val); 3422 else 3423 AuthMechanisms = NULL; 3424 break; 3425 3426 case O_SASLREALM: 3427 if (AuthRealm != NULL) 3428 sm_free(AuthRealm); 3429 if (*val != '\0') 3430 AuthRealm = newstr(val); 3431 else 3432 AuthRealm = NULL; 3433 break; 3434 3435 case O_SASLOPTS: 3436 while (val != NULL && *val != '\0') 3437 { 3438 switch (*val) 3439 { 3440 case 'A': 3441 SASLOpts |= SASL_AUTH_AUTH; 3442 break; 3443 3444 case 'a': 3445 SASLOpts |= SASL_SEC_NOACTIVE; 3446 break; 3447 3448 case 'c': 3449 SASLOpts |= SASL_SEC_PASS_CREDENTIALS; 3450 break; 3451 3452 case 'd': 3453 SASLOpts |= SASL_SEC_NODICTIONARY; 3454 break; 3455 3456 case 'f': 3457 SASLOpts |= SASL_SEC_FORWARD_SECRECY; 3458 break; 3459 3460 # if SASL >= 20101 3461 case 'm': 3462 SASLOpts |= SASL_SEC_MUTUAL_AUTH; 3463 break; 3464 # endif /* SASL >= 20101 */ 3465 3466 case 'p': 3467 SASLOpts |= SASL_SEC_NOPLAINTEXT; 3468 break; 3469 3470 case 'y': 3471 SASLOpts |= SASL_SEC_NOANONYMOUS; 3472 break; 3473 3474 case ' ': /* ignore */ 3475 case '\t': /* ignore */ 3476 case ',': /* ignore */ 3477 break; 3478 3479 default: 3480 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3481 "Warning: Option: %s unknown parameter '%c'\n", 3482 OPTNAME, 3483 (isascii(*val) && 3484 isprint(*val)) 3485 ? *val : '?'); 3486 break; 3487 } 3488 ++val; 3489 val = strpbrk(val, ", \t"); 3490 if (val != NULL) 3491 ++val; 3492 } 3493 break; 3494 3495 case O_SASLBITS: 3496 MaxSLBits = atoi(val); 3497 break; 3498 3499 #else /* SASL */ 3500 case O_SASLINFO: 3501 case O_SASLMECH: 3502 case O_SASLREALM: 3503 case O_SASLOPTS: 3504 case O_SASLBITS: 3505 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3506 "Warning: Option: %s requires SASL support (-DSASL)\n", 3507 OPTNAME); 3508 break; 3509 #endif /* SASL */ 3510 3511 #if STARTTLS 3512 case O_SRVCERTFILE: 3513 SET_STRING_EXP(SrvCertFile); 3514 case O_SRVKEYFILE: 3515 SET_STRING_EXP(SrvKeyFile); 3516 case O_CLTCERTFILE: 3517 SET_STRING_EXP(CltCertFile); 3518 case O_CLTKEYFILE: 3519 SET_STRING_EXP(CltKeyFile); 3520 case O_CACERTFILE: 3521 SET_STRING_EXP(CACertFile); 3522 case O_CACERTPATH: 3523 SET_STRING_EXP(CACertPath); 3524 case O_DHPARAMS: 3525 SET_STRING_EXP(DHParams); 3526 # if _FFR_TLS_1 3527 case O_DHPARAMS5: 3528 SET_STRING_EXP(DHParams5); 3529 case O_CIPHERLIST: 3530 SET_STRING_EXP(CipherList); 3531 # endif /* _FFR_TLS_1 */ 3532 case O_CRLFILE: 3533 # if OPENSSL_VERSION_NUMBER > 0x00907000L 3534 SET_STRING_EXP(CRLFile); 3535 # else /* OPENSSL_VERSION_NUMBER > 0x00907000L */ 3536 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3537 "Warning: Option: %s requires at least OpenSSL 0.9.7\n", 3538 OPTNAME); 3539 break; 3540 # endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ 3541 3542 # if _FFR_CRLPATH 3543 case O_CRLPATH: 3544 # if OPENSSL_VERSION_NUMBER > 0x00907000L 3545 SET_STRING_EXP(CRLPath); 3546 # else /* OPENSSL_VERSION_NUMBER > 0x00907000L */ 3547 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3548 "Warning: Option: %s requires at least OpenSSL 0.9.7\n", 3549 OPTNAME); 3550 break; 3551 # endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ 3552 # endif /* _FFR_CRLPATH */ 3553 3554 /* 3555 ** XXX How about options per daemon/client instead of globally? 3556 ** This doesn't work well for some options, e.g., no server cert, 3557 ** but fine for others. 3558 ** 3559 ** XXX Some people may want different certs per server. 3560 ** 3561 ** See also srvfeatures() 3562 */ 3563 3564 case O_TLS_SRV_OPTS: 3565 while (val != NULL && *val != '\0') 3566 { 3567 switch (*val) 3568 { 3569 case 'V': 3570 TLS_Srv_Opts |= TLS_I_NO_VRFY; 3571 break; 3572 # if _FFR_TLS_1 3573 /* 3574 ** Server without a cert? That works only if 3575 ** AnonDH is enabled as cipher, which is not in the 3576 ** default list. Hence the CipherList option must 3577 ** be available. Moreover: which clients support this 3578 ** besides sendmail with this setting? 3579 */ 3580 3581 case 'C': 3582 TLS_Srv_Opts &= ~TLS_I_SRV_CERT; 3583 break; 3584 # endif /* _FFR_TLS_1 */ 3585 case ' ': /* ignore */ 3586 case '\t': /* ignore */ 3587 case ',': /* ignore */ 3588 break; 3589 default: 3590 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3591 "Warning: Option: %s unknown parameter '%c'\n", 3592 OPTNAME, 3593 (isascii(*val) && 3594 isprint(*val)) 3595 ? *val : '?'); 3596 break; 3597 } 3598 ++val; 3599 val = strpbrk(val, ", \t"); 3600 if (val != NULL) 3601 ++val; 3602 } 3603 break; 3604 3605 case O_RANDFILE: 3606 PSTRSET(RandFile, val); 3607 break; 3608 3609 #else /* STARTTLS */ 3610 case O_SRVCERTFILE: 3611 case O_SRVKEYFILE: 3612 case O_CLTCERTFILE: 3613 case O_CLTKEYFILE: 3614 case O_CACERTFILE: 3615 case O_CACERTPATH: 3616 case O_DHPARAMS: 3617 # if _FFR_TLS_1 3618 case O_DHPARAMS5: 3619 case O_CIPHERLIST: 3620 # endif /* _FFR_TLS_1 */ 3621 case O_CRLFILE: 3622 # if _FFR_CRLPATH 3623 case O_CRLPATH: 3624 # endif /* _FFR_CRLPATH */ 3625 case O_RANDFILE: 3626 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3627 "Warning: Option: %s requires TLS support\n", 3628 OPTNAME); 3629 break; 3630 3631 #endif /* STARTTLS */ 3632 3633 case O_CLIENTPORT: 3634 setclientoptions(val); 3635 break; 3636 3637 case O_DF_BUFSIZE: 3638 DataFileBufferSize = atoi(val); 3639 break; 3640 3641 case O_XF_BUFSIZE: 3642 XscriptFileBufferSize = atoi(val); 3643 break; 3644 3645 case O_LDAPDEFAULTSPEC: 3646 #if LDAPMAP 3647 ldapmap_set_defaults(val); 3648 #else /* LDAPMAP */ 3649 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3650 "Warning: Option: %s requires LDAP support (-DLDAPMAP)\n", 3651 OPTNAME); 3652 #endif /* LDAPMAP */ 3653 break; 3654 3655 case O_INPUTMILTER: 3656 #if MILTER 3657 InputFilterList = newstr(val); 3658 #else /* MILTER */ 3659 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3660 "Warning: Option: %s requires Milter support (-DMILTER)\n", 3661 OPTNAME); 3662 #endif /* MILTER */ 3663 break; 3664 3665 case O_MILTER: 3666 #if MILTER 3667 milter_set_option(subopt, val, sticky); 3668 #else /* MILTER */ 3669 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3670 "Warning: Option: %s requires Milter support (-DMILTER)\n", 3671 OPTNAME); 3672 #endif /* MILTER */ 3673 break; 3674 3675 case O_QUEUE_FILE_MODE: /* queue file mode */ 3676 QueueFileMode = atooct(val) & 0777; 3677 break; 3678 3679 case O_DLVR_MIN: /* deliver by minimum time */ 3680 DeliverByMin = convtime(val, 's'); 3681 break; 3682 3683 /* modifiers {daemon_flags} for direct submissions */ 3684 case O_DIRECTSUBMODIFIERS: 3685 { 3686 BITMAP256 m; /* ignored */ 3687 extern ENVELOPE BlankEnvelope; 3688 3689 macdefine(&BlankEnvelope.e_macro, A_PERM, 3690 macid("{daemon_flags}"), 3691 getmodifiers(val, m)); 3692 } 3693 break; 3694 3695 case O_FASTSPLIT: 3696 FastSplit = atoi(val); 3697 break; 3698 3699 case O_MBDB: 3700 Mbdb = newstr(val); 3701 break; 3702 3703 case O_MSQ: 3704 UseMSP = atobool(val); 3705 break; 3706 3707 #if _FFR_SOFT_BOUNCE 3708 case O_SOFTBOUNCE: 3709 SoftBounce = atobool(val); 3710 break; 3711 #endif /* _FFR_SOFT_BOUNCE */ 3712 3713 case O_REJECTLOGINTERVAL: /* time btwn log msgs while refusing */ 3714 RejectLogInterval = convtime(val, 'h'); 3715 break; 3716 3717 case O_REQUIRES_DIR_FSYNC: 3718 #if REQUIRES_DIR_FSYNC 3719 RequiresDirfsync = atobool(val); 3720 #else /* REQUIRES_DIR_FSYNC */ 3721 /* silently ignored... required for cf file option */ 3722 #endif /* REQUIRES_DIR_FSYNC */ 3723 break; 3724 3725 case O_CONNECTION_RATE_WINDOW_SIZE: 3726 ConnectionRateWindowSize = convtime(val, 's'); 3727 break; 3728 3729 case O_FALLBACKSMARTHOST: /* fallback smart host */ 3730 if (val[0] != '\0') 3731 FallbackSmartHost = newstr(val); 3732 break; 3733 3734 #if _FFR_HELONAME 3735 case O_HELONAME: 3736 HeloName = newstr(val); 3737 break; 3738 #endif /* _FFR_HELONAME */ 3739 #if _FFR_MEMSTAT 3740 case O_REFUSELOWMEM: 3741 RefuseLowMem = atoi(val); 3742 break; 3743 case O_QUEUELOWMEM: 3744 QueueLowMem = atoi(val); 3745 break; 3746 case O_MEMRESOURCE: 3747 MemoryResource = newstr(val); 3748 break; 3749 #endif /* _FFR_MEMSTAT */ 3750 3751 #if _FFR_MAXNOOPCOMMANDS 3752 case O_MAXNOOPCOMMANDS: 3753 MaxNOOPCommands = atoi(val); 3754 break; 3755 #endif /* _FFR_MAXNOOPCOMMANDS */ 3756 3757 #if _FFR_MSG_ACCEPT 3758 case O_MSG_ACCEPT: 3759 MessageAccept = newstr(val); 3760 break; 3761 #endif /* _FFR_MSG_ACCEPT */ 3762 3763 #if _FFR_QUEUE_RUN_PARANOIA 3764 case O_CHK_Q_RUNNERS: 3765 CheckQueueRunners = atoi(val); 3766 break; 3767 #endif /* _FFR_QUEUE_RUN_PARANOIA */ 3768 3769 default: 3770 if (tTd(37, 1)) 3771 { 3772 if (isascii(opt) && isprint(opt)) 3773 sm_dprintf("Warning: option %c unknown\n", opt); 3774 else 3775 sm_dprintf("Warning: option 0x%x unknown\n", opt); 3776 } 3777 break; 3778 } 3779 3780 /* 3781 ** Options with suboptions are responsible for taking care 3782 ** of sticky-ness (e.g., that a command line setting is kept 3783 ** when reading in the sendmail.cf file). This has to be done 3784 ** when the suboptions are parsed since each suboption must be 3785 ** sticky, not the root option. 3786 */ 3787 3788 if (sticky && !bitset(OI_SUBOPT, o->o_flags)) 3789 setbitn(opt, StickyOpt); 3790 } 3791 /* 3792 ** SETCLASS -- set a string into a class 3793 ** 3794 ** Parameters: 3795 ** class -- the class to put the string in. 3796 ** str -- the string to enter 3797 ** 3798 ** Returns: 3799 ** none. 3800 ** 3801 ** Side Effects: 3802 ** puts the word into the symbol table. 3803 */ 3804 3805 void 3806 setclass(class, str) 3807 int class; 3808 char *str; 3809 { 3810 register STAB *s; 3811 3812 if ((*str & 0377) == MATCHCLASS) 3813 { 3814 int mid; 3815 3816 str++; 3817 mid = macid(str); 3818 if (mid == 0) 3819 return; 3820 3821 if (tTd(37, 8)) 3822 sm_dprintf("setclass(%s, $=%s)\n", 3823 macname(class), macname(mid)); 3824 copy_class(mid, class); 3825 } 3826 else 3827 { 3828 if (tTd(37, 8)) 3829 sm_dprintf("setclass(%s, %s)\n", macname(class), str); 3830 3831 s = stab(str, ST_CLASS, ST_ENTER); 3832 setbitn(bitidx(class), s->s_class); 3833 } 3834 } 3835 /* 3836 ** MAKEMAPENTRY -- create a map entry 3837 ** 3838 ** Parameters: 3839 ** line -- the config file line 3840 ** 3841 ** Returns: 3842 ** A pointer to the map that has been created. 3843 ** NULL if there was a syntax error. 3844 ** 3845 ** Side Effects: 3846 ** Enters the map into the dictionary. 3847 */ 3848 3849 MAP * 3850 makemapentry(line) 3851 char *line; 3852 { 3853 register char *p; 3854 char *mapname; 3855 char *classname; 3856 register STAB *s; 3857 STAB *class; 3858 3859 for (p = line; isascii(*p) && isspace(*p); p++) 3860 continue; 3861 if (!(isascii(*p) && isalnum(*p))) 3862 { 3863 syserr("readcf: config K line: no map name"); 3864 return NULL; 3865 } 3866 3867 mapname = p; 3868 while ((isascii(*++p) && isalnum(*p)) || *p == '_' || *p == '.') 3869 continue; 3870 if (*p != '\0') 3871 *p++ = '\0'; 3872 while (isascii(*p) && isspace(*p)) 3873 p++; 3874 if (!(isascii(*p) && isalnum(*p))) 3875 { 3876 syserr("readcf: config K line, map %s: no map class", mapname); 3877 return NULL; 3878 } 3879 classname = p; 3880 while (isascii(*++p) && isalnum(*p)) 3881 continue; 3882 if (*p != '\0') 3883 *p++ = '\0'; 3884 while (isascii(*p) && isspace(*p)) 3885 p++; 3886 3887 /* look up the class */ 3888 class = stab(classname, ST_MAPCLASS, ST_FIND); 3889 if (class == NULL) 3890 { 3891 syserr("readcf: map %s: class %s not available", mapname, 3892 classname); 3893 return NULL; 3894 } 3895 3896 /* enter the map */ 3897 s = stab(mapname, ST_MAP, ST_ENTER); 3898 s->s_map.map_class = &class->s_mapclass; 3899 s->s_map.map_mname = newstr(mapname); 3900 3901 if (class->s_mapclass.map_parse(&s->s_map, p)) 3902 s->s_map.map_mflags |= MF_VALID; 3903 3904 if (tTd(37, 5)) 3905 { 3906 sm_dprintf("map %s, class %s, flags %lx, file %s,\n", 3907 s->s_map.map_mname, s->s_map.map_class->map_cname, 3908 s->s_map.map_mflags, s->s_map.map_file); 3909 sm_dprintf("\tapp %s, domain %s, rebuild %s\n", 3910 s->s_map.map_app, s->s_map.map_domain, 3911 s->s_map.map_rebuild); 3912 } 3913 return &s->s_map; 3914 } 3915 /* 3916 ** STRTORWSET -- convert string to rewriting set number 3917 ** 3918 ** Parameters: 3919 ** p -- the pointer to the string to decode. 3920 ** endp -- if set, store the trailing delimiter here. 3921 ** stabmode -- ST_ENTER to create this entry, ST_FIND if 3922 ** it must already exist. 3923 ** 3924 ** Returns: 3925 ** The appropriate ruleset number. 3926 ** -1 if it is not valid (error already printed) 3927 */ 3928 3929 int 3930 strtorwset(p, endp, stabmode) 3931 char *p; 3932 char **endp; 3933 int stabmode; 3934 { 3935 int ruleset; 3936 static int nextruleset = MAXRWSETS; 3937 3938 while (isascii(*p) && isspace(*p)) 3939 p++; 3940 if (!isascii(*p)) 3941 { 3942 syserr("invalid ruleset name: \"%.20s\"", p); 3943 return -1; 3944 } 3945 if (isdigit(*p)) 3946 { 3947 ruleset = strtol(p, endp, 10); 3948 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 3949 { 3950 syserr("bad ruleset %d (%d max)", 3951 ruleset, MAXRWSETS / 2); 3952 ruleset = -1; 3953 } 3954 } 3955 else 3956 { 3957 STAB *s; 3958 char delim; 3959 char *q = NULL; 3960 3961 q = p; 3962 while (*p != '\0' && isascii(*p) && 3963 (isalnum(*p) || *p == '_')) 3964 p++; 3965 if (q == p || !(isascii(*q) && isalpha(*q))) 3966 { 3967 /* no valid characters */ 3968 syserr("invalid ruleset name: \"%.20s\"", q); 3969 return -1; 3970 } 3971 while (isascii(*p) && isspace(*p)) 3972 *p++ = '\0'; 3973 delim = *p; 3974 if (delim != '\0') 3975 *p = '\0'; 3976 s = stab(q, ST_RULESET, stabmode); 3977 if (delim != '\0') 3978 *p = delim; 3979 3980 if (s == NULL) 3981 return -1; 3982 3983 if (stabmode == ST_ENTER && delim == '=') 3984 { 3985 while (isascii(*++p) && isspace(*p)) 3986 continue; 3987 if (!(isascii(*p) && isdigit(*p))) 3988 { 3989 syserr("bad ruleset definition \"%s\" (number required after `=')", q); 3990 ruleset = -1; 3991 } 3992 else 3993 { 3994 ruleset = strtol(p, endp, 10); 3995 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 3996 { 3997 syserr("bad ruleset number %d in \"%s\" (%d max)", 3998 ruleset, q, MAXRWSETS / 2); 3999 ruleset = -1; 4000 } 4001 } 4002 } 4003 else 4004 { 4005 if (endp != NULL) 4006 *endp = p; 4007 if (s->s_ruleset >= 0) 4008 ruleset = s->s_ruleset; 4009 else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 4010 { 4011 syserr("%s: too many named rulesets (%d max)", 4012 q, MAXRWSETS / 2); 4013 ruleset = -1; 4014 } 4015 } 4016 if (s->s_ruleset >= 0 && 4017 ruleset >= 0 && 4018 ruleset != s->s_ruleset) 4019 { 4020 syserr("%s: ruleset changed value (old %d, new %d)", 4021 q, s->s_ruleset, ruleset); 4022 ruleset = s->s_ruleset; 4023 } 4024 else if (ruleset >= 0) 4025 { 4026 s->s_ruleset = ruleset; 4027 } 4028 if (stabmode == ST_ENTER && ruleset >= 0) 4029 { 4030 char *h = NULL; 4031 4032 if (RuleSetNames[ruleset] != NULL) 4033 sm_free(RuleSetNames[ruleset]); /* XXX */ 4034 if (delim != '\0' && (h = strchr(q, delim)) != NULL) 4035 *h = '\0'; 4036 RuleSetNames[ruleset] = newstr(q); 4037 if (delim == '/' && h != NULL) 4038 *h = delim; /* put back delim */ 4039 } 4040 } 4041 return ruleset; 4042 } 4043 /* 4044 ** SETTIMEOUT -- set an individual timeout 4045 ** 4046 ** Parameters: 4047 ** name -- the name of the timeout. 4048 ** val -- the value of the timeout. 4049 ** sticky -- if set, don't let other setoptions override 4050 ** this value. 4051 ** 4052 ** Returns: 4053 ** none. 4054 */ 4055 4056 /* set if Timeout sub-option is stuck */ 4057 static BITMAP256 StickyTimeoutOpt; 4058 4059 static struct timeoutinfo 4060 { 4061 char *to_name; /* long name of timeout */ 4062 unsigned char to_code; /* code for option */ 4063 } TimeOutTab[] = 4064 { 4065 #define TO_INITIAL 0x01 4066 { "initial", TO_INITIAL }, 4067 #define TO_MAIL 0x02 4068 { "mail", TO_MAIL }, 4069 #define TO_RCPT 0x03 4070 { "rcpt", TO_RCPT }, 4071 #define TO_DATAINIT 0x04 4072 { "datainit", TO_DATAINIT }, 4073 #define TO_DATABLOCK 0x05 4074 { "datablock", TO_DATABLOCK }, 4075 #define TO_DATAFINAL 0x06 4076 { "datafinal", TO_DATAFINAL }, 4077 #define TO_COMMAND 0x07 4078 { "command", TO_COMMAND }, 4079 #define TO_RSET 0x08 4080 { "rset", TO_RSET }, 4081 #define TO_HELO 0x09 4082 { "helo", TO_HELO }, 4083 #define TO_QUIT 0x0A 4084 { "quit", TO_QUIT }, 4085 #define TO_MISC 0x0B 4086 { "misc", TO_MISC }, 4087 #define TO_IDENT 0x0C 4088 { "ident", TO_IDENT }, 4089 #define TO_FILEOPEN 0x0D 4090 { "fileopen", TO_FILEOPEN }, 4091 #define TO_CONNECT 0x0E 4092 { "connect", TO_CONNECT }, 4093 #define TO_ICONNECT 0x0F 4094 { "iconnect", TO_ICONNECT }, 4095 #define TO_QUEUEWARN 0x10 4096 { "queuewarn", TO_QUEUEWARN }, 4097 { "queuewarn.*", TO_QUEUEWARN }, 4098 #define TO_QUEUEWARN_NORMAL 0x11 4099 { "queuewarn.normal", TO_QUEUEWARN_NORMAL }, 4100 #define TO_QUEUEWARN_URGENT 0x12 4101 { "queuewarn.urgent", TO_QUEUEWARN_URGENT }, 4102 #define TO_QUEUEWARN_NON_URGENT 0x13 4103 { "queuewarn.non-urgent", TO_QUEUEWARN_NON_URGENT }, 4104 #define TO_QUEUERETURN 0x14 4105 { "queuereturn", TO_QUEUERETURN }, 4106 { "queuereturn.*", TO_QUEUERETURN }, 4107 #define TO_QUEUERETURN_NORMAL 0x15 4108 { "queuereturn.normal", TO_QUEUERETURN_NORMAL }, 4109 #define TO_QUEUERETURN_URGENT 0x16 4110 { "queuereturn.urgent", TO_QUEUERETURN_URGENT }, 4111 #define TO_QUEUERETURN_NON_URGENT 0x17 4112 { "queuereturn.non-urgent", TO_QUEUERETURN_NON_URGENT }, 4113 #define TO_HOSTSTATUS 0x18 4114 { "hoststatus", TO_HOSTSTATUS }, 4115 #define TO_RESOLVER_RETRANS 0x19 4116 { "resolver.retrans", TO_RESOLVER_RETRANS }, 4117 #define TO_RESOLVER_RETRANS_NORMAL 0x1A 4118 { "resolver.retrans.normal", TO_RESOLVER_RETRANS_NORMAL }, 4119 #define TO_RESOLVER_RETRANS_FIRST 0x1B 4120 { "resolver.retrans.first", TO_RESOLVER_RETRANS_FIRST }, 4121 #define TO_RESOLVER_RETRY 0x1C 4122 { "resolver.retry", TO_RESOLVER_RETRY }, 4123 #define TO_RESOLVER_RETRY_NORMAL 0x1D 4124 { "resolver.retry.normal", TO_RESOLVER_RETRY_NORMAL }, 4125 #define TO_RESOLVER_RETRY_FIRST 0x1E 4126 { "resolver.retry.first", TO_RESOLVER_RETRY_FIRST }, 4127 #define TO_CONTROL 0x1F 4128 { "control", TO_CONTROL }, 4129 #define TO_LHLO 0x20 4130 { "lhlo", TO_LHLO }, 4131 #define TO_AUTH 0x21 4132 { "auth", TO_AUTH }, 4133 #define TO_STARTTLS 0x22 4134 { "starttls", TO_STARTTLS }, 4135 #define TO_ACONNECT 0x23 4136 { "aconnect", TO_ACONNECT }, 4137 #define TO_QUEUEWARN_DSN 0x24 4138 { "queuewarn.dsn", TO_QUEUEWARN_DSN }, 4139 #define TO_QUEUERETURN_DSN 0x25 4140 { "queuereturn.dsn", TO_QUEUERETURN_DSN }, 4141 { NULL, 0 }, 4142 }; 4143 4144 4145 static void 4146 settimeout(name, val, sticky) 4147 char *name; 4148 char *val; 4149 bool sticky; 4150 { 4151 register struct timeoutinfo *to; 4152 int i, addopts; 4153 time_t toval; 4154 4155 if (tTd(37, 2)) 4156 sm_dprintf("settimeout(%s = %s)", name, val); 4157 4158 for (to = TimeOutTab; to->to_name != NULL; to++) 4159 { 4160 if (sm_strcasecmp(to->to_name, name) == 0) 4161 break; 4162 } 4163 4164 if (to->to_name == NULL) 4165 { 4166 errno = 0; /* avoid bogus error text */ 4167 syserr("settimeout: invalid timeout %s", name); 4168 return; 4169 } 4170 4171 /* 4172 ** See if this option is preset for us. 4173 */ 4174 4175 if (!sticky && bitnset(to->to_code, StickyTimeoutOpt)) 4176 { 4177 if (tTd(37, 2)) 4178 sm_dprintf(" (ignored)\n"); 4179 return; 4180 } 4181 4182 if (tTd(37, 2)) 4183 sm_dprintf("\n"); 4184 4185 toval = convtime(val, 'm'); 4186 addopts = 0; 4187 4188 switch (to->to_code) 4189 { 4190 case TO_INITIAL: 4191 TimeOuts.to_initial = toval; 4192 break; 4193 4194 case TO_MAIL: 4195 TimeOuts.to_mail = toval; 4196 break; 4197 4198 case TO_RCPT: 4199 TimeOuts.to_rcpt = toval; 4200 break; 4201 4202 case TO_DATAINIT: 4203 TimeOuts.to_datainit = toval; 4204 break; 4205 4206 case TO_DATABLOCK: 4207 TimeOuts.to_datablock = toval; 4208 break; 4209 4210 case TO_DATAFINAL: 4211 TimeOuts.to_datafinal = toval; 4212 break; 4213 4214 case TO_COMMAND: 4215 TimeOuts.to_nextcommand = toval; 4216 break; 4217 4218 case TO_RSET: 4219 TimeOuts.to_rset = toval; 4220 break; 4221 4222 case TO_HELO: 4223 TimeOuts.to_helo = toval; 4224 break; 4225 4226 case TO_QUIT: 4227 TimeOuts.to_quit = toval; 4228 break; 4229 4230 case TO_MISC: 4231 TimeOuts.to_miscshort = toval; 4232 break; 4233 4234 case TO_IDENT: 4235 TimeOuts.to_ident = toval; 4236 break; 4237 4238 case TO_FILEOPEN: 4239 TimeOuts.to_fileopen = toval; 4240 break; 4241 4242 case TO_CONNECT: 4243 TimeOuts.to_connect = toval; 4244 break; 4245 4246 case TO_ICONNECT: 4247 TimeOuts.to_iconnect = toval; 4248 break; 4249 4250 case TO_ACONNECT: 4251 TimeOuts.to_aconnect = toval; 4252 break; 4253 4254 case TO_QUEUEWARN: 4255 toval = convtime(val, 'h'); 4256 TimeOuts.to_q_warning[TOC_NORMAL] = toval; 4257 TimeOuts.to_q_warning[TOC_URGENT] = toval; 4258 TimeOuts.to_q_warning[TOC_NONURGENT] = toval; 4259 TimeOuts.to_q_warning[TOC_DSN] = toval; 4260 addopts = 2; 4261 break; 4262 4263 case TO_QUEUEWARN_NORMAL: 4264 toval = convtime(val, 'h'); 4265 TimeOuts.to_q_warning[TOC_NORMAL] = toval; 4266 break; 4267 4268 case TO_QUEUEWARN_URGENT: 4269 toval = convtime(val, 'h'); 4270 TimeOuts.to_q_warning[TOC_URGENT] = toval; 4271 break; 4272 4273 case TO_QUEUEWARN_NON_URGENT: 4274 toval = convtime(val, 'h'); 4275 TimeOuts.to_q_warning[TOC_NONURGENT] = toval; 4276 break; 4277 4278 case TO_QUEUEWARN_DSN: 4279 toval = convtime(val, 'h'); 4280 TimeOuts.to_q_warning[TOC_DSN] = toval; 4281 break; 4282 4283 case TO_QUEUERETURN: 4284 toval = convtime(val, 'd'); 4285 TimeOuts.to_q_return[TOC_NORMAL] = toval; 4286 TimeOuts.to_q_return[TOC_URGENT] = toval; 4287 TimeOuts.to_q_return[TOC_NONURGENT] = toval; 4288 TimeOuts.to_q_return[TOC_DSN] = toval; 4289 addopts = 2; 4290 break; 4291 4292 case TO_QUEUERETURN_NORMAL: 4293 toval = convtime(val, 'd'); 4294 TimeOuts.to_q_return[TOC_NORMAL] = toval; 4295 break; 4296 4297 case TO_QUEUERETURN_URGENT: 4298 toval = convtime(val, 'd'); 4299 TimeOuts.to_q_return[TOC_URGENT] = toval; 4300 break; 4301 4302 case TO_QUEUERETURN_NON_URGENT: 4303 toval = convtime(val, 'd'); 4304 TimeOuts.to_q_return[TOC_NONURGENT] = toval; 4305 break; 4306 4307 case TO_QUEUERETURN_DSN: 4308 toval = convtime(val, 'd'); 4309 TimeOuts.to_q_return[TOC_DSN] = toval; 4310 break; 4311 4312 case TO_HOSTSTATUS: 4313 MciInfoTimeout = toval; 4314 break; 4315 4316 case TO_RESOLVER_RETRANS: 4317 toval = convtime(val, 's'); 4318 TimeOuts.res_retrans[RES_TO_DEFAULT] = toval; 4319 TimeOuts.res_retrans[RES_TO_FIRST] = toval; 4320 TimeOuts.res_retrans[RES_TO_NORMAL] = toval; 4321 addopts = 2; 4322 break; 4323 4324 case TO_RESOLVER_RETRY: 4325 i = atoi(val); 4326 TimeOuts.res_retry[RES_TO_DEFAULT] = i; 4327 TimeOuts.res_retry[RES_TO_FIRST] = i; 4328 TimeOuts.res_retry[RES_TO_NORMAL] = i; 4329 addopts = 2; 4330 break; 4331 4332 case TO_RESOLVER_RETRANS_NORMAL: 4333 TimeOuts.res_retrans[RES_TO_NORMAL] = convtime(val, 's'); 4334 break; 4335 4336 case TO_RESOLVER_RETRY_NORMAL: 4337 TimeOuts.res_retry[RES_TO_NORMAL] = atoi(val); 4338 break; 4339 4340 case TO_RESOLVER_RETRANS_FIRST: 4341 TimeOuts.res_retrans[RES_TO_FIRST] = convtime(val, 's'); 4342 break; 4343 4344 case TO_RESOLVER_RETRY_FIRST: 4345 TimeOuts.res_retry[RES_TO_FIRST] = atoi(val); 4346 break; 4347 4348 case TO_CONTROL: 4349 TimeOuts.to_control = toval; 4350 break; 4351 4352 case TO_LHLO: 4353 TimeOuts.to_lhlo = toval; 4354 break; 4355 4356 #if SASL 4357 case TO_AUTH: 4358 TimeOuts.to_auth = toval; 4359 break; 4360 #endif /* SASL */ 4361 4362 #if STARTTLS 4363 case TO_STARTTLS: 4364 TimeOuts.to_starttls = toval; 4365 break; 4366 #endif /* STARTTLS */ 4367 4368 default: 4369 syserr("settimeout: invalid timeout %s", name); 4370 break; 4371 } 4372 4373 if (sticky) 4374 { 4375 for (i = 0; i <= addopts; i++) 4376 setbitn(to->to_code + i, StickyTimeoutOpt); 4377 } 4378 } 4379 /* 4380 ** INITTIMEOUTS -- parse and set timeout values 4381 ** 4382 ** Parameters: 4383 ** val -- a pointer to the values. If NULL, do initial 4384 ** settings. 4385 ** sticky -- if set, don't let other setoptions override 4386 ** this suboption value. 4387 ** 4388 ** Returns: 4389 ** none. 4390 ** 4391 ** Side Effects: 4392 ** Initializes the TimeOuts structure 4393 */ 4394 4395 void 4396 inittimeouts(val, sticky) 4397 register char *val; 4398 bool sticky; 4399 { 4400 register char *p; 4401 4402 if (tTd(37, 2)) 4403 sm_dprintf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val); 4404 if (val == NULL) 4405 { 4406 TimeOuts.to_connect = (time_t) 0 SECONDS; 4407 TimeOuts.to_aconnect = (time_t) 0 SECONDS; 4408 TimeOuts.to_iconnect = (time_t) 0 SECONDS; 4409 TimeOuts.to_initial = (time_t) 5 MINUTES; 4410 TimeOuts.to_helo = (time_t) 5 MINUTES; 4411 TimeOuts.to_mail = (time_t) 10 MINUTES; 4412 TimeOuts.to_rcpt = (time_t) 1 HOUR; 4413 TimeOuts.to_datainit = (time_t) 5 MINUTES; 4414 TimeOuts.to_datablock = (time_t) 1 HOUR; 4415 TimeOuts.to_datafinal = (time_t) 1 HOUR; 4416 TimeOuts.to_rset = (time_t) 5 MINUTES; 4417 TimeOuts.to_quit = (time_t) 2 MINUTES; 4418 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 4419 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 4420 #if IDENTPROTO 4421 TimeOuts.to_ident = (time_t) 5 SECONDS; 4422 #else /* IDENTPROTO */ 4423 TimeOuts.to_ident = (time_t) 0 SECONDS; 4424 #endif /* IDENTPROTO */ 4425 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 4426 TimeOuts.to_control = (time_t) 2 MINUTES; 4427 TimeOuts.to_lhlo = (time_t) 2 MINUTES; 4428 #if SASL 4429 TimeOuts.to_auth = (time_t) 10 MINUTES; 4430 #endif /* SASL */ 4431 #if STARTTLS 4432 TimeOuts.to_starttls = (time_t) 1 HOUR; 4433 #endif /* STARTTLS */ 4434 if (tTd(37, 5)) 4435 { 4436 sm_dprintf("Timeouts:\n"); 4437 sm_dprintf(" connect = %ld\n", 4438 (long) TimeOuts.to_connect); 4439 sm_dprintf(" aconnect = %ld\n", 4440 (long) TimeOuts.to_aconnect); 4441 sm_dprintf(" initial = %ld\n", 4442 (long) TimeOuts.to_initial); 4443 sm_dprintf(" helo = %ld\n", (long) TimeOuts.to_helo); 4444 sm_dprintf(" mail = %ld\n", (long) TimeOuts.to_mail); 4445 sm_dprintf(" rcpt = %ld\n", (long) TimeOuts.to_rcpt); 4446 sm_dprintf(" datainit = %ld\n", 4447 (long) TimeOuts.to_datainit); 4448 sm_dprintf(" datablock = %ld\n", 4449 (long) TimeOuts.to_datablock); 4450 sm_dprintf(" datafinal = %ld\n", 4451 (long) TimeOuts.to_datafinal); 4452 sm_dprintf(" rset = %ld\n", (long) TimeOuts.to_rset); 4453 sm_dprintf(" quit = %ld\n", (long) TimeOuts.to_quit); 4454 sm_dprintf(" nextcommand = %ld\n", 4455 (long) TimeOuts.to_nextcommand); 4456 sm_dprintf(" miscshort = %ld\n", 4457 (long) TimeOuts.to_miscshort); 4458 sm_dprintf(" ident = %ld\n", (long) TimeOuts.to_ident); 4459 sm_dprintf(" fileopen = %ld\n", 4460 (long) TimeOuts.to_fileopen); 4461 sm_dprintf(" lhlo = %ld\n", 4462 (long) TimeOuts.to_lhlo); 4463 sm_dprintf(" control = %ld\n", 4464 (long) TimeOuts.to_control); 4465 } 4466 return; 4467 } 4468 4469 for (;; val = p) 4470 { 4471 while (isascii(*val) && isspace(*val)) 4472 val++; 4473 if (*val == '\0') 4474 break; 4475 for (p = val; *p != '\0' && *p != ','; p++) 4476 continue; 4477 if (*p != '\0') 4478 *p++ = '\0'; 4479 4480 if (isascii(*val) && isdigit(*val)) 4481 { 4482 /* old syntax -- set everything */ 4483 TimeOuts.to_mail = convtime(val, 'm'); 4484 TimeOuts.to_rcpt = TimeOuts.to_mail; 4485 TimeOuts.to_datainit = TimeOuts.to_mail; 4486 TimeOuts.to_datablock = TimeOuts.to_mail; 4487 TimeOuts.to_datafinal = TimeOuts.to_mail; 4488 TimeOuts.to_nextcommand = TimeOuts.to_mail; 4489 if (sticky) 4490 { 4491 setbitn(TO_MAIL, StickyTimeoutOpt); 4492 setbitn(TO_RCPT, StickyTimeoutOpt); 4493 setbitn(TO_DATAINIT, StickyTimeoutOpt); 4494 setbitn(TO_DATABLOCK, StickyTimeoutOpt); 4495 setbitn(TO_DATAFINAL, StickyTimeoutOpt); 4496 setbitn(TO_COMMAND, StickyTimeoutOpt); 4497 } 4498 continue; 4499 } 4500 else 4501 { 4502 register char *q = strchr(val, ':'); 4503 4504 if (q == NULL && (q = strchr(val, '=')) == NULL) 4505 { 4506 /* syntax error */ 4507 continue; 4508 } 4509 *q++ = '\0'; 4510 settimeout(val, q, sticky); 4511 } 4512 } 4513 } 4514