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