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