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.75 (Berkeley) 03/21/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, 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, 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, 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 int sff; 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 sff = SFF_REGONLY; 674 if (safe) 675 sff |= SFF_OPENASROOT; 676 f = safefopen(filename, O_RDONLY, 0, sff); 677 if (f == NULL && !optional) 678 { 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 = 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 = 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