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.110 (Berkeley) 06/21/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 endpwent(); 1471 (void) setgid(RealGid); 1472 (void) setuid(RealUid); 1473 } 1474 } 1475 } 1476 if (tTd(37, 1)) 1477 printf("\n"); 1478 1479 switch (opt & 0xff) 1480 { 1481 case '7': /* force seven-bit input */ 1482 SevenBitInput = atobool(val); 1483 break; 1484 1485 #if MIME8TO7 1486 case '8': /* handling of 8-bit input */ 1487 switch (*val) 1488 { 1489 case 'm': /* convert 8-bit, convert MIME */ 1490 MimeMode = MM_CVTMIME|MM_MIME8BIT; 1491 break; 1492 1493 case 'p': /* pass 8 bit, convert MIME */ 1494 MimeMode = MM_CVTMIME|MM_PASS8BIT; 1495 break; 1496 1497 case 's': /* strict adherence */ 1498 MimeMode = MM_CVTMIME; 1499 break; 1500 1501 #if 0 1502 case 'r': /* reject 8-bit, don't convert MIME */ 1503 MimeMode = 0; 1504 break; 1505 1506 case 'j': /* "just send 8" */ 1507 MimeMode = MM_PASS8BIT; 1508 break; 1509 1510 case 'a': /* encode 8 bit if available */ 1511 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1512 break; 1513 1514 case 'c': /* convert 8 bit to MIME, never 7 bit */ 1515 MimeMode = MM_MIME8BIT; 1516 break; 1517 #endif 1518 1519 default: 1520 syserr("Unknown 8-bit mode %c", *val); 1521 exit(EX_USAGE); 1522 } 1523 break; 1524 #endif 1525 1526 case 'A': /* set default alias file */ 1527 if (val[0] == '\0') 1528 setalias("aliases"); 1529 else 1530 setalias(val); 1531 break; 1532 1533 case 'a': /* look N minutes for "@:@" in alias file */ 1534 if (val[0] == '\0') 1535 SafeAlias = 5 * 60; /* five minutes */ 1536 else 1537 SafeAlias = convtime(val, 'm'); 1538 break; 1539 1540 case 'B': /* substitution for blank character */ 1541 SpaceSub = val[0]; 1542 if (SpaceSub == '\0') 1543 SpaceSub = ' '; 1544 break; 1545 1546 case 'b': /* min blocks free on queue fs/max msg size */ 1547 p = strchr(val, '/'); 1548 if (p != NULL) 1549 { 1550 *p++ = '\0'; 1551 MaxMessageSize = atol(p); 1552 } 1553 MinBlocksFree = atol(val); 1554 break; 1555 1556 case 'c': /* don't connect to "expensive" mailers */ 1557 NoConnect = atobool(val); 1558 break; 1559 1560 case 'C': /* checkpoint every N addresses */ 1561 CheckpointInterval = atoi(val); 1562 break; 1563 1564 case 'd': /* delivery mode */ 1565 switch (*val) 1566 { 1567 case '\0': 1568 e->e_sendmode = SM_DELIVER; 1569 break; 1570 1571 case SM_QUEUE: /* queue only */ 1572 #ifndef QUEUE 1573 syserr("need QUEUE to set -odqueue"); 1574 #endif /* QUEUE */ 1575 /* fall through..... */ 1576 1577 case SM_DELIVER: /* do everything */ 1578 case SM_FORK: /* fork after verification */ 1579 e->e_sendmode = *val; 1580 break; 1581 1582 default: 1583 syserr("Unknown delivery mode %c", *val); 1584 exit(EX_USAGE); 1585 } 1586 break; 1587 1588 case 'D': /* rebuild alias database as needed */ 1589 AutoRebuild = atobool(val); 1590 break; 1591 1592 case 'E': /* error message header/header file */ 1593 if (*val != '\0') 1594 ErrMsgFile = newstr(val); 1595 break; 1596 1597 case 'e': /* set error processing mode */ 1598 switch (*val) 1599 { 1600 case EM_QUIET: /* be silent about it */ 1601 case EM_MAIL: /* mail back */ 1602 case EM_BERKNET: /* do berknet error processing */ 1603 case EM_WRITE: /* write back (or mail) */ 1604 case EM_PRINT: /* print errors normally (default) */ 1605 e->e_errormode = *val; 1606 break; 1607 } 1608 break; 1609 1610 case 'F': /* file mode */ 1611 FileMode = atooct(val) & 0777; 1612 break; 1613 1614 case 'f': /* save Unix-style From lines on front */ 1615 SaveFrom = atobool(val); 1616 break; 1617 1618 case 'G': /* match recipients against GECOS field */ 1619 MatchGecos = atobool(val); 1620 break; 1621 1622 case 'g': /* default gid */ 1623 g_opt: 1624 if (isascii(*val) && isdigit(*val)) 1625 DefGid = atoi(val); 1626 else 1627 { 1628 register struct group *gr; 1629 1630 DefGid = -1; 1631 gr = getgrnam(val); 1632 if (gr == NULL) 1633 syserr("readcf: option %c: unknown group %s", 1634 opt, val); 1635 else 1636 DefGid = gr->gr_gid; 1637 } 1638 break; 1639 1640 case 'H': /* help file */ 1641 if (val[0] == '\0') 1642 HelpFile = "sendmail.hf"; 1643 else 1644 HelpFile = newstr(val); 1645 break; 1646 1647 case 'h': /* maximum hop count */ 1648 MaxHopCount = atoi(val); 1649 break; 1650 1651 case 'I': /* use internet domain name server */ 1652 #if NAMED_BIND 1653 for (p = val; *p != 0; ) 1654 { 1655 bool clearmode; 1656 char *q; 1657 struct resolverflags *rfp; 1658 1659 while (*p == ' ') 1660 p++; 1661 if (*p == '\0') 1662 break; 1663 clearmode = FALSE; 1664 if (*p == '-') 1665 clearmode = TRUE; 1666 else if (*p != '+') 1667 p--; 1668 p++; 1669 q = p; 1670 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1671 p++; 1672 if (*p != '\0') 1673 *p++ = '\0'; 1674 if (strcasecmp(q, "HasWildcardMX") == 0) 1675 { 1676 HasWildcardMX = !clearmode; 1677 continue; 1678 } 1679 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 1680 { 1681 if (strcasecmp(q, rfp->rf_name) == 0) 1682 break; 1683 } 1684 if (rfp->rf_name == NULL) 1685 syserr("readcf: I option value %s unrecognized", q); 1686 else if (clearmode) 1687 _res.options &= ~rfp->rf_bits; 1688 else 1689 _res.options |= rfp->rf_bits; 1690 } 1691 if (tTd(8, 2)) 1692 printf("_res.options = %x, HasWildcardMX = %d\n", 1693 _res.options, HasWildcardMX); 1694 #else 1695 usrerr("name server (I option) specified but BIND not compiled in"); 1696 #endif 1697 break; 1698 1699 case 'i': /* ignore dot lines in message */ 1700 IgnrDot = atobool(val); 1701 break; 1702 1703 case 'j': /* send errors in MIME (RFC 1341) format */ 1704 SendMIMEErrors = atobool(val); 1705 break; 1706 1707 case 'J': /* .forward search path */ 1708 ForwardPath = newstr(val); 1709 break; 1710 1711 case 'k': /* connection cache size */ 1712 MaxMciCache = atoi(val); 1713 if (MaxMciCache < 0) 1714 MaxMciCache = 0; 1715 break; 1716 1717 case 'K': /* connection cache timeout */ 1718 MciCacheTimeout = convtime(val, 'm'); 1719 break; 1720 1721 case 'l': /* use Errors-To: header */ 1722 UseErrorsTo = atobool(val); 1723 break; 1724 1725 case 'L': /* log level */ 1726 if (safe || LogLevel < atoi(val)) 1727 LogLevel = atoi(val); 1728 break; 1729 1730 case 'M': /* define macro */ 1731 p = newstr(&val[1]); 1732 if (!safe) 1733 cleanstrcpy(p, p, MAXNAME); 1734 define(val[0], p, CurEnv); 1735 sticky = FALSE; 1736 break; 1737 1738 case 'm': /* send to me too */ 1739 MeToo = atobool(val); 1740 break; 1741 1742 case 'n': /* validate RHS in newaliases */ 1743 CheckAliases = atobool(val); 1744 break; 1745 1746 /* 'N' available -- was "net name" */ 1747 1748 case 'O': /* daemon options */ 1749 setdaemonoptions(val); 1750 break; 1751 1752 case 'o': /* assume old style headers */ 1753 if (atobool(val)) 1754 CurEnv->e_flags |= EF_OLDSTYLE; 1755 else 1756 CurEnv->e_flags &= ~EF_OLDSTYLE; 1757 break; 1758 1759 case 'p': /* select privacy level */ 1760 p = val; 1761 for (;;) 1762 { 1763 register struct prival *pv; 1764 extern struct prival PrivacyValues[]; 1765 1766 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 1767 p++; 1768 if (*p == '\0') 1769 break; 1770 val = p; 1771 while (isascii(*p) && isalnum(*p)) 1772 p++; 1773 if (*p != '\0') 1774 *p++ = '\0'; 1775 1776 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 1777 { 1778 if (strcasecmp(val, pv->pv_name) == 0) 1779 break; 1780 } 1781 if (pv->pv_name == NULL) 1782 syserr("readcf: Op line: %s unrecognized", val); 1783 PrivacyFlags |= pv->pv_flag; 1784 } 1785 sticky = FALSE; 1786 break; 1787 1788 case 'P': /* postmaster copy address for returned mail */ 1789 PostMasterCopy = newstr(val); 1790 break; 1791 1792 case 'q': /* slope of queue only function */ 1793 QueueFactor = atoi(val); 1794 break; 1795 1796 case 'Q': /* queue directory */ 1797 if (val[0] == '\0') 1798 QueueDir = "mqueue"; 1799 else 1800 QueueDir = newstr(val); 1801 if (RealUid != 0 && !safe) 1802 Warn_Q_option = TRUE; 1803 break; 1804 1805 case 'R': /* don't prune routes */ 1806 DontPruneRoutes = atobool(val); 1807 break; 1808 1809 case 'r': /* read timeout */ 1810 if (subopt == NULL) 1811 inittimeouts(val); 1812 else 1813 settimeout(subopt, val); 1814 break; 1815 1816 case 'S': /* status file */ 1817 if (val[0] == '\0') 1818 StatFile = "sendmail.st"; 1819 else 1820 StatFile = newstr(val); 1821 break; 1822 1823 case 's': /* be super safe, even if expensive */ 1824 SuperSafe = atobool(val); 1825 break; 1826 1827 case 'T': /* queue timeout */ 1828 p = strchr(val, '/'); 1829 if (p != NULL) 1830 { 1831 *p++ = '\0'; 1832 settimeout("queuewarn", p); 1833 } 1834 settimeout("queuereturn", val); 1835 break; 1836 1837 case 't': /* time zone name */ 1838 TimeZoneSpec = newstr(val); 1839 break; 1840 1841 case 'U': /* location of user database */ 1842 UdbSpec = newstr(val); 1843 break; 1844 1845 case 'u': /* set default uid */ 1846 for (p = val; *p != '\0'; p++) 1847 { 1848 if (*p == '.' || *p == '/' || *p == ':') 1849 { 1850 *p++ = '\0'; 1851 break; 1852 } 1853 } 1854 if (isascii(*val) && isdigit(*val)) 1855 DefUid = atoi(val); 1856 else 1857 { 1858 register struct passwd *pw; 1859 1860 DefUid = -1; 1861 pw = sm_getpwnam(val); 1862 if (pw == NULL) 1863 syserr("readcf: option u: unknown user %s", val); 1864 else 1865 { 1866 DefUid = pw->pw_uid; 1867 DefGid = pw->pw_gid; 1868 } 1869 } 1870 setdefuser(); 1871 1872 /* handle the group if it is there */ 1873 if (*p == '\0') 1874 break; 1875 val = p; 1876 goto g_opt; 1877 1878 case 'V': /* fallback MX host */ 1879 FallBackMX = newstr(val); 1880 break; 1881 1882 case 'v': /* run in verbose mode */ 1883 Verbose = atobool(val); 1884 break; 1885 1886 case 'w': /* if we are best MX, try host directly */ 1887 TryNullMXList = atobool(val); 1888 break; 1889 1890 /* 'W' available -- was wizard password */ 1891 1892 case 'x': /* load avg at which to auto-queue msgs */ 1893 QueueLA = atoi(val); 1894 break; 1895 1896 case 'X': /* load avg at which to auto-reject connections */ 1897 RefuseLA = atoi(val); 1898 break; 1899 1900 case 'y': /* work recipient factor */ 1901 WkRecipFact = atoi(val); 1902 break; 1903 1904 case 'Y': /* fork jobs during queue runs */ 1905 ForkQueueRuns = atobool(val); 1906 break; 1907 1908 case 'z': /* work message class factor */ 1909 WkClassFact = atoi(val); 1910 break; 1911 1912 case 'Z': /* work time factor */ 1913 WkTimeFact = atoi(val); 1914 break; 1915 1916 case O_QUEUESORTORD: /* queue sorting order */ 1917 switch (*val) 1918 { 1919 case 'h': /* Host first */ 1920 case 'H': 1921 QueueSortOrder = QS_BYHOST; 1922 break; 1923 1924 case 'p': /* Priority order */ 1925 case 'P': 1926 QueueSortOrder = QS_BYPRIORITY; 1927 break; 1928 1929 default: 1930 syserr("Invalid queue sort order \"%s\"", val); 1931 } 1932 break; 1933 1934 case O_HOSTSFILE: /* pathname of /etc/hosts file */ 1935 HostsFile = newstr(val); 1936 break; 1937 1938 case O_MQA: /* minimum queue age between deliveries */ 1939 MinQueueAge = convtime(val, 'm'); 1940 break; 1941 1942 case O_MHSA: /* maximum age of cached host status */ 1943 MaxHostStatAge = convtime(val, 'm'); 1944 break; 1945 1946 case O_DEFCHARSET: /* default character set for mimefying */ 1947 DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 1948 break; 1949 1950 case O_SSFILE: /* service switch file */ 1951 ServiceSwitchFile = newstr(val); 1952 break; 1953 1954 case O_DIALDELAY: /* delay for dial-on-demand operation */ 1955 DialDelay = convtime(val, 's'); 1956 break; 1957 1958 case O_NORCPTACTION: /* what to do if no recipient */ 1959 if (strcasecmp(val, "none") == 0) 1960 NoRecipientAction = NRA_NO_ACTION; 1961 else if (strcasecmp(val, "add-to") == 0) 1962 NoRecipientAction = NRA_ADD_TO; 1963 else if (strcasecmp(val, "add-apparently-to") == 0) 1964 NoRecipientAction = NRA_ADD_APPARENTLY_TO; 1965 else if (strcasecmp(val, "add-bcc") == 0) 1966 NoRecipientAction = NRA_ADD_BCC; 1967 else if (strcasecmp(val, "add-to-undisclosed") == 0) 1968 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 1969 else 1970 syserr("Invalid NoRecipientAction: %s", val); 1971 1972 case O_SAFEFILEENV: /* chroot() environ for writing to files */ 1973 SafeFileEnv = newstr(val); 1974 break; 1975 1976 case O_MAXMSGSIZE: /* maximum message size */ 1977 MaxMessageSize = atol(val); 1978 break; 1979 1980 case O_COLONOKINADDR: /* old style handling of colon addresses */ 1981 ColonOkInAddr = atobool(val); 1982 break; 1983 1984 case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 1985 MaxQueueRun = atol(val); 1986 break; 1987 1988 case O_MAXCHILDREN: /* max # of children of daemon */ 1989 MaxChildren = atoi(val); 1990 break; 1991 1992 case O_KEEPCNAMES: /* don't expand CNAME records */ 1993 DontExpandCnames = atobool(val); 1994 break; 1995 1996 default: 1997 if (tTd(37, 1)) 1998 { 1999 if (isascii(opt) && isprint(opt)) 2000 printf("Warning: option %c unknown\n", opt); 2001 else 2002 printf("Warning: option 0x%x unknown\n", opt); 2003 } 2004 break; 2005 } 2006 if (sticky) 2007 setbitn(opt, StickyOpt); 2008 } 2009 /* 2010 ** SETCLASS -- set a string into a class 2011 ** 2012 ** Parameters: 2013 ** class -- the class to put the string in. 2014 ** str -- the string to enter 2015 ** 2016 ** Returns: 2017 ** none. 2018 ** 2019 ** Side Effects: 2020 ** puts the word into the symbol table. 2021 */ 2022 2023 void 2024 setclass(class, str) 2025 int class; 2026 char *str; 2027 { 2028 register STAB *s; 2029 2030 if (tTd(37, 8)) 2031 printf("setclass(%c, %s)\n", class, str); 2032 s = stab(str, ST_CLASS, ST_ENTER); 2033 setbitn(class, s->s_class); 2034 } 2035 /* 2036 ** MAKEMAPENTRY -- create a map entry 2037 ** 2038 ** Parameters: 2039 ** line -- the config file line 2040 ** 2041 ** Returns: 2042 ** A pointer to the map that has been created. 2043 ** NULL if there was a syntax error. 2044 ** 2045 ** Side Effects: 2046 ** Enters the map into the dictionary. 2047 */ 2048 2049 MAP * 2050 makemapentry(line) 2051 char *line; 2052 { 2053 register char *p; 2054 char *mapname; 2055 char *classname; 2056 register STAB *s; 2057 STAB *class; 2058 2059 for (p = line; isascii(*p) && isspace(*p); p++) 2060 continue; 2061 if (!(isascii(*p) && isalnum(*p))) 2062 { 2063 syserr("readcf: config K line: no map name"); 2064 return NULL; 2065 } 2066 2067 mapname = p; 2068 while ((isascii(*++p) && isalnum(*p)) || *p == '.') 2069 continue; 2070 if (*p != '\0') 2071 *p++ = '\0'; 2072 while (isascii(*p) && isspace(*p)) 2073 p++; 2074 if (!(isascii(*p) && isalnum(*p))) 2075 { 2076 syserr("readcf: config K line, map %s: no map class", mapname); 2077 return NULL; 2078 } 2079 classname = p; 2080 while (isascii(*++p) && isalnum(*p)) 2081 continue; 2082 if (*p != '\0') 2083 *p++ = '\0'; 2084 while (isascii(*p) && isspace(*p)) 2085 p++; 2086 2087 /* look up the class */ 2088 class = stab(classname, ST_MAPCLASS, ST_FIND); 2089 if (class == NULL) 2090 { 2091 syserr("readcf: map %s: class %s not available", mapname, classname); 2092 return NULL; 2093 } 2094 2095 /* enter the map */ 2096 s = stab(mapname, ST_MAP, ST_ENTER); 2097 s->s_map.map_class = &class->s_mapclass; 2098 s->s_map.map_mname = newstr(mapname); 2099 2100 if (class->s_mapclass.map_parse(&s->s_map, p)) 2101 s->s_map.map_mflags |= MF_VALID; 2102 2103 if (tTd(37, 5)) 2104 { 2105 printf("map %s, class %s, flags %x, file %s,\n", 2106 s->s_map.map_mname, s->s_map.map_class->map_cname, 2107 s->s_map.map_mflags, 2108 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 2109 printf("\tapp %s, domain %s, rebuild %s\n", 2110 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 2111 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 2112 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 2113 } 2114 2115 return &s->s_map; 2116 } 2117 /* 2118 ** STRTORWSET -- convert string to rewriting set number 2119 ** 2120 ** Parameters: 2121 ** p -- the pointer to the string to decode. 2122 ** endp -- if set, store the trailing delimiter here. 2123 ** stabmode -- ST_ENTER to create this entry, ST_FIND if 2124 ** it must already exist. 2125 ** 2126 ** Returns: 2127 ** The appropriate ruleset number. 2128 ** -1 if it is not valid (error already printed) 2129 */ 2130 2131 int 2132 strtorwset(p, endp, stabmode) 2133 char *p; 2134 char **endp; 2135 int stabmode; 2136 { 2137 int ruleset; 2138 static int nextruleset = MAXRWSETS; 2139 2140 while (isascii(*p) && isspace(*p)) 2141 p++; 2142 if (!isascii(*p)) 2143 { 2144 syserr("invalid ruleset name: \"%.20s\"", p); 2145 return -1; 2146 } 2147 if (isdigit(*p)) 2148 { 2149 ruleset = strtol(p, endp, 10); 2150 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 2151 { 2152 syserr("bad ruleset %d (%d max)", 2153 ruleset, MAXRWSETS / 2); 2154 ruleset = -1; 2155 } 2156 } 2157 else 2158 { 2159 STAB *s; 2160 char delim; 2161 char *q; 2162 2163 q = p; 2164 while (*p != '\0' && isascii(*p) && 2165 (isalnum(*p) || strchr("-_$", *p) != NULL)) 2166 p++; 2167 if (q == p || !isalpha(*q)) 2168 { 2169 /* no valid characters */ 2170 syserr("invalid ruleset name: \"%.20s\"", q); 2171 return -1; 2172 } 2173 while (isascii(*p) && isspace(*p)) 2174 *p++ = '\0'; 2175 delim = *p; 2176 if (delim != '\0') 2177 *p = '\0'; 2178 s = stab(q, ST_RULESET, stabmode); 2179 if (delim != '\0') 2180 *p = delim; 2181 2182 if (s == NULL) 2183 { 2184 syserr("unknown ruleset %s", q); 2185 return -1; 2186 } 2187 2188 if (stabmode == ST_ENTER && delim == '=') 2189 { 2190 ruleset = strtol(++p, endp, 10); 2191 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 2192 { 2193 syserr("bad ruleset %s = %d (%d max)", 2194 q, ruleset, MAXRWSETS / 2); 2195 ruleset = -1; 2196 } 2197 } 2198 else 2199 { 2200 if (endp != NULL) 2201 *endp = p; 2202 if (s->s_ruleset > 0) 2203 ruleset = s->s_ruleset; 2204 else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 2205 { 2206 syserr("%s: too many named rulesets (%d max)", 2207 q, MAXRWSETS / 2); 2208 ruleset = -1; 2209 } 2210 } 2211 if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset) 2212 { 2213 syserr("%s: ruleset changed value (old %d, new %d)", 2214 q, ruleset, s->s_ruleset); 2215 ruleset = s->s_ruleset; 2216 } 2217 else if (ruleset > 0) 2218 { 2219 s->s_ruleset = ruleset; 2220 } 2221 } 2222 return ruleset; 2223 } 2224 /* 2225 ** INITTIMEOUTS -- parse and set timeout values 2226 ** 2227 ** Parameters: 2228 ** val -- a pointer to the values. If NULL, do initial 2229 ** settings. 2230 ** 2231 ** Returns: 2232 ** none. 2233 ** 2234 ** Side Effects: 2235 ** Initializes the TimeOuts structure 2236 */ 2237 2238 #define SECONDS 2239 #define MINUTES * 60 2240 #define HOUR * 3600 2241 2242 void 2243 inittimeouts(val) 2244 register char *val; 2245 { 2246 register char *p; 2247 extern time_t convtime(); 2248 2249 if (val == NULL) 2250 { 2251 TimeOuts.to_initial = (time_t) 5 MINUTES; 2252 TimeOuts.to_helo = (time_t) 5 MINUTES; 2253 TimeOuts.to_mail = (time_t) 10 MINUTES; 2254 TimeOuts.to_rcpt = (time_t) 1 HOUR; 2255 TimeOuts.to_datainit = (time_t) 5 MINUTES; 2256 TimeOuts.to_datablock = (time_t) 1 HOUR; 2257 TimeOuts.to_datafinal = (time_t) 1 HOUR; 2258 TimeOuts.to_rset = (time_t) 5 MINUTES; 2259 TimeOuts.to_quit = (time_t) 2 MINUTES; 2260 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 2261 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2262 #if IDENTPROTO 2263 TimeOuts.to_ident = (time_t) 30 SECONDS; 2264 #else 2265 TimeOuts.to_ident = (time_t) 0 SECONDS; 2266 #endif 2267 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 2268 return; 2269 } 2270 2271 for (;; val = p) 2272 { 2273 while (isascii(*val) && isspace(*val)) 2274 val++; 2275 if (*val == '\0') 2276 break; 2277 for (p = val; *p != '\0' && *p != ','; p++) 2278 continue; 2279 if (*p != '\0') 2280 *p++ = '\0'; 2281 2282 if (isascii(*val) && isdigit(*val)) 2283 { 2284 /* old syntax -- set everything */ 2285 TimeOuts.to_mail = convtime(val, 'm'); 2286 TimeOuts.to_rcpt = TimeOuts.to_mail; 2287 TimeOuts.to_datainit = TimeOuts.to_mail; 2288 TimeOuts.to_datablock = TimeOuts.to_mail; 2289 TimeOuts.to_datafinal = TimeOuts.to_mail; 2290 TimeOuts.to_nextcommand = TimeOuts.to_mail; 2291 continue; 2292 } 2293 else 2294 { 2295 register char *q = strchr(val, ':'); 2296 2297 if (q == NULL && (q = strchr(val, '=')) == NULL) 2298 { 2299 /* syntax error */ 2300 continue; 2301 } 2302 *q++ = '\0'; 2303 settimeout(val, q); 2304 } 2305 } 2306 } 2307 /* 2308 ** SETTIMEOUT -- set an individual timeout 2309 ** 2310 ** Parameters: 2311 ** name -- the name of the timeout. 2312 ** val -- the value of the timeout. 2313 ** 2314 ** Returns: 2315 ** none. 2316 */ 2317 2318 void 2319 settimeout(name, val) 2320 char *name; 2321 char *val; 2322 { 2323 register char *p; 2324 time_t to; 2325 extern time_t convtime(); 2326 2327 to = convtime(val, 'm'); 2328 p = strchr(name, '.'); 2329 if (p != NULL) 2330 *p++ = '\0'; 2331 2332 if (strcasecmp(name, "initial") == 0) 2333 TimeOuts.to_initial = to; 2334 else if (strcasecmp(name, "mail") == 0) 2335 TimeOuts.to_mail = to; 2336 else if (strcasecmp(name, "rcpt") == 0) 2337 TimeOuts.to_rcpt = to; 2338 else if (strcasecmp(name, "datainit") == 0) 2339 TimeOuts.to_datainit = to; 2340 else if (strcasecmp(name, "datablock") == 0) 2341 TimeOuts.to_datablock = to; 2342 else if (strcasecmp(name, "datafinal") == 0) 2343 TimeOuts.to_datafinal = to; 2344 else if (strcasecmp(name, "command") == 0) 2345 TimeOuts.to_nextcommand = to; 2346 else if (strcasecmp(name, "rset") == 0) 2347 TimeOuts.to_rset = to; 2348 else if (strcasecmp(name, "helo") == 0) 2349 TimeOuts.to_helo = to; 2350 else if (strcasecmp(name, "quit") == 0) 2351 TimeOuts.to_quit = to; 2352 else if (strcasecmp(name, "misc") == 0) 2353 TimeOuts.to_miscshort = to; 2354 else if (strcasecmp(name, "ident") == 0) 2355 TimeOuts.to_ident = to; 2356 else if (strcasecmp(name, "fileopen") == 0) 2357 TimeOuts.to_fileopen = to; 2358 else if (strcasecmp(name, "queuewarn") == 0) 2359 { 2360 to = convtime(val, 'h'); 2361 if (p == NULL || strcmp(p, "*") == 0) 2362 { 2363 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2364 TimeOuts.to_q_warning[TOC_URGENT] = to; 2365 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2366 } 2367 else if (strcasecmp(p, "normal") == 0) 2368 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2369 else if (strcasecmp(p, "urgent") == 0) 2370 TimeOuts.to_q_warning[TOC_URGENT] = to; 2371 else if (strcasecmp(p, "non-urgent") == 0) 2372 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2373 else 2374 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2375 } 2376 else if (strcasecmp(name, "queuereturn") == 0) 2377 { 2378 to = convtime(val, 'd'); 2379 if (p == NULL || strcmp(p, "*") == 0) 2380 { 2381 TimeOuts.to_q_return[TOC_NORMAL] = to; 2382 TimeOuts.to_q_return[TOC_URGENT] = to; 2383 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2384 } 2385 else if (strcasecmp(p, "normal") == 0) 2386 TimeOuts.to_q_return[TOC_NORMAL] = to; 2387 else if (strcasecmp(p, "urgent") == 0) 2388 TimeOuts.to_q_return[TOC_URGENT] = to; 2389 else if (strcasecmp(p, "non-urgent") == 0) 2390 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2391 else 2392 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2393 } 2394 else 2395 syserr("settimeout: invalid timeout %s", name); 2396 } 2397