1 /* 2 * Copyright (c) 1983, 1995 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.107 (Berkeley) 06/20/95"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include <grp.h> 15 #if NAMED_BIND 16 # include <resolv.h> 17 #endif 18 19 /* 20 ** READCF -- read control file. 21 ** 22 ** This routine reads the control file and builds the internal 23 ** form. 24 ** 25 ** The file is formatted as a sequence of lines, each taken 26 ** atomically. The first character of each line describes how 27 ** the line is to be interpreted. The lines are: 28 ** Dxval Define macro x to have value val. 29 ** Cxword Put word into class x. 30 ** Fxfile [fmt] Read file for lines to put into 31 ** class x. Use scanf string 'fmt' 32 ** or "%s" if not present. Fmt should 33 ** only produce one string-valued result. 34 ** Hname: value Define header with field-name 'name' 35 ** and value as specified; this will be 36 ** macro expanded immediately before 37 ** use. 38 ** Sn Use rewriting set n. 39 ** Rlhs rhs Rewrite addresses that match lhs to 40 ** be rhs. 41 ** Mn arg=val... Define mailer. n is the internal name. 42 ** Args specify mailer parameters. 43 ** Oxvalue Set option x to value. 44 ** Pname=value Set precedence name to value. 45 ** Vversioncode[/vendorcode] 46 ** Version level/vendor name of 47 ** configuration syntax. 48 ** Kmapname mapclass arguments.... 49 ** Define keyed lookup of a given class. 50 ** Arguments are class dependent. 51 ** Eenvar=value Set the environment value to the given value. 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 void 67 readcf(cfname, safe, e) 68 char *cfname; 69 bool safe; 70 register ENVELOPE *e; 71 { 72 FILE *cf; 73 int ruleset = 0; 74 char *q; 75 struct rewrite *rwp = NULL; 76 char *bp; 77 auto char *ep; 78 int nfuzzy; 79 char *file; 80 bool optional; 81 int mid; 82 char buf[MAXLINE]; 83 register char *p; 84 extern char **copyplist(); 85 struct stat statb; 86 char exbuf[MAXLINE]; 87 char pvpbuf[MAXLINE + MAXATOM]; 88 static char *null_list[1] = { NULL }; 89 extern char *munchstring __P((char *, char **)); 90 extern void fileclass __P((int, char *, char *, bool, bool)); 91 extern void toomany __P((int, int)); 92 93 FileName = cfname; 94 LineNumber = 0; 95 96 cf = fopen(cfname, "r"); 97 if (cf == NULL) 98 { 99 syserr("cannot open"); 100 exit(EX_OSFILE); 101 } 102 103 if (fstat(fileno(cf), &statb) < 0) 104 { 105 syserr("cannot fstat"); 106 exit(EX_OSFILE); 107 } 108 109 if (!S_ISREG(statb.st_mode)) 110 { 111 syserr("not a plain file"); 112 exit(EX_OSFILE); 113 } 114 115 if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 116 { 117 if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS) 118 fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 119 FileName); 120 #ifdef LOG 121 if (LogLevel > 0) 122 syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 123 FileName); 124 #endif 125 } 126 127 #ifdef XLA 128 xla_zero(); 129 #endif 130 131 while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 132 { 133 if (bp[0] == '#') 134 { 135 if (bp != buf) 136 free(bp); 137 continue; 138 } 139 140 /* do macro expansion mappings */ 141 for (p = bp; *p != '\0'; p++) 142 { 143 if (*p == '#' && p > bp && ConfigLevel >= 3) 144 { 145 /* this is an on-line comment */ 146 register char *e; 147 148 switch (*--p & 0377) 149 { 150 case MACROEXPAND: 151 /* it's from $# -- let it go through */ 152 p++; 153 break; 154 155 case '\\': 156 /* it's backslash escaped */ 157 (void) strcpy(p, p + 1); 158 break; 159 160 default: 161 /* delete preceeding white space */ 162 while (isascii(*p) && isspace(*p) && p > bp) 163 p--; 164 if ((e = strchr(++p, '\n')) != NULL) 165 (void) strcpy(p, e); 166 else 167 p[0] = p[1] = '\0'; 168 break; 169 } 170 continue; 171 } 172 173 if (*p != '$' || p[1] == '\0') 174 continue; 175 176 if (p[1] == '$') 177 { 178 /* actual dollar sign.... */ 179 (void) strcpy(p, p + 1); 180 continue; 181 } 182 183 /* convert to macro expansion character */ 184 *p++ = MACROEXPAND; 185 186 /* convert macro name to code */ 187 *p = macid(p, &ep); 188 if (ep != p) 189 strcpy(p + 1, ep); 190 } 191 192 /* interpret this line */ 193 errno = 0; 194 switch (bp[0]) 195 { 196 case '\0': 197 case '#': /* comment */ 198 break; 199 200 case 'R': /* rewriting rule */ 201 for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 202 continue; 203 204 if (*p == '\0') 205 { 206 syserr("invalid rewrite line \"%s\" (tab expected)", bp); 207 break; 208 } 209 210 /* allocate space for the rule header */ 211 if (rwp == NULL) 212 { 213 RewriteRules[ruleset] = rwp = 214 (struct rewrite *) xalloc(sizeof *rwp); 215 } 216 else 217 { 218 rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 219 rwp = rwp->r_next; 220 } 221 rwp->r_next = NULL; 222 223 /* expand and save the LHS */ 224 *p = '\0'; 225 expand(&bp[1], exbuf, sizeof exbuf, e); 226 rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 227 sizeof pvpbuf, NULL, NULL); 228 nfuzzy = 0; 229 if (rwp->r_lhs != NULL) 230 { 231 register char **ap; 232 233 rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 234 235 /* count the number of fuzzy matches in LHS */ 236 for (ap = rwp->r_lhs; *ap != NULL; ap++) 237 { 238 char *botch; 239 240 botch = NULL; 241 switch (**ap & 0377) 242 { 243 case MATCHZANY: 244 case MATCHANY: 245 case MATCHONE: 246 case MATCHCLASS: 247 case MATCHNCLASS: 248 nfuzzy++; 249 break; 250 251 case MATCHREPL: 252 botch = "$0-$9"; 253 break; 254 255 case CANONNET: 256 botch = "$#"; 257 break; 258 259 case CANONUSER: 260 botch = "$:"; 261 break; 262 263 case CALLSUBR: 264 botch = "$>"; 265 break; 266 267 case CONDIF: 268 botch = "$?"; 269 break; 270 271 case CONDELSE: 272 botch = "$|"; 273 break; 274 275 case CONDFI: 276 botch = "$."; 277 break; 278 279 case HOSTBEGIN: 280 botch = "$["; 281 break; 282 283 case HOSTEND: 284 botch = "$]"; 285 break; 286 287 case LOOKUPBEGIN: 288 botch = "$("; 289 break; 290 291 case LOOKUPEND: 292 botch = "$)"; 293 break; 294 } 295 if (botch != NULL) 296 syserr("Inappropriate use of %s on LHS", 297 botch); 298 } 299 } 300 else 301 { 302 syserr("R line: null LHS"); 303 rwp->r_lhs = null_list; 304 } 305 306 /* expand and save the RHS */ 307 while (*++p == '\t') 308 continue; 309 q = p; 310 while (*p != '\0' && *p != '\t') 311 p++; 312 *p = '\0'; 313 expand(q, exbuf, sizeof exbuf, e); 314 rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 315 sizeof pvpbuf, NULL, NULL); 316 if (rwp->r_rhs != NULL) 317 { 318 register char **ap; 319 320 rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 321 322 /* check no out-of-bounds replacements */ 323 nfuzzy += '0'; 324 for (ap = rwp->r_rhs; *ap != NULL; ap++) 325 { 326 char *botch; 327 328 botch = NULL; 329 switch (**ap & 0377) 330 { 331 case MATCHREPL: 332 if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 333 { 334 syserr("replacement $%c out of bounds", 335 (*ap)[1]); 336 } 337 break; 338 339 case MATCHZANY: 340 botch = "$*"; 341 break; 342 343 case MATCHANY: 344 botch = "$+"; 345 break; 346 347 case MATCHONE: 348 botch = "$-"; 349 break; 350 351 case MATCHCLASS: 352 botch = "$="; 353 break; 354 355 case MATCHNCLASS: 356 botch = "$~"; 357 break; 358 } 359 if (botch != NULL) 360 syserr("Inappropriate use of %s on RHS", 361 botch); 362 } 363 } 364 else 365 { 366 syserr("R line: null RHS"); 367 rwp->r_rhs = null_list; 368 } 369 break; 370 371 case 'S': /* select rewriting set */ 372 ruleset = strtorwset(&bp[1], NULL, ST_ENTER); 373 rwp = RewriteRules[ruleset]; 374 if (rwp != NULL) 375 { 376 while (rwp->r_next != NULL) 377 rwp = rwp->r_next; 378 fprintf(stderr, "WARNING: Ruleset %s redefined\n", 379 &bp[1]); 380 } 381 break; 382 383 case 'D': /* macro definition */ 384 mid = macid(&bp[1], &ep); 385 p = munchstring(ep, NULL); 386 define(mid, newstr(p), e); 387 break; 388 389 case 'H': /* required header line */ 390 (void) chompheader(&bp[1], TRUE, NULL, e); 391 break; 392 393 case 'C': /* word class */ 394 case 'T': /* trusted user (set class `t') */ 395 if (bp[0] == 'C') 396 { 397 mid = macid(&bp[1], &ep); 398 expand(ep, exbuf, sizeof exbuf, e); 399 p = exbuf; 400 } 401 else 402 { 403 mid = 't'; 404 p = &bp[1]; 405 } 406 while (*p != '\0') 407 { 408 register char *wd; 409 char delim; 410 411 while (*p != '\0' && isascii(*p) && isspace(*p)) 412 p++; 413 wd = p; 414 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 415 p++; 416 delim = *p; 417 *p = '\0'; 418 if (wd[0] != '\0') 419 setclass(mid, wd); 420 *p = delim; 421 } 422 break; 423 424 case 'F': /* word class from file */ 425 mid = macid(&bp[1], &ep); 426 for (p = ep; isascii(*p) && isspace(*p); ) 427 p++; 428 if (p[0] == '-' && p[1] == 'o') 429 { 430 optional = TRUE; 431 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 432 p++; 433 while (isascii(*p) && isspace(*p)) 434 p++; 435 } 436 else 437 optional = FALSE; 438 file = p; 439 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 440 p++; 441 if (*p == '\0') 442 p = "%s"; 443 else 444 { 445 *p = '\0'; 446 while (isascii(*++p) && isspace(*p)) 447 continue; 448 } 449 fileclass(bp[1], file, p, safe, optional); 450 break; 451 452 #ifdef XLA 453 case 'L': /* extended load average description */ 454 xla_init(&bp[1]); 455 break; 456 #endif 457 458 case 'M': /* define mailer */ 459 makemailer(&bp[1]); 460 break; 461 462 case 'O': /* set option */ 463 setoption(bp[1], &bp[2], safe, FALSE, e); 464 break; 465 466 case 'P': /* set precedence */ 467 if (NumPriorities >= MAXPRIORITIES) 468 { 469 toomany('P', MAXPRIORITIES); 470 break; 471 } 472 for (p = &bp[1]; *p != '\0' && *p != '='; p++) 473 continue; 474 if (*p == '\0') 475 goto badline; 476 *p = '\0'; 477 Priorities[NumPriorities].pri_name = newstr(&bp[1]); 478 Priorities[NumPriorities].pri_val = atoi(++p); 479 NumPriorities++; 480 break; 481 482 case 'V': /* configuration syntax version */ 483 for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 484 continue; 485 if (!isascii(*p) || !isdigit(*p)) 486 { 487 syserr("invalid argument to V line: \"%.20s\"", 488 &bp[1]); 489 break; 490 } 491 ConfigLevel = strtol(p, &ep, 10); 492 493 /* 494 ** Do heuristic tweaking for back compatibility. 495 */ 496 497 if (ConfigLevel >= 5) 498 { 499 /* level 5 configs have short name in $w */ 500 p = macvalue('w', e); 501 if (p != NULL && (p = strchr(p, '.')) != NULL) 502 *p = '\0'; 503 } 504 if (ConfigLevel >= 6) 505 { 506 ColonOkInAddr = FALSE; 507 } 508 509 /* 510 ** Look for vendor code. 511 */ 512 513 if (*ep++ == '/') 514 { 515 /* extract vendor code */ 516 for (p = ep; isascii(*p) && isalpha(*p); ) 517 p++; 518 *p = '\0'; 519 520 if (!setvendor(ep)) 521 syserr("invalid V line vendor code: \"%s\"", 522 ep); 523 } 524 break; 525 526 case 'K': 527 (void) makemapentry(&bp[1]); 528 break; 529 530 case 'E': 531 p = strchr(bp, '='); 532 if (p != NULL) 533 *p++ = '\0'; 534 setuserenv(&bp[1], p); 535 break; 536 537 default: 538 badline: 539 syserr("unknown control line \"%s\"", bp); 540 } 541 if (bp != buf) 542 free(bp); 543 } 544 if (ferror(cf)) 545 { 546 syserr("I/O read error", cfname); 547 exit(EX_OSFILE); 548 } 549 fclose(cf); 550 FileName = NULL; 551 552 /* initialize host maps from local service tables */ 553 inithostmaps(); 554 555 /* determine if we need to do special name-server frotz */ 556 { 557 int nmaps; 558 char *maptype[MAXMAPSTACK]; 559 short mapreturn[MAXMAPACTIONS]; 560 561 nmaps = switch_map_find("hosts", maptype, mapreturn); 562 UseNameServer = FALSE; 563 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 564 { 565 register int mapno; 566 567 for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 568 { 569 if (strcmp(maptype[mapno], "dns") == 0) 570 UseNameServer = TRUE; 571 } 572 } 573 574 #ifdef HESIOD 575 nmaps = switch_map_find("passwd", maptype, mapreturn); 576 UseHesiod = FALSE; 577 if (nmaps > 0 && nmaps <= MAXMAPSTACK) 578 { 579 register int mapno; 580 581 for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 582 { 583 if (strcmp(maptype[mapno], "hesiod") == 0) 584 UseHesiod = TRUE; 585 } 586 } 587 #endif 588 } 589 } 590 /* 591 ** TOOMANY -- signal too many of some option 592 ** 593 ** Parameters: 594 ** id -- the id of the error line 595 ** maxcnt -- the maximum possible values 596 ** 597 ** Returns: 598 ** none. 599 ** 600 ** Side Effects: 601 ** gives a syserr. 602 */ 603 604 void 605 toomany(id, maxcnt) 606 int id; 607 int maxcnt; 608 { 609 syserr("too many %c lines, %d max", id, maxcnt); 610 } 611 /* 612 ** FILECLASS -- read members of a class from a file 613 ** 614 ** Parameters: 615 ** class -- class to define. 616 ** filename -- name of file to read. 617 ** fmt -- scanf string to use for match. 618 ** safe -- if set, this is a safe read. 619 ** optional -- if set, it is not an error for the file to 620 ** not exist. 621 ** 622 ** Returns: 623 ** none 624 ** 625 ** Side Effects: 626 ** 627 ** puts all lines in filename that match a scanf into 628 ** the named class. 629 */ 630 631 void 632 fileclass(class, filename, fmt, safe, optional) 633 int class; 634 char *filename; 635 char *fmt; 636 bool safe; 637 bool optional; 638 { 639 FILE *f; 640 int sff; 641 int pid; 642 register char *p; 643 char buf[MAXLINE]; 644 645 if (tTd(37, 2)) 646 printf("fileclass(%s, fmt=%s)\n", filename, fmt); 647 648 if (filename[0] == '|') 649 { 650 auto int fd; 651 int i; 652 char *argv[MAXPV + 1]; 653 654 i = 0; 655 for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t")) 656 { 657 if (i >= MAXPV) 658 break; 659 argv[i++] = p; 660 } 661 argv[i] = NULL; 662 pid = prog_open(argv, &fd, CurEnv); 663 if (pid < 0) 664 f = NULL; 665 else 666 f = fdopen(fd, "r"); 667 } 668 else 669 { 670 pid = -1; 671 sff = SFF_REGONLY; 672 if (safe) 673 sff |= SFF_OPENASROOT; 674 f = safefopen(filename, O_RDONLY, 0, sff); 675 } 676 if (f == NULL) 677 { 678 if (!optional) 679 syserr("fileclass: cannot open %s", filename); 680 return; 681 } 682 683 while (fgets(buf, sizeof buf, f) != NULL) 684 { 685 register char *p; 686 # if SCANF 687 char wordbuf[MAXNAME+1]; 688 689 if (sscanf(buf, fmt, wordbuf) != 1) 690 continue; 691 p = wordbuf; 692 # else /* SCANF */ 693 p = buf; 694 # endif /* SCANF */ 695 696 /* 697 ** Break up the match into words. 698 */ 699 700 while (*p != '\0') 701 { 702 register char *q; 703 704 /* strip leading spaces */ 705 while (isascii(*p) && isspace(*p)) 706 p++; 707 if (*p == '\0') 708 break; 709 710 /* find the end of the word */ 711 q = p; 712 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 713 p++; 714 if (*p != '\0') 715 *p++ = '\0'; 716 717 /* enter the word in the symbol table */ 718 setclass(class, q); 719 } 720 } 721 722 (void) fclose(f); 723 if (pid > 0) 724 (void) waitfor(pid); 725 } 726 /* 727 ** MAKEMAILER -- define a new mailer. 728 ** 729 ** Parameters: 730 ** line -- description of mailer. This is in labeled 731 ** fields. The fields are: 732 ** A -- the argv for this mailer 733 ** C -- the character set for MIME conversions 734 ** D -- the directory to run in 735 ** E -- the eol string 736 ** F -- the flags associated with the mailer 737 ** L -- the maximum line length 738 ** M -- the maximum message size 739 ** N -- the niceness at which to run 740 ** P -- the path to the mailer 741 ** R -- the recipient rewriting set 742 ** S -- the sender rewriting set 743 ** T -- the mailer type (for DSNs) 744 ** U -- the uid to run as 745 ** The first word is the canonical name of the mailer. 746 ** 747 ** Returns: 748 ** none. 749 ** 750 ** Side Effects: 751 ** enters the mailer into the mailer table. 752 */ 753 754 void 755 makemailer(line) 756 char *line; 757 { 758 register char *p; 759 register struct mailer *m; 760 register STAB *s; 761 int i; 762 char fcode; 763 auto char *endp; 764 extern int NextMailer; 765 extern char **makeargv(); 766 extern char *munchstring(); 767 768 /* allocate a mailer and set up defaults */ 769 m = (struct mailer *) xalloc(sizeof *m); 770 bzero((char *) m, sizeof *m); 771 m->m_eol = "\n"; 772 m->m_uid = m->m_gid = 0; 773 774 /* collect the mailer name */ 775 for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 776 continue; 777 if (*p != '\0') 778 *p++ = '\0'; 779 m->m_name = newstr(line); 780 781 /* now scan through and assign info from the fields */ 782 while (*p != '\0') 783 { 784 auto char *delimptr; 785 786 while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 787 p++; 788 789 /* p now points to field code */ 790 fcode = *p; 791 while (*p != '\0' && *p != '=' && *p != ',') 792 p++; 793 if (*p++ != '=') 794 { 795 syserr("mailer %s: `=' expected", m->m_name); 796 return; 797 } 798 while (isascii(*p) && isspace(*p)) 799 p++; 800 801 /* p now points to the field body */ 802 p = munchstring(p, &delimptr); 803 804 /* install the field into the mailer struct */ 805 switch (fcode) 806 { 807 case 'P': /* pathname */ 808 m->m_mailer = newstr(p); 809 break; 810 811 case 'F': /* flags */ 812 for (; *p != '\0'; p++) 813 if (!(isascii(*p) && isspace(*p))) 814 setbitn(*p, m->m_flags); 815 break; 816 817 case 'S': /* sender rewriting ruleset */ 818 case 'R': /* recipient rewriting ruleset */ 819 i = strtorwset(p, &endp, ST_ENTER); 820 if (i < 0) 821 return; 822 if (fcode == 'S') 823 m->m_sh_rwset = m->m_se_rwset = i; 824 else 825 m->m_rh_rwset = m->m_re_rwset = i; 826 827 p = endp; 828 if (*p++ == '/') 829 { 830 i = strtorwset(p, NULL); 831 if (i < 0) 832 return; 833 if (fcode == 'S') 834 m->m_sh_rwset = i; 835 else 836 m->m_rh_rwset = i; 837 } 838 break; 839 840 case 'E': /* end of line string */ 841 m->m_eol = newstr(p); 842 break; 843 844 case 'A': /* argument vector */ 845 m->m_argv = makeargv(p); 846 break; 847 848 case 'M': /* maximum message size */ 849 m->m_maxsize = atol(p); 850 break; 851 852 case 'L': /* maximum line length */ 853 m->m_linelimit = atoi(p); 854 break; 855 856 case 'N': /* run niceness */ 857 m->m_nice = atoi(p); 858 break; 859 860 case 'D': /* working directory */ 861 m->m_execdir = newstr(p); 862 break; 863 864 case 'C': /* default charset */ 865 m->m_defcharset = newstr(p); 866 break; 867 868 case 'T': /* MTA-Name/Address/Diagnostic types */ 869 /* extract MTA name type; default to "dns" */ 870 m->m_mtatype = newstr(p); 871 p = strchr(m->m_mtatype, '/'); 872 if (p != NULL) 873 { 874 *p++ = '\0'; 875 if (*p == '\0') 876 p = NULL; 877 } 878 if (*m->m_mtatype == '\0') 879 m->m_mtatype = "dns"; 880 881 /* extract address type; default to "rfc822" */ 882 m->m_addrtype = p; 883 if (p != NULL) 884 p = strchr(p, '/'); 885 if (p != NULL) 886 { 887 *p++ = '\0'; 888 if (*p == '\0') 889 p = NULL; 890 } 891 if (m->m_addrtype == NULL || *m->m_addrtype == '\0') 892 m->m_addrtype = "rfc822"; 893 894 /* extract diagnostic type; default to "smtp" */ 895 m->m_diagtype = p; 896 if (m->m_diagtype == NULL || *m->m_diagtype == '\0') 897 m->m_diagtype = "smtp"; 898 break; 899 900 case 'U': /* user id */ 901 if (isascii(*p) && !isdigit(*p)) 902 { 903 char *q = p; 904 struct passwd *pw; 905 906 while (isascii(*p) && isalnum(*p)) 907 p++; 908 while (isascii(*p) && isspace(*p)) 909 *p++ = '\0'; 910 if (*p != '\0') 911 *p++ = '\0'; 912 pw = sm_getpwnam(q); 913 if (pw == NULL) 914 syserr("readcf: mailer U= flag: unknown user %s", q); 915 else 916 { 917 m->m_uid = pw->pw_uid; 918 m->m_gid = pw->pw_gid; 919 } 920 } 921 else 922 { 923 auto char *q; 924 925 m->m_uid = strtol(p, &q, 0); 926 p = q; 927 } 928 while (isascii(*p) && isspace(*p)) 929 p++; 930 if (*p == '\0') 931 break; 932 if (isascii(*p) && !isdigit(*p)) 933 { 934 char *q = p; 935 struct group *gr; 936 937 while (isascii(*p) && isalnum(*p)) 938 p++; 939 *p++ = '\0'; 940 gr = getgrnam(q); 941 if (gr == NULL) 942 syserr("readcf: mailer U= flag: unknown group %s", q); 943 else 944 m->m_gid = gr->gr_gid; 945 } 946 else 947 { 948 m->m_gid = strtol(p, NULL, 0); 949 } 950 break; 951 } 952 953 p = delimptr; 954 } 955 956 /* do some rationality checking */ 957 if (m->m_argv == NULL) 958 { 959 syserr("M%s: A= argument required", m->m_name); 960 return; 961 } 962 if (m->m_mailer == NULL) 963 { 964 syserr("M%s: P= argument required", m->m_name); 965 return; 966 } 967 968 if (NextMailer >= MAXMAILERS) 969 { 970 syserr("too many mailers defined (%d max)", MAXMAILERS); 971 return; 972 } 973 974 /* do some heuristic cleanup for back compatibility */ 975 if (bitnset(M_LIMITS, m->m_flags)) 976 { 977 if (m->m_linelimit == 0) 978 m->m_linelimit = SMTPLINELIM; 979 if (ConfigLevel < 2) 980 setbitn(M_7BITS, m->m_flags); 981 } 982 983 if (ConfigLevel < 6 && 984 (strcmp(m->m_mailer, "[IPC]") == 0 || 985 strcmp(m->m_mailer, "[TCP]") == 0)) 986 { 987 if (m->m_mtatype == NULL) 988 m->m_mtatype = "dns"; 989 if (m->m_addrtype == NULL) 990 m->m_addrtype = "rfc822"; 991 if (m->m_diagtype == NULL) 992 m->m_diagtype = "smtp"; 993 } 994 995 /* enter the mailer into the symbol table */ 996 s = stab(m->m_name, ST_MAILER, ST_ENTER); 997 if (s->s_mailer != NULL) 998 { 999 i = s->s_mailer->m_mno; 1000 free(s->s_mailer); 1001 } 1002 else 1003 { 1004 i = NextMailer++; 1005 } 1006 Mailer[i] = s->s_mailer = m; 1007 m->m_mno = i; 1008 } 1009 /* 1010 ** MUNCHSTRING -- translate a string into internal form. 1011 ** 1012 ** Parameters: 1013 ** p -- the string to munch. 1014 ** delimptr -- if non-NULL, set to the pointer of the 1015 ** field delimiter character. 1016 ** 1017 ** Returns: 1018 ** the munched string. 1019 */ 1020 1021 char * 1022 munchstring(p, delimptr) 1023 register char *p; 1024 char **delimptr; 1025 { 1026 register char *q; 1027 bool backslash = FALSE; 1028 bool quotemode = FALSE; 1029 static char buf[MAXLINE]; 1030 1031 for (q = buf; *p != '\0'; p++) 1032 { 1033 if (backslash) 1034 { 1035 /* everything is roughly literal */ 1036 backslash = FALSE; 1037 switch (*p) 1038 { 1039 case 'r': /* carriage return */ 1040 *q++ = '\r'; 1041 continue; 1042 1043 case 'n': /* newline */ 1044 *q++ = '\n'; 1045 continue; 1046 1047 case 'f': /* form feed */ 1048 *q++ = '\f'; 1049 continue; 1050 1051 case 'b': /* backspace */ 1052 *q++ = '\b'; 1053 continue; 1054 } 1055 *q++ = *p; 1056 } 1057 else 1058 { 1059 if (*p == '\\') 1060 backslash = TRUE; 1061 else if (*p == '"') 1062 quotemode = !quotemode; 1063 else if (quotemode || *p != ',') 1064 *q++ = *p; 1065 else 1066 break; 1067 } 1068 } 1069 1070 if (delimptr != NULL) 1071 *delimptr = p; 1072 *q++ = '\0'; 1073 return (buf); 1074 } 1075 /* 1076 ** MAKEARGV -- break up a string into words 1077 ** 1078 ** Parameters: 1079 ** p -- the string to break up. 1080 ** 1081 ** Returns: 1082 ** a char **argv (dynamically allocated) 1083 ** 1084 ** Side Effects: 1085 ** munges p. 1086 */ 1087 1088 char ** 1089 makeargv(p) 1090 register char *p; 1091 { 1092 char *q; 1093 int i; 1094 char **avp; 1095 char *argv[MAXPV + 1]; 1096 1097 /* take apart the words */ 1098 i = 0; 1099 while (*p != '\0' && i < MAXPV) 1100 { 1101 q = p; 1102 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1103 p++; 1104 while (isascii(*p) && isspace(*p)) 1105 *p++ = '\0'; 1106 argv[i++] = newstr(q); 1107 } 1108 argv[i++] = NULL; 1109 1110 /* now make a copy of the argv */ 1111 avp = (char **) xalloc(sizeof *avp * i); 1112 bcopy((char *) argv, (char *) avp, sizeof *avp * i); 1113 1114 return (avp); 1115 } 1116 /* 1117 ** PRINTRULES -- print rewrite rules (for debugging) 1118 ** 1119 ** Parameters: 1120 ** none. 1121 ** 1122 ** Returns: 1123 ** none. 1124 ** 1125 ** Side Effects: 1126 ** prints rewrite rules. 1127 */ 1128 1129 void 1130 printrules() 1131 { 1132 register struct rewrite *rwp; 1133 register int ruleset; 1134 1135 for (ruleset = 0; ruleset < 10; ruleset++) 1136 { 1137 if (RewriteRules[ruleset] == NULL) 1138 continue; 1139 printf("\n----Rule Set %d:", ruleset); 1140 1141 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 1142 { 1143 printf("\nLHS:"); 1144 printav(rwp->r_lhs); 1145 printf("RHS:"); 1146 printav(rwp->r_rhs); 1147 } 1148 } 1149 } 1150 /* 1151 ** PRINTMAILER -- print mailer structure (for debugging) 1152 ** 1153 ** Parameters: 1154 ** m -- the mailer to print 1155 ** 1156 ** Returns: 1157 ** none. 1158 */ 1159 1160 void 1161 printmailer(m) 1162 register MAILER *m; 1163 { 1164 int j; 1165 1166 printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 1167 m->m_mno, m->m_name, 1168 m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 1169 m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 1170 m->m_uid, m->m_gid); 1171 for (j = '\0'; j <= '\177'; j++) 1172 if (bitnset(j, m->m_flags)) 1173 (void) putchar(j); 1174 printf(" L=%d E=", m->m_linelimit); 1175 xputs(m->m_eol); 1176 if (m->m_defcharset != NULL) 1177 printf(" C=%s", m->m_defcharset); 1178 printf(" T=%s/%s/%s", 1179 m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 1180 m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 1181 m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 1182 if (m->m_argv != NULL) 1183 { 1184 char **a = m->m_argv; 1185 1186 printf(" A="); 1187 while (*a != NULL) 1188 { 1189 if (a != m->m_argv) 1190 printf(" "); 1191 xputs(*a++); 1192 } 1193 } 1194 printf("\n"); 1195 } 1196 /* 1197 ** SETOPTION -- set global processing option 1198 ** 1199 ** Parameters: 1200 ** opt -- option name. 1201 ** val -- option value (as a text string). 1202 ** safe -- set if this came from a configuration file. 1203 ** Some options (if set from the command line) will 1204 ** reset the user id to avoid security problems. 1205 ** sticky -- if set, don't let other setoptions override 1206 ** this value. 1207 ** e -- the main envelope. 1208 ** 1209 ** Returns: 1210 ** none. 1211 ** 1212 ** Side Effects: 1213 ** Sets options as implied by the arguments. 1214 */ 1215 1216 static BITMAP StickyOpt; /* set if option is stuck */ 1217 extern void settimeout __P((char *, char *)); 1218 1219 1220 #if NAMED_BIND 1221 1222 struct resolverflags 1223 { 1224 char *rf_name; /* name of the flag */ 1225 long rf_bits; /* bits to set/clear */ 1226 } ResolverFlags[] = 1227 { 1228 "debug", RES_DEBUG, 1229 "aaonly", RES_AAONLY, 1230 "usevc", RES_USEVC, 1231 "primary", RES_PRIMARY, 1232 "igntc", RES_IGNTC, 1233 "recurse", RES_RECURSE, 1234 "defnames", RES_DEFNAMES, 1235 "stayopen", RES_STAYOPEN, 1236 "dnsrch", RES_DNSRCH, 1237 "true", 0, /* to avoid error on old syntax */ 1238 NULL, 0 1239 }; 1240 1241 #endif 1242 1243 struct optioninfo 1244 { 1245 char *o_name; /* long name of option */ 1246 u_char o_code; /* short name of option */ 1247 bool o_safe; /* safe for random people to use */ 1248 } OptionTab[] = 1249 { 1250 "SevenBitInput", '7', TRUE, 1251 #if MIME8TO7 1252 "EightBitMode", '8', TRUE, 1253 #endif 1254 "AliasFile", 'A', FALSE, 1255 "AliasWait", 'a', FALSE, 1256 "BlankSub", 'B', FALSE, 1257 "MinFreeBlocks", 'b', TRUE, 1258 "CheckpointInterval", 'C', TRUE, 1259 "HoldExpensive", 'c', FALSE, 1260 "AutoRebuildAliases", 'D', FALSE, 1261 "DeliveryMode", 'd', TRUE, 1262 "ErrorHeader", 'E', FALSE, 1263 "ErrorMode", 'e', TRUE, 1264 "TempFileMode", 'F', FALSE, 1265 "SaveFromLine", 'f', FALSE, 1266 "MatchGECOS", 'G', FALSE, 1267 "HelpFile", 'H', FALSE, 1268 "MaxHopCount", 'h', FALSE, 1269 "ResolverOptions", 'I', FALSE, 1270 "IgnoreDots", 'i', TRUE, 1271 "ForwardPath", 'J', FALSE, 1272 "SendMimeErrors", 'j', TRUE, 1273 "ConnectionCacheSize", 'k', FALSE, 1274 "ConnectionCacheTimeout", 'K', FALSE, 1275 "UseErrorsTo", 'l', FALSE, 1276 "LogLevel", 'L', FALSE, 1277 "MeToo", 'm', TRUE, 1278 "CheckAliases", 'n', FALSE, 1279 "OldStyleHeaders", 'o', TRUE, 1280 "DaemonPortOptions", 'O', FALSE, 1281 "PrivacyOptions", 'p', TRUE, 1282 "PostmasterCopy", 'P', FALSE, 1283 "QueueFactor", 'q', FALSE, 1284 "QueueDirectory", 'Q', FALSE, 1285 "DontPruneRoutes", 'R', FALSE, 1286 "Timeout", 'r', TRUE, 1287 "StatusFile", 'S', FALSE, 1288 "SuperSafe", 's', TRUE, 1289 "QueueTimeout", 'T', FALSE, 1290 "TimeZoneSpec", 't', FALSE, 1291 "UserDatabaseSpec", 'U', FALSE, 1292 "DefaultUser", 'u', FALSE, 1293 "FallbackMXhost", 'V', FALSE, 1294 "Verbose", 'v', TRUE, 1295 "TryNullMXList", 'w', TRUE, 1296 "QueueLA", 'x', FALSE, 1297 "RefuseLA", 'X', FALSE, 1298 "RecipientFactor", 'y', FALSE, 1299 "ForkEachJob", 'Y', FALSE, 1300 "ClassFactor", 'z', FALSE, 1301 "RetryFactor", 'Z', FALSE, 1302 #define O_QUEUESORTORD 0x81 1303 "QueueSortOrder", O_QUEUESORTORD, TRUE, 1304 #define O_HOSTSFILE 0x82 1305 "HostsFile", O_HOSTSFILE, FALSE, 1306 #define O_MQA 0x83 1307 "MinQueueAge", O_MQA, TRUE, 1308 #define O_MHSA 0x84 1309 /* 1310 "MaxHostStatAge", O_MHSA, TRUE, 1311 */ 1312 #define O_DEFCHARSET 0x85 1313 "DefaultCharSet", O_DEFCHARSET, TRUE, 1314 #define O_SSFILE 0x86 1315 "ServiceSwitchFile", O_SSFILE, FALSE, 1316 #define O_DIALDELAY 0x87 1317 "DialDelay", O_DIALDELAY, TRUE, 1318 #define O_NORCPTACTION 0x88 1319 "NoRecipientAction", O_NORCPTACTION, TRUE, 1320 #define O_SAFEFILEENV 0x89 1321 "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 1322 #define O_MAXMSGSIZE 0x8a 1323 "MaxMessageSize", O_MAXMSGSIZE, FALSE, 1324 #define O_COLONOKINADDR 0x8b 1325 "ColonOkInAddr", O_COLONOKINADDR, TRUE, 1326 #define O_MAXQUEUERUN 0x8c 1327 "MaxQueueRunSize", O_MAXQUEUERUN, TRUE, 1328 #define O_MAXCHILDREN 0x8d 1329 /* 1330 "MaxDaemonChildren", O_MAXCHILDREN, FALSE, 1331 */ 1332 #define O_KEEPCNAMES 0x8e 1333 "DontExpandCnames", O_KEEPCNAMES, FALSE, 1334 1335 NULL, '\0', FALSE, 1336 }; 1337 1338 1339 1340 void 1341 setoption(opt, val, safe, sticky, e) 1342 int opt; 1343 char *val; 1344 bool safe; 1345 bool sticky; 1346 register ENVELOPE *e; 1347 { 1348 register char *p; 1349 register struct optioninfo *o; 1350 char *subopt; 1351 extern bool atobool(); 1352 extern time_t convtime(); 1353 extern int QueueLA; 1354 extern int RefuseLA; 1355 extern bool Warn_Q_option; 1356 1357 errno = 0; 1358 if (opt == ' ') 1359 { 1360 /* full word options */ 1361 struct optioninfo *sel; 1362 1363 p = strchr(val, '='); 1364 if (p == NULL) 1365 p = &val[strlen(val)]; 1366 while (*--p == ' ') 1367 continue; 1368 while (*++p == ' ') 1369 *p = '\0'; 1370 if (p == val) 1371 { 1372 syserr("readcf: null option name"); 1373 return; 1374 } 1375 if (*p == '=') 1376 *p++ = '\0'; 1377 while (*p == ' ') 1378 p++; 1379 subopt = strchr(val, '.'); 1380 if (subopt != NULL) 1381 *subopt++ = '\0'; 1382 sel = NULL; 1383 for (o = OptionTab; o->o_name != NULL; o++) 1384 { 1385 if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1386 continue; 1387 if (strlen(o->o_name) == strlen(val)) 1388 { 1389 /* completely specified -- this must be it */ 1390 sel = NULL; 1391 break; 1392 } 1393 if (sel != NULL) 1394 break; 1395 sel = o; 1396 } 1397 if (sel != NULL && o->o_name == NULL) 1398 o = sel; 1399 else if (o->o_name == NULL) 1400 { 1401 syserr("readcf: unknown option name %s", val); 1402 return; 1403 } 1404 else if (sel != NULL) 1405 { 1406 syserr("readcf: ambiguous option name %s (matches %s and %s)", 1407 val, sel->o_name, o->o_name); 1408 return; 1409 } 1410 if (strlen(val) != strlen(o->o_name)) 1411 { 1412 bool oldVerbose = Verbose; 1413 1414 Verbose = TRUE; 1415 message("Option %s used as abbreviation for %s", 1416 val, o->o_name); 1417 Verbose = oldVerbose; 1418 } 1419 opt = o->o_code; 1420 val = p; 1421 } 1422 else 1423 { 1424 for (o = OptionTab; o->o_name != NULL; o++) 1425 { 1426 if (o->o_code == opt) 1427 break; 1428 } 1429 subopt = NULL; 1430 } 1431 1432 if (tTd(37, 1)) 1433 { 1434 printf(isascii(opt) && isprint(opt) ? 1435 "setoption %s (%c).%s=" : 1436 "setoption %s (0x%x).%s=", 1437 o->o_name == NULL ? "<unknown>" : o->o_name, 1438 opt, 1439 subopt == NULL ? "" : subopt); 1440 xputs(val); 1441 } 1442 1443 /* 1444 ** See if this option is preset for us. 1445 */ 1446 1447 if (!sticky && bitnset(opt, StickyOpt)) 1448 { 1449 if (tTd(37, 1)) 1450 printf(" (ignored)\n"); 1451 return; 1452 } 1453 1454 /* 1455 ** Check to see if this option can be specified by this user. 1456 */ 1457 1458 if (!safe && RealUid == 0) 1459 safe = TRUE; 1460 if (!safe && !o->o_safe) 1461 { 1462 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 1463 { 1464 if (tTd(37, 1)) 1465 printf(" (unsafe)"); 1466 if (RealUid != geteuid()) 1467 { 1468 if (tTd(37, 1)) 1469 printf("(Resetting uid)"); 1470 (void) setgid(RealGid); 1471 (void) setuid(RealUid); 1472 } 1473 } 1474 } 1475 if (tTd(37, 1)) 1476 printf("\n"); 1477 1478 switch (opt & 0xff) 1479 { 1480 case '7': /* force seven-bit input */ 1481 SevenBitInput = atobool(val); 1482 break; 1483 1484 #if MIME8TO7 1485 case '8': /* handling of 8-bit input */ 1486 switch (*val) 1487 { 1488 case 'm': /* convert 8-bit, convert MIME */ 1489 MimeMode = MM_CVTMIME|MM_MIME8BIT; 1490 break; 1491 1492 case 'p': /* pass 8 bit, convert MIME */ 1493 MimeMode = MM_CVTMIME|MM_PASS8BIT; 1494 break; 1495 1496 case 's': /* strict adherence */ 1497 MimeMode = MM_CVTMIME; 1498 break; 1499 1500 #if 0 1501 case 'r': /* reject 8-bit, don't convert MIME */ 1502 MimeMode = 0; 1503 break; 1504 1505 case 'j': /* "just send 8" */ 1506 MimeMode = MM_PASS8BIT; 1507 break; 1508 1509 case 'a': /* encode 8 bit if available */ 1510 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1511 break; 1512 1513 case 'c': /* convert 8 bit to MIME, never 7 bit */ 1514 MimeMode = MM_MIME8BIT; 1515 break; 1516 #endif 1517 1518 default: 1519 syserr("Unknown 8-bit mode %c", *val); 1520 exit(EX_USAGE); 1521 } 1522 break; 1523 #endif 1524 1525 case 'A': /* set default alias file */ 1526 if (val[0] == '\0') 1527 setalias("aliases"); 1528 else 1529 setalias(val); 1530 break; 1531 1532 case 'a': /* look N minutes for "@:@" in alias file */ 1533 if (val[0] == '\0') 1534 SafeAlias = 5 * 60; /* five minutes */ 1535 else 1536 SafeAlias = convtime(val, 'm'); 1537 break; 1538 1539 case 'B': /* substitution for blank character */ 1540 SpaceSub = val[0]; 1541 if (SpaceSub == '\0') 1542 SpaceSub = ' '; 1543 break; 1544 1545 case 'b': /* min blocks free on queue fs/max msg size */ 1546 p = strchr(val, '/'); 1547 if (p != NULL) 1548 { 1549 *p++ = '\0'; 1550 MaxMessageSize = atol(p); 1551 } 1552 MinBlocksFree = atol(val); 1553 break; 1554 1555 case 'c': /* don't connect to "expensive" mailers */ 1556 NoConnect = atobool(val); 1557 break; 1558 1559 case 'C': /* checkpoint every N addresses */ 1560 CheckpointInterval = atoi(val); 1561 break; 1562 1563 case 'd': /* delivery mode */ 1564 switch (*val) 1565 { 1566 case '\0': 1567 e->e_sendmode = SM_DELIVER; 1568 break; 1569 1570 case SM_QUEUE: /* queue only */ 1571 #ifndef QUEUE 1572 syserr("need QUEUE to set -odqueue"); 1573 #endif /* QUEUE */ 1574 /* fall through..... */ 1575 1576 case SM_DELIVER: /* do everything */ 1577 case SM_FORK: /* fork after verification */ 1578 e->e_sendmode = *val; 1579 break; 1580 1581 default: 1582 syserr("Unknown delivery mode %c", *val); 1583 exit(EX_USAGE); 1584 } 1585 break; 1586 1587 case 'D': /* rebuild alias database as needed */ 1588 AutoRebuild = atobool(val); 1589 break; 1590 1591 case 'E': /* error message header/header file */ 1592 if (*val != '\0') 1593 ErrMsgFile = newstr(val); 1594 break; 1595 1596 case 'e': /* set error processing mode */ 1597 switch (*val) 1598 { 1599 case EM_QUIET: /* be silent about it */ 1600 case EM_MAIL: /* mail back */ 1601 case EM_BERKNET: /* do berknet error processing */ 1602 case EM_WRITE: /* write back (or mail) */ 1603 case EM_PRINT: /* print errors normally (default) */ 1604 e->e_errormode = *val; 1605 break; 1606 } 1607 break; 1608 1609 case 'F': /* file mode */ 1610 FileMode = atooct(val) & 0777; 1611 break; 1612 1613 case 'f': /* save Unix-style From lines on front */ 1614 SaveFrom = atobool(val); 1615 break; 1616 1617 case 'G': /* match recipients against GECOS field */ 1618 MatchGecos = atobool(val); 1619 break; 1620 1621 case 'g': /* default gid */ 1622 g_opt: 1623 if (isascii(*val) && isdigit(*val)) 1624 DefGid = atoi(val); 1625 else 1626 { 1627 register struct group *gr; 1628 1629 DefGid = -1; 1630 gr = getgrnam(val); 1631 if (gr == NULL) 1632 syserr("readcf: option %c: unknown group %s", 1633 opt, val); 1634 else 1635 DefGid = gr->gr_gid; 1636 } 1637 break; 1638 1639 case 'H': /* help file */ 1640 if (val[0] == '\0') 1641 HelpFile = "sendmail.hf"; 1642 else 1643 HelpFile = newstr(val); 1644 break; 1645 1646 case 'h': /* maximum hop count */ 1647 MaxHopCount = atoi(val); 1648 break; 1649 1650 case 'I': /* use internet domain name server */ 1651 #if NAMED_BIND 1652 for (p = val; *p != 0; ) 1653 { 1654 bool clearmode; 1655 char *q; 1656 struct resolverflags *rfp; 1657 1658 while (*p == ' ') 1659 p++; 1660 if (*p == '\0') 1661 break; 1662 clearmode = FALSE; 1663 if (*p == '-') 1664 clearmode = TRUE; 1665 else if (*p != '+') 1666 p--; 1667 p++; 1668 q = p; 1669 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1670 p++; 1671 if (*p != '\0') 1672 *p++ = '\0'; 1673 if (strcasecmp(q, "HasWildcardMX") == 0) 1674 { 1675 HasWildcardMX = !clearmode; 1676 continue; 1677 } 1678 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 1679 { 1680 if (strcasecmp(q, rfp->rf_name) == 0) 1681 break; 1682 } 1683 if (rfp->rf_name == NULL) 1684 syserr("readcf: I option value %s unrecognized", q); 1685 else if (clearmode) 1686 _res.options &= ~rfp->rf_bits; 1687 else 1688 _res.options |= rfp->rf_bits; 1689 } 1690 if (tTd(8, 2)) 1691 printf("_res.options = %x, HasWildcardMX = %d\n", 1692 _res.options, HasWildcardMX); 1693 #else 1694 usrerr("name server (I option) specified but BIND not compiled in"); 1695 #endif 1696 break; 1697 1698 case 'i': /* ignore dot lines in message */ 1699 IgnrDot = atobool(val); 1700 break; 1701 1702 case 'j': /* send errors in MIME (RFC 1341) format */ 1703 SendMIMEErrors = atobool(val); 1704 break; 1705 1706 case 'J': /* .forward search path */ 1707 ForwardPath = newstr(val); 1708 break; 1709 1710 case 'k': /* connection cache size */ 1711 MaxMciCache = atoi(val); 1712 if (MaxMciCache < 0) 1713 MaxMciCache = 0; 1714 break; 1715 1716 case 'K': /* connection cache timeout */ 1717 MciCacheTimeout = convtime(val, 'm'); 1718 break; 1719 1720 case 'l': /* use Errors-To: header */ 1721 UseErrorsTo = atobool(val); 1722 break; 1723 1724 case 'L': /* log level */ 1725 if (safe || LogLevel < atoi(val)) 1726 LogLevel = atoi(val); 1727 break; 1728 1729 case 'M': /* define macro */ 1730 p = newstr(&val[1]); 1731 if (!safe) 1732 cleanstrcpy(p, p, MAXNAME); 1733 define(val[0], p, CurEnv); 1734 sticky = FALSE; 1735 break; 1736 1737 case 'm': /* send to me too */ 1738 MeToo = atobool(val); 1739 break; 1740 1741 case 'n': /* validate RHS in newaliases */ 1742 CheckAliases = atobool(val); 1743 break; 1744 1745 /* 'N' available -- was "net name" */ 1746 1747 case 'O': /* daemon options */ 1748 setdaemonoptions(val); 1749 break; 1750 1751 case 'o': /* assume old style headers */ 1752 if (atobool(val)) 1753 CurEnv->e_flags |= EF_OLDSTYLE; 1754 else 1755 CurEnv->e_flags &= ~EF_OLDSTYLE; 1756 break; 1757 1758 case 'p': /* select privacy level */ 1759 p = val; 1760 for (;;) 1761 { 1762 register struct prival *pv; 1763 extern struct prival PrivacyValues[]; 1764 1765 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 1766 p++; 1767 if (*p == '\0') 1768 break; 1769 val = p; 1770 while (isascii(*p) && isalnum(*p)) 1771 p++; 1772 if (*p != '\0') 1773 *p++ = '\0'; 1774 1775 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 1776 { 1777 if (strcasecmp(val, pv->pv_name) == 0) 1778 break; 1779 } 1780 if (pv->pv_name == NULL) 1781 syserr("readcf: Op line: %s unrecognized", val); 1782 PrivacyFlags |= pv->pv_flag; 1783 } 1784 sticky = FALSE; 1785 break; 1786 1787 case 'P': /* postmaster copy address for returned mail */ 1788 PostMasterCopy = newstr(val); 1789 break; 1790 1791 case 'q': /* slope of queue only function */ 1792 QueueFactor = atoi(val); 1793 break; 1794 1795 case 'Q': /* queue directory */ 1796 if (val[0] == '\0') 1797 QueueDir = "mqueue"; 1798 else 1799 QueueDir = newstr(val); 1800 if (RealUid != 0 && !safe) 1801 Warn_Q_option = TRUE; 1802 break; 1803 1804 case 'R': /* don't prune routes */ 1805 DontPruneRoutes = atobool(val); 1806 break; 1807 1808 case 'r': /* read timeout */ 1809 if (subopt == NULL) 1810 inittimeouts(val); 1811 else 1812 settimeout(subopt, val); 1813 break; 1814 1815 case 'S': /* status file */ 1816 if (val[0] == '\0') 1817 StatFile = "sendmail.st"; 1818 else 1819 StatFile = newstr(val); 1820 break; 1821 1822 case 's': /* be super safe, even if expensive */ 1823 SuperSafe = atobool(val); 1824 break; 1825 1826 case 'T': /* queue timeout */ 1827 p = strchr(val, '/'); 1828 if (p != NULL) 1829 { 1830 *p++ = '\0'; 1831 settimeout("queuewarn", p); 1832 } 1833 settimeout("queuereturn", val); 1834 break; 1835 1836 case 't': /* time zone name */ 1837 TimeZoneSpec = newstr(val); 1838 break; 1839 1840 case 'U': /* location of user database */ 1841 UdbSpec = newstr(val); 1842 break; 1843 1844 case 'u': /* set default uid */ 1845 for (p = val; *p != '\0'; p++) 1846 { 1847 if (*p == '.' || *p == '/' || *p == ':') 1848 { 1849 *p++ = '\0'; 1850 break; 1851 } 1852 } 1853 if (isascii(*val) && isdigit(*val)) 1854 DefUid = atoi(val); 1855 else 1856 { 1857 register struct passwd *pw; 1858 1859 DefUid = -1; 1860 pw = sm_getpwnam(val); 1861 if (pw == NULL) 1862 syserr("readcf: option u: unknown user %s", val); 1863 else 1864 { 1865 DefUid = pw->pw_uid; 1866 DefGid = pw->pw_gid; 1867 } 1868 } 1869 setdefuser(); 1870 1871 /* handle the group if it is there */ 1872 if (*p == '\0') 1873 break; 1874 val = p; 1875 goto g_opt; 1876 1877 case 'V': /* fallback MX host */ 1878 FallBackMX = newstr(val); 1879 break; 1880 1881 case 'v': /* run in verbose mode */ 1882 Verbose = atobool(val); 1883 break; 1884 1885 case 'w': /* if we are best MX, try host directly */ 1886 TryNullMXList = atobool(val); 1887 break; 1888 1889 /* 'W' available -- was wizard password */ 1890 1891 case 'x': /* load avg at which to auto-queue msgs */ 1892 QueueLA = atoi(val); 1893 break; 1894 1895 case 'X': /* load avg at which to auto-reject connections */ 1896 RefuseLA = atoi(val); 1897 break; 1898 1899 case 'y': /* work recipient factor */ 1900 WkRecipFact = atoi(val); 1901 break; 1902 1903 case 'Y': /* fork jobs during queue runs */ 1904 ForkQueueRuns = atobool(val); 1905 break; 1906 1907 case 'z': /* work message class factor */ 1908 WkClassFact = atoi(val); 1909 break; 1910 1911 case 'Z': /* work time factor */ 1912 WkTimeFact = atoi(val); 1913 break; 1914 1915 case O_QUEUESORTORD: /* queue sorting order */ 1916 switch (*val) 1917 { 1918 case 'h': /* Host first */ 1919 case 'H': 1920 QueueSortOrder = QS_BYHOST; 1921 break; 1922 1923 case 'p': /* Priority order */ 1924 case 'P': 1925 QueueSortOrder = QS_BYPRIORITY; 1926 break; 1927 1928 default: 1929 syserr("Invalid queue sort order \"%s\"", val); 1930 } 1931 break; 1932 1933 case O_HOSTSFILE: /* pathname of /etc/hosts file */ 1934 HostsFile = newstr(val); 1935 break; 1936 1937 case O_MQA: /* minimum queue age between deliveries */ 1938 MinQueueAge = convtime(val, 'm'); 1939 break; 1940 1941 case O_MHSA: /* maximum age of cached host status */ 1942 MaxHostStatAge = convtime(val, 'm'); 1943 break; 1944 1945 case O_DEFCHARSET: /* default character set for mimefying */ 1946 DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 1947 break; 1948 1949 case O_SSFILE: /* service switch file */ 1950 ServiceSwitchFile = newstr(val); 1951 break; 1952 1953 case O_DIALDELAY: /* delay for dial-on-demand operation */ 1954 DialDelay = convtime(val, 's'); 1955 break; 1956 1957 case O_NORCPTACTION: /* what to do if no recipient */ 1958 if (strcasecmp(val, "none") == 0) 1959 NoRecipientAction = NRA_NO_ACTION; 1960 else if (strcasecmp(val, "add-to") == 0) 1961 NoRecipientAction = NRA_ADD_TO; 1962 else if (strcasecmp(val, "add-apparently-to") == 0) 1963 NoRecipientAction = NRA_ADD_APPARENTLY_TO; 1964 else if (strcasecmp(val, "add-bcc") == 0) 1965 NoRecipientAction = NRA_ADD_BCC; 1966 else if (strcasecmp(val, "add-to-undisclosed") == 0) 1967 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 1968 else 1969 syserr("Invalid NoRecipientAction: %s", val); 1970 1971 case O_SAFEFILEENV: /* chroot() environ for writing to files */ 1972 SafeFileEnv = newstr(val); 1973 break; 1974 1975 case O_MAXMSGSIZE: /* maximum message size */ 1976 MaxMessageSize = atol(val); 1977 break; 1978 1979 case O_COLONOKINADDR: /* old style handling of colon addresses */ 1980 ColonOkInAddr = atobool(val); 1981 break; 1982 1983 case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 1984 MaxQueueRun = atol(val); 1985 break; 1986 1987 case O_MAXCHILDREN: /* max # of children of daemon */ 1988 MaxChildren = atoi(val); 1989 break; 1990 1991 case O_KEEPCNAMES: /* don't expand CNAME records */ 1992 DontExpandCnames = atobool(val); 1993 break; 1994 1995 default: 1996 if (tTd(37, 1)) 1997 { 1998 if (isascii(opt) && isprint(opt)) 1999 printf("Warning: option %c unknown\n", opt); 2000 else 2001 printf("Warning: option 0x%x unknown\n", opt); 2002 } 2003 break; 2004 } 2005 if (sticky) 2006 setbitn(opt, StickyOpt); 2007 } 2008 /* 2009 ** SETCLASS -- set a string into a class 2010 ** 2011 ** Parameters: 2012 ** class -- the class to put the string in. 2013 ** str -- the string to enter 2014 ** 2015 ** Returns: 2016 ** none. 2017 ** 2018 ** Side Effects: 2019 ** puts the word into the symbol table. 2020 */ 2021 2022 void 2023 setclass(class, str) 2024 int class; 2025 char *str; 2026 { 2027 register STAB *s; 2028 2029 if (tTd(37, 8)) 2030 printf("setclass(%c, %s)\n", class, str); 2031 s = stab(str, ST_CLASS, ST_ENTER); 2032 setbitn(class, s->s_class); 2033 } 2034 /* 2035 ** MAKEMAPENTRY -- create a map entry 2036 ** 2037 ** Parameters: 2038 ** line -- the config file line 2039 ** 2040 ** Returns: 2041 ** A pointer to the map that has been created. 2042 ** NULL if there was a syntax error. 2043 ** 2044 ** Side Effects: 2045 ** Enters the map into the dictionary. 2046 */ 2047 2048 MAP * 2049 makemapentry(line) 2050 char *line; 2051 { 2052 register char *p; 2053 char *mapname; 2054 char *classname; 2055 register STAB *s; 2056 STAB *class; 2057 2058 for (p = line; isascii(*p) && isspace(*p); p++) 2059 continue; 2060 if (!(isascii(*p) && isalnum(*p))) 2061 { 2062 syserr("readcf: config K line: no map name"); 2063 return NULL; 2064 } 2065 2066 mapname = p; 2067 while ((isascii(*++p) && isalnum(*p)) || *p == '.') 2068 continue; 2069 if (*p != '\0') 2070 *p++ = '\0'; 2071 while (isascii(*p) && isspace(*p)) 2072 p++; 2073 if (!(isascii(*p) && isalnum(*p))) 2074 { 2075 syserr("readcf: config K line, map %s: no map class", mapname); 2076 return NULL; 2077 } 2078 classname = p; 2079 while (isascii(*++p) && isalnum(*p)) 2080 continue; 2081 if (*p != '\0') 2082 *p++ = '\0'; 2083 while (isascii(*p) && isspace(*p)) 2084 p++; 2085 2086 /* look up the class */ 2087 class = stab(classname, ST_MAPCLASS, ST_FIND); 2088 if (class == NULL) 2089 { 2090 syserr("readcf: map %s: class %s not available", mapname, classname); 2091 return NULL; 2092 } 2093 2094 /* enter the map */ 2095 s = stab(mapname, ST_MAP, ST_ENTER); 2096 s->s_map.map_class = &class->s_mapclass; 2097 s->s_map.map_mname = newstr(mapname); 2098 2099 if (class->s_mapclass.map_parse(&s->s_map, p)) 2100 s->s_map.map_mflags |= MF_VALID; 2101 2102 if (tTd(37, 5)) 2103 { 2104 printf("map %s, class %s, flags %x, file %s,\n", 2105 s->s_map.map_mname, s->s_map.map_class->map_cname, 2106 s->s_map.map_mflags, 2107 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 2108 printf("\tapp %s, domain %s, rebuild %s\n", 2109 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 2110 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 2111 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 2112 } 2113 2114 return &s->s_map; 2115 } 2116 /* 2117 ** STRTORWSET -- convert string to rewriting set number 2118 ** 2119 ** Parameters: 2120 ** p -- the pointer to the string to decode. 2121 ** endp -- if set, store the trailing delimiter here. 2122 ** stabmode -- ST_ENTER to create this entry, ST_FIND if 2123 ** it must already exist. 2124 ** 2125 ** Returns: 2126 ** The appropriate ruleset number. 2127 ** -1 if it is not valid (error already printed) 2128 */ 2129 2130 int 2131 strtorwset(p, endp, stabmode) 2132 char *p; 2133 char **endp; 2134 int stabmode; 2135 { 2136 int ruleset; 2137 static int nextruleset = MAXRWSETS; 2138 2139 while (isascii(*p) && isspace(*p)) 2140 p++; 2141 if (!isascii(*p)) 2142 { 2143 syserr("invalid ruleset name: \"%.20s\"", p); 2144 return -1; 2145 } 2146 if (isdigit(*p)) 2147 { 2148 ruleset = strtol(p, endp, 10); 2149 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 2150 { 2151 syserr("bad ruleset %d (%d max)", 2152 ruleset, MAXRWSETS / 2); 2153 ruleset = -1; 2154 } 2155 } 2156 else 2157 { 2158 STAB *s; 2159 char delim; 2160 char *q; 2161 2162 q = p; 2163 while (*p != '\0' && isascii(*p) && 2164 (isalnum(*p) || strchr("-_$", *p) != NULL)) 2165 p++; 2166 while (isascii(*p) && isspace(*p)) 2167 *p++ = '\0'; 2168 delim = *p; 2169 if (delim != '\0') 2170 *p = '\0'; 2171 s = stab(q, ST_RULESET, stabmode); 2172 if (delim != '\0') 2173 *p = delim; 2174 2175 if (s == NULL) 2176 { 2177 syserr("unknown ruleset %s", q); 2178 return -1; 2179 } 2180 2181 if (stabmode == ST_ENTER && delim == '=') 2182 { 2183 ruleset = strtol(p, endp, 10); 2184 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 2185 { 2186 syserr("bad ruleset %s = %d (%d max)", 2187 q, ruleset, MAXRWSETS / 2); 2188 ruleset = -1; 2189 } 2190 } 2191 else 2192 { 2193 if (endp != NULL) 2194 *endp = p; 2195 if (s->s_ruleset > 0) 2196 ruleset = s->s_ruleset; 2197 else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 2198 { 2199 syserr("%s: too many named rulesets (%d max)", 2200 q, MAXRWSETS / 2); 2201 ruleset = -1; 2202 } 2203 } 2204 if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset) 2205 { 2206 syserr("%s: ruleset changed value (old %d, new %d)", 2207 q, ruleset, s->s_ruleset); 2208 ruleset = s->s_ruleset; 2209 } 2210 else if (ruleset > 0) 2211 { 2212 s->s_ruleset = ruleset; 2213 } 2214 } 2215 return ruleset; 2216 } 2217 /* 2218 ** INITTIMEOUTS -- parse and set timeout values 2219 ** 2220 ** Parameters: 2221 ** val -- a pointer to the values. If NULL, do initial 2222 ** settings. 2223 ** 2224 ** Returns: 2225 ** none. 2226 ** 2227 ** Side Effects: 2228 ** Initializes the TimeOuts structure 2229 */ 2230 2231 #define SECONDS 2232 #define MINUTES * 60 2233 #define HOUR * 3600 2234 2235 void 2236 inittimeouts(val) 2237 register char *val; 2238 { 2239 register char *p; 2240 extern time_t convtime(); 2241 2242 if (val == NULL) 2243 { 2244 TimeOuts.to_initial = (time_t) 5 MINUTES; 2245 TimeOuts.to_helo = (time_t) 5 MINUTES; 2246 TimeOuts.to_mail = (time_t) 10 MINUTES; 2247 TimeOuts.to_rcpt = (time_t) 1 HOUR; 2248 TimeOuts.to_datainit = (time_t) 5 MINUTES; 2249 TimeOuts.to_datablock = (time_t) 1 HOUR; 2250 TimeOuts.to_datafinal = (time_t) 1 HOUR; 2251 TimeOuts.to_rset = (time_t) 5 MINUTES; 2252 TimeOuts.to_quit = (time_t) 2 MINUTES; 2253 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 2254 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2255 #if IDENTPROTO 2256 TimeOuts.to_ident = (time_t) 30 SECONDS; 2257 #else 2258 TimeOuts.to_ident = (time_t) 0 SECONDS; 2259 #endif 2260 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 2261 return; 2262 } 2263 2264 for (;; val = p) 2265 { 2266 while (isascii(*val) && isspace(*val)) 2267 val++; 2268 if (*val == '\0') 2269 break; 2270 for (p = val; *p != '\0' && *p != ','; p++) 2271 continue; 2272 if (*p != '\0') 2273 *p++ = '\0'; 2274 2275 if (isascii(*val) && isdigit(*val)) 2276 { 2277 /* old syntax -- set everything */ 2278 TimeOuts.to_mail = convtime(val, 'm'); 2279 TimeOuts.to_rcpt = TimeOuts.to_mail; 2280 TimeOuts.to_datainit = TimeOuts.to_mail; 2281 TimeOuts.to_datablock = TimeOuts.to_mail; 2282 TimeOuts.to_datafinal = TimeOuts.to_mail; 2283 TimeOuts.to_nextcommand = TimeOuts.to_mail; 2284 continue; 2285 } 2286 else 2287 { 2288 register char *q = strchr(val, ':'); 2289 2290 if (q == NULL && (q = strchr(val, '=')) == NULL) 2291 { 2292 /* syntax error */ 2293 continue; 2294 } 2295 *q++ = '\0'; 2296 settimeout(val, q); 2297 } 2298 } 2299 } 2300 /* 2301 ** SETTIMEOUT -- set an individual timeout 2302 ** 2303 ** Parameters: 2304 ** name -- the name of the timeout. 2305 ** val -- the value of the timeout. 2306 ** 2307 ** Returns: 2308 ** none. 2309 */ 2310 2311 void 2312 settimeout(name, val) 2313 char *name; 2314 char *val; 2315 { 2316 register char *p; 2317 time_t to; 2318 extern time_t convtime(); 2319 2320 to = convtime(val, 'm'); 2321 p = strchr(name, '.'); 2322 if (p != NULL) 2323 *p++ = '\0'; 2324 2325 if (strcasecmp(name, "initial") == 0) 2326 TimeOuts.to_initial = to; 2327 else if (strcasecmp(name, "mail") == 0) 2328 TimeOuts.to_mail = to; 2329 else if (strcasecmp(name, "rcpt") == 0) 2330 TimeOuts.to_rcpt = to; 2331 else if (strcasecmp(name, "datainit") == 0) 2332 TimeOuts.to_datainit = to; 2333 else if (strcasecmp(name, "datablock") == 0) 2334 TimeOuts.to_datablock = to; 2335 else if (strcasecmp(name, "datafinal") == 0) 2336 TimeOuts.to_datafinal = to; 2337 else if (strcasecmp(name, "command") == 0) 2338 TimeOuts.to_nextcommand = to; 2339 else if (strcasecmp(name, "rset") == 0) 2340 TimeOuts.to_rset = to; 2341 else if (strcasecmp(name, "helo") == 0) 2342 TimeOuts.to_helo = to; 2343 else if (strcasecmp(name, "quit") == 0) 2344 TimeOuts.to_quit = to; 2345 else if (strcasecmp(name, "misc") == 0) 2346 TimeOuts.to_miscshort = to; 2347 else if (strcasecmp(name, "ident") == 0) 2348 TimeOuts.to_ident = to; 2349 else if (strcasecmp(name, "fileopen") == 0) 2350 TimeOuts.to_fileopen = to; 2351 else if (strcasecmp(name, "queuewarn") == 0) 2352 { 2353 to = convtime(val, 'h'); 2354 if (p == NULL || strcmp(p, "*") == 0) 2355 { 2356 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2357 TimeOuts.to_q_warning[TOC_URGENT] = to; 2358 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2359 } 2360 else if (strcasecmp(p, "normal") == 0) 2361 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2362 else if (strcasecmp(p, "urgent") == 0) 2363 TimeOuts.to_q_warning[TOC_URGENT] = to; 2364 else if (strcasecmp(p, "non-urgent") == 0) 2365 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2366 else 2367 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2368 } 2369 else if (strcasecmp(name, "queuereturn") == 0) 2370 { 2371 to = convtime(val, 'd'); 2372 if (p == NULL || strcmp(p, "*") == 0) 2373 { 2374 TimeOuts.to_q_return[TOC_NORMAL] = to; 2375 TimeOuts.to_q_return[TOC_URGENT] = to; 2376 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2377 } 2378 else if (strcasecmp(p, "normal") == 0) 2379 TimeOuts.to_q_return[TOC_NORMAL] = to; 2380 else if (strcasecmp(p, "urgent") == 0) 2381 TimeOuts.to_q_return[TOC_URGENT] = to; 2382 else if (strcasecmp(p, "non-urgent") == 0) 2383 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2384 else 2385 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2386 } 2387 else 2388 syserr("settimeout: invalid timeout %s", name); 2389 } 2390