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