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