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.62 (Berkeley) 02/06/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 define(val[0], newstr(&val[1]), CurEnv); 1679 sticky = FALSE; 1680 break; 1681 1682 case 'm': /* send to me too */ 1683 MeToo = atobool(val); 1684 break; 1685 1686 case 'n': /* validate RHS in newaliases */ 1687 CheckAliases = atobool(val); 1688 break; 1689 1690 /* 'N' available -- was "net name" */ 1691 1692 case 'O': /* daemon options */ 1693 setdaemonoptions(val); 1694 break; 1695 1696 case 'o': /* assume old style headers */ 1697 if (atobool(val)) 1698 CurEnv->e_flags |= EF_OLDSTYLE; 1699 else 1700 CurEnv->e_flags &= ~EF_OLDSTYLE; 1701 break; 1702 1703 case 'p': /* select privacy level */ 1704 p = val; 1705 for (;;) 1706 { 1707 register struct prival *pv; 1708 extern struct prival PrivacyValues[]; 1709 1710 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 1711 p++; 1712 if (*p == '\0') 1713 break; 1714 val = p; 1715 while (isascii(*p) && isalnum(*p)) 1716 p++; 1717 if (*p != '\0') 1718 *p++ = '\0'; 1719 1720 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 1721 { 1722 if (strcasecmp(val, pv->pv_name) == 0) 1723 break; 1724 } 1725 if (pv->pv_name == NULL) 1726 syserr("readcf: Op line: %s unrecognized", val); 1727 PrivacyFlags |= pv->pv_flag; 1728 } 1729 break; 1730 1731 case 'P': /* postmaster copy address for returned mail */ 1732 PostMasterCopy = newstr(val); 1733 break; 1734 1735 case 'q': /* slope of queue only function */ 1736 QueueFactor = atoi(val); 1737 break; 1738 1739 case 'Q': /* queue directory */ 1740 if (val[0] == '\0') 1741 QueueDir = "mqueue"; 1742 else 1743 QueueDir = newstr(val); 1744 if (RealUid != 0 && !safe) 1745 Warn_Q_option = TRUE; 1746 break; 1747 1748 case 'R': /* don't prune routes */ 1749 DontPruneRoutes = atobool(val); 1750 break; 1751 1752 case 'r': /* read timeout */ 1753 if (subopt == NULL) 1754 inittimeouts(val); 1755 else 1756 settimeout(subopt, val); 1757 break; 1758 1759 case 'S': /* status file */ 1760 if (val[0] == '\0') 1761 StatFile = "sendmail.st"; 1762 else 1763 StatFile = newstr(val); 1764 break; 1765 1766 case 's': /* be super safe, even if expensive */ 1767 SuperSafe = atobool(val); 1768 break; 1769 1770 case 'T': /* queue timeout */ 1771 p = strchr(val, '/'); 1772 if (p != NULL) 1773 { 1774 *p++ = '\0'; 1775 settimeout("queuewarn", p); 1776 } 1777 settimeout("queuereturn", val); 1778 break; 1779 1780 case 't': /* time zone name */ 1781 TimeZoneSpec = newstr(val); 1782 break; 1783 1784 case 'U': /* location of user database */ 1785 UdbSpec = newstr(val); 1786 break; 1787 1788 case 'u': /* set default uid */ 1789 for (p = val; *p != '\0'; p++) 1790 { 1791 if (*p == '.' || *p == '/' || *p == ':') 1792 { 1793 *p++ = '\0'; 1794 break; 1795 } 1796 } 1797 if (isascii(*val) && isdigit(*val)) 1798 DefUid = atoi(val); 1799 else 1800 { 1801 register struct passwd *pw; 1802 1803 DefUid = -1; 1804 pw = getpwnam(val); 1805 if (pw == NULL) 1806 syserr("readcf: option u: unknown user %s", val); 1807 else 1808 { 1809 DefUid = pw->pw_uid; 1810 DefGid = pw->pw_gid; 1811 } 1812 } 1813 setdefuser(); 1814 1815 /* handle the group if it is there */ 1816 if (*p == '\0') 1817 break; 1818 val = p; 1819 goto g_opt; 1820 1821 case 'V': /* fallback MX host */ 1822 FallBackMX = newstr(val); 1823 break; 1824 1825 case 'v': /* run in verbose mode */ 1826 Verbose = atobool(val); 1827 break; 1828 1829 case 'w': /* if we are best MX, try host directly */ 1830 TryNullMXList = atobool(val); 1831 break; 1832 1833 /* 'W' available -- was wizard password */ 1834 1835 case 'x': /* load avg at which to auto-queue msgs */ 1836 QueueLA = atoi(val); 1837 break; 1838 1839 case 'X': /* load avg at which to auto-reject connections */ 1840 RefuseLA = atoi(val); 1841 break; 1842 1843 case 'y': /* work recipient factor */ 1844 WkRecipFact = atoi(val); 1845 break; 1846 1847 case 'Y': /* fork jobs during queue runs */ 1848 ForkQueueRuns = atobool(val); 1849 break; 1850 1851 case 'z': /* work message class factor */ 1852 WkClassFact = atoi(val); 1853 break; 1854 1855 case 'Z': /* work time factor */ 1856 WkTimeFact = atoi(val); 1857 break; 1858 1859 case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 1860 BrokenSmtpPeers = atobool(val); 1861 break; 1862 1863 case O_QUEUESORTORD: /* queue sorting order */ 1864 switch (*val) 1865 { 1866 case 'h': /* Host first */ 1867 case 'H': 1868 QueueSortOrder = QS_BYHOST; 1869 break; 1870 1871 case 'p': /* Priority order */ 1872 case 'P': 1873 QueueSortOrder = QS_BYPRIORITY; 1874 break; 1875 1876 default: 1877 syserr("Invalid queue sort order \"%s\"", val); 1878 } 1879 break; 1880 1881 case O_MQA: /* minimum queue age between deliveries */ 1882 MinQueueAge = convtime(val, 'm'); 1883 break; 1884 1885 case O_MHSA: /* maximum age of cached host status */ 1886 MaxHostStatAge = convtime(val, 'm'); 1887 break; 1888 1889 case O_DEFCHARSET: /* default character set for mimefying */ 1890 DefaultCharSet = newstr(val); 1891 break; 1892 1893 case O_SSFILE: /* service switch file */ 1894 ServiceSwitchFile = newstr(val); 1895 break; 1896 1897 case O_DIALDELAY: /* delay for dial-on-demand operation */ 1898 DialDelay = convtime(val, 's'); 1899 break; 1900 1901 default: 1902 if (tTd(37, 1)) 1903 { 1904 if (isascii(opt) && isprint(opt)) 1905 printf("Warning: option %c unknown\n", opt); 1906 else 1907 printf("Warning: option 0x%x unknown\n", opt); 1908 } 1909 break; 1910 } 1911 if (sticky) 1912 setbitn(opt, StickyOpt); 1913 return; 1914 } 1915 /* 1916 ** SETCLASS -- set a word into a class 1917 ** 1918 ** Parameters: 1919 ** class -- the class to put the word in. 1920 ** word -- the word to enter 1921 ** 1922 ** Returns: 1923 ** none. 1924 ** 1925 ** Side Effects: 1926 ** puts the word into the symbol table. 1927 */ 1928 1929 setclass(class, word) 1930 int class; 1931 char *word; 1932 { 1933 register STAB *s; 1934 1935 if (tTd(37, 8)) 1936 printf("setclass(%c, %s)\n", class, word); 1937 s = stab(word, ST_CLASS, ST_ENTER); 1938 setbitn(class, s->s_class); 1939 } 1940 /* 1941 ** MAKEMAPENTRY -- create a map entry 1942 ** 1943 ** Parameters: 1944 ** line -- the config file line 1945 ** 1946 ** Returns: 1947 ** TRUE if it successfully entered the map entry. 1948 ** FALSE otherwise (usually syntax error). 1949 ** 1950 ** Side Effects: 1951 ** Enters the map into the dictionary. 1952 */ 1953 1954 void 1955 makemapentry(line) 1956 char *line; 1957 { 1958 register char *p; 1959 char *mapname; 1960 char *classname; 1961 register STAB *s; 1962 STAB *class; 1963 1964 for (p = line; isascii(*p) && isspace(*p); p++) 1965 continue; 1966 if (!(isascii(*p) && isalnum(*p))) 1967 { 1968 syserr("readcf: config K line: no map name"); 1969 return; 1970 } 1971 1972 mapname = p; 1973 while ((isascii(*++p) && isalnum(*p)) || *p == '.') 1974 continue; 1975 if (*p != '\0') 1976 *p++ = '\0'; 1977 while (isascii(*p) && isspace(*p)) 1978 p++; 1979 if (!(isascii(*p) && isalnum(*p))) 1980 { 1981 syserr("readcf: config K line, map %s: no map class", mapname); 1982 return; 1983 } 1984 classname = p; 1985 while (isascii(*++p) && isalnum(*p)) 1986 continue; 1987 if (*p != '\0') 1988 *p++ = '\0'; 1989 while (isascii(*p) && isspace(*p)) 1990 p++; 1991 1992 /* look up the class */ 1993 class = stab(classname, ST_MAPCLASS, ST_FIND); 1994 if (class == NULL) 1995 { 1996 syserr("readcf: map %s: class %s not available", mapname, classname); 1997 return; 1998 } 1999 2000 /* enter the map */ 2001 s = stab(mapname, ST_MAP, ST_ENTER); 2002 s->s_map.map_class = &class->s_mapclass; 2003 s->s_map.map_mname = newstr(mapname); 2004 2005 if (class->s_mapclass.map_parse(&s->s_map, p)) 2006 s->s_map.map_mflags |= MF_VALID; 2007 2008 if (tTd(37, 5)) 2009 { 2010 printf("map %s, class %s, flags %x, file %s,\n", 2011 s->s_map.map_mname, s->s_map.map_class->map_cname, 2012 s->s_map.map_mflags, 2013 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 2014 printf("\tapp %s, domain %s, rebuild %s\n", 2015 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 2016 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 2017 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 2018 } 2019 } 2020 /* 2021 ** INITTIMEOUTS -- parse and set timeout values 2022 ** 2023 ** Parameters: 2024 ** val -- a pointer to the values. If NULL, do initial 2025 ** settings. 2026 ** 2027 ** Returns: 2028 ** none. 2029 ** 2030 ** Side Effects: 2031 ** Initializes the TimeOuts structure 2032 */ 2033 2034 #define SECONDS 2035 #define MINUTES * 60 2036 #define HOUR * 3600 2037 2038 inittimeouts(val) 2039 register char *val; 2040 { 2041 register char *p; 2042 extern time_t convtime(); 2043 2044 if (val == NULL) 2045 { 2046 TimeOuts.to_initial = (time_t) 5 MINUTES; 2047 TimeOuts.to_helo = (time_t) 5 MINUTES; 2048 TimeOuts.to_mail = (time_t) 10 MINUTES; 2049 TimeOuts.to_rcpt = (time_t) 1 HOUR; 2050 TimeOuts.to_datainit = (time_t) 5 MINUTES; 2051 TimeOuts.to_datablock = (time_t) 1 HOUR; 2052 TimeOuts.to_datafinal = (time_t) 1 HOUR; 2053 TimeOuts.to_rset = (time_t) 5 MINUTES; 2054 TimeOuts.to_quit = (time_t) 2 MINUTES; 2055 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 2056 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2057 #if IDENTPROTO 2058 TimeOuts.to_ident = (time_t) 30 SECONDS; 2059 #else 2060 TimeOuts.to_ident = (time_t) 0 SECONDS; 2061 #endif 2062 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 2063 return; 2064 } 2065 2066 for (;; val = p) 2067 { 2068 while (isascii(*val) && isspace(*val)) 2069 val++; 2070 if (*val == '\0') 2071 break; 2072 for (p = val; *p != '\0' && *p != ','; p++) 2073 continue; 2074 if (*p != '\0') 2075 *p++ = '\0'; 2076 2077 if (isascii(*val) && isdigit(*val)) 2078 { 2079 /* old syntax -- set everything */ 2080 TimeOuts.to_mail = convtime(val, 'm'); 2081 TimeOuts.to_rcpt = TimeOuts.to_mail; 2082 TimeOuts.to_datainit = TimeOuts.to_mail; 2083 TimeOuts.to_datablock = TimeOuts.to_mail; 2084 TimeOuts.to_datafinal = TimeOuts.to_mail; 2085 TimeOuts.to_nextcommand = TimeOuts.to_mail; 2086 continue; 2087 } 2088 else 2089 { 2090 register char *q = strchr(val, ':'); 2091 2092 if (q == NULL && (q = strchr(val, '=')) == NULL) 2093 { 2094 /* syntax error */ 2095 continue; 2096 } 2097 *q++ = '\0'; 2098 settimeout(val, q); 2099 } 2100 } 2101 } 2102 /* 2103 ** SETTIMEOUT -- set an individual timeout 2104 ** 2105 ** Parameters: 2106 ** name -- the name of the timeout. 2107 ** val -- the value of the timeout. 2108 ** 2109 ** Returns: 2110 ** none. 2111 */ 2112 2113 settimeout(name, val) 2114 char *name; 2115 char *val; 2116 { 2117 register char *p; 2118 time_t to; 2119 extern time_t convtime(); 2120 2121 to = convtime(val, 'm'); 2122 p = strchr(name, '.'); 2123 if (p != NULL) 2124 *p++ = '\0'; 2125 2126 if (strcasecmp(name, "initial") == 0) 2127 TimeOuts.to_initial = to; 2128 else if (strcasecmp(name, "mail") == 0) 2129 TimeOuts.to_mail = to; 2130 else if (strcasecmp(name, "rcpt") == 0) 2131 TimeOuts.to_rcpt = to; 2132 else if (strcasecmp(name, "datainit") == 0) 2133 TimeOuts.to_datainit = to; 2134 else if (strcasecmp(name, "datablock") == 0) 2135 TimeOuts.to_datablock = to; 2136 else if (strcasecmp(name, "datafinal") == 0) 2137 TimeOuts.to_datafinal = to; 2138 else if (strcasecmp(name, "command") == 0) 2139 TimeOuts.to_nextcommand = to; 2140 else if (strcasecmp(name, "rset") == 0) 2141 TimeOuts.to_rset = to; 2142 else if (strcasecmp(name, "helo") == 0) 2143 TimeOuts.to_helo = to; 2144 else if (strcasecmp(name, "quit") == 0) 2145 TimeOuts.to_quit = to; 2146 else if (strcasecmp(name, "misc") == 0) 2147 TimeOuts.to_miscshort = to; 2148 else if (strcasecmp(name, "ident") == 0) 2149 TimeOuts.to_ident = to; 2150 else if (strcasecmp(name, "fileopen") == 0) 2151 TimeOuts.to_fileopen = to; 2152 else if (strcasecmp(name, "queuewarn") == 0) 2153 { 2154 to = convtime(val, 'h'); 2155 if (p == NULL || strcmp(p, "*") == 0) 2156 { 2157 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2158 TimeOuts.to_q_warning[TOC_URGENT] = to; 2159 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2160 } 2161 else if (strcasecmp(p, "normal") == 0) 2162 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2163 else if (strcasecmp(p, "urgent") == 0) 2164 TimeOuts.to_q_warning[TOC_URGENT] = to; 2165 else if (strcasecmp(p, "non-urgent") == 0) 2166 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2167 else 2168 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2169 } 2170 else if (strcasecmp(name, "queuereturn") == 0) 2171 { 2172 to = convtime(val, 'd'); 2173 if (p == NULL || strcmp(p, "*") == 0) 2174 { 2175 TimeOuts.to_q_return[TOC_NORMAL] = to; 2176 TimeOuts.to_q_return[TOC_URGENT] = to; 2177 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2178 } 2179 else if (strcasecmp(p, "normal") == 0) 2180 TimeOuts.to_q_return[TOC_NORMAL] = to; 2181 else if (strcasecmp(p, "urgent") == 0) 2182 TimeOuts.to_q_return[TOC_URGENT] = to; 2183 else if (strcasecmp(p, "non-urgent") == 0) 2184 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2185 else 2186 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2187 } 2188 else 2189 syserr("settimeout: invalid timeout %s", name); 2190 } 2191