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.59 (Berkeley) 01/07/95"; 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]") == 0)) 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 "Timeout", '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_QUEUESORTORD 0x81 1219 "QueueSortOrder", O_QUEUESORTORD, TRUE, 1220 #define O_MQA 0x83 1221 "MinQueueAge", O_MQA, TRUE, 1222 #define O_MHSA 0x84 1223 /* 1224 "MaxHostStatAge", O_MHSA, TRUE, 1225 */ 1226 #define O_DEFCHARSET 0x85 1227 "DefaultCharSet", O_DEFCHARSET, TRUE, 1228 #define O_SSFILE 0x86 1229 "ServiceSwitchFile", O_SSFILE, FALSE, 1230 #define O_DIALDELAY 0x87 1231 "DialDelay", O_DIALDELAY, TRUE, 1232 1233 NULL, '\0', FALSE, 1234 }; 1235 1236 1237 1238 setoption(opt, val, safe, sticky, e) 1239 u_char opt; 1240 char *val; 1241 bool safe; 1242 bool sticky; 1243 register ENVELOPE *e; 1244 { 1245 register char *p; 1246 register struct optioninfo *o; 1247 char *subopt; 1248 extern bool atobool(); 1249 extern time_t convtime(); 1250 extern int QueueLA; 1251 extern int RefuseLA; 1252 extern bool Warn_Q_option; 1253 1254 errno = 0; 1255 if (opt == ' ') 1256 { 1257 /* full word options */ 1258 struct optioninfo *sel; 1259 1260 p = strchr(val, '='); 1261 if (p == NULL) 1262 p = &val[strlen(val)]; 1263 while (*--p == ' ') 1264 continue; 1265 while (*++p == ' ') 1266 *p = '\0'; 1267 if (p == val) 1268 { 1269 syserr("readcf: null option name"); 1270 return; 1271 } 1272 if (*p == '=') 1273 *p++ = '\0'; 1274 while (*p == ' ') 1275 p++; 1276 subopt = strchr(val, '.'); 1277 if (subopt != NULL) 1278 *subopt++ = '\0'; 1279 sel = NULL; 1280 for (o = OptionTab; o->o_name != NULL; o++) 1281 { 1282 if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1283 continue; 1284 if (strlen(o->o_name) == strlen(val)) 1285 { 1286 /* completely specified -- this must be it */ 1287 sel = NULL; 1288 break; 1289 } 1290 if (sel != NULL) 1291 break; 1292 sel = o; 1293 } 1294 if (sel != NULL && o->o_name == NULL) 1295 o = sel; 1296 else if (o->o_name == NULL) 1297 { 1298 syserr("readcf: unknown option name %s", val); 1299 return; 1300 } 1301 else if (sel != NULL) 1302 { 1303 syserr("readcf: ambiguous option name %s (matches %s and %s)", 1304 val, sel->o_name, o->o_name); 1305 return; 1306 } 1307 if (strlen(val) != strlen(o->o_name)) 1308 { 1309 bool oldVerbose = Verbose; 1310 1311 Verbose = TRUE; 1312 message("Option %s used as abbreviation for %s", 1313 val, o->o_name); 1314 Verbose = oldVerbose; 1315 } 1316 opt = o->o_code; 1317 val = p; 1318 } 1319 else 1320 { 1321 for (o = OptionTab; o->o_name != NULL; o++) 1322 { 1323 if (o->o_code == opt) 1324 break; 1325 } 1326 subopt = NULL; 1327 } 1328 1329 if (tTd(37, 1)) 1330 { 1331 printf(isascii(opt) && isprint(opt) ? 1332 "setoption %s (%c).%s=%s" : 1333 "setoption %s (0x%x).%s=%s", 1334 o->o_name == NULL ? "<unknown>" : o->o_name, 1335 opt, 1336 subopt == NULL ? "" : subopt, 1337 val); 1338 } 1339 1340 /* 1341 ** See if this option is preset for us. 1342 */ 1343 1344 if (!sticky && bitnset(opt, StickyOpt)) 1345 { 1346 if (tTd(37, 1)) 1347 printf(" (ignored)\n"); 1348 return; 1349 } 1350 1351 /* 1352 ** Check to see if this option can be specified by this user. 1353 */ 1354 1355 if (!safe && RealUid == 0) 1356 safe = TRUE; 1357 if (!safe && !o->o_safe) 1358 { 1359 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 1360 { 1361 if (tTd(37, 1)) 1362 printf(" (unsafe)"); 1363 if (RealUid != geteuid()) 1364 { 1365 if (tTd(37, 1)) 1366 printf("(Resetting uid)"); 1367 (void) setgid(RealGid); 1368 (void) setuid(RealUid); 1369 } 1370 } 1371 } 1372 if (tTd(37, 1)) 1373 printf("\n"); 1374 1375 switch (opt & 0xff) 1376 { 1377 case '7': /* force seven-bit input */ 1378 SevenBitInput = atobool(val); 1379 break; 1380 1381 case '8': /* handling of 8-bit input */ 1382 switch (*val) 1383 { 1384 case 'r': /* reject 8-bit, don't convert MIME */ 1385 MimeMode = 0; 1386 break; 1387 1388 case 'm': /* convert 8-bit, convert MIME */ 1389 MimeMode = MM_CVTMIME|MM_MIME8BIT; 1390 break; 1391 1392 case 'j': /* "just send 8" */ 1393 MimeMode = MM_PASS8BIT; 1394 break; 1395 1396 case 'p': /* pass 8 bit, convert MIME */ 1397 MimeMode = MM_PASS8BIT|MM_CVTMIME; 1398 break; 1399 1400 case 's': /* strict adherence */ 1401 MimeMode = MM_CVTMIME; 1402 break; 1403 1404 case 'a': /* encode 8 bit if available */ 1405 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1406 break; 1407 1408 case 'c': /* convert 8 bit to MIME, never 7 bit */ 1409 MimeMode = MM_MIME8BIT; 1410 break; 1411 1412 default: 1413 syserr("Unknown 8-bit mode %c", *val); 1414 exit(EX_USAGE); 1415 } 1416 break; 1417 1418 case 'A': /* set default alias file */ 1419 if (val[0] == '\0') 1420 setalias("aliases"); 1421 else 1422 setalias(val); 1423 break; 1424 1425 case 'a': /* look N minutes for "@:@" in alias file */ 1426 if (val[0] == '\0') 1427 SafeAlias = 5 * 60; /* five minutes */ 1428 else 1429 SafeAlias = convtime(val, 'm'); 1430 break; 1431 1432 case 'B': /* substitution for blank character */ 1433 SpaceSub = val[0]; 1434 if (SpaceSub == '\0') 1435 SpaceSub = ' '; 1436 break; 1437 1438 case 'b': /* min blocks free on queue fs/max msg size */ 1439 p = strchr(val, '/'); 1440 if (p != NULL) 1441 { 1442 *p++ = '\0'; 1443 MaxMessageSize = atol(p); 1444 } 1445 MinBlocksFree = atol(val); 1446 break; 1447 1448 case 'c': /* don't connect to "expensive" mailers */ 1449 NoConnect = atobool(val); 1450 break; 1451 1452 case 'C': /* checkpoint every N addresses */ 1453 CheckpointInterval = atoi(val); 1454 break; 1455 1456 case 'd': /* delivery mode */ 1457 switch (*val) 1458 { 1459 case '\0': 1460 e->e_sendmode = SM_DELIVER; 1461 break; 1462 1463 case SM_QUEUE: /* queue only */ 1464 #ifndef QUEUE 1465 syserr("need QUEUE to set -odqueue"); 1466 #endif /* QUEUE */ 1467 /* fall through..... */ 1468 1469 case SM_DELIVER: /* do everything */ 1470 case SM_FORK: /* fork after verification */ 1471 e->e_sendmode = *val; 1472 break; 1473 1474 default: 1475 syserr("Unknown delivery mode %c", *val); 1476 exit(EX_USAGE); 1477 } 1478 break; 1479 1480 case 'D': /* rebuild alias database as needed */ 1481 AutoRebuild = atobool(val); 1482 break; 1483 1484 case 'E': /* error message header/header file */ 1485 if (*val != '\0') 1486 ErrMsgFile = newstr(val); 1487 break; 1488 1489 case 'e': /* set error processing mode */ 1490 switch (*val) 1491 { 1492 case EM_QUIET: /* be silent about it */ 1493 case EM_MAIL: /* mail back */ 1494 case EM_BERKNET: /* do berknet error processing */ 1495 case EM_WRITE: /* write back (or mail) */ 1496 case EM_PRINT: /* print errors normally (default) */ 1497 e->e_errormode = *val; 1498 break; 1499 } 1500 break; 1501 1502 case 'F': /* file mode */ 1503 FileMode = atooct(val) & 0777; 1504 break; 1505 1506 case 'f': /* save Unix-style From lines on front */ 1507 SaveFrom = atobool(val); 1508 break; 1509 1510 case 'G': /* match recipients against GECOS field */ 1511 MatchGecos = atobool(val); 1512 break; 1513 1514 case 'g': /* default gid */ 1515 g_opt: 1516 if (isascii(*val) && isdigit(*val)) 1517 DefGid = atoi(val); 1518 else 1519 { 1520 register struct group *gr; 1521 1522 DefGid = -1; 1523 gr = getgrnam(val); 1524 if (gr == NULL) 1525 syserr("readcf: option %c: unknown group %s", 1526 opt, val); 1527 else 1528 DefGid = gr->gr_gid; 1529 } 1530 break; 1531 1532 case 'H': /* help file */ 1533 if (val[0] == '\0') 1534 HelpFile = "sendmail.hf"; 1535 else 1536 HelpFile = newstr(val); 1537 break; 1538 1539 case 'h': /* maximum hop count */ 1540 MaxHopCount = atoi(val); 1541 break; 1542 1543 case 'I': /* use internet domain name server */ 1544 #if NAMED_BIND 1545 for (p = val; *p != 0; ) 1546 { 1547 bool clearmode; 1548 char *q; 1549 struct resolverflags *rfp; 1550 1551 while (*p == ' ') 1552 p++; 1553 if (*p == '\0') 1554 break; 1555 clearmode = FALSE; 1556 if (*p == '-') 1557 clearmode = TRUE; 1558 else if (*p != '+') 1559 p--; 1560 p++; 1561 q = p; 1562 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1563 p++; 1564 if (*p != '\0') 1565 *p++ = '\0'; 1566 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 1567 { 1568 if (strcasecmp(q, rfp->rf_name) == 0) 1569 break; 1570 } 1571 if (rfp->rf_name == NULL) 1572 syserr("readcf: I option value %s unrecognized", q); 1573 else if (clearmode) 1574 _res.options &= ~rfp->rf_bits; 1575 else 1576 _res.options |= rfp->rf_bits; 1577 } 1578 if (tTd(8, 2)) 1579 printf("_res.options = %x\n", _res.options); 1580 #else 1581 usrerr("name server (I option) specified but BIND not compiled in"); 1582 #endif 1583 break; 1584 1585 case 'i': /* ignore dot lines in message */ 1586 IgnrDot = atobool(val); 1587 break; 1588 1589 case 'j': /* send errors in MIME (RFC 1341) format */ 1590 SendMIMEErrors = atobool(val); 1591 break; 1592 1593 case 'J': /* .forward search path */ 1594 ForwardPath = newstr(val); 1595 break; 1596 1597 case 'k': /* connection cache size */ 1598 MaxMciCache = atoi(val); 1599 if (MaxMciCache < 0) 1600 MaxMciCache = 0; 1601 break; 1602 1603 case 'K': /* connection cache timeout */ 1604 MciCacheTimeout = convtime(val, 'm'); 1605 break; 1606 1607 case 'l': /* use Errors-To: header */ 1608 UseErrorsTo = atobool(val); 1609 break; 1610 1611 case 'L': /* log level */ 1612 if (safe || LogLevel < atoi(val)) 1613 LogLevel = atoi(val); 1614 break; 1615 1616 case 'M': /* define macro */ 1617 define(val[0], newstr(&val[1]), CurEnv); 1618 sticky = FALSE; 1619 break; 1620 1621 case 'm': /* send to me too */ 1622 MeToo = atobool(val); 1623 break; 1624 1625 case 'n': /* validate RHS in newaliases */ 1626 CheckAliases = atobool(val); 1627 break; 1628 1629 /* 'N' available -- was "net name" */ 1630 1631 case 'O': /* daemon options */ 1632 setdaemonoptions(val); 1633 break; 1634 1635 case 'o': /* assume old style headers */ 1636 if (atobool(val)) 1637 CurEnv->e_flags |= EF_OLDSTYLE; 1638 else 1639 CurEnv->e_flags &= ~EF_OLDSTYLE; 1640 break; 1641 1642 case 'p': /* select privacy level */ 1643 p = val; 1644 for (;;) 1645 { 1646 register struct prival *pv; 1647 extern struct prival PrivacyValues[]; 1648 1649 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 1650 p++; 1651 if (*p == '\0') 1652 break; 1653 val = p; 1654 while (isascii(*p) && isalnum(*p)) 1655 p++; 1656 if (*p != '\0') 1657 *p++ = '\0'; 1658 1659 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 1660 { 1661 if (strcasecmp(val, pv->pv_name) == 0) 1662 break; 1663 } 1664 if (pv->pv_name == NULL) 1665 syserr("readcf: Op line: %s unrecognized", val); 1666 PrivacyFlags |= pv->pv_flag; 1667 } 1668 break; 1669 1670 case 'P': /* postmaster copy address for returned mail */ 1671 PostMasterCopy = newstr(val); 1672 break; 1673 1674 case 'q': /* slope of queue only function */ 1675 QueueFactor = atoi(val); 1676 break; 1677 1678 case 'Q': /* queue directory */ 1679 if (val[0] == '\0') 1680 QueueDir = "mqueue"; 1681 else 1682 QueueDir = newstr(val); 1683 if (RealUid != 0 && !safe) 1684 Warn_Q_option = TRUE; 1685 break; 1686 1687 case 'R': /* don't prune routes */ 1688 DontPruneRoutes = atobool(val); 1689 break; 1690 1691 case 'r': /* read timeout */ 1692 if (subopt == NULL) 1693 inittimeouts(val); 1694 else 1695 settimeout(subopt, val); 1696 break; 1697 1698 case 'S': /* status file */ 1699 if (val[0] == '\0') 1700 StatFile = "sendmail.st"; 1701 else 1702 StatFile = newstr(val); 1703 break; 1704 1705 case 's': /* be super safe, even if expensive */ 1706 SuperSafe = atobool(val); 1707 break; 1708 1709 case 'T': /* queue timeout */ 1710 p = strchr(val, '/'); 1711 if (p != NULL) 1712 { 1713 *p++ = '\0'; 1714 settimeout("queuewarn", p); 1715 } 1716 settimeout("queuereturn", val); 1717 break; 1718 1719 case 't': /* time zone name */ 1720 TimeZoneSpec = newstr(val); 1721 break; 1722 1723 case 'U': /* location of user database */ 1724 UdbSpec = newstr(val); 1725 break; 1726 1727 case 'u': /* set default uid */ 1728 for (p = val; *p != '\0'; p++) 1729 { 1730 if (*p == '.' || *p == '/' || *p == ':') 1731 { 1732 *p++ = '\0'; 1733 break; 1734 } 1735 } 1736 if (isascii(*val) && isdigit(*val)) 1737 DefUid = atoi(val); 1738 else 1739 { 1740 register struct passwd *pw; 1741 1742 DefUid = -1; 1743 pw = getpwnam(val); 1744 if (pw == NULL) 1745 syserr("readcf: option u: unknown user %s", val); 1746 else 1747 { 1748 DefUid = pw->pw_uid; 1749 DefGid = pw->pw_gid; 1750 } 1751 } 1752 setdefuser(); 1753 1754 /* handle the group if it is there */ 1755 if (*p == '\0') 1756 break; 1757 val = p; 1758 goto g_opt; 1759 1760 case 'V': /* fallback MX host */ 1761 FallBackMX = newstr(val); 1762 break; 1763 1764 case 'v': /* run in verbose mode */ 1765 Verbose = atobool(val); 1766 break; 1767 1768 case 'w': /* if we are best MX, try host directly */ 1769 TryNullMXList = atobool(val); 1770 break; 1771 1772 /* 'W' available -- was wizard password */ 1773 1774 case 'x': /* load avg at which to auto-queue msgs */ 1775 QueueLA = atoi(val); 1776 break; 1777 1778 case 'X': /* load avg at which to auto-reject connections */ 1779 RefuseLA = atoi(val); 1780 break; 1781 1782 case 'y': /* work recipient factor */ 1783 WkRecipFact = atoi(val); 1784 break; 1785 1786 case 'Y': /* fork jobs during queue runs */ 1787 ForkQueueRuns = atobool(val); 1788 break; 1789 1790 case 'z': /* work message class factor */ 1791 WkClassFact = atoi(val); 1792 break; 1793 1794 case 'Z': /* work time factor */ 1795 WkTimeFact = atoi(val); 1796 break; 1797 1798 case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 1799 BrokenSmtpPeers = atobool(val); 1800 break; 1801 1802 case O_QUEUESORTORD: /* queue sorting order */ 1803 switch (*val) 1804 { 1805 case 'h': /* Host first */ 1806 case 'H': 1807 QueueSortOrder = QS_BYHOST; 1808 break; 1809 1810 case 'p': /* Priority order */ 1811 case 'P': 1812 QueueSortOrder = QS_BYPRIORITY; 1813 break; 1814 1815 default: 1816 syserr("Invalid queue sort order \"%s\"", val); 1817 } 1818 break; 1819 1820 case O_MQA: /* minimum queue age between deliveries */ 1821 MinQueueAge = convtime(val, 'm'); 1822 break; 1823 1824 case O_MHSA: /* maximum age of cached host status */ 1825 MaxHostStatAge = convtime(val, 'm'); 1826 break; 1827 1828 case O_DEFCHARSET: /* default character set for mimefying */ 1829 DefaultCharSet = newstr(val); 1830 break; 1831 1832 case O_SSFILE: /* service switch file */ 1833 ServiceSwitchFile = newstr(val); 1834 break; 1835 1836 case O_DIALDELAY: /* delay for dial-on-demand operation */ 1837 DialDelay = convtime(val, 's'); 1838 break; 1839 1840 default: 1841 if (tTd(37, 1)) 1842 { 1843 if (isascii(opt) && isprint(opt)) 1844 printf("Warning: option %c unknown\n", opt); 1845 else 1846 printf("Warning: option 0x%x unknown\n", opt); 1847 } 1848 break; 1849 } 1850 if (sticky) 1851 setbitn(opt, StickyOpt); 1852 return; 1853 } 1854 /* 1855 ** SETCLASS -- set a word into a class 1856 ** 1857 ** Parameters: 1858 ** class -- the class to put the word in. 1859 ** word -- the word to enter 1860 ** 1861 ** Returns: 1862 ** none. 1863 ** 1864 ** Side Effects: 1865 ** puts the word into the symbol table. 1866 */ 1867 1868 setclass(class, word) 1869 int class; 1870 char *word; 1871 { 1872 register STAB *s; 1873 1874 if (tTd(37, 8)) 1875 printf("setclass(%c, %s)\n", class, word); 1876 s = stab(word, ST_CLASS, ST_ENTER); 1877 setbitn(class, s->s_class); 1878 } 1879 /* 1880 ** MAKEMAPENTRY -- create a map entry 1881 ** 1882 ** Parameters: 1883 ** line -- the config file line 1884 ** 1885 ** Returns: 1886 ** TRUE if it successfully entered the map entry. 1887 ** FALSE otherwise (usually syntax error). 1888 ** 1889 ** Side Effects: 1890 ** Enters the map into the dictionary. 1891 */ 1892 1893 void 1894 makemapentry(line) 1895 char *line; 1896 { 1897 register char *p; 1898 char *mapname; 1899 char *classname; 1900 register STAB *s; 1901 STAB *class; 1902 1903 for (p = line; isascii(*p) && isspace(*p); p++) 1904 continue; 1905 if (!(isascii(*p) && isalnum(*p))) 1906 { 1907 syserr("readcf: config K line: no map name"); 1908 return; 1909 } 1910 1911 mapname = p; 1912 while ((isascii(*++p) && isalnum(*p)) || *p == '.') 1913 continue; 1914 if (*p != '\0') 1915 *p++ = '\0'; 1916 while (isascii(*p) && isspace(*p)) 1917 p++; 1918 if (!(isascii(*p) && isalnum(*p))) 1919 { 1920 syserr("readcf: config K line, map %s: no map class", mapname); 1921 return; 1922 } 1923 classname = p; 1924 while (isascii(*++p) && isalnum(*p)) 1925 continue; 1926 if (*p != '\0') 1927 *p++ = '\0'; 1928 while (isascii(*p) && isspace(*p)) 1929 p++; 1930 1931 /* look up the class */ 1932 class = stab(classname, ST_MAPCLASS, ST_FIND); 1933 if (class == NULL) 1934 { 1935 syserr("readcf: map %s: class %s not available", mapname, classname); 1936 return; 1937 } 1938 1939 /* enter the map */ 1940 s = stab(mapname, ST_MAP, ST_ENTER); 1941 s->s_map.map_class = &class->s_mapclass; 1942 s->s_map.map_mname = newstr(mapname); 1943 1944 if (class->s_mapclass.map_parse(&s->s_map, p)) 1945 s->s_map.map_mflags |= MF_VALID; 1946 1947 if (tTd(37, 5)) 1948 { 1949 printf("map %s, class %s, flags %x, file %s,\n", 1950 s->s_map.map_mname, s->s_map.map_class->map_cname, 1951 s->s_map.map_mflags, 1952 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 1953 printf("\tapp %s, domain %s, rebuild %s\n", 1954 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 1955 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 1956 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 1957 } 1958 } 1959 /* 1960 ** INITTIMEOUTS -- parse and set timeout values 1961 ** 1962 ** Parameters: 1963 ** val -- a pointer to the values. If NULL, do initial 1964 ** settings. 1965 ** 1966 ** Returns: 1967 ** none. 1968 ** 1969 ** Side Effects: 1970 ** Initializes the TimeOuts structure 1971 */ 1972 1973 #define SECONDS 1974 #define MINUTES * 60 1975 #define HOUR * 3600 1976 1977 inittimeouts(val) 1978 register char *val; 1979 { 1980 register char *p; 1981 extern time_t convtime(); 1982 1983 if (val == NULL) 1984 { 1985 TimeOuts.to_initial = (time_t) 5 MINUTES; 1986 TimeOuts.to_helo = (time_t) 5 MINUTES; 1987 TimeOuts.to_mail = (time_t) 10 MINUTES; 1988 TimeOuts.to_rcpt = (time_t) 1 HOUR; 1989 TimeOuts.to_datainit = (time_t) 5 MINUTES; 1990 TimeOuts.to_datablock = (time_t) 1 HOUR; 1991 TimeOuts.to_datafinal = (time_t) 1 HOUR; 1992 TimeOuts.to_rset = (time_t) 5 MINUTES; 1993 TimeOuts.to_quit = (time_t) 2 MINUTES; 1994 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 1995 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 1996 #if IDENTPROTO 1997 TimeOuts.to_ident = (time_t) 30 SECONDS; 1998 #else 1999 TimeOuts.to_ident = (time_t) 0 SECONDS; 2000 #endif 2001 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 2002 return; 2003 } 2004 2005 for (;; val = p) 2006 { 2007 while (isascii(*val) && isspace(*val)) 2008 val++; 2009 if (*val == '\0') 2010 break; 2011 for (p = val; *p != '\0' && *p != ','; p++) 2012 continue; 2013 if (*p != '\0') 2014 *p++ = '\0'; 2015 2016 if (isascii(*val) && isdigit(*val)) 2017 { 2018 /* old syntax -- set everything */ 2019 TimeOuts.to_mail = convtime(val, 'm'); 2020 TimeOuts.to_rcpt = TimeOuts.to_mail; 2021 TimeOuts.to_datainit = TimeOuts.to_mail; 2022 TimeOuts.to_datablock = TimeOuts.to_mail; 2023 TimeOuts.to_datafinal = TimeOuts.to_mail; 2024 TimeOuts.to_nextcommand = TimeOuts.to_mail; 2025 continue; 2026 } 2027 else 2028 { 2029 register char *q = strchr(val, ':'); 2030 2031 if (q == NULL && (q = strchr(val, '=')) == NULL) 2032 { 2033 /* syntax error */ 2034 continue; 2035 } 2036 *q++ = '\0'; 2037 settimeout(val, q); 2038 } 2039 } 2040 } 2041 /* 2042 ** SETTIMEOUT -- set an individual timeout 2043 ** 2044 ** Parameters: 2045 ** name -- the name of the timeout. 2046 ** val -- the value of the timeout. 2047 ** 2048 ** Returns: 2049 ** none. 2050 */ 2051 2052 settimeout(name, val) 2053 char *name; 2054 char *val; 2055 { 2056 register char *p; 2057 time_t to; 2058 extern time_t convtime(); 2059 2060 to = convtime(val, 'm'); 2061 p = strchr(name, '.'); 2062 if (p != NULL) 2063 *p++ = '\0'; 2064 2065 if (strcasecmp(name, "initial") == 0) 2066 TimeOuts.to_initial = to; 2067 else if (strcasecmp(name, "mail") == 0) 2068 TimeOuts.to_mail = to; 2069 else if (strcasecmp(name, "rcpt") == 0) 2070 TimeOuts.to_rcpt = to; 2071 else if (strcasecmp(name, "datainit") == 0) 2072 TimeOuts.to_datainit = to; 2073 else if (strcasecmp(name, "datablock") == 0) 2074 TimeOuts.to_datablock = to; 2075 else if (strcasecmp(name, "datafinal") == 0) 2076 TimeOuts.to_datafinal = to; 2077 else if (strcasecmp(name, "command") == 0) 2078 TimeOuts.to_nextcommand = to; 2079 else if (strcasecmp(name, "rset") == 0) 2080 TimeOuts.to_rset = to; 2081 else if (strcasecmp(name, "helo") == 0) 2082 TimeOuts.to_helo = to; 2083 else if (strcasecmp(name, "quit") == 0) 2084 TimeOuts.to_quit = to; 2085 else if (strcasecmp(name, "misc") == 0) 2086 TimeOuts.to_miscshort = to; 2087 else if (strcasecmp(name, "ident") == 0) 2088 TimeOuts.to_ident = to; 2089 else if (strcasecmp(name, "fileopen") == 0) 2090 TimeOuts.to_fileopen = to; 2091 else if (strcasecmp(name, "queuewarn") == 0) 2092 { 2093 to = convtime(val, 'h'); 2094 if (p == NULL || strcmp(p, "*") == 0) 2095 { 2096 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2097 TimeOuts.to_q_warning[TOC_URGENT] = to; 2098 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2099 } 2100 else if (strcasecmp(p, "normal") == 0) 2101 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2102 else if (strcasecmp(p, "urgent") == 0) 2103 TimeOuts.to_q_warning[TOC_URGENT] = to; 2104 else if (strcasecmp(p, "non-urgent") == 0) 2105 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2106 else 2107 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2108 } 2109 else if (strcasecmp(name, "queuereturn") == 0) 2110 { 2111 to = convtime(val, 'd'); 2112 if (p == NULL || strcmp(p, "*") == 0) 2113 { 2114 TimeOuts.to_q_return[TOC_NORMAL] = to; 2115 TimeOuts.to_q_return[TOC_URGENT] = to; 2116 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2117 } 2118 else if (strcasecmp(p, "normal") == 0) 2119 TimeOuts.to_q_return[TOC_NORMAL] = to; 2120 else if (strcasecmp(p, "urgent") == 0) 2121 TimeOuts.to_q_return[TOC_URGENT] = to; 2122 else if (strcasecmp(p, "non-urgent") == 0) 2123 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2124 else 2125 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2126 } 2127 else 2128 syserr("settimeout: invalid timeout %s", name); 2129 } 2130