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