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