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