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