1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)readcf.c 8.52 (Berkeley) 11/27/94"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include <pwd.h> 15 # include <grp.h> 16 #if NAMED_BIND 17 # include <resolv.h> 18 #endif 19 20 /* 21 ** READCF -- read control file. 22 ** 23 ** This routine reads the control file and builds the internal 24 ** form. 25 ** 26 ** The file is formatted as a sequence of lines, each taken 27 ** atomically. The first character of each line describes how 28 ** the line is to be interpreted. The lines are: 29 ** Dxval Define macro x to have value val. 30 ** Cxword Put word into class x. 31 ** Fxfile [fmt] Read file for lines to put into 32 ** class x. Use scanf string 'fmt' 33 ** or "%s" if not present. Fmt should 34 ** only produce one string-valued result. 35 ** Hname: value Define header with field-name 'name' 36 ** and value as specified; this will be 37 ** macro expanded immediately before 38 ** use. 39 ** Sn Use rewriting set n. 40 ** Rlhs rhs Rewrite addresses that match lhs to 41 ** be rhs. 42 ** Mn arg=val... Define mailer. n is the internal name. 43 ** Args specify mailer parameters. 44 ** Oxvalue Set option x to value. 45 ** Pname=value Set precedence name to value. 46 ** Vversioncode[/vendorcode] 47 ** Version level/vendor name of 48 ** configuration syntax. 49 ** Kmapname mapclass arguments.... 50 ** Define keyed lookup of a given class. 51 ** Arguments are class dependent. 52 ** 53 ** Parameters: 54 ** cfname -- control file name. 55 ** safe -- TRUE if this is the system config file; 56 ** FALSE otherwise. 57 ** e -- the main envelope. 58 ** 59 ** Returns: 60 ** none. 61 ** 62 ** Side Effects: 63 ** Builds several internal tables. 64 */ 65 66 readcf(cfname, safe, e) 67 char *cfname; 68 bool safe; 69 register ENVELOPE *e; 70 { 71 FILE *cf; 72 int ruleset = 0; 73 char *q; 74 struct rewrite *rwp = NULL; 75 char *bp; 76 auto char *ep; 77 int nfuzzy; 78 char *file; 79 bool optional; 80 int mid; 81 char buf[MAXLINE]; 82 register char *p; 83 extern char **copyplist(); 84 struct stat statb; 85 char exbuf[MAXLINE]; 86 char pvpbuf[MAXLINE + MAXATOM]; 87 static char *null_list[1] = { NULL }; 88 extern char *munchstring(); 89 extern void makemapentry(); 90 91 FileName = cfname; 92 LineNumber = 0; 93 94 cf = fopen(cfname, "r"); 95 if (cf == NULL) 96 { 97 syserr("cannot open"); 98 exit(EX_OSFILE); 99 } 100 101 if (fstat(fileno(cf), &statb) < 0) 102 { 103 syserr("cannot fstat"); 104 exit(EX_OSFILE); 105 } 106 107 if (!S_ISREG(statb.st_mode)) 108 { 109 syserr("not a plain file"); 110 exit(EX_OSFILE); 111 } 112 113 if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 114 { 115 if (OpMode == MD_DAEMON || OpMode == MD_FREEZE) 116 fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 117 FileName); 118 #ifdef LOG 119 if (LogLevel > 0) 120 syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 121 FileName); 122 #endif 123 } 124 125 #ifdef XLA 126 xla_zero(); 127 #endif 128 129 while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 130 { 131 if (bp[0] == '#') 132 { 133 if (bp != buf) 134 free(bp); 135 continue; 136 } 137 138 /* do macro expansion mappings */ 139 for (p = bp; *p != '\0'; p++) 140 { 141 if (*p == '#' && p > bp && ConfigLevel >= 3) 142 { 143 /* this is an on-line comment */ 144 register char *e; 145 146 switch (*--p & 0377) 147 { 148 case MACROEXPAND: 149 /* it's from $# -- let it go through */ 150 p++; 151 break; 152 153 case '\\': 154 /* it's backslash escaped */ 155 (void) strcpy(p, p + 1); 156 break; 157 158 default: 159 /* delete preceeding white space */ 160 while (isascii(*p) && isspace(*p) && p > bp) 161 p--; 162 if ((e = strchr(++p, '\n')) != NULL) 163 (void) strcpy(p, e); 164 else 165 p[0] = p[1] = '\0'; 166 break; 167 } 168 continue; 169 } 170 171 if (*p != '$' || p[1] == '\0') 172 continue; 173 174 if (p[1] == '$') 175 { 176 /* actual dollar sign.... */ 177 (void) strcpy(p, p + 1); 178 continue; 179 } 180 181 /* convert to macro expansion character */ 182 *p++ = MACROEXPAND; 183 184 /* convert macro name to code */ 185 *p = macid(p, &ep); 186 if (ep != p) 187 strcpy(p + 1, ep); 188 } 189 190 /* interpret this line */ 191 errno = 0; 192 switch (bp[0]) 193 { 194 case '\0': 195 case '#': /* comment */ 196 break; 197 198 case 'R': /* rewriting rule */ 199 for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 200 continue; 201 202 if (*p == '\0') 203 { 204 syserr("invalid rewrite line \"%s\" (tab expected)", bp); 205 break; 206 } 207 208 /* allocate space for the rule header */ 209 if (rwp == NULL) 210 { 211 RewriteRules[ruleset] = rwp = 212 (struct rewrite *) xalloc(sizeof *rwp); 213 } 214 else 215 { 216 rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 217 rwp = rwp->r_next; 218 } 219 rwp->r_next = NULL; 220 221 /* expand and save the LHS */ 222 *p = '\0'; 223 expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e); 224 rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 225 sizeof pvpbuf, NULL); 226 nfuzzy = 0; 227 if (rwp->r_lhs != NULL) 228 { 229 register char **ap; 230 231 rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 232 233 /* count the number of fuzzy matches in LHS */ 234 for (ap = rwp->r_lhs; *ap != NULL; ap++) 235 { 236 char *botch; 237 238 botch = NULL; 239 switch (**ap & 0377) 240 { 241 case MATCHZANY: 242 case MATCHANY: 243 case MATCHONE: 244 case MATCHCLASS: 245 case MATCHNCLASS: 246 nfuzzy++; 247 break; 248 249 case MATCHREPL: 250 botch = "$0-$9"; 251 break; 252 253 case CANONNET: 254 botch = "$#"; 255 break; 256 257 case CANONUSER: 258 botch = "$:"; 259 break; 260 261 case CALLSUBR: 262 botch = "$>"; 263 break; 264 265 case CONDIF: 266 botch = "$?"; 267 break; 268 269 case CONDELSE: 270 botch = "$|"; 271 break; 272 273 case CONDFI: 274 botch = "$."; 275 break; 276 277 case HOSTBEGIN: 278 botch = "$["; 279 break; 280 281 case HOSTEND: 282 botch = "$]"; 283 break; 284 285 case LOOKUPBEGIN: 286 botch = "$("; 287 break; 288 289 case LOOKUPEND: 290 botch = "$)"; 291 break; 292 } 293 if (botch != NULL) 294 syserr("Inappropriate use of %s on LHS", 295 botch); 296 } 297 } 298 else 299 { 300 syserr("R line: null LHS"); 301 rwp->r_lhs = null_list; 302 } 303 304 /* expand and save the RHS */ 305 while (*++p == '\t') 306 continue; 307 q = p; 308 while (*p != '\0' && *p != '\t') 309 p++; 310 *p = '\0'; 311 expand(q, exbuf, &exbuf[sizeof exbuf], e); 312 rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 313 sizeof pvpbuf, NULL); 314 if (rwp->r_rhs != NULL) 315 { 316 register char **ap; 317 318 rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 319 320 /* check no out-of-bounds replacements */ 321 nfuzzy += '0'; 322 for (ap = rwp->r_rhs; *ap != NULL; ap++) 323 { 324 char *botch; 325 326 botch = NULL; 327 switch (**ap & 0377) 328 { 329 case MATCHREPL: 330 if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 331 { 332 syserr("replacement $%c out of bounds", 333 (*ap)[1]); 334 } 335 break; 336 337 case MATCHZANY: 338 botch = "$*"; 339 break; 340 341 case MATCHANY: 342 botch = "$+"; 343 break; 344 345 case MATCHONE: 346 botch = "$-"; 347 break; 348 349 case MATCHCLASS: 350 botch = "$="; 351 break; 352 353 case MATCHNCLASS: 354 botch = "$~"; 355 break; 356 } 357 if (botch != NULL) 358 syserr("Inappropriate use of %s on RHS", 359 botch); 360 } 361 } 362 else 363 { 364 syserr("R line: null RHS"); 365 rwp->r_rhs = null_list; 366 } 367 break; 368 369 case 'S': /* select rewriting set */ 370 for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 371 continue; 372 if (!isascii(*p) || !isdigit(*p)) 373 { 374 syserr("invalid argument to S line: \"%.20s\"", 375 &bp[1]); 376 break; 377 } 378 ruleset = atoi(p); 379 if (ruleset >= MAXRWSETS || ruleset < 0) 380 { 381 syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS); 382 ruleset = 0; 383 } 384 rwp = NULL; 385 break; 386 387 case 'D': /* macro definition */ 388 mid = macid(&bp[1], &ep); 389 p = munchstring(ep, NULL); 390 define(mid, newstr(p), e); 391 break; 392 393 case 'H': /* required header line */ 394 (void) chompheader(&bp[1], TRUE, e); 395 break; 396 397 case 'C': /* word class */ 398 /* scan the list of words and set class for all */ 399 mid = macid(&bp[1], &ep); 400 expand(ep, exbuf, &exbuf[sizeof exbuf], e); 401 for (p = exbuf; *p != '\0'; ) 402 { 403 register char *wd; 404 char delim; 405 406 while (*p != '\0' && isascii(*p) && isspace(*p)) 407 p++; 408 wd = p; 409 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 410 p++; 411 delim = *p; 412 *p = '\0'; 413 if (wd[0] != '\0') 414 setclass(mid, wd); 415 *p = delim; 416 } 417 break; 418 419 case 'F': /* word class from file */ 420 mid = macid(&bp[1], &ep); 421 for (p = ep; isascii(*p) && isspace(*p); ) 422 p++; 423 if (p[0] == '-' && p[1] == 'o') 424 { 425 optional = TRUE; 426 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 427 p++; 428 while (isascii(*p) && isspace(*p)) 429 p++; 430 } 431 else 432 optional = FALSE; 433 file = p; 434 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 435 p++; 436 if (*p == '\0') 437 p = "%s"; 438 else 439 { 440 *p = '\0'; 441 while (isascii(*++p) && isspace(*p)) 442 continue; 443 } 444 fileclass(bp[1], file, p, safe, optional); 445 break; 446 447 #ifdef XLA 448 case 'L': /* extended load average description */ 449 xla_init(&bp[1]); 450 break; 451 #endif 452 453 case 'M': /* define mailer */ 454 makemailer(&bp[1]); 455 break; 456 457 case 'O': /* set option */ 458 setoption(bp[1], &bp[2], safe, FALSE, e); 459 break; 460 461 case 'P': /* set precedence */ 462 if (NumPriorities >= MAXPRIORITIES) 463 { 464 toomany('P', MAXPRIORITIES); 465 break; 466 } 467 for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 468 continue; 469 if (*p == '\0') 470 goto badline; 471 *p = '\0'; 472 Priorities[NumPriorities].pri_name = newstr(&bp[1]); 473 Priorities[NumPriorities].pri_val = atoi(++p); 474 NumPriorities++; 475 break; 476 477 case 'T': /* trusted user(s) */ 478 /* this option is obsolete, but will be ignored */ 479 break; 480 481 case 'V': /* configuration syntax version */ 482 for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 483 continue; 484 if (!isascii(*p) || !isdigit(*p)) 485 { 486 syserr("invalid argument to V line: \"%.20s\"", 487 &bp[1]); 488 break; 489 } 490 ConfigLevel = strtol(p, &ep, 10); 491 if (ConfigLevel >= 5) 492 { 493 /* level 5 configs have short name in $w */ 494 p = macvalue('w', e); 495 if (p != NULL && (p = strchr(p, '.')) != NULL) 496 *p = '\0'; 497 } 498 if (*ep++ == '/') 499 { 500 /* extract vendor code */ 501 for (p = ep; isascii(*p) && isalpha(*p); ) 502 p++; 503 *p = '\0'; 504 505 if (!setvendor(ep)) 506 syserr("invalid V line vendor code: \"%s\"", 507 ep); 508 } 509 break; 510 511 case 'K': 512 makemapentry(&bp[1]); 513 break; 514 515 default: 516 badline: 517 syserr("unknown control line \"%s\"", bp); 518 } 519 if (bp != buf) 520 free(bp); 521 } 522 if (ferror(cf)) 523 { 524 syserr("I/O read error", cfname); 525 exit(EX_OSFILE); 526 } 527 fclose(cf); 528 FileName = NULL; 529 530 /* initialize host maps from local service tables */ 531 inithostmaps(); 532 533 /* determine if we need to do special name-server frotz */ 534 { 535 int nmaps; 536 char *maptype[MAXMAPSTACK]; 537 short mapreturn[MAXMAPACTIONS]; 538 539 nmaps = switch_map_find("hosts", maptype, mapreturn); 540 UseNameServer = FALSE; 541 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 542 { 543 register int mapno; 544 545 for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 546 { 547 if (strcmp(maptype[mapno], "dns") == 0) 548 UseNameServer = TRUE; 549 } 550 } 551 } 552 } 553 /* 554 ** TOOMANY -- signal too many of some option 555 ** 556 ** Parameters: 557 ** id -- the id of the error line 558 ** maxcnt -- the maximum possible values 559 ** 560 ** Returns: 561 ** none. 562 ** 563 ** Side Effects: 564 ** gives a syserr. 565 */ 566 567 toomany(id, maxcnt) 568 char id; 569 int maxcnt; 570 { 571 syserr("too many %c lines, %d max", id, maxcnt); 572 } 573 /* 574 ** FILECLASS -- read members of a class from a file 575 ** 576 ** Parameters: 577 ** class -- class to define. 578 ** filename -- name of file to read. 579 ** fmt -- scanf string to use for match. 580 ** safe -- if set, this is a safe read. 581 ** optional -- if set, it is not an error for the file to 582 ** not exist. 583 ** 584 ** Returns: 585 ** none 586 ** 587 ** Side Effects: 588 ** 589 ** puts all lines in filename that match a scanf into 590 ** the named class. 591 */ 592 593 fileclass(class, filename, fmt, safe, optional) 594 int class; 595 char *filename; 596 char *fmt; 597 bool safe; 598 bool optional; 599 { 600 FILE *f; 601 struct stat stbuf; 602 char buf[MAXLINE]; 603 604 if (tTd(37, 2)) 605 printf("fileclass(%s, fmt=%s)\n", filename, fmt); 606 607 if (filename[0] == '|') 608 { 609 syserr("fileclass: pipes (F%c%s) not supported due to security problems", 610 class, filename); 611 return; 612 } 613 if (stat(filename, &stbuf) < 0) 614 { 615 if (tTd(37, 2)) 616 printf(" cannot stat (%s)\n", errstring(errno)); 617 if (!optional) 618 syserr("fileclass: cannot stat %s", filename); 619 return; 620 } 621 if (!S_ISREG(stbuf.st_mode)) 622 { 623 syserr("fileclass: %s not a regular file", filename); 624 return; 625 } 626 if (!safe && access(filename, R_OK) < 0) 627 { 628 syserr("fileclass: access denied on %s", filename); 629 return; 630 } 631 f = fopen(filename, "r"); 632 if (f == NULL) 633 { 634 syserr("fileclass: cannot open %s", filename); 635 return; 636 } 637 638 while (fgets(buf, sizeof buf, f) != NULL) 639 { 640 register STAB *s; 641 register char *p; 642 # ifdef SCANF 643 char wordbuf[MAXNAME+1]; 644 645 if (sscanf(buf, fmt, wordbuf) != 1) 646 continue; 647 p = wordbuf; 648 # else /* SCANF */ 649 p = buf; 650 # endif /* SCANF */ 651 652 /* 653 ** Break up the match into words. 654 */ 655 656 while (*p != '\0') 657 { 658 register char *q; 659 660 /* strip leading spaces */ 661 while (isascii(*p) && isspace(*p)) 662 p++; 663 if (*p == '\0') 664 break; 665 666 /* find the end of the word */ 667 q = p; 668 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 669 p++; 670 if (*p != '\0') 671 *p++ = '\0'; 672 673 /* enter the word in the symbol table */ 674 setclass(class, q); 675 } 676 } 677 678 (void) fclose(f); 679 } 680 /* 681 ** MAKEMAILER -- define a new mailer. 682 ** 683 ** Parameters: 684 ** line -- description of mailer. This is in labeled 685 ** fields. The fields are: 686 ** A -- the argv for this mailer 687 ** C -- the character set for MIME conversions 688 ** D -- the directory to run in 689 ** E -- the eol string 690 ** F -- the flags associated with the mailer 691 ** L -- the maximum line length 692 ** M -- the maximum message size 693 ** P -- the path to the mailer 694 ** R -- the recipient rewriting set 695 ** S -- the sender rewriting set 696 ** T -- the mailer type (for DSNs) 697 ** U -- the uid to run as 698 ** The first word is the canonical name of the mailer. 699 ** 700 ** Returns: 701 ** none. 702 ** 703 ** Side Effects: 704 ** enters the mailer into the mailer table. 705 */ 706 707 makemailer(line) 708 char *line; 709 { 710 register char *p; 711 register struct mailer *m; 712 register STAB *s; 713 int i; 714 char fcode; 715 auto char *endp; 716 extern int NextMailer; 717 extern char **makeargv(); 718 extern char *munchstring(); 719 extern long atol(); 720 721 /* allocate a mailer and set up defaults */ 722 m = (struct mailer *) xalloc(sizeof *m); 723 bzero((char *) m, sizeof *m); 724 m->m_eol = "\n"; 725 m->m_uid = m->m_gid = 0; 726 727 /* collect the mailer name */ 728 for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 729 continue; 730 if (*p != '\0') 731 *p++ = '\0'; 732 m->m_name = newstr(line); 733 734 /* now scan through and assign info from the fields */ 735 while (*p != '\0') 736 { 737 auto char *delimptr; 738 739 while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 740 p++; 741 742 /* p now points to field code */ 743 fcode = *p; 744 while (*p != '\0' && *p != '=' && *p != ',') 745 p++; 746 if (*p++ != '=') 747 { 748 syserr("mailer %s: `=' expected", m->m_name); 749 return; 750 } 751 while (isascii(*p) && isspace(*p)) 752 p++; 753 754 /* p now points to the field body */ 755 p = munchstring(p, &delimptr); 756 757 /* install the field into the mailer struct */ 758 switch (fcode) 759 { 760 case 'P': /* pathname */ 761 m->m_mailer = newstr(p); 762 break; 763 764 case 'F': /* flags */ 765 for (; *p != '\0'; p++) 766 if (!(isascii(*p) && isspace(*p))) 767 setbitn(*p, m->m_flags); 768 break; 769 770 case 'S': /* sender rewriting ruleset */ 771 case 'R': /* recipient rewriting ruleset */ 772 i = strtol(p, &endp, 10); 773 if (i < 0 || i >= MAXRWSETS) 774 { 775 syserr("invalid rewrite set, %d max", MAXRWSETS); 776 return; 777 } 778 if (fcode == 'S') 779 m->m_sh_rwset = m->m_se_rwset = i; 780 else 781 m->m_rh_rwset = m->m_re_rwset = i; 782 783 p = endp; 784 if (*p++ == '/') 785 { 786 i = strtol(p, NULL, 10); 787 if (i < 0 || i >= MAXRWSETS) 788 { 789 syserr("invalid rewrite set, %d max", 790 MAXRWSETS); 791 return; 792 } 793 if (fcode == 'S') 794 m->m_sh_rwset = i; 795 else 796 m->m_rh_rwset = i; 797 } 798 break; 799 800 case 'E': /* end of line string */ 801 m->m_eol = newstr(p); 802 break; 803 804 case 'A': /* argument vector */ 805 m->m_argv = makeargv(p); 806 break; 807 808 case 'M': /* maximum message size */ 809 m->m_maxsize = atol(p); 810 break; 811 812 case 'L': /* maximum line length */ 813 m->m_linelimit = atoi(p); 814 break; 815 816 case 'D': /* working directory */ 817 m->m_execdir = newstr(p); 818 break; 819 820 case 'C': /* default charset */ 821 m->m_defcharset = newstr(p); 822 break; 823 824 case 'T': /* MTS Type */ 825 m->m_mtstype = newstr(p); 826 break; 827 828 case 'U': /* user id */ 829 if (isascii(*p) && !isdigit(*p)) 830 { 831 char *q = p; 832 struct passwd *pw; 833 834 while (isascii(*p) && isalnum(*p)) 835 p++; 836 while (isascii(*p) && isspace(*p)) 837 *p++ = '\0'; 838 if (*p != '\0') 839 *p++ = '\0'; 840 pw = getpwnam(q); 841 if (pw == NULL) 842 syserr("readcf: mailer U= flag: unknown user %s", q); 843 else 844 { 845 m->m_uid = pw->pw_uid; 846 m->m_gid = pw->pw_gid; 847 } 848 } 849 else 850 { 851 auto char *q; 852 853 m->m_uid = strtol(p, &q, 0); 854 p = q; 855 } 856 while (isascii(*p) && isspace(*p)) 857 p++; 858 if (*p == '\0') 859 break; 860 if (isascii(*p) && !isdigit(*p)) 861 { 862 char *q = p; 863 struct group *gr; 864 865 while (isascii(*p) && isalnum(*p)) 866 p++; 867 *p++ = '\0'; 868 gr = getgrnam(q); 869 if (gr == NULL) 870 syserr("readcf: mailer U= flag: unknown group %s", q); 871 else 872 m->m_gid = gr->gr_gid; 873 } 874 else 875 { 876 m->m_gid = strtol(p, NULL, 0); 877 } 878 break; 879 } 880 881 p = delimptr; 882 } 883 884 /* do some rationality checking */ 885 if (m->m_argv == NULL) 886 { 887 syserr("M%s: A= argument required", m->m_name); 888 return; 889 } 890 if (m->m_mailer == NULL) 891 { 892 syserr("M%s: P= argument required", m->m_name); 893 return; 894 } 895 896 if (NextMailer >= MAXMAILERS) 897 { 898 syserr("too many mailers defined (%d max)", MAXMAILERS); 899 return; 900 } 901 902 /* do some heuristic cleanup for back compatibility */ 903 if (bitnset(M_LIMITS, m->m_flags)) 904 { 905 if (m->m_linelimit == 0) 906 m->m_linelimit = SMTPLINELIM; 907 if (ConfigLevel < 2) 908 setbitn(M_7BITS, m->m_flags); 909 } 910 911 if (ConfigLevel < 6 && m->m_mtstype == NULL && 912 (strcmp(m->m_mailer, "[IPC]") == 0 || 913 strcmp(m->m_mailer, "[TCP]") == NULL)) 914 m->m_mtstype = "Internet"; 915 916 /* enter the mailer into the symbol table */ 917 s = stab(m->m_name, ST_MAILER, ST_ENTER); 918 if (s->s_mailer != NULL) 919 { 920 i = s->s_mailer->m_mno; 921 free(s->s_mailer); 922 } 923 else 924 { 925 i = NextMailer++; 926 } 927 Mailer[i] = s->s_mailer = m; 928 m->m_mno = i; 929 } 930 /* 931 ** MUNCHSTRING -- translate a string into internal form. 932 ** 933 ** Parameters: 934 ** p -- the string to munch. 935 ** delimptr -- if non-NULL, set to the pointer of the 936 ** field delimiter character. 937 ** 938 ** Returns: 939 ** the munched string. 940 */ 941 942 char * 943 munchstring(p, delimptr) 944 register char *p; 945 char **delimptr; 946 { 947 register char *q; 948 bool backslash = FALSE; 949 bool quotemode = FALSE; 950 static char buf[MAXLINE]; 951 952 for (q = buf; *p != '\0'; p++) 953 { 954 if (backslash) 955 { 956 /* everything is roughly literal */ 957 backslash = FALSE; 958 switch (*p) 959 { 960 case 'r': /* carriage return */ 961 *q++ = '\r'; 962 continue; 963 964 case 'n': /* newline */ 965 *q++ = '\n'; 966 continue; 967 968 case 'f': /* form feed */ 969 *q++ = '\f'; 970 continue; 971 972 case 'b': /* backspace */ 973 *q++ = '\b'; 974 continue; 975 } 976 *q++ = *p; 977 } 978 else 979 { 980 if (*p == '\\') 981 backslash = TRUE; 982 else if (*p == '"') 983 quotemode = !quotemode; 984 else if (quotemode || *p != ',') 985 *q++ = *p; 986 else 987 break; 988 } 989 } 990 991 if (delimptr != NULL) 992 *delimptr = p; 993 *q++ = '\0'; 994 return (buf); 995 } 996 /* 997 ** MAKEARGV -- break up a string into words 998 ** 999 ** Parameters: 1000 ** p -- the string to break up. 1001 ** 1002 ** Returns: 1003 ** a char **argv (dynamically allocated) 1004 ** 1005 ** Side Effects: 1006 ** munges p. 1007 */ 1008 1009 char ** 1010 makeargv(p) 1011 register char *p; 1012 { 1013 char *q; 1014 int i; 1015 char **avp; 1016 char *argv[MAXPV + 1]; 1017 1018 /* take apart the words */ 1019 i = 0; 1020 while (*p != '\0' && i < MAXPV) 1021 { 1022 q = p; 1023 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1024 p++; 1025 while (isascii(*p) && isspace(*p)) 1026 *p++ = '\0'; 1027 argv[i++] = newstr(q); 1028 } 1029 argv[i++] = NULL; 1030 1031 /* now make a copy of the argv */ 1032 avp = (char **) xalloc(sizeof *avp * i); 1033 bcopy((char *) argv, (char *) avp, sizeof *avp * i); 1034 1035 return (avp); 1036 } 1037 /* 1038 ** PRINTRULES -- print rewrite rules (for debugging) 1039 ** 1040 ** Parameters: 1041 ** none. 1042 ** 1043 ** Returns: 1044 ** none. 1045 ** 1046 ** Side Effects: 1047 ** prints rewrite rules. 1048 */ 1049 1050 printrules() 1051 { 1052 register struct rewrite *rwp; 1053 register int ruleset; 1054 1055 for (ruleset = 0; ruleset < 10; ruleset++) 1056 { 1057 if (RewriteRules[ruleset] == NULL) 1058 continue; 1059 printf("\n----Rule Set %d:", ruleset); 1060 1061 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 1062 { 1063 printf("\nLHS:"); 1064 printav(rwp->r_lhs); 1065 printf("RHS:"); 1066 printav(rwp->r_rhs); 1067 } 1068 } 1069 } 1070 /* 1071 ** PRINTMAILER -- print mailer structure (for debugging) 1072 ** 1073 ** Parameters: 1074 ** m -- the mailer to print 1075 ** 1076 ** Returns: 1077 ** none. 1078 */ 1079 1080 printmailer(m) 1081 register MAILER *m; 1082 { 1083 int j; 1084 1085 printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 1086 m->m_mno, m->m_name, 1087 m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 1088 m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 1089 m->m_uid, m->m_gid); 1090 for (j = '\0'; j <= '\177'; j++) 1091 if (bitnset(j, m->m_flags)) 1092 (void) putchar(j); 1093 printf(" L=%d E=", m->m_linelimit); 1094 xputs(m->m_eol); 1095 if (m->m_defcharset != NULL) 1096 printf(" C=%s", m->m_defcharset); 1097 if (m->m_mtstype != NULL) 1098 printf(" T=%s", m->m_mtstype); 1099 if (m->m_argv != NULL) 1100 { 1101 char **a = m->m_argv; 1102 1103 printf(" A="); 1104 while (*a != NULL) 1105 { 1106 if (a != m->m_argv) 1107 printf(" "); 1108 xputs(*a++); 1109 } 1110 } 1111 printf("\n"); 1112 } 1113 /* 1114 ** SETOPTION -- set global processing option 1115 ** 1116 ** Parameters: 1117 ** opt -- option name. 1118 ** val -- option value (as a text string). 1119 ** safe -- set if this came from a configuration file. 1120 ** Some options (if set from the command line) will 1121 ** reset the user id to avoid security problems. 1122 ** sticky -- if set, don't let other setoptions override 1123 ** this value. 1124 ** e -- the main envelope. 1125 ** 1126 ** Returns: 1127 ** none. 1128 ** 1129 ** Side Effects: 1130 ** Sets options as implied by the arguments. 1131 */ 1132 1133 static BITMAP StickyOpt; /* set if option is stuck */ 1134 1135 1136 #if NAMED_BIND 1137 1138 struct resolverflags 1139 { 1140 char *rf_name; /* name of the flag */ 1141 long rf_bits; /* bits to set/clear */ 1142 } ResolverFlags[] = 1143 { 1144 "debug", RES_DEBUG, 1145 "aaonly", RES_AAONLY, 1146 "usevc", RES_USEVC, 1147 "primary", RES_PRIMARY, 1148 "igntc", RES_IGNTC, 1149 "recurse", RES_RECURSE, 1150 "defnames", RES_DEFNAMES, 1151 "stayopen", RES_STAYOPEN, 1152 "dnsrch", RES_DNSRCH, 1153 "true", 0, /* to avoid error on old syntax */ 1154 NULL, 0 1155 }; 1156 1157 #endif 1158 1159 struct optioninfo 1160 { 1161 char *o_name; /* long name of option */ 1162 u_char o_code; /* short name of option */ 1163 bool o_safe; /* safe for random people to use */ 1164 } OptionTab[] = 1165 { 1166 "SevenBitInput", '7', TRUE, 1167 "EightBitMode", '8', TRUE, 1168 "AliasFile", 'A', FALSE, 1169 "AliasWait", 'a', FALSE, 1170 "BlankSub", 'B', FALSE, 1171 "MinFreeBlocks", 'b', TRUE, 1172 "CheckpointInterval", 'C', TRUE, 1173 "HoldExpensive", 'c', FALSE, 1174 "AutoRebuildAliases", 'D', FALSE, 1175 "DeliveryMode", 'd', TRUE, 1176 "ErrorHeader", 'E', FALSE, 1177 "ErrorMode", 'e', TRUE, 1178 "TempFileMode", 'F', FALSE, 1179 "SaveFromLine", 'f', FALSE, 1180 "MatchGECOS", 'G', FALSE, 1181 "HelpFile", 'H', FALSE, 1182 "MaxHopCount", 'h', FALSE, 1183 "NameServerOptions", 'I', FALSE, 1184 "IgnoreDots", 'i', TRUE, 1185 "ForwardPath", 'J', FALSE, 1186 "SendMimeErrors", 'j', TRUE, 1187 "ConnectionCacheSize", 'k', FALSE, 1188 "ConnectionCacheTimeout", 'K', FALSE, 1189 "UseErrorsTo", 'l', FALSE, 1190 "LogLevel", 'L', FALSE, 1191 "MeToo", 'm', TRUE, 1192 "CheckAliases", 'n', FALSE, 1193 "OldStyleHeaders", 'o', TRUE, 1194 "DaemonPortOptions", 'O', FALSE, 1195 "PrivacyOptions", 'p', TRUE, 1196 "PostmasterCopy", 'P', FALSE, 1197 "QueueFactor", 'q', FALSE, 1198 "QueueDirectory", 'Q', FALSE, 1199 "DontPruneRoutes", 'R', FALSE, 1200 "Timeouts", 'r', TRUE, 1201 "StatusFile", 'S', FALSE, 1202 "SuperSafe", 's', TRUE, 1203 "QueueTimeout", 'T', FALSE, 1204 "TimeZoneSpec", 't', FALSE, 1205 "UserDatabaseSpec", 'U', FALSE, 1206 "DefaultUser", 'u', FALSE, 1207 "FallbackMXhost", 'V', FALSE, 1208 "Verbose", 'v', TRUE, 1209 "TryNullMXList", 'w', TRUE, 1210 "QueueLA", 'x', FALSE, 1211 "RefuseLA", 'X', FALSE, 1212 "RecipientFactor", 'y', FALSE, 1213 "ForkQueueRuns", 'Y', FALSE, 1214 "ClassFactor", 'z', FALSE, 1215 "TimeFactor", 'Z', FALSE, 1216 #define O_BSP 0x80 1217 "BrokenSmtpPeers", O_BSP, TRUE, 1218 #define O_SQBH 0x81 1219 "SortQueueByHost", O_SQBH, TRUE, 1220 #define O_DNICE 0x82 1221 "DeliveryNiceness", O_DNICE, TRUE, 1222 #define O_MQA 0x83 1223 "MinQueueAge", O_MQA, TRUE, 1224 #define O_MHSA 0x84 1225 "MaxHostStatAge", O_MHSA, TRUE, 1226 #define O_DEFCHARSET 0x85 1227 "DefaultCharSet", O_DEFCHARSET, TRUE, 1228 #define O_SSFILE 0x86 1229 "ServiceSwitchFile", O_SSFILE, FALSE, 1230 1231 NULL, '\0', FALSE, 1232 }; 1233 1234 1235 1236 setoption(opt, val, safe, sticky, e) 1237 u_char opt; 1238 char *val; 1239 bool safe; 1240 bool sticky; 1241 register ENVELOPE *e; 1242 { 1243 register char *p; 1244 register struct optioninfo *o; 1245 char *subopt; 1246 extern bool atobool(); 1247 extern time_t convtime(); 1248 extern int QueueLA; 1249 extern int RefuseLA; 1250 extern bool Warn_Q_option; 1251 1252 errno = 0; 1253 if (opt == ' ') 1254 { 1255 /* full word options */ 1256 struct optioninfo *sel; 1257 1258 p = strchr(val, '='); 1259 if (p == NULL) 1260 p = &val[strlen(val)]; 1261 while (*--p == ' ') 1262 continue; 1263 while (*++p == ' ') 1264 *p = '\0'; 1265 if (p == val) 1266 { 1267 syserr("readcf: null option name"); 1268 return; 1269 } 1270 if (*p == '=') 1271 *p++ = '\0'; 1272 while (*p == ' ') 1273 p++; 1274 subopt = strchr(val, '.'); 1275 if (subopt != NULL) 1276 *subopt++ = '\0'; 1277 sel = NULL; 1278 for (o = OptionTab; o->o_name != NULL; o++) 1279 { 1280 if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1281 continue; 1282 if (strlen(o->o_name) == strlen(val)) 1283 { 1284 /* completely specified -- this must be it */ 1285 sel = NULL; 1286 break; 1287 } 1288 if (sel != NULL) 1289 break; 1290 sel = o; 1291 } 1292 if (sel != NULL && o->o_name == NULL) 1293 o = sel; 1294 else if (o->o_name == NULL) 1295 { 1296 syserr("readcf: unknown option name %s", val); 1297 return; 1298 } 1299 else if (sel != NULL) 1300 { 1301 syserr("readcf: ambiguous option name %s (matches %s and %s)", 1302 val, sel->o_name, o->o_name); 1303 return; 1304 } 1305 if (strlen(val) != strlen(o->o_name)) 1306 { 1307 bool oldVerbose = Verbose; 1308 1309 Verbose = TRUE; 1310 message("Option %s used as abbreviation for %s", 1311 val, o->o_name); 1312 Verbose = oldVerbose; 1313 } 1314 opt = o->o_code; 1315 val = p; 1316 } 1317 else 1318 { 1319 for (o = OptionTab; o->o_name != NULL; o++) 1320 { 1321 if (o->o_code == opt) 1322 break; 1323 } 1324 subopt = NULL; 1325 } 1326 1327 if (tTd(37, 1)) 1328 { 1329 printf(isascii(opt) && isprint(opt) ? 1330 "setoption %s (%c).%s=%s" : 1331 "setoption %s (0x%x).%s=%s", 1332 o->o_name == NULL ? "<unknown>" : o->o_name, 1333 opt, 1334 subopt == NULL ? "" : subopt, 1335 val); 1336 } 1337 1338 /* 1339 ** See if this option is preset for us. 1340 */ 1341 1342 if (!sticky && bitnset(opt, StickyOpt)) 1343 { 1344 if (tTd(37, 1)) 1345 printf(" (ignored)\n"); 1346 return; 1347 } 1348 1349 /* 1350 ** Check to see if this option can be specified by this user. 1351 */ 1352 1353 if (!safe && RealUid == 0) 1354 safe = TRUE; 1355 if (!safe && !o->o_safe) 1356 { 1357 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 1358 { 1359 if (tTd(37, 1)) 1360 printf(" (unsafe)"); 1361 if (RealUid != geteuid()) 1362 { 1363 if (tTd(37, 1)) 1364 printf("(Resetting uid)"); 1365 (void) setgid(RealGid); 1366 (void) setuid(RealUid); 1367 } 1368 } 1369 } 1370 if (tTd(37, 1)) 1371 printf("\n"); 1372 1373 switch (opt & 0xff) 1374 { 1375 case '7': /* force seven-bit input */ 1376 SevenBitInput = atobool(val); 1377 break; 1378 1379 case '8': /* handling of 8-bit input */ 1380 switch (*val) 1381 { 1382 case 'r': /* reject 8-bit, don't convert MIME */ 1383 MimeMode = 0; 1384 break; 1385 1386 case 'm': /* convert 8-bit, convert MIME */ 1387 MimeMode = MM_CVTMIME|MM_MIME8BIT; 1388 break; 1389 1390 case 'j': /* "just send 8" */ 1391 MimeMode = MM_PASS8BIT; 1392 break; 1393 1394 case 'p': /* pass 8 bit, convert MIME */ 1395 MimeMode = MM_PASS8BIT|MM_CVTMIME; 1396 break; 1397 1398 case 's': /* strict adherence */ 1399 MimeMode = MM_CVTMIME; 1400 break; 1401 1402 case 'a': /* encode 8 bit if available */ 1403 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1404 break; 1405 1406 case 'c': /* convert 8 bit to MIME, never 7 bit */ 1407 MimeMode = MM_MIME8BIT; 1408 break; 1409 1410 default: 1411 syserr("Unknown 8-bit mode %c", *val); 1412 exit(EX_USAGE); 1413 } 1414 break; 1415 1416 case 'A': /* set default alias file */ 1417 if (val[0] == '\0') 1418 setalias("aliases"); 1419 else 1420 setalias(val); 1421 break; 1422 1423 case 'a': /* look N minutes for "@:@" in alias file */ 1424 if (val[0] == '\0') 1425 SafeAlias = 5 * 60; /* five minutes */ 1426 else 1427 SafeAlias = convtime(val, 'm'); 1428 break; 1429 1430 case 'B': /* substitution for blank character */ 1431 SpaceSub = val[0]; 1432 if (SpaceSub == '\0') 1433 SpaceSub = ' '; 1434 break; 1435 1436 case 'b': /* min blocks free on queue fs/max msg size */ 1437 p = strchr(val, '/'); 1438 if (p != NULL) 1439 { 1440 *p++ = '\0'; 1441 MaxMessageSize = atol(p); 1442 } 1443 MinBlocksFree = atol(val); 1444 break; 1445 1446 case 'c': /* don't connect to "expensive" mailers */ 1447 NoConnect = atobool(val); 1448 break; 1449 1450 case 'C': /* checkpoint every N addresses */ 1451 CheckpointInterval = atoi(val); 1452 break; 1453 1454 case 'd': /* delivery mode */ 1455 switch (*val) 1456 { 1457 case '\0': 1458 e->e_sendmode = SM_DELIVER; 1459 break; 1460 1461 case SM_QUEUE: /* queue only */ 1462 #ifndef QUEUE 1463 syserr("need QUEUE to set -odqueue"); 1464 #endif /* QUEUE */ 1465 /* fall through..... */ 1466 1467 case SM_DELIVER: /* do everything */ 1468 case SM_FORK: /* fork after verification */ 1469 e->e_sendmode = *val; 1470 break; 1471 1472 default: 1473 syserr("Unknown delivery mode %c", *val); 1474 exit(EX_USAGE); 1475 } 1476 break; 1477 1478 case 'D': /* rebuild alias database as needed */ 1479 AutoRebuild = atobool(val); 1480 break; 1481 1482 case 'E': /* error message header/header file */ 1483 if (*val != '\0') 1484 ErrMsgFile = newstr(val); 1485 break; 1486 1487 case 'e': /* set error processing mode */ 1488 switch (*val) 1489 { 1490 case EM_QUIET: /* be silent about it */ 1491 case EM_MAIL: /* mail back */ 1492 case EM_BERKNET: /* do berknet error processing */ 1493 case EM_WRITE: /* write back (or mail) */ 1494 case EM_PRINT: /* print errors normally (default) */ 1495 e->e_errormode = *val; 1496 break; 1497 } 1498 break; 1499 1500 case 'F': /* file mode */ 1501 FileMode = atooct(val) & 0777; 1502 break; 1503 1504 case 'f': /* save Unix-style From lines on front */ 1505 SaveFrom = atobool(val); 1506 break; 1507 1508 case 'G': /* match recipients against GECOS field */ 1509 MatchGecos = atobool(val); 1510 break; 1511 1512 case 'g': /* default gid */ 1513 g_opt: 1514 if (isascii(*val) && isdigit(*val)) 1515 DefGid = atoi(val); 1516 else 1517 { 1518 register struct group *gr; 1519 1520 DefGid = -1; 1521 gr = getgrnam(val); 1522 if (gr == NULL) 1523 syserr("readcf: option %c: unknown group %s", 1524 opt, val); 1525 else 1526 DefGid = gr->gr_gid; 1527 } 1528 break; 1529 1530 case 'H': /* help file */ 1531 if (val[0] == '\0') 1532 HelpFile = "sendmail.hf"; 1533 else 1534 HelpFile = newstr(val); 1535 break; 1536 1537 case 'h': /* maximum hop count */ 1538 MaxHopCount = atoi(val); 1539 break; 1540 1541 case 'I': /* use internet domain name server */ 1542 #if NAMED_BIND 1543 for (p = val; *p != 0; ) 1544 { 1545 bool clearmode; 1546 char *q; 1547 struct resolverflags *rfp; 1548 1549 while (*p == ' ') 1550 p++; 1551 if (*p == '\0') 1552 break; 1553 clearmode = FALSE; 1554 if (*p == '-') 1555 clearmode = TRUE; 1556 else if (*p != '+') 1557 p--; 1558 p++; 1559 q = p; 1560 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1561 p++; 1562 if (*p != '\0') 1563 *p++ = '\0'; 1564 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 1565 { 1566 if (strcasecmp(q, rfp->rf_name) == 0) 1567 break; 1568 } 1569 if (rfp->rf_name == NULL) 1570 syserr("readcf: I option value %s unrecognized", q); 1571 else if (clearmode) 1572 _res.options &= ~rfp->rf_bits; 1573 else 1574 _res.options |= rfp->rf_bits; 1575 } 1576 if (tTd(8, 2)) 1577 printf("_res.options = %x\n", _res.options); 1578 #else 1579 usrerr("name server (I option) specified but BIND not compiled in"); 1580 #endif 1581 break; 1582 1583 case 'i': /* ignore dot lines in message */ 1584 IgnrDot = atobool(val); 1585 break; 1586 1587 case 'j': /* send errors in MIME (RFC 1341) format */ 1588 SendMIMEErrors = atobool(val); 1589 break; 1590 1591 case 'J': /* .forward search path */ 1592 ForwardPath = newstr(val); 1593 break; 1594 1595 case 'k': /* connection cache size */ 1596 MaxMciCache = atoi(val); 1597 if (MaxMciCache < 0) 1598 MaxMciCache = 0; 1599 break; 1600 1601 case 'K': /* connection cache timeout */ 1602 MciCacheTimeout = convtime(val, 'm'); 1603 break; 1604 1605 case 'l': /* use Errors-To: header */ 1606 UseErrorsTo = atobool(val); 1607 break; 1608 1609 case 'L': /* log level */ 1610 if (safe || LogLevel < atoi(val)) 1611 LogLevel = atoi(val); 1612 break; 1613 1614 case 'M': /* define macro */ 1615 define(val[0], newstr(&val[1]), CurEnv); 1616 sticky = FALSE; 1617 break; 1618 1619 case 'm': /* send to me too */ 1620 MeToo = atobool(val); 1621 break; 1622 1623 case 'n': /* validate RHS in newaliases */ 1624 CheckAliases = atobool(val); 1625 break; 1626 1627 /* 'N' available -- was "net name" */ 1628 1629 case 'O': /* daemon options */ 1630 setdaemonoptions(val); 1631 break; 1632 1633 case 'o': /* assume old style headers */ 1634 if (atobool(val)) 1635 CurEnv->e_flags |= EF_OLDSTYLE; 1636 else 1637 CurEnv->e_flags &= ~EF_OLDSTYLE; 1638 break; 1639 1640 case 'p': /* select privacy level */ 1641 p = val; 1642 for (;;) 1643 { 1644 register struct prival *pv; 1645 extern struct prival PrivacyValues[]; 1646 1647 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 1648 p++; 1649 if (*p == '\0') 1650 break; 1651 val = p; 1652 while (isascii(*p) && isalnum(*p)) 1653 p++; 1654 if (*p != '\0') 1655 *p++ = '\0'; 1656 1657 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 1658 { 1659 if (strcasecmp(val, pv->pv_name) == 0) 1660 break; 1661 } 1662 if (pv->pv_name == NULL) 1663 syserr("readcf: Op line: %s unrecognized", val); 1664 PrivacyFlags |= pv->pv_flag; 1665 } 1666 break; 1667 1668 case 'P': /* postmaster copy address for returned mail */ 1669 PostMasterCopy = newstr(val); 1670 break; 1671 1672 case 'q': /* slope of queue only function */ 1673 QueueFactor = atoi(val); 1674 break; 1675 1676 case 'Q': /* queue directory */ 1677 if (val[0] == '\0') 1678 QueueDir = "mqueue"; 1679 else 1680 QueueDir = newstr(val); 1681 if (RealUid != 0 && !safe) 1682 Warn_Q_option = TRUE; 1683 break; 1684 1685 case 'R': /* don't prune routes */ 1686 DontPruneRoutes = atobool(val); 1687 break; 1688 1689 case 'r': /* read timeout */ 1690 if (subopt == NULL) 1691 inittimeouts(val); 1692 else 1693 settimeout(subopt, val); 1694 break; 1695 1696 case 'S': /* status file */ 1697 if (val[0] == '\0') 1698 StatFile = "sendmail.st"; 1699 else 1700 StatFile = newstr(val); 1701 break; 1702 1703 case 's': /* be super safe, even if expensive */ 1704 SuperSafe = atobool(val); 1705 break; 1706 1707 case 'T': /* queue timeout */ 1708 p = strchr(val, '/'); 1709 if (p != NULL) 1710 { 1711 *p++ = '\0'; 1712 settimeout("queuewarn", p); 1713 } 1714 settimeout("queuereturn", val); 1715 break; 1716 1717 case 't': /* time zone name */ 1718 TimeZoneSpec = newstr(val); 1719 break; 1720 1721 case 'U': /* location of user database */ 1722 UdbSpec = newstr(val); 1723 break; 1724 1725 case 'u': /* set default uid */ 1726 for (p = val; *p != '\0'; p++) 1727 { 1728 if (*p == '.' || *p == '/' || *p == ':') 1729 { 1730 *p++ = '\0'; 1731 break; 1732 } 1733 } 1734 if (isascii(*val) && isdigit(*val)) 1735 DefUid = atoi(val); 1736 else 1737 { 1738 register struct passwd *pw; 1739 1740 DefUid = -1; 1741 pw = getpwnam(val); 1742 if (pw == NULL) 1743 syserr("readcf: option u: unknown user %s", val); 1744 else 1745 { 1746 DefUid = pw->pw_uid; 1747 DefGid = pw->pw_gid; 1748 } 1749 } 1750 setdefuser(); 1751 1752 /* handle the group if it is there */ 1753 if (*p == '\0') 1754 break; 1755 val = p; 1756 goto g_opt; 1757 1758 case 'V': /* fallback MX host */ 1759 FallBackMX = newstr(val); 1760 break; 1761 1762 case 'v': /* run in verbose mode */ 1763 Verbose = atobool(val); 1764 break; 1765 1766 case 'w': /* if we are best MX, try host directly */ 1767 TryNullMXList = atobool(val); 1768 break; 1769 1770 /* 'W' available -- was wizard password */ 1771 1772 case 'x': /* load avg at which to auto-queue msgs */ 1773 QueueLA = atoi(val); 1774 break; 1775 1776 case 'X': /* load avg at which to auto-reject connections */ 1777 RefuseLA = atoi(val); 1778 break; 1779 1780 case 'y': /* work recipient factor */ 1781 WkRecipFact = atoi(val); 1782 break; 1783 1784 case 'Y': /* fork jobs during queue runs */ 1785 ForkQueueRuns = atobool(val); 1786 break; 1787 1788 case 'z': /* work message class factor */ 1789 WkClassFact = atoi(val); 1790 break; 1791 1792 case 'Z': /* work time factor */ 1793 WkTimeFact = atoi(val); 1794 break; 1795 1796 case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 1797 BrokenSmtpPeers = atobool(val); 1798 break; 1799 1800 case O_SQBH: /* sort work queue by host first */ 1801 SortQueueByHost = atobool(val); 1802 break; 1803 1804 case O_DNICE: /* delivery nice value */ 1805 DeliveryNiceness = atoi(val); 1806 break; 1807 1808 case O_MQA: /* minimum queue age between deliveries */ 1809 MinQueueAge = convtime(val, 'm'); 1810 break; 1811 1812 case O_MHSA: /* maximum age of cached host status */ 1813 MaxHostStatAge = convtime(val, 'm'); 1814 break; 1815 1816 case O_DEFCHARSET: /* default character set for mimefying */ 1817 DefaultCharSet = newstr(val); 1818 break; 1819 1820 case O_SSFILE: /* service switch file */ 1821 ServiceSwitchFile = newstr(val); 1822 break; 1823 1824 default: 1825 break; 1826 } 1827 if (sticky) 1828 setbitn(opt, StickyOpt); 1829 return; 1830 } 1831 /* 1832 ** SETCLASS -- set a word into a class 1833 ** 1834 ** Parameters: 1835 ** class -- the class to put the word in. 1836 ** word -- the word to enter 1837 ** 1838 ** Returns: 1839 ** none. 1840 ** 1841 ** Side Effects: 1842 ** puts the word into the symbol table. 1843 */ 1844 1845 setclass(class, word) 1846 int class; 1847 char *word; 1848 { 1849 register STAB *s; 1850 1851 if (tTd(37, 8)) 1852 printf("setclass(%c, %s)\n", class, word); 1853 s = stab(word, ST_CLASS, ST_ENTER); 1854 setbitn(class, s->s_class); 1855 } 1856 /* 1857 ** MAKEMAPENTRY -- create a map entry 1858 ** 1859 ** Parameters: 1860 ** line -- the config file line 1861 ** 1862 ** Returns: 1863 ** TRUE if it successfully entered the map entry. 1864 ** FALSE otherwise (usually syntax error). 1865 ** 1866 ** Side Effects: 1867 ** Enters the map into the dictionary. 1868 */ 1869 1870 void 1871 makemapentry(line) 1872 char *line; 1873 { 1874 register char *p; 1875 char *mapname; 1876 char *classname; 1877 register STAB *s; 1878 STAB *class; 1879 1880 for (p = line; isascii(*p) && isspace(*p); p++) 1881 continue; 1882 if (!(isascii(*p) && isalnum(*p))) 1883 { 1884 syserr("readcf: config K line: no map name"); 1885 return; 1886 } 1887 1888 mapname = p; 1889 while ((isascii(*++p) && isalnum(*p)) || *p == '.') 1890 continue; 1891 if (*p != '\0') 1892 *p++ = '\0'; 1893 while (isascii(*p) && isspace(*p)) 1894 p++; 1895 if (!(isascii(*p) && isalnum(*p))) 1896 { 1897 syserr("readcf: config K line, map %s: no map class", mapname); 1898 return; 1899 } 1900 classname = p; 1901 while (isascii(*++p) && isalnum(*p)) 1902 continue; 1903 if (*p != '\0') 1904 *p++ = '\0'; 1905 while (isascii(*p) && isspace(*p)) 1906 p++; 1907 1908 /* look up the class */ 1909 class = stab(classname, ST_MAPCLASS, ST_FIND); 1910 if (class == NULL) 1911 { 1912 syserr("readcf: map %s: class %s not available", mapname, classname); 1913 return; 1914 } 1915 1916 /* enter the map */ 1917 s = stab(mapname, ST_MAP, ST_ENTER); 1918 s->s_map.map_class = &class->s_mapclass; 1919 s->s_map.map_mname = newstr(mapname); 1920 1921 if (class->s_mapclass.map_parse(&s->s_map, p)) 1922 s->s_map.map_mflags |= MF_VALID; 1923 1924 if (tTd(37, 5)) 1925 { 1926 printf("map %s, class %s, flags %x, file %s,\n", 1927 s->s_map.map_mname, s->s_map.map_class->map_cname, 1928 s->s_map.map_mflags, 1929 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 1930 printf("\tapp %s, domain %s, rebuild %s\n", 1931 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 1932 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 1933 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 1934 } 1935 } 1936 /* 1937 ** INITTIMEOUTS -- parse and set timeout values 1938 ** 1939 ** Parameters: 1940 ** val -- a pointer to the values. If NULL, do initial 1941 ** settings. 1942 ** 1943 ** Returns: 1944 ** none. 1945 ** 1946 ** Side Effects: 1947 ** Initializes the TimeOuts structure 1948 */ 1949 1950 #define SECONDS 1951 #define MINUTES * 60 1952 #define HOUR * 3600 1953 1954 inittimeouts(val) 1955 register char *val; 1956 { 1957 register char *p; 1958 extern time_t convtime(); 1959 1960 if (val == NULL) 1961 { 1962 TimeOuts.to_initial = (time_t) 5 MINUTES; 1963 TimeOuts.to_helo = (time_t) 5 MINUTES; 1964 TimeOuts.to_mail = (time_t) 10 MINUTES; 1965 TimeOuts.to_rcpt = (time_t) 1 HOUR; 1966 TimeOuts.to_datainit = (time_t) 5 MINUTES; 1967 TimeOuts.to_datablock = (time_t) 1 HOUR; 1968 TimeOuts.to_datafinal = (time_t) 1 HOUR; 1969 TimeOuts.to_rset = (time_t) 5 MINUTES; 1970 TimeOuts.to_quit = (time_t) 2 MINUTES; 1971 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 1972 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 1973 TimeOuts.to_ident = (time_t) 30 SECONDS; 1974 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 1975 return; 1976 } 1977 1978 for (;; val = p) 1979 { 1980 while (isascii(*val) && isspace(*val)) 1981 val++; 1982 if (*val == '\0') 1983 break; 1984 for (p = val; *p != '\0' && *p != ','; p++) 1985 continue; 1986 if (*p != '\0') 1987 *p++ = '\0'; 1988 1989 if (isascii(*val) && isdigit(*val)) 1990 { 1991 /* old syntax -- set everything */ 1992 TimeOuts.to_mail = convtime(val, 'm'); 1993 TimeOuts.to_rcpt = TimeOuts.to_mail; 1994 TimeOuts.to_datainit = TimeOuts.to_mail; 1995 TimeOuts.to_datablock = TimeOuts.to_mail; 1996 TimeOuts.to_datafinal = TimeOuts.to_mail; 1997 TimeOuts.to_nextcommand = TimeOuts.to_mail; 1998 continue; 1999 } 2000 else 2001 { 2002 register char *q = strchr(val, ':'); 2003 2004 if (q == NULL && (q = strchr(val, '=')) == NULL) 2005 { 2006 /* syntax error */ 2007 continue; 2008 } 2009 *q++ = '\0'; 2010 settimeout(val, q); 2011 } 2012 } 2013 } 2014 /* 2015 ** SETTIMEOUT -- set an individual timeout 2016 ** 2017 ** Parameters: 2018 ** name -- the name of the timeout. 2019 ** val -- the value of the timeout. 2020 ** 2021 ** Returns: 2022 ** none. 2023 */ 2024 2025 settimeout(name, val) 2026 char *name; 2027 char *val; 2028 { 2029 register char *p; 2030 time_t to; 2031 extern time_t convtime(); 2032 2033 to = convtime(val, 'm'); 2034 p = strchr(name, '.'); 2035 if (p != NULL) 2036 *p++ = '\0'; 2037 2038 if (strcasecmp(name, "initial") == 0) 2039 TimeOuts.to_initial = to; 2040 else if (strcasecmp(name, "mail") == 0) 2041 TimeOuts.to_mail = to; 2042 else if (strcasecmp(name, "rcpt") == 0) 2043 TimeOuts.to_rcpt = to; 2044 else if (strcasecmp(name, "datainit") == 0) 2045 TimeOuts.to_datainit = to; 2046 else if (strcasecmp(name, "datablock") == 0) 2047 TimeOuts.to_datablock = to; 2048 else if (strcasecmp(name, "datafinal") == 0) 2049 TimeOuts.to_datafinal = to; 2050 else if (strcasecmp(name, "command") == 0) 2051 TimeOuts.to_nextcommand = to; 2052 else if (strcasecmp(name, "rset") == 0) 2053 TimeOuts.to_rset = to; 2054 else if (strcasecmp(name, "helo") == 0) 2055 TimeOuts.to_helo = to; 2056 else if (strcasecmp(name, "quit") == 0) 2057 TimeOuts.to_quit = to; 2058 else if (strcasecmp(name, "misc") == 0) 2059 TimeOuts.to_miscshort = to; 2060 else if (strcasecmp(name, "ident") == 0) 2061 TimeOuts.to_ident = to; 2062 else if (strcasecmp(name, "fileopen") == 0) 2063 TimeOuts.to_fileopen = to; 2064 else if (strcasecmp(name, "queuewarn") == 0) 2065 { 2066 to = convtime(val, 'h'); 2067 if (p == NULL || strcmp(p, "*") == 0) 2068 { 2069 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2070 TimeOuts.to_q_warning[TOC_URGENT] = to; 2071 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2072 } 2073 else if (strcasecmp(p, "normal") == 0) 2074 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2075 else if (strcasecmp(p, "urgent") == 0) 2076 TimeOuts.to_q_warning[TOC_URGENT] = to; 2077 else if (strcasecmp(p, "non-urgent") == 0) 2078 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2079 else 2080 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2081 } 2082 else if (strcasecmp(name, "queuereturn") == 0) 2083 { 2084 to = convtime(val, 'd'); 2085 if (p == NULL || strcmp(p, "*") == 0) 2086 { 2087 TimeOuts.to_q_return[TOC_NORMAL] = to; 2088 TimeOuts.to_q_return[TOC_URGENT] = to; 2089 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2090 } 2091 else if (strcasecmp(p, "normal") == 0) 2092 TimeOuts.to_q_return[TOC_NORMAL] = to; 2093 else if (strcasecmp(p, "urgent") == 0) 2094 TimeOuts.to_q_return[TOC_URGENT] = to; 2095 else if (strcasecmp(p, "non-urgent") == 0) 2096 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2097 else 2098 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2099 } 2100 else 2101 syserr("settimeout: invalid timeout %s", name); 2102 } 2103