2 * Copyright (c) 1998-2006, 2008-2010, 2013 Proofpoint, Inc. and its suppliers.
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.
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.
15 #include <sm/sendmail.h>
20 # include <sm_resolve.h>
23 SM_RCSID("@(#)$Id: readcf.c,v 8.692 2013-11-22 20:51:56 ca Exp $")
25 #if NETINET || NETINET6
26 # include <arpa/inet.h>
35 static void fileclass __P((int, char *, char *, bool, bool, bool));
36 static char **makeargv __P((char *));
37 static void settimeout __P((char *, char *, bool));
38 static void toomany __P((int, int));
39 static char *extrquotstr __P((char *, char **, char *, bool *));
40 static void parse_class_words __P((int, char *));
44 static char *bouncequeue = NULL;
45 static void initbouncequeue __P((void));
48 ** INITBOUNCEQUEUE -- determine BounceQueue if option is set.
66 if (bouncequeue == NULL || bouncequeue[0] == '\0')
69 s = stab(bouncequeue, ST_QUEUE, ST_FIND);
72 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
73 "Warning: option BounceQueue: unknown queue group %s\n",
77 BounceQueue = s->s_quegrp->qg_index;
79 #endif /* _FFR_BOUNCE_QUEUE */
82 void setupdynmailers __P((void));
84 #define setupdynmailers()
88 ** READCF -- read configuration file.
90 ** This routine reads the configuration file and builds the internal
93 ** The file is formatted as a sequence of lines, each taken
94 ** atomically. The first character of each line describes how
95 ** the line is to be interpreted. The lines are:
96 ** Dxval Define macro x to have value val.
97 ** Cxword Put word into class x.
98 ** Fxfile [fmt] Read file for lines to put into
99 ** class x. Use scanf string 'fmt'
100 ** or "%s" if not present. Fmt should
101 ** only produce one string-valued result.
102 ** Hname: value Define header with field-name 'name'
103 ** and value as specified; this will be
104 ** macro expanded immediately before
106 ** Sn Use rewriting set n.
107 ** Rlhs rhs Rewrite addresses that match lhs to
109 ** Mn arg=val... Define mailer. n is the internal name.
110 ** Args specify mailer parameters.
111 ** Oxvalue Set option x to value.
112 ** O option value Set option (long name) to value.
113 ** Pname=value Set precedence name to value.
114 ** Qn arg=val... Define queue groups. n is the internal name.
115 ** Args specify queue parameters.
116 ** Vversioncode[/vendorcode]
117 ** Version level/vendor name of
118 ** configuration syntax.
119 ** Kmapname mapclass arguments....
120 ** Define keyed lookup of a given class.
121 ** Arguments are class dependent.
122 ** Eenvar=value Set the environment value to the given value.
125 ** cfname -- configuration file name.
126 ** safe -- true if this is the system config file;
128 ** e -- the main envelope.
134 ** Builds several internal tables.
138 readcf(cfname, safe, e)
141 register ENVELOPE *e;
146 struct rewrite *rwp = NULL;
156 long sff = SFF_OPENASROOT;
161 char pvpbuf[MAXLINE + MAXATOM];
162 static char *null_list[1] = { NULL };
163 extern unsigned char TokTypeNoC[];
168 if (DontLockReadFiles)
170 cf = safefopen(cfname, O_RDONLY, 0444, sff);
173 syserr("cannot open");
174 finis(false, true, EX_OSFILE);
177 if (fstat(sm_io_getinfo(cf, SM_IO_WHAT_FD, NULL), &statb) < 0)
179 syserr("cannot fstat");
180 finis(false, true, EX_OSFILE);
183 if (!S_ISREG(statb.st_mode))
185 syserr("not a plain file");
186 finis(false, true, EX_OSFILE);
189 if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
191 if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS || OpMode == MD_CHECKCONFIG)
192 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
193 "%s: WARNING: dangerous write permissions\n",
196 sm_syslog(LOG_CRIT, NOQID,
197 "%s: WARNING: dangerous write permissions",
205 while (bufsize = sizeof(buf),
206 (bp = fgetfolded(buf, &bufsize, cf)) != NULL)
213 sm_free(bp); /* XXX */
217 /* do macro expansion mappings */
218 nbp = translate_dollars(bp, bp, &bufsize);
219 if (nbp != bp && bp != buf)
223 /* interpret this line */
228 case '#': /* comment */
231 case 'R': /* rewriting rule */
234 syserr("missing valid ruleset for \"%s\"", bp);
237 for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
242 syserr("invalid rewrite line \"%s\" (tab expected)", bp);
246 /* allocate space for the rule header */
249 RewriteRules[ruleset] = rwp =
250 (struct rewrite *) xalloc(sizeof(*rwp));
254 rwp->r_next = (struct rewrite *) xalloc(sizeof(*rwp));
259 /* expand and save the LHS */
261 expand(&bp[1], exbuf, sizeof(exbuf), e);
262 rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
263 sizeof(pvpbuf), NULL,
264 ConfigLevel >= 9 ? TokTypeNoC : IntTokenTab,
267 if (rwp->r_lhs != NULL)
271 rwp->r_lhs = copyplist(rwp->r_lhs, true, NULL);
273 /* count the number of fuzzy matches in LHS */
274 for (ap = rwp->r_lhs; *ap != NULL; ap++)
279 switch (ap[0][0] & 0377)
326 syserr("Inappropriate use of %s on LHS",
329 rwp->r_line = LineNumber;
333 syserr("R line: null LHS");
334 rwp->r_lhs = null_list;
336 if (nfuzzy > MAXMATCH)
338 syserr("R line: too many wildcards");
339 rwp->r_lhs = null_list;
342 /* expand and save the RHS */
346 while (*p != '\0' && *p != '\t')
349 expand(q, exbuf, sizeof(exbuf), e);
350 rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
351 sizeof(pvpbuf), NULL,
352 ConfigLevel >= 9 ? TokTypeNoC : IntTokenTab,
354 if (rwp->r_rhs != NULL)
358 #if _FFR_EXTRA_MAP_CHECK
363 rwp->r_rhs = copyplist(rwp->r_rhs, true, NULL);
365 /* check no out-of-bounds replacements */
370 for (ap = rwp->r_rhs; *ap != NULL; ap++)
375 switch (ap[0][0] & 0377)
378 if (ap[0][1] <= '0' ||
381 syserr("replacement $%c out of bounds",
409 if (++args >= MAX_MAP_ARGS)
410 syserr("too many arguments for map lookup");
418 if ((ap[0][0] & 0377) == LOOKUPBEGIN)
419 endtoken = LOOKUPEND;
421 syserr("cannot nest map lookups");
424 #if _FFR_EXTRA_MAP_CHECK
427 syserr("syntax error in map lookup");
430 nexttoken = ap[1][0] & 0377;
431 if (nexttoken == CANONHOST ||
432 nexttoken == CANONUSER ||
433 nexttoken == endtoken)
435 syserr("missing map name for lookup");
440 syserr("syntax error in map lookup");
443 if ((unsigned char) ap[0][0] == HOSTBEGIN)
445 nexttoken = ap[2][0] & 0377;
446 if (nexttoken == CANONHOST ||
447 nexttoken == CANONUSER ||
448 nexttoken == endtoken)
450 syserr("missing key name for lookup");
453 #endif /* _FFR_EXTRA_MAP_CHECK */
458 if ((ap[0][0] & 0377) != endtoken)
467 ** This doesn't work yet as there are maps defined *after* the cf
468 ** is read such as host, user, and alias. So for now, it's removed.
469 ** When it comes back, the RELEASE_NOTES entry will be:
470 ** Emit warnings for unknown maps when reading the .cf file. Based on
471 ** patch from Robert Harker of Harker Systems.
476 ** Got a database lookup,
477 ** check if map is defined.
481 if ((ep[0] & 0377) != MACRODEXPAND &&
482 stab(ep, ST_MAP, ST_FIND) == NULL)
484 (void) sm_io_fprintf(smioout,
486 "Warning: %s: line %d: map %s not found\n",
495 syserr("Inappropriate use of %s on RHS",
499 syserr("missing map closing token");
503 syserr("R line: null RHS");
504 rwp->r_rhs = null_list;
508 case 'S': /* select rewriting set */
509 expand(&bp[1], exbuf, sizeof(exbuf), e);
510 ruleset = strtorwset(exbuf, NULL, ST_ENTER);
514 rwp = RewriteRules[ruleset];
517 if (OpMode == MD_TEST || OpMode == MD_CHECKCONFIG)
518 (void) sm_io_fprintf(smioout,
520 "WARNING: Ruleset %s has multiple definitions\n",
523 sm_dprintf("WARNING: Ruleset %s has multiple definitions\n",
525 while (rwp->r_next != NULL)
530 case 'D': /* macro definition */
531 mid = macid_parse(&bp[1], &ep);
534 p = munchstring(ep, NULL, '\0');
535 macdefine(&e->e_macro, A_TEMP, mid, p);
538 case 'H': /* required header line */
539 (void) chompheader(&bp[1], CHHDR_DEF, NULL, e);
542 case 'C': /* word class */
543 case 'T': /* trusted user (set class `t') */
546 mid = macid_parse(&bp[1], &ep);
549 expand(ep, exbuf, sizeof(exbuf), e);
562 while (*p != '\0' && SM_ISSPACE(*p))
565 while (*p != '\0' && !(SM_ISSPACE(*p)))
575 case 'F': /* word class from file */
576 mid = macid_parse(&bp[1], &ep);
579 for (p = ep; SM_ISSPACE(*p); )
581 if (p[0] == '-' && p[1] == 'o')
587 while (SM_ISSPACE(*p))
593 /* check if [key]@map:spec */
595 if (!SM_IS_DIR_DELIM(*p) &&
597 (q = strchr(p, '@')) != NULL)
601 /* look for @LDAP or @map: in string */
602 if (strcmp(q, "LDAP") == 0 ||
604 strchr(q, ':') != NULL))
610 /* use entire spec */
615 file = extrquotstr(p, &q, " ", &ok);
618 syserr("illegal filename '%s'", p);
623 if (*file == '|' || ismap)
633 while (isascii(*++p) && isspace(*p))
637 fileclass(mid, file, p, ismap, safe, optional);
641 case 'L': /* extended load average description */
646 #if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO)
647 case 'L': /* lookup macro */
648 case 'G': /* lookup class */
649 /* reserved for Sun -- NIS+ database lookup */
650 if (VendorCode != VENDOR_SUN)
652 sun_lg_config_line(bp, e);
654 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) */
656 case 'M': /* define mailer */
660 case 'O': /* set option */
661 setoption(bp[1], &bp[2], safe, false, e);
664 case 'P': /* set precedence */
665 if (NumPriorities >= MAXPRIORITIES)
667 toomany('P', MAXPRIORITIES);
670 for (p = &bp[1]; *p != '\0' && *p != '='; p++)
675 Priorities[NumPriorities].pri_name = newstr(&bp[1]);
676 Priorities[NumPriorities].pri_val = atoi(++p);
680 case 'Q': /* define queue */
681 makequeue(&bp[1], true);
684 case 'V': /* configuration syntax version */
685 for (p = &bp[1]; SM_ISSPACE(*p); p++)
687 if (!isascii(*p) || !isdigit(*p))
689 syserr("invalid argument to V line: \"%.20s\"",
693 ConfigLevel = strtol(p, &ep, 10);
696 ** Do heuristic tweaking for back compatibility.
699 if (ConfigLevel >= 5)
701 /* level 5 configs have short name in $w */
702 p = macvalue('w', e);
703 if (p != NULL && (p = strchr(p, '.')) != NULL)
706 macdefine(&e->e_macro, A_TEMP, 'w',
710 if (ConfigLevel >= 6)
712 ColonOkInAddr = false;
716 ** Look for vendor code.
721 /* extract vendor code */
722 for (p = ep; isascii(*p) && isalpha(*p); )
727 syserr("invalid V line vendor code: \"%s\"",
733 expand(&bp[1], exbuf, sizeof(exbuf), e);
734 (void) makemapentry(exbuf);
741 sm_setuserenv(&bp[1], p);
744 case 'X': /* mail filter */
746 milter_setup(&bp[1]);
748 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
749 "Warning: Filter usage ('X') requires Milter support (-DMILTER)\n");
755 syserr("unknown configuration line \"%s\"", bp);
758 sm_free(bp); /* XXX */
762 syserr("I/O read error");
763 finis(false, true, EX_OSFILE);
765 (void) sm_io_close(cf, SM_TIME_DEFAULT);
768 #if _FFR_BOUNCE_QUEUE
772 /* initialize host maps from local service tables */
775 /* initialize daemon (if not defined yet) */
778 /* determine if we need to do special name-server frotz */
781 char *maptype[MAXMAPSTACK];
782 short mapreturn[MAXMAPACTIONS];
784 nmaps = switch_map_find("hosts", maptype, mapreturn);
785 UseNameServer = false;
786 if (nmaps > 0 && nmaps <= MAXMAPSTACK)
790 for (mapno = 0; mapno < nmaps && !UseNameServer;
793 if (strcmp(maptype[mapno], "dns") == 0)
794 UseNameServer = true;
802 ** TRANSLATE_DOLLARS -- convert $x into internal form
804 ** Actually does all appropriate pre-processing of a config line
805 ** to turn it into internal form.
808 ** ibp -- the buffer to translate.
809 ** obp -- where to put the translation; may be the same as obp
810 ** bsp -- a pointer to the size of obp; will be updated if
811 ** the buffer needs to be replaced.
814 ** The buffer pointer; may differ from obp if the expansion
815 ** is larger then *bsp, in which case this will point to
816 ** malloc()ed memory which must be free()d by the caller.
820 translate_dollars(ibp, obp, bsp)
831 sm_dprintf("translate_dollars(");
832 xputs(sm_debug_file(), ibp);
836 bp = quote_internal_chars(ibp, obp, bsp);
838 for (p = bp; *p != '\0'; p++)
840 if (*p == '#' && p > bp && ConfigLevel >= 3)
847 /* it's from $# -- let it go through */
852 /* it's backslash escaped */
853 (void) sm_strlcpy(p, p + 1, strlen(p));
857 /* delete leading white space */
858 while (SM_ISSPACE(*p) &&
859 *p != '\n' && p > bp)
863 if ((e = strchr(++p, '\n')) != NULL)
864 (void) sm_strlcpy(p, e, strlen(p));
872 if (*p != '$' || p[1] == '\0')
877 /* actual dollar sign.... */
878 (void) sm_strlcpy(p, p + 1, strlen(p));
882 /* convert to macro expansion character */
885 /* special handling for $=, $~, $&, and $? */
886 if (*p == '=' || *p == '~' || *p == '&' || *p == '?')
889 /* convert macro name to code */
890 *p = macid_parse(p, &ep);
892 (void) sm_strlcpy(p + 1, ep, strlen(p + 1));
895 /* strip trailing white space from the line */
896 while (--p > bp && SM_ISSPACE(*p))
901 sm_dprintf(" translate_dollars => ");
902 xputs(sm_debug_file(), bp);
909 ** TOOMANY -- signal too many of some option
912 ** id -- the id of the error line
913 ** maxcnt -- the maximum possible values
927 syserr("too many %c lines, %d max", id, maxcnt);
930 ** FILECLASS -- read members of a class from a file
933 ** class -- class to define.
934 ** filename -- name of file to read.
935 ** fmt -- scanf string to use for match.
936 ** ismap -- if set, this is a map lookup.
937 ** safe -- if set, this is a safe read.
938 ** optional -- if set, it is not an error for the file to
945 ** puts all lines in filename that match a scanf into
950 ** Break up the match into words and add to class.
954 parse_class_words(class, line)
958 while (line != NULL && *line != '\0')
962 /* strip leading spaces */
963 while (SM_ISSPACE(*line))
968 /* find the end of the word */
970 while (*line != '\0' && !(SM_ISSPACE(*line)))
975 /* enter the word in the symbol table */
981 fileclass(class, filename, fmt, ismap, safe, optional)
996 sm_dprintf("fileclass(%s, fmt=%s)\n", filename, fmt);
998 if (*filename == '\0')
1000 syserr("fileclass: missing file name");
1012 mn = newstr(macname(class));
1017 if ((p = strchr(filename, '@')) == NULL)
1019 /* should not happen */
1020 syserr("fileclass: bogus map specification");
1030 if (strcmp(cl, "LDAP") == 0)
1034 char jbuf[MAXHOSTNAMELEN];
1035 char lcbuf[MAXLINE];
1038 expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope);
1039 if (jbuf[0] == '\0')
1041 (void) sm_strlcpy(jbuf, "localhost",
1045 /* impose the default schema */
1046 lc = macvalue(macid("{sendmailMTACluster}"), CurEnv);
1051 expand(lc, lcbuf, sizeof(lcbuf), CurEnv);
1056 n = sm_snprintf(buf, sizeof(buf),
1057 "-k (&(objectClass=sendmailMTAClass)(sendmailMTAClassName=%s)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))) -v sendmailMTAClassValue,sendmailMTAClassSearch:FILTER:sendmailMTAClass,sendmailMTAClassURL:URL:sendmailMTAClass",
1059 if (n >= sizeof(buf))
1061 syserr("fileclass: F{%s}: Default LDAP string too long",
1069 #endif /* LDAPMAP */
1071 if ((spec = strchr(cl, ':')) == NULL)
1073 syserr("fileclass: F{%s}: missing map class",
1081 /* set up map structure */
1082 mapclass = stab(cl, ST_MAPCLASS, ST_FIND);
1083 if (mapclass == NULL)
1085 syserr("fileclass: F{%s}: class %s not available",
1090 memset(&map, '\0', sizeof(map));
1091 map.map_class = &mapclass->s_mapclass;
1093 map.map_mflags |= MF_FILECLASS;
1096 sm_dprintf("fileclass: F{%s}: map class %s, key %s, spec %s\n",
1100 /* parse map spec */
1101 if (!map.map_class->map_parse(&map, spec))
1103 /* map_parse() showed the error already */
1107 map.map_mflags |= MF_VALID;
1110 if (map.map_class->map_open(&map, O_RDONLY))
1112 map.map_mflags |= MF_OPEN;
1113 map.map_pid = getpid();
1118 !bitset(MF_OPTIONAL, map.map_mflags))
1119 syserr("fileclass: F{%s}: map open failed",
1126 p = (*map.map_class->map_lookup)(&map, key, NULL, &status);
1127 if (status != EX_OK && status != EX_NOTFOUND)
1130 syserr("fileclass: F{%s}: map lookup failed",
1135 /* use the results */
1137 parse_class_words(class, p);
1140 map.map_mflags |= MF_CLOSING;
1141 map.map_class->map_close(&map);
1142 map.map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
1146 else if (filename[0] == '|')
1150 char *argv[MAXPV + 1];
1153 for (p = strtok(&filename[1], " \t");
1154 p != NULL && i < MAXPV;
1155 p = strtok(NULL, " \t"))
1158 pid = prog_open(argv, &fd, CurEnv);
1162 f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
1163 (void *) &fd, SM_IO_RDONLY, NULL);
1169 if (!bitnset(DBS_CLASSFILEINUNSAFEDIRPATH, DontBlameSendmail))
1170 sff |= SFF_SAFEDIRPATH;
1171 if (!bitnset(DBS_LINKEDCLASSFILEINWRITABLEDIR,
1175 sff |= SFF_OPENASROOT;
1176 else if (RealUid == 0)
1178 if (DontLockReadFiles)
1180 f = safefopen(filename, O_RDONLY, 0, sff);
1185 syserr("fileclass: cannot open '%s'", filename);
1189 while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
1192 char wordbuf[MAXLINE + 1];
1198 if (sm_io_sscanf(buf, fmt, wordbuf) != 1)
1205 parse_class_words(class, p);
1208 ** If anything else is added here,
1209 ** check if the '@' map case above
1210 ** needs the code as well.
1214 (void) sm_io_close(f, SM_TIME_DEFAULT);
1216 (void) waitfor(pid);
1220 /* first character for dynamically created mailers */
1221 static char dynmailerp = ' ';
1223 /* list of first characters for cf defined mailers */
1224 static char frst[MAXMAILERS + 1];
1227 ** SETUPDYNMAILERS -- find a char that isn't used as first element of any
1236 ** Note: space is not valid in cf defined mailers hence the function
1237 ** will always find a char. It's not nice, but this is for
1238 ** internal names only.
1245 char pp[] = "YXZ0123456789ABCDEFGHIJKLMNOPQRSTUVWyxzabcfghijkmnoqtuvw ";
1247 frst[MAXMAILERS] = '\0';
1248 for (i = 0; i < strlen(pp); i++)
1250 if (strchr(frst, pp[i]) == NULL)
1254 sm_dprintf("dynmailerp=%c\n", dynmailerp);
1264 ** NEWMODMAILER -- Create a new mailer with modifications
1267 ** rcpt -- current RCPT
1268 ** fl -- flag to set
1271 ** true iff successful.
1273 ** Note: this creates a copy of the mailer for the rcpt and
1274 ** modifies exactly one flag. It does not work
1275 ** for multiple flags!
1279 newmodmailer(rcpt, fl)
1288 SM_REQUIRE(rcpt != NULL);
1289 if (rcpt->q_mailer == NULL)
1292 sm_dprintf("newmodmailer: rcpt=%s\n", rcpt->q_paddr);
1293 SM_REQUIRE(rcpt->q_mailer->m_name != NULL);
1294 SM_REQUIRE(rcpt->q_mailer->m_name[0] != '\0');
1295 sm_strlcpy(mname, rcpt->q_mailer->m_name, sizeof(mname));
1296 mname[0] = dynmailerp;
1298 sm_dprintf("newmodmailer: name=%s\n", mname);
1299 s = stab(mname, ST_MAILER, ST_ENTER);
1300 if (s->s_mailer != NULL)
1302 idx = s->s_mailer->m_mno;
1304 sm_dprintf("newmodmailer: found idx=%d\n", idx);
1308 idx = rcpt->q_mailer->m_mno;
1311 sm_dprintf("newmodmailer: idx=%d\n", idx);
1312 if (idx > SM_ARRAY_SIZE(Mailer))
1318 m = (struct mailer *) xalloc(sizeof(*m));
1319 memset((char *) m, '\0', sizeof(*m));
1320 STRUCTCOPY(*rcpt->q_mailer, *m);
1323 /* "modify" the mailer */
1324 setbitn(bitidx(fl), m->m_flags);
1327 m->m_name = newstr(mname);
1329 sm_dprintf("newmodmailer: mailer[%d]=%s %p\n",
1330 idx, Mailer[idx]->m_name, Mailer[idx]);
1335 #endif /* _FFR_RCPTFLAGS */
1338 ** MAKEMAILER -- define a new mailer.
1341 ** line -- description of mailer. This is in labeled
1342 ** fields. The fields are:
1343 ** A -- the argv for this mailer
1344 ** C -- the character set for MIME conversions
1345 ** D -- the directory to run in
1346 ** E -- the eol string
1347 ** F -- the flags associated with the mailer
1348 ** L -- the maximum line length
1349 ** M -- the maximum message size
1350 ** N -- the niceness at which to run
1351 ** P -- the path to the mailer
1352 ** Q -- the queue group for the mailer
1353 ** R -- the recipient rewriting set
1354 ** S -- the sender rewriting set
1355 ** T -- the mailer type (for DSNs)
1356 ** U -- the uid to run as
1357 ** W -- the time to wait at the end
1358 ** m -- maximum messages per connection
1359 ** r -- maximum number of recipients per message
1360 ** / -- new root directory
1361 ** The first word is the canonical name of the mailer.
1367 ** enters the mailer into the mailer table.
1376 register struct mailer *m;
1381 static int nextmailer = 0; /* "free" index into Mailer struct */
1383 /* allocate a mailer and set up defaults */
1384 m = (struct mailer *) xalloc(sizeof(*m));
1385 memset((char *) m, '\0', sizeof(*m));
1386 errno = 0; /* avoid bogus error text */
1388 /* collect the mailer name */
1390 *p != '\0' && *p != ',' && !(SM_ISSPACE(*p));
1395 if (line[0] == '\0')
1397 syserr("name required for mailer");
1400 m->m_name = newstr(line);
1402 frst[nextmailer] = line[0];
1408 /* now scan through and assign info from the fields */
1411 auto char *delimptr;
1413 while (*p != '\0' &&
1414 (*p == ',' || (SM_ISSPACE(*p))))
1417 /* p now points to field code */
1419 while (*p != '\0' && *p != '=' && *p != ',')
1423 syserr("mailer %s: `=' expected", m->m_name);
1426 while (SM_ISSPACE(*p))
1429 /* p now points to the field body */
1430 p = munchstring(p, &delimptr, ',');
1432 /* install the field into the mailer struct */
1435 case 'P': /* pathname */
1436 if (*p != '\0') /* error is issued below */
1437 m->m_mailer = newstr(p);
1440 case 'F': /* flags */
1441 for (; *p != '\0'; p++)
1443 if (!(SM_ISSPACE(*p)))
1445 if (*p == M_INTERNAL)
1446 sm_syslog(LOG_WARNING, NOQID,
1447 "WARNING: mailer=%s, flag=%c deprecated",
1449 setbitn(bitidx(*p), m->m_flags);
1454 case 'S': /* sender rewriting ruleset */
1455 case 'R': /* recipient rewriting ruleset */
1456 i = strtorwset(p, &endp, ST_ENTER);
1460 m->m_sh_rwset = m->m_se_rwset = i;
1462 m->m_rh_rwset = m->m_re_rwset = i;
1467 i = strtorwset(p, NULL, ST_ENTER);
1477 case 'E': /* end of line string */
1479 syserr("mailer %s: null end-of-line string",
1482 m->m_eol = newstr(p);
1485 case 'A': /* argument vector */
1486 if (*p != '\0') /* error is issued below */
1487 m->m_argv = makeargv(p);
1490 case 'M': /* maximum message size */
1491 m->m_maxsize = atol(p);
1494 case 'm': /* maximum messages per connection */
1495 m->m_maxdeliveries = atoi(p);
1498 case 'r': /* max recipient per envelope */
1499 m->m_maxrcpt = atoi(p);
1502 case 'L': /* maximum line length */
1503 m->m_linelimit = atoi(p);
1504 if (m->m_linelimit < 0)
1508 case 'N': /* run niceness */
1509 m->m_nice = atoi(p);
1512 case 'D': /* working directory */
1514 syserr("mailer %s: null working directory",
1517 m->m_execdir = newstr(p);
1520 case 'C': /* default charset */
1522 syserr("mailer %s: null charset", m->m_name);
1524 m->m_defcharset = newstr(p);
1527 case 'Q': /* queue for this mailer */
1530 syserr("mailer %s: null queue", m->m_name);
1533 s = stab(p, ST_QUEUE, ST_FIND);
1535 syserr("mailer %s: unknown queue %s",
1538 m->m_qgrp = s->s_quegrp->qg_index;
1541 case 'T': /* MTA-Name/Address/Diagnostic types */
1542 /* extract MTA name type; default to "dns" */
1543 m->m_mtatype = newstr(p);
1544 p = strchr(m->m_mtatype, '/');
1551 if (*m->m_mtatype == '\0')
1552 m->m_mtatype = "dns";
1554 /* extract address type; default to "rfc822" */
1564 if (m->m_addrtype == NULL || *m->m_addrtype == '\0')
1565 m->m_addrtype = "rfc822";
1567 /* extract diagnostic type; default to "smtp" */
1569 if (m->m_diagtype == NULL || *m->m_diagtype == '\0')
1570 m->m_diagtype = "smtp";
1573 case 'U': /* user id */
1574 if (isascii(*p) && !isdigit(*p))
1579 while (*p != '\0' && isascii(*p) &&
1580 # if _FFR_DOTTED_USERNAMES
1581 (isalnum(*p) || strchr(SM_PWN_CHARS, *p) != NULL))
1583 (isalnum(*p) || strchr("-_", *p) != NULL))
1586 while (SM_ISSPACE(*p))
1592 syserr("mailer %s: null user name",
1596 pw = sm_getpwnam(q);
1599 syserr("readcf: mailer U= flag: unknown user %s", q);
1604 m->m_uid = pw->pw_uid;
1605 m->m_gid = pw->pw_gid;
1612 m->m_uid = strtol(p, &q, 0);
1614 while (SM_ISSPACE(*p))
1619 while (SM_ISSPACE(*p))
1623 if (isascii(*p) && !isdigit(*p))
1628 while (isascii(*p) &&
1629 (isalnum(*p) || strchr(SM_PWN_CHARS, *p) != NULL))
1634 syserr("mailer %s: null group name",
1641 syserr("readcf: mailer U= flag: unknown group %s", q);
1645 m->m_gid = gr->gr_gid;
1649 m->m_gid = strtol(p, NULL, 0);
1653 case 'W': /* wait timeout */
1654 m->m_wait = convtime(p, 's');
1657 case '/': /* new root directory */
1659 syserr("mailer %s: null root directory",
1662 m->m_rootdir = newstr(p);
1666 syserr("M%s: unknown mailer equate %c=",
1675 if (bitnset(M_SECURE_PORT, m->m_flags))
1677 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1678 "M%s: Warning: F=%c set on system that doesn't support rresvport()\n",
1679 m->m_name, M_SECURE_PORT);
1681 #endif /* !HASRRESVPORT */
1686 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1687 "M%s: Warning: N= set on system that doesn't support nice()\n",
1690 #endif /* !HASNICE */
1692 /* do some rationality checking */
1693 if (m->m_argv == NULL)
1695 syserr("M%s: A= argument required", m->m_name);
1698 if (m->m_mailer == NULL)
1700 syserr("M%s: P= argument required", m->m_name);
1704 if (nextmailer >= MAXMAILERS)
1706 syserr("too many mailers defined (%d max)", MAXMAILERS);
1710 if (m->m_maxrcpt <= 0)
1711 m->m_maxrcpt = DEFAULT_MAX_RCPT;
1713 /* do some heuristic cleanup for back compatibility */
1714 if (bitnset(M_LIMITS, m->m_flags))
1716 if (m->m_linelimit == 0)
1717 m->m_linelimit = SMTPLINELIM;
1718 if (ConfigLevel < 2)
1719 setbitn(M_7BITS, m->m_flags);
1722 if (strcmp(m->m_mailer, "[TCP]") == 0)
1724 syserr("M%s: P=[TCP] must be replaced by P=[IPC]", m->m_name);
1728 if (strcmp(m->m_mailer, "[IPC]") == 0)
1730 /* Use the second argument for host or path to socket */
1731 if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
1732 m->m_argv[1][0] == '\0')
1734 syserr("M%s: too few parameters for %s mailer",
1735 m->m_name, m->m_mailer);
1738 if (strcmp(m->m_argv[0], "TCP") != 0
1740 && strcmp(m->m_argv[0], "FILE") != 0
1744 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1745 "M%s: Warning: first argument in %s mailer must be %s\n",
1746 m->m_name, m->m_mailer,
1754 if (m->m_mtatype == NULL)
1755 m->m_mtatype = "dns";
1756 if (m->m_addrtype == NULL)
1757 m->m_addrtype = "rfc822";
1758 if (m->m_diagtype == NULL)
1760 if (m->m_argv[0] != NULL &&
1761 strcmp(m->m_argv[0], "FILE") == 0)
1762 m->m_diagtype = "x-unix";
1764 m->m_diagtype = "smtp";
1767 else if (strcmp(m->m_mailer, "[FILE]") == 0)
1769 /* Use the second argument for filename */
1770 if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
1771 m->m_argv[2] != NULL)
1773 syserr("M%s: too %s parameters for [FILE] mailer",
1775 (m->m_argv[0] == NULL ||
1776 m->m_argv[1] == NULL) ? "few" : "many");
1779 else if (strcmp(m->m_argv[0], "FILE") != 0)
1781 syserr("M%s: first argument in [FILE] mailer must be FILE",
1787 if (m->m_eol == NULL)
1791 /* default for SMTP is \r\n; use \n for local delivery */
1792 for (pp = m->m_argv; *pp != NULL; pp++)
1794 for (p = *pp; *p != '\0'; )
1796 if ((*p++ & 0377) == MACROEXPAND && *p == 'u')
1808 /* enter the mailer into the symbol table */
1809 s = stab(m->m_name, ST_MAILER, ST_ENTER);
1810 if (s->s_mailer != NULL)
1812 i = s->s_mailer->m_mno;
1813 sm_free(s->s_mailer); /* XXX */
1819 Mailer[i] = s->s_mailer = m;
1823 ** MUNCHSTRING -- translate a string into internal form.
1826 ** p -- the string to munch.
1827 ** delimptr -- if non-NULL, set to the pointer of the
1828 ** field delimiter character.
1829 ** delim -- the delimiter for the field.
1832 ** the munched string.
1835 ** the munched string is a local static buffer.
1836 ** it must be copied before the function is called again.
1840 munchstring(p, delimptr, delim)
1846 bool backslash = false;
1847 bool quotemode = false;
1848 static char buf[MAXLINE];
1850 for (q = buf; *p != '\0' && q < &buf[sizeof(buf) - 1]; p++)
1854 /* everything is roughly literal */
1858 case 'r': /* carriage return */
1862 case 'n': /* newline */
1866 case 'f': /* form feed */
1870 case 'b': /* backspace */
1881 quotemode = !quotemode;
1882 else if (quotemode || *p != delim)
1889 if (delimptr != NULL)
1895 ** EXTRQUOTSTR -- extract a (quoted) string.
1897 ** This routine deals with quoted (") strings and escaped
1901 ** p -- source string.
1902 ** delimptr -- if non-NULL, set to the pointer of the
1903 ** field delimiter character.
1904 ** delimbuf -- delimiters for the field.
1905 ** st -- if non-NULL, store the return value (whether the
1906 ** string was correctly quoted) here.
1909 ** the extracted string.
1912 ** the returned string is a local static buffer.
1913 ** it must be copied before the function is called again.
1917 extrquotstr(p, delimptr, delimbuf, st)
1924 bool backslash = false;
1925 bool quotemode = false;
1926 static char buf[MAXLINE];
1928 for (q = buf; *p != '\0' && q < &buf[sizeof(buf) - 1]; p++)
1939 quotemode = !quotemode;
1940 else if (quotemode ||
1941 strchr(delimbuf, (int) *p) == NULL)
1947 if (delimptr != NULL)
1951 *st = !(quotemode || backslash);
1955 ** MAKEARGV -- break up a string into words
1958 ** p -- the string to break up.
1961 ** a char **argv (dynamically allocated)
1974 char *argv[MAXPV + 1];
1976 /* take apart the words */
1978 while (*p != '\0' && i < MAXPV)
1981 while (*p != '\0' && !(SM_ISSPACE(*p)))
1983 while (SM_ISSPACE(*p))
1985 argv[i++] = newstr(q);
1989 /* now make a copy of the argv */
1990 avp = (char **) xalloc(sizeof(*avp) * i);
1991 memmove((char *) avp, (char *) argv, sizeof(*avp) * i);
1996 ** PRINTRULES -- print rewrite rules (for debugging)
2005 ** prints rewrite rules.
2011 register struct rewrite *rwp;
2012 register int ruleset;
2014 for (ruleset = 0; ruleset < 10; ruleset++)
2016 if (RewriteRules[ruleset] == NULL)
2018 sm_dprintf("\n----Rule Set %d:", ruleset);
2020 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
2022 sm_dprintf("\nLHS:");
2023 printav(sm_debug_file(), rwp->r_lhs);
2025 printav(sm_debug_file(), rwp->r_rhs);
2030 ** PRINTMAILER -- print mailer structure (for debugging)
2033 ** fp -- output file
2034 ** m -- the mailer to print
2047 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2048 "mailer %d (%s): P=%s S=", m->m_mno, m->m_name,
2050 if (RuleSetNames[m->m_se_rwset] == NULL)
2051 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d/",
2054 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s/",
2055 RuleSetNames[m->m_se_rwset]);
2056 if (RuleSetNames[m->m_sh_rwset] == NULL)
2057 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d R=",
2060 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s R=",
2061 RuleSetNames[m->m_sh_rwset]);
2062 if (RuleSetNames[m->m_re_rwset] == NULL)
2063 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d/",
2066 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s/",
2067 RuleSetNames[m->m_re_rwset]);
2068 if (RuleSetNames[m->m_rh_rwset] == NULL)
2069 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d ",
2072 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s ",
2073 RuleSetNames[m->m_rh_rwset]);
2074 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "M=%ld U=%d:%d F=",
2075 m->m_maxsize, (int) m->m_uid, (int) m->m_gid);
2076 for (j = '\0'; j <= '\177'; j++)
2077 if (bitnset(j, m->m_flags))
2078 (void) sm_io_putc(fp, SM_TIME_DEFAULT, j);
2079 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " L=%d E=",
2081 xputs(fp, m->m_eol);
2082 if (m->m_defcharset != NULL)
2083 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " C=%s",
2085 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " T=%s/%s/%s",
2086 m->m_mtatype == NULL
2087 ? "<undefined>" : m->m_mtatype,
2088 m->m_addrtype == NULL
2089 ? "<undefined>" : m->m_addrtype,
2090 m->m_diagtype == NULL
2091 ? "<undefined>" : m->m_diagtype);
2092 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " r=%d", m->m_maxrcpt);
2093 if (m->m_argv != NULL)
2095 char **a = m->m_argv;
2097 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " A=");
2101 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2106 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\n");
2110 static struct ssl_options
2112 const char *sslopt_name; /* name of the flag */
2113 long sslopt_bits; /* bits to set/clear */
2116 /* Workaround for bugs are turned on by default (as well as some others) */
2117 #ifdef SSL_OP_MICROSOFT_SESS_ID_BUG
2118 { "SSL_OP_MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG },
2120 #ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG
2121 { "SSL_OP_NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG },
2123 #ifdef SSL_OP_LEGACY_SERVER_CONNECT
2124 { "SSL_OP_LEGACY_SERVER_CONNECT", SSL_OP_LEGACY_SERVER_CONNECT },
2126 #ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
2127 { "SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG },
2129 #ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
2130 { "SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG },
2132 #ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
2133 { "SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER },
2135 #ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
2136 { "SSL_OP_MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING },
2138 #ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG
2139 { "SSL_OP_SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG },
2141 #ifdef SSL_OP_TLS_D5_BUG
2142 { "SSL_OP_TLS_D5_BUG", SSL_OP_TLS_D5_BUG },
2144 #ifdef SSL_OP_TLS_BLOCK_PADDING_BUG
2145 { "SSL_OP_TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG },
2147 #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
2148 { "SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS },
2151 { "SSL_OP_ALL", SSL_OP_ALL },
2153 #ifdef SSL_OP_NO_QUERY_MTU
2154 { "SSL_OP_NO_QUERY_MTU", SSL_OP_NO_QUERY_MTU },
2156 #ifdef SSL_OP_COOKIE_EXCHANGE
2157 { "SSL_OP_COOKIE_EXCHANGE", SSL_OP_COOKIE_EXCHANGE },
2159 #ifdef SSL_OP_NO_TICKET
2160 { "SSL_OP_NO_TICKET", SSL_OP_NO_TICKET },
2162 #ifdef SSL_OP_CISCO_ANYCONNECT
2163 { "SSL_OP_CISCO_ANYCONNECT", SSL_OP_CISCO_ANYCONNECT },
2165 #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
2166 { "SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION },
2168 #ifdef SSL_OP_NO_COMPRESSION
2169 { "SSL_OP_NO_COMPRESSION", SSL_OP_NO_COMPRESSION },
2171 #ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
2172 { "SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION },
2174 #ifdef SSL_OP_SINGLE_ECDH_USE
2175 { "SSL_OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE },
2177 #ifdef SSL_OP_SINGLE_DH_USE
2178 { "SSL_OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE },
2180 #ifdef SSL_OP_EPHEMERAL_RSA
2181 { "SSL_OP_EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA },
2183 #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
2184 { "SSL_OP_CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE },
2186 #ifdef SSL_OP_TLS_ROLLBACK_BUG
2187 { "SSL_OP_TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG },
2189 #ifdef SSL_OP_NO_SSLv2
2190 { "SSL_OP_NO_SSLv2", SSL_OP_NO_SSLv2 },
2192 #ifdef SSL_OP_NO_SSLv3
2193 { "SSL_OP_NO_SSLv3", SSL_OP_NO_SSLv3 },
2195 #ifdef SSL_OP_NO_TLSv1
2196 { "SSL_OP_NO_TLSv1", SSL_OP_NO_TLSv1 },
2198 #ifdef SSL_OP_NO_TLSv1_3
2199 { "SSL_OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3 },
2201 #ifdef SSL_OP_NO_TLSv1_2
2202 { "SSL_OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2 },
2204 #ifdef SSL_OP_NO_TLSv1_1
2205 { "SSL_OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1 },
2207 #ifdef SSL_OP_PKCS1_CHECK_1
2208 { "SSL_OP_PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1 },
2210 #ifdef SSL_OP_PKCS1_CHECK_2
2211 { "SSL_OP_PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2 },
2213 #ifdef SSL_OP_NETSCAPE_CA_DN_BUG
2214 { "SSL_OP_NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG },
2216 #ifdef SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
2217 { "SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG },
2219 #ifdef SSL_OP_CRYPTOPRO_TLSEXT_BUG
2220 { "SSL_OP_CRYPTOPRO_TLSEXT_BUG", SSL_OP_CRYPTOPRO_TLSEXT_BUG },
2222 #ifdef SSL_OP_TLSEXT_PADDING
2223 { "SSL_OP_TLSEXT_PADDING", SSL_OP_TLSEXT_PADDING },
2225 #ifdef SSL_OP_NO_RENEGOTIATION
2226 { "SSL_OP_NO_RENEGOTIATION", SSL_OP_NO_RENEGOTIATION },
2228 #ifdef SSL_OP_NO_ANTI_REPLAY
2229 { "SSL_OP_NO_ANTI_REPLAY", SSL_OP_NO_ANTI_REPLAY },
2231 #ifdef SSL_OP_ALLOW_NO_DHE_KEX
2232 { "SSL_OP_ALLOW_NO_DHE_KEX", SSL_OP_ALLOW_NO_DHE_KEX },
2234 #ifdef SSL_OP_NO_ENCRYPT_THEN_MAC
2235 { "SSL_OP_NO_ENCRYPT_THEN_MAC", SSL_OP_NO_ENCRYPT_THEN_MAC },
2237 #ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
2238 { "SSL_OP_ENABLE_MIDDLEBOX_COMPAT", SSL_OP_ENABLE_MIDDLEBOX_COMPAT },
2240 #ifdef SSL_OP_PRIORITIZE_CHACHA
2241 { "SSL_OP_PRIORITIZE_CHACHA", SSL_OP_PRIORITIZE_CHACHA },
2247 ** READSSLOPTIONS -- read SSL_OP_* values
2250 ** opt -- name of option (can be NULL)
2251 ** val -- string with SSL_OP_* values or hex value
2252 ** delim -- end of string (e.g., '\0' or ';')
2253 ** pssloptions -- return value (output)
2259 #define SSLOPERR_NAN 1
2260 #define SSLOPERR_NOTFOUND 2
2262 static int readssloptions __P((char *, char *, unsigned long *, int ));
2265 readssloptions(opt, val, pssloptions, delim)
2268 unsigned long *pssloptions;
2275 for (p = val; *p != '\0' && *p != delim; )
2279 unsigned long sslopt_val;
2280 struct ssl_options *sslopts;
2287 if (*p == '-' || *p == '+')
2288 clearmode = *p++ == '-';
2290 while (*p != '\0' && !(SM_ISSPACE(*p)) && *p != ',')
2299 sslopt_val = strtoul(q, &end, 0);
2301 /* not a complete "syntax" check but good enough */
2307 syserr("readcf: %s option value %s not a number",
2314 for (sslopts = SSL_Option;
2315 sslopts->sslopt_name != NULL; sslopts++)
2317 if (sm_strcasecmp(q, sslopts->sslopt_name) == 0)
2319 sslopt_val = sslopts->sslopt_bits;
2323 if (sslopts->sslopt_name == NULL)
2326 ret = SSLOPERR_NOTFOUND;
2328 syserr("readcf: %s option value %s unrecognized",
2332 if (sslopt_val != 0)
2335 *pssloptions &= ~sslopt_val;
2337 *pssloptions |= sslopt_val;
2344 ** GET_TLS_SE_OPTIONS -- get TLS session options (from ruleset)
2348 ** ssl -- TLS session context
2349 ** tlsi_ctx -- TLS info context
2357 get_tls_se_options(e, ssl, tlsi_ctx, srv)
2360 tlsi_ctx_T *tlsi_ctx;
2363 bool saveQuickAbort, saveSuprErrs, ok;
2364 char *optionlist, *opt, *val;
2365 char *keyfile, *certfile;
2369 # define who (srv ? "server" : "client")
2370 # define NAME_C_S macvalue(macid(srv ? "{client_name}" : "{server_name}"), e)
2371 # define ADDR_C_S macvalue(macid(srv ? "{client_addr}" : "{server_addr}"), e)
2372 # define WHICH srv ? "srv" : "clt"
2375 keyfile = certfile = opt = val = NULL;
2376 saveQuickAbort = QuickAbort;
2377 saveSuprErrs = SuprErrs;
2382 ok = rscheck(srv ? "tls_srv_features" : "tls_clt_features",
2383 NAME_C_S, ADDR_C_S, e,
2384 RSF_RMCOMM|RSF_ADDR|RSF_STRING,
2385 5, NULL, NOQID, NULL, &optionlist) == EX_OK;
2386 if (!ok && LogLevel > 8)
2388 sm_syslog(LOG_NOTICE, NOQID,
2389 "rscheck(tls_%s_features)=failed, relay=%s [%s], errors=%d",
2390 WHICH, NAME_C_S, ADDR_C_S,
2393 QuickAbort = saveQuickAbort;
2394 SuprErrs = saveSuprErrs;
2395 if (ok && LogLevel > 9)
2397 sm_syslog(LOG_INFO, NOQID,
2398 "tls_%s_features=%s, relay=%s [%s]",
2399 WHICH, optionlist, NAME_C_S, ADDR_C_S);
2401 if (!ok || optionlist == NULL || (len = strlen(optionlist)) < 2)
2404 sm_syslog(LOG_INFO, NOQID,
2405 "tls_%s_features=empty, relay=%s [%s]",
2406 WHICH, NAME_C_S, ADDR_C_S);
2412 if (optionlist[0] == '"' && optionlist[len - 1] == '"')
2414 optionlist[0] = ' ';
2415 optionlist[--len] = '\0';
2418 if (LogLevel > 9 && len > 1)
2419 sm_syslog(LOG_INFO, NOQID,
2420 "tls_%s_features=too_short, relay=%s [%s]",
2421 WHICH, NAME_C_S, ADDR_C_S);
2423 /* this is not treated as error! */
2429 # define INVALIDSYNTAX \
2432 sm_syslog(LOG_INFO, NOQID, \
2433 "tls_%s_features=invalid_syntax, opt=%s, relay=%s [%s]", \
2434 WHICH, opt, NAME_C_S, ADDR_C_S); \
2446 while (i < len && SM_ISSPACE(optionlist[i])) \
2451 /* parse and handle opt=val; */
2456 opt = optionlist + i;
2458 while (i < len && optionlist[i] != sep
2459 && optionlist[i] != '\0' && !SM_ISSPACE(optionlist[i]))
2462 while (i < len && SM_ISSPACE(optionlist[i]))
2463 optionlist[i++] = '\0';
2465 if (optionlist[i] != sep)
2467 optionlist[i++] = '\0';
2470 val = optionlist + i;
2472 while (i < len && optionlist[i] != sep && optionlist[i] != '\0')
2474 if (optionlist[i] != '\0')
2477 optionlist[i++] = '\0';
2481 sm_syslog(LOG_DEBUG, NOQID,
2482 "tls_%s_features=parsed, %s=%s, relay=%s [%s]",
2483 WHICH, opt, val, NAME_C_S, ADDR_C_S);
2485 if (sm_strcasecmp(opt, "options") == 0)
2487 unsigned long ssloptions;
2490 ret = readssloptions(NULL, val, &ssloptions, ';');
2492 (void) SSL_set_options(ssl, (long) ssloptions);
2493 else if (LogLevel > 8)
2495 sm_syslog(LOG_WARNING, NOQID,
2496 "tls_%s_features=%s, error=%s, relay=%s [%s]",
2498 (ret == SSLOPERR_NAN) ? "not a number" :
2499 ((ret == SSLOPERR_NOTFOUND) ? "SSL_OP not found" :
2501 NAME_C_S, ADDR_C_S);
2504 else if (sm_strcasecmp(opt, "cipherlist") == 0)
2506 if (SSL_set_cipher_list(ssl, val) <= 0)
2511 sm_syslog(LOG_WARNING, NOQID,
2512 "STARTTLS=%s, error: SSL_set_cipher_list(%s) failed",
2515 tlslogerr(LOG_WARNING, 9, who);
2519 else if (sm_strcasecmp(opt, "flags") == 0)
2523 for (p = val; *p != '\0'; p++)
2525 if (isascii(*p) && isalnum(*p))
2526 setbitn(bitidx(*p), tlsi_ctx->tlsi_flags);
2529 else if (sm_strcasecmp(opt, "keyfile") == 0)
2531 else if (sm_strcasecmp(opt, "certfile") == 0)
2538 sm_syslog(LOG_INFO, NOQID,
2539 "tls_%s_features=unknown_option, opt=%s, relay=%s [%s]",
2540 WHICH, opt, NAME_C_S, ADDR_C_S);
2544 } while (optionlist[i] != '\0' && i < len);
2546 /* need cert and key before we can use the options */
2547 /* does not implement the "," hack for 2nd cert/key pair */
2548 if (keyfile != NULL && certfile != NULL)
2550 load_certkey(ssl, srv, certfile, keyfile);
2551 keyfile = certfile = NULL;
2553 else if (keyfile != NULL || certfile != NULL)
2558 sm_syslog(LOG_INFO, NOQID,
2559 "tls_%s_features=only_one_of_CertFile/KeyFile_specified, relay=%s [%s]",
2560 WHICH, NAME_C_S, ADDR_C_S);
2570 #endif /* STARTTLS */
2573 ** SETOPTION -- set global processing option
2576 ** opt -- option name.
2577 ** val -- option value (as a text string).
2578 ** safe -- set if this came from a configuration file.
2579 ** Some options (if set from the command line) will
2580 ** reset the user id to avoid security problems.
2581 ** sticky -- if set, don't let other setoptions override
2583 ** e -- the main envelope.
2589 ** Sets options as implied by the arguments.
2592 static BITMAP256 StickyOpt; /* set if option is stuck */
2596 static struct resolverflags
2598 char *rf_name; /* name of the flag */
2599 long rf_bits; /* bits to set/clear */
2602 { "debug", RES_DEBUG },
2603 { "aaonly", RES_AAONLY },
2604 { "usevc", RES_USEVC },
2605 { "primary", RES_PRIMARY },
2606 { "igntc", RES_IGNTC },
2607 { "recurse", RES_RECURSE },
2608 { "defnames", RES_DEFNAMES },
2609 { "stayopen", RES_STAYOPEN },
2610 { "dnsrch", RES_DNSRCH },
2611 # ifdef RES_USE_INET6
2612 { "use_inet6", RES_USE_INET6 },
2614 # ifdef RES_USE_EDNS0
2615 { "use_edns0", RES_USE_EDNS0 },
2617 # ifdef RES_USE_DNSSEC
2618 { "use_dnssec", RES_USE_DNSSEC },
2621 { "trustad", RES_TRUSTAD },
2623 { "true", 0 }, /* avoid error on old syntax */
2624 { "true", 0 }, /* avoid error on old syntax */
2628 #endif /* NAMED_BIND */
2630 #define OI_NONE 0 /* no special treatment */
2631 #define OI_SAFE 0x0001 /* safe for random people to use */
2632 #define OI_SUBOPT 0x0002 /* option has suboptions */
2634 static struct optioninfo
2636 char *o_name; /* long name of option */
2637 unsigned char o_code; /* short name of option */
2638 unsigned short o_flags; /* option flags */
2641 #if defined(SUN_EXTENSIONS) && defined(REMOTE_MODE)
2642 { "RemoteMode", '>', OI_NONE },
2644 { "SevenBitInput", '7', OI_SAFE },
2645 { "EightBitMode", '8', OI_SAFE },
2646 { "AliasFile", 'A', OI_NONE },
2647 { "AliasWait", 'a', OI_NONE },
2648 { "BlankSub", 'B', OI_NONE },
2649 { "MinFreeBlocks", 'b', OI_SAFE },
2650 { "CheckpointInterval", 'C', OI_SAFE },
2651 { "HoldExpensive", 'c', OI_NONE },
2652 { "DeliveryMode", 'd', OI_SAFE },
2653 { "ErrorHeader", 'E', OI_NONE },
2654 { "ErrorMode", 'e', OI_SAFE },
2655 { "TempFileMode", 'F', OI_NONE },
2656 { "SaveFromLine", 'f', OI_NONE },
2657 { "MatchGECOS", 'G', OI_NONE },
2659 /* no long name, just here to avoid problems in setoption */
2660 { "", 'g', OI_NONE },
2661 { "HelpFile", 'H', OI_NONE },
2662 { "MaxHopCount", 'h', OI_NONE },
2663 { "ResolverOptions", 'I', OI_NONE },
2664 { "IgnoreDots", 'i', OI_SAFE },
2665 { "ForwardPath", 'J', OI_NONE },
2666 { "SendMimeErrors", 'j', OI_SAFE },
2667 { "ConnectionCacheSize", 'k', OI_NONE },
2668 { "ConnectionCacheTimeout", 'K', OI_NONE },
2669 { "UseErrorsTo", 'l', OI_NONE },
2670 { "LogLevel", 'L', OI_SAFE },
2671 { "MeToo", 'm', OI_SAFE },
2673 /* no long name, just here to avoid problems in setoption */
2674 { "", 'M', OI_NONE },
2675 { "CheckAliases", 'n', OI_NONE },
2676 { "OldStyleHeaders", 'o', OI_SAFE },
2677 { "DaemonPortOptions", 'O', OI_NONE },
2678 { "PrivacyOptions", 'p', OI_SAFE },
2679 { "PostmasterCopy", 'P', OI_NONE },
2680 { "QueueFactor", 'q', OI_NONE },
2681 { "QueueDirectory", 'Q', OI_NONE },
2682 { "DontPruneRoutes", 'R', OI_NONE },
2683 { "Timeout", 'r', OI_SUBOPT },
2684 { "StatusFile", 'S', OI_NONE },
2685 { "SuperSafe", 's', OI_SAFE },
2686 { "QueueTimeout", 'T', OI_NONE },
2687 { "TimeZoneSpec", 't', OI_NONE },
2688 { "UserDatabaseSpec", 'U', OI_NONE },
2689 { "DefaultUser", 'u', OI_NONE },
2690 { "FallbackMXhost", 'V', OI_NONE },
2691 { "Verbose", 'v', OI_SAFE },
2692 { "TryNullMXList", 'w', OI_NONE },
2693 { "QueueLA", 'x', OI_NONE },
2694 { "RefuseLA", 'X', OI_NONE },
2695 { "RecipientFactor", 'y', OI_NONE },
2696 { "ForkEachJob", 'Y', OI_NONE },
2697 { "ClassFactor", 'z', OI_NONE },
2698 { "RetryFactor", 'Z', OI_NONE },
2699 #define O_QUEUESORTORD 0x81
2700 { "QueueSortOrder", O_QUEUESORTORD, OI_SAFE },
2701 #define O_HOSTSFILE 0x82
2702 { "HostsFile", O_HOSTSFILE, OI_NONE },
2704 { "MinQueueAge", O_MQA, OI_SAFE },
2705 #define O_DEFCHARSET 0x85
2706 { "DefaultCharSet", O_DEFCHARSET, OI_SAFE },
2707 #define O_SSFILE 0x86
2708 { "ServiceSwitchFile", O_SSFILE, OI_NONE },
2709 #define O_DIALDELAY 0x87
2710 { "DialDelay", O_DIALDELAY, OI_SAFE },
2711 #define O_NORCPTACTION 0x88
2712 { "NoRecipientAction", O_NORCPTACTION, OI_SAFE },
2713 #define O_SAFEFILEENV 0x89
2714 { "SafeFileEnvironment", O_SAFEFILEENV, OI_NONE },
2715 #define O_MAXMSGSIZE 0x8a
2716 { "MaxMessageSize", O_MAXMSGSIZE, OI_NONE },
2717 #define O_COLONOKINADDR 0x8b
2718 { "ColonOkInAddr", O_COLONOKINADDR, OI_SAFE },
2719 #define O_MAXQUEUERUN 0x8c
2720 { "MaxQueueRunSize", O_MAXQUEUERUN, OI_SAFE },
2721 #define O_MAXCHILDREN 0x8d
2722 { "MaxDaemonChildren", O_MAXCHILDREN, OI_NONE },
2723 #define O_KEEPCNAMES 0x8e
2724 { "DontExpandCnames", O_KEEPCNAMES, OI_NONE },
2725 #define O_MUSTQUOTE 0x8f
2726 { "MustQuoteChars", O_MUSTQUOTE, OI_NONE },
2727 #define O_SMTPGREETING 0x90
2728 { "SmtpGreetingMessage", O_SMTPGREETING, OI_NONE },
2729 #define O_UNIXFROM 0x91
2730 { "UnixFromLine", O_UNIXFROM, OI_NONE },
2731 #define O_OPCHARS 0x92
2732 { "OperatorChars", O_OPCHARS, OI_NONE },
2733 #define O_DONTINITGRPS 0x93
2734 { "DontInitGroups", O_DONTINITGRPS, OI_NONE },
2736 { "SingleLineFromHeader", O_SLFH, OI_SAFE },
2738 { "AllowBogusHELO", O_ABH, OI_SAFE },
2739 #define O_CONNTHROT 0x97
2740 { "ConnectionRateThrottle", O_CONNTHROT, OI_NONE },
2742 { "UnsafeGroupWrites", O_UGW, OI_NONE },
2743 #define O_DBLBOUNCE 0x9a
2744 { "DoubleBounceAddress", O_DBLBOUNCE, OI_NONE },
2745 #define O_HSDIR 0x9b
2746 { "HostStatusDirectory", O_HSDIR, OI_NONE },
2747 #define O_SINGTHREAD 0x9c
2748 { "SingleThreadDelivery", O_SINGTHREAD, OI_NONE },
2749 #define O_RUNASUSER 0x9d
2750 { "RunAsUser", O_RUNASUSER, OI_NONE },
2751 #define O_DSN_RRT 0x9e
2752 { "RrtImpliesDsn", O_DSN_RRT, OI_NONE },
2753 #define O_PIDFILE 0x9f
2754 { "PidFile", O_PIDFILE, OI_NONE },
2755 #define O_DONTBLAMESENDMAIL 0xa0
2756 { "DontBlameSendmail", O_DONTBLAMESENDMAIL, OI_NONE },
2758 { "DontProbeInterfaces", O_DPI, OI_NONE },
2759 #define O_MAXRCPT 0xa2
2760 { "MaxRecipientsPerMessage", O_MAXRCPT, OI_SAFE },
2761 #define O_DEADLETTER 0xa3
2762 { "DeadLetterDrop", O_DEADLETTER, OI_NONE },
2763 #if _FFR_DONTLOCKFILESFORREAD_OPTION
2764 # define O_DONTLOCK 0xa4
2765 { "DontLockFilesForRead", O_DONTLOCK, OI_NONE },
2767 #define O_MAXALIASRCSN 0xa5
2768 { "MaxAliasRecursion", O_MAXALIASRCSN, OI_NONE },
2769 #define O_CNCTONLYTO 0xa6
2770 { "ConnectOnlyTo", O_CNCTONLYTO, OI_NONE },
2771 #define O_TRUSTUSER 0xa7
2772 { "TrustedUser", O_TRUSTUSER, OI_NONE },
2773 #define O_MAXMIMEHDRLEN 0xa8
2774 { "MaxMimeHeaderLength", O_MAXMIMEHDRLEN, OI_NONE },
2775 #define O_CONTROLSOCKET 0xa9
2776 { "ControlSocketName", O_CONTROLSOCKET, OI_NONE },
2777 #define O_MAXHDRSLEN 0xaa
2778 { "MaxHeadersLength", O_MAXHDRSLEN, OI_NONE },
2779 #if _FFR_MAX_FORWARD_ENTRIES
2780 # define O_MAXFORWARD 0xab
2781 { "MaxForwardEntries", O_MAXFORWARD, OI_NONE },
2783 #define O_PROCTITLEPREFIX 0xac
2784 { "ProcessTitlePrefix", O_PROCTITLEPREFIX, OI_NONE },
2785 #define O_SASLINFO 0xad
2786 #if _FFR_ALLOW_SASLINFO
2787 { "DefaultAuthInfo", O_SASLINFO, OI_SAFE },
2789 { "DefaultAuthInfo", O_SASLINFO, OI_NONE },
2791 #define O_SASLMECH 0xae
2792 { "AuthMechanisms", O_SASLMECH, OI_NONE },
2793 #define O_CLIENTPORT 0xaf
2794 { "ClientPortOptions", O_CLIENTPORT, OI_NONE },
2795 #define O_DF_BUFSIZE 0xb0
2796 { "DataFileBufferSize", O_DF_BUFSIZE, OI_NONE },
2797 #define O_XF_BUFSIZE 0xb1
2798 { "XscriptFileBufferSize", O_XF_BUFSIZE, OI_NONE },
2799 #define O_LDAPDEFAULTSPEC 0xb2
2800 { "LDAPDefaultSpec", O_LDAPDEFAULTSPEC, OI_NONE },
2801 #define O_SRVCERTFILE 0xb4
2802 { "ServerCertFile", O_SRVCERTFILE, OI_NONE },
2803 #define O_SRVKEYFILE 0xb5
2804 { "ServerKeyFile", O_SRVKEYFILE, OI_NONE },
2805 #define O_CLTCERTFILE 0xb6
2806 { "ClientCertFile", O_CLTCERTFILE, OI_NONE },
2807 #define O_CLTKEYFILE 0xb7
2808 { "ClientKeyFile", O_CLTKEYFILE, OI_NONE },
2809 #define O_CACERTFILE 0xb8
2810 { "CACertFile", O_CACERTFILE, OI_NONE },
2811 #define O_CACERTPATH 0xb9
2812 { "CACertPath", O_CACERTPATH, OI_NONE },
2813 #define O_DHPARAMS 0xba
2814 { "DHParameters", O_DHPARAMS, OI_NONE },
2815 #define O_INPUTMILTER 0xbb
2816 { "InputMailFilters", O_INPUTMILTER, OI_NONE },
2817 #define O_MILTER 0xbc
2818 { "Milter", O_MILTER, OI_SUBOPT },
2819 #define O_SASLOPTS 0xbd
2820 { "AuthOptions", O_SASLOPTS, OI_NONE },
2821 #define O_QUEUE_FILE_MODE 0xbe
2822 { "QueueFileMode", O_QUEUE_FILE_MODE, OI_NONE },
2823 #define O_DIG_ALG 0xbf
2824 { "CertFingerprintAlgorithm", O_DIG_ALG, OI_NONE },
2825 #define O_CIPHERLIST 0xc0
2826 { "CipherList", O_CIPHERLIST, OI_NONE },
2827 #define O_RANDFILE 0xc1
2828 { "RandFile", O_RANDFILE, OI_NONE },
2829 #define O_TLS_SRV_OPTS 0xc2
2830 { "TLSSrvOptions", O_TLS_SRV_OPTS, OI_NONE },
2831 #define O_RCPTTHROT 0xc3
2832 { "BadRcptThrottle", O_RCPTTHROT, OI_SAFE },
2833 #define O_DLVR_MIN 0xc4
2834 { "DeliverByMin", O_DLVR_MIN, OI_NONE },
2835 #define O_MAXQUEUECHILDREN 0xc5
2836 { "MaxQueueChildren", O_MAXQUEUECHILDREN, OI_NONE },
2837 #define O_MAXRUNNERSPERQUEUE 0xc6
2838 { "MaxRunnersPerQueue", O_MAXRUNNERSPERQUEUE, OI_NONE },
2839 #define O_DIRECTSUBMODIFIERS 0xc7
2840 { "DirectSubmissionModifiers", O_DIRECTSUBMODIFIERS, OI_NONE },
2841 #define O_NICEQUEUERUN 0xc8
2842 { "NiceQueueRun", O_NICEQUEUERUN, OI_NONE },
2843 #define O_SHMKEY 0xc9
2844 { "SharedMemoryKey", O_SHMKEY, OI_NONE },
2845 #define O_SASLBITS 0xca
2846 { "AuthMaxBits", O_SASLBITS, OI_NONE },
2848 { "MailboxDatabase", O_MBDB, OI_NONE },
2850 { "UseMSP", O_MSQ, OI_NONE },
2851 #define O_DELAY_LA 0xcd
2852 { "DelayLA", O_DELAY_LA, OI_NONE },
2853 #define O_FASTSPLIT 0xce
2854 { "FastSplit", O_FASTSPLIT, OI_NONE },
2855 #define O_SOFTBOUNCE 0xcf
2856 { "SoftBounce", O_SOFTBOUNCE, OI_NONE },
2857 #define O_SHMKEYFILE 0xd0
2858 { "SharedMemoryKeyFile", O_SHMKEYFILE, OI_NONE },
2859 #define O_REJECTLOGINTERVAL 0xd1
2860 { "RejectLogInterval", O_REJECTLOGINTERVAL, OI_NONE },
2861 #define O_REQUIRES_DIR_FSYNC 0xd2
2862 { "RequiresDirfsync", O_REQUIRES_DIR_FSYNC, OI_NONE },
2863 #define O_CONNECTION_RATE_WINDOW_SIZE 0xd3
2864 { "ConnectionRateWindowSize", O_CONNECTION_RATE_WINDOW_SIZE, OI_NONE },
2865 #define O_CRLFILE 0xd4
2866 { "CRLFile", O_CRLFILE, OI_NONE },
2867 #define O_FALLBACKSMARTHOST 0xd5
2868 { "FallbackSmartHost", O_FALLBACKSMARTHOST, OI_NONE },
2869 #define O_SASLREALM 0xd6
2870 { "AuthRealm", O_SASLREALM, OI_NONE },
2871 #define O_CRLPATH 0xd7
2872 { "CRLPath", O_CRLPATH, OI_NONE },
2873 #define O_HELONAME 0xd8
2874 { "HeloName", O_HELONAME, OI_NONE },
2876 # define O_REFUSELOWMEM 0xd9
2877 { "RefuseLowMem", O_REFUSELOWMEM, OI_NONE },
2878 # define O_QUEUELOWMEM 0xda
2879 { "QueueLowMem", O_QUEUELOWMEM, OI_NONE },
2880 # define O_MEMRESOURCE 0xdb
2881 { "MemoryResource", O_MEMRESOURCE, OI_NONE },
2882 #endif /* _FFR_MEMSTAT */
2883 #define O_MAXNOOPCOMMANDS 0xdc
2884 { "MaxNOOPCommands", O_MAXNOOPCOMMANDS, OI_NONE },
2886 # define O_MSG_ACCEPT 0xdd
2887 { "MessageAccept", O_MSG_ACCEPT, OI_NONE },
2889 #if _FFR_QUEUE_RUN_PARANOIA
2890 # define O_CHK_Q_RUNNERS 0xde
2891 { "CheckQueueRunners", O_CHK_Q_RUNNERS, OI_NONE },
2893 #if _FFR_EIGHT_BIT_ADDR_OK
2895 # ERROR FFR_EIGHT_BIT_ADDR_OK requires _ALLOW_255
2897 # define O_EIGHT_BIT_ADDR_OK 0xdf
2898 { "EightBitAddrOK", O_EIGHT_BIT_ADDR_OK, OI_NONE },
2899 #endif /* _FFR_EIGHT_BIT_ADDR_OK */
2900 #if _FFR_ADDR_TYPE_MODES
2901 # define O_ADDR_TYPE_MODES 0xe0
2902 { "AddrTypeModes", O_ADDR_TYPE_MODES, OI_NONE },
2904 #if _FFR_BADRCPT_SHUTDOWN
2905 # define O_RCPTSHUTD 0xe1
2906 { "BadRcptShutdown", O_RCPTSHUTD, OI_SAFE },
2907 # define O_RCPTSHUTDG 0xe2
2908 { "BadRcptShutdownGood", O_RCPTSHUTDG, OI_SAFE },
2909 #endif /* _FFR_BADRCPT_SHUTDOWN */
2910 #define O_SRV_SSL_OPTIONS 0xe3
2911 { "ServerSSLOptions", O_SRV_SSL_OPTIONS, OI_NONE },
2912 #define O_CLT_SSL_OPTIONS 0xe4
2913 { "ClientSSLOptions", O_CLT_SSL_OPTIONS, OI_NONE },
2914 #define O_MAX_QUEUE_AGE 0xe5
2915 { "MaxQueueAge", O_MAX_QUEUE_AGE, OI_NONE },
2916 #if _FFR_RCPTTHROTDELAY
2917 # define O_RCPTTHROTDELAY 0xe6
2918 { "BadRcptThrottleDelay", O_RCPTTHROTDELAY, OI_SAFE },
2920 #if 0 && _FFR_QOS && defined(SOL_IP) && defined(IP_TOS)
2921 # define O_INETQOS 0xe7 /* reserved for FFR_QOS */
2922 { "InetQoS", O_INETQOS, OI_NONE },
2924 #if STARTTLS && _FFR_FIPSMODE
2925 # define O_FIPSMODE 0xe8
2926 { "FIPSMode", O_FIPSMODE, OI_NONE },
2928 #if _FFR_REJECT_NUL_BYTE
2929 # define O_REJECTNUL 0xe9
2930 { "RejectNUL", O_REJECTNUL, OI_SAFE },
2932 #if _FFR_BOUNCE_QUEUE
2933 # define O_BOUNCEQUEUE 0xea
2934 { "BounceQueue", O_BOUNCEQUEUE, OI_NONE },
2937 # define O_ADDBCC 0xeb
2938 { "AddBcc", O_ADDBCC, OI_NONE },
2940 #define O_USECOMPRESSEDIPV6ADDRESSES 0xec
2941 { "UseCompressedIPv6Addresses", O_USECOMPRESSEDIPV6ADDRESSES, OI_NONE },
2943 # define O_SSLENGINE 0xed
2944 { "SSLEngine", O_SSLENGINE, OI_NONE },
2945 # define O_SSLENGINEPATH 0xee
2946 { "SSLEnginePath", O_SSLENGINEPATH, OI_NONE },
2947 # define O_TLSFB2CLEAR 0xef
2948 { "TLSFallbacktoClear", O_TLSFB2CLEAR, OI_NONE },
2951 # define O_NSPORTIP 0xf0
2952 { "NameServer", O_NSPORTIP, OI_NONE },
2955 # define O_DANE 0xf1
2956 { "DANE", O_DANE, OI_NONE },
2959 # define O_NSSRCHLIST 0xf2
2960 { "NameSearchList", O_NSSRCHLIST, OI_NONE },
2962 #if _FFR_BLANKENV_MACV
2963 # define O_HACKS 0xf4
2964 { "Hacks", O_HACKS, OI_NONE },
2967 # define O_KEEPBCC 0xf3
2968 { "KeepBcc", O_KEEPBCC, OI_NONE },
2972 #define O_CLTCACERTFILE 0xf5
2973 { "ClientCACertFile", O_CLTCACERTFILE, OI_NONE },
2974 #define O_CLTCACERTPATH 0xf6
2975 { "ClientCACertPath", O_CLTCACERTPATH, OI_NONE },
2977 #if _FFR_TLS_ALTNAMES
2978 # define O_CHECKALTNAMES 0xf7
2979 { "SetCertAltnames", O_CHECKALTNAMES, OI_NONE },
2982 { NULL, '\0', OI_NONE }
2985 # define CANONIFY(val)
2987 # define SET_OPT_DEFAULT(opt, val) opt = val
2989 /* set a string option by expanding the value and assigning it */
2990 /* WARNING this belongs ONLY into a case statement! */
2991 #define SET_STRING_EXP(str) \
2992 expand(val, exbuf, sizeof(exbuf), e); \
2993 newval = sm_pstrdup_x(exbuf); \
3000 #define OPTNAME o->o_name == NULL ? "<unknown>" : o->o_name
3003 setoption(opt, val, safe, sticky, e)
3008 register ENVELOPE *e;
3011 register struct optioninfo *o;
3014 bool can_setuid = RunAsUid == 0;
3017 extern bool Warn_Q_option;
3018 #if _FFR_ALLOW_SASLINFO
3019 extern unsigned int SubmitMode;
3021 #if STARTTLS || SM_CONF_SHM
3023 char exbuf[MAXLINE];
3026 unsigned long *pssloptions = NULL;
3032 /* full word options */
3033 struct optioninfo *sel;
3035 p = strchr(val, '=');
3037 p = &val[strlen(val)];
3044 syserr("readcf: null option name");
3051 subopt = strchr(val, '.');
3055 for (o = OptionTab; o->o_name != NULL; o++)
3057 if (sm_strncasecmp(o->o_name, val, strlen(val)) != 0)
3059 if (strlen(o->o_name) == strlen(val))
3061 /* completely specified -- this must be it */
3069 if (sel != NULL && o->o_name == NULL)
3071 else if (o->o_name == NULL)
3073 syserr("readcf: unknown option name %s", val);
3076 else if (sel != NULL)
3078 syserr("readcf: ambiguous option name %s (matches %s and %s)",
3079 val, sel->o_name, o->o_name);
3082 if (strlen(val) != strlen(o->o_name))
3084 int oldVerbose = Verbose;
3087 message("Option %s used as abbreviation for %s",
3089 Verbose = oldVerbose;
3096 for (o = OptionTab; o->o_name != NULL; o++)
3098 if (o->o_code == opt)
3101 if (o->o_name == NULL)
3103 syserr("readcf: unknown option name 0x%x", opt & 0xff);
3109 if (subopt != NULL && !bitset(OI_SUBOPT, o->o_flags))
3112 sm_dprintf("setoption: %s does not support suboptions, ignoring .%s\n",
3119 sm_dprintf(isascii(opt) && isprint(opt) ?
3120 "setoption %s (%c)%s%s=" :
3121 "setoption %s (0x%x)%s%s=",
3122 OPTNAME, opt, subopt == NULL ? "" : ".",
3123 subopt == NULL ? "" : subopt);
3124 xputs(sm_debug_file(), val);
3128 ** See if this option is preset for us.
3131 if (!sticky && bitnset(opt, StickyOpt))
3134 sm_dprintf(" (ignored)\n");
3139 ** Check to see if this option can be specified by this user.
3142 if (!safe && RealUid == 0)
3144 if (!safe && !bitset(OI_SAFE, o->o_flags))
3146 if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
3151 sm_dprintf(" (unsafe)");
3152 dp = drop_privileges(true);
3161 case '7': /* force seven-bit input */
3162 SevenBitInput = atobool(val);
3165 case '8': /* handling of 8-bit input */
3169 case 'p': /* pass 8 bit, convert MIME */
3170 MimeMode = MM_CVTMIME|MM_PASS8BIT;
3173 case 'm': /* convert 8-bit, convert MIME */
3174 MimeMode = MM_CVTMIME|MM_MIME8BIT;
3177 case 's': /* strict adherence */
3178 MimeMode = MM_CVTMIME;
3182 case 'r': /* reject 8-bit, don't convert MIME */
3186 case 'j': /* "just send 8" */
3187 MimeMode = MM_PASS8BIT;
3190 case 'a': /* encode 8 bit if available */
3191 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
3194 case 'c': /* convert 8 bit to MIME, never 7 bit */
3195 MimeMode = MM_MIME8BIT;
3200 syserr("Unknown 8-bit mode %c", *val);
3201 finis(false, true, EX_USAGE);
3203 #else /* MIME8TO7 */
3204 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3205 "Warning: Option: %s requires MIME8TO7 support\n",
3207 #endif /* MIME8TO7 */
3210 case 'A': /* set default alias file */
3215 SET_OPT_DEFAULT(al, "aliases");
3222 case 'a': /* look N minutes for "@:@" in alias file */
3224 SafeAlias = 5 MINUTES;
3226 SafeAlias = convtime(val, 'm');
3229 case 'B': /* substitution for blank character */
3231 if (SpaceSub == '\0')
3235 case 'b': /* min blocks free on queue fs/max msg size */
3236 p = strchr(val, '/');
3240 MaxMessageSize = atol(p);
3242 MinBlocksFree = atol(val);
3245 case 'c': /* don't connect to "expensive" mailers */
3246 NoConnect = atobool(val);
3249 case 'C': /* checkpoint every N addresses */
3250 if (safe || CheckpointInterval > atoi(val))
3251 CheckpointInterval = atoi(val);
3254 case 'd': /* delivery mode */
3258 set_delivery_mode(SM_DELIVER, e);
3261 case SM_QUEUE: /* queue only */
3262 case SM_DEFER: /* queue only and defer map lookups */
3263 case SM_DELIVER: /* do everything */
3264 case SM_FORK: /* fork after verification */
3266 /* deliver first TA in background, then queue */
3269 set_delivery_mode(*val, e);
3274 set_delivery_mode(*val, e);
3276 #endif /* _FFR_PROXY */
3279 syserr("Unknown delivery mode %c", *val);
3280 finis(false, true, EX_USAGE);
3284 case 'E': /* error message header/header file */
3286 ErrMsgFile = newstr(val);
3289 case 'e': /* set error processing mode */
3292 case EM_QUIET: /* be silent about it */
3293 case EM_MAIL: /* mail back */
3294 case EM_BERKNET: /* do berknet error processing */
3295 case EM_WRITE: /* write back (or mail) */
3296 case EM_PRINT: /* print errors normally (default) */
3297 e->e_errormode = *val;
3302 case 'F': /* file mode */
3303 FileMode = atooct(val) & 0777;
3306 case 'f': /* save Unix-style From lines on front */
3307 SaveFrom = atobool(val);
3310 case 'G': /* match recipients against GECOS field */
3311 MatchGecos = atobool(val);
3314 case 'g': /* default gid */
3316 if (isascii(*val) && isdigit(*val))
3320 register struct group *gr;
3325 syserr("readcf: option %c: unknown group %s",
3328 DefGid = gr->gr_gid;
3332 case 'H': /* help file */
3335 SET_OPT_DEFAULT(HelpFile, "helpfile");
3340 HelpFile = newstr(val);
3344 case 'h': /* maximum hop count */
3345 MaxHopCount = atoi(val);
3348 case 'I': /* use internet domain name server */
3350 for (p = val; *p != 0; )
3354 struct resolverflags *rfp;
3367 while (*p != '\0' && !(SM_ISSPACE(*p)))
3371 if (sm_strcasecmp(q, "HasWildcardMX") == 0)
3373 HasWildcardMX = !clearmode;
3376 if (sm_strcasecmp(q, "WorkAroundBrokenAAAA") == 0)
3378 WorkAroundBrokenAAAA = !clearmode;
3381 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
3383 if (sm_strcasecmp(q, rfp->rf_name) == 0)
3386 if (rfp->rf_name == NULL)
3387 syserr("readcf: I option value %s unrecognized", q);
3389 _res.options &= ~rfp->rf_bits;
3391 _res.options |= rfp->rf_bits;
3394 sm_dprintf("_res.options = %x, HasWildcardMX = %d\n",
3395 (unsigned int) _res.options, HasWildcardMX);
3396 #else /* NAMED_BIND */
3397 usrerr("name server (I option) specified but BIND not compiled in");
3398 #endif /* NAMED_BIND */
3401 case 'i': /* ignore dot lines in message */
3402 IgnrDot = atobool(val);
3405 case 'j': /* send errors in MIME (RFC 1341) format */
3406 SendMIMEErrors = atobool(val);
3409 case 'J': /* .forward search path */
3411 ForwardPath = newstr(val);
3414 case 'k': /* connection cache size */
3415 MaxMciCache = atoi(val);
3416 if (MaxMciCache < 0)
3420 case 'K': /* connection cache timeout */
3421 MciCacheTimeout = convtime(val, 'm');
3424 case 'l': /* use Errors-To: header */
3425 UseErrorsTo = atobool(val);
3428 case 'L': /* log level */
3429 if (safe || LogLevel < atoi(val))
3430 LogLevel = atoi(val);
3433 case 'M': /* define macro */
3435 i = macid_parse(val, &ep);
3440 cleanstrcpy(p, p, strlen(p) + 1);
3441 macdefine(&CurEnv->e_macro, A_TEMP, i, p);
3444 case 'm': /* send to me too */
3445 MeToo = atobool(val);
3448 case 'n': /* validate RHS in newaliases */
3449 CheckAliases = atobool(val);
3452 /* 'N' available -- was "net name" */
3454 case 'O': /* daemon options */
3455 if (!setdaemonoptions(val))
3456 syserr("too many daemons defined (%d max)", MAXDAEMONS);
3459 case 'o': /* assume old style headers */
3461 CurEnv->e_flags |= EF_OLDSTYLE;
3463 CurEnv->e_flags &= ~EF_OLDSTYLE;
3466 case 'p': /* select privacy level */
3470 register struct prival *pv;
3471 extern struct prival PrivacyValues[];
3473 while (isascii(*p) && (isspace(*p) || ispunct(*p)))
3478 while (isascii(*p) && isalnum(*p))
3483 for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
3485 if (sm_strcasecmp(val, pv->pv_name) == 0)
3488 if (pv->pv_name == NULL)
3489 syserr("readcf: Op line: %s unrecognized", val);
3491 PrivacyFlags |= pv->pv_flag;
3496 case 'P': /* postmaster copy address for returned mail */
3497 PostMasterCopy = newstr(val);
3500 case 'q': /* slope of queue only function */
3501 QueueFactor = atoi(val);
3504 case 'Q': /* queue directory */
3507 QueueDir = "mqueue";
3511 QueueDir = newstr(val);
3513 if (RealUid != 0 && !safe)
3514 Warn_Q_option = true;
3517 case 'R': /* don't prune routes */
3518 DontPruneRoutes = atobool(val);
3521 case 'r': /* read timeout */
3523 inittimeouts(val, sticky);
3525 settimeout(subopt, val, sticky);
3528 case 'S': /* status file */
3531 SET_OPT_DEFAULT(StatFile, "statistics");
3536 StatFile = newstr(val);
3540 case 's': /* be super safe, even if expensive */
3541 if (tolower(*val) == 'i')
3542 SuperSafe = SAFE_INTERACTIVE;
3543 else if (tolower(*val) == 'p')
3545 SuperSafe = SAFE_REALLY_POSTMILTER;
3547 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3548 "Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n");
3551 SuperSafe = atobool(val) ? SAFE_REALLY : SAFE_NO;
3554 case 'T': /* queue timeout */
3555 p = strchr(val, '/');
3559 settimeout("queuewarn", p, sticky);
3561 settimeout("queuereturn", val, sticky);
3564 case 't': /* time zone name */
3565 TimeZoneSpec = newstr(val);
3568 case 'U': /* location of user database */
3569 UdbSpec = newstr(val);
3572 case 'u': /* set default uid */
3573 for (p = val; *p != '\0'; p++)
3575 # if _FFR_DOTTED_USERNAMES
3576 if (*p == '/' || *p == ':')
3578 if (*p == '.' || *p == '/' || *p == ':')
3585 if (isascii(*val) && isdigit(*val))
3592 register struct passwd *pw;
3595 pw = sm_getpwnam(val);
3598 syserr("readcf: option u: unknown user %s", val);
3603 DefUid = pw->pw_uid;
3604 DefGid = pw->pw_gid;
3605 DefUser = newstr(pw->pw_name);
3610 if (DefUid > UID_MAX)
3612 syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored",
3613 (long)DefUid, (long)UID_MAX);
3616 # endif /* UID_MAX */
3618 /* handle the group if it is there */
3624 case 'V': /* fallback MX host */
3626 FallbackMX = newstr(val);
3629 case 'v': /* run in verbose mode */
3630 Verbose = atobool(val) ? 1 : 0;
3633 case 'w': /* if we are best MX, try host directly */
3634 TryNullMXList = atobool(val);
3637 /* 'W' available -- was wizard password */
3639 case 'x': /* load avg at which to auto-queue msgs */
3640 QueueLA = atoi(val);
3643 case 'X': /* load avg at which to auto-reject connections */
3644 RefuseLA = atoi(val);
3647 case O_DELAY_LA: /* load avg at which to delay connections */
3648 DelayLA = atoi(val);
3651 case 'y': /* work recipient factor */
3652 WkRecipFact = atoi(val);
3655 case 'Y': /* fork jobs during queue runs */
3656 ForkQueueRuns = atobool(val);
3659 case 'z': /* work message class factor */
3660 WkClassFact = atoi(val);
3663 case 'Z': /* work time factor */
3664 WkTimeFact = atoi(val);
3668 #if _FFR_QUEUE_GROUP_SORTORDER
3669 /* coordinate this with makequeue() */
3671 case O_QUEUESORTORD: /* queue sorting order */
3674 case 'f': /* File Name */
3676 QueueSortOrder = QSO_BYFILENAME;
3679 case 'h': /* Host first */
3681 QueueSortOrder = QSO_BYHOST;
3684 case 'm': /* Modification time */
3686 QueueSortOrder = QSO_BYMODTIME;
3689 case 'p': /* Priority order */
3691 QueueSortOrder = QSO_BYPRIORITY;
3694 case 't': /* Submission time */
3696 QueueSortOrder = QSO_BYTIME;
3699 case 'r': /* Random */
3701 QueueSortOrder = QSO_RANDOM;
3705 case 's': /* Shuffled host name */
3707 QueueSortOrder = QSO_BYSHUFFLE;
3709 #endif /* _FFR_RHS */
3711 case 'n': /* none */
3713 QueueSortOrder = QSO_NONE;
3717 syserr("Invalid queue sort order \"%s\"", val);
3721 case O_HOSTSFILE: /* pathname of /etc/hosts file */
3723 HostsFile = newstr(val);
3726 case O_MQA: /* minimum queue age between deliveries */
3727 MinQueueAge = convtime(val, 'm');
3730 case O_MAX_QUEUE_AGE:
3731 MaxQueueAge = convtime(val, 'm');
3734 case O_DEFCHARSET: /* default character set for mimefying */
3735 DefaultCharSet = newstr(denlstring(val, true, true));
3738 case O_SSFILE: /* service switch file */
3740 ServiceSwitchFile = newstr(val);
3743 case O_DIALDELAY: /* delay for dial-on-demand operation */
3744 DialDelay = convtime(val, 's');
3747 case O_NORCPTACTION: /* what to do if no recipient */
3748 if (sm_strcasecmp(val, "none") == 0)
3749 NoRecipientAction = NRA_NO_ACTION;
3750 else if (sm_strcasecmp(val, "add-to") == 0)
3751 NoRecipientAction = NRA_ADD_TO;
3752 else if (sm_strcasecmp(val, "add-apparently-to") == 0)
3753 NoRecipientAction = NRA_ADD_APPARENTLY_TO;
3754 else if (sm_strcasecmp(val, "add-bcc") == 0)
3755 NoRecipientAction = NRA_ADD_BCC;
3756 else if (sm_strcasecmp(val, "add-to-undisclosed") == 0)
3757 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED;
3759 syserr("Invalid NoRecipientAction: %s", val);
3762 case O_SAFEFILEENV: /* chroot() environ for writing to files */
3766 /* strip trailing slashes */
3767 p = val + strlen(val) - 1;
3768 while (p >= val && *p == '/')
3774 SafeFileEnv = newstr(val);
3777 case O_MAXMSGSIZE: /* maximum message size */
3778 MaxMessageSize = atol(val);
3781 case O_COLONOKINADDR: /* old style handling of colon addresses */
3782 ColonOkInAddr = atobool(val);
3785 case O_MAXQUEUERUN: /* max # of jobs in a single queue run */
3786 MaxQueueRun = atoi(val);
3789 case O_MAXCHILDREN: /* max # of children of daemon */
3790 MaxChildren = atoi(val);
3793 case O_MAXQUEUECHILDREN: /* max # of children of daemon */
3794 MaxQueueChildren = atoi(val);
3797 case O_MAXRUNNERSPERQUEUE: /* max # runners in a queue group */
3798 MaxRunnersPerQueue = atoi(val);
3801 case O_NICEQUEUERUN: /* nice queue runs */
3803 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3804 "Warning: NiceQueueRun set on system that doesn't support nice()\n");
3807 /* XXX do we want to check the range? > 0 ? */
3808 NiceQueueRun = atoi(val);
3811 case O_SHMKEY: /* shared memory key */
3814 #else /* SM_CONF_SHM */
3815 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3816 "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n",
3818 #endif /* SM_CONF_SHM */
3821 case O_SHMKEYFILE: /* shared memory key file */
3823 SET_STRING_EXP(ShmKeyFile);
3824 #else /* SM_CONF_SHM */
3825 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3826 "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n",
3829 #endif /* SM_CONF_SHM */
3831 #if _FFR_MAX_FORWARD_ENTRIES
3832 case O_MAXFORWARD: /* max # of forward entries */
3833 MaxForwardEntries = atoi(val);
3837 case O_KEEPCNAMES: /* don't expand CNAME records */
3838 DontExpandCnames = atobool(val);
3841 case O_MUSTQUOTE: /* must quote these characters in phrases */
3842 (void) sm_strlcpy(buf, "@,;:\\()[]", sizeof(buf));
3843 if (strlen(val) < sizeof(buf) - 10)
3844 (void) sm_strlcat(buf, val, sizeof(buf));
3846 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3847 "Warning: MustQuoteChars too long, ignored.\n");
3848 MustQuoteChars = newstr(buf);
3851 case O_SMTPGREETING: /* SMTP greeting message (old $e macro) */
3852 SmtpGreeting = newstr(munchstring(val, NULL, '\0'));
3855 case O_UNIXFROM: /* UNIX From_ line (old $l macro) */
3856 UnixFromLine = newstr(munchstring(val, NULL, '\0'));
3859 case O_OPCHARS: /* operator characters (old $o macro) */
3860 if (OperatorChars != NULL)
3861 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3862 "Warning: OperatorChars is being redefined.\n It should only be set before ruleset definitions.\n");
3863 OperatorChars = newstr(munchstring(val, NULL, '\0'));
3866 case O_DONTINITGRPS: /* don't call initgroups(3) */
3867 DontInitGroups = atobool(val);
3870 case O_SLFH: /* make sure from fits on one line */
3871 SingleLineFromHeader = atobool(val);
3874 case O_ABH: /* allow HELO commands with syntax errors */
3875 AllowBogusHELO = atobool(val);
3878 case O_CONNTHROT: /* connection rate throttle */
3879 ConnRateThrottle = atoi(val);
3882 case O_UGW: /* group writable files are unsafe */
3885 setbitn(DBS_GROUPWRITABLEFORWARDFILESAFE,
3887 setbitn(DBS_GROUPWRITABLEINCLUDEFILESAFE,
3892 case O_DBLBOUNCE: /* address to which to send double bounces */
3893 DoubleBounceAddr = newstr(val);
3896 case O_HSDIR: /* persistent host status directory */
3900 HostStatDir = newstr(val);
3904 case O_SINGTHREAD: /* single thread deliveries (requires hsdir) */
3905 SingleThreadDelivery = atobool(val);
3908 case O_RUNASUSER: /* run bulk of code as this user */
3909 for (p = val; *p != '\0'; p++)
3911 # if _FFR_DOTTED_USERNAMES
3912 if (*p == '/' || *p == ':')
3914 if (*p == '.' || *p == '/' || *p == ':')
3921 if (isascii(*val) && isdigit(*val))
3924 RunAsUid = atoi(val);
3928 register struct passwd *pw;
3930 pw = sm_getpwnam(val);
3933 syserr("readcf: option RunAsUser: unknown user %s", val);
3936 else if (can_setuid)
3939 RunAsUserName = newstr(val);
3940 RunAsUid = pw->pw_uid;
3941 RunAsGid = pw->pw_gid;
3943 else if (EffGid == pw->pw_gid)
3944 RunAsGid = pw->pw_gid;
3945 else if (UseMSP && *p == '\0')
3946 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3947 "WARNING: RunAsUser for MSP ignored, check group ids (egid=%ld, want=%ld)\n",
3952 if (RunAsUid > UID_MAX)
3954 syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored",
3955 (long) RunAsUid, (long) UID_MAX);
3958 # endif /* UID_MAX */
3961 if (isascii(*p) && isdigit(*p))
3965 runasgid = (gid_t) atoi(p);
3966 if (can_setuid || EffGid == runasgid)
3967 RunAsGid = runasgid;
3969 (void) sm_io_fprintf(smioout,
3971 "WARNING: RunAsUser for MSP ignored, check group ids (egid=%ld, want=%ld)\n",
3977 register struct group *gr;
3981 syserr("readcf: option RunAsUser: unknown group %s",
3983 else if (can_setuid || EffGid == gr->gr_gid)
3984 RunAsGid = gr->gr_gid;
3986 (void) sm_io_fprintf(smioout,
3988 "WARNING: RunAsUser for MSP ignored, check group ids (egid=%ld, want=%ld)\n",
3994 sm_dprintf("readcf: RunAsUser = %d:%d\n",
3995 (int) RunAsUid, (int) RunAsGid);
3999 RrtImpliesDsn = atobool(val);
4003 PSTRSET(PidFile, val);
4006 case O_DONTBLAMESENDMAIL:
4010 register struct dbsval *dbs;
4011 extern struct dbsval DontBlameSendmailValues[];
4013 while (isascii(*p) && (isspace(*p) || ispunct(*p)))
4018 while (isascii(*p) && isalnum(*p))
4023 for (dbs = DontBlameSendmailValues;
4024 dbs->dbs_name != NULL; dbs++)
4026 if (sm_strcasecmp(val, dbs->dbs_name) == 0)
4029 if (dbs->dbs_name == NULL)
4030 syserr("readcf: DontBlameSendmail option: %s unrecognized", val);
4031 else if (dbs->dbs_flag == DBS_SAFE)
4032 clrbitmap(DontBlameSendmail);
4034 setbitn(dbs->dbs_flag, DontBlameSendmail);
4040 if (sm_strcasecmp(val, "loopback") == 0)
4041 DontProbeInterfaces = DPI_SKIPLOOPBACK;
4042 else if (atobool(val))
4043 DontProbeInterfaces = DPI_PROBENONE;
4045 DontProbeInterfaces = DPI_PROBEALL;
4049 MaxRcptPerMsg = atoi(val);
4053 BadRcptThrottle = atoi(val);
4056 #if _FFR_RCPTTHROTDELAY
4057 case O_RCPTTHROTDELAY:
4058 BadRcptThrottleDelay = atoi(val);
4064 PSTRSET(DeadLetterDrop, val);
4067 #if _FFR_DONTLOCKFILESFORREAD_OPTION
4069 DontLockReadFiles = atobool(val);
4073 case O_MAXALIASRCSN:
4074 MaxAliasRecursion = atoi(val);
4078 /* XXX should probably use gethostbyname */
4079 #if NETINET || NETINET6
4081 if ((subopt = strchr(val, '@')) != NULL)
4084 i = (int) strtoul(val, NULL, 0);
4086 /* stricter checks? probably not useful. */
4089 syserr("readcf: option ConnectOnlyTo: invalid port %s",
4095 ConnectOnlyTo.sa.sa_family = AF_UNSPEC;
4097 if (anynet_pton(AF_INET6, val,
4098 &ConnectOnlyTo.sin6.sin6_addr) == 1)
4100 ConnectOnlyTo.sa.sa_family = AF_INET6;
4102 ConnectOnlyTo.sin6.sin6_port = htons(i);
4105 # endif /* NETINET6 */
4108 ConnectOnlyTo.sin.sin_addr.s_addr = inet_addr(val);
4109 if (ConnectOnlyTo.sin.sin_addr.s_addr != INADDR_NONE)
4110 ConnectOnlyTo.sa.sa_family = AF_INET;
4112 ConnectOnlyTo.sin.sin_port = htons(i);
4115 # endif /* NETINET */
4116 if (ConnectOnlyTo.sa.sa_family == AF_UNSPEC)
4118 syserr("readcf: option ConnectOnlyTo: invalid IP address %s",
4122 #endif /* NETINET || NETINET6 */
4126 # if !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING)
4128 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4129 "readcf: option TrustedUser may cause problems on systems\n which do not support fchown() if UseMSP is not set.\n");
4130 # endif /* !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING) */
4131 if (isascii(*val) && isdigit(*val))
4132 TrustedUid = atoi(val);
4135 register struct passwd *pw;
4138 pw = sm_getpwnam(val);
4141 syserr("readcf: option TrustedUser: unknown user %s", val);
4145 TrustedUid = pw->pw_uid;
4149 if (TrustedUid > UID_MAX)
4151 syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)",
4152 (long) TrustedUid, (long) UID_MAX);
4155 # endif /* UID_MAX */
4158 case O_MAXMIMEHDRLEN:
4159 p = strchr(val, '/');
4162 MaxMimeHeaderLength = atoi(val);
4163 if (p != NULL && *p != '\0')
4164 MaxMimeFieldLength = atoi(p);
4166 MaxMimeFieldLength = MaxMimeHeaderLength / 2;
4168 if (MaxMimeHeaderLength <= 0)
4169 MaxMimeHeaderLength = 0;
4170 else if (MaxMimeHeaderLength < 128)
4171 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4172 "Warning: MaxMimeHeaderLength: header length limit set lower than 128\n");
4174 if (MaxMimeFieldLength <= 0)
4175 MaxMimeFieldLength = 0;
4176 else if (MaxMimeFieldLength < 40)
4177 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4178 "Warning: MaxMimeHeaderLength: field length limit set lower than 40\n");
4181 ** Headers field values now include leading space, so let's
4182 ** adjust the values to be "backward compatible".
4185 if (MaxMimeHeaderLength > 0)
4186 MaxMimeHeaderLength++;
4187 if (MaxMimeFieldLength > 0)
4188 MaxMimeFieldLength++;
4191 case O_CONTROLSOCKET:
4192 PSTRSET(ControlSocketName, val);
4196 MaxHeadersLength = atoi(val);
4198 if (MaxHeadersLength > 0 &&
4199 MaxHeadersLength < (MAXHDRSLEN / 2))
4200 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4201 "Warning: MaxHeadersLength: headers length limit set lower than %d\n",
4205 case O_PROCTITLEPREFIX:
4206 PSTRSET(ProcTitlePrefix, val);
4211 # if _FFR_ALLOW_SASLINFO
4213 ** Allow users to select their own authinfo file
4214 ** under certain circumstances, otherwise just ignore
4215 ** the option. If the option isn't ignored, several
4216 ** commands don't work very well, e.g., mailq.
4217 ** However, this is not a "perfect" solution.
4218 ** If mail is queued, the authentication info
4219 ** will not be used in subsequent delivery attempts.
4220 ** If we really want to support this, then it has
4221 ** to be stored in the queue file.
4223 if (!bitset(SUBMIT_MSA, SubmitMode) && RealUid != 0 &&
4224 RunAsUid != RealUid)
4226 # endif /* _FFR_ALLOW_SASLINFO */
4227 PSTRSET(SASLInfo, val);
4231 if (AuthMechanisms != NULL)
4232 sm_free(AuthMechanisms); /* XXX */
4234 AuthMechanisms = newstr(val);
4236 AuthMechanisms = NULL;
4240 if (AuthRealm != NULL)
4243 AuthRealm = newstr(val);
4249 while (val != NULL && *val != '\0')
4254 SASLOpts |= SASL_AUTH_AUTH;
4258 SASLOpts |= SASL_SEC_NOACTIVE;
4262 SASLOpts |= SASL_SEC_PASS_CREDENTIALS;
4266 SASLOpts |= SASL_SEC_NODICTIONARY;
4270 SASLOpts |= SASL_SEC_FORWARD_SECRECY;
4275 SASLOpts |= SASL_SEC_MUTUAL_AUTH;
4277 # endif /* SASL >= 20101 */
4280 SASLOpts |= SASL_SEC_NOPLAINTEXT;
4284 SASLOpts |= SASL_SEC_NOANONYMOUS;
4287 case ' ': /* ignore */
4288 case '\t': /* ignore */
4289 case ',': /* ignore */
4293 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4294 "Warning: Option: %s unknown parameter '%c'\n",
4302 val = strpbrk(val, ", \t");
4309 MaxSLBits = atoi(val);
4318 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4319 "Warning: Option: %s requires SASL support (-DSASL)\n",
4326 TLSFallbacktoClear = atobool(val);
4329 SET_STRING_EXP(SrvCertFile);
4331 SET_STRING_EXP(SrvKeyFile);
4333 SET_STRING_EXP(CltCertFile);
4335 SET_STRING_EXP(CltKeyFile);
4337 SET_STRING_EXP(CACertFile);
4339 SET_STRING_EXP(CACertPath);
4341 case O_CLTCACERTFILE:
4342 SET_STRING_EXP(CltCACertFile);
4343 case O_CLTCACERTPATH:
4344 SET_STRING_EXP(CltCACertPath);
4347 SET_STRING_EXP(DHParams);
4349 SET_STRING_EXP(CipherList);
4351 SET_STRING_EXP(CertFingerprintAlgorithm);
4352 case O_SSLENGINEPATH:
4353 SET_STRING_EXP(SSLEnginePath);
4355 newval = sm_pstrdup_x(val);
4356 if (SSLEngine != NULL)
4361 ** Which engines need to be initialized before fork()?
4362 ** XXX hack, should be an option?
4365 if (strcmp(SSLEngine, "chil") == 0)
4366 SSLEngineprefork = true;
4368 case O_SRV_SSL_OPTIONS:
4369 pssloptions = &Srv_SSL_Options;
4370 case O_CLT_SSL_OPTIONS:
4371 if (pssloptions == NULL)
4372 pssloptions = &Clt_SSL_Options;
4373 (void) readssloptions(o->o_name, val, pssloptions, '\0');
4375 sm_dprintf("ssloptions=%#lx\n", *pssloptions);
4381 SET_STRING_EXP(CRLFile);
4385 SET_STRING_EXP(CRLPath);
4389 ** XXX How about options per daemon/client instead of globally?
4390 ** This doesn't work well for some options, e.g., no server cert,
4391 ** but fine for others.
4393 ** XXX Some people may want different certs per server.
4395 ** See also srvfeatures()
4398 case O_TLS_SRV_OPTS:
4399 while (val != NULL && *val != '\0')
4404 TLS_Srv_Opts |= TLS_I_NO_VRFY;
4407 ** Server without a cert? That works only if
4408 ** AnonDH is enabled as cipher, which is not in the
4409 ** default list. Hence the CipherList option must
4410 ** be available. Moreover: which clients support this
4411 ** besides sendmail with this setting?
4415 TLS_Srv_Opts &= ~TLS_I_SRV_CERT;
4417 case ' ': /* ignore */
4418 case '\t': /* ignore */
4419 case ',': /* ignore */
4422 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4423 "Warning: Option: %s unknown parameter '%c'\n",
4431 val = strpbrk(val, ", \t");
4438 PSTRSET(RandFile, val);
4441 #else /* STARTTLS */
4449 case O_CLTCACERTFILE:
4450 case O_CLTCACERTPATH:
4453 case O_SRV_SSL_OPTIONS:
4454 case O_CLT_SSL_OPTIONS:
4460 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4461 "Warning: Option: %s requires TLS support\n",
4465 #endif /* STARTTLS */
4466 #if STARTTLS && _FFR_FIPSMODE
4468 FipsMode = atobool(val);
4473 setclientoptions(val);
4477 DataFileBufferSize = atoi(val);
4481 XscriptFileBufferSize = atoi(val);
4484 case O_LDAPDEFAULTSPEC:
4486 ldapmap_set_defaults(val);
4488 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4489 "Warning: Option: %s requires LDAP support (-DLDAPMAP)\n",
4491 #endif /* LDAPMAP */
4496 InputFilterList = newstr(val);
4498 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4499 "Warning: Option: %s requires Milter support (-DMILTER)\n",
4506 milter_set_option(subopt, val, sticky);
4508 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4509 "Warning: Option: %s requires Milter support (-DMILTER)\n",
4514 case O_QUEUE_FILE_MODE: /* queue file mode */
4515 QueueFileMode = atooct(val) & 0777;
4518 case O_DLVR_MIN: /* deliver by minimum time */
4519 DeliverByMin = convtime(val, 's');
4522 /* modifiers {daemon_flags} for direct submissions */
4523 case O_DIRECTSUBMODIFIERS:
4525 BITMAP256 m; /* ignored */
4526 extern ENVELOPE BlankEnvelope;
4528 macdefine(&BlankEnvelope.e_macro, A_PERM,
4529 macid("{daemon_flags}"),
4530 getmodifiers(val, m));
4535 FastSplit = atoi(val);
4543 UseMSP = atobool(val);
4547 SoftBounce = atobool(val);
4550 case O_REJECTLOGINTERVAL: /* time btwn log msgs while refusing */
4551 RejectLogInterval = convtime(val, 'h');
4554 case O_REQUIRES_DIR_FSYNC:
4555 #if REQUIRES_DIR_FSYNC
4556 RequiresDirfsync = atobool(val);
4558 /* silently ignored... required for cf file option */
4562 case O_CONNECTION_RATE_WINDOW_SIZE:
4563 ConnectionRateWindowSize = convtime(val, 's');
4566 case O_FALLBACKSMARTHOST: /* fallback smart host */
4568 FallbackSmartHost = newstr(val);
4572 HeloName = newstr(val);
4576 case O_REFUSELOWMEM:
4577 RefuseLowMem = atoi(val);
4580 QueueLowMem = atoi(val);
4583 MemoryResource = newstr(val);
4585 #endif /* _FFR_MEMSTAT */
4587 case O_MAXNOOPCOMMANDS:
4588 MaxNOOPCommands = atoi(val);
4593 MessageAccept = newstr(val);
4597 #if _FFR_QUEUE_RUN_PARANOIA
4598 case O_CHK_Q_RUNNERS:
4599 CheckQueueRunners = atoi(val);
4603 #if _FFR_EIGHT_BIT_ADDR_OK
4604 case O_EIGHT_BIT_ADDR_OK:
4605 EightBitAddrOK = atobool(val);
4609 #if _FFR_ADDR_TYPE_MODES
4610 case O_ADDR_TYPE_MODES:
4611 AddrTypeModes = atobool(val);
4615 #if _FFR_BADRCPT_SHUTDOWN
4617 BadRcptShutdown = atoi(val);
4621 BadRcptShutdownGood = atoi(val);
4623 #endif /* _FFR_BADRCPT_SHUTDOWN */
4625 #if _FFR_REJECT_NUL_BYTE
4627 RejectNUL = atobool(val);
4631 #if _FFR_BOUNCE_QUEUE
4633 bouncequeue = newstr(val);
4639 AddBcc = atobool(val);
4642 case O_USECOMPRESSEDIPV6ADDRESSES:
4643 UseCompressedIPv6Addresses = atobool(val);
4651 NameSearchList = sm_strdup(val);
4657 if (sm_strcasecmp(val, "always") == 0)
4660 Dane = atobool(val) ? DANE_SECURE : DANE_NEVER;
4664 #if _FFR_BLANKENV_MACV
4666 Hacks = (int) strtol(val, NULL, 0);
4672 KeepBcc = atobool(val);
4676 # if _FFR_TLS_ALTNAMES
4677 case O_CHECKALTNAMES:
4678 SetCertAltnames = atobool(val);
4685 if (isascii(opt) && isprint(opt))
4686 sm_dprintf("Warning: option %c unknown\n", opt);
4688 sm_dprintf("Warning: option 0x%x unknown\n", opt);
4694 ** Options with suboptions are responsible for taking care
4695 ** of sticky-ness (e.g., that a command line setting is kept
4696 ** when reading in the sendmail.cf file). This has to be done
4697 ** when the suboptions are parsed since each suboption must be
4698 ** sticky, not the root option.
4701 if (sticky && !bitset(OI_SUBOPT, o->o_flags))
4702 setbitn(opt, StickyOpt);
4705 ** SETCLASS -- set a string into a class
4708 ** class -- the class to put the string in.
4709 ** str -- the string to enter
4715 ** puts the word into the symbol table.
4719 setclass(class, str)
4725 if ((str[0] & 0377) == MATCHCLASS)
4735 sm_dprintf("setclass(%s, $=%s)\n",
4736 macname(class), macname(mid));
4737 copy_class(mid, class);
4742 sm_dprintf("setclass(%s, %s)\n", macname(class), str);
4744 s = stab(str, ST_CLASS, ST_ENTER);
4745 setbitn(bitidx(class), s->s_class);
4749 ** MAKEMAPENTRY -- create a map entry
4752 ** line -- the config file line
4755 ** A pointer to the map that has been created.
4756 ** NULL if there was a syntax error.
4759 ** Enters the map into the dictionary.
4772 for (p = line; SM_ISSPACE(*p); p++)
4774 if (!(isascii(*p) && isalnum(*p)))
4776 syserr("readcf: config K line: no map name");
4781 while ((isascii(*++p) && isalnum(*p)) || *p == '_' || *p == '.')
4785 while (SM_ISSPACE(*p))
4787 if (!(isascii(*p) && isalnum(*p)))
4789 syserr("readcf: config K line, map %s: no map class", mapname);
4793 while (isascii(*++p) && isalnum(*p))
4797 while (SM_ISSPACE(*p))
4800 /* look up the class */
4801 class = stab(classname, ST_MAPCLASS, ST_FIND);
4804 syserr("readcf: map %s: class %s not available", mapname,
4810 s = stab(mapname, ST_MAP, ST_ENTER);
4811 s->s_map.map_class = &class->s_mapclass;
4812 s->s_map.map_mname = newstr(mapname);
4814 if (class->s_mapclass.map_parse(&s->s_map, p))
4815 s->s_map.map_mflags |= MF_VALID;
4819 sm_dprintf("map %s, class %s, flags %lx, file %s,\n",
4820 s->s_map.map_mname, s->s_map.map_class->map_cname,
4821 s->s_map.map_mflags, s->s_map.map_file);
4822 sm_dprintf("\tapp %s, domain %s, rebuild %s\n",
4823 s->s_map.map_app, s->s_map.map_domain,
4824 s->s_map.map_rebuild);
4829 ** STRTORWSET -- convert string to rewriting set number
4832 ** p -- the pointer to the string to decode.
4833 ** endp -- if set, store the trailing delimiter here.
4834 ** stabmode -- ST_ENTER to create this entry, ST_FIND if
4835 ** it must already exist.
4838 ** The appropriate ruleset number.
4839 ** -1 if it is not valid (error already printed)
4843 strtorwset(p, endp, stabmode)
4849 static int nextruleset = MAXRWSETS;
4851 while (SM_ISSPACE(*p))
4855 syserr("invalid ruleset name: \"%.20s\"", p);
4860 ruleset = strtol(p, endp, 10);
4861 if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
4863 syserr("bad ruleset %d (%d max)",
4864 ruleset, MAXRWSETS / 2);
4875 while (*p != '\0' && isascii(*p) && (isalnum(*p) || *p == '_'))
4877 if (q == p || !(isascii(*q) && isalpha(*q)))
4879 /* no valid characters */
4880 syserr("invalid ruleset name: \"%.20s\"", q);
4883 while (SM_ISSPACE(*p))
4888 s = stab(q, ST_RULESET, stabmode);
4895 if (stabmode == ST_ENTER && delim == '=')
4897 while (isascii(*++p) && isspace(*p))
4899 if (!(isascii(*p) && isdigit(*p)))
4901 syserr("bad ruleset definition \"%s\" (number required after `=')", q);
4906 ruleset = strtol(p, endp, 10);
4907 if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
4909 syserr("bad ruleset number %d in \"%s\" (%d max)",
4910 ruleset, q, MAXRWSETS / 2);
4919 if (s->s_ruleset >= 0)
4920 ruleset = s->s_ruleset;
4921 else if ((ruleset = --nextruleset) < MAXRWSETS / 2)
4923 syserr("%s: too many named rulesets (%d max)",
4928 if (s->s_ruleset >= 0 &&
4930 ruleset != s->s_ruleset)
4932 syserr("%s: ruleset changed value (old %d, new %d)",
4933 q, s->s_ruleset, ruleset);
4934 ruleset = s->s_ruleset;
4936 else if (ruleset >= 0)
4938 s->s_ruleset = ruleset;
4940 if (stabmode == ST_ENTER && ruleset >= 0)
4944 if (RuleSetNames[ruleset] != NULL)
4945 sm_free(RuleSetNames[ruleset]); /* XXX */
4946 if (delim != '\0' && (h = strchr(q, delim)) != NULL)
4948 RuleSetNames[ruleset] = newstr(q);
4949 if (delim == '/' && h != NULL)
4950 *h = delim; /* put back delim */
4956 ** SETTIMEOUT -- set an individual timeout
4959 ** name -- the name of the timeout.
4960 ** val -- the value of the timeout.
4961 ** sticky -- if set, don't let other setoptions override
4968 /* set if Timeout sub-option is stuck */
4969 static BITMAP256 StickyTimeoutOpt;
4971 static struct timeoutinfo
4973 char *to_name; /* long name of timeout */
4974 unsigned char to_code; /* code for option */
4977 #define TO_INITIAL 0x01
4978 { "initial", TO_INITIAL },
4979 #define TO_MAIL 0x02
4980 { "mail", TO_MAIL },
4981 #define TO_RCPT 0x03
4982 { "rcpt", TO_RCPT },
4983 #define TO_DATAINIT 0x04
4984 { "datainit", TO_DATAINIT },
4985 #define TO_DATABLOCK 0x05
4986 { "datablock", TO_DATABLOCK },
4987 #define TO_DATAFINAL 0x06
4988 { "datafinal", TO_DATAFINAL },
4989 #define TO_COMMAND 0x07
4990 { "command", TO_COMMAND },
4991 #define TO_RSET 0x08
4992 { "rset", TO_RSET },
4993 #define TO_HELO 0x09
4994 { "helo", TO_HELO },
4995 #define TO_QUIT 0x0A
4996 { "quit", TO_QUIT },
4997 #define TO_MISC 0x0B
4998 { "misc", TO_MISC },
4999 #define TO_IDENT 0x0C
5000 { "ident", TO_IDENT },
5001 #define TO_FILEOPEN 0x0D
5002 { "fileopen", TO_FILEOPEN },
5003 #define TO_CONNECT 0x0E
5004 { "connect", TO_CONNECT },
5005 #define TO_ICONNECT 0x0F
5006 { "iconnect", TO_ICONNECT },
5007 #define TO_QUEUEWARN 0x10
5008 { "queuewarn", TO_QUEUEWARN },
5009 { "queuewarn.*", TO_QUEUEWARN },
5010 #define TO_QUEUEWARN_NORMAL 0x11
5011 { "queuewarn.normal", TO_QUEUEWARN_NORMAL },
5012 #define TO_QUEUEWARN_URGENT 0x12
5013 { "queuewarn.urgent", TO_QUEUEWARN_URGENT },
5014 #define TO_QUEUEWARN_NON_URGENT 0x13
5015 { "queuewarn.non-urgent", TO_QUEUEWARN_NON_URGENT },
5016 #define TO_QUEUERETURN 0x14
5017 { "queuereturn", TO_QUEUERETURN },
5018 { "queuereturn.*", TO_QUEUERETURN },
5019 #define TO_QUEUERETURN_NORMAL 0x15
5020 { "queuereturn.normal", TO_QUEUERETURN_NORMAL },
5021 #define TO_QUEUERETURN_URGENT 0x16
5022 { "queuereturn.urgent", TO_QUEUERETURN_URGENT },
5023 #define TO_QUEUERETURN_NON_URGENT 0x17
5024 { "queuereturn.non-urgent", TO_QUEUERETURN_NON_URGENT },
5025 #define TO_HOSTSTATUS 0x18
5026 { "hoststatus", TO_HOSTSTATUS },
5027 #define TO_RESOLVER_RETRANS 0x19
5028 { "resolver.retrans", TO_RESOLVER_RETRANS },
5029 #define TO_RESOLVER_RETRANS_NORMAL 0x1A
5030 { "resolver.retrans.normal", TO_RESOLVER_RETRANS_NORMAL },
5031 #define TO_RESOLVER_RETRANS_FIRST 0x1B
5032 { "resolver.retrans.first", TO_RESOLVER_RETRANS_FIRST },
5033 #define TO_RESOLVER_RETRY 0x1C
5034 { "resolver.retry", TO_RESOLVER_RETRY },
5035 #define TO_RESOLVER_RETRY_NORMAL 0x1D
5036 { "resolver.retry.normal", TO_RESOLVER_RETRY_NORMAL },
5037 #define TO_RESOLVER_RETRY_FIRST 0x1E
5038 { "resolver.retry.first", TO_RESOLVER_RETRY_FIRST },
5039 #define TO_CONTROL 0x1F
5040 { "control", TO_CONTROL },
5041 #define TO_LHLO 0x20
5042 { "lhlo", TO_LHLO },
5043 #define TO_AUTH 0x21
5044 { "auth", TO_AUTH },
5045 #define TO_STARTTLS 0x22
5046 { "starttls", TO_STARTTLS },
5047 #define TO_ACONNECT 0x23
5048 { "aconnect", TO_ACONNECT },
5049 #define TO_QUEUEWARN_DSN 0x24
5050 { "queuewarn.dsn", TO_QUEUEWARN_DSN },
5051 #define TO_QUEUERETURN_DSN 0x25
5052 { "queuereturn.dsn", TO_QUEUERETURN_DSN },
5058 settimeout(name, val, sticky)
5063 register struct timeoutinfo *to;
5068 sm_dprintf("settimeout(%s = %s)", name, val);
5070 for (to = TimeOutTab; to->to_name != NULL; to++)
5072 if (sm_strcasecmp(to->to_name, name) == 0)
5076 if (to->to_name == NULL)
5078 errno = 0; /* avoid bogus error text */
5079 syserr("settimeout: invalid timeout %s", name);
5084 ** See if this option is preset for us.
5087 if (!sticky && bitnset(to->to_code, StickyTimeoutOpt))
5090 sm_dprintf(" (ignored)\n");
5097 toval = convtime(val, 'm');
5100 switch (to->to_code)
5103 TimeOuts.to_initial = toval;
5107 TimeOuts.to_mail = toval;
5111 TimeOuts.to_rcpt = toval;
5115 TimeOuts.to_datainit = toval;
5119 TimeOuts.to_datablock = toval;
5123 TimeOuts.to_datafinal = toval;
5127 TimeOuts.to_nextcommand = toval;
5131 TimeOuts.to_rset = toval;
5135 TimeOuts.to_helo = toval;
5139 TimeOuts.to_quit = toval;
5143 TimeOuts.to_miscshort = toval;
5147 TimeOuts.to_ident = toval;
5151 TimeOuts.to_fileopen = toval;
5155 TimeOuts.to_connect = toval;
5159 TimeOuts.to_iconnect = toval;
5163 TimeOuts.to_aconnect = toval;
5167 toval = convtime(val, 'h');
5168 TimeOuts.to_q_warning[TOC_NORMAL] = toval;
5169 TimeOuts.to_q_warning[TOC_URGENT] = toval;
5170 TimeOuts.to_q_warning[TOC_NONURGENT] = toval;
5171 TimeOuts.to_q_warning[TOC_DSN] = toval;
5175 case TO_QUEUEWARN_NORMAL:
5176 toval = convtime(val, 'h');
5177 TimeOuts.to_q_warning[TOC_NORMAL] = toval;
5180 case TO_QUEUEWARN_URGENT:
5181 toval = convtime(val, 'h');
5182 TimeOuts.to_q_warning[TOC_URGENT] = toval;
5185 case TO_QUEUEWARN_NON_URGENT:
5186 toval = convtime(val, 'h');
5187 TimeOuts.to_q_warning[TOC_NONURGENT] = toval;
5190 case TO_QUEUEWARN_DSN:
5191 toval = convtime(val, 'h');
5192 TimeOuts.to_q_warning[TOC_DSN] = toval;
5195 case TO_QUEUERETURN:
5196 toval = convtime(val, 'd');
5197 TimeOuts.to_q_return[TOC_NORMAL] = toval;
5198 TimeOuts.to_q_return[TOC_URGENT] = toval;
5199 TimeOuts.to_q_return[TOC_NONURGENT] = toval;
5200 TimeOuts.to_q_return[TOC_DSN] = toval;
5204 case TO_QUEUERETURN_NORMAL:
5205 toval = convtime(val, 'd');
5206 TimeOuts.to_q_return[TOC_NORMAL] = toval;
5209 case TO_QUEUERETURN_URGENT:
5210 toval = convtime(val, 'd');
5211 TimeOuts.to_q_return[TOC_URGENT] = toval;
5214 case TO_QUEUERETURN_NON_URGENT:
5215 toval = convtime(val, 'd');
5216 TimeOuts.to_q_return[TOC_NONURGENT] = toval;
5219 case TO_QUEUERETURN_DSN:
5220 toval = convtime(val, 'd');
5221 TimeOuts.to_q_return[TOC_DSN] = toval;
5225 MciInfoTimeout = toval;
5228 case TO_RESOLVER_RETRANS:
5229 toval = convtime(val, 's');
5230 TimeOuts.res_retrans[RES_TO_DEFAULT] = toval;
5231 TimeOuts.res_retrans[RES_TO_FIRST] = toval;
5232 TimeOuts.res_retrans[RES_TO_NORMAL] = toval;
5236 case TO_RESOLVER_RETRY:
5238 TimeOuts.res_retry[RES_TO_DEFAULT] = i;
5239 TimeOuts.res_retry[RES_TO_FIRST] = i;
5240 TimeOuts.res_retry[RES_TO_NORMAL] = i;
5244 case TO_RESOLVER_RETRANS_NORMAL:
5245 TimeOuts.res_retrans[RES_TO_NORMAL] = convtime(val, 's');
5248 case TO_RESOLVER_RETRY_NORMAL:
5249 TimeOuts.res_retry[RES_TO_NORMAL] = atoi(val);
5252 case TO_RESOLVER_RETRANS_FIRST:
5253 TimeOuts.res_retrans[RES_TO_FIRST] = convtime(val, 's');
5256 case TO_RESOLVER_RETRY_FIRST:
5257 TimeOuts.res_retry[RES_TO_FIRST] = atoi(val);
5261 TimeOuts.to_control = toval;
5265 TimeOuts.to_lhlo = toval;
5270 TimeOuts.to_auth = toval;
5276 TimeOuts.to_starttls = toval;
5281 syserr("settimeout: invalid timeout %s", name);
5287 for (i = 0; i <= addopts; i++)
5288 setbitn(to->to_code + i, StickyTimeoutOpt);
5292 ** INITTIMEOUTS -- parse and set timeout values
5295 ** val -- a pointer to the values. If NULL, do initial
5297 ** sticky -- if set, don't let other setoptions override
5298 ** this suboption value.
5304 ** Initializes the TimeOuts structure
5308 inittimeouts(val, sticky)
5315 sm_dprintf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val);
5318 TimeOuts.to_connect = (time_t) 0 SECONDS;
5319 TimeOuts.to_aconnect = (time_t) 0 SECONDS;
5320 TimeOuts.to_iconnect = (time_t) 0 SECONDS;
5321 TimeOuts.to_initial = (time_t) 5 MINUTES;
5322 TimeOuts.to_helo = (time_t) 5 MINUTES;
5323 TimeOuts.to_mail = (time_t) 10 MINUTES;
5324 TimeOuts.to_rcpt = (time_t) 1 HOUR;
5325 TimeOuts.to_datainit = (time_t) 5 MINUTES;
5326 TimeOuts.to_datablock = (time_t) 1 HOUR;
5327 TimeOuts.to_datafinal = (time_t) 1 HOUR;
5328 TimeOuts.to_rset = (time_t) 5 MINUTES;
5329 TimeOuts.to_quit = (time_t) 2 MINUTES;
5330 TimeOuts.to_nextcommand = (time_t) 1 HOUR;
5331 TimeOuts.to_miscshort = (time_t) 2 MINUTES;
5333 TimeOuts.to_ident = (time_t) 5 SECONDS;
5335 TimeOuts.to_ident = (time_t) 0 SECONDS;
5337 TimeOuts.to_fileopen = (time_t) 60 SECONDS;
5338 TimeOuts.to_control = (time_t) 2 MINUTES;
5339 TimeOuts.to_lhlo = (time_t) 2 MINUTES;
5341 TimeOuts.to_auth = (time_t) 10 MINUTES;
5344 TimeOuts.to_starttls = (time_t) 1 HOUR;
5348 sm_dprintf("Timeouts:\n");
5349 sm_dprintf(" connect = %ld\n",
5350 (long) TimeOuts.to_connect);
5351 sm_dprintf(" aconnect = %ld\n",
5352 (long) TimeOuts.to_aconnect);
5353 sm_dprintf(" initial = %ld\n",
5354 (long) TimeOuts.to_initial);
5355 sm_dprintf(" helo = %ld\n", (long) TimeOuts.to_helo);
5356 sm_dprintf(" mail = %ld\n", (long) TimeOuts.to_mail);
5357 sm_dprintf(" rcpt = %ld\n", (long) TimeOuts.to_rcpt);
5358 sm_dprintf(" datainit = %ld\n",
5359 (long) TimeOuts.to_datainit);
5360 sm_dprintf(" datablock = %ld\n",
5361 (long) TimeOuts.to_datablock);
5362 sm_dprintf(" datafinal = %ld\n",
5363 (long) TimeOuts.to_datafinal);
5364 sm_dprintf(" rset = %ld\n", (long) TimeOuts.to_rset);
5365 sm_dprintf(" quit = %ld\n", (long) TimeOuts.to_quit);
5366 sm_dprintf(" nextcommand = %ld\n",
5367 (long) TimeOuts.to_nextcommand);
5368 sm_dprintf(" miscshort = %ld\n",
5369 (long) TimeOuts.to_miscshort);
5370 sm_dprintf(" ident = %ld\n", (long) TimeOuts.to_ident);
5371 sm_dprintf(" fileopen = %ld\n",
5372 (long) TimeOuts.to_fileopen);
5373 sm_dprintf(" lhlo = %ld\n",
5374 (long) TimeOuts.to_lhlo);
5375 sm_dprintf(" control = %ld\n",
5376 (long) TimeOuts.to_control);
5383 while (SM_ISSPACE(*val))
5387 for (p = val; *p != '\0' && *p != ','; p++)
5392 if (isascii(*val) && isdigit(*val))
5394 /* old syntax -- set everything */
5395 TimeOuts.to_mail = convtime(val, 'm');
5396 TimeOuts.to_rcpt = TimeOuts.to_mail;
5397 TimeOuts.to_datainit = TimeOuts.to_mail;
5398 TimeOuts.to_datablock = TimeOuts.to_mail;
5399 TimeOuts.to_datafinal = TimeOuts.to_mail;
5400 TimeOuts.to_nextcommand = TimeOuts.to_mail;
5403 setbitn(TO_MAIL, StickyTimeoutOpt);
5404 setbitn(TO_RCPT, StickyTimeoutOpt);
5405 setbitn(TO_DATAINIT, StickyTimeoutOpt);
5406 setbitn(TO_DATABLOCK, StickyTimeoutOpt);
5407 setbitn(TO_DATAFINAL, StickyTimeoutOpt);
5408 setbitn(TO_COMMAND, StickyTimeoutOpt);
5414 register char *q = strchr(val, ':');
5416 if (q == NULL && (q = strchr(val, '=')) == NULL)
5422 settimeout(val, q, sticky);