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