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.101 (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 #define O_KEEPCNAMES 0x8e 1329 "DontExpandCnames", O_KEEPCNAMES, FALSE, 1330 1331 NULL, '\0', FALSE, 1332 }; 1333 1334 1335 1336 void 1337 setoption(opt, val, safe, sticky, e) 1338 int opt; 1339 char *val; 1340 bool safe; 1341 bool sticky; 1342 register ENVELOPE *e; 1343 { 1344 register char *p; 1345 register struct optioninfo *o; 1346 char *subopt; 1347 extern bool atobool(); 1348 extern time_t convtime(); 1349 extern int QueueLA; 1350 extern int RefuseLA; 1351 extern bool Warn_Q_option; 1352 1353 errno = 0; 1354 if (opt == ' ') 1355 { 1356 /* full word options */ 1357 struct optioninfo *sel; 1358 1359 p = strchr(val, '='); 1360 if (p == NULL) 1361 p = &val[strlen(val)]; 1362 while (*--p == ' ') 1363 continue; 1364 while (*++p == ' ') 1365 *p = '\0'; 1366 if (p == val) 1367 { 1368 syserr("readcf: null option name"); 1369 return; 1370 } 1371 if (*p == '=') 1372 *p++ = '\0'; 1373 while (*p == ' ') 1374 p++; 1375 subopt = strchr(val, '.'); 1376 if (subopt != NULL) 1377 *subopt++ = '\0'; 1378 sel = NULL; 1379 for (o = OptionTab; o->o_name != NULL; o++) 1380 { 1381 if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1382 continue; 1383 if (strlen(o->o_name) == strlen(val)) 1384 { 1385 /* completely specified -- this must be it */ 1386 sel = NULL; 1387 break; 1388 } 1389 if (sel != NULL) 1390 break; 1391 sel = o; 1392 } 1393 if (sel != NULL && o->o_name == NULL) 1394 o = sel; 1395 else if (o->o_name == NULL) 1396 { 1397 syserr("readcf: unknown option name %s", val); 1398 return; 1399 } 1400 else if (sel != NULL) 1401 { 1402 syserr("readcf: ambiguous option name %s (matches %s and %s)", 1403 val, sel->o_name, o->o_name); 1404 return; 1405 } 1406 if (strlen(val) != strlen(o->o_name)) 1407 { 1408 bool oldVerbose = Verbose; 1409 1410 Verbose = TRUE; 1411 message("Option %s used as abbreviation for %s", 1412 val, o->o_name); 1413 Verbose = oldVerbose; 1414 } 1415 opt = o->o_code; 1416 val = p; 1417 } 1418 else 1419 { 1420 for (o = OptionTab; o->o_name != NULL; o++) 1421 { 1422 if (o->o_code == opt) 1423 break; 1424 } 1425 subopt = NULL; 1426 } 1427 1428 if (tTd(37, 1)) 1429 { 1430 printf(isascii(opt) && isprint(opt) ? 1431 "setoption %s (%c).%s=%s" : 1432 "setoption %s (0x%x).%s=%s", 1433 o->o_name == NULL ? "<unknown>" : o->o_name, 1434 opt, 1435 subopt == NULL ? "" : subopt, 1436 val); 1437 } 1438 1439 /* 1440 ** See if this option is preset for us. 1441 */ 1442 1443 if (!sticky && bitnset(opt, StickyOpt)) 1444 { 1445 if (tTd(37, 1)) 1446 printf(" (ignored)\n"); 1447 return; 1448 } 1449 1450 /* 1451 ** Check to see if this option can be specified by this user. 1452 */ 1453 1454 if (!safe && RealUid == 0) 1455 safe = TRUE; 1456 if (!safe && !o->o_safe) 1457 { 1458 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 1459 { 1460 if (tTd(37, 1)) 1461 printf(" (unsafe)"); 1462 if (RealUid != geteuid()) 1463 { 1464 if (tTd(37, 1)) 1465 printf("(Resetting uid)"); 1466 (void) setgid(RealGid); 1467 (void) setuid(RealUid); 1468 } 1469 } 1470 } 1471 if (tTd(37, 1)) 1472 printf("\n"); 1473 1474 switch (opt & 0xff) 1475 { 1476 case '7': /* force seven-bit input */ 1477 SevenBitInput = atobool(val); 1478 break; 1479 1480 #if MIME8TO7 1481 case '8': /* handling of 8-bit input */ 1482 switch (*val) 1483 { 1484 case 'm': /* convert 8-bit, convert MIME */ 1485 MimeMode = MM_CVTMIME|MM_MIME8BIT; 1486 break; 1487 1488 case 'p': /* pass 8 bit, convert MIME */ 1489 MimeMode = MM_CVTMIME|MM_PASS8BIT; 1490 break; 1491 1492 case 's': /* strict adherence */ 1493 MimeMode = MM_CVTMIME; 1494 break; 1495 1496 #if 0 1497 case 'r': /* reject 8-bit, don't convert MIME */ 1498 MimeMode = 0; 1499 break; 1500 1501 case 'j': /* "just send 8" */ 1502 MimeMode = MM_PASS8BIT; 1503 break; 1504 1505 case 'a': /* encode 8 bit if available */ 1506 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1507 break; 1508 1509 case 'c': /* convert 8 bit to MIME, never 7 bit */ 1510 MimeMode = MM_MIME8BIT; 1511 break; 1512 #endif 1513 1514 default: 1515 syserr("Unknown 8-bit mode %c", *val); 1516 exit(EX_USAGE); 1517 } 1518 break; 1519 #endif 1520 1521 case 'A': /* set default alias file */ 1522 if (val[0] == '\0') 1523 setalias("aliases"); 1524 else 1525 setalias(val); 1526 break; 1527 1528 case 'a': /* look N minutes for "@:@" in alias file */ 1529 if (val[0] == '\0') 1530 SafeAlias = 5 * 60; /* five minutes */ 1531 else 1532 SafeAlias = convtime(val, 'm'); 1533 break; 1534 1535 case 'B': /* substitution for blank character */ 1536 SpaceSub = val[0]; 1537 if (SpaceSub == '\0') 1538 SpaceSub = ' '; 1539 break; 1540 1541 case 'b': /* min blocks free on queue fs/max msg size */ 1542 p = strchr(val, '/'); 1543 if (p != NULL) 1544 { 1545 *p++ = '\0'; 1546 MaxMessageSize = atol(p); 1547 } 1548 MinBlocksFree = atol(val); 1549 break; 1550 1551 case 'c': /* don't connect to "expensive" mailers */ 1552 NoConnect = atobool(val); 1553 break; 1554 1555 case 'C': /* checkpoint every N addresses */ 1556 CheckpointInterval = atoi(val); 1557 break; 1558 1559 case 'd': /* delivery mode */ 1560 switch (*val) 1561 { 1562 case '\0': 1563 e->e_sendmode = SM_DELIVER; 1564 break; 1565 1566 case SM_QUEUE: /* queue only */ 1567 #ifndef QUEUE 1568 syserr("need QUEUE to set -odqueue"); 1569 #endif /* QUEUE */ 1570 /* fall through..... */ 1571 1572 case SM_DELIVER: /* do everything */ 1573 case SM_FORK: /* fork after verification */ 1574 e->e_sendmode = *val; 1575 break; 1576 1577 default: 1578 syserr("Unknown delivery mode %c", *val); 1579 exit(EX_USAGE); 1580 } 1581 break; 1582 1583 case 'D': /* rebuild alias database as needed */ 1584 AutoRebuild = atobool(val); 1585 break; 1586 1587 case 'E': /* error message header/header file */ 1588 if (*val != '\0') 1589 ErrMsgFile = newstr(val); 1590 break; 1591 1592 case 'e': /* set error processing mode */ 1593 switch (*val) 1594 { 1595 case EM_QUIET: /* be silent about it */ 1596 case EM_MAIL: /* mail back */ 1597 case EM_BERKNET: /* do berknet error processing */ 1598 case EM_WRITE: /* write back (or mail) */ 1599 case EM_PRINT: /* print errors normally (default) */ 1600 e->e_errormode = *val; 1601 break; 1602 } 1603 break; 1604 1605 case 'F': /* file mode */ 1606 FileMode = atooct(val) & 0777; 1607 break; 1608 1609 case 'f': /* save Unix-style From lines on front */ 1610 SaveFrom = atobool(val); 1611 break; 1612 1613 case 'G': /* match recipients against GECOS field */ 1614 MatchGecos = atobool(val); 1615 break; 1616 1617 case 'g': /* default gid */ 1618 g_opt: 1619 if (isascii(*val) && isdigit(*val)) 1620 DefGid = atoi(val); 1621 else 1622 { 1623 register struct group *gr; 1624 1625 DefGid = -1; 1626 gr = getgrnam(val); 1627 if (gr == NULL) 1628 syserr("readcf: option %c: unknown group %s", 1629 opt, val); 1630 else 1631 DefGid = gr->gr_gid; 1632 } 1633 break; 1634 1635 case 'H': /* help file */ 1636 if (val[0] == '\0') 1637 HelpFile = "sendmail.hf"; 1638 else 1639 HelpFile = newstr(val); 1640 break; 1641 1642 case 'h': /* maximum hop count */ 1643 MaxHopCount = atoi(val); 1644 break; 1645 1646 case 'I': /* use internet domain name server */ 1647 #if NAMED_BIND 1648 for (p = val; *p != 0; ) 1649 { 1650 bool clearmode; 1651 char *q; 1652 struct resolverflags *rfp; 1653 1654 while (*p == ' ') 1655 p++; 1656 if (*p == '\0') 1657 break; 1658 clearmode = FALSE; 1659 if (*p == '-') 1660 clearmode = TRUE; 1661 else if (*p != '+') 1662 p--; 1663 p++; 1664 q = p; 1665 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1666 p++; 1667 if (*p != '\0') 1668 *p++ = '\0'; 1669 if (strcasecmp(q, "HasWildcardMX") == 0) 1670 { 1671 NoMXforCanon = !clearmode; 1672 continue; 1673 } 1674 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 1675 { 1676 if (strcasecmp(q, rfp->rf_name) == 0) 1677 break; 1678 } 1679 if (rfp->rf_name == NULL) 1680 syserr("readcf: I option value %s unrecognized", q); 1681 else if (clearmode) 1682 _res.options &= ~rfp->rf_bits; 1683 else 1684 _res.options |= rfp->rf_bits; 1685 } 1686 if (tTd(8, 2)) 1687 printf("_res.options = %x, HasWildcardMX = %d\n", 1688 _res.options, !NoMXforCanon); 1689 #else 1690 usrerr("name server (I option) specified but BIND not compiled in"); 1691 #endif 1692 break; 1693 1694 case 'i': /* ignore dot lines in message */ 1695 IgnrDot = atobool(val); 1696 break; 1697 1698 case 'j': /* send errors in MIME (RFC 1341) format */ 1699 SendMIMEErrors = atobool(val); 1700 break; 1701 1702 case 'J': /* .forward search path */ 1703 ForwardPath = newstr(val); 1704 break; 1705 1706 case 'k': /* connection cache size */ 1707 MaxMciCache = atoi(val); 1708 if (MaxMciCache < 0) 1709 MaxMciCache = 0; 1710 break; 1711 1712 case 'K': /* connection cache timeout */ 1713 MciCacheTimeout = convtime(val, 'm'); 1714 break; 1715 1716 case 'l': /* use Errors-To: header */ 1717 UseErrorsTo = atobool(val); 1718 break; 1719 1720 case 'L': /* log level */ 1721 if (safe || LogLevel < atoi(val)) 1722 LogLevel = atoi(val); 1723 break; 1724 1725 case 'M': /* define macro */ 1726 p = newstr(&val[1]); 1727 if (!safe) 1728 cleanstrcpy(p, p, MAXNAME); 1729 define(val[0], p, CurEnv); 1730 sticky = FALSE; 1731 break; 1732 1733 case 'm': /* send to me too */ 1734 MeToo = atobool(val); 1735 break; 1736 1737 case 'n': /* validate RHS in newaliases */ 1738 CheckAliases = atobool(val); 1739 break; 1740 1741 /* 'N' available -- was "net name" */ 1742 1743 case 'O': /* daemon options */ 1744 setdaemonoptions(val); 1745 break; 1746 1747 case 'o': /* assume old style headers */ 1748 if (atobool(val)) 1749 CurEnv->e_flags |= EF_OLDSTYLE; 1750 else 1751 CurEnv->e_flags &= ~EF_OLDSTYLE; 1752 break; 1753 1754 case 'p': /* select privacy level */ 1755 p = val; 1756 for (;;) 1757 { 1758 register struct prival *pv; 1759 extern struct prival PrivacyValues[]; 1760 1761 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 1762 p++; 1763 if (*p == '\0') 1764 break; 1765 val = p; 1766 while (isascii(*p) && isalnum(*p)) 1767 p++; 1768 if (*p != '\0') 1769 *p++ = '\0'; 1770 1771 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 1772 { 1773 if (strcasecmp(val, pv->pv_name) == 0) 1774 break; 1775 } 1776 if (pv->pv_name == NULL) 1777 syserr("readcf: Op line: %s unrecognized", val); 1778 PrivacyFlags |= pv->pv_flag; 1779 } 1780 sticky = FALSE; 1781 break; 1782 1783 case 'P': /* postmaster copy address for returned mail */ 1784 PostMasterCopy = newstr(val); 1785 break; 1786 1787 case 'q': /* slope of queue only function */ 1788 QueueFactor = atoi(val); 1789 break; 1790 1791 case 'Q': /* queue directory */ 1792 if (val[0] == '\0') 1793 QueueDir = "mqueue"; 1794 else 1795 QueueDir = newstr(val); 1796 if (RealUid != 0 && !safe) 1797 Warn_Q_option = TRUE; 1798 break; 1799 1800 case 'R': /* don't prune routes */ 1801 DontPruneRoutes = atobool(val); 1802 break; 1803 1804 case 'r': /* read timeout */ 1805 if (subopt == NULL) 1806 inittimeouts(val); 1807 else 1808 settimeout(subopt, val); 1809 break; 1810 1811 case 'S': /* status file */ 1812 if (val[0] == '\0') 1813 StatFile = "sendmail.st"; 1814 else 1815 StatFile = newstr(val); 1816 break; 1817 1818 case 's': /* be super safe, even if expensive */ 1819 SuperSafe = atobool(val); 1820 break; 1821 1822 case 'T': /* queue timeout */ 1823 p = strchr(val, '/'); 1824 if (p != NULL) 1825 { 1826 *p++ = '\0'; 1827 settimeout("queuewarn", p); 1828 } 1829 settimeout("queuereturn", val); 1830 break; 1831 1832 case 't': /* time zone name */ 1833 TimeZoneSpec = newstr(val); 1834 break; 1835 1836 case 'U': /* location of user database */ 1837 UdbSpec = newstr(val); 1838 break; 1839 1840 case 'u': /* set default uid */ 1841 for (p = val; *p != '\0'; p++) 1842 { 1843 if (*p == '.' || *p == '/' || *p == ':') 1844 { 1845 *p++ = '\0'; 1846 break; 1847 } 1848 } 1849 if (isascii(*val) && isdigit(*val)) 1850 DefUid = atoi(val); 1851 else 1852 { 1853 register struct passwd *pw; 1854 1855 DefUid = -1; 1856 pw = sm_getpwnam(val); 1857 if (pw == NULL) 1858 syserr("readcf: option u: unknown user %s", val); 1859 else 1860 { 1861 DefUid = pw->pw_uid; 1862 DefGid = pw->pw_gid; 1863 } 1864 } 1865 setdefuser(); 1866 1867 /* handle the group if it is there */ 1868 if (*p == '\0') 1869 break; 1870 val = p; 1871 goto g_opt; 1872 1873 case 'V': /* fallback MX host */ 1874 FallBackMX = newstr(val); 1875 break; 1876 1877 case 'v': /* run in verbose mode */ 1878 Verbose = atobool(val); 1879 break; 1880 1881 case 'w': /* if we are best MX, try host directly */ 1882 TryNullMXList = atobool(val); 1883 break; 1884 1885 /* 'W' available -- was wizard password */ 1886 1887 case 'x': /* load avg at which to auto-queue msgs */ 1888 QueueLA = atoi(val); 1889 break; 1890 1891 case 'X': /* load avg at which to auto-reject connections */ 1892 RefuseLA = atoi(val); 1893 break; 1894 1895 case 'y': /* work recipient factor */ 1896 WkRecipFact = atoi(val); 1897 break; 1898 1899 case 'Y': /* fork jobs during queue runs */ 1900 ForkQueueRuns = atobool(val); 1901 break; 1902 1903 case 'z': /* work message class factor */ 1904 WkClassFact = atoi(val); 1905 break; 1906 1907 case 'Z': /* work time factor */ 1908 WkTimeFact = atoi(val); 1909 break; 1910 1911 case O_QUEUESORTORD: /* queue sorting order */ 1912 switch (*val) 1913 { 1914 case 'h': /* Host first */ 1915 case 'H': 1916 QueueSortOrder = QS_BYHOST; 1917 break; 1918 1919 case 'p': /* Priority order */ 1920 case 'P': 1921 QueueSortOrder = QS_BYPRIORITY; 1922 break; 1923 1924 default: 1925 syserr("Invalid queue sort order \"%s\"", val); 1926 } 1927 break; 1928 1929 case O_HOSTSFILE: /* pathname of /etc/hosts file */ 1930 HostsFile = newstr(val); 1931 break; 1932 1933 case O_MQA: /* minimum queue age between deliveries */ 1934 MinQueueAge = convtime(val, 'm'); 1935 break; 1936 1937 case O_MHSA: /* maximum age of cached host status */ 1938 MaxHostStatAge = convtime(val, 'm'); 1939 break; 1940 1941 case O_DEFCHARSET: /* default character set for mimefying */ 1942 DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 1943 break; 1944 1945 case O_SSFILE: /* service switch file */ 1946 ServiceSwitchFile = newstr(val); 1947 break; 1948 1949 case O_DIALDELAY: /* delay for dial-on-demand operation */ 1950 DialDelay = convtime(val, 's'); 1951 break; 1952 1953 case O_NORCPTACTION: /* what to do if no recipient */ 1954 if (strcasecmp(val, "none") == 0) 1955 NoRecipientAction = NRA_NO_ACTION; 1956 else if (strcasecmp(val, "add-to") == 0) 1957 NoRecipientAction = NRA_ADD_TO; 1958 else if (strcasecmp(val, "add-apparently-to") == 0) 1959 NoRecipientAction = NRA_ADD_APPARENTLY_TO; 1960 else if (strcasecmp(val, "add-bcc") == 0) 1961 NoRecipientAction = NRA_ADD_BCC; 1962 else if (strcasecmp(val, "add-to-undisclosed") == 0) 1963 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 1964 else 1965 syserr("Invalid NoRecipientAction: %s", val); 1966 1967 case O_SAFEFILEENV: /* chroot() environ for writing to files */ 1968 SafeFileEnv = newstr(val); 1969 break; 1970 1971 case O_MAXMSGSIZE: /* maximum message size */ 1972 MaxMessageSize = atol(val); 1973 break; 1974 1975 case O_COLONOKINADDR: /* old style handling of colon addresses */ 1976 ColonOkInAddr = atobool(val); 1977 break; 1978 1979 case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 1980 MaxQueueRun = atol(val); 1981 break; 1982 1983 case O_MAXCHILDREN: /* max # of children of daemon */ 1984 MaxChildren = atoi(val); 1985 break; 1986 1987 case O_KEEPCNAMES: /* don't expand CNAME records */ 1988 DontExpandCnames = atobool(val); 1989 break; 1990 1991 default: 1992 if (tTd(37, 1)) 1993 { 1994 if (isascii(opt) && isprint(opt)) 1995 printf("Warning: option %c unknown\n", opt); 1996 else 1997 printf("Warning: option 0x%x unknown\n", opt); 1998 } 1999 break; 2000 } 2001 if (sticky) 2002 setbitn(opt, StickyOpt); 2003 } 2004 /* 2005 ** SETCLASS -- set a string into a class 2006 ** 2007 ** Parameters: 2008 ** class -- the class to put the string in. 2009 ** str -- the string to enter 2010 ** 2011 ** Returns: 2012 ** none. 2013 ** 2014 ** Side Effects: 2015 ** puts the word into the symbol table. 2016 */ 2017 2018 void 2019 setclass(class, str) 2020 int class; 2021 char *str; 2022 { 2023 register STAB *s; 2024 2025 if (tTd(37, 8)) 2026 printf("setclass(%c, %s)\n", class, str); 2027 s = stab(str, ST_CLASS, ST_ENTER); 2028 setbitn(class, s->s_class); 2029 } 2030 /* 2031 ** MAKEMAPENTRY -- create a map entry 2032 ** 2033 ** Parameters: 2034 ** line -- the config file line 2035 ** 2036 ** Returns: 2037 ** A pointer to the map that has been created. 2038 ** NULL if there was a syntax error. 2039 ** 2040 ** Side Effects: 2041 ** Enters the map into the dictionary. 2042 */ 2043 2044 MAP * 2045 makemapentry(line) 2046 char *line; 2047 { 2048 register char *p; 2049 char *mapname; 2050 char *classname; 2051 register STAB *s; 2052 STAB *class; 2053 2054 for (p = line; isascii(*p) && isspace(*p); p++) 2055 continue; 2056 if (!(isascii(*p) && isalnum(*p))) 2057 { 2058 syserr("readcf: config K line: no map name"); 2059 return NULL; 2060 } 2061 2062 mapname = p; 2063 while ((isascii(*++p) && isalnum(*p)) || *p == '.') 2064 continue; 2065 if (*p != '\0') 2066 *p++ = '\0'; 2067 while (isascii(*p) && isspace(*p)) 2068 p++; 2069 if (!(isascii(*p) && isalnum(*p))) 2070 { 2071 syserr("readcf: config K line, map %s: no map class", mapname); 2072 return NULL; 2073 } 2074 classname = p; 2075 while (isascii(*++p) && isalnum(*p)) 2076 continue; 2077 if (*p != '\0') 2078 *p++ = '\0'; 2079 while (isascii(*p) && isspace(*p)) 2080 p++; 2081 2082 /* look up the class */ 2083 class = stab(classname, ST_MAPCLASS, ST_FIND); 2084 if (class == NULL) 2085 { 2086 syserr("readcf: map %s: class %s not available", mapname, classname); 2087 return NULL; 2088 } 2089 2090 /* enter the map */ 2091 s = stab(mapname, ST_MAP, ST_ENTER); 2092 s->s_map.map_class = &class->s_mapclass; 2093 s->s_map.map_mname = newstr(mapname); 2094 2095 if (class->s_mapclass.map_parse(&s->s_map, p)) 2096 s->s_map.map_mflags |= MF_VALID; 2097 2098 if (tTd(37, 5)) 2099 { 2100 printf("map %s, class %s, flags %x, file %s,\n", 2101 s->s_map.map_mname, s->s_map.map_class->map_cname, 2102 s->s_map.map_mflags, 2103 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 2104 printf("\tapp %s, domain %s, rebuild %s\n", 2105 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 2106 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 2107 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 2108 } 2109 2110 return &s->s_map; 2111 } 2112 /* 2113 ** STRTORWSET -- convert string to rewriting set number 2114 ** 2115 ** Parameters: 2116 ** p -- the pointer to the string to decode. 2117 ** endp -- if set, store the trailing delimiter here. 2118 ** stabmode -- ST_ENTER to create this entry, ST_FIND if 2119 ** it must already exist. 2120 ** 2121 ** Returns: 2122 ** The appropriate ruleset number. 2123 ** -1 if it is not valid (error already printed) 2124 */ 2125 2126 int 2127 strtorwset(p, endp, stabmode) 2128 char *p; 2129 char **endp; 2130 int stabmode; 2131 { 2132 int ruleset; 2133 static int nextruleset = MAXRWSETS; 2134 2135 while (isascii(*p) && isspace(*p)) 2136 p++; 2137 if (!isascii(*p)) 2138 { 2139 syserr("invalid ruleset name: \"%.20s\"", p); 2140 return -1; 2141 } 2142 if (isdigit(*p)) 2143 { 2144 ruleset = strtol(p, endp, 10); 2145 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 2146 { 2147 syserr("bad ruleset %d (%d max)", 2148 ruleset, MAXRWSETS / 2); 2149 ruleset = -1; 2150 } 2151 } 2152 else 2153 { 2154 STAB *s; 2155 char delim; 2156 char *q; 2157 2158 q = p; 2159 while (*p != '\0' && isascii(*p) && 2160 (isalnum(*p) || strchr("-_$", *p) != NULL)) 2161 p++; 2162 while (isascii(*p) && isspace(*p)) 2163 *p++ = '\0'; 2164 delim = *p; 2165 if (delim != '\0') 2166 *p = '\0'; 2167 s = stab(q, ST_RULESET, stabmode); 2168 if (delim != '\0') 2169 *p = delim; 2170 2171 if (s == NULL) 2172 { 2173 syserr("unknown ruleset %s", q); 2174 return -1; 2175 } 2176 2177 if (stabmode == ST_ENTER && delim == '=') 2178 { 2179 ruleset = strtol(p, endp, 10); 2180 if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 2181 { 2182 syserr("bad ruleset %s = %d (%d max)", 2183 q, ruleset, MAXRWSETS / 2); 2184 ruleset = -1; 2185 } 2186 } 2187 else 2188 { 2189 if (endp != NULL) 2190 *endp = p; 2191 if (s->s_ruleset > 0) 2192 ruleset = s->s_ruleset; 2193 else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 2194 { 2195 syserr("%s: too many named rulesets (%d max)", 2196 q, MAXRWSETS / 2); 2197 ruleset = -1; 2198 } 2199 } 2200 if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset) 2201 { 2202 syserr("%s: ruleset changed value (old %d, new %d)", 2203 q, ruleset, s->s_ruleset); 2204 ruleset = s->s_ruleset; 2205 } 2206 else if (ruleset > 0) 2207 { 2208 s->s_ruleset = ruleset; 2209 } 2210 } 2211 return ruleset; 2212 } 2213 /* 2214 ** INITTIMEOUTS -- parse and set timeout values 2215 ** 2216 ** Parameters: 2217 ** val -- a pointer to the values. If NULL, do initial 2218 ** settings. 2219 ** 2220 ** Returns: 2221 ** none. 2222 ** 2223 ** Side Effects: 2224 ** Initializes the TimeOuts structure 2225 */ 2226 2227 #define SECONDS 2228 #define MINUTES * 60 2229 #define HOUR * 3600 2230 2231 void 2232 inittimeouts(val) 2233 register char *val; 2234 { 2235 register char *p; 2236 extern time_t convtime(); 2237 2238 if (val == NULL) 2239 { 2240 TimeOuts.to_initial = (time_t) 5 MINUTES; 2241 TimeOuts.to_helo = (time_t) 5 MINUTES; 2242 TimeOuts.to_mail = (time_t) 10 MINUTES; 2243 TimeOuts.to_rcpt = (time_t) 1 HOUR; 2244 TimeOuts.to_datainit = (time_t) 5 MINUTES; 2245 TimeOuts.to_datablock = (time_t) 1 HOUR; 2246 TimeOuts.to_datafinal = (time_t) 1 HOUR; 2247 TimeOuts.to_rset = (time_t) 5 MINUTES; 2248 TimeOuts.to_quit = (time_t) 2 MINUTES; 2249 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 2250 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2251 #if IDENTPROTO 2252 TimeOuts.to_ident = (time_t) 30 SECONDS; 2253 #else 2254 TimeOuts.to_ident = (time_t) 0 SECONDS; 2255 #endif 2256 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 2257 return; 2258 } 2259 2260 for (;; val = p) 2261 { 2262 while (isascii(*val) && isspace(*val)) 2263 val++; 2264 if (*val == '\0') 2265 break; 2266 for (p = val; *p != '\0' && *p != ','; p++) 2267 continue; 2268 if (*p != '\0') 2269 *p++ = '\0'; 2270 2271 if (isascii(*val) && isdigit(*val)) 2272 { 2273 /* old syntax -- set everything */ 2274 TimeOuts.to_mail = convtime(val, 'm'); 2275 TimeOuts.to_rcpt = TimeOuts.to_mail; 2276 TimeOuts.to_datainit = TimeOuts.to_mail; 2277 TimeOuts.to_datablock = TimeOuts.to_mail; 2278 TimeOuts.to_datafinal = TimeOuts.to_mail; 2279 TimeOuts.to_nextcommand = TimeOuts.to_mail; 2280 continue; 2281 } 2282 else 2283 { 2284 register char *q = strchr(val, ':'); 2285 2286 if (q == NULL && (q = strchr(val, '=')) == NULL) 2287 { 2288 /* syntax error */ 2289 continue; 2290 } 2291 *q++ = '\0'; 2292 settimeout(val, q); 2293 } 2294 } 2295 } 2296 /* 2297 ** SETTIMEOUT -- set an individual timeout 2298 ** 2299 ** Parameters: 2300 ** name -- the name of the timeout. 2301 ** val -- the value of the timeout. 2302 ** 2303 ** Returns: 2304 ** none. 2305 */ 2306 2307 void 2308 settimeout(name, val) 2309 char *name; 2310 char *val; 2311 { 2312 register char *p; 2313 time_t to; 2314 extern time_t convtime(); 2315 2316 to = convtime(val, 'm'); 2317 p = strchr(name, '.'); 2318 if (p != NULL) 2319 *p++ = '\0'; 2320 2321 if (strcasecmp(name, "initial") == 0) 2322 TimeOuts.to_initial = to; 2323 else if (strcasecmp(name, "mail") == 0) 2324 TimeOuts.to_mail = to; 2325 else if (strcasecmp(name, "rcpt") == 0) 2326 TimeOuts.to_rcpt = to; 2327 else if (strcasecmp(name, "datainit") == 0) 2328 TimeOuts.to_datainit = to; 2329 else if (strcasecmp(name, "datablock") == 0) 2330 TimeOuts.to_datablock = to; 2331 else if (strcasecmp(name, "datafinal") == 0) 2332 TimeOuts.to_datafinal = to; 2333 else if (strcasecmp(name, "command") == 0) 2334 TimeOuts.to_nextcommand = to; 2335 else if (strcasecmp(name, "rset") == 0) 2336 TimeOuts.to_rset = to; 2337 else if (strcasecmp(name, "helo") == 0) 2338 TimeOuts.to_helo = to; 2339 else if (strcasecmp(name, "quit") == 0) 2340 TimeOuts.to_quit = to; 2341 else if (strcasecmp(name, "misc") == 0) 2342 TimeOuts.to_miscshort = to; 2343 else if (strcasecmp(name, "ident") == 0) 2344 TimeOuts.to_ident = to; 2345 else if (strcasecmp(name, "fileopen") == 0) 2346 TimeOuts.to_fileopen = to; 2347 else if (strcasecmp(name, "queuewarn") == 0) 2348 { 2349 to = convtime(val, 'h'); 2350 if (p == NULL || strcmp(p, "*") == 0) 2351 { 2352 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2353 TimeOuts.to_q_warning[TOC_URGENT] = to; 2354 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2355 } 2356 else if (strcasecmp(p, "normal") == 0) 2357 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2358 else if (strcasecmp(p, "urgent") == 0) 2359 TimeOuts.to_q_warning[TOC_URGENT] = to; 2360 else if (strcasecmp(p, "non-urgent") == 0) 2361 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2362 else 2363 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2364 } 2365 else if (strcasecmp(name, "queuereturn") == 0) 2366 { 2367 to = convtime(val, 'd'); 2368 if (p == NULL || strcmp(p, "*") == 0) 2369 { 2370 TimeOuts.to_q_return[TOC_NORMAL] = to; 2371 TimeOuts.to_q_return[TOC_URGENT] = to; 2372 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2373 } 2374 else if (strcasecmp(p, "normal") == 0) 2375 TimeOuts.to_q_return[TOC_NORMAL] = to; 2376 else if (strcasecmp(p, "urgent") == 0) 2377 TimeOuts.to_q_return[TOC_URGENT] = to; 2378 else if (strcasecmp(p, "non-urgent") == 0) 2379 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2380 else 2381 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2382 } 2383 else 2384 syserr("settimeout: invalid timeout %s", name); 2385 } 2386