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