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