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