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.65 (Berkeley) 02/10/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 p = &buf[1]; 479 while (*p != '\0') 480 { 481 while (isspace(*p)) 482 p++; 483 q = p; 484 while (*p != '\0' && !isspace(*p)) 485 p++; 486 if (*p != '\0') 487 *p++ = '\0'; 488 if (*q == '\0') 489 continue; 490 (void) stab(q, ST_TRUSTED, ST_ENTER); 491 } 492 break; 493 494 case 'V': /* configuration syntax version */ 495 for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 496 continue; 497 if (!isascii(*p) || !isdigit(*p)) 498 { 499 syserr("invalid argument to V line: \"%.20s\"", 500 &bp[1]); 501 break; 502 } 503 ConfigLevel = strtol(p, &ep, 10); 504 if (ConfigLevel >= 5) 505 { 506 /* level 5 configs have short name in $w */ 507 p = macvalue('w', e); 508 if (p != NULL && (p = strchr(p, '.')) != NULL) 509 *p = '\0'; 510 } 511 if (*ep++ == '/') 512 { 513 /* extract vendor code */ 514 for (p = ep; isascii(*p) && isalpha(*p); ) 515 p++; 516 *p = '\0'; 517 518 if (!setvendor(ep)) 519 syserr("invalid V line vendor code: \"%s\"", 520 ep); 521 } 522 break; 523 524 case 'K': 525 makemapentry(&bp[1]); 526 break; 527 528 default: 529 badline: 530 syserr("unknown control line \"%s\"", bp); 531 } 532 if (bp != buf) 533 free(bp); 534 } 535 if (ferror(cf)) 536 { 537 syserr("I/O read error", cfname); 538 exit(EX_OSFILE); 539 } 540 fclose(cf); 541 FileName = NULL; 542 543 /* initialize host maps from local service tables */ 544 inithostmaps(); 545 546 /* determine if we need to do special name-server frotz */ 547 { 548 int nmaps; 549 char *maptype[MAXMAPSTACK]; 550 short mapreturn[MAXMAPACTIONS]; 551 552 nmaps = switch_map_find("hosts", maptype, mapreturn); 553 UseNameServer = FALSE; 554 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 555 { 556 register int mapno; 557 558 for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 559 { 560 if (strcmp(maptype[mapno], "dns") == 0) 561 UseNameServer = TRUE; 562 } 563 } 564 565 #ifdef HESIOD 566 nmaps = switch_map_find("passwd", maptype, mapreturn); 567 UseHesiod = FALSE; 568 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 569 { 570 register int mapno; 571 572 for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 573 { 574 if (strcmp(maptype[mapno], "hesiod") == 0) 575 UseHesiod = TRUE; 576 } 577 } 578 #endif 579 } 580 } 581 /* 582 ** TOOMANY -- signal too many of some option 583 ** 584 ** Parameters: 585 ** id -- the id of the error line 586 ** maxcnt -- the maximum possible values 587 ** 588 ** Returns: 589 ** none. 590 ** 591 ** Side Effects: 592 ** gives a syserr. 593 */ 594 595 toomany(id, maxcnt) 596 char id; 597 int maxcnt; 598 { 599 syserr("too many %c lines, %d max", id, maxcnt); 600 } 601 /* 602 ** FILECLASS -- read members of a class from a file 603 ** 604 ** Parameters: 605 ** class -- class to define. 606 ** filename -- name of file to read. 607 ** fmt -- scanf string to use for match. 608 ** safe -- if set, this is a safe read. 609 ** optional -- if set, it is not an error for the file to 610 ** not exist. 611 ** 612 ** Returns: 613 ** none 614 ** 615 ** Side Effects: 616 ** 617 ** puts all lines in filename that match a scanf into 618 ** the named class. 619 */ 620 621 fileclass(class, filename, fmt, safe, optional) 622 int class; 623 char *filename; 624 char *fmt; 625 bool safe; 626 bool optional; 627 { 628 FILE *f; 629 struct stat stbuf; 630 char buf[MAXLINE]; 631 632 if (tTd(37, 2)) 633 printf("fileclass(%s, fmt=%s)\n", filename, fmt); 634 635 if (filename[0] == '|') 636 { 637 syserr("fileclass: pipes (F%c%s) not supported due to security problems", 638 class, filename); 639 return; 640 } 641 if (stat(filename, &stbuf) < 0) 642 { 643 if (tTd(37, 2)) 644 printf(" cannot stat (%s)\n", errstring(errno)); 645 if (!optional) 646 syserr("fileclass: cannot stat %s", filename); 647 return; 648 } 649 if (!S_ISREG(stbuf.st_mode)) 650 { 651 syserr("fileclass: %s not a regular file", filename); 652 return; 653 } 654 if (!safe && access(filename, R_OK) < 0) 655 { 656 syserr("fileclass: access denied on %s", filename); 657 return; 658 } 659 f = fopen(filename, "r"); 660 if (f == NULL) 661 { 662 syserr("fileclass: cannot open %s", filename); 663 return; 664 } 665 666 while (fgets(buf, sizeof buf, f) != NULL) 667 { 668 register STAB *s; 669 register char *p; 670 # ifdef SCANF 671 char wordbuf[MAXNAME+1]; 672 673 if (sscanf(buf, fmt, wordbuf) != 1) 674 continue; 675 p = wordbuf; 676 # else /* SCANF */ 677 p = buf; 678 # endif /* SCANF */ 679 680 /* 681 ** Break up the match into words. 682 */ 683 684 while (*p != '\0') 685 { 686 register char *q; 687 688 /* strip leading spaces */ 689 while (isascii(*p) && isspace(*p)) 690 p++; 691 if (*p == '\0') 692 break; 693 694 /* find the end of the word */ 695 q = p; 696 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 697 p++; 698 if (*p != '\0') 699 *p++ = '\0'; 700 701 /* enter the word in the symbol table */ 702 setclass(class, q); 703 } 704 } 705 706 (void) fclose(f); 707 } 708 /* 709 ** MAKEMAILER -- define a new mailer. 710 ** 711 ** Parameters: 712 ** line -- description of mailer. This is in labeled 713 ** fields. The fields are: 714 ** A -- the argv for this mailer 715 ** C -- the character set for MIME conversions 716 ** D -- the directory to run in 717 ** E -- the eol string 718 ** F -- the flags associated with the mailer 719 ** L -- the maximum line length 720 ** M -- the maximum message size 721 ** P -- the path to the mailer 722 ** R -- the recipient rewriting set 723 ** S -- the sender rewriting set 724 ** T -- the mailer type (for DSNs) 725 ** U -- the uid to run as 726 ** The first word is the canonical name of the mailer. 727 ** 728 ** Returns: 729 ** none. 730 ** 731 ** Side Effects: 732 ** enters the mailer into the mailer table. 733 */ 734 735 makemailer(line) 736 char *line; 737 { 738 register char *p; 739 register struct mailer *m; 740 register STAB *s; 741 int i; 742 char fcode; 743 auto char *endp; 744 extern int NextMailer; 745 extern char **makeargv(); 746 extern char *munchstring(); 747 extern long atol(); 748 749 /* allocate a mailer and set up defaults */ 750 m = (struct mailer *) xalloc(sizeof *m); 751 bzero((char *) m, sizeof *m); 752 m->m_eol = "\n"; 753 m->m_uid = m->m_gid = 0; 754 755 /* collect the mailer name */ 756 for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 757 continue; 758 if (*p != '\0') 759 *p++ = '\0'; 760 m->m_name = newstr(line); 761 762 /* now scan through and assign info from the fields */ 763 while (*p != '\0') 764 { 765 auto char *delimptr; 766 767 while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 768 p++; 769 770 /* p now points to field code */ 771 fcode = *p; 772 while (*p != '\0' && *p != '=' && *p != ',') 773 p++; 774 if (*p++ != '=') 775 { 776 syserr("mailer %s: `=' expected", m->m_name); 777 return; 778 } 779 while (isascii(*p) && isspace(*p)) 780 p++; 781 782 /* p now points to the field body */ 783 p = munchstring(p, &delimptr); 784 785 /* install the field into the mailer struct */ 786 switch (fcode) 787 { 788 case 'P': /* pathname */ 789 m->m_mailer = newstr(p); 790 break; 791 792 case 'F': /* flags */ 793 for (; *p != '\0'; p++) 794 if (!(isascii(*p) && isspace(*p))) 795 setbitn(*p, m->m_flags); 796 break; 797 798 case 'S': /* sender rewriting ruleset */ 799 case 'R': /* recipient rewriting ruleset */ 800 i = strtol(p, &endp, 10); 801 if (i < 0 || i >= MAXRWSETS) 802 { 803 syserr("invalid rewrite set, %d max", MAXRWSETS); 804 return; 805 } 806 if (fcode == 'S') 807 m->m_sh_rwset = m->m_se_rwset = i; 808 else 809 m->m_rh_rwset = m->m_re_rwset = i; 810 811 p = endp; 812 if (*p++ == '/') 813 { 814 i = strtol(p, NULL, 10); 815 if (i < 0 || i >= MAXRWSETS) 816 { 817 syserr("invalid rewrite set, %d max", 818 MAXRWSETS); 819 return; 820 } 821 if (fcode == 'S') 822 m->m_sh_rwset = i; 823 else 824 m->m_rh_rwset = i; 825 } 826 break; 827 828 case 'E': /* end of line string */ 829 m->m_eol = newstr(p); 830 break; 831 832 case 'A': /* argument vector */ 833 m->m_argv = makeargv(p); 834 break; 835 836 case 'M': /* maximum message size */ 837 m->m_maxsize = atol(p); 838 break; 839 840 case 'L': /* maximum line length */ 841 m->m_linelimit = atoi(p); 842 break; 843 844 case 'D': /* working directory */ 845 m->m_execdir = newstr(p); 846 break; 847 848 case 'C': /* default charset */ 849 m->m_defcharset = newstr(p); 850 break; 851 852 case 'T': /* MTA Type */ 853 m->m_mtatype = newstr(p); 854 p = strchr(m->m_mtatype, '/'); 855 if (p != NULL) 856 { 857 *p++ = '\0'; 858 if (*p == '\0') 859 p = NULL; 860 } 861 if (p == NULL) 862 m->m_addrtype = m->m_mtatype; 863 else 864 { 865 m->m_addrtype = p; 866 p = strchr(p, '/'); 867 } 868 if (p != NULL) 869 { 870 *p++ = '\0'; 871 if (*p == '\0') 872 p = NULL; 873 } 874 if (p == NULL) 875 m->m_diagtype = m->m_mtatype; 876 else 877 m->m_diagtype = p; 878 break; 879 880 case 'U': /* user id */ 881 if (isascii(*p) && !isdigit(*p)) 882 { 883 char *q = p; 884 struct passwd *pw; 885 886 while (isascii(*p) && isalnum(*p)) 887 p++; 888 while (isascii(*p) && isspace(*p)) 889 *p++ = '\0'; 890 if (*p != '\0') 891 *p++ = '\0'; 892 pw = getpwnam(q); 893 if (pw == NULL) 894 syserr("readcf: mailer U= flag: unknown user %s", q); 895 else 896 { 897 m->m_uid = pw->pw_uid; 898 m->m_gid = pw->pw_gid; 899 } 900 } 901 else 902 { 903 auto char *q; 904 905 m->m_uid = strtol(p, &q, 0); 906 p = q; 907 } 908 while (isascii(*p) && isspace(*p)) 909 p++; 910 if (*p == '\0') 911 break; 912 if (isascii(*p) && !isdigit(*p)) 913 { 914 char *q = p; 915 struct group *gr; 916 917 while (isascii(*p) && isalnum(*p)) 918 p++; 919 *p++ = '\0'; 920 gr = getgrnam(q); 921 if (gr == NULL) 922 syserr("readcf: mailer U= flag: unknown group %s", q); 923 else 924 m->m_gid = gr->gr_gid; 925 } 926 else 927 { 928 m->m_gid = strtol(p, NULL, 0); 929 } 930 break; 931 } 932 933 p = delimptr; 934 } 935 936 /* do some rationality checking */ 937 if (m->m_argv == NULL) 938 { 939 syserr("M%s: A= argument required", m->m_name); 940 return; 941 } 942 if (m->m_mailer == NULL) 943 { 944 syserr("M%s: P= argument required", m->m_name); 945 return; 946 } 947 948 if (NextMailer >= MAXMAILERS) 949 { 950 syserr("too many mailers defined (%d max)", MAXMAILERS); 951 return; 952 } 953 954 /* do some heuristic cleanup for back compatibility */ 955 if (bitnset(M_LIMITS, m->m_flags)) 956 { 957 if (m->m_linelimit == 0) 958 m->m_linelimit = SMTPLINELIM; 959 if (ConfigLevel < 2) 960 setbitn(M_7BITS, m->m_flags); 961 } 962 963 if (ConfigLevel < 6 && 964 (strcmp(m->m_mailer, "[IPC]") == 0 || 965 strcmp(m->m_mailer, "[TCP]") == 0)) 966 { 967 if (m->m_mtatype == NULL) 968 m->m_mtatype = "dns"; 969 if (m->m_addrtype == NULL) 970 m->m_addrtype = "rfc822"; 971 if (m->m_diagtype == NULL) 972 m->m_diagtype = "smtp"; 973 } 974 975 /* enter the mailer into the symbol table */ 976 s = stab(m->m_name, ST_MAILER, ST_ENTER); 977 if (s->s_mailer != NULL) 978 { 979 i = s->s_mailer->m_mno; 980 free(s->s_mailer); 981 } 982 else 983 { 984 i = NextMailer++; 985 } 986 Mailer[i] = s->s_mailer = m; 987 m->m_mno = i; 988 } 989 /* 990 ** MUNCHSTRING -- translate a string into internal form. 991 ** 992 ** Parameters: 993 ** p -- the string to munch. 994 ** delimptr -- if non-NULL, set to the pointer of the 995 ** field delimiter character. 996 ** 997 ** Returns: 998 ** the munched string. 999 */ 1000 1001 char * 1002 munchstring(p, delimptr) 1003 register char *p; 1004 char **delimptr; 1005 { 1006 register char *q; 1007 bool backslash = FALSE; 1008 bool quotemode = FALSE; 1009 static char buf[MAXLINE]; 1010 1011 for (q = buf; *p != '\0'; p++) 1012 { 1013 if (backslash) 1014 { 1015 /* everything is roughly literal */ 1016 backslash = FALSE; 1017 switch (*p) 1018 { 1019 case 'r': /* carriage return */ 1020 *q++ = '\r'; 1021 continue; 1022 1023 case 'n': /* newline */ 1024 *q++ = '\n'; 1025 continue; 1026 1027 case 'f': /* form feed */ 1028 *q++ = '\f'; 1029 continue; 1030 1031 case 'b': /* backspace */ 1032 *q++ = '\b'; 1033 continue; 1034 } 1035 *q++ = *p; 1036 } 1037 else 1038 { 1039 if (*p == '\\') 1040 backslash = TRUE; 1041 else if (*p == '"') 1042 quotemode = !quotemode; 1043 else if (quotemode || *p != ',') 1044 *q++ = *p; 1045 else 1046 break; 1047 } 1048 } 1049 1050 if (delimptr != NULL) 1051 *delimptr = p; 1052 *q++ = '\0'; 1053 return (buf); 1054 } 1055 /* 1056 ** MAKEARGV -- break up a string into words 1057 ** 1058 ** Parameters: 1059 ** p -- the string to break up. 1060 ** 1061 ** Returns: 1062 ** a char **argv (dynamically allocated) 1063 ** 1064 ** Side Effects: 1065 ** munges p. 1066 */ 1067 1068 char ** 1069 makeargv(p) 1070 register char *p; 1071 { 1072 char *q; 1073 int i; 1074 char **avp; 1075 char *argv[MAXPV + 1]; 1076 1077 /* take apart the words */ 1078 i = 0; 1079 while (*p != '\0' && i < MAXPV) 1080 { 1081 q = p; 1082 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1083 p++; 1084 while (isascii(*p) && isspace(*p)) 1085 *p++ = '\0'; 1086 argv[i++] = newstr(q); 1087 } 1088 argv[i++] = NULL; 1089 1090 /* now make a copy of the argv */ 1091 avp = (char **) xalloc(sizeof *avp * i); 1092 bcopy((char *) argv, (char *) avp, sizeof *avp * i); 1093 1094 return (avp); 1095 } 1096 /* 1097 ** PRINTRULES -- print rewrite rules (for debugging) 1098 ** 1099 ** Parameters: 1100 ** none. 1101 ** 1102 ** Returns: 1103 ** none. 1104 ** 1105 ** Side Effects: 1106 ** prints rewrite rules. 1107 */ 1108 1109 printrules() 1110 { 1111 register struct rewrite *rwp; 1112 register int ruleset; 1113 1114 for (ruleset = 0; ruleset < 10; ruleset++) 1115 { 1116 if (RewriteRules[ruleset] == NULL) 1117 continue; 1118 printf("\n----Rule Set %d:", ruleset); 1119 1120 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 1121 { 1122 printf("\nLHS:"); 1123 printav(rwp->r_lhs); 1124 printf("RHS:"); 1125 printav(rwp->r_rhs); 1126 } 1127 } 1128 } 1129 /* 1130 ** PRINTMAILER -- print mailer structure (for debugging) 1131 ** 1132 ** Parameters: 1133 ** m -- the mailer to print 1134 ** 1135 ** Returns: 1136 ** none. 1137 */ 1138 1139 printmailer(m) 1140 register MAILER *m; 1141 { 1142 int j; 1143 1144 printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 1145 m->m_mno, m->m_name, 1146 m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 1147 m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 1148 m->m_uid, m->m_gid); 1149 for (j = '\0'; j <= '\177'; j++) 1150 if (bitnset(j, m->m_flags)) 1151 (void) putchar(j); 1152 printf(" L=%d E=", m->m_linelimit); 1153 xputs(m->m_eol); 1154 if (m->m_defcharset != NULL) 1155 printf(" C=%s", m->m_defcharset); 1156 printf(" T=%s/%s/%s", 1157 m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 1158 m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 1159 m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 1160 if (m->m_argv != NULL) 1161 { 1162 char **a = m->m_argv; 1163 1164 printf(" A="); 1165 while (*a != NULL) 1166 { 1167 if (a != m->m_argv) 1168 printf(" "); 1169 xputs(*a++); 1170 } 1171 } 1172 printf("\n"); 1173 } 1174 /* 1175 ** SETOPTION -- set global processing option 1176 ** 1177 ** Parameters: 1178 ** opt -- option name. 1179 ** val -- option value (as a text string). 1180 ** safe -- set if this came from a configuration file. 1181 ** Some options (if set from the command line) will 1182 ** reset the user id to avoid security problems. 1183 ** sticky -- if set, don't let other setoptions override 1184 ** this value. 1185 ** e -- the main envelope. 1186 ** 1187 ** Returns: 1188 ** none. 1189 ** 1190 ** Side Effects: 1191 ** Sets options as implied by the arguments. 1192 */ 1193 1194 static BITMAP StickyOpt; /* set if option is stuck */ 1195 1196 1197 #if NAMED_BIND 1198 1199 struct resolverflags 1200 { 1201 char *rf_name; /* name of the flag */ 1202 long rf_bits; /* bits to set/clear */ 1203 } ResolverFlags[] = 1204 { 1205 "debug", RES_DEBUG, 1206 "aaonly", RES_AAONLY, 1207 "usevc", RES_USEVC, 1208 "primary", RES_PRIMARY, 1209 "igntc", RES_IGNTC, 1210 "recurse", RES_RECURSE, 1211 "defnames", RES_DEFNAMES, 1212 "stayopen", RES_STAYOPEN, 1213 "dnsrch", RES_DNSRCH, 1214 "true", 0, /* to avoid error on old syntax */ 1215 NULL, 0 1216 }; 1217 1218 #endif 1219 1220 struct optioninfo 1221 { 1222 char *o_name; /* long name of option */ 1223 u_char o_code; /* short name of option */ 1224 bool o_safe; /* safe for random people to use */ 1225 } OptionTab[] = 1226 { 1227 "SevenBitInput", '7', TRUE, 1228 "EightBitMode", '8', TRUE, 1229 "AliasFile", 'A', FALSE, 1230 "AliasWait", 'a', FALSE, 1231 "BlankSub", 'B', FALSE, 1232 "MinFreeBlocks", 'b', TRUE, 1233 "CheckpointInterval", 'C', TRUE, 1234 "HoldExpensive", 'c', FALSE, 1235 "AutoRebuildAliases", 'D', FALSE, 1236 "DeliveryMode", 'd', TRUE, 1237 "ErrorHeader", 'E', FALSE, 1238 "ErrorMode", 'e', TRUE, 1239 "TempFileMode", 'F', FALSE, 1240 "SaveFromLine", 'f', FALSE, 1241 "MatchGECOS", 'G', FALSE, 1242 "HelpFile", 'H', FALSE, 1243 "MaxHopCount", 'h', FALSE, 1244 "NameServerOptions", 'I', FALSE, 1245 "IgnoreDots", 'i', TRUE, 1246 "ForwardPath", 'J', FALSE, 1247 "SendMimeErrors", 'j', TRUE, 1248 "ConnectionCacheSize", 'k', FALSE, 1249 "ConnectionCacheTimeout", 'K', FALSE, 1250 "UseErrorsTo", 'l', FALSE, 1251 "LogLevel", 'L', FALSE, 1252 "MeToo", 'm', TRUE, 1253 "CheckAliases", 'n', FALSE, 1254 "OldStyleHeaders", 'o', TRUE, 1255 "DaemonPortOptions", 'O', FALSE, 1256 "PrivacyOptions", 'p', TRUE, 1257 "PostmasterCopy", 'P', FALSE, 1258 "QueueFactor", 'q', FALSE, 1259 "QueueDirectory", 'Q', FALSE, 1260 "DontPruneRoutes", 'R', FALSE, 1261 "Timeout", 'r', TRUE, 1262 "StatusFile", 'S', FALSE, 1263 "SuperSafe", 's', TRUE, 1264 "QueueTimeout", 'T', FALSE, 1265 "TimeZoneSpec", 't', FALSE, 1266 "UserDatabaseSpec", 'U', FALSE, 1267 "DefaultUser", 'u', FALSE, 1268 "FallbackMXhost", 'V', FALSE, 1269 "Verbose", 'v', TRUE, 1270 "TryNullMXList", 'w', TRUE, 1271 "QueueLA", 'x', FALSE, 1272 "RefuseLA", 'X', FALSE, 1273 "RecipientFactor", 'y', FALSE, 1274 "ForkQueueRuns", 'Y', FALSE, 1275 "ClassFactor", 'z', FALSE, 1276 "TimeFactor", 'Z', FALSE, 1277 #define O_BSP 0x80 1278 "BrokenSmtpPeers", O_BSP, TRUE, 1279 #define O_QUEUESORTORD 0x81 1280 "QueueSortOrder", O_QUEUESORTORD, TRUE, 1281 #define O_MQA 0x83 1282 "MinQueueAge", O_MQA, TRUE, 1283 #define O_MHSA 0x84 1284 /* 1285 "MaxHostStatAge", O_MHSA, TRUE, 1286 */ 1287 #define O_DEFCHARSET 0x85 1288 "DefaultCharSet", O_DEFCHARSET, TRUE, 1289 #define O_SSFILE 0x86 1290 "ServiceSwitchFile", O_SSFILE, FALSE, 1291 #define O_DIALDELAY 0x87 1292 "DialDelay", O_DIALDELAY, TRUE, 1293 1294 NULL, '\0', FALSE, 1295 }; 1296 1297 1298 1299 setoption(opt, val, safe, sticky, e) 1300 u_char opt; 1301 char *val; 1302 bool safe; 1303 bool sticky; 1304 register ENVELOPE *e; 1305 { 1306 register char *p; 1307 register struct optioninfo *o; 1308 char *subopt; 1309 extern bool atobool(); 1310 extern time_t convtime(); 1311 extern int QueueLA; 1312 extern int RefuseLA; 1313 extern bool Warn_Q_option; 1314 1315 errno = 0; 1316 if (opt == ' ') 1317 { 1318 /* full word options */ 1319 struct optioninfo *sel; 1320 1321 p = strchr(val, '='); 1322 if (p == NULL) 1323 p = &val[strlen(val)]; 1324 while (*--p == ' ') 1325 continue; 1326 while (*++p == ' ') 1327 *p = '\0'; 1328 if (p == val) 1329 { 1330 syserr("readcf: null option name"); 1331 return; 1332 } 1333 if (*p == '=') 1334 *p++ = '\0'; 1335 while (*p == ' ') 1336 p++; 1337 subopt = strchr(val, '.'); 1338 if (subopt != NULL) 1339 *subopt++ = '\0'; 1340 sel = NULL; 1341 for (o = OptionTab; o->o_name != NULL; o++) 1342 { 1343 if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1344 continue; 1345 if (strlen(o->o_name) == strlen(val)) 1346 { 1347 /* completely specified -- this must be it */ 1348 sel = NULL; 1349 break; 1350 } 1351 if (sel != NULL) 1352 break; 1353 sel = o; 1354 } 1355 if (sel != NULL && o->o_name == NULL) 1356 o = sel; 1357 else if (o->o_name == NULL) 1358 { 1359 syserr("readcf: unknown option name %s", val); 1360 return; 1361 } 1362 else if (sel != NULL) 1363 { 1364 syserr("readcf: ambiguous option name %s (matches %s and %s)", 1365 val, sel->o_name, o->o_name); 1366 return; 1367 } 1368 if (strlen(val) != strlen(o->o_name)) 1369 { 1370 bool oldVerbose = Verbose; 1371 1372 Verbose = TRUE; 1373 message("Option %s used as abbreviation for %s", 1374 val, o->o_name); 1375 Verbose = oldVerbose; 1376 } 1377 opt = o->o_code; 1378 val = p; 1379 } 1380 else 1381 { 1382 for (o = OptionTab; o->o_name != NULL; o++) 1383 { 1384 if (o->o_code == opt) 1385 break; 1386 } 1387 subopt = NULL; 1388 } 1389 1390 if (tTd(37, 1)) 1391 { 1392 printf(isascii(opt) && isprint(opt) ? 1393 "setoption %s (%c).%s=%s" : 1394 "setoption %s (0x%x).%s=%s", 1395 o->o_name == NULL ? "<unknown>" : o->o_name, 1396 opt, 1397 subopt == NULL ? "" : subopt, 1398 val); 1399 } 1400 1401 /* 1402 ** See if this option is preset for us. 1403 */ 1404 1405 if (!sticky && bitnset(opt, StickyOpt)) 1406 { 1407 if (tTd(37, 1)) 1408 printf(" (ignored)\n"); 1409 return; 1410 } 1411 1412 /* 1413 ** Check to see if this option can be specified by this user. 1414 */ 1415 1416 if (!safe && RealUid == 0) 1417 safe = TRUE; 1418 if (!safe && !o->o_safe) 1419 { 1420 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 1421 { 1422 if (tTd(37, 1)) 1423 printf(" (unsafe)"); 1424 if (RealUid != geteuid()) 1425 { 1426 if (tTd(37, 1)) 1427 printf("(Resetting uid)"); 1428 (void) setgid(RealGid); 1429 (void) setuid(RealUid); 1430 } 1431 } 1432 } 1433 if (tTd(37, 1)) 1434 printf("\n"); 1435 1436 switch (opt & 0xff) 1437 { 1438 case '7': /* force seven-bit input */ 1439 SevenBitInput = atobool(val); 1440 break; 1441 1442 case '8': /* handling of 8-bit input */ 1443 switch (*val) 1444 { 1445 case 'r': /* reject 8-bit, don't convert MIME */ 1446 MimeMode = 0; 1447 break; 1448 1449 case 'm': /* convert 8-bit, convert MIME */ 1450 MimeMode = MM_CVTMIME|MM_MIME8BIT; 1451 break; 1452 1453 case 'j': /* "just send 8" */ 1454 MimeMode = MM_PASS8BIT; 1455 break; 1456 1457 case 'p': /* pass 8 bit, convert MIME */ 1458 MimeMode = MM_PASS8BIT|MM_CVTMIME; 1459 break; 1460 1461 case 's': /* strict adherence */ 1462 MimeMode = MM_CVTMIME; 1463 break; 1464 1465 case 'a': /* encode 8 bit if available */ 1466 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1467 break; 1468 1469 case 'c': /* convert 8 bit to MIME, never 7 bit */ 1470 MimeMode = MM_MIME8BIT; 1471 break; 1472 1473 default: 1474 syserr("Unknown 8-bit mode %c", *val); 1475 exit(EX_USAGE); 1476 } 1477 break; 1478 1479 case 'A': /* set default alias file */ 1480 if (val[0] == '\0') 1481 setalias("aliases"); 1482 else 1483 setalias(val); 1484 break; 1485 1486 case 'a': /* look N minutes for "@:@" in alias file */ 1487 if (val[0] == '\0') 1488 SafeAlias = 5 * 60; /* five minutes */ 1489 else 1490 SafeAlias = convtime(val, 'm'); 1491 break; 1492 1493 case 'B': /* substitution for blank character */ 1494 SpaceSub = val[0]; 1495 if (SpaceSub == '\0') 1496 SpaceSub = ' '; 1497 break; 1498 1499 case 'b': /* min blocks free on queue fs/max msg size */ 1500 p = strchr(val, '/'); 1501 if (p != NULL) 1502 { 1503 *p++ = '\0'; 1504 MaxMessageSize = atol(p); 1505 } 1506 MinBlocksFree = atol(val); 1507 break; 1508 1509 case 'c': /* don't connect to "expensive" mailers */ 1510 NoConnect = atobool(val); 1511 break; 1512 1513 case 'C': /* checkpoint every N addresses */ 1514 CheckpointInterval = atoi(val); 1515 break; 1516 1517 case 'd': /* delivery mode */ 1518 switch (*val) 1519 { 1520 case '\0': 1521 e->e_sendmode = SM_DELIVER; 1522 break; 1523 1524 case SM_QUEUE: /* queue only */ 1525 #ifndef QUEUE 1526 syserr("need QUEUE to set -odqueue"); 1527 #endif /* QUEUE */ 1528 /* fall through..... */ 1529 1530 case SM_DELIVER: /* do everything */ 1531 case SM_FORK: /* fork after verification */ 1532 e->e_sendmode = *val; 1533 break; 1534 1535 default: 1536 syserr("Unknown delivery mode %c", *val); 1537 exit(EX_USAGE); 1538 } 1539 break; 1540 1541 case 'D': /* rebuild alias database as needed */ 1542 AutoRebuild = atobool(val); 1543 break; 1544 1545 case 'E': /* error message header/header file */ 1546 if (*val != '\0') 1547 ErrMsgFile = newstr(val); 1548 break; 1549 1550 case 'e': /* set error processing mode */ 1551 switch (*val) 1552 { 1553 case EM_QUIET: /* be silent about it */ 1554 case EM_MAIL: /* mail back */ 1555 case EM_BERKNET: /* do berknet error processing */ 1556 case EM_WRITE: /* write back (or mail) */ 1557 case EM_PRINT: /* print errors normally (default) */ 1558 e->e_errormode = *val; 1559 break; 1560 } 1561 break; 1562 1563 case 'F': /* file mode */ 1564 FileMode = atooct(val) & 0777; 1565 break; 1566 1567 case 'f': /* save Unix-style From lines on front */ 1568 SaveFrom = atobool(val); 1569 break; 1570 1571 case 'G': /* match recipients against GECOS field */ 1572 MatchGecos = atobool(val); 1573 break; 1574 1575 case 'g': /* default gid */ 1576 g_opt: 1577 if (isascii(*val) && isdigit(*val)) 1578 DefGid = atoi(val); 1579 else 1580 { 1581 register struct group *gr; 1582 1583 DefGid = -1; 1584 gr = getgrnam(val); 1585 if (gr == NULL) 1586 syserr("readcf: option %c: unknown group %s", 1587 opt, val); 1588 else 1589 DefGid = gr->gr_gid; 1590 } 1591 break; 1592 1593 case 'H': /* help file */ 1594 if (val[0] == '\0') 1595 HelpFile = "sendmail.hf"; 1596 else 1597 HelpFile = newstr(val); 1598 break; 1599 1600 case 'h': /* maximum hop count */ 1601 MaxHopCount = atoi(val); 1602 break; 1603 1604 case 'I': /* use internet domain name server */ 1605 #if NAMED_BIND 1606 for (p = val; *p != 0; ) 1607 { 1608 bool clearmode; 1609 char *q; 1610 struct resolverflags *rfp; 1611 1612 while (*p == ' ') 1613 p++; 1614 if (*p == '\0') 1615 break; 1616 clearmode = FALSE; 1617 if (*p == '-') 1618 clearmode = TRUE; 1619 else if (*p != '+') 1620 p--; 1621 p++; 1622 q = p; 1623 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1624 p++; 1625 if (*p != '\0') 1626 *p++ = '\0'; 1627 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 1628 { 1629 if (strcasecmp(q, rfp->rf_name) == 0) 1630 break; 1631 } 1632 if (rfp->rf_name == NULL) 1633 syserr("readcf: I option value %s unrecognized", q); 1634 else if (clearmode) 1635 _res.options &= ~rfp->rf_bits; 1636 else 1637 _res.options |= rfp->rf_bits; 1638 } 1639 if (tTd(8, 2)) 1640 printf("_res.options = %x\n", _res.options); 1641 #else 1642 usrerr("name server (I option) specified but BIND not compiled in"); 1643 #endif 1644 break; 1645 1646 case 'i': /* ignore dot lines in message */ 1647 IgnrDot = atobool(val); 1648 break; 1649 1650 case 'j': /* send errors in MIME (RFC 1341) format */ 1651 SendMIMEErrors = atobool(val); 1652 break; 1653 1654 case 'J': /* .forward search path */ 1655 ForwardPath = newstr(val); 1656 break; 1657 1658 case 'k': /* connection cache size */ 1659 MaxMciCache = atoi(val); 1660 if (MaxMciCache < 0) 1661 MaxMciCache = 0; 1662 break; 1663 1664 case 'K': /* connection cache timeout */ 1665 MciCacheTimeout = convtime(val, 'm'); 1666 break; 1667 1668 case 'l': /* use Errors-To: header */ 1669 UseErrorsTo = atobool(val); 1670 break; 1671 1672 case 'L': /* log level */ 1673 if (safe || LogLevel < atoi(val)) 1674 LogLevel = atoi(val); 1675 break; 1676 1677 case 'M': /* define macro */ 1678 p = newstr(&val[1]); 1679 if (!safe) 1680 cleanstrcpy(p, p, MAXNAME); 1681 define(val[0], p, CurEnv); 1682 sticky = FALSE; 1683 break; 1684 1685 case 'm': /* send to me too */ 1686 MeToo = atobool(val); 1687 break; 1688 1689 case 'n': /* validate RHS in newaliases */ 1690 CheckAliases = atobool(val); 1691 break; 1692 1693 /* 'N' available -- was "net name" */ 1694 1695 case 'O': /* daemon options */ 1696 setdaemonoptions(val); 1697 break; 1698 1699 case 'o': /* assume old style headers */ 1700 if (atobool(val)) 1701 CurEnv->e_flags |= EF_OLDSTYLE; 1702 else 1703 CurEnv->e_flags &= ~EF_OLDSTYLE; 1704 break; 1705 1706 case 'p': /* select privacy level */ 1707 p = val; 1708 for (;;) 1709 { 1710 register struct prival *pv; 1711 extern struct prival PrivacyValues[]; 1712 1713 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 1714 p++; 1715 if (*p == '\0') 1716 break; 1717 val = p; 1718 while (isascii(*p) && isalnum(*p)) 1719 p++; 1720 if (*p != '\0') 1721 *p++ = '\0'; 1722 1723 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 1724 { 1725 if (strcasecmp(val, pv->pv_name) == 0) 1726 break; 1727 } 1728 if (pv->pv_name == NULL) 1729 syserr("readcf: Op line: %s unrecognized", val); 1730 PrivacyFlags |= pv->pv_flag; 1731 } 1732 break; 1733 1734 case 'P': /* postmaster copy address for returned mail */ 1735 PostMasterCopy = newstr(val); 1736 break; 1737 1738 case 'q': /* slope of queue only function */ 1739 QueueFactor = atoi(val); 1740 break; 1741 1742 case 'Q': /* queue directory */ 1743 if (val[0] == '\0') 1744 QueueDir = "mqueue"; 1745 else 1746 QueueDir = newstr(val); 1747 if (RealUid != 0 && !safe) 1748 Warn_Q_option = TRUE; 1749 break; 1750 1751 case 'R': /* don't prune routes */ 1752 DontPruneRoutes = atobool(val); 1753 break; 1754 1755 case 'r': /* read timeout */ 1756 if (subopt == NULL) 1757 inittimeouts(val); 1758 else 1759 settimeout(subopt, val); 1760 break; 1761 1762 case 'S': /* status file */ 1763 if (val[0] == '\0') 1764 StatFile = "sendmail.st"; 1765 else 1766 StatFile = newstr(val); 1767 break; 1768 1769 case 's': /* be super safe, even if expensive */ 1770 SuperSafe = atobool(val); 1771 break; 1772 1773 case 'T': /* queue timeout */ 1774 p = strchr(val, '/'); 1775 if (p != NULL) 1776 { 1777 *p++ = '\0'; 1778 settimeout("queuewarn", p); 1779 } 1780 settimeout("queuereturn", val); 1781 break; 1782 1783 case 't': /* time zone name */ 1784 TimeZoneSpec = newstr(val); 1785 break; 1786 1787 case 'U': /* location of user database */ 1788 UdbSpec = newstr(val); 1789 break; 1790 1791 case 'u': /* set default uid */ 1792 for (p = val; *p != '\0'; p++) 1793 { 1794 if (*p == '.' || *p == '/' || *p == ':') 1795 { 1796 *p++ = '\0'; 1797 break; 1798 } 1799 } 1800 if (isascii(*val) && isdigit(*val)) 1801 DefUid = atoi(val); 1802 else 1803 { 1804 register struct passwd *pw; 1805 1806 DefUid = -1; 1807 pw = getpwnam(val); 1808 if (pw == NULL) 1809 syserr("readcf: option u: unknown user %s", val); 1810 else 1811 { 1812 DefUid = pw->pw_uid; 1813 DefGid = pw->pw_gid; 1814 } 1815 } 1816 setdefuser(); 1817 1818 /* handle the group if it is there */ 1819 if (*p == '\0') 1820 break; 1821 val = p; 1822 goto g_opt; 1823 1824 case 'V': /* fallback MX host */ 1825 FallBackMX = newstr(val); 1826 break; 1827 1828 case 'v': /* run in verbose mode */ 1829 Verbose = atobool(val); 1830 break; 1831 1832 case 'w': /* if we are best MX, try host directly */ 1833 TryNullMXList = atobool(val); 1834 break; 1835 1836 /* 'W' available -- was wizard password */ 1837 1838 case 'x': /* load avg at which to auto-queue msgs */ 1839 QueueLA = atoi(val); 1840 break; 1841 1842 case 'X': /* load avg at which to auto-reject connections */ 1843 RefuseLA = atoi(val); 1844 break; 1845 1846 case 'y': /* work recipient factor */ 1847 WkRecipFact = atoi(val); 1848 break; 1849 1850 case 'Y': /* fork jobs during queue runs */ 1851 ForkQueueRuns = atobool(val); 1852 break; 1853 1854 case 'z': /* work message class factor */ 1855 WkClassFact = atoi(val); 1856 break; 1857 1858 case 'Z': /* work time factor */ 1859 WkTimeFact = atoi(val); 1860 break; 1861 1862 case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 1863 BrokenSmtpPeers = atobool(val); 1864 break; 1865 1866 case O_QUEUESORTORD: /* queue sorting order */ 1867 switch (*val) 1868 { 1869 case 'h': /* Host first */ 1870 case 'H': 1871 QueueSortOrder = QS_BYHOST; 1872 break; 1873 1874 case 'p': /* Priority order */ 1875 case 'P': 1876 QueueSortOrder = QS_BYPRIORITY; 1877 break; 1878 1879 default: 1880 syserr("Invalid queue sort order \"%s\"", val); 1881 } 1882 break; 1883 1884 case O_MQA: /* minimum queue age between deliveries */ 1885 MinQueueAge = convtime(val, 'm'); 1886 break; 1887 1888 case O_MHSA: /* maximum age of cached host status */ 1889 MaxHostStatAge = convtime(val, 'm'); 1890 break; 1891 1892 case O_DEFCHARSET: /* default character set for mimefying */ 1893 DefaultCharSet = newstr(denlstring(val)); 1894 break; 1895 1896 case O_SSFILE: /* service switch file */ 1897 ServiceSwitchFile = newstr(val); 1898 break; 1899 1900 case O_DIALDELAY: /* delay for dial-on-demand operation */ 1901 DialDelay = convtime(val, 's'); 1902 break; 1903 1904 default: 1905 if (tTd(37, 1)) 1906 { 1907 if (isascii(opt) && isprint(opt)) 1908 printf("Warning: option %c unknown\n", opt); 1909 else 1910 printf("Warning: option 0x%x unknown\n", opt); 1911 } 1912 break; 1913 } 1914 if (sticky) 1915 setbitn(opt, StickyOpt); 1916 return; 1917 } 1918 /* 1919 ** SETCLASS -- set a word into a class 1920 ** 1921 ** Parameters: 1922 ** class -- the class to put the word in. 1923 ** word -- the word to enter 1924 ** 1925 ** Returns: 1926 ** none. 1927 ** 1928 ** Side Effects: 1929 ** puts the word into the symbol table. 1930 */ 1931 1932 setclass(class, word) 1933 int class; 1934 char *word; 1935 { 1936 register STAB *s; 1937 1938 if (tTd(37, 8)) 1939 printf("setclass(%c, %s)\n", class, word); 1940 s = stab(word, ST_CLASS, ST_ENTER); 1941 setbitn(class, s->s_class); 1942 } 1943 /* 1944 ** MAKEMAPENTRY -- create a map entry 1945 ** 1946 ** Parameters: 1947 ** line -- the config file line 1948 ** 1949 ** Returns: 1950 ** TRUE if it successfully entered the map entry. 1951 ** FALSE otherwise (usually syntax error). 1952 ** 1953 ** Side Effects: 1954 ** Enters the map into the dictionary. 1955 */ 1956 1957 void 1958 makemapentry(line) 1959 char *line; 1960 { 1961 register char *p; 1962 char *mapname; 1963 char *classname; 1964 register STAB *s; 1965 STAB *class; 1966 1967 for (p = line; isascii(*p) && isspace(*p); p++) 1968 continue; 1969 if (!(isascii(*p) && isalnum(*p))) 1970 { 1971 syserr("readcf: config K line: no map name"); 1972 return; 1973 } 1974 1975 mapname = p; 1976 while ((isascii(*++p) && isalnum(*p)) || *p == '.') 1977 continue; 1978 if (*p != '\0') 1979 *p++ = '\0'; 1980 while (isascii(*p) && isspace(*p)) 1981 p++; 1982 if (!(isascii(*p) && isalnum(*p))) 1983 { 1984 syserr("readcf: config K line, map %s: no map class", mapname); 1985 return; 1986 } 1987 classname = p; 1988 while (isascii(*++p) && isalnum(*p)) 1989 continue; 1990 if (*p != '\0') 1991 *p++ = '\0'; 1992 while (isascii(*p) && isspace(*p)) 1993 p++; 1994 1995 /* look up the class */ 1996 class = stab(classname, ST_MAPCLASS, ST_FIND); 1997 if (class == NULL) 1998 { 1999 syserr("readcf: map %s: class %s not available", mapname, classname); 2000 return; 2001 } 2002 2003 /* enter the map */ 2004 s = stab(mapname, ST_MAP, ST_ENTER); 2005 s->s_map.map_class = &class->s_mapclass; 2006 s->s_map.map_mname = newstr(mapname); 2007 2008 if (class->s_mapclass.map_parse(&s->s_map, p)) 2009 s->s_map.map_mflags |= MF_VALID; 2010 2011 if (tTd(37, 5)) 2012 { 2013 printf("map %s, class %s, flags %x, file %s,\n", 2014 s->s_map.map_mname, s->s_map.map_class->map_cname, 2015 s->s_map.map_mflags, 2016 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 2017 printf("\tapp %s, domain %s, rebuild %s\n", 2018 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 2019 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 2020 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 2021 } 2022 } 2023 /* 2024 ** INITTIMEOUTS -- parse and set timeout values 2025 ** 2026 ** Parameters: 2027 ** val -- a pointer to the values. If NULL, do initial 2028 ** settings. 2029 ** 2030 ** Returns: 2031 ** none. 2032 ** 2033 ** Side Effects: 2034 ** Initializes the TimeOuts structure 2035 */ 2036 2037 #define SECONDS 2038 #define MINUTES * 60 2039 #define HOUR * 3600 2040 2041 inittimeouts(val) 2042 register char *val; 2043 { 2044 register char *p; 2045 extern time_t convtime(); 2046 2047 if (val == NULL) 2048 { 2049 TimeOuts.to_initial = (time_t) 5 MINUTES; 2050 TimeOuts.to_helo = (time_t) 5 MINUTES; 2051 TimeOuts.to_mail = (time_t) 10 MINUTES; 2052 TimeOuts.to_rcpt = (time_t) 1 HOUR; 2053 TimeOuts.to_datainit = (time_t) 5 MINUTES; 2054 TimeOuts.to_datablock = (time_t) 1 HOUR; 2055 TimeOuts.to_datafinal = (time_t) 1 HOUR; 2056 TimeOuts.to_rset = (time_t) 5 MINUTES; 2057 TimeOuts.to_quit = (time_t) 2 MINUTES; 2058 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 2059 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2060 #if IDENTPROTO 2061 TimeOuts.to_ident = (time_t) 30 SECONDS; 2062 #else 2063 TimeOuts.to_ident = (time_t) 0 SECONDS; 2064 #endif 2065 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 2066 return; 2067 } 2068 2069 for (;; val = p) 2070 { 2071 while (isascii(*val) && isspace(*val)) 2072 val++; 2073 if (*val == '\0') 2074 break; 2075 for (p = val; *p != '\0' && *p != ','; p++) 2076 continue; 2077 if (*p != '\0') 2078 *p++ = '\0'; 2079 2080 if (isascii(*val) && isdigit(*val)) 2081 { 2082 /* old syntax -- set everything */ 2083 TimeOuts.to_mail = convtime(val, 'm'); 2084 TimeOuts.to_rcpt = TimeOuts.to_mail; 2085 TimeOuts.to_datainit = TimeOuts.to_mail; 2086 TimeOuts.to_datablock = TimeOuts.to_mail; 2087 TimeOuts.to_datafinal = TimeOuts.to_mail; 2088 TimeOuts.to_nextcommand = TimeOuts.to_mail; 2089 continue; 2090 } 2091 else 2092 { 2093 register char *q = strchr(val, ':'); 2094 2095 if (q == NULL && (q = strchr(val, '=')) == NULL) 2096 { 2097 /* syntax error */ 2098 continue; 2099 } 2100 *q++ = '\0'; 2101 settimeout(val, q); 2102 } 2103 } 2104 } 2105 /* 2106 ** SETTIMEOUT -- set an individual timeout 2107 ** 2108 ** Parameters: 2109 ** name -- the name of the timeout. 2110 ** val -- the value of the timeout. 2111 ** 2112 ** Returns: 2113 ** none. 2114 */ 2115 2116 settimeout(name, val) 2117 char *name; 2118 char *val; 2119 { 2120 register char *p; 2121 time_t to; 2122 extern time_t convtime(); 2123 2124 to = convtime(val, 'm'); 2125 p = strchr(name, '.'); 2126 if (p != NULL) 2127 *p++ = '\0'; 2128 2129 if (strcasecmp(name, "initial") == 0) 2130 TimeOuts.to_initial = to; 2131 else if (strcasecmp(name, "mail") == 0) 2132 TimeOuts.to_mail = to; 2133 else if (strcasecmp(name, "rcpt") == 0) 2134 TimeOuts.to_rcpt = to; 2135 else if (strcasecmp(name, "datainit") == 0) 2136 TimeOuts.to_datainit = to; 2137 else if (strcasecmp(name, "datablock") == 0) 2138 TimeOuts.to_datablock = to; 2139 else if (strcasecmp(name, "datafinal") == 0) 2140 TimeOuts.to_datafinal = to; 2141 else if (strcasecmp(name, "command") == 0) 2142 TimeOuts.to_nextcommand = to; 2143 else if (strcasecmp(name, "rset") == 0) 2144 TimeOuts.to_rset = to; 2145 else if (strcasecmp(name, "helo") == 0) 2146 TimeOuts.to_helo = to; 2147 else if (strcasecmp(name, "quit") == 0) 2148 TimeOuts.to_quit = to; 2149 else if (strcasecmp(name, "misc") == 0) 2150 TimeOuts.to_miscshort = to; 2151 else if (strcasecmp(name, "ident") == 0) 2152 TimeOuts.to_ident = to; 2153 else if (strcasecmp(name, "fileopen") == 0) 2154 TimeOuts.to_fileopen = to; 2155 else if (strcasecmp(name, "queuewarn") == 0) 2156 { 2157 to = convtime(val, 'h'); 2158 if (p == NULL || strcmp(p, "*") == 0) 2159 { 2160 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2161 TimeOuts.to_q_warning[TOC_URGENT] = to; 2162 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2163 } 2164 else if (strcasecmp(p, "normal") == 0) 2165 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2166 else if (strcasecmp(p, "urgent") == 0) 2167 TimeOuts.to_q_warning[TOC_URGENT] = to; 2168 else if (strcasecmp(p, "non-urgent") == 0) 2169 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2170 else 2171 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2172 } 2173 else if (strcasecmp(name, "queuereturn") == 0) 2174 { 2175 to = convtime(val, 'd'); 2176 if (p == NULL || strcmp(p, "*") == 0) 2177 { 2178 TimeOuts.to_q_return[TOC_NORMAL] = to; 2179 TimeOuts.to_q_return[TOC_URGENT] = to; 2180 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2181 } 2182 else if (strcasecmp(p, "normal") == 0) 2183 TimeOuts.to_q_return[TOC_NORMAL] = to; 2184 else if (strcasecmp(p, "urgent") == 0) 2185 TimeOuts.to_q_return[TOC_URGENT] = to; 2186 else if (strcasecmp(p, "non-urgent") == 0) 2187 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2188 else 2189 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2190 } 2191 else 2192 syserr("settimeout: invalid timeout %s", name); 2193 } 2194