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