1 /* 2 * Copyright (c) 1998-2001 Sendmail, 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 #ifndef lint 15 static char id[] = "@(#)$Id: readcf.c,v 8.382.4.40 2001/05/03 17:24:13 gshapiro Exp $"; 16 #endif /* ! lint */ 17 18 #include <sendmail.h> 19 20 21 #if NETINET || NETINET6 22 # include <arpa/inet.h> 23 #endif /* NETINET || NETINET6 */ 24 25 #define SECONDS 26 #define MINUTES * 60 27 #define HOUR * 3600 28 #define HOURS HOUR 29 30 static void fileclass __P((int, char *, char *, bool, bool)); 31 static char **makeargv __P((char *)); 32 static void settimeout __P((char *, char *, bool)); 33 static void toomany __P((int, int)); 34 35 /* 36 ** READCF -- read configuration file. 37 ** 38 ** This routine reads the configuration file and builds the internal 39 ** form. 40 ** 41 ** The file is formatted as a sequence of lines, each taken 42 ** atomically. The first character of each line describes how 43 ** the line is to be interpreted. The lines are: 44 ** Dxval Define macro x to have value val. 45 ** Cxword Put word into class x. 46 ** Fxfile [fmt] Read file for lines to put into 47 ** class x. Use scanf string 'fmt' 48 ** or "%s" if not present. Fmt should 49 ** only produce one string-valued result. 50 ** Hname: value Define header with field-name 'name' 51 ** and value as specified; this will be 52 ** macro expanded immediately before 53 ** use. 54 ** Sn Use rewriting set n. 55 ** Rlhs rhs Rewrite addresses that match lhs to 56 ** be rhs. 57 ** Mn arg=val... Define mailer. n is the internal name. 58 ** Args specify mailer parameters. 59 ** Oxvalue Set option x to value. 60 ** Pname=value Set precedence name to value. 61 ** Vversioncode[/vendorcode] 62 ** Version level/vendor name of 63 ** configuration syntax. 64 ** Kmapname mapclass arguments.... 65 ** Define keyed lookup of a given class. 66 ** Arguments are class dependent. 67 ** Eenvar=value Set the environment value to the given value. 68 ** 69 ** Parameters: 70 ** cfname -- configuration file name. 71 ** safe -- TRUE if this is the system config file; 72 ** FALSE otherwise. 73 ** e -- the main envelope. 74 ** 75 ** Returns: 76 ** none. 77 ** 78 ** Side Effects: 79 ** Builds several internal tables. 80 */ 81 82 void 83 readcf(cfname, safe, e) 84 char *cfname; 85 bool safe; 86 register ENVELOPE *e; 87 { 88 FILE *cf; 89 int ruleset = -1; 90 char *q; 91 struct rewrite *rwp = NULL; 92 char *bp; 93 auto char *ep; 94 int nfuzzy; 95 char *file; 96 bool optional; 97 int mid; 98 register char *p; 99 long sff = SFF_OPENASROOT; 100 struct stat statb; 101 char buf[MAXLINE]; 102 char exbuf[MAXLINE]; 103 char pvpbuf[MAXLINE + MAXATOM]; 104 static char *null_list[1] = { NULL }; 105 extern u_char TokTypeNoC[]; 106 107 FileName = cfname; 108 LineNumber = 0; 109 110 if (DontLockReadFiles) 111 sff |= SFF_NOLOCK; 112 cf = safefopen(cfname, O_RDONLY, 0444, sff); 113 if (cf == NULL) 114 { 115 syserr("cannot open"); 116 finis(FALSE, EX_OSFILE); 117 } 118 119 if (fstat(fileno(cf), &statb) < 0) 120 { 121 syserr("cannot fstat"); 122 finis(FALSE, EX_OSFILE); 123 } 124 125 if (!S_ISREG(statb.st_mode)) 126 { 127 syserr("not a plain file"); 128 finis(FALSE, EX_OSFILE); 129 } 130 131 if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 132 { 133 if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS) 134 fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 135 FileName); 136 if (LogLevel > 0) 137 sm_syslog(LOG_CRIT, NOQID, 138 "%s: WARNING: dangerous write permissions", 139 FileName); 140 } 141 142 #ifdef XLA 143 xla_zero(); 144 #endif /* XLA */ 145 146 while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 147 { 148 if (bp[0] == '#') 149 { 150 if (bp != buf) 151 sm_free(bp); 152 continue; 153 } 154 155 /* do macro expansion mappings */ 156 translate_dollars(bp); 157 158 /* interpret this line */ 159 errno = 0; 160 switch (bp[0]) 161 { 162 case '\0': 163 case '#': /* comment */ 164 break; 165 166 case 'R': /* rewriting rule */ 167 if (ruleset < 0) 168 { 169 syserr("missing valid ruleset for \"%s\"", bp); 170 break; 171 } 172 for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 173 continue; 174 175 if (*p == '\0') 176 { 177 syserr("invalid rewrite line \"%s\" (tab expected)", bp); 178 break; 179 } 180 181 /* allocate space for the rule header */ 182 if (rwp == NULL) 183 { 184 RewriteRules[ruleset] = rwp = 185 (struct rewrite *) xalloc(sizeof *rwp); 186 } 187 else 188 { 189 rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 190 rwp = rwp->r_next; 191 } 192 rwp->r_next = NULL; 193 194 /* expand and save the LHS */ 195 *p = '\0'; 196 expand(&bp[1], exbuf, sizeof exbuf, e); 197 rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 198 sizeof pvpbuf, NULL, 199 ConfigLevel >= 9 ? TokTypeNoC : NULL); 200 nfuzzy = 0; 201 if (rwp->r_lhs != NULL) 202 { 203 register char **ap; 204 205 rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 206 207 /* count the number of fuzzy matches in LHS */ 208 for (ap = rwp->r_lhs; *ap != NULL; ap++) 209 { 210 char *botch; 211 212 botch = NULL; 213 switch (**ap & 0377) 214 { 215 case MATCHZANY: 216 case MATCHANY: 217 case MATCHONE: 218 case MATCHCLASS: 219 case MATCHNCLASS: 220 nfuzzy++; 221 break; 222 223 case MATCHREPL: 224 botch = "$0-$9"; 225 break; 226 227 case CANONUSER: 228 botch = "$:"; 229 break; 230 231 case CALLSUBR: 232 botch = "$>"; 233 break; 234 235 case CONDIF: 236 botch = "$?"; 237 break; 238 239 case CONDFI: 240 botch = "$."; 241 break; 242 243 case HOSTBEGIN: 244 botch = "$["; 245 break; 246 247 case HOSTEND: 248 botch = "$]"; 249 break; 250 251 case LOOKUPBEGIN: 252 botch = "$("; 253 break; 254 255 case LOOKUPEND: 256 botch = "$)"; 257 break; 258 } 259 if (botch != NULL) 260 syserr("Inappropriate use of %s on LHS", 261 botch); 262 } 263 rwp->r_line = LineNumber; 264 } 265 else 266 { 267 syserr("R line: null LHS"); 268 rwp->r_lhs = null_list; 269 } 270 271 /* expand and save the RHS */ 272 while (*++p == '\t') 273 continue; 274 q = p; 275 while (*p != '\0' && *p != '\t') 276 p++; 277 *p = '\0'; 278 expand(q, exbuf, sizeof exbuf, e); 279 rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 280 sizeof pvpbuf, NULL, 281 ConfigLevel >= 9 ? TokTypeNoC : NULL); 282 if (rwp->r_rhs != NULL) 283 { 284 register char **ap; 285 286 rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 287 288 /* check no out-of-bounds replacements */ 289 nfuzzy += '0'; 290 for (ap = rwp->r_rhs; *ap != NULL; ap++) 291 { 292 char *botch; 293 294 botch = NULL; 295 switch (**ap & 0377) 296 { 297 case MATCHREPL: 298 if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 299 { 300 syserr("replacement $%c out of bounds", 301 (*ap)[1]); 302 } 303 break; 304 305 case MATCHZANY: 306 botch = "$*"; 307 break; 308 309 case MATCHANY: 310 botch = "$+"; 311 break; 312 313 case MATCHONE: 314 botch = "$-"; 315 break; 316 317 case MATCHCLASS: 318 botch = "$="; 319 break; 320 321 case MATCHNCLASS: 322 botch = "$~"; 323 break; 324 } 325 if (botch != NULL) 326 syserr("Inappropriate use of %s on RHS", 327 botch); 328 } 329 } 330 else 331 { 332 syserr("R line: null RHS"); 333 rwp->r_rhs = null_list; 334 } 335 break; 336 337 case 'S': /* select rewriting set */ 338 expand(&bp[1], exbuf, sizeof exbuf, e); 339 ruleset = strtorwset(exbuf, NULL, ST_ENTER); 340 if (ruleset < 0) 341 break; 342 343 rwp = RewriteRules[ruleset]; 344 if (rwp != NULL) 345 { 346 if (OpMode == MD_TEST) 347 printf("WARNING: Ruleset %s has multiple definitions\n", 348 &bp[1]); 349 if (tTd(37, 1)) 350 dprintf("WARNING: Ruleset %s has multiple definitions\n", 351 &bp[1]); 352 while (rwp->r_next != NULL) 353 rwp = rwp->r_next; 354 } 355 break; 356 357 case 'D': /* macro definition */ 358 mid = macid(&bp[1], &ep); 359 if (mid == 0) 360 break; 361 p = munchstring(ep, NULL, '\0'); 362 define(mid, newstr(p), e); 363 break; 364 365 case 'H': /* required header line */ 366 (void) chompheader(&bp[1], CHHDR_DEF, NULL, e); 367 break; 368 369 case 'C': /* word class */ 370 case 'T': /* trusted user (set class `t') */ 371 if (bp[0] == 'C') 372 { 373 mid = macid(&bp[1], &ep); 374 if (mid == 0) 375 break; 376 expand(ep, exbuf, sizeof exbuf, e); 377 p = exbuf; 378 } 379 else 380 { 381 mid = 't'; 382 p = &bp[1]; 383 } 384 while (*p != '\0') 385 { 386 register char *wd; 387 char delim; 388 389 while (*p != '\0' && isascii(*p) && isspace(*p)) 390 p++; 391 wd = p; 392 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 393 p++; 394 delim = *p; 395 *p = '\0'; 396 if (wd[0] != '\0') 397 setclass(mid, wd); 398 *p = delim; 399 } 400 break; 401 402 case 'F': /* word class from file */ 403 mid = macid(&bp[1], &ep); 404 if (mid == 0) 405 break; 406 for (p = ep; isascii(*p) && isspace(*p); ) 407 p++; 408 if (p[0] == '-' && p[1] == 'o') 409 { 410 optional = TRUE; 411 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 412 p++; 413 while (isascii(*p) && isspace(*p)) 414 p++; 415 } 416 else 417 optional = FALSE; 418 419 file = p; 420 q = p; 421 while (*q != '\0' && !(isascii(*q) && isspace(*q))) 422 q++; 423 if (*file == '|') 424 p = "%s"; 425 else 426 { 427 p = q; 428 if (*p == '\0') 429 p = "%s"; 430 else 431 { 432 *p = '\0'; 433 while (isascii(*++p) && isspace(*p)) 434 continue; 435 } 436 } 437 fileclass(mid, file, p, safe, optional); 438 break; 439 440 #ifdef XLA 441 case 'L': /* extended load average description */ 442 xla_init(&bp[1]); 443 break; 444 #endif /* XLA */ 445 446 #if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) 447 case 'L': /* lookup macro */ 448 case 'G': /* lookup class */ 449 /* reserved for Sun -- NIS+ database lookup */ 450 if (VendorCode != VENDOR_SUN) 451 goto badline; 452 sun_lg_config_line(bp, e); 453 break; 454 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) */ 455 456 case 'M': /* define mailer */ 457 makemailer(&bp[1]); 458 break; 459 460 case 'O': /* set option */ 461 setoption(bp[1], &bp[2], safe, FALSE, e); 462 break; 463 464 case 'P': /* set precedence */ 465 if (NumPriorities >= MAXPRIORITIES) 466 { 467 toomany('P', MAXPRIORITIES); 468 break; 469 } 470 for (p = &bp[1]; *p != '\0' && *p != '='; p++) 471 continue; 472 if (*p == '\0') 473 goto badline; 474 *p = '\0'; 475 Priorities[NumPriorities].pri_name = newstr(&bp[1]); 476 Priorities[NumPriorities].pri_val = atoi(++p); 477 NumPriorities++; 478 break; 479 480 case 'V': /* configuration syntax version */ 481 for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 482 continue; 483 if (!isascii(*p) || !isdigit(*p)) 484 { 485 syserr("invalid argument to V line: \"%.20s\"", 486 &bp[1]); 487 break; 488 } 489 ConfigLevel = strtol(p, &ep, 10); 490 491 /* 492 ** Do heuristic tweaking for back compatibility. 493 */ 494 495 if (ConfigLevel >= 5) 496 { 497 /* level 5 configs have short name in $w */ 498 p = macvalue('w', e); 499 if (p != NULL && (p = strchr(p, '.')) != NULL) 500 *p = '\0'; 501 define('w', macvalue('w', e), e); 502 } 503 if (ConfigLevel >= 6) 504 { 505 ColonOkInAddr = FALSE; 506 } 507 508 /* 509 ** Look for vendor code. 510 */ 511 512 if (*ep++ == '/') 513 { 514 /* extract vendor code */ 515 for (p = ep; isascii(*p) && isalpha(*p); ) 516 p++; 517 *p = '\0'; 518 519 if (!setvendor(ep)) 520 syserr("invalid V line vendor code: \"%s\"", 521 ep); 522 } 523 break; 524 525 case 'K': 526 expand(&bp[1], exbuf, sizeof exbuf, e); 527 (void) makemapentry(exbuf); 528 break; 529 530 case 'E': 531 p = strchr(bp, '='); 532 if (p != NULL) 533 *p++ = '\0'; 534 setuserenv(&bp[1], p); 535 break; 536 537 #if _FFR_MILTER 538 case 'X': /* mail filter */ 539 milter_setup(&bp[1]); 540 break; 541 #endif /* _FFR_MILTER */ 542 543 default: 544 badline: 545 syserr("unknown configuration line \"%s\"", bp); 546 } 547 if (bp != buf) 548 sm_free(bp); 549 } 550 if (ferror(cf)) 551 { 552 syserr("I/O read error"); 553 finis(FALSE, EX_OSFILE); 554 } 555 (void) fclose(cf); 556 FileName = NULL; 557 558 /* initialize host maps from local service tables */ 559 inithostmaps(); 560 561 /* initialize daemon (if not defined yet) */ 562 initdaemon(); 563 564 /* determine if we need to do special name-server frotz */ 565 { 566 int nmaps; 567 char *maptype[MAXMAPSTACK]; 568 short mapreturn[MAXMAPACTIONS]; 569 570 nmaps = switch_map_find("hosts", maptype, mapreturn); 571 UseNameServer = FALSE; 572 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 573 { 574 register int mapno; 575 576 for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 577 { 578 if (strcmp(maptype[mapno], "dns") == 0) 579 UseNameServer = TRUE; 580 } 581 } 582 583 #ifdef HESIOD 584 nmaps = switch_map_find("passwd", maptype, mapreturn); 585 UseHesiod = FALSE; 586 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 587 { 588 register int mapno; 589 590 for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 591 { 592 if (strcmp(maptype[mapno], "hesiod") == 0) 593 UseHesiod = TRUE; 594 } 595 } 596 #endif /* HESIOD */ 597 } 598 } 599 /* 600 ** TRANSLATE_DOLLARS -- convert $x into internal form 601 ** 602 ** Actually does all appropriate pre-processing of a config line 603 ** to turn it into internal form. 604 ** 605 ** Parameters: 606 ** bp -- the buffer to translate. 607 ** 608 ** Returns: 609 ** None. The buffer is translated in place. Since the 610 ** translations always make the buffer shorter, this is 611 ** safe without a size parameter. 612 */ 613 614 void 615 translate_dollars(bp) 616 char *bp; 617 { 618 register char *p; 619 auto char *ep; 620 621 for (p = bp; *p != '\0'; p++) 622 { 623 if (*p == '#' && p > bp && ConfigLevel >= 3) 624 { 625 /* this is an on-line comment */ 626 register char *e; 627 628 switch (*--p & 0377) 629 { 630 case MACROEXPAND: 631 /* it's from $# -- let it go through */ 632 p++; 633 break; 634 635 case '\\': 636 /* it's backslash escaped */ 637 (void) strlcpy(p, p + 1, strlen(p)); 638 break; 639 640 default: 641 /* delete leading white space */ 642 while (isascii(*p) && isspace(*p) && 643 *p != '\n' && p > bp) 644 p--; 645 if ((e = strchr(++p, '\n')) != NULL) 646 (void) strlcpy(p, e, strlen(p)); 647 else 648 *p-- = '\0'; 649 break; 650 } 651 continue; 652 } 653 654 if (*p != '$' || p[1] == '\0') 655 continue; 656 657 if (p[1] == '$') 658 { 659 /* actual dollar sign.... */ 660 (void) strlcpy(p, p + 1, strlen(p)); 661 continue; 662 } 663 664 /* convert to macro expansion character */ 665 *p++ = MACROEXPAND; 666 667 /* special handling for $=, $~, $&, and $? */ 668 if (*p == '=' || *p == '~' || *p == '&' || *p == '?') 669 p++; 670 671 /* convert macro name to code */ 672 *p = macid(p, &ep); 673 if (ep != p + 1) 674 (void) strlcpy(p + 1, ep, strlen(p + 1)); 675 } 676 677 /* strip trailing white space from the line */ 678 while (--p > bp && isascii(*p) && isspace(*p)) 679 *p = '\0'; 680 } 681 /* 682 ** TOOMANY -- signal too many of some option 683 ** 684 ** Parameters: 685 ** id -- the id of the error line 686 ** maxcnt -- the maximum possible values 687 ** 688 ** Returns: 689 ** none. 690 ** 691 ** Side Effects: 692 ** gives a syserr. 693 */ 694 695 static void 696 toomany(id, maxcnt) 697 int id; 698 int maxcnt; 699 { 700 syserr("too many %c lines, %d max", id, maxcnt); 701 } 702 /* 703 ** FILECLASS -- read members of a class from a file 704 ** 705 ** Parameters: 706 ** class -- class to define. 707 ** filename -- name of file to read. 708 ** fmt -- scanf string to use for match. 709 ** safe -- if set, this is a safe read. 710 ** optional -- if set, it is not an error for the file to 711 ** not exist. 712 ** 713 ** Returns: 714 ** none 715 ** 716 ** Side Effects: 717 ** 718 ** puts all lines in filename that match a scanf into 719 ** the named class. 720 */ 721 722 static void 723 fileclass(class, filename, fmt, safe, optional) 724 int class; 725 char *filename; 726 char *fmt; 727 bool safe; 728 bool optional; 729 { 730 FILE *f; 731 long sff; 732 pid_t pid; 733 register char *p; 734 char buf[MAXLINE]; 735 736 if (tTd(37, 2)) 737 dprintf("fileclass(%s, fmt=%s)\n", filename, fmt); 738 739 if (filename[0] == '|') 740 { 741 auto int fd; 742 int i; 743 char *argv[MAXPV + 1]; 744 745 i = 0; 746 for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t")) 747 { 748 if (i >= MAXPV) 749 break; 750 argv[i++] = p; 751 } 752 argv[i] = NULL; 753 pid = prog_open(argv, &fd, CurEnv); 754 if (pid < 0) 755 f = NULL; 756 else 757 f = fdopen(fd, "r"); 758 } 759 else 760 { 761 pid = -1; 762 sff = SFF_REGONLY; 763 if (!bitnset(DBS_CLASSFILEINUNSAFEDIRPATH, DontBlameSendmail)) 764 sff |= SFF_SAFEDIRPATH; 765 if (!bitnset(DBS_LINKEDCLASSFILEINWRITABLEDIR, 766 DontBlameSendmail)) 767 sff |= SFF_NOWLINK; 768 if (safe) 769 sff |= SFF_OPENASROOT; 770 if (DontLockReadFiles) 771 sff |= SFF_NOLOCK; 772 f = safefopen(filename, O_RDONLY, 0, sff); 773 } 774 if (f == NULL) 775 { 776 if (!optional) 777 syserr("fileclass: cannot open '%s'", filename); 778 return; 779 } 780 781 while (fgets(buf, sizeof buf, f) != NULL) 782 { 783 #if SCANF 784 char wordbuf[MAXLINE + 1]; 785 #endif /* SCANF */ 786 787 if (buf[0] == '#') 788 continue; 789 #if SCANF 790 if (sscanf(buf, fmt, wordbuf) != 1) 791 continue; 792 p = wordbuf; 793 #else /* SCANF */ 794 p = buf; 795 #endif /* SCANF */ 796 797 /* 798 ** Break up the match into words. 799 */ 800 801 while (*p != '\0') 802 { 803 register char *q; 804 805 /* strip leading spaces */ 806 while (isascii(*p) && isspace(*p)) 807 p++; 808 if (*p == '\0') 809 break; 810 811 /* find the end of the word */ 812 q = p; 813 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 814 p++; 815 if (*p != '\0') 816 *p++ = '\0'; 817 818 /* enter the word in the symbol table */ 819 setclass(class, q); 820 } 821 } 822 823 (void) fclose(f); 824 if (pid > 0) 825 (void) waitfor(pid); 826 } 827 /* 828 ** MAKEMAILER -- define a new mailer. 829 ** 830 ** Parameters: 831 ** line -- description of mailer. This is in labeled 832 ** fields. The fields are: 833 ** A -- the argv for this mailer 834 ** C -- the character set for MIME conversions 835 ** D -- the directory to run in 836 ** E -- the eol string 837 ** F -- the flags associated with the mailer 838 ** L -- the maximum line length 839 ** M -- the maximum message size 840 ** N -- the niceness at which to run 841 ** P -- the path to the mailer 842 ** R -- the recipient rewriting set 843 ** S -- the sender rewriting set 844 ** T -- the mailer type (for DSNs) 845 ** U -- the uid to run as 846 ** W -- the time to wait at the end 847 ** m -- maximum messages per connection 848 ** / -- new root directory 849 ** The first word is the canonical name of the mailer. 850 ** 851 ** Returns: 852 ** none. 853 ** 854 ** Side Effects: 855 ** enters the mailer into the mailer table. 856 */ 857 858 void 859 makemailer(line) 860 char *line; 861 { 862 register char *p; 863 register struct mailer *m; 864 register STAB *s; 865 int i; 866 char fcode; 867 auto char *endp; 868 extern int NextMailer; 869 870 /* allocate a mailer and set up defaults */ 871 m = (struct mailer *) xalloc(sizeof *m); 872 memset((char *) m, '\0', sizeof *m); 873 874 /* collect the mailer name */ 875 for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 876 continue; 877 if (*p != '\0') 878 *p++ = '\0'; 879 if (line[0] == '\0') 880 { 881 syserr("name required for mailer"); 882 return; 883 } 884 m->m_name = newstr(line); 885 886 /* now scan through and assign info from the fields */ 887 while (*p != '\0') 888 { 889 auto char *delimptr; 890 891 while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 892 p++; 893 894 /* p now points to field code */ 895 fcode = *p; 896 while (*p != '\0' && *p != '=' && *p != ',') 897 p++; 898 if (*p++ != '=') 899 { 900 syserr("mailer %s: `=' expected", m->m_name); 901 return; 902 } 903 while (isascii(*p) && isspace(*p)) 904 p++; 905 906 /* p now points to the field body */ 907 p = munchstring(p, &delimptr, ','); 908 909 /* install the field into the mailer struct */ 910 switch (fcode) 911 { 912 case 'P': /* pathname */ 913 if (*p == '\0') 914 syserr("mailer %s: empty path name", m->m_name); 915 else 916 m->m_mailer = newstr(p); 917 break; 918 919 case 'F': /* flags */ 920 for (; *p != '\0'; p++) 921 if (!(isascii(*p) && isspace(*p))) 922 setbitn(bitidx(*p), m->m_flags); 923 break; 924 925 case 'S': /* sender rewriting ruleset */ 926 case 'R': /* recipient rewriting ruleset */ 927 i = strtorwset(p, &endp, ST_ENTER); 928 if (i < 0) 929 return; 930 if (fcode == 'S') 931 m->m_sh_rwset = m->m_se_rwset = i; 932 else 933 m->m_rh_rwset = m->m_re_rwset = i; 934 935 p = endp; 936 if (*p++ == '/') 937 { 938 i = strtorwset(p, NULL, ST_ENTER); 939 if (i < 0) 940 return; 941 if (fcode == 'S') 942 m->m_sh_rwset = i; 943 else 944 m->m_rh_rwset = i; 945 } 946 break; 947 948 case 'E': /* end of line string */ 949 if (*p == '\0') 950 syserr("mailer %s: null end-of-line string", 951 m->m_name); 952 else 953 m->m_eol = newstr(p); 954 break; 955 956 case 'A': /* argument vector */ 957 if (*p == '\0') 958 syserr("mailer %s: null argument vector", 959 m->m_name); 960 else 961 m->m_argv = makeargv(p); 962 break; 963 964 case 'M': /* maximum message size */ 965 m->m_maxsize = atol(p); 966 break; 967 968 case 'm': /* maximum messages per connection */ 969 m->m_maxdeliveries = atoi(p); 970 break; 971 972 #if _FFR_DYNAMIC_TOBUF 973 case 'r': /* max recipient per envelope */ 974 m->m_maxrcpt = atoi(p); 975 break; 976 #endif /* _FFR_DYNAMIC_TOBUF */ 977 978 case 'L': /* maximum line length */ 979 m->m_linelimit = atoi(p); 980 if (m->m_linelimit < 0) 981 m->m_linelimit = 0; 982 break; 983 984 case 'N': /* run niceness */ 985 m->m_nice = atoi(p); 986 break; 987 988 case 'D': /* working directory */ 989 if (*p == '\0') 990 syserr("mailer %s: null working directory", 991 m->m_name); 992 else 993 m->m_execdir = newstr(p); 994 break; 995 996 case 'C': /* default charset */ 997 if (*p == '\0') 998 syserr("mailer %s: null charset", m->m_name); 999 else 1000 m->m_defcharset = newstr(p); 1001 break; 1002 1003 case 'T': /* MTA-Name/Address/Diagnostic types */ 1004 /* extract MTA name type; default to "dns" */ 1005 m->m_mtatype = newstr(p); 1006 p = strchr(m->m_mtatype, '/'); 1007 if (p != NULL) 1008 { 1009 *p++ = '\0'; 1010 if (*p == '\0') 1011 p = NULL; 1012 } 1013 if (*m->m_mtatype == '\0') 1014 m->m_mtatype = "dns"; 1015 1016 /* extract address type; default to "rfc822" */ 1017 m->m_addrtype = p; 1018 if (p != NULL) 1019 p = strchr(p, '/'); 1020 if (p != NULL) 1021 { 1022 *p++ = '\0'; 1023 if (*p == '\0') 1024 p = NULL; 1025 } 1026 if (m->m_addrtype == NULL || *m->m_addrtype == '\0') 1027 m->m_addrtype = "rfc822"; 1028 1029 /* extract diagnostic type; default to "smtp" */ 1030 m->m_diagtype = p; 1031 if (m->m_diagtype == NULL || *m->m_diagtype == '\0') 1032 m->m_diagtype = "smtp"; 1033 break; 1034 1035 case 'U': /* user id */ 1036 if (isascii(*p) && !isdigit(*p)) 1037 { 1038 char *q = p; 1039 struct passwd *pw; 1040 1041 while (*p != '\0' && isascii(*p) && 1042 (isalnum(*p) || strchr("-_", *p) != NULL)) 1043 p++; 1044 while (isascii(*p) && isspace(*p)) 1045 *p++ = '\0'; 1046 if (*p != '\0') 1047 *p++ = '\0'; 1048 if (*q == '\0') 1049 { 1050 syserr("mailer %s: null user name", 1051 m->m_name); 1052 break; 1053 } 1054 pw = sm_getpwnam(q); 1055 if (pw == NULL) 1056 { 1057 syserr("readcf: mailer U= flag: unknown user %s", q); 1058 break; 1059 } 1060 else 1061 { 1062 m->m_uid = pw->pw_uid; 1063 m->m_gid = pw->pw_gid; 1064 } 1065 } 1066 else 1067 { 1068 auto char *q; 1069 1070 m->m_uid = strtol(p, &q, 0); 1071 p = q; 1072 while (isascii(*p) && isspace(*p)) 1073 p++; 1074 if (*p != '\0') 1075 p++; 1076 } 1077 while (isascii(*p) && isspace(*p)) 1078 p++; 1079 if (*p == '\0') 1080 break; 1081 if (isascii(*p) && !isdigit(*p)) 1082 { 1083 char *q = p; 1084 struct group *gr; 1085 1086 while (isascii(*p) && isalnum(*p)) 1087 p++; 1088 *p++ = '\0'; 1089 if (*q == '\0') 1090 { 1091 syserr("mailer %s: null group name", 1092 m->m_name); 1093 break; 1094 } 1095 gr = getgrnam(q); 1096 if (gr == NULL) 1097 { 1098 syserr("readcf: mailer U= flag: unknown group %s", q); 1099 break; 1100 } 1101 else 1102 m->m_gid = gr->gr_gid; 1103 } 1104 else 1105 { 1106 m->m_gid = strtol(p, NULL, 0); 1107 } 1108 break; 1109 1110 case 'W': /* wait timeout */ 1111 m->m_wait = convtime(p, 's'); 1112 break; 1113 1114 case '/': /* new root directory */ 1115 if (*p == '\0') 1116 syserr("mailer %s: null root directory", 1117 m->m_name); 1118 else 1119 m->m_rootdir = newstr(p); 1120 break; 1121 1122 default: 1123 syserr("M%s: unknown mailer equate %c=", 1124 m->m_name, fcode); 1125 break; 1126 } 1127 1128 p = delimptr; 1129 } 1130 1131 /* do some rationality checking */ 1132 if (m->m_argv == NULL) 1133 { 1134 syserr("M%s: A= argument required", m->m_name); 1135 return; 1136 } 1137 if (m->m_mailer == NULL) 1138 { 1139 syserr("M%s: P= argument required", m->m_name); 1140 return; 1141 } 1142 1143 if (NextMailer >= MAXMAILERS) 1144 { 1145 syserr("too many mailers defined (%d max)", MAXMAILERS); 1146 return; 1147 } 1148 1149 #if _FFR_DYNAMIC_TOBUF 1150 if (m->m_maxrcpt <= 0) 1151 m->m_maxrcpt = DEFAULT_MAX_RCPT; 1152 #endif /* _FFR_DYNAMIC_TOBUF */ 1153 1154 /* do some heuristic cleanup for back compatibility */ 1155 if (bitnset(M_LIMITS, m->m_flags)) 1156 { 1157 if (m->m_linelimit == 0) 1158 m->m_linelimit = SMTPLINELIM; 1159 if (ConfigLevel < 2) 1160 setbitn(M_7BITS, m->m_flags); 1161 } 1162 1163 if (strcmp(m->m_mailer, "[TCP]") == 0) 1164 { 1165 #if _FFR_REMOVE_TCP_MAILER_PATH 1166 syserr("M%s: P=[TCP] is deprecated, use P=[IPC] instead\n", 1167 m->m_name); 1168 return; 1169 #else /* _FFR_REMOVE_TCP_MAILER_PATH */ 1170 printf("M%s: Warning: P=[TCP] is deprecated, use P=[IPC] instead\n", 1171 m->m_name); 1172 #endif /* _FFR_REMOVE_TCP_MAILER_PATH */ 1173 } 1174 1175 if (strcmp(m->m_mailer, "[IPC]") == 0 1176 #if !_FFR_REMOVE_TCP_MAILER_PATH 1177 || strcmp(m->m_mailer, "[TCP]") == 0 1178 #endif /* !_FFR_REMOVE_TCP_MAILER_PATH */ 1179 ) 1180 { 1181 /* Use the second argument for host or path to socket */ 1182 if (m->m_argv[0] == NULL || m->m_argv[1] == NULL || 1183 m->m_argv[1][0] == '\0') 1184 { 1185 syserr("M%s: too few parameters for %s mailer", 1186 m->m_name, m->m_mailer); 1187 return; 1188 } 1189 if (strcmp(m->m_argv[0], "TCP") != 0 1190 #if NETUNIX 1191 && strcmp(m->m_argv[0], "FILE") != 0 1192 #endif /* NETUNIX */ 1193 #if !_FFR_DEPRECATE_IPC_MAILER_ARG 1194 && strcmp(m->m_argv[0], "IPC") != 0 1195 #endif /* !_FFR_DEPRECATE_IPC_MAILER_ARG */ 1196 ) 1197 { 1198 printf("M%s: Warning: first argument in %s mailer must be %s\n", 1199 m->m_name, m->m_mailer, 1200 #if NETUNIX 1201 "TCP or FILE" 1202 #else /* NETUNIX */ 1203 "TCP" 1204 #endif /* NETUNIX */ 1205 ); 1206 } 1207 1208 } 1209 else if (strcmp(m->m_mailer, "[FILE]") == 0) 1210 { 1211 /* Use the second argument for filename */ 1212 if (m->m_argv[0] == NULL || m->m_argv[1] == NULL || 1213 m->m_argv[2] != NULL) 1214 { 1215 syserr("M%s: too %s parameters for [FILE] mailer", 1216 m->m_name, 1217 (m->m_argv[0] == NULL || 1218 m->m_argv[1] == NULL) ? "few" : "many"); 1219 return; 1220 } 1221 else if (strcmp(m->m_argv[0], "FILE") != 0) 1222 { 1223 syserr("M%s: first argument in [FILE] mailer must be FILE", 1224 m->m_name); 1225 return; 1226 } 1227 } 1228 1229 if (strcmp(m->m_mailer, "[IPC]") == 0 || 1230 strcmp(m->m_mailer, "[TCP]") == 0) 1231 { 1232 if (m->m_mtatype == NULL) 1233 m->m_mtatype = "dns"; 1234 if (m->m_addrtype == NULL) 1235 m->m_addrtype = "rfc822"; 1236 if (m->m_diagtype == NULL) 1237 { 1238 if (m->m_argv[0] != NULL && 1239 strcmp(m->m_argv[0], "FILE") == 0) 1240 m->m_diagtype = "x-unix"; 1241 else 1242 m->m_diagtype = "smtp"; 1243 } 1244 } 1245 1246 if (m->m_eol == NULL) 1247 { 1248 char **pp; 1249 1250 /* default for SMTP is \r\n; use \n for local delivery */ 1251 for (pp = m->m_argv; *pp != NULL; pp++) 1252 { 1253 for (p = *pp; *p != '\0'; ) 1254 { 1255 if ((*p++ & 0377) == MACROEXPAND && *p == 'u') 1256 break; 1257 } 1258 if (*p != '\0') 1259 break; 1260 } 1261 if (*pp == NULL) 1262 m->m_eol = "\r\n"; 1263 else 1264 m->m_eol = "\n"; 1265 } 1266 1267 /* enter the mailer into the symbol table */ 1268 s = stab(m->m_name, ST_MAILER, ST_ENTER); 1269 if (s->s_mailer != NULL) 1270 { 1271 i = s->s_mailer->m_mno; 1272 sm_free(s->s_mailer); 1273 } 1274 else 1275 { 1276 i = NextMailer++; 1277 } 1278 Mailer[i] = s->s_mailer = m; 1279 m->m_mno = i; 1280 } 1281 /* 1282 ** MUNCHSTRING -- translate a string into internal form. 1283 ** 1284 ** Parameters: 1285 ** p -- the string to munch. 1286 ** delimptr -- if non-NULL, set to the pointer of the 1287 ** field delimiter character. 1288 ** delim -- the delimiter for the field. 1289 ** 1290 ** Returns: 1291 ** the munched string. 1292 ** 1293 ** Side Effects: 1294 ** the munched string is a local static buffer. 1295 ** it must be copied before the function is called again. 1296 */ 1297 1298 char * 1299 munchstring(p, delimptr, delim) 1300 register char *p; 1301 char **delimptr; 1302 int delim; 1303 { 1304 register char *q; 1305 bool backslash = FALSE; 1306 bool quotemode = FALSE; 1307 static char buf[MAXLINE]; 1308 1309 for (q = buf; *p != '\0' && q < &buf[sizeof buf - 1]; p++) 1310 { 1311 if (backslash) 1312 { 1313 /* everything is roughly literal */ 1314 backslash = FALSE; 1315 switch (*p) 1316 { 1317 case 'r': /* carriage return */ 1318 *q++ = '\r'; 1319 continue; 1320 1321 case 'n': /* newline */ 1322 *q++ = '\n'; 1323 continue; 1324 1325 case 'f': /* form feed */ 1326 *q++ = '\f'; 1327 continue; 1328 1329 case 'b': /* backspace */ 1330 *q++ = '\b'; 1331 continue; 1332 } 1333 *q++ = *p; 1334 } 1335 else 1336 { 1337 if (*p == '\\') 1338 backslash = TRUE; 1339 else if (*p == '"') 1340 quotemode = !quotemode; 1341 else if (quotemode || *p != delim) 1342 *q++ = *p; 1343 else 1344 break; 1345 } 1346 } 1347 1348 if (delimptr != NULL) 1349 *delimptr = p; 1350 *q++ = '\0'; 1351 return buf; 1352 } 1353 /* 1354 ** MAKEARGV -- break up a string into words 1355 ** 1356 ** Parameters: 1357 ** p -- the string to break up. 1358 ** 1359 ** Returns: 1360 ** a char **argv (dynamically allocated) 1361 ** 1362 ** Side Effects: 1363 ** munges p. 1364 */ 1365 1366 static char ** 1367 makeargv(p) 1368 register char *p; 1369 { 1370 char *q; 1371 int i; 1372 char **avp; 1373 char *argv[MAXPV + 1]; 1374 1375 /* take apart the words */ 1376 i = 0; 1377 while (*p != '\0' && i < MAXPV) 1378 { 1379 q = p; 1380 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1381 p++; 1382 while (isascii(*p) && isspace(*p)) 1383 *p++ = '\0'; 1384 argv[i++] = newstr(q); 1385 } 1386 argv[i++] = NULL; 1387 1388 /* now make a copy of the argv */ 1389 avp = (char **) xalloc(sizeof *avp * i); 1390 memmove((char *) avp, (char *) argv, sizeof *avp * i); 1391 1392 return avp; 1393 } 1394 /* 1395 ** PRINTRULES -- print rewrite rules (for debugging) 1396 ** 1397 ** Parameters: 1398 ** none. 1399 ** 1400 ** Returns: 1401 ** none. 1402 ** 1403 ** Side Effects: 1404 ** prints rewrite rules. 1405 */ 1406 1407 void 1408 printrules() 1409 { 1410 register struct rewrite *rwp; 1411 register int ruleset; 1412 1413 for (ruleset = 0; ruleset < 10; ruleset++) 1414 { 1415 if (RewriteRules[ruleset] == NULL) 1416 continue; 1417 printf("\n----Rule Set %d:", ruleset); 1418 1419 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 1420 { 1421 printf("\nLHS:"); 1422 printav(rwp->r_lhs); 1423 printf("RHS:"); 1424 printav(rwp->r_rhs); 1425 } 1426 } 1427 } 1428 /* 1429 ** PRINTMAILER -- print mailer structure (for debugging) 1430 ** 1431 ** Parameters: 1432 ** m -- the mailer to print 1433 ** 1434 ** Returns: 1435 ** none. 1436 */ 1437 1438 void 1439 printmailer(m) 1440 register MAILER *m; 1441 { 1442 int j; 1443 1444 printf("mailer %d (%s): P=%s S=", m->m_mno, m->m_name, m->m_mailer); 1445 if (RuleSetNames[m->m_se_rwset] == NULL) 1446 printf("%d/", m->m_se_rwset); 1447 else 1448 printf("%s/", RuleSetNames[m->m_se_rwset]); 1449 if (RuleSetNames[m->m_sh_rwset] == NULL) 1450 printf("%d R=", m->m_sh_rwset); 1451 else 1452 printf("%s R=", RuleSetNames[m->m_sh_rwset]); 1453 if (RuleSetNames[m->m_re_rwset] == NULL) 1454 printf("%d/", m->m_re_rwset); 1455 else 1456 printf("%s/", RuleSetNames[m->m_re_rwset]); 1457 if (RuleSetNames[m->m_rh_rwset] == NULL) 1458 printf("%d ", m->m_rh_rwset); 1459 else 1460 printf("%s ", RuleSetNames[m->m_rh_rwset]); 1461 printf("M=%ld U=%d:%d F=", m->m_maxsize, 1462 (int) m->m_uid, (int) m->m_gid); 1463 for (j = '\0'; j <= '\177'; j++) 1464 if (bitnset(j, m->m_flags)) 1465 (void) putchar(j); 1466 printf(" L=%d E=", m->m_linelimit); 1467 xputs(m->m_eol); 1468 if (m->m_defcharset != NULL) 1469 printf(" C=%s", m->m_defcharset); 1470 printf(" T=%s/%s/%s", 1471 m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 1472 m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 1473 m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 1474 #if _FFR_DYNAMIC_TOBUF 1475 printf(" r=%d", m->m_maxrcpt); 1476 #endif /* _FFR_DYNAMIC_TOBUF */ 1477 if (m->m_argv != NULL) 1478 { 1479 char **a = m->m_argv; 1480 1481 printf(" A="); 1482 while (*a != NULL) 1483 { 1484 if (a != m->m_argv) 1485 printf(" "); 1486 xputs(*a++); 1487 } 1488 } 1489 printf("\n"); 1490 } 1491 /* 1492 ** SETOPTION -- set global processing option 1493 ** 1494 ** Parameters: 1495 ** opt -- option name. 1496 ** val -- option value (as a text string). 1497 ** safe -- set if this came from a configuration file. 1498 ** Some options (if set from the command line) will 1499 ** reset the user id to avoid security problems. 1500 ** sticky -- if set, don't let other setoptions override 1501 ** this value. 1502 ** e -- the main envelope. 1503 ** 1504 ** Returns: 1505 ** none. 1506 ** 1507 ** Side Effects: 1508 ** Sets options as implied by the arguments. 1509 */ 1510 1511 static BITMAP256 StickyOpt; /* set if option is stuck */ 1512 1513 #if NAMED_BIND 1514 1515 static struct resolverflags 1516 { 1517 char *rf_name; /* name of the flag */ 1518 long rf_bits; /* bits to set/clear */ 1519 } ResolverFlags[] = 1520 { 1521 { "debug", RES_DEBUG }, 1522 { "aaonly", RES_AAONLY }, 1523 { "usevc", RES_USEVC }, 1524 { "primary", RES_PRIMARY }, 1525 { "igntc", RES_IGNTC }, 1526 { "recurse", RES_RECURSE }, 1527 { "defnames", RES_DEFNAMES }, 1528 { "stayopen", RES_STAYOPEN }, 1529 { "dnsrch", RES_DNSRCH }, 1530 { "true", 0 }, /* avoid error on old syntax */ 1531 { NULL, 0 } 1532 }; 1533 1534 #endif /* NAMED_BIND */ 1535 1536 #define OI_NONE 0 /* no special treatment */ 1537 #define OI_SAFE 0x0001 /* safe for random people to use */ 1538 #define OI_SUBOPT 0x0002 /* option has suboptions */ 1539 1540 static struct optioninfo 1541 { 1542 char *o_name; /* long name of option */ 1543 u_char o_code; /* short name of option */ 1544 u_short o_flags; /* option flags */ 1545 } OptionTab[] = 1546 { 1547 #if defined(SUN_EXTENSIONS) && defined(REMOTE_MODE) 1548 { "RemoteMode", '>', OI_NONE }, 1549 #endif /* defined(SUN_EXTENSIONS) && defined(REMOTE_MODE) */ 1550 { "SevenBitInput", '7', OI_SAFE }, 1551 { "EightBitMode", '8', OI_SAFE }, 1552 { "AliasFile", 'A', OI_NONE }, 1553 { "AliasWait", 'a', OI_NONE }, 1554 { "BlankSub", 'B', OI_NONE }, 1555 { "MinFreeBlocks", 'b', OI_SAFE }, 1556 { "CheckpointInterval", 'C', OI_SAFE }, 1557 { "HoldExpensive", 'c', OI_NONE }, 1558 #if !_FFR_REMOVE_AUTOREBUILD 1559 { "AutoRebuildAliases", 'D', OI_NONE }, 1560 #endif /* !_FFR_REMOVE_AUTOREBUILD */ 1561 { "DeliveryMode", 'd', OI_SAFE }, 1562 { "ErrorHeader", 'E', OI_NONE }, 1563 { "ErrorMode", 'e', OI_SAFE }, 1564 { "TempFileMode", 'F', OI_NONE }, 1565 { "SaveFromLine", 'f', OI_NONE }, 1566 { "MatchGECOS", 'G', OI_NONE }, 1567 { "HelpFile", 'H', OI_NONE }, 1568 { "MaxHopCount", 'h', OI_NONE }, 1569 { "ResolverOptions", 'I', OI_NONE }, 1570 { "IgnoreDots", 'i', OI_SAFE }, 1571 { "ForwardPath", 'J', OI_NONE }, 1572 { "SendMimeErrors", 'j', OI_SAFE }, 1573 { "ConnectionCacheSize", 'k', OI_NONE }, 1574 { "ConnectionCacheTimeout", 'K', OI_NONE }, 1575 { "UseErrorsTo", 'l', OI_NONE }, 1576 { "LogLevel", 'L', OI_SAFE }, 1577 { "MeToo", 'm', OI_SAFE }, 1578 { "CheckAliases", 'n', OI_NONE }, 1579 { "OldStyleHeaders", 'o', OI_SAFE }, 1580 { "DaemonPortOptions", 'O', OI_NONE }, 1581 { "PrivacyOptions", 'p', OI_SAFE }, 1582 { "PostmasterCopy", 'P', OI_NONE }, 1583 { "QueueFactor", 'q', OI_NONE }, 1584 { "QueueDirectory", 'Q', OI_NONE }, 1585 { "DontPruneRoutes", 'R', OI_NONE }, 1586 { "Timeout", 'r', OI_SUBOPT }, 1587 { "StatusFile", 'S', OI_NONE }, 1588 { "SuperSafe", 's', OI_SAFE }, 1589 { "QueueTimeout", 'T', OI_NONE }, 1590 { "TimeZoneSpec", 't', OI_NONE }, 1591 { "UserDatabaseSpec", 'U', OI_NONE }, 1592 { "DefaultUser", 'u', OI_NONE }, 1593 { "FallbackMXhost", 'V', OI_NONE }, 1594 { "Verbose", 'v', OI_SAFE }, 1595 { "TryNullMXList", 'w', OI_NONE }, 1596 { "QueueLA", 'x', OI_NONE }, 1597 { "RefuseLA", 'X', OI_NONE }, 1598 { "RecipientFactor", 'y', OI_NONE }, 1599 { "ForkEachJob", 'Y', OI_NONE }, 1600 { "ClassFactor", 'z', OI_NONE }, 1601 { "RetryFactor", 'Z', OI_NONE }, 1602 #define O_QUEUESORTORD 0x81 1603 { "QueueSortOrder", O_QUEUESORTORD, OI_SAFE }, 1604 #define O_HOSTSFILE 0x82 1605 { "HostsFile", O_HOSTSFILE, OI_NONE }, 1606 #define O_MQA 0x83 1607 { "MinQueueAge", O_MQA, OI_SAFE }, 1608 #define O_DEFCHARSET 0x85 1609 { "DefaultCharSet", O_DEFCHARSET, OI_SAFE }, 1610 #define O_SSFILE 0x86 1611 { "ServiceSwitchFile", O_SSFILE, OI_NONE }, 1612 #define O_DIALDELAY 0x87 1613 { "DialDelay", O_DIALDELAY, OI_SAFE }, 1614 #define O_NORCPTACTION 0x88 1615 { "NoRecipientAction", O_NORCPTACTION, OI_SAFE }, 1616 #define O_SAFEFILEENV 0x89 1617 { "SafeFileEnvironment", O_SAFEFILEENV, OI_NONE }, 1618 #define O_MAXMSGSIZE 0x8a 1619 { "MaxMessageSize", O_MAXMSGSIZE, OI_NONE }, 1620 #define O_COLONOKINADDR 0x8b 1621 { "ColonOkInAddr", O_COLONOKINADDR, OI_SAFE }, 1622 #define O_MAXQUEUERUN 0x8c 1623 { "MaxQueueRunSize", O_MAXQUEUERUN, OI_SAFE }, 1624 #define O_MAXCHILDREN 0x8d 1625 { "MaxDaemonChildren", O_MAXCHILDREN, OI_NONE }, 1626 #define O_KEEPCNAMES 0x8e 1627 { "DontExpandCnames", O_KEEPCNAMES, OI_NONE }, 1628 #define O_MUSTQUOTE 0x8f 1629 { "MustQuoteChars", O_MUSTQUOTE, OI_NONE }, 1630 #define O_SMTPGREETING 0x90 1631 { "SmtpGreetingMessage", O_SMTPGREETING, OI_NONE }, 1632 #define O_UNIXFROM 0x91 1633 { "UnixFromLine", O_UNIXFROM, OI_NONE }, 1634 #define O_OPCHARS 0x92 1635 { "OperatorChars", O_OPCHARS, OI_NONE }, 1636 #define O_DONTINITGRPS 0x93 1637 { "DontInitGroups", O_DONTINITGRPS, OI_NONE }, 1638 #define O_SLFH 0x94 1639 { "SingleLineFromHeader", O_SLFH, OI_SAFE }, 1640 #define O_ABH 0x95 1641 { "AllowBogusHELO", O_ABH, OI_SAFE }, 1642 #define O_CONNTHROT 0x97 1643 { "ConnectionRateThrottle", O_CONNTHROT, OI_NONE }, 1644 #define O_UGW 0x99 1645 { "UnsafeGroupWrites", O_UGW, OI_NONE }, 1646 #define O_DBLBOUNCE 0x9a 1647 { "DoubleBounceAddress", O_DBLBOUNCE, OI_NONE }, 1648 #define O_HSDIR 0x9b 1649 { "HostStatusDirectory", O_HSDIR, OI_NONE }, 1650 #define O_SINGTHREAD 0x9c 1651 { "SingleThreadDelivery", O_SINGTHREAD, OI_NONE }, 1652 #define O_RUNASUSER 0x9d 1653 { "RunAsUser", O_RUNASUSER, OI_NONE }, 1654 #define O_DSN_RRT 0x9e 1655 { "RrtImpliesDsn", O_DSN_RRT, OI_NONE }, 1656 #define O_PIDFILE 0x9f 1657 { "PidFile", O_PIDFILE, OI_NONE }, 1658 #define O_DONTBLAMESENDMAIL 0xa0 1659 { "DontBlameSendmail", O_DONTBLAMESENDMAIL, OI_NONE }, 1660 #define O_DPI 0xa1 1661 { "DontProbeInterfaces", O_DPI, OI_NONE }, 1662 #define O_MAXRCPT 0xa2 1663 { "MaxRecipientsPerMessage", O_MAXRCPT, OI_SAFE }, 1664 #define O_DEADLETTER 0xa3 1665 { "DeadLetterDrop", O_DEADLETTER, OI_NONE }, 1666 #if _FFR_DONTLOCKFILESFORREAD_OPTION 1667 # define O_DONTLOCK 0xa4 1668 { "DontLockFilesForRead", O_DONTLOCK, OI_NONE }, 1669 #endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */ 1670 #define O_MAXALIASRCSN 0xa5 1671 { "MaxAliasRecursion", O_MAXALIASRCSN, OI_NONE }, 1672 #define O_CNCTONLYTO 0xa6 1673 { "ConnectOnlyTo", O_CNCTONLYTO, OI_NONE }, 1674 #define O_TRUSTUSER 0xa7 1675 { "TrustedUser", O_TRUSTUSER, OI_NONE }, 1676 #define O_MAXMIMEHDRLEN 0xa8 1677 { "MaxMimeHeaderLength", O_MAXMIMEHDRLEN, OI_NONE }, 1678 #define O_CONTROLSOCKET 0xa9 1679 { "ControlSocketName", O_CONTROLSOCKET, OI_NONE }, 1680 #define O_MAXHDRSLEN 0xaa 1681 { "MaxHeadersLength", O_MAXHDRSLEN, OI_NONE }, 1682 #if _FFR_MAX_FORWARD_ENTRIES 1683 # define O_MAXFORWARD 0xab 1684 { "MaxForwardEntries", O_MAXFORWARD, OI_NONE }, 1685 #endif /* _FFR_MAX_FORWARD_ENTRIES */ 1686 #define O_PROCTITLEPREFIX 0xac 1687 { "ProcessTitlePrefix", O_PROCTITLEPREFIX, OI_NONE }, 1688 #define O_SASLINFO 0xad 1689 #if _FFR_ALLOW_SASLINFO 1690 { "DefaultAuthInfo", O_SASLINFO, OI_SAFE }, 1691 #else /* _FFR_ALLOW_SASLINFO */ 1692 { "DefaultAuthInfo", O_SASLINFO, OI_NONE }, 1693 #endif /* _FFR_ALLOW_SASLINFO */ 1694 #define O_SASLMECH 0xae 1695 { "AuthMechanisms", O_SASLMECH, OI_NONE }, 1696 #define O_CLIENTPORT 0xaf 1697 { "ClientPortOptions", O_CLIENTPORT, OI_NONE }, 1698 #define O_DF_BUFSIZE 0xb0 1699 { "DataFileBufferSize", O_DF_BUFSIZE, OI_NONE }, 1700 #define O_XF_BUFSIZE 0xb1 1701 { "XscriptFileBufferSize", O_XF_BUFSIZE, OI_NONE }, 1702 # define O_LDAPDEFAULTSPEC 0xb2 1703 { "LDAPDefaultSpec", O_LDAPDEFAULTSPEC, OI_NONE }, 1704 #if _FFR_QUEUEDELAY 1705 #define O_QUEUEDELAY 0xb3 1706 { "QueueDelay", O_QUEUEDELAY, OI_NONE }, 1707 #endif /* _FFR_QUEUEDELAY */ 1708 # define O_SRVCERTFILE 0xb4 1709 { "ServerCertFile", O_SRVCERTFILE, OI_NONE }, 1710 # define O_SRVKEYFILE 0xb5 1711 { "Serverkeyfile", O_SRVKEYFILE, OI_NONE }, 1712 # define O_CLTCERTFILE 0xb6 1713 { "ClientCertFile", O_CLTCERTFILE, OI_NONE }, 1714 # define O_CLTKEYFILE 0xb7 1715 { "Clientkeyfile", O_CLTKEYFILE, OI_NONE }, 1716 # define O_CACERTFILE 0xb8 1717 { "CACERTFile", O_CACERTFILE, OI_NONE }, 1718 # define O_CACERTPATH 0xb9 1719 { "CACERTPath", O_CACERTPATH, OI_NONE }, 1720 # define O_DHPARAMS 0xba 1721 { "DHParameters", O_DHPARAMS, OI_NONE }, 1722 #if _FFR_MILTER 1723 #define O_INPUTMILTER 0xbb 1724 { "InputMailFilters", O_INPUTMILTER, OI_NONE }, 1725 #define O_MILTER 0xbc 1726 { "Milter", O_MILTER, OI_SUBOPT }, 1727 #endif /* _FFR_MILTER */ 1728 #define O_SASLOPTS 0xbd 1729 { "AuthOptions", O_SASLOPTS, OI_NONE }, 1730 #if _FFR_QUEUE_FILE_MODE 1731 #define O_QUEUE_FILE_MODE 0xbe 1732 { "QueueFileMode", O_QUEUE_FILE_MODE, OI_NONE }, 1733 #endif /* _FFR_QUEUE_FILE_MODE */ 1734 # if _FFR_TLS_1 1735 # define O_DHPARAMS5 0xbf 1736 { "DHParameters512", O_DHPARAMS5, OI_NONE }, 1737 # define O_CIPHERLIST 0xc0 1738 { "CipherList", O_CIPHERLIST, OI_NONE }, 1739 # endif /* _FFR_TLS_1 */ 1740 # define O_RANDFILE 0xc1 1741 { "RandFile", O_RANDFILE, OI_NONE }, 1742 { NULL, '\0', OI_NONE } 1743 }; 1744 1745 void 1746 setoption(opt, val, safe, sticky, e) 1747 int opt; 1748 char *val; 1749 bool safe; 1750 bool sticky; 1751 register ENVELOPE *e; 1752 { 1753 register char *p; 1754 register struct optioninfo *o; 1755 char *subopt; 1756 int mid; 1757 bool can_setuid = RunAsUid == 0; 1758 auto char *ep; 1759 char buf[50]; 1760 extern bool Warn_Q_option; 1761 #if _FFR_ALLOW_SASLINFO 1762 extern int SubmitMode; 1763 #endif /* _FFR_ALLOW_SASLINFO */ 1764 1765 errno = 0; 1766 if (opt == ' ') 1767 { 1768 /* full word options */ 1769 struct optioninfo *sel; 1770 1771 p = strchr(val, '='); 1772 if (p == NULL) 1773 p = &val[strlen(val)]; 1774 while (*--p == ' ') 1775 continue; 1776 while (*++p == ' ') 1777 *p = '\0'; 1778 if (p == val) 1779 { 1780 syserr("readcf: null option name"); 1781 return; 1782 } 1783 if (*p == '=') 1784 *p++ = '\0'; 1785 while (*p == ' ') 1786 p++; 1787 subopt = strchr(val, '.'); 1788 if (subopt != NULL) 1789 *subopt++ = '\0'; 1790 sel = NULL; 1791 for (o = OptionTab; o->o_name != NULL; o++) 1792 { 1793 if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1794 continue; 1795 if (strlen(o->o_name) == strlen(val)) 1796 { 1797 /* completely specified -- this must be it */ 1798 sel = NULL; 1799 break; 1800 } 1801 if (sel != NULL) 1802 break; 1803 sel = o; 1804 } 1805 if (sel != NULL && o->o_name == NULL) 1806 o = sel; 1807 else if (o->o_name == NULL) 1808 { 1809 syserr("readcf: unknown option name %s", val); 1810 return; 1811 } 1812 else if (sel != NULL) 1813 { 1814 syserr("readcf: ambiguous option name %s (matches %s and %s)", 1815 val, sel->o_name, o->o_name); 1816 return; 1817 } 1818 if (strlen(val) != strlen(o->o_name)) 1819 { 1820 int oldVerbose = Verbose; 1821 1822 Verbose = 1; 1823 message("Option %s used as abbreviation for %s", 1824 val, o->o_name); 1825 Verbose = oldVerbose; 1826 } 1827 opt = o->o_code; 1828 val = p; 1829 } 1830 else 1831 { 1832 for (o = OptionTab; o->o_name != NULL; o++) 1833 { 1834 if (o->o_code == opt) 1835 break; 1836 } 1837 subopt = NULL; 1838 } 1839 1840 if (subopt != NULL && !bitset(OI_SUBOPT, o->o_flags)) 1841 { 1842 if (tTd(37, 1)) 1843 dprintf("setoption: %s does not support suboptions, ignoring .%s\n", 1844 o->o_name == NULL ? "<unknown>" : o->o_name, 1845 subopt); 1846 subopt = NULL; 1847 } 1848 1849 if (tTd(37, 1)) 1850 { 1851 dprintf(isascii(opt) && isprint(opt) ? 1852 "setoption %s (%c)%s%s=" : 1853 "setoption %s (0x%x)%s%s=", 1854 o->o_name == NULL ? "<unknown>" : o->o_name, 1855 opt, 1856 subopt == NULL ? "" : ".", 1857 subopt == NULL ? "" : subopt); 1858 xputs(val); 1859 } 1860 1861 /* 1862 ** See if this option is preset for us. 1863 */ 1864 1865 if (!sticky && bitnset(opt, StickyOpt)) 1866 { 1867 if (tTd(37, 1)) 1868 dprintf(" (ignored)\n"); 1869 return; 1870 } 1871 1872 /* 1873 ** Check to see if this option can be specified by this user. 1874 */ 1875 1876 if (!safe && RealUid == 0) 1877 safe = TRUE; 1878 if (!safe && !bitset(OI_SAFE, o->o_flags)) 1879 { 1880 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 1881 { 1882 int dp; 1883 1884 if (tTd(37, 1)) 1885 dprintf(" (unsafe)"); 1886 dp = drop_privileges(TRUE); 1887 setstat(dp); 1888 } 1889 } 1890 if (tTd(37, 1)) 1891 dprintf("\n"); 1892 1893 switch (opt & 0xff) 1894 { 1895 case '7': /* force seven-bit input */ 1896 SevenBitInput = atobool(val); 1897 break; 1898 1899 case '8': /* handling of 8-bit input */ 1900 #if MIME8TO7 1901 switch (*val) 1902 { 1903 case 'm': /* convert 8-bit, convert MIME */ 1904 MimeMode = MM_CVTMIME|MM_MIME8BIT; 1905 break; 1906 1907 case 'p': /* pass 8 bit, convert MIME */ 1908 MimeMode = MM_CVTMIME|MM_PASS8BIT; 1909 break; 1910 1911 case 's': /* strict adherence */ 1912 MimeMode = MM_CVTMIME; 1913 break; 1914 1915 # if 0 1916 case 'r': /* reject 8-bit, don't convert MIME */ 1917 MimeMode = 0; 1918 break; 1919 1920 case 'j': /* "just send 8" */ 1921 MimeMode = MM_PASS8BIT; 1922 break; 1923 1924 case 'a': /* encode 8 bit if available */ 1925 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1926 break; 1927 1928 case 'c': /* convert 8 bit to MIME, never 7 bit */ 1929 MimeMode = MM_MIME8BIT; 1930 break; 1931 # endif /* 0 */ 1932 1933 default: 1934 syserr("Unknown 8-bit mode %c", *val); 1935 finis(FALSE, EX_USAGE); 1936 } 1937 #else /* MIME8TO7 */ 1938 printf("Warning: Option EightBitMode requires MIME8TO7 support\n"); 1939 #endif /* MIME8TO7 */ 1940 break; 1941 1942 case 'A': /* set default alias file */ 1943 if (val[0] == '\0') 1944 setalias("aliases"); 1945 else 1946 setalias(val); 1947 break; 1948 1949 case 'a': /* look N minutes for "@:@" in alias file */ 1950 if (val[0] == '\0') 1951 SafeAlias = 5 * 60; /* five minutes */ 1952 else 1953 SafeAlias = convtime(val, 'm'); 1954 break; 1955 1956 case 'B': /* substitution for blank character */ 1957 SpaceSub = val[0]; 1958 if (SpaceSub == '\0') 1959 SpaceSub = ' '; 1960 break; 1961 1962 case 'b': /* min blocks free on queue fs/max msg size */ 1963 p = strchr(val, '/'); 1964 if (p != NULL) 1965 { 1966 *p++ = '\0'; 1967 MaxMessageSize = atol(p); 1968 } 1969 MinBlocksFree = atol(val); 1970 break; 1971 1972 case 'c': /* don't connect to "expensive" mailers */ 1973 NoConnect = atobool(val); 1974 break; 1975 1976 case 'C': /* checkpoint every N addresses */ 1977 CheckpointInterval = atoi(val); 1978 break; 1979 1980 case 'd': /* delivery mode */ 1981 switch (*val) 1982 { 1983 case '\0': 1984 set_delivery_mode(SM_DELIVER, e); 1985 break; 1986 1987 case SM_QUEUE: /* queue only */ 1988 case SM_DEFER: /* queue only and defer map lookups */ 1989 #if !QUEUE 1990 syserr("need QUEUE to set -odqueue or -oddefer"); 1991 break; 1992 #endif /* !QUEUE */ 1993 /* FALLTHROUGH */ 1994 1995 case SM_DELIVER: /* do everything */ 1996 case SM_FORK: /* fork after verification */ 1997 set_delivery_mode(*val, e); 1998 break; 1999 2000 default: 2001 syserr("Unknown delivery mode %c", *val); 2002 finis(FALSE, EX_USAGE); 2003 } 2004 break; 2005 2006 #if !_FFR_REMOVE_AUTOREBUILD 2007 case 'D': /* rebuild alias database as needed */ 2008 AutoRebuild = atobool(val); 2009 break; 2010 #endif /* !_FFR_REMOVE_AUTOREBUILD */ 2011 2012 case 'E': /* error message header/header file */ 2013 if (*val != '\0') 2014 ErrMsgFile = newstr(val); 2015 break; 2016 2017 case 'e': /* set error processing mode */ 2018 switch (*val) 2019 { 2020 case EM_QUIET: /* be silent about it */ 2021 case EM_MAIL: /* mail back */ 2022 case EM_BERKNET: /* do berknet error processing */ 2023 case EM_WRITE: /* write back (or mail) */ 2024 case EM_PRINT: /* print errors normally (default) */ 2025 e->e_errormode = *val; 2026 break; 2027 } 2028 break; 2029 2030 case 'F': /* file mode */ 2031 FileMode = atooct(val) & 0777; 2032 break; 2033 2034 case 'f': /* save Unix-style From lines on front */ 2035 SaveFrom = atobool(val); 2036 break; 2037 2038 case 'G': /* match recipients against GECOS field */ 2039 MatchGecos = atobool(val); 2040 break; 2041 2042 case 'g': /* default gid */ 2043 g_opt: 2044 if (isascii(*val) && isdigit(*val)) 2045 DefGid = atoi(val); 2046 else 2047 { 2048 register struct group *gr; 2049 2050 DefGid = -1; 2051 gr = getgrnam(val); 2052 if (gr == NULL) 2053 syserr("readcf: option %c: unknown group %s", 2054 opt, val); 2055 else 2056 DefGid = gr->gr_gid; 2057 } 2058 break; 2059 2060 case 'H': /* help file */ 2061 if (val[0] == '\0') 2062 HelpFile = "helpfile"; 2063 else 2064 { 2065 HelpFile = newstr(val); 2066 } 2067 break; 2068 2069 case 'h': /* maximum hop count */ 2070 MaxHopCount = atoi(val); 2071 break; 2072 2073 case 'I': /* use internet domain name server */ 2074 #if NAMED_BIND 2075 for (p = val; *p != 0; ) 2076 { 2077 bool clearmode; 2078 char *q; 2079 struct resolverflags *rfp; 2080 2081 while (*p == ' ') 2082 p++; 2083 if (*p == '\0') 2084 break; 2085 clearmode = FALSE; 2086 if (*p == '-') 2087 clearmode = TRUE; 2088 else if (*p != '+') 2089 p--; 2090 p++; 2091 q = p; 2092 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2093 p++; 2094 if (*p != '\0') 2095 *p++ = '\0'; 2096 if (strcasecmp(q, "HasWildcardMX") == 0) 2097 { 2098 HasWildcardMX = !clearmode; 2099 continue; 2100 } 2101 #if _FFR_WORKAROUND_BROKEN_NAMESERVERS 2102 if (sm_strcasecmp(q, "WorkAroundBrokenAAAA") == 0) 2103 { 2104 WorkAroundBrokenAAAA = !clearmode; 2105 continue; 2106 } 2107 #endif /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */ 2108 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 2109 { 2110 if (strcasecmp(q, rfp->rf_name) == 0) 2111 break; 2112 } 2113 if (rfp->rf_name == NULL) 2114 syserr("readcf: I option value %s unrecognized", q); 2115 else if (clearmode) 2116 _res.options &= ~rfp->rf_bits; 2117 else 2118 _res.options |= rfp->rf_bits; 2119 } 2120 if (tTd(8, 2)) 2121 dprintf("_res.options = %x, HasWildcardMX = %d\n", 2122 (u_int) _res.options, HasWildcardMX); 2123 #else /* NAMED_BIND */ 2124 usrerr("name server (I option) specified but BIND not compiled in"); 2125 #endif /* NAMED_BIND */ 2126 break; 2127 2128 case 'i': /* ignore dot lines in message */ 2129 IgnrDot = atobool(val); 2130 break; 2131 2132 case 'j': /* send errors in MIME (RFC 1341) format */ 2133 SendMIMEErrors = atobool(val); 2134 break; 2135 2136 case 'J': /* .forward search path */ 2137 ForwardPath = newstr(val); 2138 break; 2139 2140 case 'k': /* connection cache size */ 2141 MaxMciCache = atoi(val); 2142 if (MaxMciCache < 0) 2143 MaxMciCache = 0; 2144 break; 2145 2146 case 'K': /* connection cache timeout */ 2147 MciCacheTimeout = convtime(val, 'm'); 2148 break; 2149 2150 case 'l': /* use Errors-To: header */ 2151 UseErrorsTo = atobool(val); 2152 break; 2153 2154 case 'L': /* log level */ 2155 if (safe || LogLevel < atoi(val)) 2156 LogLevel = atoi(val); 2157 break; 2158 2159 case 'M': /* define macro */ 2160 sticky = FALSE; 2161 mid = macid(val, &ep); 2162 if (mid == 0) 2163 break; 2164 p = newstr(ep); 2165 if (!safe) 2166 cleanstrcpy(p, p, MAXNAME); 2167 define(mid, p, CurEnv); 2168 break; 2169 2170 case 'm': /* send to me too */ 2171 MeToo = atobool(val); 2172 break; 2173 2174 case 'n': /* validate RHS in newaliases */ 2175 CheckAliases = atobool(val); 2176 break; 2177 2178 /* 'N' available -- was "net name" */ 2179 2180 case 'O': /* daemon options */ 2181 #if DAEMON 2182 if (!setdaemonoptions(val)) 2183 syserr("too many daemons defined (%d max)", MAXDAEMONS); 2184 #else /* DAEMON */ 2185 syserr("DaemonPortOptions (O option) set but DAEMON not compiled in"); 2186 #endif /* DAEMON */ 2187 break; 2188 2189 case 'o': /* assume old style headers */ 2190 if (atobool(val)) 2191 CurEnv->e_flags |= EF_OLDSTYLE; 2192 else 2193 CurEnv->e_flags &= ~EF_OLDSTYLE; 2194 break; 2195 2196 case 'p': /* select privacy level */ 2197 p = val; 2198 for (;;) 2199 { 2200 register struct prival *pv; 2201 extern struct prival PrivacyValues[]; 2202 2203 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 2204 p++; 2205 if (*p == '\0') 2206 break; 2207 val = p; 2208 while (isascii(*p) && isalnum(*p)) 2209 p++; 2210 if (*p != '\0') 2211 *p++ = '\0'; 2212 2213 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 2214 { 2215 if (strcasecmp(val, pv->pv_name) == 0) 2216 break; 2217 } 2218 if (pv->pv_name == NULL) 2219 syserr("readcf: Op line: %s unrecognized", val); 2220 else 2221 PrivacyFlags |= pv->pv_flag; 2222 } 2223 sticky = FALSE; 2224 break; 2225 2226 case 'P': /* postmaster copy address for returned mail */ 2227 PostMasterCopy = newstr(val); 2228 break; 2229 2230 case 'q': /* slope of queue only function */ 2231 QueueFactor = atoi(val); 2232 break; 2233 2234 case 'Q': /* queue directory */ 2235 if (val[0] == '\0') 2236 { 2237 QueueDir = "mqueue"; 2238 } 2239 else 2240 { 2241 QueueDir = newstr(val); 2242 } 2243 if (RealUid != 0 && !safe) 2244 Warn_Q_option = TRUE; 2245 break; 2246 2247 case 'R': /* don't prune routes */ 2248 DontPruneRoutes = atobool(val); 2249 break; 2250 2251 case 'r': /* read timeout */ 2252 if (subopt == NULL) 2253 inittimeouts(val, sticky); 2254 else 2255 settimeout(subopt, val, sticky); 2256 break; 2257 2258 case 'S': /* status file */ 2259 if (val[0] == '\0') 2260 StatFile = "statistics"; 2261 else 2262 { 2263 StatFile = newstr(val); 2264 } 2265 break; 2266 2267 case 's': /* be super safe, even if expensive */ 2268 SuperSafe = atobool(val); 2269 break; 2270 2271 case 'T': /* queue timeout */ 2272 p = strchr(val, '/'); 2273 if (p != NULL) 2274 { 2275 *p++ = '\0'; 2276 settimeout("queuewarn", p, sticky); 2277 } 2278 settimeout("queuereturn", val, sticky); 2279 break; 2280 2281 case 't': /* time zone name */ 2282 TimeZoneSpec = newstr(val); 2283 break; 2284 2285 case 'U': /* location of user database */ 2286 UdbSpec = newstr(val); 2287 break; 2288 2289 case 'u': /* set default uid */ 2290 for (p = val; *p != '\0'; p++) 2291 { 2292 if (*p == '.' || *p == '/' || *p == ':') 2293 { 2294 *p++ = '\0'; 2295 break; 2296 } 2297 } 2298 if (isascii(*val) && isdigit(*val)) 2299 { 2300 DefUid = atoi(val); 2301 setdefuser(); 2302 } 2303 else 2304 { 2305 register struct passwd *pw; 2306 2307 DefUid = -1; 2308 pw = sm_getpwnam(val); 2309 if (pw == NULL) 2310 { 2311 syserr("readcf: option u: unknown user %s", val); 2312 break; 2313 } 2314 else 2315 { 2316 DefUid = pw->pw_uid; 2317 DefGid = pw->pw_gid; 2318 DefUser = newstr(pw->pw_name); 2319 } 2320 } 2321 2322 #ifdef UID_MAX 2323 if (DefUid > UID_MAX) 2324 { 2325 syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored", 2326 (long) DefUid, (long) UID_MAX); 2327 break; 2328 } 2329 #endif /* UID_MAX */ 2330 2331 /* handle the group if it is there */ 2332 if (*p == '\0') 2333 break; 2334 val = p; 2335 goto g_opt; 2336 2337 case 'V': /* fallback MX host */ 2338 if (val[0] != '\0') 2339 FallBackMX = newstr(val); 2340 break; 2341 2342 case 'v': /* run in verbose mode */ 2343 Verbose = atobool(val) ? 1 : 0; 2344 break; 2345 2346 case 'w': /* if we are best MX, try host directly */ 2347 TryNullMXList = atobool(val); 2348 break; 2349 2350 /* 'W' available -- was wizard password */ 2351 2352 case 'x': /* load avg at which to auto-queue msgs */ 2353 QueueLA = atoi(val); 2354 break; 2355 2356 case 'X': /* load avg at which to auto-reject connections */ 2357 RefuseLA = atoi(val); 2358 break; 2359 2360 case 'y': /* work recipient factor */ 2361 WkRecipFact = atoi(val); 2362 break; 2363 2364 case 'Y': /* fork jobs during queue runs */ 2365 ForkQueueRuns = atobool(val); 2366 break; 2367 2368 case 'z': /* work message class factor */ 2369 WkClassFact = atoi(val); 2370 break; 2371 2372 case 'Z': /* work time factor */ 2373 WkTimeFact = atoi(val); 2374 break; 2375 2376 2377 case O_QUEUESORTORD: /* queue sorting order */ 2378 switch (*val) 2379 { 2380 case 'h': /* Host first */ 2381 case 'H': 2382 QueueSortOrder = QSO_BYHOST; 2383 break; 2384 2385 case 'p': /* Priority order */ 2386 case 'P': 2387 QueueSortOrder = QSO_BYPRIORITY; 2388 break; 2389 2390 case 't': /* Submission time */ 2391 case 'T': 2392 QueueSortOrder = QSO_BYTIME; 2393 break; 2394 2395 case 'f': /* File Name */ 2396 case 'F': 2397 QueueSortOrder = QSO_BYFILENAME; 2398 break; 2399 2400 default: 2401 syserr("Invalid queue sort order \"%s\"", val); 2402 } 2403 break; 2404 2405 #if _FFR_QUEUEDELAY 2406 case O_QUEUEDELAY: /* queue delay algorithm */ 2407 switch (*val) 2408 { 2409 case 'e': /* exponential */ 2410 case 'E': 2411 QueueAlg = QD_EXP; 2412 QueueInitDelay = 10 MINUTES; 2413 QueueMaxDelay = 2 HOURS; 2414 p = strchr(val, '/'); 2415 if (p != NULL) 2416 { 2417 char *q; 2418 2419 *p++ = '\0'; 2420 q = strchr(p, '/'); 2421 if (q != NULL) 2422 *q++ = '\0'; 2423 QueueInitDelay = convtime(p, 's'); 2424 if (q != NULL) 2425 { 2426 QueueMaxDelay = convtime(q, 's'); 2427 } 2428 } 2429 break; 2430 2431 case 'l': /* linear */ 2432 case 'L': 2433 QueueAlg = QD_LINEAR; 2434 break; 2435 2436 default: 2437 syserr("Invalid queue delay algorithm \"%s\"", val); 2438 } 2439 break; 2440 #endif /* _FFR_QUEUEDELAY */ 2441 2442 case O_HOSTSFILE: /* pathname of /etc/hosts file */ 2443 HostsFile = newstr(val); 2444 break; 2445 2446 case O_MQA: /* minimum queue age between deliveries */ 2447 MinQueueAge = convtime(val, 'm'); 2448 break; 2449 2450 case O_DEFCHARSET: /* default character set for mimefying */ 2451 DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 2452 break; 2453 2454 case O_SSFILE: /* service switch file */ 2455 ServiceSwitchFile = newstr(val); 2456 break; 2457 2458 case O_DIALDELAY: /* delay for dial-on-demand operation */ 2459 DialDelay = convtime(val, 's'); 2460 break; 2461 2462 case O_NORCPTACTION: /* what to do if no recipient */ 2463 if (strcasecmp(val, "none") == 0) 2464 NoRecipientAction = NRA_NO_ACTION; 2465 else if (strcasecmp(val, "add-to") == 0) 2466 NoRecipientAction = NRA_ADD_TO; 2467 else if (strcasecmp(val, "add-apparently-to") == 0) 2468 NoRecipientAction = NRA_ADD_APPARENTLY_TO; 2469 else if (strcasecmp(val, "add-bcc") == 0) 2470 NoRecipientAction = NRA_ADD_BCC; 2471 else if (strcasecmp(val, "add-to-undisclosed") == 0) 2472 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 2473 else 2474 syserr("Invalid NoRecipientAction: %s", val); 2475 break; 2476 2477 case O_SAFEFILEENV: /* chroot() environ for writing to files */ 2478 SafeFileEnv = newstr(val); 2479 break; 2480 2481 case O_MAXMSGSIZE: /* maximum message size */ 2482 MaxMessageSize = atol(val); 2483 break; 2484 2485 case O_COLONOKINADDR: /* old style handling of colon addresses */ 2486 ColonOkInAddr = atobool(val); 2487 break; 2488 2489 case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 2490 MaxQueueRun = atol(val); 2491 break; 2492 2493 case O_MAXCHILDREN: /* max # of children of daemon */ 2494 MaxChildren = atoi(val); 2495 break; 2496 2497 #if _FFR_MAX_FORWARD_ENTRIES 2498 case O_MAXFORWARD: /* max # of forward entries */ 2499 MaxForwardEntries = atoi(val); 2500 break; 2501 #endif /* _FFR_MAX_FORWARD_ENTRIES */ 2502 2503 case O_KEEPCNAMES: /* don't expand CNAME records */ 2504 DontExpandCnames = atobool(val); 2505 break; 2506 2507 case O_MUSTQUOTE: /* must quote these characters in phrases */ 2508 (void) strlcpy(buf, "@,;:\\()[]", sizeof buf); 2509 if (strlen(val) < (SIZE_T) sizeof buf - 10) 2510 (void) strlcat(buf, val, sizeof buf); 2511 else 2512 printf("Warning: MustQuoteChars too long, ignored.\n"); 2513 MustQuoteChars = newstr(buf); 2514 break; 2515 2516 case O_SMTPGREETING: /* SMTP greeting message (old $e macro) */ 2517 SmtpGreeting = newstr(munchstring(val, NULL, '\0')); 2518 break; 2519 2520 case O_UNIXFROM: /* UNIX From_ line (old $l macro) */ 2521 UnixFromLine = newstr(munchstring(val, NULL, '\0')); 2522 break; 2523 2524 case O_OPCHARS: /* operator characters (old $o macro) */ 2525 if (OperatorChars != NULL) 2526 printf("Warning: OperatorChars is being redefined.\n It should only be set before ruleset definitions.\n"); 2527 OperatorChars = newstr(munchstring(val, NULL, '\0')); 2528 break; 2529 2530 case O_DONTINITGRPS: /* don't call initgroups(3) */ 2531 DontInitGroups = atobool(val); 2532 break; 2533 2534 case O_SLFH: /* make sure from fits on one line */ 2535 SingleLineFromHeader = atobool(val); 2536 break; 2537 2538 case O_ABH: /* allow HELO commands with syntax errors */ 2539 AllowBogusHELO = atobool(val); 2540 break; 2541 2542 case O_CONNTHROT: /* connection rate throttle */ 2543 ConnRateThrottle = atoi(val); 2544 break; 2545 2546 case O_UGW: /* group writable files are unsafe */ 2547 if (!atobool(val)) 2548 { 2549 setbitn(DBS_GROUPWRITABLEFORWARDFILESAFE, 2550 DontBlameSendmail); 2551 setbitn(DBS_GROUPWRITABLEINCLUDEFILESAFE, 2552 DontBlameSendmail); 2553 } 2554 break; 2555 2556 case O_DBLBOUNCE: /* address to which to send double bounces */ 2557 if (val[0] != '\0') 2558 DoubleBounceAddr = newstr(val); 2559 else 2560 syserr("readcf: option DoubleBounceAddress: value required"); 2561 break; 2562 2563 case O_HSDIR: /* persistent host status directory */ 2564 if (val[0] != '\0') 2565 { 2566 HostStatDir = newstr(val); 2567 } 2568 break; 2569 2570 case O_SINGTHREAD: /* single thread deliveries (requires hsdir) */ 2571 SingleThreadDelivery = atobool(val); 2572 break; 2573 2574 case O_RUNASUSER: /* run bulk of code as this user */ 2575 for (p = val; *p != '\0'; p++) 2576 { 2577 if (*p == '.' || *p == '/' || *p == ':') 2578 { 2579 *p++ = '\0'; 2580 break; 2581 } 2582 } 2583 if (isascii(*val) && isdigit(*val)) 2584 { 2585 if (can_setuid) 2586 RunAsUid = atoi(val); 2587 } 2588 else 2589 { 2590 register struct passwd *pw; 2591 2592 pw = sm_getpwnam(val); 2593 if (pw == NULL) 2594 { 2595 syserr("readcf: option RunAsUser: unknown user %s", val); 2596 break; 2597 } 2598 else if (can_setuid) 2599 { 2600 if (*p == '\0') 2601 RunAsUserName = newstr(val); 2602 RunAsUid = pw->pw_uid; 2603 RunAsGid = pw->pw_gid; 2604 } 2605 } 2606 #ifdef UID_MAX 2607 if (RunAsUid > UID_MAX) 2608 { 2609 syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored", 2610 (long) RunAsUid, (long) UID_MAX); 2611 break; 2612 } 2613 #endif /* UID_MAX */ 2614 if (*p != '\0') 2615 { 2616 if (isascii(*p) && isdigit(*p)) 2617 { 2618 if (can_setuid) 2619 RunAsGid = atoi(p); 2620 } 2621 else 2622 { 2623 register struct group *gr; 2624 2625 gr = getgrnam(p); 2626 if (gr == NULL) 2627 syserr("readcf: option RunAsUser: unknown group %s", 2628 p); 2629 else if (can_setuid) 2630 RunAsGid = gr->gr_gid; 2631 } 2632 } 2633 if (tTd(47, 5)) 2634 dprintf("readcf: RunAsUser = %d:%d\n", 2635 (int)RunAsUid, (int)RunAsGid); 2636 break; 2637 2638 case O_DSN_RRT: 2639 RrtImpliesDsn = atobool(val); 2640 break; 2641 2642 case O_PIDFILE: 2643 if (PidFile != NULL) 2644 sm_free(PidFile); 2645 PidFile = newstr(val); 2646 break; 2647 2648 case O_DONTBLAMESENDMAIL: 2649 p = val; 2650 for (;;) 2651 { 2652 register struct dbsval *dbs; 2653 extern struct dbsval DontBlameSendmailValues[]; 2654 2655 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 2656 p++; 2657 if (*p == '\0') 2658 break; 2659 val = p; 2660 while (isascii(*p) && isalnum(*p)) 2661 p++; 2662 if (*p != '\0') 2663 *p++ = '\0'; 2664 2665 for (dbs = DontBlameSendmailValues; 2666 dbs->dbs_name != NULL; dbs++) 2667 { 2668 if (strcasecmp(val, dbs->dbs_name) == 0) 2669 break; 2670 } 2671 if (dbs->dbs_name == NULL) 2672 syserr("readcf: DontBlameSendmail option: %s unrecognized", val); 2673 else if (dbs->dbs_flag == DBS_SAFE) 2674 clrbitmap(DontBlameSendmail); 2675 else 2676 setbitn(dbs->dbs_flag, DontBlameSendmail); 2677 } 2678 sticky = FALSE; 2679 break; 2680 2681 case O_DPI: 2682 DontProbeInterfaces = atobool(val); 2683 break; 2684 2685 case O_MAXRCPT: 2686 MaxRcptPerMsg = atoi(val); 2687 break; 2688 2689 case O_DEADLETTER: 2690 if (DeadLetterDrop != NULL) 2691 sm_free(DeadLetterDrop); 2692 DeadLetterDrop = newstr(val); 2693 break; 2694 2695 #if _FFR_DONTLOCKFILESFORREAD_OPTION 2696 case O_DONTLOCK: 2697 DontLockReadFiles = atobool(val); 2698 break; 2699 #endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */ 2700 2701 case O_MAXALIASRCSN: 2702 MaxAliasRecursion = atoi(val); 2703 break; 2704 2705 case O_CNCTONLYTO: 2706 /* XXX should probably use gethostbyname */ 2707 #if NETINET || NETINET6 2708 # if NETINET6 2709 if (inet_addr(val) == INADDR_NONE) 2710 { 2711 ConnectOnlyTo.sa.sa_family = AF_INET6; 2712 if (inet_pton(AF_INET6, val, 2713 &ConnectOnlyTo.sin6.sin6_addr) != 1) 2714 syserr("readcf: option ConnectOnlyTo: invalid IP address %s", 2715 val); 2716 } 2717 else 2718 # endif /* NETINET6 */ 2719 { 2720 ConnectOnlyTo.sa.sa_family = AF_INET; 2721 ConnectOnlyTo.sin.sin_addr.s_addr = inet_addr(val); 2722 } 2723 #endif /* NETINET || NETINET6 */ 2724 break; 2725 2726 case O_TRUSTUSER: 2727 #if HASFCHOWN 2728 if (isascii(*val) && isdigit(*val)) 2729 TrustedUid = atoi(val); 2730 else 2731 { 2732 register struct passwd *pw; 2733 2734 TrustedUid = 0; 2735 pw = sm_getpwnam(val); 2736 if (pw == NULL) 2737 { 2738 syserr("readcf: option TrustedUser: unknown user %s", val); 2739 break; 2740 } 2741 else 2742 TrustedUid = pw->pw_uid; 2743 } 2744 2745 # ifdef UID_MAX 2746 if (TrustedUid > UID_MAX) 2747 { 2748 syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)", 2749 (long) TrustedUid, (long) UID_MAX); 2750 TrustedUid = 0; 2751 } 2752 # endif /* UID_MAX */ 2753 #else /* HASFCHOWN */ 2754 syserr("readcf: option TrustedUser: can not be used on systems which do not support fchown()"); 2755 #endif /* HASFCHOWN */ 2756 break; 2757 2758 case O_MAXMIMEHDRLEN: 2759 p = strchr(val, '/'); 2760 if (p != NULL) 2761 *p++ = '\0'; 2762 MaxMimeHeaderLength = atoi(val); 2763 if (p != NULL && *p != '\0') 2764 MaxMimeFieldLength = atoi(p); 2765 else 2766 MaxMimeFieldLength = MaxMimeHeaderLength / 2; 2767 2768 if (MaxMimeHeaderLength < 0) 2769 MaxMimeHeaderLength = 0; 2770 else if (MaxMimeHeaderLength < 128) 2771 printf("Warning: MaxMimeHeaderLength: header length limit set lower than 128\n"); 2772 2773 if (MaxMimeFieldLength < 0) 2774 MaxMimeFieldLength = 0; 2775 else if (MaxMimeFieldLength < 40) 2776 printf("Warning: MaxMimeHeaderLength: field length limit set lower than 40\n"); 2777 break; 2778 2779 case O_CONTROLSOCKET: 2780 if (ControlSocketName != NULL) 2781 sm_free(ControlSocketName); 2782 ControlSocketName = newstr(val); 2783 break; 2784 2785 case O_MAXHDRSLEN: 2786 MaxHeadersLength = atoi(val); 2787 2788 if (MaxHeadersLength > 0 && 2789 MaxHeadersLength < (MAXHDRSLEN / 2)) 2790 printf("Warning: MaxHeadersLength: headers length limit set lower than %d\n", (MAXHDRSLEN / 2)); 2791 break; 2792 2793 case O_PROCTITLEPREFIX: 2794 if (ProcTitlePrefix != NULL) 2795 sm_free(ProcTitlePrefix); 2796 ProcTitlePrefix = newstr(val); 2797 break; 2798 2799 #if SASL 2800 case O_SASLINFO: 2801 #if _FFR_ALLOW_SASLINFO 2802 /* 2803 ** Allow users to select their own authinfo file. 2804 ** However, this is not a "perfect" solution. 2805 ** If mail is queued, the authentication info 2806 ** will not be used in subsequent delivery attempts. 2807 ** If we really want to support this, then it has 2808 ** to be stored in the queue file. 2809 */ 2810 if (!bitset(SUBMIT_MSA, SubmitMode) && RealUid != 0 && 2811 RunAsUid != RealUid) 2812 { 2813 errno = 0; 2814 syserr("Error: %s only allowed with -U\n", 2815 o->o_name == NULL ? "<unknown>" : o->o_name); 2816 ExitStat = EX_USAGE; 2817 break; 2818 } 2819 #endif /* _FFR_ALLOW_SASLINFO */ 2820 if (SASLInfo != NULL) 2821 sm_free(SASLInfo); 2822 SASLInfo = newstr(val); 2823 break; 2824 2825 case O_SASLMECH: 2826 if (AuthMechanisms != NULL) 2827 sm_free(AuthMechanisms); 2828 if (*val != '\0') 2829 AuthMechanisms = newstr(val); 2830 else 2831 AuthMechanisms = NULL; 2832 break; 2833 2834 case O_SASLOPTS: 2835 while (val != NULL && *val != '\0') 2836 { 2837 switch(*val) 2838 { 2839 case 'A': 2840 SASLOpts |= SASL_AUTH_AUTH; 2841 break; 2842 # if _FFR_SASL_OPTS 2843 case 'a': 2844 SASLOpts |= SASL_SEC_NOACTIVE; 2845 break; 2846 case 'c': 2847 SASLOpts |= SASL_SEC_PASS_CREDENTIALS; 2848 break; 2849 case 'd': 2850 SASLOpts |= SASL_SEC_NODICTIONARY; 2851 break; 2852 case 'f': 2853 SASLOpts |= SASL_SEC_FORWARD_SECRECY; 2854 break; 2855 case 'p': 2856 SASLOpts |= SASL_SEC_NOPLAINTEXT; 2857 break; 2858 case 'y': 2859 SASLOpts |= SASL_SEC_NOANONYMOUS; 2860 break; 2861 # endif /* _FFR_SASL_OPTS */ 2862 default: 2863 printf("Warning: Option: %s unknown parameter '%c'\n", 2864 o->o_name == NULL ? "<unknown>" 2865 : o->o_name, 2866 (isascii(*val) && isprint(*val)) ? *val 2867 : '?'); 2868 break; 2869 } 2870 ++val; 2871 val = strpbrk(val, ", \t"); 2872 if (val != NULL) 2873 ++val; 2874 } 2875 break; 2876 2877 #else /* SASL */ 2878 case O_SASLINFO: 2879 case O_SASLMECH: 2880 case O_SASLOPTS: 2881 printf("Warning: Option: %s requires SASL support (-DSASL)\n", 2882 o->o_name == NULL ? "<unknown>" : o->o_name); 2883 break; 2884 #endif /* SASL */ 2885 2886 #if STARTTLS 2887 case O_SRVCERTFILE: 2888 if (SrvCERTfile != NULL) 2889 sm_free(SrvCERTfile); 2890 SrvCERTfile = newstr(val); 2891 break; 2892 2893 case O_SRVKEYFILE: 2894 if (Srvkeyfile != NULL) 2895 sm_free(Srvkeyfile); 2896 Srvkeyfile = newstr(val); 2897 break; 2898 2899 case O_CLTCERTFILE: 2900 if (CltCERTfile != NULL) 2901 sm_free(CltCERTfile); 2902 CltCERTfile = newstr(val); 2903 break; 2904 2905 case O_CLTKEYFILE: 2906 if (Cltkeyfile != NULL) 2907 sm_free(Cltkeyfile); 2908 Cltkeyfile = newstr(val); 2909 break; 2910 2911 case O_CACERTFILE: 2912 if (CACERTfile != NULL) 2913 sm_free(CACERTfile); 2914 CACERTfile = newstr(val); 2915 break; 2916 2917 case O_CACERTPATH: 2918 if (CACERTpath != NULL) 2919 sm_free(CACERTpath); 2920 CACERTpath = newstr(val); 2921 break; 2922 2923 case O_DHPARAMS: 2924 if (DHParams != NULL) 2925 sm_free(DHParams); 2926 DHParams = newstr(val); 2927 break; 2928 2929 # if _FFR_TLS_1 2930 case O_DHPARAMS5: 2931 if (DHParams5 != NULL) 2932 sm_free(DHParams5); 2933 DHParams5 = newstr(val); 2934 break; 2935 2936 case O_CIPHERLIST: 2937 if (CipherList != NULL) 2938 sm_free(CipherList); 2939 CipherList = newstr(val); 2940 break; 2941 # endif /* _FFR_TLS_1 */ 2942 2943 case O_RANDFILE: 2944 if (RandFile != NULL) 2945 sm_free(RandFile); 2946 RandFile= newstr(val); 2947 break; 2948 2949 # else /* STARTTLS */ 2950 case O_SRVCERTFILE: 2951 case O_SRVKEYFILE: 2952 case O_CLTCERTFILE: 2953 case O_CLTKEYFILE: 2954 case O_CACERTFILE: 2955 case O_CACERTPATH: 2956 case O_DHPARAMS: 2957 # if _FFR_TLS_1 2958 case O_DHPARAMS5: 2959 case O_CIPHERLIST: 2960 # endif /* _FFR_TLS_1 */ 2961 case O_RANDFILE: 2962 printf("Warning: Option: %s requires TLS support\n", 2963 o->o_name == NULL ? "<unknown>" : o->o_name); 2964 break; 2965 2966 # endif /* STARTTLS */ 2967 2968 case O_CLIENTPORT: 2969 #if DAEMON 2970 setclientoptions(val); 2971 #else /* DAEMON */ 2972 syserr("ClientPortOptions (O option) set but DAEMON not compiled in"); 2973 #endif /* DAEMON */ 2974 break; 2975 2976 case O_DF_BUFSIZE: 2977 DataFileBufferSize = atoi(val); 2978 break; 2979 2980 case O_XF_BUFSIZE: 2981 XscriptFileBufferSize = atoi(val); 2982 break; 2983 2984 case O_LDAPDEFAULTSPEC: 2985 #ifdef LDAPMAP 2986 ldapmap_set_defaults(val); 2987 #else /* LDAPMAP */ 2988 printf("Warning: Option: %s requires LDAP support (-DLDAPMAP)\n", 2989 o->o_name == NULL ? "<unknown>" : o->o_name); 2990 #endif /* LDAPMAP */ 2991 break; 2992 2993 #if _FFR_MILTER 2994 case O_INPUTMILTER: 2995 InputFilterList = newstr(val); 2996 break; 2997 2998 case O_MILTER: 2999 milter_set_option(subopt, val, sticky); 3000 break; 3001 #endif /* _FFR_MILTER */ 3002 3003 #if _FFR_QUEUE_FILE_MODE 3004 case O_QUEUE_FILE_MODE: /* queue file mode */ 3005 QueueFileMode = atooct(val) & 0777; 3006 break; 3007 #endif /* _FFR_QUEUE_FILE_MODE */ 3008 3009 default: 3010 if (tTd(37, 1)) 3011 { 3012 if (isascii(opt) && isprint(opt)) 3013 dprintf("Warning: option %c unknown\n", opt); 3014 else 3015 dprintf("Warning: option 0x%x unknown\n", opt); 3016 } 3017 break; 3018 } 3019 3020 /* 3021 ** Options with suboptions are responsible for taking care 3022 ** of sticky-ness (e.g., that a command line setting is kept 3023 ** when reading in the sendmail.cf file). This has to be done 3024 ** when the suboptions are parsed since each suboption must be 3025 ** sticky, not the root option. 3026 */ 3027 3028 if (sticky && !bitset(OI_SUBOPT, o->o_flags)) 3029 setbitn(opt, StickyOpt); 3030 } 3031 /* 3032 ** SETCLASS -- set a string into a class 3033 ** 3034 ** Parameters: 3035 ** class -- the class to put the string in. 3036 ** str -- the string to enter 3037 ** 3038 ** Returns: 3039 ** none. 3040 ** 3041 ** Side Effects: 3042 ** puts the word into the symbol table. 3043 */ 3044 3045 void 3046 setclass(class, str) 3047 int class; 3048 char *str; 3049 { 3050 register STAB *s; 3051 3052 if ((*str & 0377) == MATCHCLASS) 3053 { 3054 int mid; 3055 3056 str++; 3057 mid = macid(str, NULL); 3058 if (mid == 0) 3059 return; 3060 3061 if (tTd(37, 8)) 3062 dprintf("setclass(%s, $=%s)\n", 3063 macname(class), macname(mid)); 3064 copy_class(mid, class); 3065 } 3066 else 3067 { 3068 if (tTd(37, 8)) 3069 dprintf("setclass(%s, %s)\n", macname(class), str); 3070 3071 s = stab(str, ST_CLASS, ST_ENTER); 3072 setbitn(bitidx(class), s->s_class); 3073 } 3074 } 3075 /* 3076 ** MAKEMAPENTRY -- create a map entry 3077 ** 3078 ** Parameters: 3079 ** line -- the config file line 3080 ** 3081 ** Returns: 3082 ** A pointer to the map that has been created. 3083 ** NULL if there was a syntax error. 3084 ** 3085 ** Side Effects: 3086 ** Enters the map into the dictionary. 3087 */ 3088 3089 MAP * 3090 makemapentry(line) 3091 char *line; 3092 { 3093 register char *p; 3094 char *mapname; 3095 char *classname; 3096 register STAB *s; 3097 STAB *class; 3098 3099 for (p = line; isascii(*p) && isspace(*p); p++) 3100 continue; 3101 if (!(isascii(*p) && isalnum(*p))) 3102 { 3103 syserr("readcf: config K line: no map name"); 3104 return NULL; 3105 } 3106 3107 mapname = p; 3108 while ((isascii(*++p) && isalnum(*p)) || *p == '_' || *p == '.') 3109 continue; 3110 if (*p != '\0') 3111 *p++ = '\0'; 3112 while (isascii(*p) && isspace(*p)) 3113 p++; 3114 if (!(isascii(*p) && isalnum(*p))) 3115 { 3116 syserr("readcf: config K line, map %s: no map class", mapname); 3117 return NULL; 3118 } 3119 classname = p; 3120 while (isascii(*++p) && isalnum(*p)) 3121 continue; 3122 if (*p != '\0') 3123 *p++ = '\0'; 3124 while (isascii(*p) && isspace(*p)) 3125 p++; 3126 3127 /* look up the class */ 3128 class = stab(classname, ST_MAPCLASS, ST_FIND); 3129 if (class == NULL) 3130 { 3131 syserr("readcf: map %s: class %s not available", mapname, classname); 3132 return NULL; 3133 } 3134 3135 /* enter the map */ 3136 s = stab(mapname, ST_MAP, ST_ENTER); 3137 s->s_map.map_class = &class->s_mapclass; 3138 s->s_map.map_mname = newstr(mapname); 3139 3140 if (class->s_mapclass.map_parse(&s->s_map, p)) 3141 s->s_map.map_mflags |= MF_VALID; 3142 3143 if (tTd(37, 5)) 3144 { 3145 dprintf("map %s, class %s, flags %lx, file %s,\n", 3146 s->s_map.map_mname, s->s_map.map_class->map_cname, 3147 s->s_map.map_mflags, 3148 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 3149 dprintf("\tapp %s, domain %s, rebuild %s\n", 3150 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 3151 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 3152 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 3153 } 3154 3155 return &s->s_map; 3156 } 3157 /* 3158 ** STRTORWSET -- convert string to rewriting set number 3159 ** 3160 ** Parameters: 3161 ** p -- the pointer to the string to decode. 3162 ** endp -- if set, store the trailing delimiter here. 3163 ** stabmode -- ST_ENTER to create this entry, ST_FIND if 3164 ** it must already exist. 3165 ** 3166 ** Returns: 3167 ** The appropriate ruleset number. 3168 ** -1 if it is not valid (error already printed) 3169 */ 3170 3171 int 3172 strtorwset(p, endp, stabmode) 3173 char *p; 3174 char **endp; 3175 int stabmode; 3176 { 3177 int ruleset; 3178 static int nextruleset = MAXRWSETS; 3179 3180 while (isascii(*p) && isspace(*p)) 3181 p++; 3182 if (!isascii(*p)) 3183 { 3184 syserr("invalid ruleset name: \"%.20s\"", p); 3185 return -1; 3186 } 3187 if (isdigit(*p)) 3188 { 3189 ruleset = strtol(p, endp, 10); 3190 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 3191 { 3192 syserr("bad ruleset %d (%d max)", 3193 ruleset, MAXRWSETS / 2); 3194 ruleset = -1; 3195 } 3196 } 3197 else 3198 { 3199 STAB *s; 3200 char delim; 3201 char *q = NULL; 3202 3203 q = p; 3204 while (*p != '\0' && isascii(*p) && 3205 (isalnum(*p) || *p == '_')) 3206 p++; 3207 if (q == p || !(isascii(*q) && isalpha(*q))) 3208 { 3209 /* no valid characters */ 3210 syserr("invalid ruleset name: \"%.20s\"", q); 3211 return -1; 3212 } 3213 while (isascii(*p) && isspace(*p)) 3214 *p++ = '\0'; 3215 delim = *p; 3216 if (delim != '\0') 3217 *p = '\0'; 3218 s = stab(q, ST_RULESET, stabmode); 3219 if (delim != '\0') 3220 *p = delim; 3221 3222 if (s == NULL) 3223 return -1; 3224 3225 if (stabmode == ST_ENTER && delim == '=') 3226 { 3227 while (isascii(*++p) && isspace(*p)) 3228 continue; 3229 if (!(isascii(*p) && isdigit(*p))) 3230 { 3231 syserr("bad ruleset definition \"%s\" (number required after `=')", q); 3232 ruleset = -1; 3233 } 3234 else 3235 { 3236 ruleset = strtol(p, endp, 10); 3237 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 3238 { 3239 syserr("bad ruleset number %d in \"%s\" (%d max)", 3240 ruleset, q, MAXRWSETS / 2); 3241 ruleset = -1; 3242 } 3243 } 3244 } 3245 else 3246 { 3247 if (endp != NULL) 3248 *endp = p; 3249 if (s->s_ruleset >= 0) 3250 ruleset = s->s_ruleset; 3251 else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 3252 { 3253 syserr("%s: too many named rulesets (%d max)", 3254 q, MAXRWSETS / 2); 3255 ruleset = -1; 3256 } 3257 } 3258 if (s->s_ruleset >= 0 && 3259 ruleset >= 0 && 3260 ruleset != s->s_ruleset) 3261 { 3262 syserr("%s: ruleset changed value (old %d, new %d)", 3263 q, s->s_ruleset, ruleset); 3264 ruleset = s->s_ruleset; 3265 } 3266 else if (ruleset >= 0) 3267 { 3268 s->s_ruleset = ruleset; 3269 } 3270 if (stabmode == ST_ENTER && ruleset >= 0) 3271 { 3272 char *h = NULL; 3273 3274 if (RuleSetNames[ruleset] != NULL) 3275 sm_free(RuleSetNames[ruleset]); 3276 if (delim != '\0' && (h = strchr(q, delim)) != NULL) 3277 *h = '\0'; 3278 RuleSetNames[ruleset] = newstr(q); 3279 if (delim == '/' && h != NULL) 3280 *h = delim; /* put back delim */ 3281 } 3282 } 3283 return ruleset; 3284 } 3285 /* 3286 ** SETTIMEOUT -- set an individual timeout 3287 ** 3288 ** Parameters: 3289 ** name -- the name of the timeout. 3290 ** val -- the value of the timeout. 3291 ** sticky -- if set, don't let other setoptions override 3292 ** this value. 3293 ** 3294 ** Returns: 3295 ** none. 3296 */ 3297 3298 /* set if Timeout sub-option is stuck */ 3299 static BITMAP256 StickyTimeoutOpt; 3300 3301 static struct timeoutinfo 3302 { 3303 char *to_name; /* long name of timeout */ 3304 u_char to_code; /* code for option */ 3305 } TimeOutTab[] = 3306 { 3307 #define TO_INITIAL 0x01 3308 { "initial", TO_INITIAL }, 3309 #define TO_MAIL 0x02 3310 { "mail", TO_MAIL }, 3311 #define TO_RCPT 0x03 3312 { "rcpt", TO_RCPT }, 3313 #define TO_DATAINIT 0x04 3314 { "datainit", TO_DATAINIT }, 3315 #define TO_DATABLOCK 0x05 3316 { "datablock", TO_DATABLOCK }, 3317 #define TO_DATAFINAL 0x06 3318 { "datafinal", TO_DATAFINAL }, 3319 #define TO_COMMAND 0x07 3320 { "command", TO_COMMAND }, 3321 #define TO_RSET 0x08 3322 { "rset", TO_RSET }, 3323 #define TO_HELO 0x09 3324 { "helo", TO_HELO }, 3325 #define TO_QUIT 0x0A 3326 { "quit", TO_QUIT }, 3327 #define TO_MISC 0x0B 3328 { "misc", TO_MISC }, 3329 #define TO_IDENT 0x0C 3330 { "ident", TO_IDENT }, 3331 #define TO_FILEOPEN 0x0D 3332 { "fileopen", TO_FILEOPEN }, 3333 #define TO_CONNECT 0x0E 3334 { "connect", TO_CONNECT }, 3335 #define TO_ICONNECT 0x0F 3336 { "iconnect", TO_ICONNECT }, 3337 #define TO_QUEUEWARN 0x10 3338 { "queuewarn", TO_QUEUEWARN }, 3339 { "queuewarn.*", TO_QUEUEWARN }, 3340 #define TO_QUEUEWARN_NORMAL 0x11 3341 { "queuewarn.normal", TO_QUEUEWARN_NORMAL }, 3342 #define TO_QUEUEWARN_URGENT 0x12 3343 { "queuewarn.urgent", TO_QUEUEWARN_URGENT }, 3344 #define TO_QUEUEWARN_NON_URGENT 0x13 3345 { "queuewarn.non-urgent", TO_QUEUEWARN_NON_URGENT }, 3346 #define TO_QUEUERETURN 0x14 3347 { "queuereturn", TO_QUEUERETURN }, 3348 { "queuereturn.*", TO_QUEUERETURN }, 3349 #define TO_QUEUERETURN_NORMAL 0x15 3350 { "queuereturn.normal", TO_QUEUERETURN_NORMAL }, 3351 #define TO_QUEUERETURN_URGENT 0x16 3352 { "queuereturn.urgent", TO_QUEUERETURN_URGENT }, 3353 #define TO_QUEUERETURN_NON_URGENT 0x17 3354 { "queuereturn.non-urgent", TO_QUEUERETURN_NON_URGENT }, 3355 #define TO_HOSTSTATUS 0x18 3356 { "hoststatus", TO_HOSTSTATUS }, 3357 #define TO_RESOLVER_RETRANS 0x19 3358 { "resolver.retrans", TO_RESOLVER_RETRANS }, 3359 #define TO_RESOLVER_RETRANS_NORMAL 0x1A 3360 { "resolver.retrans.normal", TO_RESOLVER_RETRANS_NORMAL }, 3361 #define TO_RESOLVER_RETRANS_FIRST 0x1B 3362 { "resolver.retrans.first", TO_RESOLVER_RETRANS_FIRST }, 3363 #define TO_RESOLVER_RETRY 0x1C 3364 { "resolver.retry", TO_RESOLVER_RETRY }, 3365 #define TO_RESOLVER_RETRY_NORMAL 0x1D 3366 { "resolver.retry.normal", TO_RESOLVER_RETRY_NORMAL }, 3367 #define TO_RESOLVER_RETRY_FIRST 0x1E 3368 { "resolver.retry.first", TO_RESOLVER_RETRY_FIRST }, 3369 #define TO_CONTROL 0x1F 3370 { "control", TO_CONTROL }, 3371 { NULL, 0 }, 3372 }; 3373 3374 3375 static void 3376 settimeout(name, val, sticky) 3377 char *name; 3378 char *val; 3379 bool sticky; 3380 { 3381 register struct timeoutinfo *to; 3382 int i; 3383 time_t toval; 3384 3385 if (tTd(37, 2)) 3386 dprintf("settimeout(%s = %s)", name, val); 3387 3388 for (to = TimeOutTab; to->to_name != NULL; to++) 3389 { 3390 if (strcasecmp(to->to_name, name) == 0) 3391 break; 3392 } 3393 3394 if (to->to_name == NULL) 3395 { 3396 errno = 0; /* avoid bogus error text */ 3397 syserr("settimeout: invalid timeout %s", name); 3398 return; 3399 } 3400 3401 /* 3402 ** See if this option is preset for us. 3403 */ 3404 3405 if (!sticky && bitnset(to->to_code, StickyTimeoutOpt)) 3406 { 3407 if (tTd(37, 2)) 3408 dprintf(" (ignored)\n"); 3409 return; 3410 } 3411 3412 if (tTd(37, 2)) 3413 dprintf("\n"); 3414 3415 toval = convtime(val, 'm'); 3416 3417 switch (to->to_code) 3418 { 3419 case TO_INITIAL: 3420 TimeOuts.to_initial = toval; 3421 break; 3422 3423 case TO_MAIL: 3424 TimeOuts.to_mail = toval; 3425 break; 3426 3427 case TO_RCPT: 3428 TimeOuts.to_rcpt = toval; 3429 break; 3430 3431 case TO_DATAINIT: 3432 TimeOuts.to_datainit = toval; 3433 break; 3434 3435 case TO_DATABLOCK: 3436 TimeOuts.to_datablock = toval; 3437 break; 3438 3439 case TO_DATAFINAL: 3440 TimeOuts.to_datafinal = toval; 3441 break; 3442 3443 case TO_COMMAND: 3444 TimeOuts.to_nextcommand = toval; 3445 break; 3446 3447 case TO_RSET: 3448 TimeOuts.to_rset = toval; 3449 break; 3450 3451 case TO_HELO: 3452 TimeOuts.to_helo = toval; 3453 break; 3454 3455 case TO_QUIT: 3456 TimeOuts.to_quit = toval; 3457 break; 3458 3459 case TO_MISC: 3460 TimeOuts.to_miscshort = toval; 3461 break; 3462 3463 case TO_IDENT: 3464 TimeOuts.to_ident = toval; 3465 break; 3466 3467 case TO_FILEOPEN: 3468 TimeOuts.to_fileopen = toval; 3469 break; 3470 3471 case TO_CONNECT: 3472 TimeOuts.to_connect = toval; 3473 break; 3474 3475 case TO_ICONNECT: 3476 TimeOuts.to_iconnect = toval; 3477 break; 3478 3479 case TO_QUEUEWARN: 3480 toval = convtime(val, 'h'); 3481 TimeOuts.to_q_warning[TOC_NORMAL] = toval; 3482 TimeOuts.to_q_warning[TOC_URGENT] = toval; 3483 TimeOuts.to_q_warning[TOC_NONURGENT] = toval; 3484 break; 3485 3486 case TO_QUEUEWARN_NORMAL: 3487 toval = convtime(val, 'h'); 3488 TimeOuts.to_q_warning[TOC_NORMAL] = toval; 3489 break; 3490 3491 case TO_QUEUEWARN_URGENT: 3492 toval = convtime(val, 'h'); 3493 TimeOuts.to_q_warning[TOC_URGENT] = toval; 3494 break; 3495 3496 case TO_QUEUEWARN_NON_URGENT: 3497 toval = convtime(val, 'h'); 3498 TimeOuts.to_q_warning[TOC_NONURGENT] = toval; 3499 break; 3500 3501 case TO_QUEUERETURN: 3502 toval = convtime(val, 'd'); 3503 TimeOuts.to_q_return[TOC_NORMAL] = toval; 3504 TimeOuts.to_q_return[TOC_URGENT] = toval; 3505 TimeOuts.to_q_return[TOC_NONURGENT] = toval; 3506 break; 3507 3508 case TO_QUEUERETURN_NORMAL: 3509 toval = convtime(val, 'd'); 3510 TimeOuts.to_q_return[TOC_NORMAL] = toval; 3511 break; 3512 3513 case TO_QUEUERETURN_URGENT: 3514 toval = convtime(val, 'd'); 3515 TimeOuts.to_q_return[TOC_URGENT] = toval; 3516 break; 3517 3518 case TO_QUEUERETURN_NON_URGENT: 3519 toval = convtime(val, 'd'); 3520 TimeOuts.to_q_return[TOC_NONURGENT] = toval; 3521 break; 3522 3523 3524 case TO_HOSTSTATUS: 3525 MciInfoTimeout = toval; 3526 break; 3527 3528 case TO_RESOLVER_RETRANS: 3529 toval = convtime(val, 's'); 3530 TimeOuts.res_retrans[RES_TO_DEFAULT] = toval; 3531 TimeOuts.res_retrans[RES_TO_FIRST] = toval; 3532 TimeOuts.res_retrans[RES_TO_NORMAL] = toval; 3533 break; 3534 3535 case TO_RESOLVER_RETRY: 3536 i = atoi(val); 3537 TimeOuts.res_retry[RES_TO_DEFAULT] = i; 3538 TimeOuts.res_retry[RES_TO_FIRST] = i; 3539 TimeOuts.res_retry[RES_TO_NORMAL] = i; 3540 break; 3541 3542 case TO_RESOLVER_RETRANS_NORMAL: 3543 TimeOuts.res_retrans[RES_TO_NORMAL] = convtime(val, 's'); 3544 break; 3545 3546 case TO_RESOLVER_RETRY_NORMAL: 3547 TimeOuts.res_retry[RES_TO_NORMAL] = atoi(val); 3548 break; 3549 3550 case TO_RESOLVER_RETRANS_FIRST: 3551 TimeOuts.res_retrans[RES_TO_FIRST] = convtime(val, 's'); 3552 break; 3553 3554 case TO_RESOLVER_RETRY_FIRST: 3555 TimeOuts.res_retry[RES_TO_FIRST] = atoi(val); 3556 break; 3557 3558 case TO_CONTROL: 3559 TimeOuts.to_control = toval; 3560 break; 3561 3562 default: 3563 syserr("settimeout: invalid timeout %s", name); 3564 break; 3565 } 3566 3567 if (sticky) 3568 setbitn(to->to_code, StickyTimeoutOpt); 3569 } 3570 /* 3571 ** INITTIMEOUTS -- parse and set timeout values 3572 ** 3573 ** Parameters: 3574 ** val -- a pointer to the values. If NULL, do initial 3575 ** settings. 3576 ** sticky -- if set, don't let other setoptions override 3577 ** this suboption value. 3578 ** 3579 ** Returns: 3580 ** none. 3581 ** 3582 ** Side Effects: 3583 ** Initializes the TimeOuts structure 3584 */ 3585 3586 void 3587 inittimeouts(val, sticky) 3588 register char *val; 3589 bool sticky; 3590 { 3591 register char *p; 3592 3593 if (tTd(37, 2)) 3594 dprintf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val); 3595 if (val == NULL) 3596 { 3597 TimeOuts.to_connect = (time_t) 0 SECONDS; 3598 TimeOuts.to_initial = (time_t) 5 MINUTES; 3599 TimeOuts.to_helo = (time_t) 5 MINUTES; 3600 TimeOuts.to_mail = (time_t) 10 MINUTES; 3601 TimeOuts.to_rcpt = (time_t) 1 HOUR; 3602 TimeOuts.to_datainit = (time_t) 5 MINUTES; 3603 TimeOuts.to_datablock = (time_t) 1 HOUR; 3604 TimeOuts.to_datafinal = (time_t) 1 HOUR; 3605 TimeOuts.to_rset = (time_t) 5 MINUTES; 3606 TimeOuts.to_quit = (time_t) 2 MINUTES; 3607 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 3608 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 3609 #if IDENTPROTO 3610 TimeOuts.to_ident = (time_t) 5 SECONDS; 3611 #else /* IDENTPROTO */ 3612 TimeOuts.to_ident = (time_t) 0 SECONDS; 3613 #endif /* IDENTPROTO */ 3614 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 3615 TimeOuts.to_control = (time_t) 2 MINUTES; 3616 if (tTd(37, 5)) 3617 { 3618 dprintf("Timeouts:\n"); 3619 dprintf(" connect = %ld\n", (long)TimeOuts.to_connect); 3620 dprintf(" initial = %ld\n", (long)TimeOuts.to_initial); 3621 dprintf(" helo = %ld\n", (long)TimeOuts.to_helo); 3622 dprintf(" mail = %ld\n", (long)TimeOuts.to_mail); 3623 dprintf(" rcpt = %ld\n", (long)TimeOuts.to_rcpt); 3624 dprintf(" datainit = %ld\n", (long)TimeOuts.to_datainit); 3625 dprintf(" datablock = %ld\n", (long)TimeOuts.to_datablock); 3626 dprintf(" datafinal = %ld\n", (long)TimeOuts.to_datafinal); 3627 dprintf(" rset = %ld\n", (long)TimeOuts.to_rset); 3628 dprintf(" quit = %ld\n", (long)TimeOuts.to_quit); 3629 dprintf(" nextcommand = %ld\n", (long)TimeOuts.to_nextcommand); 3630 dprintf(" miscshort = %ld\n", (long)TimeOuts.to_miscshort); 3631 dprintf(" ident = %ld\n", (long)TimeOuts.to_ident); 3632 dprintf(" fileopen = %ld\n", (long)TimeOuts.to_fileopen); 3633 dprintf(" control = %ld\n", (long)TimeOuts.to_control); 3634 } 3635 return; 3636 } 3637 3638 for (;; val = p) 3639 { 3640 while (isascii(*val) && isspace(*val)) 3641 val++; 3642 if (*val == '\0') 3643 break; 3644 for (p = val; *p != '\0' && *p != ','; p++) 3645 continue; 3646 if (*p != '\0') 3647 *p++ = '\0'; 3648 3649 if (isascii(*val) && isdigit(*val)) 3650 { 3651 /* old syntax -- set everything */ 3652 TimeOuts.to_mail = convtime(val, 'm'); 3653 TimeOuts.to_rcpt = TimeOuts.to_mail; 3654 TimeOuts.to_datainit = TimeOuts.to_mail; 3655 TimeOuts.to_datablock = TimeOuts.to_mail; 3656 TimeOuts.to_datafinal = TimeOuts.to_mail; 3657 TimeOuts.to_nextcommand = TimeOuts.to_mail; 3658 if (sticky) 3659 { 3660 setbitn(TO_MAIL, StickyTimeoutOpt); 3661 setbitn(TO_RCPT, StickyTimeoutOpt); 3662 setbitn(TO_DATAINIT, StickyTimeoutOpt); 3663 setbitn(TO_DATABLOCK, StickyTimeoutOpt); 3664 setbitn(TO_DATAFINAL, StickyTimeoutOpt); 3665 setbitn(TO_COMMAND, StickyTimeoutOpt); 3666 } 3667 continue; 3668 } 3669 else 3670 { 3671 register char *q = strchr(val, ':'); 3672 3673 if (q == NULL && (q = strchr(val, '=')) == NULL) 3674 { 3675 /* syntax error */ 3676 continue; 3677 } 3678 *q++ = '\0'; 3679 settimeout(val, q, sticky); 3680 } 3681 } 3682 } 3683