diff options
Diffstat (limited to 'contrib/sendmail/src/readcf.c')
-rw-r--r-- | contrib/sendmail/src/readcf.c | 1489 |
1 files changed, 1014 insertions, 475 deletions
diff --git a/contrib/sendmail/src/readcf.c b/contrib/sendmail/src/readcf.c index 73acff5..1f6a662 100644 --- a/contrib/sendmail/src/readcf.c +++ b/contrib/sendmail/src/readcf.c @@ -11,12 +11,9 @@ * */ -#ifndef lint -static char id[] = "@(#)$Id: readcf.c,v 8.382.4.43 2001/08/14 23:08:13 ca Exp $"; -#endif /* ! lint */ - #include <sendmail.h> +SM_RCSID("@(#)$Id: readcf.c,v 8.594 2001/12/14 00:43:17 gshapiro Exp $") #if NETINET || NETINET6 # include <arpa/inet.h> @@ -31,6 +28,7 @@ static void fileclass __P((int, char *, char *, bool, bool)); static char **makeargv __P((char *)); static void settimeout __P((char *, char *, bool)); static void toomany __P((int, int)); +static char *extrquotstr __P((char *, char **, char *, bool *)); /* ** READCF -- read configuration file. @@ -57,7 +55,10 @@ static void toomany __P((int, int)); ** Mn arg=val... Define mailer. n is the internal name. ** Args specify mailer parameters. ** Oxvalue Set option x to value. +** O option value Set option (long name) to value. ** Pname=value Set precedence name to value. +** Qn arg=val... Define queue groups. n is the internal name. +** Args specify queue parameters. ** Vversioncode[/vendorcode] ** Version level/vendor name of ** configuration syntax. @@ -68,8 +69,8 @@ static void toomany __P((int, int)); ** ** Parameters: ** cfname -- configuration file name. -** safe -- TRUE if this is the system config file; -** FALSE otherwise. +** safe -- true if this is the system config file; +** false otherwise. ** e -- the main envelope. ** ** Returns: @@ -85,7 +86,7 @@ readcf(cfname, safe, e) bool safe; register ENVELOPE *e; { - FILE *cf; + SM_FILE_T *cf; int ruleset = -1; char *q; struct rewrite *rwp = NULL; @@ -94,6 +95,7 @@ readcf(cfname, safe, e) int nfuzzy; char *file; bool optional; + bool ok; int mid; register char *p; long sff = SFF_OPENASROOT; @@ -102,7 +104,7 @@ readcf(cfname, safe, e) char exbuf[MAXLINE]; char pvpbuf[MAXLINE + MAXATOM]; static char *null_list[1] = { NULL }; - extern u_char TokTypeNoC[]; + extern unsigned char TokTypeNoC[]; FileName = cfname; LineNumber = 0; @@ -113,33 +115,34 @@ readcf(cfname, safe, e) if (cf == NULL) { syserr("cannot open"); - finis(FALSE, EX_OSFILE); + finis(false, true, EX_OSFILE); } - if (fstat(fileno(cf), &statb) < 0) + if (fstat(sm_io_getinfo(cf, SM_IO_WHAT_FD, NULL), &statb) < 0) { syserr("cannot fstat"); - finis(FALSE, EX_OSFILE); + finis(false, true, EX_OSFILE); } if (!S_ISREG(statb.st_mode)) { syserr("not a plain file"); - finis(FALSE, EX_OSFILE); + finis(false, true, EX_OSFILE); } if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) { if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS) - fprintf(stderr, "%s: WARNING: dangerous write permissions\n", - FileName); + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: WARNING: dangerous write permissions\n", + FileName); if (LogLevel > 0) sm_syslog(LOG_CRIT, NOQID, "%s: WARNING: dangerous write permissions", FileName); } -#ifdef XLA +#if XLA xla_zero(); #endif /* XLA */ @@ -148,7 +151,7 @@ readcf(cfname, safe, e) if (bp[0] == '#') { if (bp != buf) - sm_free(bp); + sm_free(bp); /* XXX */ continue; } @@ -202,7 +205,7 @@ readcf(cfname, safe, e) { register char **ap; - rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); + rwp->r_lhs = copyplist(rwp->r_lhs, true, NULL); /* count the number of fuzzy matches in LHS */ for (ap = rwp->r_lhs; *ap != NULL; ap++) @@ -288,7 +291,7 @@ readcf(cfname, safe, e) { register char **ap; - rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); + rwp->r_rhs = copyplist(rwp->r_rhs, true, NULL); /* check no out-of-bounds replacements */ nfuzzy += '0'; @@ -326,6 +329,36 @@ readcf(cfname, safe, e) case MATCHNCLASS: botch = "$~"; break; + +#if 0 +/* +** This doesn't work yet as there are maps defined *after* the cf +** is read such as host, user, and alias. So for now, it's removed. +** When it comes back, the RELEASE_NOTES entry will be: +** Emit warnings for unknown maps when reading the .cf file. Based on +** patch from Robert Harker of Harker Systems. +*/ + + case LOOKUPBEGIN: + /* + ** Got a database lookup, + ** check if map is defined. + */ + + ep = *(ap + 1); + if ((*ep & 0377) != MACRODEXPAND && + stab(ep, ST_MAP, + ST_FIND) == NULL) + { + (void) sm_io_fprintf(smioout, + SM_TIME_DEFAULT, + "Warning: %s: line %d: map %s not found\n", + FileName, + LineNumber, + ep); + } + break; +#endif /* 0 */ } if (botch != NULL) syserr("Inappropriate use of %s on RHS", @@ -349,22 +382,24 @@ readcf(cfname, safe, e) if (rwp != NULL) { if (OpMode == MD_TEST) - printf("WARNING: Ruleset %s has multiple definitions\n", - &bp[1]); + (void) sm_io_fprintf(smioout, + SM_TIME_DEFAULT, + "WARNING: Ruleset %s has multiple definitions\n", + &bp[1]); if (tTd(37, 1)) - dprintf("WARNING: Ruleset %s has multiple definitions\n", - &bp[1]); + sm_dprintf("WARNING: Ruleset %s has multiple definitions\n", + &bp[1]); while (rwp->r_next != NULL) rwp = rwp->r_next; } break; case 'D': /* macro definition */ - mid = macid(&bp[1], &ep); + mid = macid_parse(&bp[1], &ep); if (mid == 0) break; p = munchstring(ep, NULL, '\0'); - define(mid, newstr(p), e); + macdefine(&e->e_macro, A_TEMP, mid, p); break; case 'H': /* required header line */ @@ -375,7 +410,7 @@ readcf(cfname, safe, e) case 'T': /* trusted user (set class `t') */ if (bp[0] == 'C') { - mid = macid(&bp[1], &ep); + mid = macid_parse(&bp[1], &ep); if (mid == 0) break; expand(ep, exbuf, sizeof exbuf, e); @@ -405,27 +440,40 @@ readcf(cfname, safe, e) break; case 'F': /* word class from file */ - mid = macid(&bp[1], &ep); + mid = macid_parse(&bp[1], &ep); if (mid == 0) break; for (p = ep; isascii(*p) && isspace(*p); ) p++; if (p[0] == '-' && p[1] == 'o') { - optional = TRUE; - while (*p != '\0' && !(isascii(*p) && isspace(*p))) + optional = true; + while (*p != '\0' && + !(isascii(*p) && isspace(*p))) p++; while (isascii(*p) && isspace(*p)) p++; + file = p; } else - optional = FALSE; + optional = false; - file = p; - q = p; - while (*q != '\0' && !(isascii(*q) && isspace(*q))) - q++; - if (*file == '|') + if (*p == '@') + { + /* use entire spec */ + file = p; + } + else + { + file = extrquotstr(p, &q, " ", &ok); + if (!ok) + { + syserr("illegal filename '%s'", p); + break; + } + } + + if (*file == '|' || *file == '@') p = "%s"; else { @@ -442,7 +490,7 @@ readcf(cfname, safe, e) fileclass(mid, file, p, safe, optional); break; -#ifdef XLA +#if XLA case 'L': /* extended load average description */ xla_init(&bp[1]); break; @@ -463,7 +511,7 @@ readcf(cfname, safe, e) break; case 'O': /* set option */ - setoption(bp[1], &bp[2], safe, FALSE, e); + setoption(bp[1], &bp[2], safe, false, e); break; case 'P': /* set precedence */ @@ -482,6 +530,10 @@ readcf(cfname, safe, e) NumPriorities++; break; + case 'Q': /* define queue */ + makequeue(&bp[1], true); + break; + case 'V': /* configuration syntax version */ for (p = &bp[1]; isascii(*p) && isspace(*p); p++) continue; @@ -502,12 +554,15 @@ readcf(cfname, safe, e) /* level 5 configs have short name in $w */ p = macvalue('w', e); if (p != NULL && (p = strchr(p, '.')) != NULL) + { *p = '\0'; - define('w', macvalue('w', e), e); + macdefine(&e->e_macro, A_TEMP, 'w', + macvalue('w', e)); + } } if (ConfigLevel >= 6) { - ColonOkInAddr = FALSE; + ColonOkInAddr = false; } /* @@ -539,25 +594,28 @@ readcf(cfname, safe, e) setuserenv(&bp[1], p); break; -#if _FFR_MILTER case 'X': /* mail filter */ +#if MILTER milter_setup(&bp[1]); +#else /* MILTER */ + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: Filter usage ('X') requires Milter support (-DMILTER)\n"); +#endif /* MILTER */ break; -#endif /* _FFR_MILTER */ default: badline: syserr("unknown configuration line \"%s\"", bp); } if (bp != buf) - sm_free(bp); + sm_free(bp); /* XXX */ } - if (ferror(cf)) + if (sm_io_error(cf)) { syserr("I/O read error"); - finis(FALSE, EX_OSFILE); + finis(false, true, EX_OSFILE); } - (void) fclose(cf); + (void) sm_io_close(cf, SM_TIME_DEFAULT); FileName = NULL; /* initialize host maps from local service tables */ @@ -573,35 +631,21 @@ readcf(cfname, safe, e) short mapreturn[MAXMAPACTIONS]; nmaps = switch_map_find("hosts", maptype, mapreturn); - UseNameServer = FALSE; + UseNameServer = false; if (nmaps > 0 && nmaps <= MAXMAPSTACK) { register int mapno; - for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) + for (mapno = 0; mapno < nmaps && !UseNameServer; + mapno++) { if (strcmp(maptype[mapno], "dns") == 0) - UseNameServer = TRUE; - } - } - -#ifdef HESIOD - nmaps = switch_map_find("passwd", maptype, mapreturn); - UseHesiod = FALSE; - if (nmaps > 0 && nmaps <= MAXMAPSTACK) - { - register int mapno; - - for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) - { - if (strcmp(maptype[mapno], "hesiod") == 0) - UseHesiod = TRUE; + UseNameServer = true; } } -#endif /* HESIOD */ } } -/* +/* ** TRANSLATE_DOLLARS -- convert $x into internal form ** ** Actually does all appropriate pre-processing of a config line @@ -627,7 +671,6 @@ translate_dollars(bp) { if (*p == '#' && p > bp && ConfigLevel >= 3) { - /* this is an on-line comment */ register char *e; switch (*--p & 0377) @@ -639,7 +682,7 @@ translate_dollars(bp) case '\\': /* it's backslash escaped */ - (void) strlcpy(p, p + 1, strlen(p)); + (void) sm_strlcpy(p, p + 1, strlen(p)); break; default: @@ -648,7 +691,7 @@ translate_dollars(bp) *p != '\n' && p > bp) p--; if ((e = strchr(++p, '\n')) != NULL) - (void) strlcpy(p, e, strlen(p)); + (void) sm_strlcpy(p, e, strlen(p)); else *p-- = '\0'; break; @@ -662,7 +705,7 @@ translate_dollars(bp) if (p[1] == '$') { /* actual dollar sign.... */ - (void) strlcpy(p, p + 1, strlen(p)); + (void) sm_strlcpy(p, p + 1, strlen(p)); continue; } @@ -674,16 +717,16 @@ translate_dollars(bp) p++; /* convert macro name to code */ - *p = macid(p, &ep); + *p = macid_parse(p, &ep); if (ep != p + 1) - (void) strlcpy(p + 1, ep, strlen(p + 1)); + (void) sm_strlcpy(p + 1, ep, strlen(p + 1)); } /* strip trailing white space from the line */ while (--p > bp && isascii(*p) && isspace(*p)) *p = '\0'; } -/* +/* ** TOOMANY -- signal too many of some option ** ** Parameters: @@ -704,7 +747,7 @@ toomany(id, maxcnt) { syserr("too many %c lines, %d max", id, maxcnt); } -/* +/* ** FILECLASS -- read members of a class from a file ** ** Parameters: @@ -719,11 +762,41 @@ toomany(id, maxcnt) ** none ** ** Side Effects: -** ** puts all lines in filename that match a scanf into ** the named class. */ +/* +** Break up the match into words and add to class. +*/ + +static void +parse_class_words(class, line) + int class; + char *line; +{ + while (line != NULL && *line != '\0') + { + register char *q; + + /* strip leading spaces */ + while (isascii(*line) && isspace(*line)) + line++; + if (*line == '\0') + break; + + /* find the end of the word */ + q = line; + while (*line != '\0' && !(isascii(*line) && isspace(*line))) + line++; + if (*line != '\0') + *line++ = '\0'; + + /* enter the word in the symbol table */ + setclass(class, q); + } +} + static void fileclass(class, filename, fmt, safe, optional) int class; @@ -732,34 +805,166 @@ fileclass(class, filename, fmt, safe, optional) bool safe; bool optional; { - FILE *f; + SM_FILE_T *f; long sff; pid_t pid; register char *p; char buf[MAXLINE]; if (tTd(37, 2)) - dprintf("fileclass(%s, fmt=%s)\n", filename, fmt); + sm_dprintf("fileclass(%s, fmt=%s)\n", filename, fmt); + + if (*filename == '\0') + { + syserr("fileclass: missing file name"); + return; + } + else if (!SM_IS_DIR_DELIM(*filename) && *filename != '|' && + (p = strchr(filename, '@')) != NULL) + { + int status = 0; + char *key; + char *mn; + char *cl, *spec; + STAB *mapclass; + MAP map; + + mn = newstr(macname(class)); + + key = filename; + + /* skip past '@' */ + *p++ = '\0'; + cl = p; + + if (strcmp(cl, "LDAP") == 0) + { + int n; + char *lc; + char jbuf[MAXHOSTNAMELEN]; + char lcbuf[MAXLINE]; + + /* Get $j */ + expand("\201j", jbuf, sizeof jbuf, &BlankEnvelope); + if (jbuf[0] == '\0') + { + (void) sm_strlcpy(jbuf, "localhost", + sizeof jbuf); + } + + /* impose the default schema */ + lc = macvalue(macid("{sendmailMTACluster}"), CurEnv); + if (lc == NULL) + lc = ""; + else + { + expand(lc, lcbuf, sizeof lcbuf, CurEnv); + lc = lcbuf; + } + + cl = "ldap"; + n = sm_snprintf(buf, sizeof buf, + "-k (&(objectClass=sendmailMTAClass)(sendmailMTAClassName=%s)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))) -v sendmailMTAClassValue", + mn, lc, jbuf); + if (n >= sizeof buf) + { + syserr("fileclass: F{%s}: Default LDAP string too long", + mn); + sm_free(mn); + return; + } + spec = buf; + } + else + { + if ((spec = strchr(cl, ':')) == NULL) + { + syserr("fileclass: F{%s}: missing map class", + mn); + sm_free(mn); + return; + } + *spec++ ='\0'; + } + + /* set up map structure */ + mapclass = stab(cl, ST_MAPCLASS, ST_FIND); + if (mapclass == NULL) + { + syserr("fileclass: F{%s}: class %s not available", + mn, cl); + sm_free(mn); + return; + } + memset(&map, '\0', sizeof map); + map.map_class = &mapclass->s_mapclass; + map.map_mname = mn; + map.map_mflags |= MF_FILECLASS; + + /* parse map spec */ + if (!map.map_class->map_parse(&map, spec)) + { + /* map_parse() showed the error already */ + sm_free(mn); + return; + } + map.map_mflags |= MF_VALID; + + /* open map */ + if (map.map_class->map_open(&map, O_RDONLY)) + { + map.map_mflags |= MF_OPEN; + map.map_pid = getpid(); + } + else + { + if (!optional && + !bitset(MF_OPTIONAL, map.map_mflags)) + syserr("fileclass: F{%s}: map open failed", + mn); + sm_free(mn); + return; + } + + /* lookup */ + p = (*map.map_class->map_lookup)(&map, key, NULL, &status); + if (status != EX_OK && status != EX_NOTFOUND) + { + if (!optional) + syserr("fileclass: F{%s}: map lookup failed", + mn); + p = NULL; + } + + /* use the results */ + if (p != NULL) + parse_class_words(class, p); - if (filename[0] == '|') + /* close map */ + map.map_mflags |= MF_CLOSING; + map.map_class->map_close(&map); + map.map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); + sm_free(mn); + return; + } + else if (filename[0] == '|') { auto int fd; int i; char *argv[MAXPV + 1]; i = 0; - for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t")) - { - if (i >= MAXPV) - break; + for (p = strtok(&filename[1], " \t"); + p != NULL && i < MAXPV; + p = strtok(NULL, " \t")) argv[i++] = p; - } argv[i] = NULL; pid = prog_open(argv, &fd, CurEnv); if (pid < 0) f = NULL; else - f = fdopen(fd, "r"); + f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, + (void *) &fd, SM_IO_RDONLY, NULL); } else { @@ -772,6 +977,8 @@ fileclass(class, filename, fmt, safe, optional) sff |= SFF_NOWLINK; if (safe) sff |= SFF_OPENASROOT; + else if (RealUid == 0) + sff |= SFF_ROOTOK; if (DontLockReadFiles) sff |= SFF_NOLOCK; f = safefopen(filename, O_RDONLY, 0, sff); @@ -783,7 +990,7 @@ fileclass(class, filename, fmt, safe, optional) return; } - while (fgets(buf, sizeof buf, f) != NULL) + while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) { #if SCANF char wordbuf[MAXLINE + 1]; @@ -792,44 +999,27 @@ fileclass(class, filename, fmt, safe, optional) if (buf[0] == '#') continue; #if SCANF - if (sscanf(buf, fmt, wordbuf) != 1) + if (sm_io_sscanf(buf, fmt, wordbuf) != 1) continue; p = wordbuf; #else /* SCANF */ p = buf; #endif /* SCANF */ + parse_class_words(class, p); + /* - ** Break up the match into words. + ** If anything else is added here, + ** check if the '@' map case above + ** needs the code as well. */ - - while (*p != '\0') - { - register char *q; - - /* strip leading spaces */ - while (isascii(*p) && isspace(*p)) - p++; - if (*p == '\0') - break; - - /* find the end of the word */ - q = p; - while (*p != '\0' && !(isascii(*p) && isspace(*p))) - p++; - if (*p != '\0') - *p++ = '\0'; - - /* enter the word in the symbol table */ - setclass(class, q); - } } - (void) fclose(f); + (void) sm_io_close(f, SM_TIME_DEFAULT); if (pid > 0) (void) waitfor(pid); } -/* +/* ** MAKEMAILER -- define a new mailer. ** ** Parameters: @@ -844,12 +1034,14 @@ fileclass(class, filename, fmt, safe, optional) ** M -- the maximum message size ** N -- the niceness at which to run ** P -- the path to the mailer +** Q -- the queue group for the mailer ** R -- the recipient rewriting set ** S -- the sender rewriting set ** T -- the mailer type (for DSNs) ** U -- the uid to run as ** W -- the time to wait at the end ** m -- maximum messages per connection +** r -- maximum number of recipients per message ** / -- new root directory ** The first word is the canonical name of the mailer. ** @@ -870,14 +1062,17 @@ makemailer(line) int i; char fcode; auto char *endp; - extern int NextMailer; + static int nextmailer = 0; /* "free" index into Mailer struct */ /* allocate a mailer and set up defaults */ m = (struct mailer *) xalloc(sizeof *m); memset((char *) m, '\0', sizeof *m); + errno = 0; /* avoid bogus error text */ /* collect the mailer name */ - for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) + for (p = line; + *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); + p++) continue; if (*p != '\0') *p++ = '\0'; @@ -893,7 +1088,8 @@ makemailer(line) { auto char *delimptr; - while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) + while (*p != '\0' && + (*p == ',' || (isascii(*p) && isspace(*p)))) p++; /* p now points to field code */ @@ -915,16 +1111,24 @@ makemailer(line) switch (fcode) { case 'P': /* pathname */ - if (*p == '\0') - syserr("mailer %s: empty path name", m->m_name); - else + if (*p != '\0') /* error is issued below */ m->m_mailer = newstr(p); break; case 'F': /* flags */ for (; *p != '\0'; p++) + { if (!(isascii(*p) && isspace(*p))) + { +#if _FFR_DEPRECATE_MAILER_FLAG_I + if (*p == M_INTERNAL) + sm_syslog(LOG_WARNING, NOQID, + "WARNING: mailer=%s, flag=%c deprecated", + m->m_name, *p); +#endif /* _FFR_DEPRECATE_MAILER_FLAG_I */ setbitn(bitidx(*p), m->m_flags); + } + } break; case 'S': /* sender rewriting ruleset */ @@ -959,10 +1163,7 @@ makemailer(line) break; case 'A': /* argument vector */ - if (*p == '\0') - syserr("mailer %s: null argument vector", - m->m_name); - else + if (*p != '\0') /* error is issued below */ m->m_argv = makeargv(p); break; @@ -974,11 +1175,9 @@ makemailer(line) m->m_maxdeliveries = atoi(p); break; -#if _FFR_DYNAMIC_TOBUF case 'r': /* max recipient per envelope */ m->m_maxrcpt = atoi(p); break; -#endif /* _FFR_DYNAMIC_TOBUF */ case 'L': /* maximum line length */ m->m_linelimit = atoi(p); @@ -1005,6 +1204,20 @@ makemailer(line) m->m_defcharset = newstr(p); break; + case 'Q': /* queue for this mailer */ + if (*p == '\0') + { + syserr("mailer %s: null queue", m->m_name); + break; + } + s = stab(p, ST_QUEUE, ST_FIND); + if (s == NULL) + syserr("mailer %s: unknown queue %s", + m->m_name, p); + else + m->m_qgrp = s->s_quegrp->qg_index; + break; + case 'T': /* MTA-Name/Address/Diagnostic types */ /* extract MTA name type; default to "dns" */ m->m_mtatype = newstr(p); @@ -1133,6 +1346,24 @@ makemailer(line) p = delimptr; } +#if !HASRRESVPORT + if (bitnset(M_SECURE_PORT, m->m_flags)) + { + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "M%s: Warning: F=%c set on system that doesn't support rresvport()\n", + m->m_name, M_SECURE_PORT); + } +#endif /* !HASRRESVPORT */ + +#if !HASNICE + if (m->m_nice != 0) + { + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "M%s: Warning: N= set on system that doesn't support nice()\n", + m->m_name); + } +#endif /* !HASNICE */ + /* do some rationality checking */ if (m->m_argv == NULL) { @@ -1145,16 +1376,14 @@ makemailer(line) return; } - if (NextMailer >= MAXMAILERS) + if (nextmailer >= MAXMAILERS) { syserr("too many mailers defined (%d max)", MAXMAILERS); return; } -#if _FFR_DYNAMIC_TOBUF if (m->m_maxrcpt <= 0) m->m_maxrcpt = DEFAULT_MAX_RCPT; -#endif /* _FFR_DYNAMIC_TOBUF */ /* do some heuristic cleanup for back compatibility */ if (bitnset(M_LIMITS, m->m_flags)) @@ -1167,21 +1396,11 @@ makemailer(line) if (strcmp(m->m_mailer, "[TCP]") == 0) { -#if _FFR_REMOVE_TCP_MAILER_PATH - syserr("M%s: P=[TCP] is deprecated, use P=[IPC] instead\n", - m->m_name); + syserr("M%s: P=[TCP] must be replaced by P=[IPC]", m->m_name); return; -#else /* _FFR_REMOVE_TCP_MAILER_PATH */ - printf("M%s: Warning: P=[TCP] is deprecated, use P=[IPC] instead\n", - m->m_name); -#endif /* _FFR_REMOVE_TCP_MAILER_PATH */ } - if (strcmp(m->m_mailer, "[IPC]") == 0 -#if !_FFR_REMOVE_TCP_MAILER_PATH - || strcmp(m->m_mailer, "[TCP]") == 0 -#endif /* !_FFR_REMOVE_TCP_MAILER_PATH */ - ) + if (strcmp(m->m_mailer, "[IPC]") == 0) { /* Use the second argument for host or path to socket */ if (m->m_argv[0] == NULL || m->m_argv[1] == NULL || @@ -1195,21 +1414,30 @@ makemailer(line) #if NETUNIX && strcmp(m->m_argv[0], "FILE") != 0 #endif /* NETUNIX */ -#if !_FFR_DEPRECATE_IPC_MAILER_ARG - && strcmp(m->m_argv[0], "IPC") != 0 -#endif /* !_FFR_DEPRECATE_IPC_MAILER_ARG */ ) { - printf("M%s: Warning: first argument in %s mailer must be %s\n", - m->m_name, m->m_mailer, + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "M%s: Warning: first argument in %s mailer must be %s\n", + m->m_name, m->m_mailer, #if NETUNIX - "TCP or FILE" + "TCP or FILE" #else /* NETUNIX */ - "TCP" + "TCP" #endif /* NETUNIX */ - ); + ); + } + if (m->m_mtatype == NULL) + m->m_mtatype = "dns"; + if (m->m_addrtype == NULL) + m->m_addrtype = "rfc822"; + if (m->m_diagtype == NULL) + { + if (m->m_argv[0] != NULL && + strcmp(m->m_argv[0], "FILE") == 0) + m->m_diagtype = "x-unix"; + else + m->m_diagtype = "smtp"; } - } else if (strcmp(m->m_mailer, "[FILE]") == 0) { @@ -1231,23 +1459,6 @@ makemailer(line) } } - if (strcmp(m->m_mailer, "[IPC]") == 0 || - strcmp(m->m_mailer, "[TCP]") == 0) - { - if (m->m_mtatype == NULL) - m->m_mtatype = "dns"; - if (m->m_addrtype == NULL) - m->m_addrtype = "rfc822"; - if (m->m_diagtype == NULL) - { - if (m->m_argv[0] != NULL && - strcmp(m->m_argv[0], "FILE") == 0) - m->m_diagtype = "x-unix"; - else - m->m_diagtype = "smtp"; - } - } - if (m->m_eol == NULL) { char **pp; @@ -1274,16 +1485,16 @@ makemailer(line) if (s->s_mailer != NULL) { i = s->s_mailer->m_mno; - sm_free(s->s_mailer); + sm_free(s->s_mailer); /* XXX */ } else { - i = NextMailer++; + i = nextmailer++; } Mailer[i] = s->s_mailer = m; m->m_mno = i; } -/* +/* ** MUNCHSTRING -- translate a string into internal form. ** ** Parameters: @@ -1307,8 +1518,8 @@ munchstring(p, delimptr, delim) int delim; { register char *q; - bool backslash = FALSE; - bool quotemode = FALSE; + bool backslash = false; + bool quotemode = false; static char buf[MAXLINE]; for (q = buf; *p != '\0' && q < &buf[sizeof buf - 1]; p++) @@ -1316,7 +1527,7 @@ munchstring(p, delimptr, delim) if (backslash) { /* everything is roughly literal */ - backslash = FALSE; + backslash = false; switch (*p) { case 'r': /* carriage return */ @@ -1340,7 +1551,7 @@ munchstring(p, delimptr, delim) else { if (*p == '\\') - backslash = TRUE; + backslash = true; else if (*p == '"') quotemode = !quotemode; else if (quotemode || *p != delim) @@ -1355,7 +1566,67 @@ munchstring(p, delimptr, delim) *q++ = '\0'; return buf; } -/* +/* +** EXTRQUOTSTR -- extract a (quoted) string. +** +** This routine deals with quoted (") strings and escaped +** spaces (\\ ). +** +** Parameters: +** p -- source string. +** delimptr -- if non-NULL, set to the pointer of the +** field delimiter character. +** delimbuf -- delimiters for the field. +** st -- if non-NULL, store the return value (whether the +** string was correctly quoted) here. +** +** Returns: +** the extracted string. +** +** Side Effects: +** the returned string is a local static buffer. +** it must be copied before the function is called again. +*/ + +static char * +extrquotstr(p, delimptr, delimbuf, st) + register char *p; + char **delimptr; + char *delimbuf; + bool *st; +{ + register char *q; + bool backslash = false; + bool quotemode = false; + static char buf[MAXLINE]; + + for (q = buf; *p != '\0' && q < &buf[sizeof buf - 1]; p++) + { + if (backslash) + { + backslash = false; + if (*p != ' ') + *q++ = '\\'; + } + if (*p == '\\') + backslash = true; + else if (*p == '"') + quotemode = !quotemode; + else if (quotemode || + strchr(delimbuf, (int) *p) == NULL) + *q++ = *p; + else + break; + } + + if (delimptr != NULL) + *delimptr = p; + *q++ = '\0'; + if (st != NULL) + *st = !(quotemode || backslash); + return buf; +} +/* ** MAKEARGV -- break up a string into words ** ** Parameters: @@ -1396,7 +1667,7 @@ makeargv(p) return avp; } -/* +/* ** PRINTRULES -- print rewrite rules (for debugging) ** ** Parameters: @@ -1419,18 +1690,21 @@ printrules() { if (RewriteRules[ruleset] == NULL) continue; - printf("\n----Rule Set %d:", ruleset); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "\n----Rule Set %d:", ruleset); for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) { - printf("\nLHS:"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "\nLHS:"); printav(rwp->r_lhs); - printf("RHS:"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "RHS:"); printav(rwp->r_rhs); } } } -/* +/* ** PRINTMAILER -- print mailer structure (for debugging) ** ** Parameters: @@ -1446,54 +1720,68 @@ printmailer(m) { int j; - printf("mailer %d (%s): P=%s S=", m->m_mno, m->m_name, m->m_mailer); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "mailer %d (%s): P=%s S=", m->m_mno, m->m_name, + m->m_mailer); if (RuleSetNames[m->m_se_rwset] == NULL) - printf("%d/", m->m_se_rwset); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d/", + m->m_se_rwset); else - printf("%s/", RuleSetNames[m->m_se_rwset]); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s/", + RuleSetNames[m->m_se_rwset]); if (RuleSetNames[m->m_sh_rwset] == NULL) - printf("%d R=", m->m_sh_rwset); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d R=", + m->m_sh_rwset); else - printf("%s R=", RuleSetNames[m->m_sh_rwset]); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s R=", + RuleSetNames[m->m_sh_rwset]); if (RuleSetNames[m->m_re_rwset] == NULL) - printf("%d/", m->m_re_rwset); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d/", + m->m_re_rwset); else - printf("%s/", RuleSetNames[m->m_re_rwset]); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s/", + RuleSetNames[m->m_re_rwset]); if (RuleSetNames[m->m_rh_rwset] == NULL) - printf("%d ", m->m_rh_rwset); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d ", + m->m_rh_rwset); else - printf("%s ", RuleSetNames[m->m_rh_rwset]); - printf("M=%ld U=%d:%d F=", m->m_maxsize, - (int) m->m_uid, (int) m->m_gid); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s ", + RuleSetNames[m->m_rh_rwset]); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "M=%ld U=%d:%d F=", + m->m_maxsize, (int) m->m_uid, (int) m->m_gid); for (j = '\0'; j <= '\177'; j++) if (bitnset(j, m->m_flags)) - (void) putchar(j); - printf(" L=%d E=", m->m_linelimit); + (void) sm_io_putc(smioout, SM_TIME_DEFAULT, j); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " L=%d E=", + m->m_linelimit); xputs(m->m_eol); if (m->m_defcharset != NULL) - printf(" C=%s", m->m_defcharset); - printf(" T=%s/%s/%s", - m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, - m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, - m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); -#if _FFR_DYNAMIC_TOBUF - printf(" r=%d", m->m_maxrcpt); -#endif /* _FFR_DYNAMIC_TOBUF */ + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " C=%s", + m->m_defcharset); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " T=%s/%s/%s", + m->m_mtatype == NULL + ? "<undefined>" : m->m_mtatype, + m->m_addrtype == NULL + ? "<undefined>" : m->m_addrtype, + m->m_diagtype == NULL + ? "<undefined>" : m->m_diagtype); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " r=%d", m->m_maxrcpt); if (m->m_argv != NULL) { char **a = m->m_argv; - printf(" A="); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " A="); while (*a != NULL) { if (a != m->m_argv) - printf(" "); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + " "); xputs(*a++); } } - printf("\n"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); } -/* +/* ** SETOPTION -- set global processing option ** ** Parameters: @@ -1532,6 +1820,9 @@ static struct resolverflags { "defnames", RES_DEFNAMES }, { "stayopen", RES_STAYOPEN }, { "dnsrch", RES_DNSRCH }, +# ifdef RES_USE_INET6 + { "use_inet6", RES_USE_INET6 }, +# endif /* RES_USE_INET6 */ { "true", 0 }, /* avoid error on old syntax */ { NULL, 0 } }; @@ -1544,9 +1835,9 @@ static struct resolverflags static struct optioninfo { - char *o_name; /* long name of option */ - u_char o_code; /* short name of option */ - u_short o_flags; /* option flags */ + char *o_name; /* long name of option */ + unsigned char o_code; /* short name of option */ + unsigned short o_flags; /* option flags */ } OptionTab[] = { #if defined(SUN_EXTENSIONS) && defined(REMOTE_MODE) @@ -1560,15 +1851,15 @@ static struct optioninfo { "MinFreeBlocks", 'b', OI_SAFE }, { "CheckpointInterval", 'C', OI_SAFE }, { "HoldExpensive", 'c', OI_NONE }, -#if !_FFR_REMOVE_AUTOREBUILD - { "AutoRebuildAliases", 'D', OI_NONE }, -#endif /* !_FFR_REMOVE_AUTOREBUILD */ { "DeliveryMode", 'd', OI_SAFE }, { "ErrorHeader", 'E', OI_NONE }, { "ErrorMode", 'e', OI_SAFE }, { "TempFileMode", 'F', OI_NONE }, { "SaveFromLine", 'f', OI_NONE }, { "MatchGECOS", 'G', OI_NONE }, + + /* no long name, just here to avoid problems in setoption */ + { "", 'g', OI_NONE }, { "HelpFile", 'H', OI_NONE }, { "MaxHopCount", 'h', OI_NONE }, { "ResolverOptions", 'I', OI_NONE }, @@ -1580,6 +1871,9 @@ static struct optioninfo { "UseErrorsTo", 'l', OI_NONE }, { "LogLevel", 'L', OI_SAFE }, { "MeToo", 'm', OI_SAFE }, + + /* no long name, just here to avoid problems in setoption */ + { "", 'M', OI_NONE }, { "CheckAliases", 'n', OI_NONE }, { "OldStyleHeaders", 'o', OI_SAFE }, { "DaemonPortOptions", 'O', OI_NONE }, @@ -1704,49 +1998,92 @@ static struct optioninfo { "DataFileBufferSize", O_DF_BUFSIZE, OI_NONE }, #define O_XF_BUFSIZE 0xb1 { "XscriptFileBufferSize", O_XF_BUFSIZE, OI_NONE }, -# define O_LDAPDEFAULTSPEC 0xb2 +#define O_LDAPDEFAULTSPEC 0xb2 { "LDAPDefaultSpec", O_LDAPDEFAULTSPEC, OI_NONE }, #if _FFR_QUEUEDELAY -#define O_QUEUEDELAY 0xb3 +# define O_QUEUEDELAY 0xb3 { "QueueDelay", O_QUEUEDELAY, OI_NONE }, #endif /* _FFR_QUEUEDELAY */ -# define O_SRVCERTFILE 0xb4 +#define O_SRVCERTFILE 0xb4 { "ServerCertFile", O_SRVCERTFILE, OI_NONE }, -# define O_SRVKEYFILE 0xb5 +#define O_SRVKEYFILE 0xb5 { "Serverkeyfile", O_SRVKEYFILE, OI_NONE }, -# define O_CLTCERTFILE 0xb6 +#define O_CLTCERTFILE 0xb6 { "ClientCertFile", O_CLTCERTFILE, OI_NONE }, -# define O_CLTKEYFILE 0xb7 +#define O_CLTKEYFILE 0xb7 { "Clientkeyfile", O_CLTKEYFILE, OI_NONE }, -# define O_CACERTFILE 0xb8 +#define O_CACERTFILE 0xb8 { "CACERTFile", O_CACERTFILE, OI_NONE }, -# define O_CACERTPATH 0xb9 +#define O_CACERTPATH 0xb9 { "CACERTPath", O_CACERTPATH, OI_NONE }, -# define O_DHPARAMS 0xba +#define O_DHPARAMS 0xba { "DHParameters", O_DHPARAMS, OI_NONE }, -#if _FFR_MILTER #define O_INPUTMILTER 0xbb { "InputMailFilters", O_INPUTMILTER, OI_NONE }, #define O_MILTER 0xbc { "Milter", O_MILTER, OI_SUBOPT }, -#endif /* _FFR_MILTER */ #define O_SASLOPTS 0xbd { "AuthOptions", O_SASLOPTS, OI_NONE }, -#if _FFR_QUEUE_FILE_MODE #define O_QUEUE_FILE_MODE 0xbe { "QueueFileMode", O_QUEUE_FILE_MODE, OI_NONE }, -#endif /* _FFR_QUEUE_FILE_MODE */ -# if _FFR_TLS_1 +#if _FFR_TLS_1 # define O_DHPARAMS5 0xbf { "DHParameters512", O_DHPARAMS5, OI_NONE }, # define O_CIPHERLIST 0xc0 { "CipherList", O_CIPHERLIST, OI_NONE }, -# endif /* _FFR_TLS_1 */ -# define O_RANDFILE 0xc1 +#endif /* _FFR_TLS_1 */ +#define O_RANDFILE 0xc1 { "RandFile", O_RANDFILE, OI_NONE }, +#define O_TLS_SRV_OPTS 0xc2 + { "TLSSrvOptions", O_TLS_SRV_OPTS, OI_NONE }, +#define O_RCPTTHROT 0xc3 + { "BadRcptThrottle", O_RCPTTHROT, OI_SAFE }, +#define O_DLVR_MIN 0xc4 + { "DeliverByMin", O_DLVR_MIN, OI_NONE }, +#define O_MAXQUEUECHILDREN 0xc5 + { "MaxQueueChildren", O_MAXQUEUECHILDREN, OI_NONE }, +#define O_MAXRUNNERSPERQUEUE 0xc6 + { "MaxRunnersPerQueue", O_MAXRUNNERSPERQUEUE, OI_NONE }, +#define O_DIRECTSUBMODIFIERS 0xc7 + { "DirectSubmissionModifiers", O_DIRECTSUBMODIFIERS, OI_NONE }, +#define O_NICEQUEUERUN 0xc8 + { "NiceQueueRun", O_NICEQUEUERUN, OI_NONE }, +#define O_SHMKEY 0xc9 + { "SharedMemoryKey", O_SHMKEY, OI_NONE }, +#define O_SASLBITS 0xca + { "AuthMaxBits", O_SASLBITS, OI_NONE }, +#define O_MBDB 0xcb + { "MailboxDatabase", O_MBDB, OI_NONE }, +#define O_MSQ 0xcc + { "UseMSP", O_MSQ, OI_NONE }, +#define O_DELAY_LA 0xcd + { "DelayLA", O_DELAY_LA, OI_NONE }, +#define O_FASTSPLIT 0xce + { "FastSplit", O_FASTSPLIT, OI_NONE }, +#if _FFR_SOFT_BOUNCE +# define O_SOFTBOUNCE 0xcf + { "SoftBounce", O_SOFTBOUNCE, OI_NONE }, +#endif /* _FFR_SOFT_BOUNCE */ { NULL, '\0', OI_NONE } }; +# define CANONIFY(val) + +# define SET_OPT_DEFAULT(opt, val) opt = val + +/* set a string option by expanding the value and assigning it */ +/* WARNING this belongs ONLY into a case statement! */ +#define SET_STRING_EXP(str) \ + expand(val, exbuf, sizeof exbuf, e); \ + newval = sm_pstrdup_x(exbuf); \ + if (str != NULL) \ + sm_free(str); \ + CANONIFY(newval); \ + str = newval; \ + break + +#define OPTNAME o->o_name == NULL ? "<unknown>" : o->o_name + void setoption(opt, val, safe, sticky, e) int opt; @@ -1764,8 +2101,12 @@ setoption(opt, val, safe, sticky, e) char buf[50]; extern bool Warn_Q_option; #if _FFR_ALLOW_SASLINFO - extern int SubmitMode; + extern unsigned int SubmitMode; #endif /* _FFR_ALLOW_SASLINFO */ +#if STARTTLS + char *newval; + char exbuf[MAXLINE]; +#endif /* STARTTLS */ errno = 0; if (opt == ' ') @@ -1795,7 +2136,7 @@ setoption(opt, val, safe, sticky, e) sel = NULL; for (o = OptionTab; o->o_name != NULL; o++) { - if (strncasecmp(o->o_name, val, strlen(val)) != 0) + if (sm_strncasecmp(o->o_name, val, strlen(val)) != 0) continue; if (strlen(o->o_name) == strlen(val)) { @@ -1839,27 +2180,29 @@ setoption(opt, val, safe, sticky, e) if (o->o_code == opt) break; } + if (o->o_name == NULL) + { + syserr("readcf: unknown option name 0x%x", opt & 0xff); + return; + } subopt = NULL; } if (subopt != NULL && !bitset(OI_SUBOPT, o->o_flags)) { if (tTd(37, 1)) - dprintf("setoption: %s does not support suboptions, ignoring .%s\n", - o->o_name == NULL ? "<unknown>" : o->o_name, - subopt); + sm_dprintf("setoption: %s does not support suboptions, ignoring .%s\n", + OPTNAME, subopt); subopt = NULL; } if (tTd(37, 1)) { - dprintf(isascii(opt) && isprint(opt) ? - "setoption %s (%c)%s%s=" : - "setoption %s (0x%x)%s%s=", - o->o_name == NULL ? "<unknown>" : o->o_name, - opt, - subopt == NULL ? "" : ".", - subopt == NULL ? "" : subopt); + sm_dprintf(isascii(opt) && isprint(opt) ? + "setoption %s (%c)%s%s=" : + "setoption %s (0x%x)%s%s=", + OPTNAME, opt, subopt == NULL ? "" : ".", + subopt == NULL ? "" : subopt); xputs(val); } @@ -1870,7 +2213,7 @@ setoption(opt, val, safe, sticky, e) if (!sticky && bitnset(opt, StickyOpt)) { if (tTd(37, 1)) - dprintf(" (ignored)\n"); + sm_dprintf(" (ignored)\n"); return; } @@ -1879,7 +2222,7 @@ setoption(opt, val, safe, sticky, e) */ if (!safe && RealUid == 0) - safe = TRUE; + safe = true; if (!safe && !bitset(OI_SAFE, o->o_flags)) { if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) @@ -1887,13 +2230,13 @@ setoption(opt, val, safe, sticky, e) int dp; if (tTd(37, 1)) - dprintf(" (unsafe)"); - dp = drop_privileges(TRUE); + sm_dprintf(" (unsafe)"); + dp = drop_privileges(true); setstat(dp); } } if (tTd(37, 1)) - dprintf("\n"); + sm_dprintf("\n"); switch (opt & 0xff) { @@ -1905,14 +2248,14 @@ setoption(opt, val, safe, sticky, e) #if MIME8TO7 switch (*val) { - case 'm': /* convert 8-bit, convert MIME */ - MimeMode = MM_CVTMIME|MM_MIME8BIT; - break; - case 'p': /* pass 8 bit, convert MIME */ MimeMode = MM_CVTMIME|MM_PASS8BIT; break; + case 'm': /* convert 8-bit, convert MIME */ + MimeMode = MM_CVTMIME|MM_MIME8BIT; + break; + case 's': /* strict adherence */ MimeMode = MM_CVTMIME; break; @@ -1937,23 +2280,30 @@ setoption(opt, val, safe, sticky, e) default: syserr("Unknown 8-bit mode %c", *val); - finis(FALSE, EX_USAGE); + finis(false, true, EX_USAGE); } #else /* MIME8TO7 */ - printf("Warning: Option EightBitMode requires MIME8TO7 support\n"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: Option: %s requires MIME8TO7 support\n", + OPTNAME); #endif /* MIME8TO7 */ break; case 'A': /* set default alias file */ if (val[0] == '\0') - setalias("aliases"); + { + char *al; + + SET_OPT_DEFAULT(al, "aliases"); + setalias(al); + } else setalias(val); break; case 'a': /* look N minutes for "@:@" in alias file */ if (val[0] == '\0') - SafeAlias = 5 * 60; /* five minutes */ + SafeAlias = 5 MINUTES; else SafeAlias = convtime(val, 'm'); break; @@ -1991,12 +2341,6 @@ setoption(opt, val, safe, sticky, e) case SM_QUEUE: /* queue only */ case SM_DEFER: /* queue only and defer map lookups */ -#if !QUEUE - syserr("need QUEUE to set -odqueue or -oddefer"); - break; -#endif /* !QUEUE */ - /* FALLTHROUGH */ - case SM_DELIVER: /* do everything */ case SM_FORK: /* fork after verification */ set_delivery_mode(*val, e); @@ -2004,16 +2348,10 @@ setoption(opt, val, safe, sticky, e) default: syserr("Unknown delivery mode %c", *val); - finis(FALSE, EX_USAGE); + finis(false, true, EX_USAGE); } break; -#if !_FFR_REMOVE_AUTOREBUILD - case 'D': /* rebuild alias database as needed */ - AutoRebuild = atobool(val); - break; -#endif /* !_FFR_REMOVE_AUTOREBUILD */ - case 'E': /* error message header/header file */ if (*val != '\0') ErrMsgFile = newstr(val); @@ -2064,9 +2402,12 @@ setoption(opt, val, safe, sticky, e) case 'H': /* help file */ if (val[0] == '\0') - HelpFile = "helpfile"; + { + SET_OPT_DEFAULT(HelpFile, "helpfile"); + } else { + CANONIFY(val); HelpFile = newstr(val); } break; @@ -2087,9 +2428,9 @@ setoption(opt, val, safe, sticky, e) p++; if (*p == '\0') break; - clearmode = FALSE; + clearmode = false; if (*p == '-') - clearmode = TRUE; + clearmode = true; else if (*p != '+') p--; p++; @@ -2098,21 +2439,19 @@ setoption(opt, val, safe, sticky, e) p++; if (*p != '\0') *p++ = '\0'; - if (strcasecmp(q, "HasWildcardMX") == 0) + if (sm_strcasecmp(q, "HasWildcardMX") == 0) { HasWildcardMX = !clearmode; continue; } -#if _FFR_WORKAROUND_BROKEN_NAMESERVERS if (sm_strcasecmp(q, "WorkAroundBrokenAAAA") == 0) { WorkAroundBrokenAAAA = !clearmode; continue; } -#endif /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */ for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) { - if (strcasecmp(q, rfp->rf_name) == 0) + if (sm_strcasecmp(q, rfp->rf_name) == 0) break; } if (rfp->rf_name == NULL) @@ -2123,8 +2462,8 @@ setoption(opt, val, safe, sticky, e) _res.options |= rfp->rf_bits; } if (tTd(8, 2)) - dprintf("_res.options = %x, HasWildcardMX = %d\n", - (u_int) _res.options, HasWildcardMX); + sm_dprintf("_res.options = %x, HasWildcardMX = %d\n", + (unsigned int) _res.options, HasWildcardMX); #else /* NAMED_BIND */ usrerr("name server (I option) specified but BIND not compiled in"); #endif /* NAMED_BIND */ @@ -2139,6 +2478,7 @@ setoption(opt, val, safe, sticky, e) break; case 'J': /* .forward search path */ + CANONIFY(val); ForwardPath = newstr(val); break; @@ -2162,14 +2502,14 @@ setoption(opt, val, safe, sticky, e) break; case 'M': /* define macro */ - sticky = FALSE; - mid = macid(val, &ep); + sticky = false; + mid = macid_parse(val, &ep); if (mid == 0) break; p = newstr(ep); if (!safe) cleanstrcpy(p, p, MAXNAME); - define(mid, p, CurEnv); + macdefine(&CurEnv->e_macro, A_TEMP, mid, p); break; case 'm': /* send to me too */ @@ -2183,12 +2523,8 @@ setoption(opt, val, safe, sticky, e) /* 'N' available -- was "net name" */ case 'O': /* daemon options */ -#if DAEMON if (!setdaemonoptions(val)) syserr("too many daemons defined (%d max)", MAXDAEMONS); -#else /* DAEMON */ - syserr("DaemonPortOptions (O option) set but DAEMON not compiled in"); -#endif /* DAEMON */ break; case 'o': /* assume old style headers */ @@ -2217,7 +2553,7 @@ setoption(opt, val, safe, sticky, e) for (pv = PrivacyValues; pv->pv_name != NULL; pv++) { - if (strcasecmp(val, pv->pv_name) == 0) + if (sm_strcasecmp(val, pv->pv_name) == 0) break; } if (pv->pv_name == NULL) @@ -2225,7 +2561,7 @@ setoption(opt, val, safe, sticky, e) else PrivacyFlags |= pv->pv_flag; } - sticky = FALSE; + sticky = false; break; case 'P': /* postmaster copy address for returned mail */ @@ -2246,7 +2582,7 @@ setoption(opt, val, safe, sticky, e) QueueDir = newstr(val); } if (RealUid != 0 && !safe) - Warn_Q_option = TRUE; + Warn_Q_option = true; break; case 'R': /* don't prune routes */ @@ -2262,15 +2598,21 @@ setoption(opt, val, safe, sticky, e) case 'S': /* status file */ if (val[0] == '\0') - StatFile = "statistics"; + { + SET_OPT_DEFAULT(StatFile, "statistics"); + } else { + CANONIFY(val); StatFile = newstr(val); } break; case 's': /* be super safe, even if expensive */ - SuperSafe = atobool(val); + if (tolower(*val) == 'i') + SuperSafe = SAFE_INTERACTIVE; + else + SuperSafe = atobool(val) ? SAFE_REALLY : SAFE_NO; break; case 'T': /* queue timeout */ @@ -2294,7 +2636,11 @@ setoption(opt, val, safe, sticky, e) case 'u': /* set default uid */ for (p = val; *p != '\0'; p++) { +#if _FFR_DOTTED_USERNAMES + if (*p == '/' || *p == ':') +#else /* _FFR_DOTTED_USERNAMES */ if (*p == '.' || *p == '/' || *p == ':') +#endif /* _FFR_DOTTED_USERNAMES */ { *p++ = '\0'; break; @@ -2324,14 +2670,14 @@ setoption(opt, val, safe, sticky, e) } } -#ifdef UID_MAX +# ifdef UID_MAX if (DefUid > UID_MAX) { syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored", - (long) DefUid, (long) UID_MAX); + (long)DefUid, (long)UID_MAX); break; } -#endif /* UID_MAX */ +# endif /* UID_MAX */ /* handle the group if it is there */ if (*p == '\0') @@ -2358,10 +2704,14 @@ setoption(opt, val, safe, sticky, e) QueueLA = atoi(val); break; - case 'X': /* load avg at which to auto-reject connections */ + case 'X': /* load avg at which to auto-reject connections */ RefuseLA = atoi(val); break; + case O_DELAY_LA: /* load avg at which to delay connections */ + DelayLA = atoi(val); + break; + case 'y': /* work recipient factor */ WkRecipFact = atoi(val); break; @@ -2382,11 +2732,21 @@ setoption(opt, val, safe, sticky, e) case O_QUEUESORTORD: /* queue sorting order */ switch (*val) { + case 'f': /* File Name */ + case 'F': + QueueSortOrder = QSO_BYFILENAME; + break; + case 'h': /* Host first */ case 'H': QueueSortOrder = QSO_BYHOST; break; + case 'm': /* Modification time */ + case 'M': + QueueSortOrder = QSO_BYMODTIME; + break; + case 'p': /* Priority order */ case 'P': QueueSortOrder = QSO_BYPRIORITY; @@ -2397,10 +2757,17 @@ setoption(opt, val, safe, sticky, e) QueueSortOrder = QSO_BYTIME; break; - case 'f': /* File Name */ - case 'F': - QueueSortOrder = QSO_BYFILENAME; + case 'r': /* Random */ + case 'R': + QueueSortOrder = QSO_RANDOM; + break; + +#if _FFR_RHS + case 's': /* Shuffled host name */ + case 'S': + QueueSortOrder = QSO_BYSHUFFLE; break; +#endif /* _FFR_RHS */ default: syserr("Invalid queue sort order \"%s\"", val); @@ -2445,6 +2812,7 @@ setoption(opt, val, safe, sticky, e) #endif /* _FFR_QUEUEDELAY */ case O_HOSTSFILE: /* pathname of /etc/hosts file */ + CANONIFY(val); HostsFile = newstr(val); break; @@ -2453,10 +2821,11 @@ setoption(opt, val, safe, sticky, e) break; case O_DEFCHARSET: /* default character set for mimefying */ - DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); + DefaultCharSet = newstr(denlstring(val, true, true)); break; case O_SSFILE: /* service switch file */ + CANONIFY(val); ServiceSwitchFile = newstr(val); break; @@ -2465,15 +2834,15 @@ setoption(opt, val, safe, sticky, e) break; case O_NORCPTACTION: /* what to do if no recipient */ - if (strcasecmp(val, "none") == 0) + if (sm_strcasecmp(val, "none") == 0) NoRecipientAction = NRA_NO_ACTION; - else if (strcasecmp(val, "add-to") == 0) + else if (sm_strcasecmp(val, "add-to") == 0) NoRecipientAction = NRA_ADD_TO; - else if (strcasecmp(val, "add-apparently-to") == 0) + else if (sm_strcasecmp(val, "add-apparently-to") == 0) NoRecipientAction = NRA_ADD_APPARENTLY_TO; - else if (strcasecmp(val, "add-bcc") == 0) + else if (sm_strcasecmp(val, "add-bcc") == 0) NoRecipientAction = NRA_ADD_BCC; - else if (strcasecmp(val, "add-to-undisclosed") == 0) + else if (sm_strcasecmp(val, "add-to-undisclosed") == 0) NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; else syserr("Invalid NoRecipientAction: %s", val); @@ -2492,13 +2861,41 @@ setoption(opt, val, safe, sticky, e) break; case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ - MaxQueueRun = atol(val); + MaxQueueRun = atoi(val); break; case O_MAXCHILDREN: /* max # of children of daemon */ MaxChildren = atoi(val); break; + case O_MAXQUEUECHILDREN: /* max # of children of daemon */ + MaxQueueChildren = atoi(val); + break; + + case O_MAXRUNNERSPERQUEUE: /* max # runners in a queue group */ + MaxRunnersPerQueue = atoi(val); + break; + + case O_NICEQUEUERUN: /* nice queue runs */ +#if !HASNICE + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: NiceQueueRun set on system that doesn't support nice()\n"); +#endif /* !HASNICE */ + + /* XXX do we want to check the range? > 0 ? */ + NiceQueueRun = atoi(val); + break; + + case O_SHMKEY : /* shared memory key */ +#if SM_CONF_SHM + ShmKey = atol(val); +#else /* SM_CONF_SHM */ + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n", + OPTNAME); +#endif /* SM_CONF_SHM */ + break; + #if _FFR_MAX_FORWARD_ENTRIES case O_MAXFORWARD: /* max # of forward entries */ MaxForwardEntries = atoi(val); @@ -2510,11 +2907,12 @@ setoption(opt, val, safe, sticky, e) break; case O_MUSTQUOTE: /* must quote these characters in phrases */ - (void) strlcpy(buf, "@,;:\\()[]", sizeof buf); - if (strlen(val) < (SIZE_T) sizeof buf - 10) - (void) strlcat(buf, val, sizeof buf); + (void) sm_strlcpy(buf, "@,;:\\()[]", sizeof buf); + if (strlen(val) < sizeof buf - 10) + (void) sm_strlcat(buf, val, sizeof buf); else - printf("Warning: MustQuoteChars too long, ignored.\n"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: MustQuoteChars too long, ignored.\n"); MustQuoteChars = newstr(buf); break; @@ -2528,7 +2926,8 @@ setoption(opt, val, safe, sticky, e) case O_OPCHARS: /* operator characters (old $o macro) */ if (OperatorChars != NULL) - printf("Warning: OperatorChars is being redefined.\n It should only be set before ruleset definitions.\n"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: OperatorChars is being redefined.\n It should only be set before ruleset definitions.\n"); OperatorChars = newstr(munchstring(val, NULL, '\0')); break; @@ -2559,15 +2958,13 @@ setoption(opt, val, safe, sticky, e) break; case O_DBLBOUNCE: /* address to which to send double bounces */ - if (val[0] != '\0') - DoubleBounceAddr = newstr(val); - else - syserr("readcf: option DoubleBounceAddress: value required"); + DoubleBounceAddr = newstr(val); break; case O_HSDIR: /* persistent host status directory */ if (val[0] != '\0') { + CANONIFY(val); HostStatDir = newstr(val); } break; @@ -2579,7 +2976,11 @@ setoption(opt, val, safe, sticky, e) case O_RUNASUSER: /* run bulk of code as this user */ for (p = val; *p != '\0'; p++) { +#if _FFR_DOTTED_USERNAMES + if (*p == '/' || *p == ':') +#else /* _FFR_DOTTED_USERNAMES */ if (*p == '.' || *p == '/' || *p == ':') +#endif /* _FFR_DOTTED_USERNAMES */ { *p++ = '\0'; break; @@ -2607,21 +3008,37 @@ setoption(opt, val, safe, sticky, e) RunAsUid = pw->pw_uid; RunAsGid = pw->pw_gid; } + else if (EffGid == pw->pw_gid) + RunAsGid = pw->pw_gid; + else if (UseMSP && *p == '\0') + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "WARNING: RunAsGid for MSP ignored, check group ids (egid=%d, want=%d)\n", + (int) EffGid, + (int) pw->pw_gid); } -#ifdef UID_MAX +# ifdef UID_MAX if (RunAsUid > UID_MAX) { syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored", (long) RunAsUid, (long) UID_MAX); break; } -#endif /* UID_MAX */ +# endif /* UID_MAX */ if (*p != '\0') { if (isascii(*p) && isdigit(*p)) { - if (can_setuid) - RunAsGid = atoi(p); + gid_t runasgid; + + runasgid = (gid_t) atoi(p); + if (can_setuid || EffGid == runasgid) + RunAsGid = runasgid; + else if (UseMSP) + (void) sm_io_fprintf(smioout, + SM_TIME_DEFAULT, + "WARNING: RunAsGid for MSP ignored, check group ids (egid=%d, want=%d)\n", + (int) EffGid, + (int) runasgid); } else { @@ -2631,13 +3048,19 @@ setoption(opt, val, safe, sticky, e) if (gr == NULL) syserr("readcf: option RunAsUser: unknown group %s", p); - else if (can_setuid) + else if (can_setuid || EffGid == gr->gr_gid) RunAsGid = gr->gr_gid; + else if (UseMSP) + (void) sm_io_fprintf(smioout, + SM_TIME_DEFAULT, + "WARNING: RunAsGid for MSP ignored, check group ids (egid=%d, want=%d)\n", + (int) EffGid, + (int) gr->gr_gid); } } if (tTd(47, 5)) - dprintf("readcf: RunAsUser = %d:%d\n", - (int)RunAsUid, (int)RunAsGid); + sm_dprintf("readcf: RunAsUser = %d:%d\n", + (int) RunAsUid, (int) RunAsGid); break; case O_DSN_RRT: @@ -2645,12 +3068,10 @@ setoption(opt, val, safe, sticky, e) break; case O_PIDFILE: - if (PidFile != NULL) - sm_free(PidFile); - PidFile = newstr(val); + PSTRSET(PidFile, val); break; - case O_DONTBLAMESENDMAIL: + case O_DONTBLAMESENDMAIL: p = val; for (;;) { @@ -2670,7 +3091,7 @@ setoption(opt, val, safe, sticky, e) for (dbs = DontBlameSendmailValues; dbs->dbs_name != NULL; dbs++) { - if (strcasecmp(val, dbs->dbs_name) == 0) + if (sm_strcasecmp(val, dbs->dbs_name) == 0) break; } if (dbs->dbs_name == NULL) @@ -2680,21 +3101,29 @@ setoption(opt, val, safe, sticky, e) else setbitn(dbs->dbs_flag, DontBlameSendmail); } - sticky = FALSE; + sticky = false; break; case O_DPI: - DontProbeInterfaces = atobool(val); + if (sm_strcasecmp(val, "loopback") == 0) + DontProbeInterfaces = DPI_SKIPLOOPBACK; + else if (atobool(val)) + DontProbeInterfaces = DPI_PROBENONE; + else + DontProbeInterfaces = DPI_PROBEALL; break; case O_MAXRCPT: MaxRcptPerMsg = atoi(val); break; + case O_RCPTTHROT: + BadRcptThrottle = atoi(val); + break; + case O_DEADLETTER: - if (DeadLetterDrop != NULL) - sm_free(DeadLetterDrop); - DeadLetterDrop = newstr(val); + CANONIFY(val); + PSTRSET(DeadLetterDrop, val); break; #if _FFR_DONTLOCKFILESFORREAD_OPTION @@ -2710,26 +3139,36 @@ setoption(opt, val, safe, sticky, e) case O_CNCTONLYTO: /* XXX should probably use gethostbyname */ #if NETINET || NETINET6 + ConnectOnlyTo.sa.sa_family = AF_UNSPEC; # if NETINET6 - if (inet_addr(val) == INADDR_NONE) - { + if (anynet_pton(AF_INET6, val, + &ConnectOnlyTo.sin6.sin6_addr) != 1) ConnectOnlyTo.sa.sa_family = AF_INET6; - if (inet_pton(AF_INET6, val, - &ConnectOnlyTo.sin6.sin6_addr) != 1) - syserr("readcf: option ConnectOnlyTo: invalid IP address %s", - val); - } else # endif /* NETINET6 */ +# if NETINET { - ConnectOnlyTo.sa.sa_family = AF_INET; ConnectOnlyTo.sin.sin_addr.s_addr = inet_addr(val); + if (ConnectOnlyTo.sin.sin_addr.s_addr != INADDR_NONE) + ConnectOnlyTo.sa.sa_family = AF_INET; + } + +# endif /* NETINET */ + if (ConnectOnlyTo.sa.sa_family == AF_UNSPEC) + { + syserr("readcf: option ConnectOnlyTo: invalid IP address %s", + val); + break; } #endif /* NETINET || NETINET6 */ break; case O_TRUSTUSER: -#if HASFCHOWN +# if !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING) + if (!UseMSP) + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "readcf: option TrustedUser may cause problems on systems\n which do not support fchown() if UseMSP is not set.\n"); +# endif /* !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING) */ if (isascii(*val) && isdigit(*val)) TrustedUid = atoi(val); else @@ -2755,9 +3194,6 @@ setoption(opt, val, safe, sticky, e) TrustedUid = 0; } # endif /* UID_MAX */ -#else /* HASFCHOWN */ - syserr("readcf: option TrustedUser: can not be used on systems which do not support fchown()"); -#endif /* HASFCHOWN */ break; case O_MAXMIMEHDRLEN: @@ -2773,18 +3209,18 @@ setoption(opt, val, safe, sticky, e) if (MaxMimeHeaderLength < 0) MaxMimeHeaderLength = 0; else if (MaxMimeHeaderLength < 128) - printf("Warning: MaxMimeHeaderLength: header length limit set lower than 128\n"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: MaxMimeHeaderLength: header length limit set lower than 128\n"); if (MaxMimeFieldLength < 0) MaxMimeFieldLength = 0; else if (MaxMimeFieldLength < 40) - printf("Warning: MaxMimeHeaderLength: field length limit set lower than 40\n"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: MaxMimeHeaderLength: field length limit set lower than 40\n"); break; case O_CONTROLSOCKET: - if (ControlSocketName != NULL) - sm_free(ControlSocketName); - ControlSocketName = newstr(val); + PSTRSET(ControlSocketName, val); break; case O_MAXHDRSLEN: @@ -2792,20 +3228,23 @@ setoption(opt, val, safe, sticky, e) if (MaxHeadersLength > 0 && MaxHeadersLength < (MAXHDRSLEN / 2)) - printf("Warning: MaxHeadersLength: headers length limit set lower than %d\n", (MAXHDRSLEN / 2)); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: MaxHeadersLength: headers length limit set lower than %d\n", + (MAXHDRSLEN / 2)); break; case O_PROCTITLEPREFIX: - if (ProcTitlePrefix != NULL) - sm_free(ProcTitlePrefix); - ProcTitlePrefix = newstr(val); + PSTRSET(ProcTitlePrefix, val); break; #if SASL case O_SASLINFO: -#if _FFR_ALLOW_SASLINFO +# if _FFR_ALLOW_SASLINFO /* - ** Allow users to select their own authinfo file. + ** Allow users to select their own authinfo file + ** under certain circumstances, otherwise just ignore + ** the option. If the option isn't ignored, several + ** commands don't work very well, e.g., mailq. ** However, this is not a "perfect" solution. ** If mail is queued, the authentication info ** will not be used in subsequent delivery attempts. @@ -2814,22 +3253,14 @@ setoption(opt, val, safe, sticky, e) */ if (!bitset(SUBMIT_MSA, SubmitMode) && RealUid != 0 && RunAsUid != RealUid) - { - errno = 0; - syserr("Error: %s only allowed with -U\n", - o->o_name == NULL ? "<unknown>" : o->o_name); - ExitStat = EX_USAGE; break; - } -#endif /* _FFR_ALLOW_SASLINFO */ - if (SASLInfo != NULL) - sm_free(SASLInfo); - SASLInfo = newstr(val); +# endif /* _FFR_ALLOW_SASLINFO */ + PSTRSET(SASLInfo, val); break; case O_SASLMECH: if (AuthMechanisms != NULL) - sm_free(AuthMechanisms); + sm_free(AuthMechanisms); /* XXX */ if (*val != '\0') AuthMechanisms = newstr(val); else @@ -2839,12 +3270,11 @@ setoption(opt, val, safe, sticky, e) case O_SASLOPTS: while (val != NULL && *val != '\0') { - switch(*val) + switch (*val) { case 'A': SASLOpts |= SASL_AUTH_AUTH; break; -# if _FFR_SASL_OPTS case 'a': SASLOpts |= SASL_SEC_NOACTIVE; break; @@ -2863,13 +3293,17 @@ setoption(opt, val, safe, sticky, e) case 'y': SASLOpts |= SASL_SEC_NOANONYMOUS; break; -# endif /* _FFR_SASL_OPTS */ + case ' ': /* ignore */ + case '\t': /* ignore */ + case ',': /* ignore */ + break; default: - printf("Warning: Option: %s unknown parameter '%c'\n", - o->o_name == NULL ? "<unknown>" - : o->o_name, - (isascii(*val) && isprint(*val)) ? *val - : '?'); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: Option: %s unknown parameter '%c'\n", + OPTNAME, + (isascii(*val) && + isprint(*val)) + ? *val : '?'); break; } ++val; @@ -2878,80 +3312,99 @@ setoption(opt, val, safe, sticky, e) ++val; } break; + case O_SASLBITS: + MaxSLBits = atoi(val); + break; #else /* SASL */ case O_SASLINFO: case O_SASLMECH: case O_SASLOPTS: - printf("Warning: Option: %s requires SASL support (-DSASL)\n", - o->o_name == NULL ? "<unknown>" : o->o_name); + case O_SASLBITS: + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: Option: %s requires SASL support (-DSASL)\n", + OPTNAME); break; #endif /* SASL */ #if STARTTLS case O_SRVCERTFILE: - if (SrvCERTfile != NULL) - sm_free(SrvCERTfile); - SrvCERTfile = newstr(val); - break; - + SET_STRING_EXP(SrvCERTfile); case O_SRVKEYFILE: - if (Srvkeyfile != NULL) - sm_free(Srvkeyfile); - Srvkeyfile = newstr(val); - break; - + SET_STRING_EXP(Srvkeyfile); case O_CLTCERTFILE: - if (CltCERTfile != NULL) - sm_free(CltCERTfile); - CltCERTfile = newstr(val); - break; - + SET_STRING_EXP(CltCERTfile); case O_CLTKEYFILE: - if (Cltkeyfile != NULL) - sm_free(Cltkeyfile); - Cltkeyfile = newstr(val); - break; - + SET_STRING_EXP(Cltkeyfile); case O_CACERTFILE: - if (CACERTfile != NULL) - sm_free(CACERTfile); - CACERTfile = newstr(val); - break; - + SET_STRING_EXP(CACERTfile); case O_CACERTPATH: - if (CACERTpath != NULL) - sm_free(CACERTpath); - CACERTpath = newstr(val); - break; - + SET_STRING_EXP(CACERTpath); case O_DHPARAMS: - if (DHParams != NULL) - sm_free(DHParams); - DHParams = newstr(val); - break; - -# if _FFR_TLS_1 + SET_STRING_EXP(DHParams); +# if _FFR_TLS_1 case O_DHPARAMS5: - if (DHParams5 != NULL) - sm_free(DHParams5); - DHParams5 = newstr(val); - break; - + SET_STRING_EXP(DHParams5); case O_CIPHERLIST: - if (CipherList != NULL) - sm_free(CipherList); - CipherList = newstr(val); + SET_STRING_EXP(CipherList); +# endif /* _FFR_TLS_1 */ + + /* + ** XXX How about options per daemon/client instead of globally? + ** This doesn't work well for some options, e.g., no server cert, + ** but fine for others. + ** + ** XXX Some people may want different certs per server. + ** + ** See also srvfeatures() + */ + + case O_TLS_SRV_OPTS: + while (val != NULL && *val != '\0') + { + switch (*val) + { + case 'V': + TLS_Srv_Opts |= TLS_I_NO_VRFY; + break; +# if _FFR_TLS_1 + /* + ** Server without a cert? That works only if + ** AnonDH is enabled as cipher, which is not in the + ** default list. Hence the CipherList option must + ** be available. Moreover: which clients support this + ** besides sendmail with this setting? + */ + + case 'C': + TLS_Srv_Opts &= ~TLS_I_SRV_CERT; + break; +# endif /* _FFR_TLS_1 */ + case ' ': /* ignore */ + case '\t': /* ignore */ + case ',': /* ignore */ + break; + default: + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: Option: %s unknown parameter '%c'\n", + OPTNAME, + (isascii(*val) && + isprint(*val)) + ? *val : '?'); + break; + } + ++val; + val = strpbrk(val, ", \t"); + if (val != NULL) + ++val; + } break; -# endif /* _FFR_TLS_1 */ case O_RANDFILE: - if (RandFile != NULL) - sm_free(RandFile); - RandFile= newstr(val); + PSTRSET(RandFile, val); break; -# else /* STARTTLS */ +#else /* STARTTLS */ case O_SRVCERTFILE: case O_SRVKEYFILE: case O_CLTCERTFILE: @@ -2959,23 +3412,20 @@ setoption(opt, val, safe, sticky, e) case O_CACERTFILE: case O_CACERTPATH: case O_DHPARAMS: -# if _FFR_TLS_1 +# if _FFR_TLS_1 case O_DHPARAMS5: case O_CIPHERLIST: -# endif /* _FFR_TLS_1 */ +# endif /* _FFR_TLS_1 */ case O_RANDFILE: - printf("Warning: Option: %s requires TLS support\n", - o->o_name == NULL ? "<unknown>" : o->o_name); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: Option: %s requires TLS support\n", + OPTNAME); break; -# endif /* STARTTLS */ +#endif /* STARTTLS */ case O_CLIENTPORT: -#if DAEMON setclientoptions(val); -#else /* DAEMON */ - syserr("ClientPortOptions (O option) set but DAEMON not compiled in"); -#endif /* DAEMON */ break; case O_DF_BUFSIZE: @@ -2987,37 +3437,80 @@ setoption(opt, val, safe, sticky, e) break; case O_LDAPDEFAULTSPEC: -#ifdef LDAPMAP +#if LDAPMAP ldapmap_set_defaults(val); #else /* LDAPMAP */ - printf("Warning: Option: %s requires LDAP support (-DLDAPMAP)\n", - o->o_name == NULL ? "<unknown>" : o->o_name); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: Option: %s requires LDAP support (-DLDAPMAP)\n", + OPTNAME); #endif /* LDAPMAP */ break; -#if _FFR_MILTER case O_INPUTMILTER: +#if MILTER InputFilterList = newstr(val); +#else /* MILTER */ + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: Option: %s requires Milter support (-DMILTER)\n", + OPTNAME); +#endif /* MILTER */ break; case O_MILTER: +#if MILTER milter_set_option(subopt, val, sticky); +#else /* MILTER */ + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: Option: %s requires Milter support (-DMILTER)\n", + OPTNAME); +#endif /* MILTER */ break; -#endif /* _FFR_MILTER */ -#if _FFR_QUEUE_FILE_MODE case O_QUEUE_FILE_MODE: /* queue file mode */ QueueFileMode = atooct(val) & 0777; break; -#endif /* _FFR_QUEUE_FILE_MODE */ + + case O_DLVR_MIN: /* deliver by minimum time */ + DeliverByMin = convtime(val, 's'); + break; + + /* modifiers {daemon_flags} for direct submissions */ + case O_DIRECTSUBMODIFIERS: + { + BITMAP256 m; /* ignored */ + extern ENVELOPE BlankEnvelope; + + macdefine(&BlankEnvelope.e_macro, A_PERM, + macid("{daemon_flags}"), + getmodifiers(val, m)); + } + break; + + case O_FASTSPLIT: + FastSplit = atoi(val); + break; + + case O_MBDB: + Mbdb = newstr(val); + break; + + case O_MSQ: + UseMSP = atobool(val); + break; + +#if _FFR_SOFT_BOUNCE + case O_SOFTBOUNCE: + SoftBounce = atobool(val); + break; +#endif /* _FFR_SOFT_BOUNCE */ default: if (tTd(37, 1)) { if (isascii(opt) && isprint(opt)) - dprintf("Warning: option %c unknown\n", opt); + sm_dprintf("Warning: option %c unknown\n", opt); else - dprintf("Warning: option 0x%x unknown\n", opt); + sm_dprintf("Warning: option 0x%x unknown\n", opt); } break; } @@ -3033,7 +3526,7 @@ setoption(opt, val, safe, sticky, e) if (sticky && !bitset(OI_SUBOPT, o->o_flags)) setbitn(opt, StickyOpt); } -/* +/* ** SETCLASS -- set a string into a class ** ** Parameters: @@ -3059,25 +3552,25 @@ setclass(class, str) int mid; str++; - mid = macid(str, NULL); + mid = macid(str); if (mid == 0) return; if (tTd(37, 8)) - dprintf("setclass(%s, $=%s)\n", - macname(class), macname(mid)); + sm_dprintf("setclass(%s, $=%s)\n", + macname(class), macname(mid)); copy_class(mid, class); } else { if (tTd(37, 8)) - dprintf("setclass(%s, %s)\n", macname(class), str); + sm_dprintf("setclass(%s, %s)\n", macname(class), str); s = stab(str, ST_CLASS, ST_ENTER); setbitn(bitidx(class), s->s_class); } } -/* +/* ** MAKEMAPENTRY -- create a map entry ** ** Parameters: @@ -3133,7 +3626,8 @@ makemapentry(line) class = stab(classname, ST_MAPCLASS, ST_FIND); if (class == NULL) { - syserr("readcf: map %s: class %s not available", mapname, classname); + syserr("readcf: map %s: class %s not available", mapname, + classname); return NULL; } @@ -3147,19 +3641,16 @@ makemapentry(line) if (tTd(37, 5)) { - dprintf("map %s, class %s, flags %lx, file %s,\n", - s->s_map.map_mname, s->s_map.map_class->map_cname, - s->s_map.map_mflags, - s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); - dprintf("\tapp %s, domain %s, rebuild %s\n", - s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, - s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, - s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); + sm_dprintf("map %s, class %s, flags %lx, file %s,\n", + s->s_map.map_mname, s->s_map.map_class->map_cname, + s->s_map.map_mflags, s->s_map.map_file); + sm_dprintf("\tapp %s, domain %s, rebuild %s\n", + s->s_map.map_app, s->s_map.map_domain, + s->s_map.map_rebuild); } - return &s->s_map; } -/* +/* ** STRTORWSET -- convert string to rewriting set number ** ** Parameters: @@ -3277,7 +3768,7 @@ strtorwset(p, endp, stabmode) char *h = NULL; if (RuleSetNames[ruleset] != NULL) - sm_free(RuleSetNames[ruleset]); + sm_free(RuleSetNames[ruleset]); /* XXX */ if (delim != '\0' && (h = strchr(q, delim)) != NULL) *h = '\0'; RuleSetNames[ruleset] = newstr(q); @@ -3287,7 +3778,7 @@ strtorwset(p, endp, stabmode) } return ruleset; } -/* +/* ** SETTIMEOUT -- set an individual timeout ** ** Parameters: @@ -3305,8 +3796,8 @@ static BITMAP256 StickyTimeoutOpt; static struct timeoutinfo { - char *to_name; /* long name of timeout */ - u_char to_code; /* code for option */ + char *to_name; /* long name of timeout */ + unsigned char to_code; /* code for option */ } TimeOutTab[] = { #define TO_INITIAL 0x01 @@ -3373,6 +3864,14 @@ static struct timeoutinfo { "resolver.retry.first", TO_RESOLVER_RETRY_FIRST }, #define TO_CONTROL 0x1F { "control", TO_CONTROL }, +#define TO_LHLO 0x20 + { "lhlo", TO_LHLO }, +#define TO_AUTH 0x21 + { "auth", TO_AUTH }, +#define TO_STARTTLS 0x22 + { "starttls", TO_STARTTLS }, +#define TO_ACONNECT 0x23 + { "aconnect", TO_ACONNECT }, { NULL, 0 }, }; @@ -3384,16 +3883,15 @@ settimeout(name, val, sticky) bool sticky; { register struct timeoutinfo *to; - int i; - int addopts; + int i, addopts; time_t toval; if (tTd(37, 2)) - dprintf("settimeout(%s = %s)", name, val); + sm_dprintf("settimeout(%s = %s)", name, val); for (to = TimeOutTab; to->to_name != NULL; to++) { - if (strcasecmp(to->to_name, name) == 0) + if (sm_strcasecmp(to->to_name, name) == 0) break; } @@ -3411,12 +3909,12 @@ settimeout(name, val, sticky) if (!sticky && bitnset(to->to_code, StickyTimeoutOpt)) { if (tTd(37, 2)) - dprintf(" (ignored)\n"); + sm_dprintf(" (ignored)\n"); return; } if (tTd(37, 2)) - dprintf("\n"); + sm_dprintf("\n"); toval = convtime(val, 'm'); addopts = 0; @@ -3483,6 +3981,10 @@ settimeout(name, val, sticky) TimeOuts.to_iconnect = toval; break; + case TO_ACONNECT: + TimeOuts.to_aconnect = toval; + break; + case TO_QUEUEWARN: toval = convtime(val, 'h'); TimeOuts.to_q_warning[TOC_NORMAL] = toval; @@ -3570,6 +4072,22 @@ settimeout(name, val, sticky) TimeOuts.to_control = toval; break; + case TO_LHLO: + TimeOuts.to_lhlo = toval; + break; + +#if SASL + case TO_AUTH: + TimeOuts.to_auth = toval; + break; +#endif /* SASL */ + +#if STARTTLS + case TO_STARTTLS: + TimeOuts.to_starttls = toval; + break; +#endif /* STARTTLS */ + default: syserr("settimeout: invalid timeout %s", name); break; @@ -3581,7 +4099,7 @@ settimeout(name, val, sticky) setbitn(to->to_code + i, StickyTimeoutOpt); } } -/* +/* ** INITTIMEOUTS -- parse and set timeout values ** ** Parameters: @@ -3605,10 +4123,11 @@ inittimeouts(val, sticky) register char *p; if (tTd(37, 2)) - dprintf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val); + sm_dprintf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val); if (val == NULL) { TimeOuts.to_connect = (time_t) 0 SECONDS; + TimeOuts.to_aconnect = (time_t) 0 SECONDS; TimeOuts.to_initial = (time_t) 5 MINUTES; TimeOuts.to_helo = (time_t) 5 MINUTES; TimeOuts.to_mail = (time_t) 10 MINUTES; @@ -3627,24 +4146,44 @@ inittimeouts(val, sticky) #endif /* IDENTPROTO */ TimeOuts.to_fileopen = (time_t) 60 SECONDS; TimeOuts.to_control = (time_t) 2 MINUTES; + TimeOuts.to_lhlo = (time_t) 2 MINUTES; +#if SASL + TimeOuts.to_auth = (time_t) 10 MINUTES; +#endif /* SASL */ +#if STARTTLS + TimeOuts.to_starttls = (time_t) 1 HOUR; +#endif /* STARTTLS */ if (tTd(37, 5)) { - dprintf("Timeouts:\n"); - dprintf(" connect = %ld\n", (long)TimeOuts.to_connect); - dprintf(" initial = %ld\n", (long)TimeOuts.to_initial); - dprintf(" helo = %ld\n", (long)TimeOuts.to_helo); - dprintf(" mail = %ld\n", (long)TimeOuts.to_mail); - dprintf(" rcpt = %ld\n", (long)TimeOuts.to_rcpt); - dprintf(" datainit = %ld\n", (long)TimeOuts.to_datainit); - dprintf(" datablock = %ld\n", (long)TimeOuts.to_datablock); - dprintf(" datafinal = %ld\n", (long)TimeOuts.to_datafinal); - dprintf(" rset = %ld\n", (long)TimeOuts.to_rset); - dprintf(" quit = %ld\n", (long)TimeOuts.to_quit); - dprintf(" nextcommand = %ld\n", (long)TimeOuts.to_nextcommand); - dprintf(" miscshort = %ld\n", (long)TimeOuts.to_miscshort); - dprintf(" ident = %ld\n", (long)TimeOuts.to_ident); - dprintf(" fileopen = %ld\n", (long)TimeOuts.to_fileopen); - dprintf(" control = %ld\n", (long)TimeOuts.to_control); + sm_dprintf("Timeouts:\n"); + sm_dprintf(" connect = %ld\n", + (long) TimeOuts.to_connect); + sm_dprintf(" aconnect = %ld\n", + (long) TimeOuts.to_aconnect); + sm_dprintf(" initial = %ld\n", + (long) TimeOuts.to_initial); + sm_dprintf(" helo = %ld\n", (long) TimeOuts.to_helo); + sm_dprintf(" mail = %ld\n", (long) TimeOuts.to_mail); + sm_dprintf(" rcpt = %ld\n", (long) TimeOuts.to_rcpt); + sm_dprintf(" datainit = %ld\n", + (long) TimeOuts.to_datainit); + sm_dprintf(" datablock = %ld\n", + (long) TimeOuts.to_datablock); + sm_dprintf(" datafinal = %ld\n", + (long) TimeOuts.to_datafinal); + sm_dprintf(" rset = %ld\n", (long) TimeOuts.to_rset); + sm_dprintf(" quit = %ld\n", (long) TimeOuts.to_quit); + sm_dprintf(" nextcommand = %ld\n", + (long) TimeOuts.to_nextcommand); + sm_dprintf(" miscshort = %ld\n", + (long) TimeOuts.to_miscshort); + sm_dprintf(" ident = %ld\n", (long) TimeOuts.to_ident); + sm_dprintf(" fileopen = %ld\n", + (long) TimeOuts.to_fileopen); + sm_dprintf(" lhlo = %ld\n", + (long) TimeOuts.to_lhlo); + sm_dprintf(" control = %ld\n", + (long) TimeOuts.to_control); } return; } |