readcf.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:74k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
  3.  * All rights reserved.
  4.  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  5.  * Copyright (c) 1988, 1993
  6.  * The Regents of the University of California.  All rights reserved.
  7.  *
  8.  * By using this file, you agree to the terms and conditions set
  9.  * forth in the LICENSE file which can be found at the top level of
  10.  * the sendmail distribution.
  11.  *
  12.  */
  13. #ifndef lint
  14. static char id[] = "@(#)$Id: readcf.c,v 8.362 1999/12/06 22:50:53 gshapiro Exp $";
  15. #endif /* ! lint */
  16. #include <sendmail.h>
  17. #if NETINET || NETINET6
  18. # include <arpa/inet.h>
  19. #endif /* NETINET || NETINET6 */
  20. #define SECONDS
  21. #define MINUTES * 60
  22. #define HOUR * 3600
  23. #define HOURS HOUR
  24. static void fileclass __P((int, char *, char *, bool, bool));
  25. static char **makeargv __P((char *));
  26. static void settimeout __P((char *, char *, bool));
  27. static void toomany __P((int, int));
  28. static char *munchstring __P((char *, char **, int));
  29. /*
  30. **  READCF -- read configuration file.
  31. **
  32. ** This routine reads the configuration file and builds the internal
  33. ** form.
  34. **
  35. ** The file is formatted as a sequence of lines, each taken
  36. ** atomically.  The first character of each line describes how
  37. ** the line is to be interpreted.  The lines are:
  38. ** Dxval Define macro x to have value val.
  39. ** Cxword Put word into class x.
  40. ** Fxfile [fmt] Read file for lines to put into
  41. ** class x.  Use scanf string 'fmt'
  42. ** or "%s" if not present.  Fmt should
  43. ** only produce one string-valued result.
  44. ** Hname: value Define header with field-name 'name'
  45. ** and value as specified; this will be
  46. ** macro expanded immediately before
  47. ** use.
  48. ** Sn Use rewriting set n.
  49. ** Rlhs rhs Rewrite addresses that match lhs to
  50. ** be rhs.
  51. ** Mn arg=val... Define mailer.  n is the internal name.
  52. ** Args specify mailer parameters.
  53. ** Oxvalue Set option x to value.
  54. ** Pname=value Set precedence name to value.
  55. ** Vversioncode[/vendorcode]
  56. ** Version level/vendor name of
  57. ** configuration syntax.
  58. ** Kmapname mapclass arguments....
  59. ** Define keyed lookup of a given class.
  60. ** Arguments are class dependent.
  61. ** Eenvar=value Set the environment value to the given value.
  62. **
  63. ** Parameters:
  64. ** cfname -- configuration file name.
  65. ** safe -- TRUE if this is the system config file;
  66. ** FALSE otherwise.
  67. ** e -- the main envelope.
  68. **
  69. ** Returns:
  70. ** none.
  71. **
  72. ** Side Effects:
  73. ** Builds several internal tables.
  74. */
  75. void
  76. readcf(cfname, safe, e)
  77. char *cfname;
  78. bool safe;
  79. register ENVELOPE *e;
  80. {
  81. FILE *cf;
  82. int ruleset = -1;
  83. char *q;
  84. struct rewrite *rwp = NULL;
  85. char *bp;
  86. auto char *ep;
  87. int nfuzzy;
  88. char *file;
  89. bool optional;
  90. int mid;
  91. int chompflags;
  92. register char *p;
  93. long sff = SFF_OPENASROOT;
  94. struct stat statb;
  95. char buf[MAXLINE];
  96. char exbuf[MAXLINE];
  97. char pvpbuf[MAXLINE + MAXATOM];
  98. static char *null_list[1] = { NULL };
  99. extern u_char TokTypeNoC[];
  100. FileName = cfname;
  101. LineNumber = 0;
  102. if (DontLockReadFiles)
  103. sff |= SFF_NOLOCK;
  104. cf = safefopen(cfname, O_RDONLY, 0444, sff);
  105. if (cf == NULL)
  106. {
  107. syserr("cannot open");
  108. finis(FALSE, EX_OSFILE);
  109. }
  110. if (fstat(fileno(cf), &statb) < 0)
  111. {
  112. syserr("cannot fstat");
  113. finis(FALSE, EX_OSFILE);
  114. }
  115. if (!S_ISREG(statb.st_mode))
  116. {
  117. syserr("not a plain file");
  118. finis(FALSE, EX_OSFILE);
  119. }
  120. if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
  121. {
  122. if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS)
  123. fprintf(stderr, "%s: WARNING: dangerous write permissionsn",
  124. FileName);
  125. if (LogLevel > 0)
  126. sm_syslog(LOG_CRIT, NOQID,
  127.   "%s: WARNING: dangerous write permissions",
  128.   FileName);
  129. }
  130. #ifdef XLA
  131. xla_zero();
  132. #endif /* XLA */
  133. while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL)
  134. {
  135. if (bp[0] == '#')
  136. {
  137. if (bp != buf)
  138. free(bp);
  139. continue;
  140. }
  141. /* do macro expansion mappings */
  142. translate_dollars(bp);
  143. /* interpret this line */
  144. errno = 0;
  145. switch (bp[0])
  146. {
  147.   case '':
  148.   case '#': /* comment */
  149. break;
  150.   case 'R': /* rewriting rule */
  151. if (ruleset < 0)
  152. {
  153. syserr("missing valid ruleset for "%s"", bp);
  154. break;
  155. }
  156. for (p = &bp[1]; *p != '' && *p != 't'; p++)
  157. continue;
  158. if (*p == '')
  159. {
  160. syserr("invalid rewrite line "%s" (tab expected)", bp);
  161. break;
  162. }
  163. /* allocate space for the rule header */
  164. if (rwp == NULL)
  165. {
  166. RewriteRules[ruleset] = rwp =
  167. (struct rewrite *) xalloc(sizeof *rwp);
  168. }
  169. else
  170. {
  171. rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
  172. rwp = rwp->r_next;
  173. }
  174. rwp->r_next = NULL;
  175. /* expand and save the LHS */
  176. *p = '';
  177. expand(&bp[1], exbuf, sizeof exbuf, e);
  178. rwp->r_lhs = prescan(exbuf, 't', pvpbuf,
  179.      sizeof pvpbuf, NULL,
  180.      ConfigLevel >= 9 ? TokTypeNoC : NULL);
  181. nfuzzy = 0;
  182. if (rwp->r_lhs != NULL)
  183. {
  184. register char **ap;
  185. rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
  186. /* count the number of fuzzy matches in LHS */
  187. for (ap = rwp->r_lhs; *ap != NULL; ap++)
  188. {
  189. char *botch;
  190. botch = NULL;
  191. switch (**ap & 0377)
  192. {
  193.   case MATCHZANY:
  194.   case MATCHANY:
  195.   case MATCHONE:
  196.   case MATCHCLASS:
  197.   case MATCHNCLASS:
  198. nfuzzy++;
  199. break;
  200.   case MATCHREPL:
  201. botch = "$0-$9";
  202. break;
  203.   case CANONUSER:
  204. botch = "$:";
  205. break;
  206.   case CALLSUBR:
  207. botch = "$>";
  208. break;
  209.   case CONDIF:
  210. botch = "$?";
  211. break;
  212.   case CONDFI:
  213. botch = "$.";
  214. break;
  215.   case HOSTBEGIN:
  216. botch = "$[";
  217. break;
  218.   case HOSTEND:
  219. botch = "$]";
  220. break;
  221.   case LOOKUPBEGIN:
  222. botch = "$(";
  223. break;
  224.   case LOOKUPEND:
  225. botch = "$)";
  226. break;
  227. }
  228. if (botch != NULL)
  229. syserr("Inappropriate use of %s on LHS",
  230. botch);
  231. }
  232. rwp->r_line = LineNumber;
  233. }
  234. else
  235. {
  236. syserr("R line: null LHS");
  237. rwp->r_lhs = null_list;
  238. }
  239. /* expand and save the RHS */
  240. while (*++p == 't')
  241. continue;
  242. q = p;
  243. while (*p != '' && *p != 't')
  244. p++;
  245. *p = '';
  246. expand(q, exbuf, sizeof exbuf, e);
  247. rwp->r_rhs = prescan(exbuf, 't', pvpbuf,
  248.      sizeof pvpbuf, NULL,
  249.      ConfigLevel >= 9 ? TokTypeNoC : NULL);
  250. if (rwp->r_rhs != NULL)
  251. {
  252. register char **ap;
  253. rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
  254. /* check no out-of-bounds replacements */
  255. nfuzzy += '0';
  256. for (ap = rwp->r_rhs; *ap != NULL; ap++)
  257. {
  258. char *botch;
  259. botch = NULL;
  260. switch (**ap & 0377)
  261. {
  262.   case MATCHREPL:
  263. if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy)
  264. {
  265. syserr("replacement $%c out of bounds",
  266. (*ap)[1]);
  267. }
  268. break;
  269.   case MATCHZANY:
  270. botch = "$*";
  271. break;
  272.   case MATCHANY:
  273. botch = "$+";
  274. break;
  275.   case MATCHONE:
  276. botch = "$-";
  277. break;
  278.   case MATCHCLASS:
  279. botch = "$=";
  280. break;
  281.   case MATCHNCLASS:
  282. botch = "$~";
  283. break;
  284. }
  285. if (botch != NULL)
  286. syserr("Inappropriate use of %s on RHS",
  287. botch);
  288. }
  289. }
  290. else
  291. {
  292. syserr("R line: null RHS");
  293. rwp->r_rhs = null_list;
  294. }
  295. break;
  296.   case 'S': /* select rewriting set */
  297. expand(&bp[1], exbuf, sizeof exbuf, e);
  298. ruleset = strtorwset(exbuf, NULL, ST_ENTER);
  299. if (ruleset < 0)
  300. break;
  301. rwp = RewriteRules[ruleset];
  302. if (rwp != NULL)
  303. {
  304. if (OpMode == MD_TEST)
  305. printf("WARNING: Ruleset %s has multiple definitionsn",
  306.        &bp[1]);
  307. if (tTd(37, 1))
  308. dprintf("WARNING: Ruleset %s has multiple definitionsn",
  309. &bp[1]);
  310. while (rwp->r_next != NULL)
  311. rwp = rwp->r_next;
  312. }
  313. break;
  314.   case 'D': /* macro definition */
  315. mid = macid(&bp[1], &ep);
  316. p = munchstring(ep, NULL, '');
  317. define(mid, newstr(p), e);
  318. break;
  319.   case 'H': /* required header line */
  320. chompflags = CHHDR_DEF;
  321. (void) chompheader(&bp[1], &chompflags, NULL, e);
  322. break;
  323.   case 'C': /* word class */
  324.   case 'T': /* trusted user (set class `t') */
  325. if (bp[0] == 'C')
  326. {
  327. mid = macid(&bp[1], &ep);
  328. expand(ep, exbuf, sizeof exbuf, e);
  329. p = exbuf;
  330. }
  331. else
  332. {
  333. mid = 't';
  334. p = &bp[1];
  335. }
  336. while (*p != '')
  337. {
  338. register char *wd;
  339. char delim;
  340. while (*p != '' && isascii(*p) && isspace(*p))
  341. p++;
  342. wd = p;
  343. while (*p != '' && !(isascii(*p) && isspace(*p)))
  344. p++;
  345. delim = *p;
  346. *p = '';
  347. if (wd[0] != '')
  348. setclass(mid, wd);
  349. *p = delim;
  350. }
  351. break;
  352.   case 'F': /* word class from file */
  353. mid = macid(&bp[1], &ep);
  354. for (p = ep; isascii(*p) && isspace(*p); )
  355. p++;
  356. if (p[0] == '-' && p[1] == 'o')
  357. {
  358. optional = TRUE;
  359. while (*p != '' && !(isascii(*p) && isspace(*p)))
  360. p++;
  361. while (isascii(*p) && isspace(*p))
  362. p++;
  363. }
  364. else
  365. optional = FALSE;
  366. file = p;
  367. if (*file == '|')
  368. p = "%s";
  369. else
  370. {
  371. while (*p != '' && !(isascii(*p) && isspace(*p)))
  372. p++;
  373. if (*p == '')
  374. p = "%s";
  375. else
  376. {
  377. *p = '';
  378. while (isascii(*++p) && isspace(*p))
  379. continue;
  380. }
  381. }
  382. fileclass(mid, file, p, safe, optional);
  383. break;
  384. #ifdef XLA
  385.   case 'L': /* extended load average description */
  386. xla_init(&bp[1]);
  387. break;
  388. #endif /* XLA */
  389. #if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO)
  390.   case 'L': /* lookup macro */
  391.   case 'G': /* lookup class */
  392. /* reserved for Sun -- NIS+ database lookup */
  393. if (VendorCode != VENDOR_SUN)
  394. goto badline;
  395. sun_lg_config_line(bp, e);
  396. break;
  397. #endif /* defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) */
  398.   case 'M': /* define mailer */
  399. makemailer(&bp[1]);
  400. break;
  401.   case 'O': /* set option */
  402. setoption(bp[1], &bp[2], safe, FALSE, e);
  403. break;
  404.   case 'P': /* set precedence */
  405. if (NumPriorities >= MAXPRIORITIES)
  406. {
  407. toomany('P', MAXPRIORITIES);
  408. break;
  409. }
  410. for (p = &bp[1]; *p != '' && *p != '='; p++)
  411. continue;
  412. if (*p == '')
  413. goto badline;
  414. *p = '';
  415. Priorities[NumPriorities].pri_name = newstr(&bp[1]);
  416. Priorities[NumPriorities].pri_val = atoi(++p);
  417. NumPriorities++;
  418. break;
  419.   case 'V': /* configuration syntax version */
  420. for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
  421. continue;
  422. if (!isascii(*p) || !isdigit(*p))
  423. {
  424. syserr("invalid argument to V line: "%.20s"",
  425. &bp[1]);
  426. break;
  427. }
  428. ConfigLevel = strtol(p, &ep, 10);
  429. /*
  430. **  Do heuristic tweaking for back compatibility.
  431. */
  432. if (ConfigLevel >= 5)
  433. {
  434. /* level 5 configs have short name in $w */
  435. p = macvalue('w', e);
  436. if (p != NULL && (p = strchr(p, '.')) != NULL)
  437. *p = '';
  438. define('w', macvalue('w', e), e);
  439. }
  440. if (ConfigLevel >= 6)
  441. {
  442. ColonOkInAddr = FALSE;
  443. }
  444. /*
  445. **  Look for vendor code.
  446. */
  447. if (*ep++ == '/')
  448. {
  449. /* extract vendor code */
  450. for (p = ep; isascii(*p) && isalpha(*p); )
  451. p++;
  452. *p = '';
  453. if (!setvendor(ep))
  454. syserr("invalid V line vendor code: "%s"",
  455. ep);
  456. }
  457. break;
  458.   case 'K':
  459. expand(&bp[1], exbuf, sizeof exbuf, e);
  460. (void) makemapentry(exbuf);
  461. break;
  462.   case 'E':
  463. p = strchr(bp, '=');
  464. if (p != NULL)
  465. *p++ = '';
  466. setuserenv(&bp[1], p);
  467. break;
  468.   default:
  469.   badline:
  470. syserr("unknown configuration line "%s"", bp);
  471. }
  472. if (bp != buf)
  473. free(bp);
  474. }
  475. if (ferror(cf))
  476. {
  477. syserr("I/O read error");
  478. finis(FALSE, EX_OSFILE);
  479. }
  480. (void) fclose(cf);
  481. FileName = NULL;
  482. /* initialize host maps from local service tables */
  483. inithostmaps();
  484. /* initialize daemon (if not defined yet) */
  485. initdaemon();
  486. /* determine if we need to do special name-server frotz */
  487. {
  488. int nmaps;
  489. char *maptype[MAXMAPSTACK];
  490. short mapreturn[MAXMAPACTIONS];
  491. nmaps = switch_map_find("hosts", maptype, mapreturn);
  492. UseNameServer = FALSE;
  493. if (nmaps > 0 && nmaps <= MAXMAPSTACK)
  494. {
  495. register int mapno;
  496. for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++)
  497. {
  498. if (strcmp(maptype[mapno], "dns") == 0)
  499. UseNameServer = TRUE;
  500. }
  501. }
  502. #ifdef HESIOD
  503. nmaps = switch_map_find("passwd", maptype, mapreturn);
  504. UseHesiod = FALSE;
  505. if (nmaps > 0 && nmaps <= MAXMAPSTACK)
  506. {
  507. register int mapno;
  508. for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++)
  509. {
  510. if (strcmp(maptype[mapno], "hesiod") == 0)
  511. UseHesiod = TRUE;
  512. }
  513. }
  514. #endif /* HESIOD */
  515. }
  516. }
  517. /*
  518. **  TRANSLATE_DOLLARS -- convert $x into internal form
  519. **
  520. ** Actually does all appropriate pre-processing of a config line
  521. ** to turn it into internal form.
  522. **
  523. ** Parameters:
  524. ** bp -- the buffer to translate.
  525. **
  526. ** Returns:
  527. ** None.  The buffer is translated in place.  Since the
  528. ** translations always make the buffer shorter, this is
  529. ** safe without a size parameter.
  530. */
  531. void
  532. translate_dollars(bp)
  533. char *bp;
  534. {
  535. register char *p;
  536. auto char *ep;
  537. for (p = bp; *p != ''; p++)
  538. {
  539. if (*p == '#' && p > bp && ConfigLevel >= 3)
  540. {
  541. /* this is an on-line comment */
  542. register char *e;
  543. switch (*--p & 0377)
  544. {
  545.   case MACROEXPAND:
  546. /* it's from $# -- let it go through */
  547. p++;
  548. break;
  549.   case '\':
  550. /* it's backslash escaped */
  551. (void) strlcpy(p, p + 1, strlen(p));
  552. break;
  553.   default:
  554. /* delete leading white space */
  555. while (isascii(*p) && isspace(*p) &&
  556.        *p != 'n' && p > bp)
  557. p--;
  558. if ((e = strchr(++p, 'n')) != NULL)
  559. (void) strlcpy(p, e, strlen(p));
  560. else
  561. *p-- = '';
  562. break;
  563. }
  564. continue;
  565. }
  566. if (*p != '$' || p[1] == '')
  567. continue;
  568. if (p[1] == '$')
  569. {
  570. /* actual dollar sign.... */
  571. (void) strlcpy(p, p + 1, strlen(p));
  572. continue;
  573. }
  574. /* convert to macro expansion character */
  575. *p++ = MACROEXPAND;
  576. /* special handling for $=, $~, $&, and $? */
  577. if (*p == '=' || *p == '~' || *p == '&' || *p == '?')
  578. p++;
  579. /* convert macro name to code */
  580. *p = macid(p, &ep);
  581. if (ep != p + 1)
  582. (void) strlcpy(p + 1, ep, strlen(p + 1));
  583. }
  584. /* strip trailing white space from the line */
  585. while (--p > bp && isascii(*p) && isspace(*p))
  586. *p = '';
  587. }
  588. /*
  589. **  TOOMANY -- signal too many of some option
  590. **
  591. ** Parameters:
  592. ** id -- the id of the error line
  593. ** maxcnt -- the maximum possible values
  594. **
  595. ** Returns:
  596. ** none.
  597. **
  598. ** Side Effects:
  599. ** gives a syserr.
  600. */
  601. static void
  602. toomany(id, maxcnt)
  603. int id;
  604. int maxcnt;
  605. {
  606. syserr("too many %c lines, %d max", id, maxcnt);
  607. }
  608. /*
  609. **  FILECLASS -- read members of a class from a file
  610. **
  611. ** Parameters:
  612. ** class -- class to define.
  613. ** filename -- name of file to read.
  614. ** fmt -- scanf string to use for match.
  615. ** safe -- if set, this is a safe read.
  616. ** optional -- if set, it is not an error for the file to
  617. ** not exist.
  618. **
  619. ** Returns:
  620. ** none
  621. **
  622. ** Side Effects:
  623. **
  624. ** puts all lines in filename that match a scanf into
  625. ** the named class.
  626. */
  627. static void
  628. fileclass(class, filename, fmt, safe, optional)
  629. int class;
  630. char *filename;
  631. char *fmt;
  632. bool safe;
  633. bool optional;
  634. {
  635. FILE *f;
  636. long sff;
  637. pid_t pid;
  638. register char *p;
  639. char buf[MAXLINE];
  640. if (tTd(37, 2))
  641. dprintf("fileclass(%s, fmt=%s)n", filename, fmt);
  642. if (filename[0] == '|')
  643. {
  644. auto int fd;
  645. int i;
  646. char *argv[MAXPV + 1];
  647. i = 0;
  648. for (p = strtok(&filename[1], " t"); p != NULL; p = strtok(NULL, " t"))
  649. {
  650. if (i >= MAXPV)
  651. break;
  652. argv[i++] = p;
  653. }
  654. argv[i] = NULL;
  655. pid = prog_open(argv, &fd, CurEnv);
  656. if (pid < 0)
  657. f = NULL;
  658. else
  659. f = fdopen(fd, "r");
  660. }
  661. else
  662. {
  663. pid = -1;
  664. sff = SFF_REGONLY;
  665. if (!bitnset(DBS_CLASSFILEINUNSAFEDIRPATH, DontBlameSendmail))
  666. sff |= SFF_SAFEDIRPATH;
  667. if (!bitnset(DBS_LINKEDCLASSFILEINWRITABLEDIR,
  668.      DontBlameSendmail))
  669. sff |= SFF_NOWLINK;
  670. if (safe)
  671. sff |= SFF_OPENASROOT;
  672. if (DontLockReadFiles)
  673. sff |= SFF_NOLOCK;
  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. while (fgets(buf, sizeof buf, f) != NULL)
  683. {
  684. #if SCANF
  685. char wordbuf[MAXLINE + 1];
  686. #endif /* SCANF */
  687. if (buf[0] == '#')
  688. continue;
  689. #if SCANF
  690. if (sscanf(buf, fmt, wordbuf) != 1)
  691. continue;
  692. p = wordbuf;
  693. #else /* SCANF */
  694. p = buf;
  695. #endif /* SCANF */
  696. /*
  697. **  Break up the match into words.
  698. */
  699. while (*p != '')
  700. {
  701. register char *q;
  702. /* strip leading spaces */
  703. while (isascii(*p) && isspace(*p))
  704. p++;
  705. if (*p == '')
  706. break;
  707. /* find the end of the word */
  708. q = p;
  709. while (*p != '' && !(isascii(*p) && isspace(*p)))
  710. p++;
  711. if (*p != '')
  712. *p++ = '';
  713. /* enter the word in the symbol table */
  714. setclass(class, q);
  715. }
  716. }
  717. (void) fclose(f);
  718. if (pid > 0)
  719. (void) waitfor(pid);
  720. }
  721. /*
  722. **  MAKEMAILER -- define a new mailer.
  723. **
  724. ** Parameters:
  725. ** line -- description of mailer.  This is in labeled
  726. ** fields.  The fields are:
  727. **    A -- the argv for this mailer
  728. **    C -- the character set for MIME conversions
  729. **    D -- the directory to run in
  730. **    E -- the eol string
  731. **    F -- the flags associated with the mailer
  732. **    L -- the maximum line length
  733. **    M -- the maximum message size
  734. **    N -- the niceness at which to run
  735. **    P -- the path to the mailer
  736. **    R -- the recipient rewriting set
  737. **    S -- the sender rewriting set
  738. **    T -- the mailer type (for DSNs)
  739. **    U -- the uid to run as
  740. **    W -- the time to wait at the end
  741. ** The first word is the canonical name of the mailer.
  742. **
  743. ** Returns:
  744. ** none.
  745. **
  746. ** Side Effects:
  747. ** enters the mailer into the mailer table.
  748. */
  749. void
  750. makemailer(line)
  751. char *line;
  752. {
  753. register char *p;
  754. register struct mailer *m;
  755. register STAB *s;
  756. int i;
  757. char fcode;
  758. auto char *endp;
  759. extern int NextMailer;
  760. /* allocate a mailer and set up defaults */
  761. m = (struct mailer *) xalloc(sizeof *m);
  762. memset((char *) m, '', sizeof *m);
  763. /* collect the mailer name */
  764. for (p = line; *p != '' && *p != ',' && !(isascii(*p) && isspace(*p)); p++)
  765. continue;
  766. if (*p != '')
  767. *p++ = '';
  768. if (line[0] == '')
  769. syserr("name required for mailer");
  770. m->m_name = newstr(line);
  771. /* now scan through and assign info from the fields */
  772. while (*p != '')
  773. {
  774. auto char *delimptr;
  775. while (*p != '' && (*p == ',' || (isascii(*p) && isspace(*p))))
  776. p++;
  777. /* p now points to field code */
  778. fcode = *p;
  779. while (*p != '' && *p != '=' && *p != ',')
  780. p++;
  781. if (*p++ != '=')
  782. {
  783. syserr("mailer %s: `=' expected", m->m_name);
  784. return;
  785. }
  786. while (isascii(*p) && isspace(*p))
  787. p++;
  788. /* p now points to the field body */
  789. p = munchstring(p, &delimptr, ',');
  790. /* install the field into the mailer struct */
  791. switch (fcode)
  792. {
  793.   case 'P': /* pathname */
  794. if (*p == '')
  795. syserr("mailer %s: empty path name", m->m_name);
  796. m->m_mailer = newstr(p);
  797. break;
  798.   case 'F': /* flags */
  799. for (; *p != ''; p++)
  800. if (!(isascii(*p) && isspace(*p)))
  801. setbitn(*p, m->m_flags);
  802. break;
  803.   case 'S': /* sender rewriting ruleset */
  804.   case 'R': /* recipient rewriting ruleset */
  805. i = strtorwset(p, &endp, ST_ENTER);
  806. if (i < 0)
  807. return;
  808. if (fcode == 'S')
  809. m->m_sh_rwset = m->m_se_rwset = i;
  810. else
  811. m->m_rh_rwset = m->m_re_rwset = i;
  812. p = endp;
  813. if (*p++ == '/')
  814. {
  815. i = strtorwset(p, NULL, ST_ENTER);
  816. if (i < 0)
  817. return;
  818. if (fcode == 'S')
  819. m->m_sh_rwset = i;
  820. else
  821. m->m_rh_rwset = i;
  822. }
  823. break;
  824.   case 'E': /* end of line string */
  825. if (*p == '')
  826. syserr("mailer %s: null end-of-line string",
  827. m->m_name);
  828. m->m_eol = newstr(p);
  829. break;
  830.   case 'A': /* argument vector */
  831. if (*p == '')
  832. syserr("mailer %s: null argument vector",
  833. m->m_name);
  834. m->m_argv = makeargv(p);
  835. break;
  836.   case 'M': /* maximum message size */
  837. m->m_maxsize = atol(p);
  838. break;
  839.   case 'm': /* maximum messages per connection */
  840. m->m_maxdeliveries = atoi(p);
  841. break;
  842.   case 'L': /* maximum line length */
  843. m->m_linelimit = atoi(p);
  844. if (m->m_linelimit < 0)
  845. m->m_linelimit = 0;
  846. break;
  847.   case 'N': /* run niceness */
  848. m->m_nice = atoi(p);
  849. break;
  850.   case 'D': /* working directory */
  851. if (*p == '')
  852. syserr("mailer %s: null working directory",
  853. m->m_name);
  854. m->m_execdir = newstr(p);
  855. break;
  856.   case 'C': /* default charset */
  857. if (*p == '')
  858. syserr("mailer %s: null charset", m->m_name);
  859. m->m_defcharset = newstr(p);
  860. break;
  861.   case 'T': /* MTA-Name/Address/Diagnostic types */
  862. /* extract MTA name type; default to "dns" */
  863. m->m_mtatype = newstr(p);
  864. p = strchr(m->m_mtatype, '/');
  865. if (p != NULL)
  866. {
  867. *p++ = '';
  868. if (*p == '')
  869. p = NULL;
  870. }
  871. if (*m->m_mtatype == '')
  872. m->m_mtatype = "dns";
  873. /* extract address type; default to "rfc822" */
  874. m->m_addrtype = p;
  875. if (p != NULL)
  876. p = strchr(p, '/');
  877. if (p != NULL)
  878. {
  879. *p++ = '';
  880. if (*p == '')
  881. p = NULL;
  882. }
  883. if (m->m_addrtype == NULL || *m->m_addrtype == '')
  884. m->m_addrtype = "rfc822";
  885. /* extract diagnostic type; default to "smtp" */
  886. m->m_diagtype = p;
  887. if (m->m_diagtype == NULL || *m->m_diagtype == '')
  888. m->m_diagtype = "smtp";
  889. break;
  890.   case 'U': /* user id */
  891. if (isascii(*p) && !isdigit(*p))
  892. {
  893. char *q = p;
  894. struct passwd *pw;
  895. while (*p != '' && isascii(*p) &&
  896.        (isalnum(*p) || strchr("-_", *p) != NULL))
  897. p++;
  898. while (isascii(*p) && isspace(*p))
  899. *p++ = '';
  900. if (*p != '')
  901. *p++ = '';
  902. if (*q == '')
  903. syserr("mailer %s: null user name",
  904. m->m_name);
  905. pw = sm_getpwnam(q);
  906. if (pw == NULL)
  907. syserr("readcf: mailer U= flag: unknown user %s", q);
  908. else
  909. {
  910. m->m_uid = pw->pw_uid;
  911. m->m_gid = pw->pw_gid;
  912. }
  913. }
  914. else
  915. {
  916. auto char *q;
  917. m->m_uid = strtol(p, &q, 0);
  918. p = q;
  919. while (isascii(*p) && isspace(*p))
  920. p++;
  921. if (*p != '')
  922. p++;
  923. }
  924. while (isascii(*p) && isspace(*p))
  925. p++;
  926. if (*p == '')
  927. break;
  928. if (isascii(*p) && !isdigit(*p))
  929. {
  930. char *q = p;
  931. struct group *gr;
  932. while (isascii(*p) && isalnum(*p))
  933. p++;
  934. *p++ = '';
  935. if (*q == '')
  936. syserr("mailer %s: null group name",
  937. m->m_name);
  938. gr = getgrnam(q);
  939. if (gr == NULL)
  940. syserr("readcf: mailer U= flag: unknown group %s", q);
  941. else
  942. m->m_gid = gr->gr_gid;
  943. }
  944. else
  945. {
  946. m->m_gid = strtol(p, NULL, 0);
  947. }
  948. break;
  949.   case 'W': /* wait timeout */
  950. m->m_wait = convtime(p, 's');
  951. break;
  952.   case '/': /* new root directory */
  953. if (*p == '')
  954. syserr("mailer %s: null root directory",
  955. m->m_name);
  956. else
  957. m->m_rootdir = newstr(p);
  958. break;
  959.   default:
  960. syserr("M%s: unknown mailer equate %c=",
  961.        m->m_name, fcode);
  962. break;
  963. }
  964. p = delimptr;
  965. }
  966. /* do some rationality checking */
  967. if (m->m_argv == NULL)
  968. {
  969. syserr("M%s: A= argument required", m->m_name);
  970. return;
  971. }
  972. if (m->m_mailer == NULL)
  973. {
  974. syserr("M%s: P= argument required", m->m_name);
  975. return;
  976. }
  977. if (NextMailer >= MAXMAILERS)
  978. {
  979. syserr("too many mailers defined (%d max)", MAXMAILERS);
  980. return;
  981. }
  982. /* do some heuristic cleanup for back compatibility */
  983. if (bitnset(M_LIMITS, m->m_flags))
  984. {
  985. if (m->m_linelimit == 0)
  986. m->m_linelimit = SMTPLINELIM;
  987. if (ConfigLevel < 2)
  988. setbitn(M_7BITS, m->m_flags);
  989. }
  990. if (strcmp(m->m_mailer, "[TCP]") == 0)
  991. {
  992. #if _FFR_REMOVE_TCP_PATH
  993. syserr("M%s: P=[TCP] is deprecated, use P=[IPC] insteadn",
  994.        m->m_name);
  995. #else /* _FFR_REMOVE_TCP_PATH */
  996. printf("M%s: Warning: P=[TCP] is deprecated, use P=[IPC] insteadn",
  997.        m->m_name);
  998. #endif /* _FFR_REMOVE_TCP_PATH */
  999. }
  1000. if (strcmp(m->m_mailer, "[IPC]") == 0 ||
  1001. #if !_FFR_REMOVE_TCP_MAILER_PATH
  1002.     strcmp(m->m_mailer, "[TCP]") == 0
  1003. #endif /* !_FFR_REMOVE_TCP_MAILER_PATH */
  1004.     )
  1005. {
  1006. /* Use the second argument for host or path to socket */
  1007. if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
  1008.     m->m_argv[1][0] == '')
  1009. {
  1010. syserr("M%s: too few parameters for %s mailer",
  1011.        m->m_name, m->m_mailer);
  1012. }
  1013. if (strcmp(m->m_argv[0], "TCP") != 0 &&
  1014. #if NETUNIX
  1015.     strcmp(m->m_argv[0], "FILE") != 0 &&
  1016. #endif /* NETUNIX */
  1017. #if !_FFR_DEPRECATE_IPC_MAILER_ARG
  1018.     strcmp(m->m_argv[0], "IPC") != 0
  1019. #endif /* !_FFR_DEPRECATE_IPC_MAILER_ARG */
  1020.     )
  1021. {
  1022. printf("M%s: Warning: first argument in %s mailer must be %sn",
  1023.        m->m_name, m->m_mailer,
  1024. #if NETUNIX
  1025.        "TCP or FILE"
  1026. #else /* NETUNIX */
  1027.        "TCP"
  1028. #endif /* NETUNIX */
  1029.        );
  1030. }
  1031. }
  1032. else if (strcmp(m->m_mailer, "[FILE]") == 0)
  1033. {
  1034. /* Use the second argument for filename */
  1035. if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
  1036.     m->m_argv[2] != NULL)
  1037. {
  1038. syserr("M%s: too %s parameters for [FILE] mailer",
  1039.        m->m_name,
  1040.        (m->m_argv[0] == NULL ||
  1041. m->m_argv[1] == NULL) ? "few" : "many");
  1042. }
  1043. else if (strcmp(m->m_argv[0], "FILE") != 0)
  1044. {
  1045. syserr("M%s: first argument in [FILE] mailer must be FILE",
  1046.        m->m_name);
  1047. }
  1048. }
  1049. if (strcmp(m->m_mailer, "[IPC]") == 0 ||
  1050.     strcmp(m->m_mailer, "[TCP]") == 0)
  1051. {
  1052. if (m->m_mtatype == NULL)
  1053. m->m_mtatype = "dns";
  1054. if (m->m_addrtype == NULL)
  1055. m->m_addrtype = "rfc822";
  1056. if (m->m_diagtype == NULL)
  1057. {
  1058. if (m->m_argv[0] != NULL &&
  1059.     strcmp(m->m_argv[0], "FILE") == 0)
  1060. m->m_diagtype = "x-unix";
  1061. else
  1062. m->m_diagtype = "smtp";
  1063. }
  1064. }
  1065. if (m->m_eol == NULL)
  1066. {
  1067. char **pp;
  1068. /* default for SMTP is rn; use n for local delivery */
  1069. for (pp = m->m_argv; *pp != NULL; pp++)
  1070. {
  1071. for (p = *pp; *p != ''; )
  1072. {
  1073. if ((*p++ & 0377) == MACROEXPAND && *p == 'u')
  1074. break;
  1075. }
  1076. if (*p != '')
  1077. break;
  1078. }
  1079. if (*pp == NULL)
  1080. m->m_eol = "rn";
  1081. else
  1082. m->m_eol = "n";
  1083. }
  1084. /* enter the mailer into the symbol table */
  1085. s = stab(m->m_name, ST_MAILER, ST_ENTER);
  1086. if (s->s_mailer != NULL)
  1087. {
  1088. i = s->s_mailer->m_mno;
  1089. free(s->s_mailer);
  1090. }
  1091. else
  1092. {
  1093. i = NextMailer++;
  1094. }
  1095. Mailer[i] = s->s_mailer = m;
  1096. m->m_mno = i;
  1097. }
  1098. /*
  1099. **  MUNCHSTRING -- translate a string into internal form.
  1100. **
  1101. ** Parameters:
  1102. ** p -- the string to munch.
  1103. ** delimptr -- if non-NULL, set to the pointer of the
  1104. ** field delimiter character.
  1105. ** delim -- the delimiter for the field.
  1106. **
  1107. ** Returns:
  1108. ** the munched string.
  1109. */
  1110. static char *
  1111. munchstring(p, delimptr, delim)
  1112. register char *p;
  1113. char **delimptr;
  1114. int delim;
  1115. {
  1116. register char *q;
  1117. bool backslash = FALSE;
  1118. bool quotemode = FALSE;
  1119. static char buf[MAXLINE];
  1120. for (q = buf; *p != '' && q < &buf[sizeof buf - 1]; p++)
  1121. {
  1122. if (backslash)
  1123. {
  1124. /* everything is roughly literal */
  1125. backslash = FALSE;
  1126. switch (*p)
  1127. {
  1128.   case 'r': /* carriage return */
  1129. *q++ = 'r';
  1130. continue;
  1131.   case 'n': /* newline */
  1132. *q++ = 'n';
  1133. continue;
  1134.   case 'f': /* form feed */
  1135. *q++ = 'f';
  1136. continue;
  1137.   case 'b': /* backspace */
  1138. *q++ = 'b';
  1139. continue;
  1140. }
  1141. *q++ = *p;
  1142. }
  1143. else
  1144. {
  1145. if (*p == '\')
  1146. backslash = TRUE;
  1147. else if (*p == '"')
  1148. quotemode = !quotemode;
  1149. else if (quotemode || *p != delim)
  1150. *q++ = *p;
  1151. else
  1152. break;
  1153. }
  1154. }
  1155. if (delimptr != NULL)
  1156. *delimptr = p;
  1157. *q++ = '';
  1158. return buf;
  1159. }
  1160. /*
  1161. **  MAKEARGV -- break up a string into words
  1162. **
  1163. ** Parameters:
  1164. ** p -- the string to break up.
  1165. **
  1166. ** Returns:
  1167. ** a char **argv (dynamically allocated)
  1168. **
  1169. ** Side Effects:
  1170. ** munges p.
  1171. */
  1172. static char **
  1173. makeargv(p)
  1174. register char *p;
  1175. {
  1176. char *q;
  1177. int i;
  1178. char **avp;
  1179. char *argv[MAXPV + 1];
  1180. /* take apart the words */
  1181. i = 0;
  1182. while (*p != '' && i < MAXPV)
  1183. {
  1184. q = p;
  1185. while (*p != '' && !(isascii(*p) && isspace(*p)))
  1186. p++;
  1187. while (isascii(*p) && isspace(*p))
  1188. *p++ = '';
  1189. argv[i++] = newstr(q);
  1190. }
  1191. argv[i++] = NULL;
  1192. /* now make a copy of the argv */
  1193. avp = (char **) xalloc(sizeof *avp * i);
  1194. memmove((char *) avp, (char *) argv, sizeof *avp * i);
  1195. return avp;
  1196. }
  1197. /*
  1198. **  PRINTRULES -- print rewrite rules (for debugging)
  1199. **
  1200. ** Parameters:
  1201. ** none.
  1202. **
  1203. ** Returns:
  1204. ** none.
  1205. **
  1206. ** Side Effects:
  1207. ** prints rewrite rules.
  1208. */
  1209. void
  1210. printrules()
  1211. {
  1212. register struct rewrite *rwp;
  1213. register int ruleset;
  1214. for (ruleset = 0; ruleset < 10; ruleset++)
  1215. {
  1216. if (RewriteRules[ruleset] == NULL)
  1217. continue;
  1218. printf("n----Rule Set %d:", ruleset);
  1219. for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
  1220. {
  1221. printf("nLHS:");
  1222. printav(rwp->r_lhs);
  1223. printf("RHS:");
  1224. printav(rwp->r_rhs);
  1225. }
  1226. }
  1227. }
  1228. /*
  1229. **  PRINTMAILER -- print mailer structure (for debugging)
  1230. **
  1231. ** Parameters:
  1232. ** m -- the mailer to print
  1233. **
  1234. ** Returns:
  1235. ** none.
  1236. */
  1237. void
  1238. printmailer(m)
  1239. register MAILER *m;
  1240. {
  1241. int j;
  1242. printf("mailer %d (%s): P=%s S=", m->m_mno, m->m_name, m->m_mailer);
  1243. if (RuleSetNames[m->m_se_rwset] == NULL)
  1244. printf("%d/", m->m_se_rwset);
  1245. else
  1246. printf("%s/", RuleSetNames[m->m_se_rwset]);
  1247. if (RuleSetNames[m->m_sh_rwset] == NULL)
  1248. printf("%d R=", m->m_sh_rwset);
  1249. else
  1250. printf("%s R=", RuleSetNames[m->m_sh_rwset]);
  1251. if (RuleSetNames[m->m_re_rwset] == NULL)
  1252. printf("%d/", m->m_re_rwset);
  1253. else
  1254. printf("%s/", RuleSetNames[m->m_re_rwset]);
  1255. if (RuleSetNames[m->m_rh_rwset] == NULL)
  1256. printf("%d ", m->m_rh_rwset);
  1257. else
  1258. printf("%s ", RuleSetNames[m->m_rh_rwset]);
  1259. printf("M=%ld U=%d:%d F=", m->m_maxsize,
  1260.        (int) m->m_uid, (int) m->m_gid);
  1261. for (j = ''; j <= '177'; j++)
  1262. if (bitnset(j, m->m_flags))
  1263. (void) putchar(j);
  1264. printf(" L=%d E=", m->m_linelimit);
  1265. xputs(m->m_eol);
  1266. if (m->m_defcharset != NULL)
  1267. printf(" C=%s", m->m_defcharset);
  1268. printf(" T=%s/%s/%s",
  1269. m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype,
  1270. m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype,
  1271. m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype);
  1272. if (m->m_argv != NULL)
  1273. {
  1274. char **a = m->m_argv;
  1275. printf(" A=");
  1276. while (*a != NULL)
  1277. {
  1278. if (a != m->m_argv)
  1279. printf(" ");
  1280. xputs(*a++);
  1281. }
  1282. }
  1283. printf("n");
  1284. }
  1285. /*
  1286. **  SETOPTION -- set global processing option
  1287. **
  1288. ** Parameters:
  1289. ** opt -- option name.
  1290. ** val -- option value (as a text string).
  1291. ** safe -- set if this came from a configuration file.
  1292. ** Some options (if set from the command line) will
  1293. ** reset the user id to avoid security problems.
  1294. ** sticky -- if set, don't let other setoptions override
  1295. ** this value.
  1296. ** e -- the main envelope.
  1297. **
  1298. ** Returns:
  1299. ** none.
  1300. **
  1301. ** Side Effects:
  1302. ** Sets options as implied by the arguments.
  1303. */
  1304. static BITMAP256 StickyOpt; /* set if option is stuck */
  1305. #if NAMED_BIND
  1306. static struct resolverflags
  1307. {
  1308. char *rf_name; /* name of the flag */
  1309. long rf_bits; /* bits to set/clear */
  1310. } ResolverFlags[] =
  1311. {
  1312. { "debug", RES_DEBUG },
  1313. { "aaonly", RES_AAONLY },
  1314. { "usevc", RES_USEVC },
  1315. { "primary", RES_PRIMARY },
  1316. { "igntc", RES_IGNTC },
  1317. { "recurse", RES_RECURSE },
  1318. { "defnames", RES_DEFNAMES },
  1319. { "stayopen", RES_STAYOPEN },
  1320. { "dnsrch", RES_DNSRCH },
  1321. { "true", 0 }, /* avoid error on old syntax */
  1322. { NULL, 0 }
  1323. };
  1324. #endif /* NAMED_BIND */
  1325. #define OI_NONE 0 /* no special treatment */
  1326. #define OI_SAFE 0x0001 /* safe for random people to use */
  1327. #define OI_SUBOPT 0x0002 /* option has suboptions */
  1328. static struct optioninfo
  1329. {
  1330. char *o_name; /* long name of option */
  1331. u_char o_code; /* short name of option */
  1332. u_short o_flags; /* option flags */
  1333. } OptionTab[] =
  1334. {
  1335. #if defined(SUN_EXTENSIONS) && defined(REMOTE_MODE)
  1336. { "RemoteMode", '>', OI_NONE },
  1337. #endif /* defined(SUN_EXTENSIONS) && defined(REMOTE_MODE) */
  1338. { "SevenBitInput", '7', OI_SAFE },
  1339. #if MIME8TO7
  1340. { "EightBitMode", '8', OI_SAFE },
  1341. #endif /* MIME8TO7 */
  1342. { "AliasFile", 'A', OI_NONE },
  1343. { "AliasWait", 'a', OI_NONE },
  1344. { "BlankSub", 'B', OI_NONE },
  1345. { "MinFreeBlocks", 'b', OI_SAFE },
  1346. { "CheckpointInterval", 'C', OI_SAFE },
  1347. { "HoldExpensive", 'c', OI_NONE },
  1348. #if !_FFR_REMOVE_AUTOREBUILD
  1349. { "AutoRebuildAliases", 'D', OI_NONE },
  1350. #endif /* !_FFR_REMOVE_AUTOREBUILD */
  1351. { "DeliveryMode", 'd', OI_SAFE },
  1352. { "ErrorHeader", 'E', OI_NONE },
  1353. { "ErrorMode", 'e', OI_SAFE },
  1354. { "TempFileMode", 'F', OI_NONE },
  1355. { "SaveFromLine", 'f', OI_NONE },
  1356. { "MatchGECOS", 'G', OI_NONE },
  1357. { "HelpFile", 'H', OI_NONE },
  1358. { "MaxHopCount", 'h', OI_NONE },
  1359. { "ResolverOptions", 'I', OI_NONE },
  1360. { "IgnoreDots", 'i', OI_SAFE },
  1361. { "ForwardPath", 'J', OI_NONE },
  1362. { "SendMimeErrors", 'j', OI_SAFE },
  1363. { "ConnectionCacheSize", 'k', OI_NONE },
  1364. { "ConnectionCacheTimeout", 'K', OI_NONE },
  1365. { "UseErrorsTo", 'l', OI_NONE },
  1366. { "LogLevel", 'L', OI_SAFE },
  1367. { "MeToo", 'm', OI_SAFE },
  1368. { "CheckAliases", 'n', OI_NONE },
  1369. { "OldStyleHeaders", 'o', OI_SAFE },
  1370. { "DaemonPortOptions", 'O', OI_NONE },
  1371. { "PrivacyOptions", 'p', OI_SAFE },
  1372. { "PostmasterCopy", 'P', OI_NONE },
  1373. { "QueueFactor", 'q', OI_NONE },
  1374. { "QueueDirectory", 'Q', OI_NONE },
  1375. { "DontPruneRoutes", 'R', OI_NONE },
  1376. { "Timeout", 'r', OI_SUBOPT },
  1377. { "StatusFile", 'S', OI_NONE },
  1378. { "SuperSafe", 's', OI_SAFE },
  1379. { "QueueTimeout", 'T', OI_NONE },
  1380. { "TimeZoneSpec", 't', OI_NONE },
  1381. { "UserDatabaseSpec", 'U', OI_NONE },
  1382. { "DefaultUser", 'u', OI_NONE },
  1383. { "FallbackMXhost", 'V', OI_NONE },
  1384. { "Verbose", 'v', OI_SAFE },
  1385. { "TryNullMXList", 'w', OI_NONE },
  1386. { "QueueLA", 'x', OI_NONE },
  1387. { "RefuseLA", 'X', OI_NONE },
  1388. { "RecipientFactor", 'y', OI_NONE },
  1389. { "ForkEachJob", 'Y', OI_NONE },
  1390. { "ClassFactor", 'z', OI_NONE },
  1391. { "RetryFactor", 'Z', OI_NONE },
  1392. #define O_QUEUESORTORD 0x81
  1393. { "QueueSortOrder", O_QUEUESORTORD, OI_SAFE },
  1394. #define O_HOSTSFILE 0x82
  1395. { "HostsFile", O_HOSTSFILE, OI_NONE },
  1396. #define O_MQA 0x83
  1397. { "MinQueueAge", O_MQA, OI_SAFE },
  1398. #define O_DEFCHARSET 0x85
  1399. { "DefaultCharSet", O_DEFCHARSET, OI_SAFE },
  1400. #define O_SSFILE 0x86
  1401. { "ServiceSwitchFile", O_SSFILE, OI_NONE },
  1402. #define O_DIALDELAY 0x87
  1403. { "DialDelay", O_DIALDELAY, OI_SAFE },
  1404. #define O_NORCPTACTION 0x88
  1405. { "NoRecipientAction", O_NORCPTACTION, OI_SAFE },
  1406. #define O_SAFEFILEENV 0x89
  1407. { "SafeFileEnvironment", O_SAFEFILEENV, OI_NONE },
  1408. #define O_MAXMSGSIZE 0x8a
  1409. { "MaxMessageSize", O_MAXMSGSIZE, OI_NONE },
  1410. #define O_COLONOKINADDR 0x8b
  1411. { "ColonOkInAddr", O_COLONOKINADDR, OI_SAFE },
  1412. #define O_MAXQUEUERUN 0x8c
  1413. { "MaxQueueRunSize", O_MAXQUEUERUN, OI_SAFE },
  1414. #define O_MAXCHILDREN 0x8d
  1415. { "MaxDaemonChildren", O_MAXCHILDREN, OI_NONE },
  1416. #define O_KEEPCNAMES 0x8e
  1417. { "DontExpandCnames", O_KEEPCNAMES, OI_NONE },
  1418. #define O_MUSTQUOTE 0x8f
  1419. { "MustQuoteChars", O_MUSTQUOTE, OI_NONE },
  1420. #define O_SMTPGREETING 0x90
  1421. { "SmtpGreetingMessage", O_SMTPGREETING, OI_NONE },
  1422. #define O_UNIXFROM 0x91
  1423. { "UnixFromLine", O_UNIXFROM, OI_NONE },
  1424. #define O_OPCHARS 0x92
  1425. { "OperatorChars", O_OPCHARS, OI_NONE },
  1426. #define O_DONTINITGRPS 0x93
  1427. { "DontInitGroups", O_DONTINITGRPS, OI_NONE },
  1428. #define O_SLFH 0x94
  1429. { "SingleLineFromHeader", O_SLFH, OI_SAFE },
  1430. #define O_ABH 0x95
  1431. { "AllowBogusHELO", O_ABH, OI_SAFE },
  1432. #define O_CONNTHROT 0x97
  1433. { "ConnectionRateThrottle", O_CONNTHROT, OI_NONE },
  1434. #define O_UGW 0x99
  1435. { "UnsafeGroupWrites", O_UGW, OI_NONE },
  1436. #define O_DBLBOUNCE 0x9a
  1437. { "DoubleBounceAddress", O_DBLBOUNCE, OI_NONE },
  1438. #define O_HSDIR 0x9b
  1439. { "HostStatusDirectory", O_HSDIR, OI_NONE },
  1440. #define O_SINGTHREAD 0x9c
  1441. { "SingleThreadDelivery", O_SINGTHREAD, OI_NONE },
  1442. #define O_RUNASUSER 0x9d
  1443. { "RunAsUser", O_RUNASUSER, OI_NONE },
  1444. #define O_DSN_RRT 0x9e
  1445. { "RrtImpliesDsn", O_DSN_RRT, OI_NONE },
  1446. #define O_PIDFILE 0x9f
  1447. { "PidFile", O_PIDFILE, OI_NONE },
  1448. #define O_DONTBLAMESENDMAIL 0xa0
  1449. { "DontBlameSendmail", O_DONTBLAMESENDMAIL, OI_NONE },
  1450. #define O_DPI 0xa1
  1451. { "DontProbeInterfaces", O_DPI, OI_NONE },
  1452. #define O_MAXRCPT 0xa2
  1453. { "MaxRecipientsPerMessage", O_MAXRCPT, OI_SAFE },
  1454. #define O_DEADLETTER 0xa3
  1455. { "DeadLetterDrop", O_DEADLETTER, OI_NONE },
  1456. #if _FFR_DONTLOCKFILESFORREAD_OPTION
  1457. # define O_DONTLOCK 0xa4
  1458. { "DontLockFilesForRead", O_DONTLOCK, OI_NONE },
  1459. #endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */
  1460. #define O_MAXALIASRCSN 0xa5
  1461. { "MaxAliasRecursion", O_MAXALIASRCSN, OI_NONE },
  1462. #define O_CNCTONLYTO 0xa6
  1463. { "ConnectOnlyTo", O_CNCTONLYTO, OI_NONE },
  1464. #define O_TRUSTUSER 0xa7
  1465. { "TrustedUser", O_TRUSTUSER, OI_NONE },
  1466. #define O_MAXMIMEHDRLEN 0xa8
  1467. { "MaxMimeHeaderLength", O_MAXMIMEHDRLEN, OI_NONE },
  1468. #define O_CONTROLSOCKET 0xa9
  1469. { "ControlSocketName", O_CONTROLSOCKET, OI_NONE },
  1470. #define O_MAXHDRSLEN 0xaa
  1471. { "MaxHeadersLength", O_MAXHDRSLEN, OI_NONE },
  1472. #if _FFR_MAX_FORWARD_ENTRIES
  1473. # define O_MAXFORWARD 0xab
  1474. { "MaxForwardEntries", O_MAXFORWARD, OI_NONE },
  1475. #endif /* _FFR_MAX_FORWARD_ENTRIES */
  1476. #define O_PROCTITLEPREFIX 0xac
  1477. { "ProcessTitlePrefix", O_PROCTITLEPREFIX, OI_NONE },
  1478. #define O_SASLINFO 0xad
  1479. { "DefaultAuthInfo", O_SASLINFO, OI_NONE },
  1480. #define O_SASLMECH 0xae
  1481. { "AuthMechanisms", O_SASLMECH, OI_NONE },
  1482. #define O_CLIENTPORT 0xaf
  1483. { "ClientPortOptions", O_CLIENTPORT, OI_NONE },
  1484. #define O_DF_BUFSIZE 0xb0
  1485. { "DataFileBufferSize", O_DF_BUFSIZE, OI_NONE },
  1486. #define O_XF_BUFSIZE 0xb1
  1487. { "XscriptFileBufferSize", O_XF_BUFSIZE, OI_NONE },
  1488. # define O_LDAPDEFAULTSPEC 0xb2
  1489. { "LDAPDefaultSpec", O_LDAPDEFAULTSPEC, OI_NONE },
  1490. #if _FFR_QUEUEDELAY
  1491. #define O_QUEUEDELAY 0xb3
  1492. { "QueueDelay", O_QUEUEDELAY, OI_NONE },
  1493. #endif /* _FFR_QUEUEDELAY */
  1494. #define O_SASLOPTS 0xbc
  1495. { "AuthOptions", O_SASLOPTS, OI_NONE },
  1496. { NULL, '', OI_NONE }
  1497. };
  1498. void
  1499. setoption(opt, val, safe, sticky, e)
  1500. int opt;
  1501. char *val;
  1502. bool safe;
  1503. bool sticky;
  1504. register ENVELOPE *e;
  1505. {
  1506. register char *p;
  1507. register struct optioninfo *o;
  1508. char *subopt;
  1509. int mid;
  1510. bool can_setuid = RunAsUid == 0;
  1511. auto char *ep;
  1512. char buf[50];
  1513. extern int QueueLA;
  1514. extern int RefuseLA;
  1515. extern bool Warn_Q_option;
  1516. errno = 0;
  1517. if (opt == ' ')
  1518. {
  1519. /* full word options */
  1520. struct optioninfo *sel;
  1521. p = strchr(val, '=');
  1522. if (p == NULL)
  1523. p = &val[strlen(val)];
  1524. while (*--p == ' ')
  1525. continue;
  1526. while (*++p == ' ')
  1527. *p = '';
  1528. if (p == val)
  1529. {
  1530. syserr("readcf: null option name");
  1531. return;
  1532. }
  1533. if (*p == '=')
  1534. *p++ = '';
  1535. while (*p == ' ')
  1536. p++;
  1537. subopt = strchr(val, '.');
  1538. if (subopt != NULL)
  1539. *subopt++ = '';
  1540. sel = NULL;
  1541. for (o = OptionTab; o->o_name != NULL; o++)
  1542. {
  1543. if (strncasecmp(o->o_name, val, strlen(val)) != 0)
  1544. continue;
  1545. if (strlen(o->o_name) == strlen(val))
  1546. {
  1547. /* completely specified -- this must be it */
  1548. sel = NULL;
  1549. break;
  1550. }
  1551. if (sel != NULL)
  1552. break;
  1553. sel = o;
  1554. }
  1555. if (sel != NULL && o->o_name == NULL)
  1556. o = sel;
  1557. else if (o->o_name == NULL)
  1558. {
  1559. syserr("readcf: unknown option name %s", val);
  1560. return;
  1561. }
  1562. else if (sel != NULL)
  1563. {
  1564. syserr("readcf: ambiguous option name %s (matches %s and %s)",
  1565. val, sel->o_name, o->o_name);
  1566. return;
  1567. }
  1568. if (strlen(val) != strlen(o->o_name))
  1569. {
  1570. int oldVerbose = Verbose;
  1571. Verbose = 1;
  1572. message("Option %s used as abbreviation for %s",
  1573. val, o->o_name);
  1574. Verbose = oldVerbose;
  1575. }
  1576. opt = o->o_code;
  1577. val = p;
  1578. }
  1579. else
  1580. {
  1581. for (o = OptionTab; o->o_name != NULL; o++)
  1582. {
  1583. if (o->o_code == opt)
  1584. break;
  1585. }
  1586. subopt = NULL;
  1587. }
  1588. if (subopt != NULL && !bitset(OI_SUBOPT, o->o_flags))
  1589. {
  1590. if (tTd(37, 1))
  1591. dprintf("setoption: %s does not support suboptions, ignoring .%sn",
  1592. o->o_name == NULL ? "<unknown>" : o->o_name,
  1593. subopt);
  1594. subopt = NULL;
  1595. }
  1596. if (tTd(37, 1))
  1597. {
  1598. dprintf(isascii(opt) && isprint(opt) ?
  1599. "setoption %s (%c)%s%s=" :
  1600. "setoption %s (0x%x)%s%s=",
  1601. o->o_name == NULL ? "<unknown>" : o->o_name,
  1602. opt,
  1603. subopt == NULL ? "" : ".",
  1604. subopt == NULL ? "" : subopt);
  1605. xputs(val);
  1606. }
  1607. /*
  1608. **  See if this option is preset for us.
  1609. */
  1610. if (!sticky && bitnset(opt, StickyOpt))
  1611. {
  1612. if (tTd(37, 1))
  1613. dprintf(" (ignored)n");
  1614. return;
  1615. }
  1616. /*
  1617. **  Check to see if this option can be specified by this user.
  1618. */
  1619. if (!safe && RealUid == 0)
  1620. safe = TRUE;
  1621. if (!safe && !bitset(OI_SAFE, o->o_flags))
  1622. {
  1623. if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
  1624. {
  1625. if (tTd(37, 1))
  1626. dprintf(" (unsafe)");
  1627. (void) drop_privileges(TRUE);
  1628. }
  1629. }
  1630. if (tTd(37, 1))
  1631. dprintf("n");
  1632. switch (opt & 0xff)
  1633. {
  1634.   case '7': /* force seven-bit input */
  1635. SevenBitInput = atobool(val);
  1636. break;
  1637. #if MIME8TO7
  1638.   case '8': /* handling of 8-bit input */
  1639. switch (*val)
  1640. {
  1641.   case 'm': /* convert 8-bit, convert MIME */
  1642. MimeMode = MM_CVTMIME|MM_MIME8BIT;
  1643. break;
  1644.   case 'p': /* pass 8 bit, convert MIME */
  1645. MimeMode = MM_CVTMIME|MM_PASS8BIT;
  1646. break;
  1647.   case 's': /* strict adherence */
  1648. MimeMode = MM_CVTMIME;
  1649. break;
  1650. # if 0
  1651.   case 'r': /* reject 8-bit, don't convert MIME */
  1652. MimeMode = 0;
  1653. break;
  1654.   case 'j': /* "just send 8" */
  1655. MimeMode = MM_PASS8BIT;
  1656. break;
  1657.   case 'a': /* encode 8 bit if available */
  1658. MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
  1659. break;
  1660.   case 'c': /* convert 8 bit to MIME, never 7 bit */
  1661. MimeMode = MM_MIME8BIT;
  1662. break;
  1663. # endif /* 0 */
  1664.   default:
  1665. syserr("Unknown 8-bit mode %c", *val);
  1666. finis(FALSE, EX_USAGE);
  1667. }
  1668. break;
  1669. #endif /* MIME8TO7 */
  1670.   case 'A': /* set default alias file */
  1671. if (val[0] == '')
  1672. setalias("aliases");
  1673. else
  1674. setalias(val);
  1675. break;
  1676.   case 'a': /* look N minutes for "@:@" in alias file */
  1677. if (val[0] == '')
  1678. SafeAlias = 5 * 60; /* five minutes */
  1679. else
  1680. SafeAlias = convtime(val, 'm');
  1681. break;
  1682.   case 'B': /* substitution for blank character */
  1683. SpaceSub = val[0];
  1684. if (SpaceSub == '')
  1685. SpaceSub = ' ';
  1686. break;
  1687.   case 'b': /* min blocks free on queue fs/max msg size */
  1688. p = strchr(val, '/');
  1689. if (p != NULL)
  1690. {
  1691. *p++ = '';
  1692. MaxMessageSize = atol(p);
  1693. }
  1694. MinBlocksFree = atol(val);
  1695. break;
  1696.   case 'c': /* don't connect to "expensive" mailers */
  1697. NoConnect = atobool(val);
  1698. break;
  1699.   case 'C': /* checkpoint every N addresses */
  1700. CheckpointInterval = atoi(val);
  1701. break;
  1702.   case 'd': /* delivery mode */
  1703. switch (*val)
  1704. {
  1705.   case '':
  1706. set_delivery_mode(SM_DELIVER, e);
  1707. break;
  1708.   case SM_QUEUE: /* queue only */
  1709.   case SM_DEFER: /* queue only and defer map lookups */
  1710. #if !QUEUE
  1711. syserr("need QUEUE to set -odqueue or -oddefer");
  1712. #endif /* !QUEUE */
  1713. /* FALLTHROUGH */
  1714.   case SM_DELIVER: /* do everything */
  1715.   case SM_FORK: /* fork after verification */
  1716. set_delivery_mode(*val, e);
  1717. break;
  1718.   default:
  1719. syserr("Unknown delivery mode %c", *val);
  1720. finis(FALSE, EX_USAGE);
  1721. }
  1722. break;
  1723. #if !_FFR_REMOVE_AUTOREBUILD
  1724.   case 'D': /* rebuild alias database as needed */
  1725. AutoRebuild = atobool(val);
  1726. break;
  1727. #endif /* !_FFR_REMOVE_AUTOREBUILD */
  1728.   case 'E': /* error message header/header file */
  1729. if (*val != '')
  1730. ErrMsgFile = newstr(val);
  1731. break;
  1732.   case 'e': /* set error processing mode */
  1733. switch (*val)
  1734. {
  1735.   case EM_QUIET: /* be silent about it */
  1736.   case EM_MAIL: /* mail back */
  1737.   case EM_BERKNET: /* do berknet error processing */
  1738.   case EM_WRITE: /* write back (or mail) */
  1739.   case EM_PRINT: /* print errors normally (default) */
  1740. e->e_errormode = *val;
  1741. break;
  1742. }
  1743. break;
  1744.   case 'F': /* file mode */
  1745. FileMode = atooct(val) & 0777;
  1746. break;
  1747.   case 'f': /* save Unix-style From lines on front */
  1748. SaveFrom = atobool(val);
  1749. break;
  1750.   case 'G': /* match recipients against GECOS field */
  1751. MatchGecos = atobool(val);
  1752. break;
  1753.   case 'g': /* default gid */
  1754.   g_opt:
  1755. if (isascii(*val) && isdigit(*val))
  1756. DefGid = atoi(val);
  1757. else
  1758. {
  1759. register struct group *gr;
  1760. DefGid = -1;
  1761. gr = getgrnam(val);
  1762. if (gr == NULL)
  1763. syserr("readcf: option %c: unknown group %s",
  1764. opt, val);
  1765. else
  1766. DefGid = gr->gr_gid;
  1767. }
  1768. break;
  1769.   case 'H': /* help file */
  1770. if (val[0] == '')
  1771. HelpFile = "helpfile";
  1772. else
  1773. HelpFile = newstr(val);
  1774. break;
  1775.   case 'h': /* maximum hop count */
  1776. MaxHopCount = atoi(val);
  1777. break;
  1778.   case 'I': /* use internet domain name server */
  1779. #if NAMED_BIND
  1780. for (p = val; *p != 0; )
  1781. {
  1782. bool clearmode;
  1783. char *q;
  1784. struct resolverflags *rfp;
  1785. while (*p == ' ')
  1786. p++;
  1787. if (*p == '')
  1788. break;
  1789. clearmode = FALSE;
  1790. if (*p == '-')
  1791. clearmode = TRUE;
  1792. else if (*p != '+')
  1793. p--;
  1794. p++;
  1795. q = p;
  1796. while (*p != '' && !(isascii(*p) && isspace(*p)))
  1797. p++;
  1798. if (*p != '')
  1799. *p++ = '';
  1800. if (strcasecmp(q, "HasWildcardMX") == 0)
  1801. {
  1802. HasWildcardMX = !clearmode;
  1803. continue;
  1804. }
  1805. for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
  1806. {
  1807. if (strcasecmp(q, rfp->rf_name) == 0)
  1808. break;
  1809. }
  1810. if (rfp->rf_name == NULL)
  1811. syserr("readcf: I option value %s unrecognized", q);
  1812. else if (clearmode)
  1813. _res.options &= ~rfp->rf_bits;
  1814. else
  1815. _res.options |= rfp->rf_bits;
  1816. }
  1817. if (tTd(8, 2))
  1818. dprintf("_res.options = %x, HasWildcardMX = %dn",
  1819. (u_int) _res.options, HasWildcardMX);
  1820. #else /* NAMED_BIND */
  1821. usrerr("name server (I option) specified but BIND not compiled in");
  1822. #endif /* NAMED_BIND */
  1823. break;
  1824.   case 'i': /* ignore dot lines in message */
  1825. IgnrDot = atobool(val);
  1826. break;
  1827.   case 'j': /* send errors in MIME (RFC 1341) format */
  1828. SendMIMEErrors = atobool(val);
  1829. break;
  1830.   case 'J': /* .forward search path */
  1831. ForwardPath = newstr(val);
  1832. break;
  1833.   case 'k': /* connection cache size */
  1834. MaxMciCache = atoi(val);
  1835. if (MaxMciCache < 0)
  1836. MaxMciCache = 0;
  1837. break;
  1838.   case 'K': /* connection cache timeout */
  1839. MciCacheTimeout = convtime(val, 'm');
  1840. break;
  1841.   case 'l': /* use Errors-To: header */
  1842. UseErrorsTo = atobool(val);
  1843. break;
  1844.   case 'L': /* log level */
  1845. if (safe || LogLevel < atoi(val))
  1846. LogLevel = atoi(val);
  1847. break;
  1848.   case 'M': /* define macro */
  1849. mid = macid(val, &ep);
  1850. p = newstr(ep);
  1851. if (!safe)
  1852. cleanstrcpy(p, p, MAXNAME);
  1853. define(mid, p, CurEnv);
  1854. sticky = FALSE;
  1855. break;
  1856.   case 'm': /* send to me too */
  1857. MeToo = atobool(val);
  1858. break;
  1859.   case 'n': /* validate RHS in newaliases */
  1860. CheckAliases = atobool(val);
  1861. break;
  1862.     /* 'N' available -- was "net name" */
  1863.   case 'O': /* daemon options */
  1864. #if DAEMON
  1865. if (!setdaemonoptions(val))
  1866. {
  1867. syserr("too many daemons defined (%d max)", MAXDAEMONS);
  1868. }
  1869. #else /* DAEMON */
  1870. syserr("DaemonPortOptions (O option) set but DAEMON not compiled in");
  1871. #endif /* DAEMON */
  1872. break;
  1873.   case 'o': /* assume old style headers */
  1874. if (atobool(val))
  1875. CurEnv->e_flags |= EF_OLDSTYLE;
  1876. else
  1877. CurEnv->e_flags &= ~EF_OLDSTYLE;
  1878. break;
  1879.   case 'p': /* select privacy level */
  1880. p = val;
  1881. for (;;)
  1882. {
  1883. register struct prival *pv;
  1884. extern struct prival PrivacyValues[];
  1885. while (isascii(*p) && (isspace(*p) || ispunct(*p)))
  1886. p++;
  1887. if (*p == '')
  1888. break;
  1889. val = p;
  1890. while (isascii(*p) && isalnum(*p))
  1891. p++;
  1892. if (*p != '')
  1893. *p++ = '';
  1894. for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
  1895. {
  1896. if (strcasecmp(val, pv->pv_name) == 0)
  1897. break;
  1898. }
  1899. if (pv->pv_name == NULL)
  1900. syserr("readcf: Op line: %s unrecognized", val);
  1901. PrivacyFlags |= pv->pv_flag;
  1902. }
  1903. sticky = FALSE;
  1904. break;
  1905.   case 'P': /* postmaster copy address for returned mail */
  1906. PostMasterCopy = newstr(val);
  1907. break;
  1908.   case 'q': /* slope of queue only function */
  1909. QueueFactor = atoi(val);
  1910. break;
  1911.   case 'Q': /* queue directory */
  1912. if (val[0] == '')
  1913. QueueDir = "mqueue";
  1914. else
  1915. QueueDir = newstr(val);
  1916. if (RealUid != 0 && !safe)
  1917. Warn_Q_option = TRUE;
  1918. break;
  1919.   case 'R': /* don't prune routes */
  1920. DontPruneRoutes = atobool(val);
  1921. break;
  1922.   case 'r': /* read timeout */
  1923. if (subopt == NULL)
  1924. inittimeouts(val, sticky);
  1925. else
  1926. settimeout(subopt, val, sticky);
  1927. break;
  1928.   case 'S': /* status file */
  1929. if (val[0] == '')
  1930. StatFile = "statistics";
  1931. else
  1932. StatFile = newstr(val);
  1933. break;
  1934.   case 's': /* be super safe, even if expensive */
  1935. SuperSafe = atobool(val);
  1936. break;
  1937.   case 'T': /* queue timeout */
  1938. p = strchr(val, '/');
  1939. if (p != NULL)
  1940. {
  1941. *p++ = '';
  1942. settimeout("queuewarn", p, sticky);
  1943. }
  1944. settimeout("queuereturn", val, sticky);
  1945. break;
  1946.   case 't': /* time zone name */
  1947. TimeZoneSpec = newstr(val);
  1948. break;
  1949.   case 'U': /* location of user database */
  1950. UdbSpec = newstr(val);
  1951. break;
  1952.   case 'u': /* set default uid */
  1953. for (p = val; *p != ''; p++)
  1954. {
  1955. if (*p == '.' || *p == '/' || *p == ':')
  1956. {
  1957. *p++ = '';
  1958. break;
  1959. }
  1960. }
  1961. if (isascii(*val) && isdigit(*val))
  1962. {
  1963. DefUid = atoi(val);
  1964. setdefuser();
  1965. }
  1966. else
  1967. {
  1968. register struct passwd *pw;
  1969. DefUid = -1;
  1970. pw = sm_getpwnam(val);
  1971. if (pw == NULL)
  1972. syserr("readcf: option u: unknown user %s", val);
  1973. else
  1974. {
  1975. DefUid = pw->pw_uid;
  1976. DefGid = pw->pw_gid;
  1977. DefUser = newstr(pw->pw_name);
  1978. }
  1979. }
  1980. #ifdef UID_MAX
  1981. if (DefUid > UID_MAX)
  1982. {
  1983. syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored",
  1984. DefUid, UID_MAX);
  1985. }
  1986. #endif /* UID_MAX */
  1987. /* handle the group if it is there */
  1988. if (*p == '')
  1989. break;
  1990. val = p;
  1991. goto g_opt;
  1992.   case 'V': /* fallback MX host */
  1993. if (val[0] != '')
  1994. FallBackMX = newstr(val);
  1995. break;
  1996.   case 'v': /* run in verbose mode */
  1997. Verbose = atobool(val) ? 1 : 0;
  1998. break;
  1999.   case 'w': /* if we are best MX, try host directly */
  2000. TryNullMXList = atobool(val);
  2001. break;
  2002.     /* 'W' available -- was wizard password */
  2003.   case 'x': /* load avg at which to auto-queue msgs */
  2004. QueueLA = atoi(val);
  2005. break;
  2006.   case 'X': /* load avg at which to auto-reject connections */
  2007. RefuseLA = atoi(val);
  2008. break;
  2009.   case 'y': /* work recipient factor */
  2010. WkRecipFact = atoi(val);
  2011. break;
  2012.   case 'Y': /* fork jobs during queue runs */
  2013. ForkQueueRuns = atobool(val);
  2014. break;
  2015.   case 'z': /* work message class factor */
  2016. WkClassFact = atoi(val);
  2017. break;
  2018.   case 'Z': /* work time factor */
  2019. WkTimeFact = atoi(val);
  2020. break;
  2021.   case O_QUEUESORTORD: /* queue sorting order */
  2022. switch (*val)
  2023. {
  2024.   case 'h': /* Host first */
  2025.   case 'H':
  2026. QueueSortOrder = QSO_BYHOST;
  2027. break;
  2028.   case 'p': /* Priority order */
  2029.   case 'P':
  2030. QueueSortOrder = QSO_BYPRIORITY;
  2031. break;
  2032.   case 't': /* Submission time */
  2033.   case 'T':
  2034. QueueSortOrder = QSO_BYTIME;
  2035. break;
  2036.   case 'f': /* File Name */
  2037.   case 'F':
  2038. QueueSortOrder = QSO_BYFILENAME;
  2039. break;
  2040.   default:
  2041. syserr("Invalid queue sort order "%s"", val);
  2042. }
  2043. break;
  2044. #if _FFR_QUEUEDELAY
  2045.   case O_QUEUEDELAY: /* queue delay algorithm */
  2046. switch (*val)
  2047. {
  2048.   case 'e': /* exponential */
  2049.   case 'E':
  2050. QueueAlg = QD_EXP;
  2051. QueueInitDelay = 10 MINUTES;
  2052. QueueMaxDelay = 2 HOURS;
  2053. p = strchr(val, '/');
  2054. if (p != NULL)
  2055. {
  2056. char *q;
  2057. *p++ = '';
  2058. q = strchr(p, '/');
  2059. if (q != NULL)
  2060. *q++ = '';
  2061. QueueInitDelay = convtime(p, 's');
  2062. if (q != NULL)
  2063. {
  2064. QueueMaxDelay = convtime(q, 's');
  2065. }
  2066. }
  2067. break;
  2068.   case 'l': /* linear */
  2069.   case 'L':
  2070. QueueAlg = QD_LINEAR;
  2071. break;
  2072.   default:
  2073. syserr("Invalid queue delay algorithm "%s"", val);
  2074. }
  2075. break;
  2076. #endif /* _FFR_QUEUEDELAY */
  2077.   case O_HOSTSFILE: /* pathname of /etc/hosts file */
  2078. HostsFile = newstr(val);
  2079. break;
  2080.   case O_MQA: /* minimum queue age between deliveries */
  2081. MinQueueAge = convtime(val, 'm');
  2082. break;
  2083.   case O_DEFCHARSET: /* default character set for mimefying */
  2084. DefaultCharSet = newstr(denlstring(val, TRUE, TRUE));
  2085. break;
  2086.   case O_SSFILE: /* service switch file */
  2087. ServiceSwitchFile = newstr(val);
  2088. break;
  2089.   case O_DIALDELAY: /* delay for dial-on-demand operation */
  2090. DialDelay = convtime(val, 's');
  2091. break;
  2092.   case O_NORCPTACTION: /* what to do if no recipient */
  2093. if (strcasecmp(val, "none") == 0)
  2094. NoRecipientAction = NRA_NO_ACTION;
  2095. else if (strcasecmp(val, "add-to") == 0)
  2096. NoRecipientAction = NRA_ADD_TO;
  2097. else if (strcasecmp(val, "add-apparently-to") == 0)
  2098. NoRecipientAction = NRA_ADD_APPARENTLY_TO;
  2099. else if (strcasecmp(val, "add-bcc") == 0)
  2100. NoRecipientAction = NRA_ADD_BCC;
  2101. else if (strcasecmp(val, "add-to-undisclosed") == 0)
  2102. NoRecipientAction = NRA_ADD_TO_UNDISCLOSED;
  2103. else
  2104. syserr("Invalid NoRecipientAction: %s", val);
  2105. break;
  2106.   case O_SAFEFILEENV: /* chroot() environ for writing to files */
  2107. SafeFileEnv = newstr(val);
  2108. break;
  2109.   case O_MAXMSGSIZE: /* maximum message size */
  2110. MaxMessageSize = atol(val);
  2111. break;
  2112.   case O_COLONOKINADDR: /* old style handling of colon addresses */
  2113. ColonOkInAddr = atobool(val);
  2114. break;
  2115.   case O_MAXQUEUERUN: /* max # of jobs in a single queue run */
  2116. MaxQueueRun = atol(val);
  2117. break;
  2118.   case O_MAXCHILDREN: /* max # of children of daemon */
  2119. MaxChildren = atoi(val);
  2120. break;
  2121. #if _FFR_MAX_FORWARD_ENTRIES
  2122.   case O_MAXFORWARD: /* max # of forward entries */
  2123. MaxForwardEntries = atoi(val);
  2124. break;
  2125. #endif /* _FFR_MAX_FORWARD_ENTRIES */
  2126.   case O_KEEPCNAMES: /* don't expand CNAME records */
  2127. DontExpandCnames = atobool(val);
  2128. break;
  2129.   case O_MUSTQUOTE: /* must quote these characters in phrases */
  2130. (void) strlcpy(buf, "@,;:\()[]", sizeof buf);
  2131. if (strlen(val) < (SIZE_T) sizeof buf - 10)
  2132. (void) strlcat(buf, val, sizeof buf);
  2133. else
  2134. printf("Warning: MustQuoteChars too long, ignored.n");
  2135. MustQuoteChars = newstr(buf);
  2136. break;
  2137.   case O_SMTPGREETING: /* SMTP greeting message (old $e macro) */
  2138. SmtpGreeting = newstr(munchstring(val, NULL, ''));
  2139. break;
  2140.   case O_UNIXFROM: /* UNIX From_ line (old $l macro) */
  2141. UnixFromLine = newstr(munchstring(val, NULL, ''));
  2142. break;
  2143.   case O_OPCHARS: /* operator characters (old $o macro) */
  2144. if (OperatorChars != NULL)
  2145. printf("Warning: OperatorChars is being redefined.n         It should only be set before ruleset definitions.n");
  2146. OperatorChars = newstr(munchstring(val, NULL, ''));
  2147. break;
  2148.   case O_DONTINITGRPS: /* don't call initgroups(3) */
  2149. DontInitGroups = atobool(val);
  2150. break;
  2151.   case O_SLFH: /* make sure from fits on one line */
  2152. SingleLineFromHeader = atobool(val);
  2153. break;
  2154.   case O_ABH: /* allow HELO commands with syntax errors */
  2155. AllowBogusHELO = atobool(val);
  2156. break;
  2157.   case O_CONNTHROT: /* connection rate throttle */
  2158. ConnRateThrottle = atoi(val);
  2159. break;
  2160.   case O_UGW: /* group writable files are unsafe */
  2161. if (!atobool(val))
  2162. {
  2163. setbitn(DBS_GROUPWRITABLEFORWARDFILESAFE,
  2164. DontBlameSendmail);
  2165. setbitn(DBS_GROUPWRITABLEINCLUDEFILESAFE,
  2166. DontBlameSendmail);
  2167. }
  2168. break;
  2169.   case O_DBLBOUNCE: /* address to which to send double bounces */
  2170. if (val[0] != '')
  2171. DoubleBounceAddr = newstr(val);
  2172. else
  2173. syserr("readcf: option DoubleBounceAddress: value required");
  2174. break;
  2175.   case O_HSDIR: /* persistent host status directory */
  2176. if (val[0] != '')
  2177. HostStatDir = newstr(val);
  2178. break;
  2179.   case O_SINGTHREAD: /* single thread deliveries (requires hsdir) */
  2180. SingleThreadDelivery = atobool(val);
  2181. break;
  2182.   case O_RUNASUSER: /* run bulk of code as this user */
  2183. for (p = val; *p != ''; p++)
  2184. {
  2185. if (*p == '.' || *p == '/' || *p == ':')
  2186. {
  2187. *p++ = '';
  2188. break;
  2189. }
  2190. }
  2191. if (isascii(*val) && isdigit(*val))
  2192. {
  2193. if (can_setuid)
  2194. RunAsUid = atoi(val);
  2195. }
  2196. else
  2197. {
  2198. register struct passwd *pw;
  2199. pw = sm_getpwnam(val);
  2200. if (pw == NULL)
  2201. syserr("readcf: option RunAsUser: unknown user %s", val);
  2202. else if (can_setuid)
  2203. {
  2204. if (*p == '')
  2205. RunAsUserName = newstr(val);
  2206. RunAsUid = pw->pw_uid;
  2207. RunAsGid = pw->pw_gid;
  2208. }
  2209. }
  2210. #ifdef UID_MAX
  2211. if (RunAsUid > UID_MAX)
  2212. {
  2213. syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored",
  2214. RunAsUid, UID_MAX);
  2215. }
  2216. #endif /* UID_MAX */
  2217. if (*p != '')
  2218. {
  2219. if (isascii(*p) && isdigit(*p))
  2220. {
  2221. if (can_setuid)
  2222. RunAsGid = atoi(p);
  2223. }
  2224. else
  2225. {
  2226. register struct group *gr;
  2227. gr = getgrnam(p);
  2228. if (gr == NULL)
  2229. syserr("readcf: option RunAsUser: unknown group %s",
  2230. p);
  2231. else if (can_setuid)
  2232. RunAsGid = gr->gr_gid;
  2233. }
  2234. }
  2235. if (tTd(47, 5))
  2236. dprintf("readcf: RunAsUser = %d:%dn",
  2237. (int)RunAsUid, (int)RunAsGid);
  2238. break;
  2239.   case O_DSN_RRT:
  2240. RrtImpliesDsn = atobool(val);
  2241. break;
  2242.   case O_PIDFILE:
  2243. if (PidFile != NULL)
  2244. free(PidFile);
  2245. PidFile = newstr(val);
  2246. break;
  2247. case O_DONTBLAMESENDMAIL:
  2248. p = val;
  2249. for (;;)
  2250. {
  2251. register struct dbsval *dbs;
  2252. extern struct dbsval DontBlameSendmailValues[];
  2253. while (isascii(*p) && (isspace(*p) || ispunct(*p)))
  2254. p++;
  2255. if (*p == '')
  2256. break;
  2257. val = p;
  2258. while (isascii(*p) && isalnum(*p))
  2259. p++;
  2260. if (*p != '')
  2261. *p++ = '';
  2262. for (dbs = DontBlameSendmailValues;
  2263.      dbs->dbs_name != NULL; dbs++)
  2264. {
  2265. if (strcasecmp(val, dbs->dbs_name) == 0)
  2266. break;
  2267. }
  2268. if (dbs->dbs_name == NULL)
  2269. syserr("readcf: DontBlameSendmail option: %s unrecognized", val);
  2270. else if (dbs->dbs_flag == DBS_SAFE)
  2271. clrbitmap(DontBlameSendmail);
  2272. else
  2273. setbitn(dbs->dbs_flag, DontBlameSendmail);
  2274. }
  2275. sticky = FALSE;
  2276. break;
  2277.   case O_DPI:
  2278. DontProbeInterfaces = atobool(val);
  2279. break;
  2280.   case O_MAXRCPT:
  2281. MaxRcptPerMsg = atoi(val);
  2282. break;
  2283.   case O_DEADLETTER:
  2284. if (DeadLetterDrop != NULL)
  2285. free(DeadLetterDrop);
  2286. DeadLetterDrop = newstr(val);
  2287. break;
  2288. #if _FFR_DONTLOCKFILESFORREAD_OPTION
  2289.   case O_DONTLOCK:
  2290. DontLockReadFiles = atobool(val);
  2291. break;
  2292. #endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */
  2293.   case O_MAXALIASRCSN:
  2294. MaxAliasRecursion = atoi(val);
  2295. break;
  2296.   case O_CNCTONLYTO:
  2297. /* XXX should probably use gethostbyname */
  2298. #if NETINET || NETINET6
  2299. # if NETINET6
  2300. if (inet_addr(val) == INADDR_NONE)
  2301. {
  2302. ConnectOnlyTo.sa.sa_family = AF_INET6;
  2303. if (inet_pton(AF_INET6, val,
  2304.       &ConnectOnlyTo.sin6.sin6_addr) != 1)
  2305. syserr("readcf: option ConnectOnlyTo: invalid IP address %s",
  2306.        val);
  2307. }
  2308. else
  2309. # endif /* NETINET6 */
  2310. {
  2311. ConnectOnlyTo.sa.sa_family = AF_INET;
  2312. ConnectOnlyTo.sin.sin_addr.s_addr = inet_addr(val);
  2313. }
  2314. #endif /* NETINET || NETINET6 */
  2315. break;
  2316.   case O_TRUSTUSER:
  2317. #if HASFCHOWN
  2318. if (isascii(*val) && isdigit(*val))
  2319. TrustedUid = atoi(val);
  2320. else
  2321. {
  2322. register struct passwd *pw;
  2323. TrustedUid = 0;
  2324. pw = sm_getpwnam(val);
  2325. if (pw == NULL)
  2326. syserr("readcf: option TrustedUser: unknown user %s", val);
  2327. else
  2328. TrustedUid = pw->pw_uid;
  2329. }
  2330. # ifdef UID_MAX
  2331. if (TrustedUid > UID_MAX)
  2332. {
  2333. syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)",
  2334. TrustedUid, UID_MAX);
  2335. TrustedUid = 0;
  2336. }
  2337. # endif /* UID_MAX */
  2338. #else /* HASFCHOWN */
  2339. syserr("readcf: option TrustedUser: can not be used on systems which do not support fchown()");
  2340. #endif /* HASFCHOWN */
  2341. break;
  2342.   case O_MAXMIMEHDRLEN:
  2343. p = strchr(val, '/');
  2344. if (p != NULL)
  2345. *p++ = '';
  2346. MaxMimeHeaderLength = atoi(val);
  2347. if (p != NULL && *p != '')
  2348. MaxMimeFieldLength = atoi(p);
  2349. else
  2350. MaxMimeFieldLength = MaxMimeHeaderLength / 2;
  2351. if (MaxMimeHeaderLength < 0)
  2352. MaxMimeHeaderLength = 0;
  2353. else if (MaxMimeHeaderLength < 128)
  2354. printf("Warning: MaxMimeHeaderLength: header length limit set lower than 128n");
  2355. if (MaxMimeFieldLength < 0)
  2356. MaxMimeFieldLength = 0;
  2357. else if (MaxMimeFieldLength < 40)
  2358. printf("Warning: MaxMimeHeaderLength: field length limit set lower than 40n");
  2359. break;
  2360.   case O_CONTROLSOCKET:
  2361. if (ControlSocketName != NULL)
  2362. free(ControlSocketName);
  2363. ControlSocketName = newstr(val);
  2364. break;
  2365.   case O_MAXHDRSLEN:
  2366. MaxHeadersLength = atoi(val);
  2367. if (MaxHeadersLength > 0 &&
  2368.     MaxHeadersLength < (MAXHDRSLEN / 2))
  2369. printf("Warning: MaxHeadersLength: headers length limit set lower than %dn", (MAXHDRSLEN / 2));
  2370. break;
  2371.   case O_PROCTITLEPREFIX:
  2372. if (ProcTitlePrefix != NULL)
  2373. free(ProcTitlePrefix);
  2374. ProcTitlePrefix = newstr(val);
  2375. break;
  2376. #if SASL
  2377.   case O_SASLINFO:
  2378. if (SASLInfo != NULL)
  2379. free(SASLInfo);
  2380. SASLInfo = newstr(val);
  2381. break;
  2382.   case O_SASLMECH:
  2383. if (AuthMechanisms != NULL)
  2384. free(AuthMechanisms);
  2385. if (*val != '')
  2386. AuthMechanisms = newstr(val);
  2387. else
  2388. AuthMechanisms = NULL;
  2389. break;
  2390.   case O_SASLOPTS:
  2391. if (*val == '')
  2392. {
  2393. printf("Warning: Option: %s requires parameter(s)n",
  2394. o->o_name == NULL ? "<unknown>" : o->o_name);
  2395. break;
  2396. }
  2397. if (*val == 'T' || *val == 't')
  2398. SASLTryAuth = SASL_TRY_AUTH;
  2399. else if (*val == 'A' || *val == 'a')
  2400. SASLTryAuth = SASL_AUTH_AUTH;
  2401. else
  2402. printf("Warning: Option: %s unknown parameter '%c'n",
  2403. o->o_name == NULL ? "<unknown>" : o->o_name,
  2404. (isascii(*val) && isprint(*val)) ? *val : '?');
  2405. break;
  2406. #else /* SASL */
  2407.   case O_SASLINFO:
  2408.   case O_SASLMECH:
  2409.   case O_SASLOPTS:
  2410. printf("Warning: Option: %s requires SASL support (-DSASL)n",
  2411. o->o_name == NULL ? "<unknown>" : o->o_name);
  2412. break;
  2413. #endif /* SASL */
  2414.   case O_CLIENTPORT:
  2415. #if DAEMON
  2416. setclientoptions(val);
  2417. #else /* DAEMON */
  2418. syserr("ClientPortOptions (O option) set but DAEMON not compiled in");
  2419. #endif /* DAEMON */
  2420. break;
  2421.   case O_DF_BUFSIZE:
  2422. DataFileBufferSize = atoi(val);
  2423. break;
  2424.   case O_XF_BUFSIZE:
  2425. XscriptFileBufferSize = atoi(val);
  2426. break;
  2427.   case O_LDAPDEFAULTSPEC:
  2428. #ifdef LDAPMAP
  2429. ldapmap_set_defaults(val);
  2430. #else /* LDAPMAP */
  2431. printf("Warning: Option: %s requires LDAP support (-DLDAPMAP)n",
  2432. o->o_name == NULL ? "<unknown>" : o->o_name);
  2433. #endif /* LDAPMAP */
  2434. break;
  2435.   default:
  2436. if (tTd(37, 1))
  2437. {
  2438. if (isascii(opt) && isprint(opt))
  2439. dprintf("Warning: option %c unknownn", opt);
  2440. else
  2441. dprintf("Warning: option 0x%x unknownn", opt);
  2442. }
  2443. break;
  2444. }
  2445. /*
  2446. **  Options with suboptions are responsible for taking care
  2447. **  of sticky-ness (e.g., that a command line setting is kept
  2448. **  when reading in the sendmail.cf file).  This has to be done
  2449. **  when the suboptions are parsed since each suboption must be
  2450. **  sticky, not the root option.
  2451. */
  2452. if (sticky && !bitset(OI_SUBOPT, o->o_flags))
  2453. setbitn(opt, StickyOpt);
  2454. }
  2455. /*
  2456. **  SETCLASS -- set a string into a class
  2457. **
  2458. ** Parameters:
  2459. ** class -- the class to put the string in.
  2460. ** str -- the string to enter
  2461. **
  2462. ** Returns:
  2463. ** none.
  2464. **
  2465. ** Side Effects:
  2466. ** puts the word into the symbol table.
  2467. */
  2468. void
  2469. setclass(class, str)
  2470. int class;
  2471. char *str;
  2472. {
  2473. register STAB *s;
  2474. if ((*str & 0377) == MATCHCLASS)
  2475. {
  2476. int mid;
  2477. str++;
  2478. mid = macid(str, NULL);
  2479. if (mid == '')
  2480. return;
  2481. if (tTd(37, 8))
  2482. dprintf("setclass(%s, $=%s)n",
  2483. macname(class), macname(mid));
  2484. copy_class(mid, class);
  2485. }
  2486. else
  2487. {
  2488. if (tTd(37, 8))
  2489. dprintf("setclass(%s, %s)n", macname(class), str);
  2490. s = stab(str, ST_CLASS, ST_ENTER);
  2491. setbitn(class, s->s_class);
  2492. }
  2493. }
  2494. /*
  2495. **  MAKEMAPENTRY -- create a map entry
  2496. **
  2497. ** Parameters:
  2498. ** line -- the config file line
  2499. **
  2500. ** Returns:
  2501. ** A pointer to the map that has been created.
  2502. ** NULL if there was a syntax error.
  2503. **
  2504. ** Side Effects:
  2505. ** Enters the map into the dictionary.
  2506. */
  2507. MAP *
  2508. makemapentry(line)
  2509. char *line;
  2510. {
  2511. register char *p;
  2512. char *mapname;
  2513. char *classname;
  2514. register STAB *s;
  2515. STAB *class;
  2516. for (p = line; isascii(*p) && isspace(*p); p++)
  2517. continue;
  2518. if (!(isascii(*p) && isalnum(*p)))
  2519. {
  2520. syserr("readcf: config K line: no map name");
  2521. return NULL;
  2522. }
  2523. mapname = p;
  2524. while ((isascii(*++p) && isalnum(*p)) || *p == '_' || *p == '.')
  2525. continue;
  2526. if (*p != '')
  2527. *p++ = '';
  2528. while (isascii(*p) && isspace(*p))
  2529. p++;
  2530. if (!(isascii(*p) && isalnum(*p)))
  2531. {
  2532. syserr("readcf: config K line, map %s: no map class", mapname);
  2533. return NULL;
  2534. }
  2535. classname = p;
  2536. while (isascii(*++p) && isalnum(*p))
  2537. continue;
  2538. if (*p != '')
  2539. *p++ = '';
  2540. while (isascii(*p) && isspace(*p))
  2541. p++;
  2542. /* look up the class */
  2543. class = stab(classname, ST_MAPCLASS, ST_FIND);
  2544. if (class == NULL)
  2545. {
  2546. syserr("readcf: map %s: class %s not available", mapname, classname);
  2547. return NULL;
  2548. }
  2549. /* enter the map */
  2550. s = stab(mapname, ST_MAP, ST_ENTER);
  2551. s->s_map.map_class = &class->s_mapclass;
  2552. s->s_map.map_mname = newstr(mapname);
  2553. if (class->s_mapclass.map_parse(&s->s_map, p))
  2554. s->s_map.map_mflags |= MF_VALID;
  2555. if (tTd(37, 5))
  2556. {
  2557. dprintf("map %s, class %s, flags %lx, file %s,n",
  2558. s->s_map.map_mname, s->s_map.map_class->map_cname,
  2559. s->s_map.map_mflags,
  2560. s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
  2561. dprintf("tapp %s, domain %s, rebuild %sn",
  2562. s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
  2563. s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
  2564. s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
  2565. }
  2566. return &s->s_map;
  2567. }
  2568. /*
  2569. **  STRTORWSET -- convert string to rewriting set number
  2570. **
  2571. ** Parameters:
  2572. ** p -- the pointer to the string to decode.
  2573. ** endp -- if set, store the trailing delimiter here.
  2574. ** stabmode -- ST_ENTER to create this entry, ST_FIND if
  2575. ** it must already exist.
  2576. **
  2577. ** Returns:
  2578. ** The appropriate ruleset number.
  2579. ** -1 if it is not valid (error already printed)
  2580. */
  2581. int
  2582. strtorwset(p, endp, stabmode)
  2583. char *p;
  2584. char **endp;
  2585. int stabmode;
  2586. {
  2587. int ruleset;
  2588. static int nextruleset = MAXRWSETS;
  2589. while (isascii(*p) && isspace(*p))
  2590. p++;
  2591. if (!isascii(*p))
  2592. {
  2593. syserr("invalid ruleset name: "%.20s"", p);
  2594. return -1;
  2595. }
  2596. if (isdigit(*p))
  2597. {
  2598. ruleset = strtol(p, endp, 10);
  2599. if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
  2600. {
  2601. syserr("bad ruleset %d (%d max)",
  2602. ruleset, MAXRWSETS / 2);
  2603. ruleset = -1;
  2604. }
  2605. }
  2606. else
  2607. {
  2608. STAB *s;
  2609. char delim;
  2610. char *q = NULL;
  2611. q = p;
  2612. while (*p != '' && isascii(*p) &&
  2613.        (isalnum(*p) || *p == '_'))
  2614. p++;
  2615. if (q == p || !(isascii(*q) && isalpha(*q)))
  2616. {
  2617. /* no valid characters */
  2618. syserr("invalid ruleset name: "%.20s"", q);
  2619. return -1;
  2620. }
  2621. while (isascii(*p) && isspace(*p))
  2622. *p++ = '';
  2623. delim = *p;
  2624. if (delim != '')
  2625. *p = '';
  2626. s = stab(q, ST_RULESET, stabmode);
  2627. if (delim != '')
  2628. *p = delim;
  2629. if (s == NULL)
  2630. return -1;
  2631. if (stabmode == ST_ENTER && delim == '=')
  2632. {
  2633. while (isascii(*++p) && isspace(*p))
  2634. continue;
  2635. if (!(isascii(*p) && isdigit(*p)))
  2636. {
  2637. syserr("bad ruleset definition "%s" (number required after `=')", q);
  2638. ruleset = -1;
  2639. }
  2640. else
  2641. {
  2642. ruleset = strtol(p, endp, 10);
  2643. if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
  2644. {
  2645. syserr("bad ruleset number %d in "%s" (%d max)",
  2646. ruleset, q, MAXRWSETS / 2);
  2647. ruleset = -1;
  2648. }
  2649. }
  2650. }
  2651. else
  2652. {
  2653. if (endp != NULL)
  2654. *endp = p;
  2655. if (s->s_ruleset >= 0)
  2656. ruleset = s->s_ruleset;
  2657. else if ((ruleset = --nextruleset) < MAXRWSETS / 2)
  2658. {
  2659. syserr("%s: too many named rulesets (%d max)",
  2660. q, MAXRWSETS / 2);
  2661. ruleset = -1;
  2662. }
  2663. }
  2664. if (s->s_ruleset >= 0 &&
  2665.     ruleset >= 0 &&
  2666.     ruleset != s->s_ruleset)
  2667. {
  2668. syserr("%s: ruleset changed value (old %d, new %d)",
  2669. q, s->s_ruleset, ruleset);
  2670. ruleset = s->s_ruleset;
  2671. }
  2672. else if (ruleset >= 0)
  2673. {
  2674. s->s_ruleset = ruleset;
  2675. }
  2676. if (stabmode == ST_ENTER)
  2677. {
  2678. char *h = NULL;
  2679. if (RuleSetNames[ruleset] != NULL)
  2680. free(RuleSetNames[ruleset]);
  2681. if (delim != '' && (h = strchr(q, delim)) != NULL)
  2682. *h = '';
  2683. RuleSetNames[ruleset] = newstr(q);
  2684. if (delim == '/' && h != NULL)
  2685. *h = delim; /* put back delim */
  2686. }
  2687. }
  2688. return ruleset;
  2689. }
  2690. /*
  2691. **  SETTIMEOUT -- set an individual timeout
  2692. **
  2693. ** Parameters:
  2694. ** name -- the name of the timeout.
  2695. ** val -- the value of the timeout.
  2696. ** sticky -- if set, don't let other setoptions override
  2697. ** this value.
  2698. **
  2699. ** Returns:
  2700. ** none.
  2701. */
  2702. /* set if Timeout sub-option is stuck */
  2703. static BITMAP256 StickyTimeoutOpt;
  2704. static struct timeoutinfo
  2705. {
  2706. char *to_name; /* long name of timeout */
  2707. u_char to_code; /* code for option */
  2708. } TimeOutTab[] =
  2709. {
  2710. #define TO_INITIAL 0x01
  2711. { "initial", TO_INITIAL },
  2712. #define TO_MAIL 0x02
  2713. { "mail", TO_MAIL },
  2714. #define TO_RCPT 0x03
  2715. { "rcpt", TO_RCPT },
  2716. #define TO_DATAINIT 0x04
  2717. { "datainit", TO_DATAINIT },
  2718. #define TO_DATABLOCK 0x05
  2719. { "datablock", TO_DATABLOCK },
  2720. #define TO_DATAFINAL 0x06
  2721. { "datafinal", TO_DATAFINAL },
  2722. #define TO_COMMAND 0x07
  2723. { "command", TO_COMMAND },
  2724. #define TO_RSET 0x08
  2725. { "rset", TO_RSET },
  2726. #define TO_HELO 0x09
  2727. { "helo", TO_HELO },
  2728. #define TO_QUIT 0x0A
  2729. { "quit", TO_QUIT },
  2730. #define TO_MISC 0x0B
  2731. { "misc", TO_MISC },
  2732. #define TO_IDENT 0x0C
  2733. { "ident", TO_IDENT },
  2734. #define TO_FILEOPEN 0x0D
  2735. { "fileopen", TO_FILEOPEN },
  2736. #define TO_CONNECT 0x0E
  2737. { "connect", TO_CONNECT },
  2738. #define TO_ICONNECT 0x0F
  2739. { "iconnect", TO_ICONNECT },
  2740. #define TO_QUEUEWARN 0x10
  2741. { "queuewarn", TO_QUEUEWARN },
  2742. { "queuewarn.*", TO_QUEUEWARN },
  2743. #define TO_QUEUEWARN_NORMAL 0x11
  2744. { "queuewarn.normal", TO_QUEUEWARN_NORMAL },
  2745. #define TO_QUEUEWARN_URGENT 0x12
  2746. { "queuewarn.urgent", TO_QUEUEWARN_URGENT },
  2747. #define TO_QUEUEWARN_NON_URGENT 0x13
  2748. { "queuewarn.non-urgent", TO_QUEUEWARN_NON_URGENT },
  2749. #define TO_QUEUERETURN 0x14
  2750. { "queuereturn", TO_QUEUERETURN },
  2751. { "queuereturn.*", TO_QUEUERETURN },
  2752. #define TO_QUEUERETURN_NORMAL 0x15
  2753. { "queuereturn.normal", TO_QUEUERETURN_NORMAL },
  2754. #define TO_QUEUERETURN_URGENT 0x16
  2755. { "queuereturn.urgent", TO_QUEUERETURN_URGENT },
  2756. #define TO_QUEUERETURN_NON_URGENT 0x17
  2757. { "queuereturn.non-urgent", TO_QUEUERETURN_NON_URGENT },
  2758. #define TO_HOSTSTATUS 0x18
  2759. { "hoststatus", TO_HOSTSTATUS },
  2760. #define TO_RESOLVER_RETRANS 0x19
  2761. { "resolver.retrans", TO_RESOLVER_RETRANS },
  2762. #define TO_RESOLVER_RETRANS_NORMAL 0x1A
  2763. { "resolver.retrans.normal", TO_RESOLVER_RETRANS_NORMAL },
  2764. #define TO_RESOLVER_RETRANS_FIRST 0x1B
  2765. { "resolver.retrans.first", TO_RESOLVER_RETRANS_FIRST },
  2766. #define TO_RESOLVER_RETRY 0x1C
  2767. { "resolver.retry", TO_RESOLVER_RETRY },
  2768. #define TO_RESOLVER_RETRY_NORMAL 0x1D
  2769. { "resolver.retry.normal", TO_RESOLVER_RETRY_NORMAL },
  2770. #define TO_RESOLVER_RETRY_FIRST 0x1E
  2771. { "resolver.retry.first", TO_RESOLVER_RETRY_FIRST },
  2772. #define TO_CONTROL 0x1F
  2773. { "control", TO_CONTROL },
  2774. { NULL, 0 },
  2775. };
  2776. static void
  2777. settimeout(name, val, sticky)
  2778. char *name;
  2779. char *val;
  2780. bool sticky;
  2781. {
  2782. register struct timeoutinfo *to;
  2783. int i;
  2784. time_t toval;
  2785. if (tTd(37, 2))
  2786. dprintf("settimeout(%s = %s)", name, val);
  2787. for (to = TimeOutTab; to->to_name != NULL; to++)
  2788. {
  2789. if (strcasecmp(to->to_name, name) == 0)
  2790. break;
  2791. }
  2792. if (to->to_name == NULL)
  2793. syserr("settimeout: invalid timeout %s", name);
  2794. /*
  2795. **  See if this option is preset for us.
  2796. */
  2797. if (!sticky && bitnset(to->to_code, StickyTimeoutOpt))
  2798. {
  2799. if (tTd(37, 2))
  2800. dprintf(" (ignored)n");
  2801. return;
  2802. }
  2803. if (tTd(37, 2))
  2804. dprintf("n");
  2805. toval = convtime(val, 'm');
  2806. switch (to->to_code)
  2807. {
  2808.   case TO_INITIAL:
  2809. TimeOuts.to_initial = toval;
  2810. break;
  2811.   case TO_MAIL:
  2812. TimeOuts.to_mail = toval;
  2813. break;
  2814.   case TO_RCPT:
  2815. TimeOuts.to_rcpt = toval;
  2816. break;
  2817.   case TO_DATAINIT:
  2818. TimeOuts.to_datainit = toval;
  2819. break;
  2820.   case TO_DATABLOCK:
  2821. TimeOuts.to_datablock = toval;
  2822. break;
  2823.   case TO_DATAFINAL:
  2824. TimeOuts.to_datafinal = toval;
  2825. break;
  2826.   case TO_COMMAND:
  2827. TimeOuts.to_nextcommand = toval;
  2828. break;
  2829.   case TO_RSET:
  2830. TimeOuts.to_rset = toval;
  2831. break;
  2832.   case TO_HELO:
  2833. TimeOuts.to_helo = toval;
  2834. break;
  2835.   case TO_QUIT:
  2836. TimeOuts.to_quit = toval;
  2837. break;
  2838.   case TO_MISC:
  2839. TimeOuts.to_miscshort = toval;
  2840. break;
  2841.   case TO_IDENT:
  2842. TimeOuts.to_ident = toval;
  2843. break;
  2844.   case TO_FILEOPEN:
  2845. TimeOuts.to_fileopen = toval;
  2846. break;
  2847.   case TO_CONNECT:
  2848. TimeOuts.to_connect = toval;
  2849. break;
  2850.   case TO_ICONNECT:
  2851. TimeOuts.to_iconnect = toval;
  2852. break;
  2853.   case TO_QUEUEWARN:
  2854. toval = convtime(val, 'h');
  2855. TimeOuts.to_q_warning[TOC_NORMAL] = toval;
  2856. TimeOuts.to_q_warning[TOC_URGENT] = toval;
  2857. TimeOuts.to_q_warning[TOC_NONURGENT] = toval;
  2858. break;
  2859.   case TO_QUEUEWARN_NORMAL:
  2860. toval = convtime(val, 'h');
  2861. TimeOuts.to_q_warning[TOC_NORMAL] = toval;
  2862. break;
  2863.   case TO_QUEUEWARN_URGENT:
  2864. toval = convtime(val, 'h');
  2865. TimeOuts.to_q_warning[TOC_URGENT] = toval;
  2866. break;
  2867.   case TO_QUEUEWARN_NON_URGENT:
  2868. toval = convtime(val, 'h');
  2869. TimeOuts.to_q_warning[TOC_NONURGENT] = toval;
  2870. break;
  2871.   case TO_QUEUERETURN:
  2872. toval = convtime(val, 'd');
  2873. TimeOuts.to_q_return[TOC_NORMAL] = toval;
  2874. TimeOuts.to_q_return[TOC_URGENT] = toval;
  2875. TimeOuts.to_q_return[TOC_NONURGENT] = toval;
  2876. break;
  2877.   case TO_QUEUERETURN_NORMAL:
  2878. toval = convtime(val, 'd');
  2879. TimeOuts.to_q_return[TOC_NORMAL] = toval;
  2880. break;
  2881.   case TO_QUEUERETURN_URGENT:
  2882. toval = convtime(val, 'd');
  2883. TimeOuts.to_q_return[TOC_URGENT] = toval;
  2884. break;
  2885.   case TO_QUEUERETURN_NON_URGENT:
  2886. toval = convtime(val, 'd');
  2887. TimeOuts.to_q_return[TOC_NONURGENT] = toval;
  2888. break;
  2889.   case TO_HOSTSTATUS:
  2890. MciInfoTimeout = convtime(val, 'm');
  2891. break;
  2892.   case TO_RESOLVER_RETRANS:
  2893. toval = convtime(val, 's');
  2894. TimeOuts.res_retrans[RES_TO_DEFAULT] = toval;
  2895. TimeOuts.res_retrans[RES_TO_FIRST] = toval;
  2896. TimeOuts.res_retrans[RES_TO_NORMAL] = toval;
  2897. break;
  2898.   case TO_RESOLVER_RETRY:
  2899. i = atoi(val);
  2900. TimeOuts.res_retry[RES_TO_DEFAULT] = i;
  2901. TimeOuts.res_retry[RES_TO_FIRST] = i;
  2902. TimeOuts.res_retry[RES_TO_NORMAL] = i;
  2903. break;
  2904.   case TO_RESOLVER_RETRANS_NORMAL:
  2905. TimeOuts.res_retrans[RES_TO_NORMAL] = convtime(val, 's');
  2906. break;
  2907.   case TO_RESOLVER_RETRY_NORMAL:
  2908. TimeOuts.res_retry[RES_TO_NORMAL] = atoi(val);
  2909. break;
  2910.   case TO_RESOLVER_RETRANS_FIRST:
  2911. TimeOuts.res_retrans[RES_TO_FIRST] = convtime(val, 's');
  2912. break;
  2913.   case TO_RESOLVER_RETRY_FIRST:
  2914. TimeOuts.res_retry[RES_TO_FIRST] = atoi(val);
  2915. break;
  2916.   case TO_CONTROL:
  2917. TimeOuts.to_control = toval;
  2918. break;
  2919.   default:
  2920. syserr("settimeout: invalid timeout %s", name);
  2921. break;
  2922. }
  2923. if (sticky)
  2924. setbitn(to->to_code, StickyTimeoutOpt);
  2925. }
  2926. /*
  2927. **  INITTIMEOUTS -- parse and set timeout values
  2928. **
  2929. ** Parameters:
  2930. ** val -- a pointer to the values.  If NULL, do initial
  2931. ** settings.
  2932. ** sticky -- if set, don't let other setoptions override
  2933. ** this suboption value.
  2934. **
  2935. ** Returns:
  2936. ** none.
  2937. **
  2938. ** Side Effects:
  2939. ** Initializes the TimeOuts structure
  2940. */
  2941. void
  2942. inittimeouts(val, sticky)
  2943. register char *val;
  2944. bool sticky;
  2945. {
  2946. register char *p;
  2947. if (tTd(37, 2))
  2948. dprintf("inittimeouts(%s)n", val == NULL ? "<NULL>" : val);
  2949. if (val == NULL)
  2950. {
  2951. TimeOuts.to_connect = (time_t) 0 SECONDS;
  2952. TimeOuts.to_initial = (time_t) 5 MINUTES;
  2953. TimeOuts.to_helo = (time_t) 5 MINUTES;
  2954. TimeOuts.to_mail = (time_t) 10 MINUTES;
  2955. TimeOuts.to_rcpt = (time_t) 1 HOUR;
  2956. TimeOuts.to_datainit = (time_t) 5 MINUTES;
  2957. TimeOuts.to_datablock = (time_t) 1 HOUR;
  2958. TimeOuts.to_datafinal = (time_t) 1 HOUR;
  2959. TimeOuts.to_rset = (time_t) 5 MINUTES;
  2960. TimeOuts.to_quit = (time_t) 2 MINUTES;
  2961. TimeOuts.to_nextcommand = (time_t) 1 HOUR;
  2962. TimeOuts.to_miscshort = (time_t) 2 MINUTES;
  2963. #if IDENTPROTO
  2964. TimeOuts.to_ident = (time_t) 30 SECONDS;
  2965. #else /* IDENTPROTO */
  2966. TimeOuts.to_ident = (time_t) 0 SECONDS;
  2967. #endif /* IDENTPROTO */
  2968. TimeOuts.to_fileopen = (time_t) 60 SECONDS;
  2969. TimeOuts.to_control = (time_t) 2 MINUTES;
  2970. if (tTd(37, 5))
  2971. {
  2972. dprintf("Timeouts:n");
  2973. dprintf("  connect = %ldn", (long)TimeOuts.to_connect);
  2974. dprintf("  initial = %ldn", (long)TimeOuts.to_initial);
  2975. dprintf("  helo = %ldn", (long)TimeOuts.to_helo);
  2976. dprintf("  mail = %ldn", (long)TimeOuts.to_mail);
  2977. dprintf("  rcpt = %ldn", (long)TimeOuts.to_rcpt);
  2978. dprintf("  datainit = %ldn", (long)TimeOuts.to_datainit);
  2979. dprintf("  datablock = %ldn", (long)TimeOuts.to_datablock);
  2980. dprintf("  datafinal = %ldn", (long)TimeOuts.to_datafinal);
  2981. dprintf("  rset = %ldn", (long)TimeOuts.to_rset);
  2982. dprintf("  quit = %ldn", (long)TimeOuts.to_quit);
  2983. dprintf("  nextcommand = %ldn", (long)TimeOuts.to_nextcommand);
  2984. dprintf("  miscshort = %ldn", (long)TimeOuts.to_miscshort);
  2985. dprintf("  ident = %ldn", (long)TimeOuts.to_ident);
  2986. dprintf("  fileopen = %ldn", (long)TimeOuts.to_fileopen);
  2987. dprintf("  control = %ldn", (long)TimeOuts.to_control);
  2988. }
  2989. return;
  2990. }
  2991. for (;; val = p)
  2992. {
  2993. while (isascii(*val) && isspace(*val))
  2994. val++;
  2995. if (*val == '')
  2996. break;
  2997. for (p = val; *p != '' && *p != ','; p++)
  2998. continue;
  2999. if (*p != '')
  3000. *p++ = '';
  3001. if (isascii(*val) && isdigit(*val))
  3002. {
  3003. /* old syntax -- set everything */
  3004. TimeOuts.to_mail = convtime(val, 'm');
  3005. TimeOuts.to_rcpt = TimeOuts.to_mail;
  3006. TimeOuts.to_datainit = TimeOuts.to_mail;
  3007. TimeOuts.to_datablock = TimeOuts.to_mail;
  3008. TimeOuts.to_datafinal = TimeOuts.to_mail;
  3009. TimeOuts.to_nextcommand = TimeOuts.to_mail;
  3010. if (sticky)
  3011. {
  3012. setbitn(TO_MAIL, StickyTimeoutOpt);
  3013. setbitn(TO_RCPT, StickyTimeoutOpt);
  3014. setbitn(TO_DATAINIT, StickyTimeoutOpt);
  3015. setbitn(TO_DATABLOCK, StickyTimeoutOpt);
  3016. setbitn(TO_DATAFINAL, StickyTimeoutOpt);
  3017. setbitn(TO_COMMAND, StickyTimeoutOpt);
  3018. }
  3019. continue;
  3020. }
  3021. else
  3022. {
  3023. register char *q = strchr(val, ':');
  3024. if (q == NULL && (q = strchr(val, '=')) == NULL)
  3025. {
  3026. /* syntax error */
  3027. continue;
  3028. }
  3029. *q++ = '';
  3030. settimeout(val, q, sticky);
  3031. }
  3032. }
  3033. }