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