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