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