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.72 (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 #define O_SAFEFILEENV 0x89 1328 "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 1329 1330 NULL, '\0', FALSE, 1331 }; 1332 1333 1334 1335 setoption(opt, val, safe, sticky, e) 1336 u_char opt; 1337 char *val; 1338 bool safe; 1339 bool sticky; 1340 register ENVELOPE *e; 1341 { 1342 register char *p; 1343 register struct optioninfo *o; 1344 char *subopt; 1345 extern bool atobool(); 1346 extern time_t convtime(); 1347 extern int QueueLA; 1348 extern int RefuseLA; 1349 extern bool Warn_Q_option; 1350 1351 errno = 0; 1352 if (opt == ' ') 1353 { 1354 /* full word options */ 1355 struct optioninfo *sel; 1356 1357 p = strchr(val, '='); 1358 if (p == NULL) 1359 p = &val[strlen(val)]; 1360 while (*--p == ' ') 1361 continue; 1362 while (*++p == ' ') 1363 *p = '\0'; 1364 if (p == val) 1365 { 1366 syserr("readcf: null option name"); 1367 return; 1368 } 1369 if (*p == '=') 1370 *p++ = '\0'; 1371 while (*p == ' ') 1372 p++; 1373 subopt = strchr(val, '.'); 1374 if (subopt != NULL) 1375 *subopt++ = '\0'; 1376 sel = NULL; 1377 for (o = OptionTab; o->o_name != NULL; o++) 1378 { 1379 if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1380 continue; 1381 if (strlen(o->o_name) == strlen(val)) 1382 { 1383 /* completely specified -- this must be it */ 1384 sel = NULL; 1385 break; 1386 } 1387 if (sel != NULL) 1388 break; 1389 sel = o; 1390 } 1391 if (sel != NULL && o->o_name == NULL) 1392 o = sel; 1393 else if (o->o_name == NULL) 1394 { 1395 syserr("readcf: unknown option name %s", val); 1396 return; 1397 } 1398 else if (sel != NULL) 1399 { 1400 syserr("readcf: ambiguous option name %s (matches %s and %s)", 1401 val, sel->o_name, o->o_name); 1402 return; 1403 } 1404 if (strlen(val) != strlen(o->o_name)) 1405 { 1406 bool oldVerbose = Verbose; 1407 1408 Verbose = TRUE; 1409 message("Option %s used as abbreviation for %s", 1410 val, o->o_name); 1411 Verbose = oldVerbose; 1412 } 1413 opt = o->o_code; 1414 val = p; 1415 } 1416 else 1417 { 1418 for (o = OptionTab; o->o_name != NULL; o++) 1419 { 1420 if (o->o_code == opt) 1421 break; 1422 } 1423 subopt = NULL; 1424 } 1425 1426 if (tTd(37, 1)) 1427 { 1428 printf(isascii(opt) && isprint(opt) ? 1429 "setoption %s (%c).%s=%s" : 1430 "setoption %s (0x%x).%s=%s", 1431 o->o_name == NULL ? "<unknown>" : o->o_name, 1432 opt, 1433 subopt == NULL ? "" : subopt, 1434 val); 1435 } 1436 1437 /* 1438 ** See if this option is preset for us. 1439 */ 1440 1441 if (!sticky && bitnset(opt, StickyOpt)) 1442 { 1443 if (tTd(37, 1)) 1444 printf(" (ignored)\n"); 1445 return; 1446 } 1447 1448 /* 1449 ** Check to see if this option can be specified by this user. 1450 */ 1451 1452 if (!safe && RealUid == 0) 1453 safe = TRUE; 1454 if (!safe && !o->o_safe) 1455 { 1456 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 1457 { 1458 if (tTd(37, 1)) 1459 printf(" (unsafe)"); 1460 if (RealUid != geteuid()) 1461 { 1462 if (tTd(37, 1)) 1463 printf("(Resetting uid)"); 1464 (void) setgid(RealGid); 1465 (void) setuid(RealUid); 1466 } 1467 } 1468 } 1469 if (tTd(37, 1)) 1470 printf("\n"); 1471 1472 switch (opt & 0xff) 1473 { 1474 case '7': /* force seven-bit input */ 1475 SevenBitInput = atobool(val); 1476 break; 1477 1478 case '8': /* handling of 8-bit input */ 1479 switch (*val) 1480 { 1481 case 'r': /* reject 8-bit, don't convert MIME */ 1482 MimeMode = 0; 1483 break; 1484 1485 case 'm': /* convert 8-bit, convert MIME */ 1486 MimeMode = MM_CVTMIME|MM_MIME8BIT; 1487 break; 1488 1489 case 'j': /* "just send 8" */ 1490 MimeMode = MM_PASS8BIT; 1491 break; 1492 1493 case 'p': /* pass 8 bit, convert MIME */ 1494 MimeMode = MM_PASS8BIT|MM_CVTMIME; 1495 break; 1496 1497 case 's': /* strict adherence */ 1498 MimeMode = MM_CVTMIME; 1499 break; 1500 1501 case 'a': /* encode 8 bit if available */ 1502 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1503 break; 1504 1505 case 'c': /* convert 8 bit to MIME, never 7 bit */ 1506 MimeMode = MM_MIME8BIT; 1507 break; 1508 1509 default: 1510 syserr("Unknown 8-bit mode %c", *val); 1511 exit(EX_USAGE); 1512 } 1513 break; 1514 1515 case 'A': /* set default alias file */ 1516 if (val[0] == '\0') 1517 setalias("aliases"); 1518 else 1519 setalias(val); 1520 break; 1521 1522 case 'a': /* look N minutes for "@:@" in alias file */ 1523 if (val[0] == '\0') 1524 SafeAlias = 5 * 60; /* five minutes */ 1525 else 1526 SafeAlias = convtime(val, 'm'); 1527 break; 1528 1529 case 'B': /* substitution for blank character */ 1530 SpaceSub = val[0]; 1531 if (SpaceSub == '\0') 1532 SpaceSub = ' '; 1533 break; 1534 1535 case 'b': /* min blocks free on queue fs/max msg size */ 1536 p = strchr(val, '/'); 1537 if (p != NULL) 1538 { 1539 *p++ = '\0'; 1540 MaxMessageSize = atol(p); 1541 } 1542 MinBlocksFree = atol(val); 1543 break; 1544 1545 case 'c': /* don't connect to "expensive" mailers */ 1546 NoConnect = atobool(val); 1547 break; 1548 1549 case 'C': /* checkpoint every N addresses */ 1550 CheckpointInterval = atoi(val); 1551 break; 1552 1553 case 'd': /* delivery mode */ 1554 switch (*val) 1555 { 1556 case '\0': 1557 e->e_sendmode = SM_DELIVER; 1558 break; 1559 1560 case SM_QUEUE: /* queue only */ 1561 #ifndef QUEUE 1562 syserr("need QUEUE to set -odqueue"); 1563 #endif /* QUEUE */ 1564 /* fall through..... */ 1565 1566 case SM_DELIVER: /* do everything */ 1567 case SM_FORK: /* fork after verification */ 1568 e->e_sendmode = *val; 1569 break; 1570 1571 default: 1572 syserr("Unknown delivery mode %c", *val); 1573 exit(EX_USAGE); 1574 } 1575 break; 1576 1577 case 'D': /* rebuild alias database as needed */ 1578 AutoRebuild = atobool(val); 1579 break; 1580 1581 case 'E': /* error message header/header file */ 1582 if (*val != '\0') 1583 ErrMsgFile = newstr(val); 1584 break; 1585 1586 case 'e': /* set error processing mode */ 1587 switch (*val) 1588 { 1589 case EM_QUIET: /* be silent about it */ 1590 case EM_MAIL: /* mail back */ 1591 case EM_BERKNET: /* do berknet error processing */ 1592 case EM_WRITE: /* write back (or mail) */ 1593 case EM_PRINT: /* print errors normally (default) */ 1594 e->e_errormode = *val; 1595 break; 1596 } 1597 break; 1598 1599 case 'F': /* file mode */ 1600 FileMode = atooct(val) & 0777; 1601 break; 1602 1603 case 'f': /* save Unix-style From lines on front */ 1604 SaveFrom = atobool(val); 1605 break; 1606 1607 case 'G': /* match recipients against GECOS field */ 1608 MatchGecos = atobool(val); 1609 break; 1610 1611 case 'g': /* default gid */ 1612 g_opt: 1613 if (isascii(*val) && isdigit(*val)) 1614 DefGid = atoi(val); 1615 else 1616 { 1617 register struct group *gr; 1618 1619 DefGid = -1; 1620 gr = getgrnam(val); 1621 if (gr == NULL) 1622 syserr("readcf: option %c: unknown group %s", 1623 opt, val); 1624 else 1625 DefGid = gr->gr_gid; 1626 } 1627 break; 1628 1629 case 'H': /* help file */ 1630 if (val[0] == '\0') 1631 HelpFile = "sendmail.hf"; 1632 else 1633 HelpFile = newstr(val); 1634 break; 1635 1636 case 'h': /* maximum hop count */ 1637 MaxHopCount = atoi(val); 1638 break; 1639 1640 case 'I': /* use internet domain name server */ 1641 #if NAMED_BIND 1642 for (p = val; *p != 0; ) 1643 { 1644 bool clearmode; 1645 char *q; 1646 struct resolverflags *rfp; 1647 1648 while (*p == ' ') 1649 p++; 1650 if (*p == '\0') 1651 break; 1652 clearmode = FALSE; 1653 if (*p == '-') 1654 clearmode = TRUE; 1655 else if (*p != '+') 1656 p--; 1657 p++; 1658 q = p; 1659 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1660 p++; 1661 if (*p != '\0') 1662 *p++ = '\0'; 1663 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 1664 { 1665 if (strcasecmp(q, rfp->rf_name) == 0) 1666 break; 1667 } 1668 if (rfp->rf_name == NULL) 1669 syserr("readcf: I option value %s unrecognized", q); 1670 else if (clearmode) 1671 _res.options &= ~rfp->rf_bits; 1672 else 1673 _res.options |= rfp->rf_bits; 1674 } 1675 if (tTd(8, 2)) 1676 printf("_res.options = %x\n", _res.options); 1677 #else 1678 usrerr("name server (I option) specified but BIND not compiled in"); 1679 #endif 1680 break; 1681 1682 case 'i': /* ignore dot lines in message */ 1683 IgnrDot = atobool(val); 1684 break; 1685 1686 case 'j': /* send errors in MIME (RFC 1341) format */ 1687 SendMIMEErrors = atobool(val); 1688 break; 1689 1690 case 'J': /* .forward search path */ 1691 ForwardPath = newstr(val); 1692 break; 1693 1694 case 'k': /* connection cache size */ 1695 MaxMciCache = atoi(val); 1696 if (MaxMciCache < 0) 1697 MaxMciCache = 0; 1698 break; 1699 1700 case 'K': /* connection cache timeout */ 1701 MciCacheTimeout = convtime(val, 'm'); 1702 break; 1703 1704 case 'l': /* use Errors-To: header */ 1705 UseErrorsTo = atobool(val); 1706 break; 1707 1708 case 'L': /* log level */ 1709 if (safe || LogLevel < atoi(val)) 1710 LogLevel = atoi(val); 1711 break; 1712 1713 case 'M': /* define macro */ 1714 p = newstr(&val[1]); 1715 if (!safe) 1716 cleanstrcpy(p, p, MAXNAME); 1717 define(val[0], p, CurEnv); 1718 sticky = FALSE; 1719 break; 1720 1721 case 'm': /* send to me too */ 1722 MeToo = atobool(val); 1723 break; 1724 1725 case 'n': /* validate RHS in newaliases */ 1726 CheckAliases = atobool(val); 1727 break; 1728 1729 /* 'N' available -- was "net name" */ 1730 1731 case 'O': /* daemon options */ 1732 setdaemonoptions(val); 1733 break; 1734 1735 case 'o': /* assume old style headers */ 1736 if (atobool(val)) 1737 CurEnv->e_flags |= EF_OLDSTYLE; 1738 else 1739 CurEnv->e_flags &= ~EF_OLDSTYLE; 1740 break; 1741 1742 case 'p': /* select privacy level */ 1743 p = val; 1744 for (;;) 1745 { 1746 register struct prival *pv; 1747 extern struct prival PrivacyValues[]; 1748 1749 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 1750 p++; 1751 if (*p == '\0') 1752 break; 1753 val = p; 1754 while (isascii(*p) && isalnum(*p)) 1755 p++; 1756 if (*p != '\0') 1757 *p++ = '\0'; 1758 1759 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 1760 { 1761 if (strcasecmp(val, pv->pv_name) == 0) 1762 break; 1763 } 1764 if (pv->pv_name == NULL) 1765 syserr("readcf: Op line: %s unrecognized", val); 1766 PrivacyFlags |= pv->pv_flag; 1767 } 1768 sticky = FALSE; 1769 break; 1770 1771 case 'P': /* postmaster copy address for returned mail */ 1772 PostMasterCopy = newstr(val); 1773 break; 1774 1775 case 'q': /* slope of queue only function */ 1776 QueueFactor = atoi(val); 1777 break; 1778 1779 case 'Q': /* queue directory */ 1780 if (val[0] == '\0') 1781 QueueDir = "mqueue"; 1782 else 1783 QueueDir = newstr(val); 1784 if (RealUid != 0 && !safe) 1785 Warn_Q_option = TRUE; 1786 break; 1787 1788 case 'R': /* don't prune routes */ 1789 DontPruneRoutes = atobool(val); 1790 break; 1791 1792 case 'r': /* read timeout */ 1793 if (subopt == NULL) 1794 inittimeouts(val); 1795 else 1796 settimeout(subopt, val); 1797 break; 1798 1799 case 'S': /* status file */ 1800 if (val[0] == '\0') 1801 StatFile = "sendmail.st"; 1802 else 1803 StatFile = newstr(val); 1804 break; 1805 1806 case 's': /* be super safe, even if expensive */ 1807 SuperSafe = atobool(val); 1808 break; 1809 1810 case 'T': /* queue timeout */ 1811 p = strchr(val, '/'); 1812 if (p != NULL) 1813 { 1814 *p++ = '\0'; 1815 settimeout("queuewarn", p); 1816 } 1817 settimeout("queuereturn", val); 1818 break; 1819 1820 case 't': /* time zone name */ 1821 TimeZoneSpec = newstr(val); 1822 break; 1823 1824 case 'U': /* location of user database */ 1825 UdbSpec = newstr(val); 1826 break; 1827 1828 case 'u': /* set default uid */ 1829 for (p = val; *p != '\0'; p++) 1830 { 1831 if (*p == '.' || *p == '/' || *p == ':') 1832 { 1833 *p++ = '\0'; 1834 break; 1835 } 1836 } 1837 if (isascii(*val) && isdigit(*val)) 1838 DefUid = atoi(val); 1839 else 1840 { 1841 register struct passwd *pw; 1842 1843 DefUid = -1; 1844 pw = getpwnam(val); 1845 if (pw == NULL) 1846 syserr("readcf: option u: unknown user %s", val); 1847 else 1848 { 1849 DefUid = pw->pw_uid; 1850 DefGid = pw->pw_gid; 1851 } 1852 } 1853 setdefuser(); 1854 1855 /* handle the group if it is there */ 1856 if (*p == '\0') 1857 break; 1858 val = p; 1859 goto g_opt; 1860 1861 case 'V': /* fallback MX host */ 1862 FallBackMX = newstr(val); 1863 break; 1864 1865 case 'v': /* run in verbose mode */ 1866 Verbose = atobool(val); 1867 break; 1868 1869 case 'w': /* if we are best MX, try host directly */ 1870 TryNullMXList = atobool(val); 1871 break; 1872 1873 /* 'W' available -- was wizard password */ 1874 1875 case 'x': /* load avg at which to auto-queue msgs */ 1876 QueueLA = atoi(val); 1877 break; 1878 1879 case 'X': /* load avg at which to auto-reject connections */ 1880 RefuseLA = atoi(val); 1881 break; 1882 1883 case 'y': /* work recipient factor */ 1884 WkRecipFact = atoi(val); 1885 break; 1886 1887 case 'Y': /* fork jobs during queue runs */ 1888 ForkQueueRuns = atobool(val); 1889 break; 1890 1891 case 'z': /* work message class factor */ 1892 WkClassFact = atoi(val); 1893 break; 1894 1895 case 'Z': /* work time factor */ 1896 WkTimeFact = atoi(val); 1897 break; 1898 1899 case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 1900 BrokenSmtpPeers = atobool(val); 1901 break; 1902 1903 case O_QUEUESORTORD: /* queue sorting order */ 1904 switch (*val) 1905 { 1906 case 'h': /* Host first */ 1907 case 'H': 1908 QueueSortOrder = QS_BYHOST; 1909 break; 1910 1911 case 'p': /* Priority order */ 1912 case 'P': 1913 QueueSortOrder = QS_BYPRIORITY; 1914 break; 1915 1916 default: 1917 syserr("Invalid queue sort order \"%s\"", val); 1918 } 1919 break; 1920 1921 case O_MQA: /* minimum queue age between deliveries */ 1922 MinQueueAge = convtime(val, 'm'); 1923 break; 1924 1925 case O_MHSA: /* maximum age of cached host status */ 1926 MaxHostStatAge = convtime(val, 'm'); 1927 break; 1928 1929 case O_DEFCHARSET: /* default character set for mimefying */ 1930 DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 1931 break; 1932 1933 case O_SSFILE: /* service switch file */ 1934 ServiceSwitchFile = newstr(val); 1935 break; 1936 1937 case O_DIALDELAY: /* delay for dial-on-demand operation */ 1938 DialDelay = convtime(val, 's'); 1939 break; 1940 1941 case O_NORCPTACTION: /* what to do if no recipient */ 1942 if (strcasecmp(val, "none") == 0) 1943 NoRecipientAction = NRA_NO_ACTION; 1944 else if (strcasecmp(val, "add-to") == 0) 1945 NoRecipientAction = NRA_ADD_TO; 1946 else if (strcasecmp(val, "add-apparently-to") == 0) 1947 NoRecipientAction = NRA_ADD_APPARENTLY_TO; 1948 else if (strcasecmp(val, "add-bcc") == 0) 1949 NoRecipientAction = NRA_ADD_BCC; 1950 else if (strcasecmp(val, "add-to-undisclosed") == 0) 1951 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 1952 else 1953 syserr("Invalid NoRecipientAction: %s", val); 1954 1955 case O_SAFEFILEENV: /* chroot() environ for writing to files */ 1956 SafeFileEnv = newstr(val); 1957 break; 1958 1959 default: 1960 if (tTd(37, 1)) 1961 { 1962 if (isascii(opt) && isprint(opt)) 1963 printf("Warning: option %c unknown\n", opt); 1964 else 1965 printf("Warning: option 0x%x unknown\n", opt); 1966 } 1967 break; 1968 } 1969 if (sticky) 1970 setbitn(opt, StickyOpt); 1971 return; 1972 } 1973 /* 1974 ** SETCLASS -- set a string into a class 1975 ** 1976 ** Parameters: 1977 ** class -- the class to put the string in. 1978 ** str -- the string to enter 1979 ** 1980 ** Returns: 1981 ** none. 1982 ** 1983 ** Side Effects: 1984 ** puts the word into the symbol table. 1985 */ 1986 1987 setclass(class, str) 1988 int class; 1989 char *str; 1990 { 1991 register STAB *s; 1992 1993 if (tTd(37, 8)) 1994 printf("setclass(%c, %s)\n", class, str); 1995 s = stab(str, ST_CLASS, ST_ENTER); 1996 setbitn(class, s->s_class); 1997 } 1998 /* 1999 ** MAKEMAPENTRY -- create a map entry 2000 ** 2001 ** Parameters: 2002 ** line -- the config file line 2003 ** 2004 ** Returns: 2005 ** TRUE if it successfully entered the map entry. 2006 ** FALSE otherwise (usually syntax error). 2007 ** 2008 ** Side Effects: 2009 ** Enters the map into the dictionary. 2010 */ 2011 2012 void 2013 makemapentry(line) 2014 char *line; 2015 { 2016 register char *p; 2017 char *mapname; 2018 char *classname; 2019 register STAB *s; 2020 STAB *class; 2021 2022 for (p = line; isascii(*p) && isspace(*p); p++) 2023 continue; 2024 if (!(isascii(*p) && isalnum(*p))) 2025 { 2026 syserr("readcf: config K line: no map name"); 2027 return; 2028 } 2029 2030 mapname = p; 2031 while ((isascii(*++p) && isalnum(*p)) || *p == '.') 2032 continue; 2033 if (*p != '\0') 2034 *p++ = '\0'; 2035 while (isascii(*p) && isspace(*p)) 2036 p++; 2037 if (!(isascii(*p) && isalnum(*p))) 2038 { 2039 syserr("readcf: config K line, map %s: no map class", mapname); 2040 return; 2041 } 2042 classname = p; 2043 while (isascii(*++p) && isalnum(*p)) 2044 continue; 2045 if (*p != '\0') 2046 *p++ = '\0'; 2047 while (isascii(*p) && isspace(*p)) 2048 p++; 2049 2050 /* look up the class */ 2051 class = stab(classname, ST_MAPCLASS, ST_FIND); 2052 if (class == NULL) 2053 { 2054 syserr("readcf: map %s: class %s not available", mapname, classname); 2055 return; 2056 } 2057 2058 /* enter the map */ 2059 s = stab(mapname, ST_MAP, ST_ENTER); 2060 s->s_map.map_class = &class->s_mapclass; 2061 s->s_map.map_mname = newstr(mapname); 2062 2063 if (class->s_mapclass.map_parse(&s->s_map, p)) 2064 s->s_map.map_mflags |= MF_VALID; 2065 2066 if (tTd(37, 5)) 2067 { 2068 printf("map %s, class %s, flags %x, file %s,\n", 2069 s->s_map.map_mname, s->s_map.map_class->map_cname, 2070 s->s_map.map_mflags, 2071 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 2072 printf("\tapp %s, domain %s, rebuild %s\n", 2073 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 2074 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 2075 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 2076 } 2077 } 2078 /* 2079 ** INITTIMEOUTS -- parse and set timeout values 2080 ** 2081 ** Parameters: 2082 ** val -- a pointer to the values. If NULL, do initial 2083 ** settings. 2084 ** 2085 ** Returns: 2086 ** none. 2087 ** 2088 ** Side Effects: 2089 ** Initializes the TimeOuts structure 2090 */ 2091 2092 #define SECONDS 2093 #define MINUTES * 60 2094 #define HOUR * 3600 2095 2096 inittimeouts(val) 2097 register char *val; 2098 { 2099 register char *p; 2100 extern time_t convtime(); 2101 2102 if (val == NULL) 2103 { 2104 TimeOuts.to_initial = (time_t) 5 MINUTES; 2105 TimeOuts.to_helo = (time_t) 5 MINUTES; 2106 TimeOuts.to_mail = (time_t) 10 MINUTES; 2107 TimeOuts.to_rcpt = (time_t) 1 HOUR; 2108 TimeOuts.to_datainit = (time_t) 5 MINUTES; 2109 TimeOuts.to_datablock = (time_t) 1 HOUR; 2110 TimeOuts.to_datafinal = (time_t) 1 HOUR; 2111 TimeOuts.to_rset = (time_t) 5 MINUTES; 2112 TimeOuts.to_quit = (time_t) 2 MINUTES; 2113 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 2114 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2115 #if IDENTPROTO 2116 TimeOuts.to_ident = (time_t) 30 SECONDS; 2117 #else 2118 TimeOuts.to_ident = (time_t) 0 SECONDS; 2119 #endif 2120 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 2121 return; 2122 } 2123 2124 for (;; val = p) 2125 { 2126 while (isascii(*val) && isspace(*val)) 2127 val++; 2128 if (*val == '\0') 2129 break; 2130 for (p = val; *p != '\0' && *p != ','; p++) 2131 continue; 2132 if (*p != '\0') 2133 *p++ = '\0'; 2134 2135 if (isascii(*val) && isdigit(*val)) 2136 { 2137 /* old syntax -- set everything */ 2138 TimeOuts.to_mail = convtime(val, 'm'); 2139 TimeOuts.to_rcpt = TimeOuts.to_mail; 2140 TimeOuts.to_datainit = TimeOuts.to_mail; 2141 TimeOuts.to_datablock = TimeOuts.to_mail; 2142 TimeOuts.to_datafinal = TimeOuts.to_mail; 2143 TimeOuts.to_nextcommand = TimeOuts.to_mail; 2144 continue; 2145 } 2146 else 2147 { 2148 register char *q = strchr(val, ':'); 2149 2150 if (q == NULL && (q = strchr(val, '=')) == NULL) 2151 { 2152 /* syntax error */ 2153 continue; 2154 } 2155 *q++ = '\0'; 2156 settimeout(val, q); 2157 } 2158 } 2159 } 2160 /* 2161 ** SETTIMEOUT -- set an individual timeout 2162 ** 2163 ** Parameters: 2164 ** name -- the name of the timeout. 2165 ** val -- the value of the timeout. 2166 ** 2167 ** Returns: 2168 ** none. 2169 */ 2170 2171 settimeout(name, val) 2172 char *name; 2173 char *val; 2174 { 2175 register char *p; 2176 time_t to; 2177 extern time_t convtime(); 2178 2179 to = convtime(val, 'm'); 2180 p = strchr(name, '.'); 2181 if (p != NULL) 2182 *p++ = '\0'; 2183 2184 if (strcasecmp(name, "initial") == 0) 2185 TimeOuts.to_initial = to; 2186 else if (strcasecmp(name, "mail") == 0) 2187 TimeOuts.to_mail = to; 2188 else if (strcasecmp(name, "rcpt") == 0) 2189 TimeOuts.to_rcpt = to; 2190 else if (strcasecmp(name, "datainit") == 0) 2191 TimeOuts.to_datainit = to; 2192 else if (strcasecmp(name, "datablock") == 0) 2193 TimeOuts.to_datablock = to; 2194 else if (strcasecmp(name, "datafinal") == 0) 2195 TimeOuts.to_datafinal = to; 2196 else if (strcasecmp(name, "command") == 0) 2197 TimeOuts.to_nextcommand = to; 2198 else if (strcasecmp(name, "rset") == 0) 2199 TimeOuts.to_rset = to; 2200 else if (strcasecmp(name, "helo") == 0) 2201 TimeOuts.to_helo = to; 2202 else if (strcasecmp(name, "quit") == 0) 2203 TimeOuts.to_quit = to; 2204 else if (strcasecmp(name, "misc") == 0) 2205 TimeOuts.to_miscshort = to; 2206 else if (strcasecmp(name, "ident") == 0) 2207 TimeOuts.to_ident = to; 2208 else if (strcasecmp(name, "fileopen") == 0) 2209 TimeOuts.to_fileopen = to; 2210 else if (strcasecmp(name, "queuewarn") == 0) 2211 { 2212 to = convtime(val, 'h'); 2213 if (p == NULL || strcmp(p, "*") == 0) 2214 { 2215 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2216 TimeOuts.to_q_warning[TOC_URGENT] = to; 2217 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2218 } 2219 else if (strcasecmp(p, "normal") == 0) 2220 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2221 else if (strcasecmp(p, "urgent") == 0) 2222 TimeOuts.to_q_warning[TOC_URGENT] = to; 2223 else if (strcasecmp(p, "non-urgent") == 0) 2224 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2225 else 2226 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2227 } 2228 else if (strcasecmp(name, "queuereturn") == 0) 2229 { 2230 to = convtime(val, 'd'); 2231 if (p == NULL || strcmp(p, "*") == 0) 2232 { 2233 TimeOuts.to_q_return[TOC_NORMAL] = to; 2234 TimeOuts.to_q_return[TOC_URGENT] = to; 2235 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2236 } 2237 else if (strcasecmp(p, "normal") == 0) 2238 TimeOuts.to_q_return[TOC_NORMAL] = to; 2239 else if (strcasecmp(p, "urgent") == 0) 2240 TimeOuts.to_q_return[TOC_URGENT] = to; 2241 else if (strcasecmp(p, "non-urgent") == 0) 2242 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2243 else 2244 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2245 } 2246 else 2247 syserr("settimeout: invalid timeout %s", name); 2248 } 2249