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