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