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