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