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.71 (Berkeley) 03/05/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 sticky = FALSE; 1767 break; 1768 1769 case 'P': /* postmaster copy address for returned mail */ 1770 PostMasterCopy = newstr(val); 1771 break; 1772 1773 case 'q': /* slope of queue only function */ 1774 QueueFactor = atoi(val); 1775 break; 1776 1777 case 'Q': /* queue directory */ 1778 if (val[0] == '\0') 1779 QueueDir = "mqueue"; 1780 else 1781 QueueDir = newstr(val); 1782 if (RealUid != 0 && !safe) 1783 Warn_Q_option = TRUE; 1784 break; 1785 1786 case 'R': /* don't prune routes */ 1787 DontPruneRoutes = atobool(val); 1788 break; 1789 1790 case 'r': /* read timeout */ 1791 if (subopt == NULL) 1792 inittimeouts(val); 1793 else 1794 settimeout(subopt, val); 1795 break; 1796 1797 case 'S': /* status file */ 1798 if (val[0] == '\0') 1799 StatFile = "sendmail.st"; 1800 else 1801 StatFile = newstr(val); 1802 break; 1803 1804 case 's': /* be super safe, even if expensive */ 1805 SuperSafe = atobool(val); 1806 break; 1807 1808 case 'T': /* queue timeout */ 1809 p = strchr(val, '/'); 1810 if (p != NULL) 1811 { 1812 *p++ = '\0'; 1813 settimeout("queuewarn", p); 1814 } 1815 settimeout("queuereturn", val); 1816 break; 1817 1818 case 't': /* time zone name */ 1819 TimeZoneSpec = newstr(val); 1820 break; 1821 1822 case 'U': /* location of user database */ 1823 UdbSpec = newstr(val); 1824 break; 1825 1826 case 'u': /* set default uid */ 1827 for (p = val; *p != '\0'; p++) 1828 { 1829 if (*p == '.' || *p == '/' || *p == ':') 1830 { 1831 *p++ = '\0'; 1832 break; 1833 } 1834 } 1835 if (isascii(*val) && isdigit(*val)) 1836 DefUid = atoi(val); 1837 else 1838 { 1839 register struct passwd *pw; 1840 1841 DefUid = -1; 1842 pw = getpwnam(val); 1843 if (pw == NULL) 1844 syserr("readcf: option u: unknown user %s", val); 1845 else 1846 { 1847 DefUid = pw->pw_uid; 1848 DefGid = pw->pw_gid; 1849 } 1850 } 1851 setdefuser(); 1852 1853 /* handle the group if it is there */ 1854 if (*p == '\0') 1855 break; 1856 val = p; 1857 goto g_opt; 1858 1859 case 'V': /* fallback MX host */ 1860 FallBackMX = newstr(val); 1861 break; 1862 1863 case 'v': /* run in verbose mode */ 1864 Verbose = atobool(val); 1865 break; 1866 1867 case 'w': /* if we are best MX, try host directly */ 1868 TryNullMXList = atobool(val); 1869 break; 1870 1871 /* 'W' available -- was wizard password */ 1872 1873 case 'x': /* load avg at which to auto-queue msgs */ 1874 QueueLA = atoi(val); 1875 break; 1876 1877 case 'X': /* load avg at which to auto-reject connections */ 1878 RefuseLA = atoi(val); 1879 break; 1880 1881 case 'y': /* work recipient factor */ 1882 WkRecipFact = atoi(val); 1883 break; 1884 1885 case 'Y': /* fork jobs during queue runs */ 1886 ForkQueueRuns = atobool(val); 1887 break; 1888 1889 case 'z': /* work message class factor */ 1890 WkClassFact = atoi(val); 1891 break; 1892 1893 case 'Z': /* work time factor */ 1894 WkTimeFact = atoi(val); 1895 break; 1896 1897 case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 1898 BrokenSmtpPeers = atobool(val); 1899 break; 1900 1901 case O_QUEUESORTORD: /* queue sorting order */ 1902 switch (*val) 1903 { 1904 case 'h': /* Host first */ 1905 case 'H': 1906 QueueSortOrder = QS_BYHOST; 1907 break; 1908 1909 case 'p': /* Priority order */ 1910 case 'P': 1911 QueueSortOrder = QS_BYPRIORITY; 1912 break; 1913 1914 default: 1915 syserr("Invalid queue sort order \"%s\"", val); 1916 } 1917 break; 1918 1919 case O_MQA: /* minimum queue age between deliveries */ 1920 MinQueueAge = convtime(val, 'm'); 1921 break; 1922 1923 case O_MHSA: /* maximum age of cached host status */ 1924 MaxHostStatAge = convtime(val, 'm'); 1925 break; 1926 1927 case O_DEFCHARSET: /* default character set for mimefying */ 1928 DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 1929 break; 1930 1931 case O_SSFILE: /* service switch file */ 1932 ServiceSwitchFile = newstr(val); 1933 break; 1934 1935 case O_DIALDELAY: /* delay for dial-on-demand operation */ 1936 DialDelay = convtime(val, 's'); 1937 break; 1938 1939 case O_NORCPTACTION: /* what to do if no recipient */ 1940 if (strcasecmp(val, "none") == 0) 1941 NoRecipientAction = NRA_NO_ACTION; 1942 else if (strcasecmp(val, "add-to") == 0) 1943 NoRecipientAction = NRA_ADD_TO; 1944 else if (strcasecmp(val, "add-apparently-to") == 0) 1945 NoRecipientAction = NRA_ADD_APPARENTLY_TO; 1946 else if (strcasecmp(val, "add-bcc") == 0) 1947 NoRecipientAction = NRA_ADD_BCC; 1948 else if (strcasecmp(val, "add-to-undisclosed") == 0) 1949 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 1950 else 1951 syserr("Invalid NoRecipientAction: %s", val); 1952 1953 default: 1954 if (tTd(37, 1)) 1955 { 1956 if (isascii(opt) && isprint(opt)) 1957 printf("Warning: option %c unknown\n", opt); 1958 else 1959 printf("Warning: option 0x%x unknown\n", opt); 1960 } 1961 break; 1962 } 1963 if (sticky) 1964 setbitn(opt, StickyOpt); 1965 return; 1966 } 1967 /* 1968 ** SETCLASS -- set a string into a class 1969 ** 1970 ** Parameters: 1971 ** class -- the class to put the string in. 1972 ** str -- the string to enter 1973 ** 1974 ** Returns: 1975 ** none. 1976 ** 1977 ** Side Effects: 1978 ** puts the word into the symbol table. 1979 */ 1980 1981 setclass(class, str) 1982 int class; 1983 char *str; 1984 { 1985 register STAB *s; 1986 1987 if (tTd(37, 8)) 1988 printf("setclass(%c, %s)\n", class, str); 1989 s = stab(str, ST_CLASS, ST_ENTER); 1990 setbitn(class, s->s_class); 1991 } 1992 /* 1993 ** MAKEMAPENTRY -- create a map entry 1994 ** 1995 ** Parameters: 1996 ** line -- the config file line 1997 ** 1998 ** Returns: 1999 ** TRUE if it successfully entered the map entry. 2000 ** FALSE otherwise (usually syntax error). 2001 ** 2002 ** Side Effects: 2003 ** Enters the map into the dictionary. 2004 */ 2005 2006 void 2007 makemapentry(line) 2008 char *line; 2009 { 2010 register char *p; 2011 char *mapname; 2012 char *classname; 2013 register STAB *s; 2014 STAB *class; 2015 2016 for (p = line; isascii(*p) && isspace(*p); p++) 2017 continue; 2018 if (!(isascii(*p) && isalnum(*p))) 2019 { 2020 syserr("readcf: config K line: no map name"); 2021 return; 2022 } 2023 2024 mapname = p; 2025 while ((isascii(*++p) && isalnum(*p)) || *p == '.') 2026 continue; 2027 if (*p != '\0') 2028 *p++ = '\0'; 2029 while (isascii(*p) && isspace(*p)) 2030 p++; 2031 if (!(isascii(*p) && isalnum(*p))) 2032 { 2033 syserr("readcf: config K line, map %s: no map class", mapname); 2034 return; 2035 } 2036 classname = p; 2037 while (isascii(*++p) && isalnum(*p)) 2038 continue; 2039 if (*p != '\0') 2040 *p++ = '\0'; 2041 while (isascii(*p) && isspace(*p)) 2042 p++; 2043 2044 /* look up the class */ 2045 class = stab(classname, ST_MAPCLASS, ST_FIND); 2046 if (class == NULL) 2047 { 2048 syserr("readcf: map %s: class %s not available", mapname, classname); 2049 return; 2050 } 2051 2052 /* enter the map */ 2053 s = stab(mapname, ST_MAP, ST_ENTER); 2054 s->s_map.map_class = &class->s_mapclass; 2055 s->s_map.map_mname = newstr(mapname); 2056 2057 if (class->s_mapclass.map_parse(&s->s_map, p)) 2058 s->s_map.map_mflags |= MF_VALID; 2059 2060 if (tTd(37, 5)) 2061 { 2062 printf("map %s, class %s, flags %x, file %s,\n", 2063 s->s_map.map_mname, s->s_map.map_class->map_cname, 2064 s->s_map.map_mflags, 2065 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 2066 printf("\tapp %s, domain %s, rebuild %s\n", 2067 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 2068 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 2069 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 2070 } 2071 } 2072 /* 2073 ** INITTIMEOUTS -- parse and set timeout values 2074 ** 2075 ** Parameters: 2076 ** val -- a pointer to the values. If NULL, do initial 2077 ** settings. 2078 ** 2079 ** Returns: 2080 ** none. 2081 ** 2082 ** Side Effects: 2083 ** Initializes the TimeOuts structure 2084 */ 2085 2086 #define SECONDS 2087 #define MINUTES * 60 2088 #define HOUR * 3600 2089 2090 inittimeouts(val) 2091 register char *val; 2092 { 2093 register char *p; 2094 extern time_t convtime(); 2095 2096 if (val == NULL) 2097 { 2098 TimeOuts.to_initial = (time_t) 5 MINUTES; 2099 TimeOuts.to_helo = (time_t) 5 MINUTES; 2100 TimeOuts.to_mail = (time_t) 10 MINUTES; 2101 TimeOuts.to_rcpt = (time_t) 1 HOUR; 2102 TimeOuts.to_datainit = (time_t) 5 MINUTES; 2103 TimeOuts.to_datablock = (time_t) 1 HOUR; 2104 TimeOuts.to_datafinal = (time_t) 1 HOUR; 2105 TimeOuts.to_rset = (time_t) 5 MINUTES; 2106 TimeOuts.to_quit = (time_t) 2 MINUTES; 2107 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 2108 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2109 #if IDENTPROTO 2110 TimeOuts.to_ident = (time_t) 30 SECONDS; 2111 #else 2112 TimeOuts.to_ident = (time_t) 0 SECONDS; 2113 #endif 2114 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 2115 return; 2116 } 2117 2118 for (;; val = p) 2119 { 2120 while (isascii(*val) && isspace(*val)) 2121 val++; 2122 if (*val == '\0') 2123 break; 2124 for (p = val; *p != '\0' && *p != ','; p++) 2125 continue; 2126 if (*p != '\0') 2127 *p++ = '\0'; 2128 2129 if (isascii(*val) && isdigit(*val)) 2130 { 2131 /* old syntax -- set everything */ 2132 TimeOuts.to_mail = convtime(val, 'm'); 2133 TimeOuts.to_rcpt = TimeOuts.to_mail; 2134 TimeOuts.to_datainit = TimeOuts.to_mail; 2135 TimeOuts.to_datablock = TimeOuts.to_mail; 2136 TimeOuts.to_datafinal = TimeOuts.to_mail; 2137 TimeOuts.to_nextcommand = TimeOuts.to_mail; 2138 continue; 2139 } 2140 else 2141 { 2142 register char *q = strchr(val, ':'); 2143 2144 if (q == NULL && (q = strchr(val, '=')) == NULL) 2145 { 2146 /* syntax error */ 2147 continue; 2148 } 2149 *q++ = '\0'; 2150 settimeout(val, q); 2151 } 2152 } 2153 } 2154 /* 2155 ** SETTIMEOUT -- set an individual timeout 2156 ** 2157 ** Parameters: 2158 ** name -- the name of the timeout. 2159 ** val -- the value of the timeout. 2160 ** 2161 ** Returns: 2162 ** none. 2163 */ 2164 2165 settimeout(name, val) 2166 char *name; 2167 char *val; 2168 { 2169 register char *p; 2170 time_t to; 2171 extern time_t convtime(); 2172 2173 to = convtime(val, 'm'); 2174 p = strchr(name, '.'); 2175 if (p != NULL) 2176 *p++ = '\0'; 2177 2178 if (strcasecmp(name, "initial") == 0) 2179 TimeOuts.to_initial = to; 2180 else if (strcasecmp(name, "mail") == 0) 2181 TimeOuts.to_mail = to; 2182 else if (strcasecmp(name, "rcpt") == 0) 2183 TimeOuts.to_rcpt = to; 2184 else if (strcasecmp(name, "datainit") == 0) 2185 TimeOuts.to_datainit = to; 2186 else if (strcasecmp(name, "datablock") == 0) 2187 TimeOuts.to_datablock = to; 2188 else if (strcasecmp(name, "datafinal") == 0) 2189 TimeOuts.to_datafinal = to; 2190 else if (strcasecmp(name, "command") == 0) 2191 TimeOuts.to_nextcommand = to; 2192 else if (strcasecmp(name, "rset") == 0) 2193 TimeOuts.to_rset = to; 2194 else if (strcasecmp(name, "helo") == 0) 2195 TimeOuts.to_helo = to; 2196 else if (strcasecmp(name, "quit") == 0) 2197 TimeOuts.to_quit = to; 2198 else if (strcasecmp(name, "misc") == 0) 2199 TimeOuts.to_miscshort = to; 2200 else if (strcasecmp(name, "ident") == 0) 2201 TimeOuts.to_ident = to; 2202 else if (strcasecmp(name, "fileopen") == 0) 2203 TimeOuts.to_fileopen = to; 2204 else if (strcasecmp(name, "queuewarn") == 0) 2205 { 2206 to = convtime(val, 'h'); 2207 if (p == NULL || strcmp(p, "*") == 0) 2208 { 2209 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2210 TimeOuts.to_q_warning[TOC_URGENT] = to; 2211 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2212 } 2213 else if (strcasecmp(p, "normal") == 0) 2214 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2215 else if (strcasecmp(p, "urgent") == 0) 2216 TimeOuts.to_q_warning[TOC_URGENT] = to; 2217 else if (strcasecmp(p, "non-urgent") == 0) 2218 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2219 else 2220 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2221 } 2222 else if (strcasecmp(name, "queuereturn") == 0) 2223 { 2224 to = convtime(val, 'd'); 2225 if (p == NULL || strcmp(p, "*") == 0) 2226 { 2227 TimeOuts.to_q_return[TOC_NORMAL] = to; 2228 TimeOuts.to_q_return[TOC_URGENT] = to; 2229 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2230 } 2231 else if (strcasecmp(p, "normal") == 0) 2232 TimeOuts.to_q_return[TOC_NORMAL] = to; 2233 else if (strcasecmp(p, "urgent") == 0) 2234 TimeOuts.to_q_return[TOC_URGENT] = to; 2235 else if (strcasecmp(p, "non-urgent") == 0) 2236 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2237 else 2238 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2239 } 2240 else 2241 syserr("settimeout: invalid timeout %s", name); 2242 } 2243