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