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