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