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.61 (Berkeley) 02/05/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': /* MTA Type */ 840 m->m_mtatype = newstr(p); 841 p = strchr(m->m_mtatype, '/'); 842 if (p != NULL) 843 { 844 *p++ = '\0'; 845 if (*p == '\0') 846 p = NULL; 847 } 848 if (p == NULL) 849 m->m_addrtype = m->m_mtatype; 850 else 851 { 852 m->m_addrtype = p; 853 p = strchr(p, '/'); 854 } 855 if (p != NULL) 856 { 857 *p++ = '\0'; 858 if (*p == '\0') 859 p = NULL; 860 } 861 if (p == NULL) 862 m->m_diagtype = m->m_mtatype; 863 else 864 m->m_diagtype = p; 865 break; 866 867 case 'U': /* user id */ 868 if (isascii(*p) && !isdigit(*p)) 869 { 870 char *q = p; 871 struct passwd *pw; 872 873 while (isascii(*p) && isalnum(*p)) 874 p++; 875 while (isascii(*p) && isspace(*p)) 876 *p++ = '\0'; 877 if (*p != '\0') 878 *p++ = '\0'; 879 pw = getpwnam(q); 880 if (pw == NULL) 881 syserr("readcf: mailer U= flag: unknown user %s", q); 882 else 883 { 884 m->m_uid = pw->pw_uid; 885 m->m_gid = pw->pw_gid; 886 } 887 } 888 else 889 { 890 auto char *q; 891 892 m->m_uid = strtol(p, &q, 0); 893 p = q; 894 } 895 while (isascii(*p) && isspace(*p)) 896 p++; 897 if (*p == '\0') 898 break; 899 if (isascii(*p) && !isdigit(*p)) 900 { 901 char *q = p; 902 struct group *gr; 903 904 while (isascii(*p) && isalnum(*p)) 905 p++; 906 *p++ = '\0'; 907 gr = getgrnam(q); 908 if (gr == NULL) 909 syserr("readcf: mailer U= flag: unknown group %s", q); 910 else 911 m->m_gid = gr->gr_gid; 912 } 913 else 914 { 915 m->m_gid = strtol(p, NULL, 0); 916 } 917 break; 918 } 919 920 p = delimptr; 921 } 922 923 /* do some rationality checking */ 924 if (m->m_argv == NULL) 925 { 926 syserr("M%s: A= argument required", m->m_name); 927 return; 928 } 929 if (m->m_mailer == NULL) 930 { 931 syserr("M%s: P= argument required", m->m_name); 932 return; 933 } 934 935 if (NextMailer >= MAXMAILERS) 936 { 937 syserr("too many mailers defined (%d max)", MAXMAILERS); 938 return; 939 } 940 941 /* do some heuristic cleanup for back compatibility */ 942 if (bitnset(M_LIMITS, m->m_flags)) 943 { 944 if (m->m_linelimit == 0) 945 m->m_linelimit = SMTPLINELIM; 946 if (ConfigLevel < 2) 947 setbitn(M_7BITS, m->m_flags); 948 } 949 950 if (ConfigLevel < 6 && 951 (strcmp(m->m_mailer, "[IPC]") == 0 || 952 strcmp(m->m_mailer, "[TCP]") == 0)) 953 { 954 if (m->m_mtatype == NULL) 955 m->m_mtatype = "dns"; 956 if (m->m_addrtype == NULL) 957 m->m_addrtype = "rfc822"; 958 if (m->m_diagtype == NULL) 959 m->m_diagtype = "smtp"; 960 } 961 962 /* enter the mailer into the symbol table */ 963 s = stab(m->m_name, ST_MAILER, ST_ENTER); 964 if (s->s_mailer != NULL) 965 { 966 i = s->s_mailer->m_mno; 967 free(s->s_mailer); 968 } 969 else 970 { 971 i = NextMailer++; 972 } 973 Mailer[i] = s->s_mailer = m; 974 m->m_mno = i; 975 } 976 /* 977 ** MUNCHSTRING -- translate a string into internal form. 978 ** 979 ** Parameters: 980 ** p -- the string to munch. 981 ** delimptr -- if non-NULL, set to the pointer of the 982 ** field delimiter character. 983 ** 984 ** Returns: 985 ** the munched string. 986 */ 987 988 char * 989 munchstring(p, delimptr) 990 register char *p; 991 char **delimptr; 992 { 993 register char *q; 994 bool backslash = FALSE; 995 bool quotemode = FALSE; 996 static char buf[MAXLINE]; 997 998 for (q = buf; *p != '\0'; p++) 999 { 1000 if (backslash) 1001 { 1002 /* everything is roughly literal */ 1003 backslash = FALSE; 1004 switch (*p) 1005 { 1006 case 'r': /* carriage return */ 1007 *q++ = '\r'; 1008 continue; 1009 1010 case 'n': /* newline */ 1011 *q++ = '\n'; 1012 continue; 1013 1014 case 'f': /* form feed */ 1015 *q++ = '\f'; 1016 continue; 1017 1018 case 'b': /* backspace */ 1019 *q++ = '\b'; 1020 continue; 1021 } 1022 *q++ = *p; 1023 } 1024 else 1025 { 1026 if (*p == '\\') 1027 backslash = TRUE; 1028 else if (*p == '"') 1029 quotemode = !quotemode; 1030 else if (quotemode || *p != ',') 1031 *q++ = *p; 1032 else 1033 break; 1034 } 1035 } 1036 1037 if (delimptr != NULL) 1038 *delimptr = p; 1039 *q++ = '\0'; 1040 return (buf); 1041 } 1042 /* 1043 ** MAKEARGV -- break up a string into words 1044 ** 1045 ** Parameters: 1046 ** p -- the string to break up. 1047 ** 1048 ** Returns: 1049 ** a char **argv (dynamically allocated) 1050 ** 1051 ** Side Effects: 1052 ** munges p. 1053 */ 1054 1055 char ** 1056 makeargv(p) 1057 register char *p; 1058 { 1059 char *q; 1060 int i; 1061 char **avp; 1062 char *argv[MAXPV + 1]; 1063 1064 /* take apart the words */ 1065 i = 0; 1066 while (*p != '\0' && i < MAXPV) 1067 { 1068 q = p; 1069 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1070 p++; 1071 while (isascii(*p) && isspace(*p)) 1072 *p++ = '\0'; 1073 argv[i++] = newstr(q); 1074 } 1075 argv[i++] = NULL; 1076 1077 /* now make a copy of the argv */ 1078 avp = (char **) xalloc(sizeof *avp * i); 1079 bcopy((char *) argv, (char *) avp, sizeof *avp * i); 1080 1081 return (avp); 1082 } 1083 /* 1084 ** PRINTRULES -- print rewrite rules (for debugging) 1085 ** 1086 ** Parameters: 1087 ** none. 1088 ** 1089 ** Returns: 1090 ** none. 1091 ** 1092 ** Side Effects: 1093 ** prints rewrite rules. 1094 */ 1095 1096 printrules() 1097 { 1098 register struct rewrite *rwp; 1099 register int ruleset; 1100 1101 for (ruleset = 0; ruleset < 10; ruleset++) 1102 { 1103 if (RewriteRules[ruleset] == NULL) 1104 continue; 1105 printf("\n----Rule Set %d:", ruleset); 1106 1107 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 1108 { 1109 printf("\nLHS:"); 1110 printav(rwp->r_lhs); 1111 printf("RHS:"); 1112 printav(rwp->r_rhs); 1113 } 1114 } 1115 } 1116 /* 1117 ** PRINTMAILER -- print mailer structure (for debugging) 1118 ** 1119 ** Parameters: 1120 ** m -- the mailer to print 1121 ** 1122 ** Returns: 1123 ** none. 1124 */ 1125 1126 printmailer(m) 1127 register MAILER *m; 1128 { 1129 int j; 1130 1131 printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 1132 m->m_mno, m->m_name, 1133 m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 1134 m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 1135 m->m_uid, m->m_gid); 1136 for (j = '\0'; j <= '\177'; j++) 1137 if (bitnset(j, m->m_flags)) 1138 (void) putchar(j); 1139 printf(" L=%d E=", m->m_linelimit); 1140 xputs(m->m_eol); 1141 if (m->m_defcharset != NULL) 1142 printf(" C=%s", m->m_defcharset); 1143 printf(" T=%s/%s/%s", 1144 m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 1145 m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 1146 m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 1147 if (m->m_argv != NULL) 1148 { 1149 char **a = m->m_argv; 1150 1151 printf(" A="); 1152 while (*a != NULL) 1153 { 1154 if (a != m->m_argv) 1155 printf(" "); 1156 xputs(*a++); 1157 } 1158 } 1159 printf("\n"); 1160 } 1161 /* 1162 ** SETOPTION -- set global processing option 1163 ** 1164 ** Parameters: 1165 ** opt -- option name. 1166 ** val -- option value (as a text string). 1167 ** safe -- set if this came from a configuration file. 1168 ** Some options (if set from the command line) will 1169 ** reset the user id to avoid security problems. 1170 ** sticky -- if set, don't let other setoptions override 1171 ** this value. 1172 ** e -- the main envelope. 1173 ** 1174 ** Returns: 1175 ** none. 1176 ** 1177 ** Side Effects: 1178 ** Sets options as implied by the arguments. 1179 */ 1180 1181 static BITMAP StickyOpt; /* set if option is stuck */ 1182 1183 1184 #if NAMED_BIND 1185 1186 struct resolverflags 1187 { 1188 char *rf_name; /* name of the flag */ 1189 long rf_bits; /* bits to set/clear */ 1190 } ResolverFlags[] = 1191 { 1192 "debug", RES_DEBUG, 1193 "aaonly", RES_AAONLY, 1194 "usevc", RES_USEVC, 1195 "primary", RES_PRIMARY, 1196 "igntc", RES_IGNTC, 1197 "recurse", RES_RECURSE, 1198 "defnames", RES_DEFNAMES, 1199 "stayopen", RES_STAYOPEN, 1200 "dnsrch", RES_DNSRCH, 1201 "true", 0, /* to avoid error on old syntax */ 1202 NULL, 0 1203 }; 1204 1205 #endif 1206 1207 struct optioninfo 1208 { 1209 char *o_name; /* long name of option */ 1210 u_char o_code; /* short name of option */ 1211 bool o_safe; /* safe for random people to use */ 1212 } OptionTab[] = 1213 { 1214 "SevenBitInput", '7', TRUE, 1215 "EightBitMode", '8', TRUE, 1216 "AliasFile", 'A', FALSE, 1217 "AliasWait", 'a', FALSE, 1218 "BlankSub", 'B', FALSE, 1219 "MinFreeBlocks", 'b', TRUE, 1220 "CheckpointInterval", 'C', TRUE, 1221 "HoldExpensive", 'c', FALSE, 1222 "AutoRebuildAliases", 'D', FALSE, 1223 "DeliveryMode", 'd', TRUE, 1224 "ErrorHeader", 'E', FALSE, 1225 "ErrorMode", 'e', TRUE, 1226 "TempFileMode", 'F', FALSE, 1227 "SaveFromLine", 'f', FALSE, 1228 "MatchGECOS", 'G', FALSE, 1229 "HelpFile", 'H', FALSE, 1230 "MaxHopCount", 'h', FALSE, 1231 "NameServerOptions", 'I', FALSE, 1232 "IgnoreDots", 'i', TRUE, 1233 "ForwardPath", 'J', FALSE, 1234 "SendMimeErrors", 'j', TRUE, 1235 "ConnectionCacheSize", 'k', FALSE, 1236 "ConnectionCacheTimeout", 'K', FALSE, 1237 "UseErrorsTo", 'l', FALSE, 1238 "LogLevel", 'L', FALSE, 1239 "MeToo", 'm', TRUE, 1240 "CheckAliases", 'n', FALSE, 1241 "OldStyleHeaders", 'o', TRUE, 1242 "DaemonPortOptions", 'O', FALSE, 1243 "PrivacyOptions", 'p', TRUE, 1244 "PostmasterCopy", 'P', FALSE, 1245 "QueueFactor", 'q', FALSE, 1246 "QueueDirectory", 'Q', FALSE, 1247 "DontPruneRoutes", 'R', FALSE, 1248 "Timeout", 'r', TRUE, 1249 "StatusFile", 'S', FALSE, 1250 "SuperSafe", 's', TRUE, 1251 "QueueTimeout", 'T', FALSE, 1252 "TimeZoneSpec", 't', FALSE, 1253 "UserDatabaseSpec", 'U', FALSE, 1254 "DefaultUser", 'u', FALSE, 1255 "FallbackMXhost", 'V', FALSE, 1256 "Verbose", 'v', TRUE, 1257 "TryNullMXList", 'w', TRUE, 1258 "QueueLA", 'x', FALSE, 1259 "RefuseLA", 'X', FALSE, 1260 "RecipientFactor", 'y', FALSE, 1261 "ForkQueueRuns", 'Y', FALSE, 1262 "ClassFactor", 'z', FALSE, 1263 "TimeFactor", 'Z', FALSE, 1264 #define O_BSP 0x80 1265 "BrokenSmtpPeers", O_BSP, TRUE, 1266 #define O_QUEUESORTORD 0x81 1267 "QueueSortOrder", O_QUEUESORTORD, TRUE, 1268 #define O_MQA 0x83 1269 "MinQueueAge", O_MQA, TRUE, 1270 #define O_MHSA 0x84 1271 /* 1272 "MaxHostStatAge", O_MHSA, TRUE, 1273 */ 1274 #define O_DEFCHARSET 0x85 1275 "DefaultCharSet", O_DEFCHARSET, TRUE, 1276 #define O_SSFILE 0x86 1277 "ServiceSwitchFile", O_SSFILE, FALSE, 1278 #define O_DIALDELAY 0x87 1279 "DialDelay", O_DIALDELAY, TRUE, 1280 1281 NULL, '\0', FALSE, 1282 }; 1283 1284 1285 1286 setoption(opt, val, safe, sticky, e) 1287 u_char opt; 1288 char *val; 1289 bool safe; 1290 bool sticky; 1291 register ENVELOPE *e; 1292 { 1293 register char *p; 1294 register struct optioninfo *o; 1295 char *subopt; 1296 extern bool atobool(); 1297 extern time_t convtime(); 1298 extern int QueueLA; 1299 extern int RefuseLA; 1300 extern bool Warn_Q_option; 1301 1302 errno = 0; 1303 if (opt == ' ') 1304 { 1305 /* full word options */ 1306 struct optioninfo *sel; 1307 1308 p = strchr(val, '='); 1309 if (p == NULL) 1310 p = &val[strlen(val)]; 1311 while (*--p == ' ') 1312 continue; 1313 while (*++p == ' ') 1314 *p = '\0'; 1315 if (p == val) 1316 { 1317 syserr("readcf: null option name"); 1318 return; 1319 } 1320 if (*p == '=') 1321 *p++ = '\0'; 1322 while (*p == ' ') 1323 p++; 1324 subopt = strchr(val, '.'); 1325 if (subopt != NULL) 1326 *subopt++ = '\0'; 1327 sel = NULL; 1328 for (o = OptionTab; o->o_name != NULL; o++) 1329 { 1330 if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1331 continue; 1332 if (strlen(o->o_name) == strlen(val)) 1333 { 1334 /* completely specified -- this must be it */ 1335 sel = NULL; 1336 break; 1337 } 1338 if (sel != NULL) 1339 break; 1340 sel = o; 1341 } 1342 if (sel != NULL && o->o_name == NULL) 1343 o = sel; 1344 else if (o->o_name == NULL) 1345 { 1346 syserr("readcf: unknown option name %s", val); 1347 return; 1348 } 1349 else if (sel != NULL) 1350 { 1351 syserr("readcf: ambiguous option name %s (matches %s and %s)", 1352 val, sel->o_name, o->o_name); 1353 return; 1354 } 1355 if (strlen(val) != strlen(o->o_name)) 1356 { 1357 bool oldVerbose = Verbose; 1358 1359 Verbose = TRUE; 1360 message("Option %s used as abbreviation for %s", 1361 val, o->o_name); 1362 Verbose = oldVerbose; 1363 } 1364 opt = o->o_code; 1365 val = p; 1366 } 1367 else 1368 { 1369 for (o = OptionTab; o->o_name != NULL; o++) 1370 { 1371 if (o->o_code == opt) 1372 break; 1373 } 1374 subopt = NULL; 1375 } 1376 1377 if (tTd(37, 1)) 1378 { 1379 printf(isascii(opt) && isprint(opt) ? 1380 "setoption %s (%c).%s=%s" : 1381 "setoption %s (0x%x).%s=%s", 1382 o->o_name == NULL ? "<unknown>" : o->o_name, 1383 opt, 1384 subopt == NULL ? "" : subopt, 1385 val); 1386 } 1387 1388 /* 1389 ** See if this option is preset for us. 1390 */ 1391 1392 if (!sticky && bitnset(opt, StickyOpt)) 1393 { 1394 if (tTd(37, 1)) 1395 printf(" (ignored)\n"); 1396 return; 1397 } 1398 1399 /* 1400 ** Check to see if this option can be specified by this user. 1401 */ 1402 1403 if (!safe && RealUid == 0) 1404 safe = TRUE; 1405 if (!safe && !o->o_safe) 1406 { 1407 if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 1408 { 1409 if (tTd(37, 1)) 1410 printf(" (unsafe)"); 1411 if (RealUid != geteuid()) 1412 { 1413 if (tTd(37, 1)) 1414 printf("(Resetting uid)"); 1415 (void) setgid(RealGid); 1416 (void) setuid(RealUid); 1417 } 1418 } 1419 } 1420 if (tTd(37, 1)) 1421 printf("\n"); 1422 1423 switch (opt & 0xff) 1424 { 1425 case '7': /* force seven-bit input */ 1426 SevenBitInput = atobool(val); 1427 break; 1428 1429 case '8': /* handling of 8-bit input */ 1430 switch (*val) 1431 { 1432 case 'r': /* reject 8-bit, don't convert MIME */ 1433 MimeMode = 0; 1434 break; 1435 1436 case 'm': /* convert 8-bit, convert MIME */ 1437 MimeMode = MM_CVTMIME|MM_MIME8BIT; 1438 break; 1439 1440 case 'j': /* "just send 8" */ 1441 MimeMode = MM_PASS8BIT; 1442 break; 1443 1444 case 'p': /* pass 8 bit, convert MIME */ 1445 MimeMode = MM_PASS8BIT|MM_CVTMIME; 1446 break; 1447 1448 case 's': /* strict adherence */ 1449 MimeMode = MM_CVTMIME; 1450 break; 1451 1452 case 'a': /* encode 8 bit if available */ 1453 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1454 break; 1455 1456 case 'c': /* convert 8 bit to MIME, never 7 bit */ 1457 MimeMode = MM_MIME8BIT; 1458 break; 1459 1460 default: 1461 syserr("Unknown 8-bit mode %c", *val); 1462 exit(EX_USAGE); 1463 } 1464 break; 1465 1466 case 'A': /* set default alias file */ 1467 if (val[0] == '\0') 1468 setalias("aliases"); 1469 else 1470 setalias(val); 1471 break; 1472 1473 case 'a': /* look N minutes for "@:@" in alias file */ 1474 if (val[0] == '\0') 1475 SafeAlias = 5 * 60; /* five minutes */ 1476 else 1477 SafeAlias = convtime(val, 'm'); 1478 break; 1479 1480 case 'B': /* substitution for blank character */ 1481 SpaceSub = val[0]; 1482 if (SpaceSub == '\0') 1483 SpaceSub = ' '; 1484 break; 1485 1486 case 'b': /* min blocks free on queue fs/max msg size */ 1487 p = strchr(val, '/'); 1488 if (p != NULL) 1489 { 1490 *p++ = '\0'; 1491 MaxMessageSize = atol(p); 1492 } 1493 MinBlocksFree = atol(val); 1494 break; 1495 1496 case 'c': /* don't connect to "expensive" mailers */ 1497 NoConnect = atobool(val); 1498 break; 1499 1500 case 'C': /* checkpoint every N addresses */ 1501 CheckpointInterval = atoi(val); 1502 break; 1503 1504 case 'd': /* delivery mode */ 1505 switch (*val) 1506 { 1507 case '\0': 1508 e->e_sendmode = SM_DELIVER; 1509 break; 1510 1511 case SM_QUEUE: /* queue only */ 1512 #ifndef QUEUE 1513 syserr("need QUEUE to set -odqueue"); 1514 #endif /* QUEUE */ 1515 /* fall through..... */ 1516 1517 case SM_DELIVER: /* do everything */ 1518 case SM_FORK: /* fork after verification */ 1519 e->e_sendmode = *val; 1520 break; 1521 1522 default: 1523 syserr("Unknown delivery mode %c", *val); 1524 exit(EX_USAGE); 1525 } 1526 break; 1527 1528 case 'D': /* rebuild alias database as needed */ 1529 AutoRebuild = atobool(val); 1530 break; 1531 1532 case 'E': /* error message header/header file */ 1533 if (*val != '\0') 1534 ErrMsgFile = newstr(val); 1535 break; 1536 1537 case 'e': /* set error processing mode */ 1538 switch (*val) 1539 { 1540 case EM_QUIET: /* be silent about it */ 1541 case EM_MAIL: /* mail back */ 1542 case EM_BERKNET: /* do berknet error processing */ 1543 case EM_WRITE: /* write back (or mail) */ 1544 case EM_PRINT: /* print errors normally (default) */ 1545 e->e_errormode = *val; 1546 break; 1547 } 1548 break; 1549 1550 case 'F': /* file mode */ 1551 FileMode = atooct(val) & 0777; 1552 break; 1553 1554 case 'f': /* save Unix-style From lines on front */ 1555 SaveFrom = atobool(val); 1556 break; 1557 1558 case 'G': /* match recipients against GECOS field */ 1559 MatchGecos = atobool(val); 1560 break; 1561 1562 case 'g': /* default gid */ 1563 g_opt: 1564 if (isascii(*val) && isdigit(*val)) 1565 DefGid = atoi(val); 1566 else 1567 { 1568 register struct group *gr; 1569 1570 DefGid = -1; 1571 gr = getgrnam(val); 1572 if (gr == NULL) 1573 syserr("readcf: option %c: unknown group %s", 1574 opt, val); 1575 else 1576 DefGid = gr->gr_gid; 1577 } 1578 break; 1579 1580 case 'H': /* help file */ 1581 if (val[0] == '\0') 1582 HelpFile = "sendmail.hf"; 1583 else 1584 HelpFile = newstr(val); 1585 break; 1586 1587 case 'h': /* maximum hop count */ 1588 MaxHopCount = atoi(val); 1589 break; 1590 1591 case 'I': /* use internet domain name server */ 1592 #if NAMED_BIND 1593 for (p = val; *p != 0; ) 1594 { 1595 bool clearmode; 1596 char *q; 1597 struct resolverflags *rfp; 1598 1599 while (*p == ' ') 1600 p++; 1601 if (*p == '\0') 1602 break; 1603 clearmode = FALSE; 1604 if (*p == '-') 1605 clearmode = TRUE; 1606 else if (*p != '+') 1607 p--; 1608 p++; 1609 q = p; 1610 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1611 p++; 1612 if (*p != '\0') 1613 *p++ = '\0'; 1614 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 1615 { 1616 if (strcasecmp(q, rfp->rf_name) == 0) 1617 break; 1618 } 1619 if (rfp->rf_name == NULL) 1620 syserr("readcf: I option value %s unrecognized", q); 1621 else if (clearmode) 1622 _res.options &= ~rfp->rf_bits; 1623 else 1624 _res.options |= rfp->rf_bits; 1625 } 1626 if (tTd(8, 2)) 1627 printf("_res.options = %x\n", _res.options); 1628 #else 1629 usrerr("name server (I option) specified but BIND not compiled in"); 1630 #endif 1631 break; 1632 1633 case 'i': /* ignore dot lines in message */ 1634 IgnrDot = atobool(val); 1635 break; 1636 1637 case 'j': /* send errors in MIME (RFC 1341) format */ 1638 SendMIMEErrors = atobool(val); 1639 break; 1640 1641 case 'J': /* .forward search path */ 1642 ForwardPath = newstr(val); 1643 break; 1644 1645 case 'k': /* connection cache size */ 1646 MaxMciCache = atoi(val); 1647 if (MaxMciCache < 0) 1648 MaxMciCache = 0; 1649 break; 1650 1651 case 'K': /* connection cache timeout */ 1652 MciCacheTimeout = convtime(val, 'm'); 1653 break; 1654 1655 case 'l': /* use Errors-To: header */ 1656 UseErrorsTo = atobool(val); 1657 break; 1658 1659 case 'L': /* log level */ 1660 if (safe || LogLevel < atoi(val)) 1661 LogLevel = atoi(val); 1662 break; 1663 1664 case 'M': /* define macro */ 1665 define(val[0], newstr(&val[1]), CurEnv); 1666 sticky = FALSE; 1667 break; 1668 1669 case 'm': /* send to me too */ 1670 MeToo = atobool(val); 1671 break; 1672 1673 case 'n': /* validate RHS in newaliases */ 1674 CheckAliases = atobool(val); 1675 break; 1676 1677 /* 'N' available -- was "net name" */ 1678 1679 case 'O': /* daemon options */ 1680 setdaemonoptions(val); 1681 break; 1682 1683 case 'o': /* assume old style headers */ 1684 if (atobool(val)) 1685 CurEnv->e_flags |= EF_OLDSTYLE; 1686 else 1687 CurEnv->e_flags &= ~EF_OLDSTYLE; 1688 break; 1689 1690 case 'p': /* select privacy level */ 1691 p = val; 1692 for (;;) 1693 { 1694 register struct prival *pv; 1695 extern struct prival PrivacyValues[]; 1696 1697 while (isascii(*p) && (isspace(*p) || ispunct(*p))) 1698 p++; 1699 if (*p == '\0') 1700 break; 1701 val = p; 1702 while (isascii(*p) && isalnum(*p)) 1703 p++; 1704 if (*p != '\0') 1705 *p++ = '\0'; 1706 1707 for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 1708 { 1709 if (strcasecmp(val, pv->pv_name) == 0) 1710 break; 1711 } 1712 if (pv->pv_name == NULL) 1713 syserr("readcf: Op line: %s unrecognized", val); 1714 PrivacyFlags |= pv->pv_flag; 1715 } 1716 break; 1717 1718 case 'P': /* postmaster copy address for returned mail */ 1719 PostMasterCopy = newstr(val); 1720 break; 1721 1722 case 'q': /* slope of queue only function */ 1723 QueueFactor = atoi(val); 1724 break; 1725 1726 case 'Q': /* queue directory */ 1727 if (val[0] == '\0') 1728 QueueDir = "mqueue"; 1729 else 1730 QueueDir = newstr(val); 1731 if (RealUid != 0 && !safe) 1732 Warn_Q_option = TRUE; 1733 break; 1734 1735 case 'R': /* don't prune routes */ 1736 DontPruneRoutes = atobool(val); 1737 break; 1738 1739 case 'r': /* read timeout */ 1740 if (subopt == NULL) 1741 inittimeouts(val); 1742 else 1743 settimeout(subopt, val); 1744 break; 1745 1746 case 'S': /* status file */ 1747 if (val[0] == '\0') 1748 StatFile = "sendmail.st"; 1749 else 1750 StatFile = newstr(val); 1751 break; 1752 1753 case 's': /* be super safe, even if expensive */ 1754 SuperSafe = atobool(val); 1755 break; 1756 1757 case 'T': /* queue timeout */ 1758 p = strchr(val, '/'); 1759 if (p != NULL) 1760 { 1761 *p++ = '\0'; 1762 settimeout("queuewarn", p); 1763 } 1764 settimeout("queuereturn", val); 1765 break; 1766 1767 case 't': /* time zone name */ 1768 TimeZoneSpec = newstr(val); 1769 break; 1770 1771 case 'U': /* location of user database */ 1772 UdbSpec = newstr(val); 1773 break; 1774 1775 case 'u': /* set default uid */ 1776 for (p = val; *p != '\0'; p++) 1777 { 1778 if (*p == '.' || *p == '/' || *p == ':') 1779 { 1780 *p++ = '\0'; 1781 break; 1782 } 1783 } 1784 if (isascii(*val) && isdigit(*val)) 1785 DefUid = atoi(val); 1786 else 1787 { 1788 register struct passwd *pw; 1789 1790 DefUid = -1; 1791 pw = getpwnam(val); 1792 if (pw == NULL) 1793 syserr("readcf: option u: unknown user %s", val); 1794 else 1795 { 1796 DefUid = pw->pw_uid; 1797 DefGid = pw->pw_gid; 1798 } 1799 } 1800 setdefuser(); 1801 1802 /* handle the group if it is there */ 1803 if (*p == '\0') 1804 break; 1805 val = p; 1806 goto g_opt; 1807 1808 case 'V': /* fallback MX host */ 1809 FallBackMX = newstr(val); 1810 break; 1811 1812 case 'v': /* run in verbose mode */ 1813 Verbose = atobool(val); 1814 break; 1815 1816 case 'w': /* if we are best MX, try host directly */ 1817 TryNullMXList = atobool(val); 1818 break; 1819 1820 /* 'W' available -- was wizard password */ 1821 1822 case 'x': /* load avg at which to auto-queue msgs */ 1823 QueueLA = atoi(val); 1824 break; 1825 1826 case 'X': /* load avg at which to auto-reject connections */ 1827 RefuseLA = atoi(val); 1828 break; 1829 1830 case 'y': /* work recipient factor */ 1831 WkRecipFact = atoi(val); 1832 break; 1833 1834 case 'Y': /* fork jobs during queue runs */ 1835 ForkQueueRuns = atobool(val); 1836 break; 1837 1838 case 'z': /* work message class factor */ 1839 WkClassFact = atoi(val); 1840 break; 1841 1842 case 'Z': /* work time factor */ 1843 WkTimeFact = atoi(val); 1844 break; 1845 1846 case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 1847 BrokenSmtpPeers = atobool(val); 1848 break; 1849 1850 case O_QUEUESORTORD: /* queue sorting order */ 1851 switch (*val) 1852 { 1853 case 'h': /* Host first */ 1854 case 'H': 1855 QueueSortOrder = QS_BYHOST; 1856 break; 1857 1858 case 'p': /* Priority order */ 1859 case 'P': 1860 QueueSortOrder = QS_BYPRIORITY; 1861 break; 1862 1863 default: 1864 syserr("Invalid queue sort order \"%s\"", val); 1865 } 1866 break; 1867 1868 case O_MQA: /* minimum queue age between deliveries */ 1869 MinQueueAge = convtime(val, 'm'); 1870 break; 1871 1872 case O_MHSA: /* maximum age of cached host status */ 1873 MaxHostStatAge = convtime(val, 'm'); 1874 break; 1875 1876 case O_DEFCHARSET: /* default character set for mimefying */ 1877 DefaultCharSet = newstr(val); 1878 break; 1879 1880 case O_SSFILE: /* service switch file */ 1881 ServiceSwitchFile = newstr(val); 1882 break; 1883 1884 case O_DIALDELAY: /* delay for dial-on-demand operation */ 1885 DialDelay = convtime(val, 's'); 1886 break; 1887 1888 default: 1889 if (tTd(37, 1)) 1890 { 1891 if (isascii(opt) && isprint(opt)) 1892 printf("Warning: option %c unknown\n", opt); 1893 else 1894 printf("Warning: option 0x%x unknown\n", opt); 1895 } 1896 break; 1897 } 1898 if (sticky) 1899 setbitn(opt, StickyOpt); 1900 return; 1901 } 1902 /* 1903 ** SETCLASS -- set a word into a class 1904 ** 1905 ** Parameters: 1906 ** class -- the class to put the word in. 1907 ** word -- the word to enter 1908 ** 1909 ** Returns: 1910 ** none. 1911 ** 1912 ** Side Effects: 1913 ** puts the word into the symbol table. 1914 */ 1915 1916 setclass(class, word) 1917 int class; 1918 char *word; 1919 { 1920 register STAB *s; 1921 1922 if (tTd(37, 8)) 1923 printf("setclass(%c, %s)\n", class, word); 1924 s = stab(word, ST_CLASS, ST_ENTER); 1925 setbitn(class, s->s_class); 1926 } 1927 /* 1928 ** MAKEMAPENTRY -- create a map entry 1929 ** 1930 ** Parameters: 1931 ** line -- the config file line 1932 ** 1933 ** Returns: 1934 ** TRUE if it successfully entered the map entry. 1935 ** FALSE otherwise (usually syntax error). 1936 ** 1937 ** Side Effects: 1938 ** Enters the map into the dictionary. 1939 */ 1940 1941 void 1942 makemapentry(line) 1943 char *line; 1944 { 1945 register char *p; 1946 char *mapname; 1947 char *classname; 1948 register STAB *s; 1949 STAB *class; 1950 1951 for (p = line; isascii(*p) && isspace(*p); p++) 1952 continue; 1953 if (!(isascii(*p) && isalnum(*p))) 1954 { 1955 syserr("readcf: config K line: no map name"); 1956 return; 1957 } 1958 1959 mapname = p; 1960 while ((isascii(*++p) && isalnum(*p)) || *p == '.') 1961 continue; 1962 if (*p != '\0') 1963 *p++ = '\0'; 1964 while (isascii(*p) && isspace(*p)) 1965 p++; 1966 if (!(isascii(*p) && isalnum(*p))) 1967 { 1968 syserr("readcf: config K line, map %s: no map class", mapname); 1969 return; 1970 } 1971 classname = p; 1972 while (isascii(*++p) && isalnum(*p)) 1973 continue; 1974 if (*p != '\0') 1975 *p++ = '\0'; 1976 while (isascii(*p) && isspace(*p)) 1977 p++; 1978 1979 /* look up the class */ 1980 class = stab(classname, ST_MAPCLASS, ST_FIND); 1981 if (class == NULL) 1982 { 1983 syserr("readcf: map %s: class %s not available", mapname, classname); 1984 return; 1985 } 1986 1987 /* enter the map */ 1988 s = stab(mapname, ST_MAP, ST_ENTER); 1989 s->s_map.map_class = &class->s_mapclass; 1990 s->s_map.map_mname = newstr(mapname); 1991 1992 if (class->s_mapclass.map_parse(&s->s_map, p)) 1993 s->s_map.map_mflags |= MF_VALID; 1994 1995 if (tTd(37, 5)) 1996 { 1997 printf("map %s, class %s, flags %x, file %s,\n", 1998 s->s_map.map_mname, s->s_map.map_class->map_cname, 1999 s->s_map.map_mflags, 2000 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 2001 printf("\tapp %s, domain %s, rebuild %s\n", 2002 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 2003 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 2004 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 2005 } 2006 } 2007 /* 2008 ** INITTIMEOUTS -- parse and set timeout values 2009 ** 2010 ** Parameters: 2011 ** val -- a pointer to the values. If NULL, do initial 2012 ** settings. 2013 ** 2014 ** Returns: 2015 ** none. 2016 ** 2017 ** Side Effects: 2018 ** Initializes the TimeOuts structure 2019 */ 2020 2021 #define SECONDS 2022 #define MINUTES * 60 2023 #define HOUR * 3600 2024 2025 inittimeouts(val) 2026 register char *val; 2027 { 2028 register char *p; 2029 extern time_t convtime(); 2030 2031 if (val == NULL) 2032 { 2033 TimeOuts.to_initial = (time_t) 5 MINUTES; 2034 TimeOuts.to_helo = (time_t) 5 MINUTES; 2035 TimeOuts.to_mail = (time_t) 10 MINUTES; 2036 TimeOuts.to_rcpt = (time_t) 1 HOUR; 2037 TimeOuts.to_datainit = (time_t) 5 MINUTES; 2038 TimeOuts.to_datablock = (time_t) 1 HOUR; 2039 TimeOuts.to_datafinal = (time_t) 1 HOUR; 2040 TimeOuts.to_rset = (time_t) 5 MINUTES; 2041 TimeOuts.to_quit = (time_t) 2 MINUTES; 2042 TimeOuts.to_nextcommand = (time_t) 1 HOUR; 2043 TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2044 #if IDENTPROTO 2045 TimeOuts.to_ident = (time_t) 30 SECONDS; 2046 #else 2047 TimeOuts.to_ident = (time_t) 0 SECONDS; 2048 #endif 2049 TimeOuts.to_fileopen = (time_t) 60 SECONDS; 2050 return; 2051 } 2052 2053 for (;; val = p) 2054 { 2055 while (isascii(*val) && isspace(*val)) 2056 val++; 2057 if (*val == '\0') 2058 break; 2059 for (p = val; *p != '\0' && *p != ','; p++) 2060 continue; 2061 if (*p != '\0') 2062 *p++ = '\0'; 2063 2064 if (isascii(*val) && isdigit(*val)) 2065 { 2066 /* old syntax -- set everything */ 2067 TimeOuts.to_mail = convtime(val, 'm'); 2068 TimeOuts.to_rcpt = TimeOuts.to_mail; 2069 TimeOuts.to_datainit = TimeOuts.to_mail; 2070 TimeOuts.to_datablock = TimeOuts.to_mail; 2071 TimeOuts.to_datafinal = TimeOuts.to_mail; 2072 TimeOuts.to_nextcommand = TimeOuts.to_mail; 2073 continue; 2074 } 2075 else 2076 { 2077 register char *q = strchr(val, ':'); 2078 2079 if (q == NULL && (q = strchr(val, '=')) == NULL) 2080 { 2081 /* syntax error */ 2082 continue; 2083 } 2084 *q++ = '\0'; 2085 settimeout(val, q); 2086 } 2087 } 2088 } 2089 /* 2090 ** SETTIMEOUT -- set an individual timeout 2091 ** 2092 ** Parameters: 2093 ** name -- the name of the timeout. 2094 ** val -- the value of the timeout. 2095 ** 2096 ** Returns: 2097 ** none. 2098 */ 2099 2100 settimeout(name, val) 2101 char *name; 2102 char *val; 2103 { 2104 register char *p; 2105 time_t to; 2106 extern time_t convtime(); 2107 2108 to = convtime(val, 'm'); 2109 p = strchr(name, '.'); 2110 if (p != NULL) 2111 *p++ = '\0'; 2112 2113 if (strcasecmp(name, "initial") == 0) 2114 TimeOuts.to_initial = to; 2115 else if (strcasecmp(name, "mail") == 0) 2116 TimeOuts.to_mail = to; 2117 else if (strcasecmp(name, "rcpt") == 0) 2118 TimeOuts.to_rcpt = to; 2119 else if (strcasecmp(name, "datainit") == 0) 2120 TimeOuts.to_datainit = to; 2121 else if (strcasecmp(name, "datablock") == 0) 2122 TimeOuts.to_datablock = to; 2123 else if (strcasecmp(name, "datafinal") == 0) 2124 TimeOuts.to_datafinal = to; 2125 else if (strcasecmp(name, "command") == 0) 2126 TimeOuts.to_nextcommand = to; 2127 else if (strcasecmp(name, "rset") == 0) 2128 TimeOuts.to_rset = to; 2129 else if (strcasecmp(name, "helo") == 0) 2130 TimeOuts.to_helo = to; 2131 else if (strcasecmp(name, "quit") == 0) 2132 TimeOuts.to_quit = to; 2133 else if (strcasecmp(name, "misc") == 0) 2134 TimeOuts.to_miscshort = to; 2135 else if (strcasecmp(name, "ident") == 0) 2136 TimeOuts.to_ident = to; 2137 else if (strcasecmp(name, "fileopen") == 0) 2138 TimeOuts.to_fileopen = to; 2139 else if (strcasecmp(name, "queuewarn") == 0) 2140 { 2141 to = convtime(val, 'h'); 2142 if (p == NULL || strcmp(p, "*") == 0) 2143 { 2144 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2145 TimeOuts.to_q_warning[TOC_URGENT] = to; 2146 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2147 } 2148 else if (strcasecmp(p, "normal") == 0) 2149 TimeOuts.to_q_warning[TOC_NORMAL] = to; 2150 else if (strcasecmp(p, "urgent") == 0) 2151 TimeOuts.to_q_warning[TOC_URGENT] = to; 2152 else if (strcasecmp(p, "non-urgent") == 0) 2153 TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2154 else 2155 syserr("settimeout: invalid queuewarn subtimeout %s", p); 2156 } 2157 else if (strcasecmp(name, "queuereturn") == 0) 2158 { 2159 to = convtime(val, 'd'); 2160 if (p == NULL || strcmp(p, "*") == 0) 2161 { 2162 TimeOuts.to_q_return[TOC_NORMAL] = to; 2163 TimeOuts.to_q_return[TOC_URGENT] = to; 2164 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2165 } 2166 else if (strcasecmp(p, "normal") == 0) 2167 TimeOuts.to_q_return[TOC_NORMAL] = to; 2168 else if (strcasecmp(p, "urgent") == 0) 2169 TimeOuts.to_q_return[TOC_URGENT] = to; 2170 else if (strcasecmp(p, "non-urgent") == 0) 2171 TimeOuts.to_q_return[TOC_NONURGENT] = to; 2172 else 2173 syserr("settimeout: invalid queuereturn subtimeout %s", p); 2174 } 2175 else 2176 syserr("settimeout: invalid timeout %s", name); 2177 } 2178