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