*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for reading the configuration file, and for displaying
#ifndef DISABLE_DKIM
{ "dkim_verify_hashes", opt_stringptr, {&dkim_verify_hashes} },
{ "dkim_verify_keytypes", opt_stringptr, {&dkim_verify_keytypes} },
+ { "dkim_verify_min_keysizes", opt_stringptr, {&dkim_verify_min_keysizes} },
{ "dkim_verify_minimal", opt_bool, {&dkim_verify_minimal} },
{ "dkim_verify_signers", opt_stringptr, {&dkim_verify_signers} },
#endif
#ifdef SUPPORT_PROXY
{ "hosts_proxy", opt_stringptr, {&hosts_proxy} },
#endif
+ { "hosts_require_helo", opt_stringptr, {&hosts_require_helo} },
{ "hosts_treat_as_local", opt_stringptr, {&hosts_treat_as_local} },
#ifdef LOOKUP_IBASE
{ "ibase_servers", opt_stringptr, {&ibase_servers} },
{ "ldap_require_cert", opt_stringptr, {&eldap_require_cert} },
{ "ldap_start_tls", opt_bool, {&eldap_start_tls} },
{ "ldap_version", opt_int, {&eldap_version} },
+#endif
+#ifdef EXPERIMENTAL_ESMTP_LIMITS
+ { "limits_advertise_hosts", opt_stringptr, {&limits_advertise_hosts} },
#endif
{ "local_from_check", opt_bool, {&local_from_check} },
{ "local_from_prefix", opt_stringptr, {&local_from_prefix} },
{ "print_topbitchars", opt_bool, {&print_topbitchars} },
{ "process_log_path", opt_stringptr, {&process_log_path} },
{ "prod_requires_admin", opt_bool, {&prod_requires_admin} },
+#ifdef SUPPORT_PROXY
+ { "proxy_protocol_timeout", opt_time, {&proxy_protocol_timeout} },
+#endif
{ "qualify_domain", opt_stringptr, {&qualify_domain_sender} },
{ "qualify_recipient", opt_stringptr, {&qualify_domain_recipient} },
{ "queue_domains", opt_stringptr, {&queue_domains} },
-#ifdef EXPERIMENTAL_QUEUE_RAMP
+#ifndef DISABLE_QUEUE_RAMP
{ "queue_fast_ramp", opt_bool, {&queue_fast_ramp} },
#endif
{ "queue_list_requires_admin",opt_bool, {&queue_list_requires_admin} },
{ "smtp_accept_max", opt_int, {&smtp_accept_max} },
{ "smtp_accept_max_nonmail", opt_int, {&smtp_accept_max_nonmail} },
{ "smtp_accept_max_nonmail_hosts", opt_stringptr, {&smtp_accept_max_nonmail_hosts} },
- { "smtp_accept_max_per_connection", opt_int, {&smtp_accept_max_per_connection} },
+ { "smtp_accept_max_per_connection", opt_stringptr, {&smtp_accept_max_per_connection} },
{ "smtp_accept_max_per_host", opt_stringptr, {&smtp_accept_max_per_host} },
{ "smtp_accept_queue", opt_int, {&smtp_accept_queue} },
{ "smtp_accept_queue_per_connection", opt_int, {&smtp_accept_queue_per_connection} },
{ "smtp_accept_reserve", opt_int, {&smtp_accept_reserve} },
{ "smtp_active_hostname", opt_stringptr, {&raw_active_hostname} },
+ { "smtp_backlog_monitor", opt_int, {&smtp_backlog_monitor} },
{ "smtp_banner", opt_stringptr, {&smtp_banner} },
{ "smtp_check_spool_space", opt_bool, {&smtp_check_spool_space} },
{ "smtp_connect_backlog", opt_int, {&smtp_connect_backlog} },
#endif
#ifdef SUPPORT_SPF
{ "spf_guess", opt_stringptr, {&spf_guess} },
+ { "spf_smtp_comment_template",opt_stringptr, {&spf_smtp_comment_template} },
#endif
{ "split_spool_directory", opt_bool, {&split_spool_directory} },
{ "spool_directory", opt_stringptr, {&spool_directory} },
{ "spool_wireformat", opt_bool, {&spool_wireformat} },
#ifdef LOOKUP_SQLITE
+ { "sqlite_dbfile", opt_stringptr, {&sqlite_dbfile} },
{ "sqlite_lock_timeout", opt_int, {&sqlite_lock_timeout} },
#endif
-#ifdef EXPERIMENTAL_SRS
+#ifdef EXPERIMENTAL_SRS_ALT
{ "srs_config", opt_stringptr, {&srs_config} },
{ "srs_hashlength", opt_int, {&srs_hashlength} },
{ "srs_hashmin", opt_int, {&srs_hashmin} },
{ "tls_privatekey", opt_stringptr, {&tls_privatekey} },
{ "tls_remember_esmtp", opt_bool, {&tls_remember_esmtp} },
{ "tls_require_ciphers", opt_stringptr, {&tls_require_ciphers} },
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
{ "tls_resumption_hosts", opt_stringptr, {&tls_resumption_hosts} },
# endif
{ "tls_try_verify_hosts", opt_stringptr, {&tls_try_verify_hosts} },
void
options_auths(void)
{
-uschar buf[64];
+uschar buf[EXIM_DRIVERNAME_MAX];
options_from_list(optionlist_auths, optionlist_auths_size, US"AUTHENTICATORS", NULL);
void
options_logging(void)
{
-uschar buf[64];
+uschar buf[EXIM_DRIVERNAME_MAX];
for (bit_table * bp = log_options; bp < log_options + log_options_count; bp++)
{
BOOL
macro_read_assignment(uschar *s)
{
-uschar name[64];
+uschar name[EXIM_DRIVERNAME_MAX];
int namelen = 0;
BOOL redef = FALSE;
macro_item *m;
}
name[namelen] = 0;
-while (isspace(*s)) s++;
+Uskip_whitespace(&s);
if (*s++ != '=')
{
log_write(0, LOG_PANIC|LOG_CONFIG_IN, "malformed macro definition");
redef = TRUE;
s++;
}
-while (isspace(*s)) s++;
+Uskip_whitespace(&s);
/* If an existing macro of the same name was defined on the command line, we
just skip this definition. It's an error to attempt to redefine a macro without
/* Find the true start of the physical line - leading spaces are always
ignored. */
-while (isspace(*ss)) ss++;
+Uskip_whitespace(&ss);
/* Process the physical line for macros. If this is the start of the logical
line, skip over initial text at the start of the line if it starts with an
if (len == 0 && isupper(*s))
{
while (isalnum(*s) || *s == '_') s++;
- while (isspace(*s)) s++;
- if (*s != '=') s = ss; /* Not a macro definition */
+ if (Uskip_whitespace(&s) != '=') s = ss; /* Not a macro definition */
}
/* Skip leading chars which cannot start a macro name, to avoid multiple
/* An empty macro replacement at the start of a line could mean that ss no
longer points to the first non-blank character. */
-while (isspace(*ss)) ss++;
+Uskip_whitespace(&ss);
return ss;
}
struct stat statbuf;
ss += 9 + include_if_exists;
- while (isspace(*ss)) ss++;
+ Uskip_whitespace(&ss);
t = ss + Ustrlen(ss);
while (t > ss && isspace(t[-1])) t--;
if (*ss == '\"' && t[-1] == '\"')
if (strncmpic(s, US"begin ", 6) == 0)
{
s += 6;
- while (isspace(*s)) s++;
+ Uskip_whitespace(&s);
if (big_buffer + len - s > sizeof(next_section) - 2)
s[sizeof(next_section) - 2] = 0;
Ustrcpy(next_section, s);
readconf_readname(uschar *name, int len, uschar *s)
{
int p = 0;
-while (isspace(*s)) s++;
-if (isalpha(*s))
- {
+BOOL broken = FALSE;
+
+if (isalpha(Uskip_whitespace(&s)))
while (isalnum(*s) || *s == '_')
{
if (p < len-1) name[p++] = *s;
+ else {
+ broken = TRUE;
+ break;
+ }
s++;
}
- }
+
name[p] = 0;
-while (isspace(*s)) s++;
+if (broken) {
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
+ "exim item name too long (>%d), unable to use \"%s\" (truncated)",
+ len, name);
+}
+Uskip_whitespace(&s);
return s;
}
*/
static optionlist *
-find_option(uschar *name, optionlist *ol, int last)
+find_option(const uschar *name, optionlist *ol, int last)
{
int first = 0;
while (last > first)
*/
static BOOL *
-get_set_flag(uschar *name, optionlist *oltop, int last, void *data_block)
+get_set_flag(const uschar *name, optionlist *oltop, int last, void *data_block)
{
optionlist *ol;
-uschar name2[64];
+uschar name2[EXIM_DRIVERNAME_MAX];
sprintf(CS name2, "*set_%.50s", name);
if (!(ol = find_option(name2, oltop, last)))
log_write(0, LOG_MAIN|LOG_PANIC_DIE,
next->next = NULL;
next->key = string_dequote(&p);
-while (isspace(*p)) p++;
-if (*p == 0)
+Uskip_whitespace(&p);
+if (!*p)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"missing rewrite replacement string");
next->flags = 0;
next->replacement = string_dequote(&p);
-while (*p != 0) switch (*p++)
+while (*p) switch (*p++)
{
case ' ': case '\t': break;
{
if (flags & opt_fn_print_label) printf("%s = ", name);
printf("%s\n", smtp_receive_timeout_s
- ? string_printing2(smtp_receive_timeout_s, FALSE)
+ ? string_printing2(smtp_receive_timeout_s, SP_TAB)
: readconf_printtime(smtp_receive_timeout));
}
else if (*str == '$')
uschar *sptr;
uschar *s = buffer;
uschar **str_target;
-uschar name[64];
-uschar name2[64];
+uschar name[EXIM_DRIVERNAME_MAX];
+uschar name2[EXIM_DRIVERNAME_MAX];
/* There may be leading spaces; thereafter, we expect an option name starting
with a letter. */
flagptr = (int *)ol3->v.value;
}
+ /* This will trap if sptr is tainted. Not sure if that can happen */
while ((p = string_nextinlist(CUSS &sptr, &sep, big_buffer, BIG_BUFFER_SIZE)))
{
rewrite_rule *next = readconf_one_rewrite(p, flagptr, FALSE);
while (count-- > 1)
{
int sep = 0;
+ /* If p is tainted we trap. Not sure that can happen */
(void)string_nextinlist(&p, &sep, big_buffer, BIG_BUFFER_SIZE);
if (!route_finduser(big_buffer, NULL, &uid))
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "user %s was not found",
while (count-- > 1)
{
int sep = 0;
+ /* If p is tainted we trap. Not sure that can happen */
(void)string_nextinlist(&p, &sep, big_buffer, BIG_BUFFER_SIZE);
if (!route_findgroup(big_buffer, &gid))
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "group %s was not found",
case opt_bool_set:
if (*s != 0)
{
- s = readconf_readname(name2, 64, s);
+ s = readconf_readname(name2, EXIM_DRIVERNAME_MAX, s);
if (strcmpic(name2, US"true") == 0 || strcmpic(name2, US"yes") == 0)
boolvalue = TRUE;
else if (strcmpic(name2, US"false") == 0 || strcmpic(name2, US"no") == 0)
*/
static BOOL
-print_ol(optionlist *ol, uschar *name, void *options_block,
+print_ol(optionlist *ol, const uschar *name, void *options_block,
optionlist *oltop, int last, BOOL no_labels)
{
struct passwd *pw;
uid_t *uidlist;
gid_t *gidlist;
uschar *s;
-uschar name2[64];
+uschar name2[EXIM_DRIVERNAME_MAX];
if (!ol)
{
case opt_rewrite: /* Show the text value */
s = *(USS value);
if (!no_labels) printf("%s = ", name);
- printf("%s\n", s ? string_printing2(s, FALSE) : US"");
+ printf("%s\n", s ? string_printing2(s, SP_TAB) : US"");
break;
case opt_int:
*/
BOOL
-readconf_print(uschar *name, uschar *type, BOOL no_labels)
+readconf_print(const uschar *name, uschar *type, BOOL no_labels)
{
BOOL names_only = FALSE;
optionlist *ol2 = NULL;
else
return print_ol(find_option(name,
- optionlist_config, nelem(optionlist_config)),
+ optionlist_config, nelem(optionlist_config)),
name, NULL, optionlist_config, nelem(optionlist_config), no_labels);
}
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "too many named %ss (max is %d)\n",
tname, max);
-while (isspace(*s)) s++;
+Uskip_whitespace(&s);
ss = s;
while (isalnum(*s) || *s == '_') s++;
t = store_get(sizeof(tree_node) + s-ss, is_tainted(ss));
Ustrncpy(t->name, ss, s-ss);
t->name[s-ss] = 0;
-while (isspace(*s)) s++;
+Uskip_whitespace(&s);
if (!tree_insertnode(anchorp, t))
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
if (*s++ != '=') log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"missing '=' after \"%s\"", t->name);
-while (isspace(*s)) s++;
+Uskip_whitespace(&s);
nb->string = read_string(s, t->name);
nb->cache_data = NULL;
/* Loop through the possible file names */
+/* Should never be a tainted list */
while((filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
{
}
else
{
- if (filename == NULL)
+ if (!filename)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "non-existent configuration file(s): "
"%s", config_main_filelist);
else
- log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", string_open_failed(errno,
- "configuration file %s", filename));
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
+ string_open_failed("configuration file %s", filename));
}
/* Now, once we found and opened our configuration file, we change the directory
if (isupper(*s))
{
- if (!macro_read_assignment(s)) exim_exit(EXIT_FAILURE, US"");
+ if (!macro_read_assignment(s)) exim_exit(EXIT_FAILURE);
continue;
}
canonize it. Some people like upper case letters in their host names, so we
don't force the case. */
-if (primary_hostname == NULL)
+if (!primary_hostname)
{
- const uschar *hostname;
+ const uschar * hostname;
struct utsname uts;
+
if (uname(&uts) < 0)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "uname() failed to yield host name");
hostname = US uts.nodename;
int af = AF_INET;
struct hostent *hostdata;
- #if HAVE_IPV6
- if (!disable_ipv6 && (dns_ipv4_lookup == NULL ||
- match_isinlist(hostname, CUSS &dns_ipv4_lookup, 0, NULL, NULL,
+#if HAVE_IPV6
+ if ( !disable_ipv6
+ && ( !dns_ipv4_lookup
+ || match_isinlist(hostname, CUSS &dns_ipv4_lookup, 0, NULL, NULL,
MCL_DOMAIN, TRUE, NULL) != OK))
af = AF_INET6;
- #else
- af = AF_INET;
- #endif
+#endif
for (;;)
{
- #if HAVE_IPV6
- #if HAVE_GETIPNODEBYNAME
+#if HAVE_IPV6
+# if HAVE_GETIPNODEBYNAME
int error_num;
hostdata = getipnodebyname(CS hostname, af, 0, &error_num);
#else
hostdata = gethostbyname2(CS hostname, af);
- #endif
- #else
+# endif
+#else
hostdata = gethostbyname(CS hostname);
- #endif
+#endif
- if (hostdata != NULL)
- {
- hostname = US hostdata->h_name;
- break;
- }
+ if (hostdata)
+ { hostname = US hostdata->h_name; break; }
if (af == AF_INET) break;
af = AF_INET;
"\"%s\": %s", log_file_path, expand_string_message);
ss = s;
+ /* should never be a tainted list */
while ((sss = string_nextinlist(&ss, &sep, big_buffer, big_buffer_size)))
{
uschar *t;
while ((buffer = get_config_line()))
{
- uschar name[64];
+ uschar name[EXIM_DRIVERNAME_MAX];
uschar *s;
/* Read the first name on the line and test for the start of a new driver. A
(d->info->init)(d);
d = NULL;
}
- if (!macro_read_assignment(buffer)) exim_exit(EXIT_FAILURE, US"");
+ if (!macro_read_assignment(buffer)) exim_exit(EXIT_FAILURE);
continue;
}
/* Check nothing more on this line, then do the next loop iteration. */
- while (isspace(*s)) s++;
+ Uskip_whitespace(&s);
if (*s) extra_chars_error(s, US"driver name ", name, US"");
continue;
}
if (*p++ != ',') log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "comma expected");
-while (isspace(*p)) p++;
+Uskip_whitespace(&p);
pp = p;
while (isalnum(*p) || (type == 1 && *p == '.')) p++;
rchain = &(next->rules);
next->pattern = string_dequote(&p);
- while (isspace(*p)) p++;
+ Uskip_whitespace(&p);
pp = p;
while (mac_isgraph(*p)) p++;
if (p - pp <= 0) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
fudge. Anything that is not a retry rule starting "F," or "G," is treated as
an address list. */
- while (isspace(*p)) p++;
+ Uskip_whitespace(&p);
if (Ustrncmp(p, "senders", 7) == 0)
{
p += 7;
- while (isspace(*p)) p++;
+ Uskip_whitespace(&p);
if (*p++ != '=') log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"\"=\" expected after \"senders\" in retry rule");
- while (isspace(*p)) p++;
+ Uskip_whitespace(&p);
next->senders = string_dequote(&p);
}
/* Now the retry rules. Keep the maximum timeout encountered. */
- while (isspace(*p)) p++;
+ Uskip_whitespace(&p);
- while (*p != 0)
+ while (*p)
{
retry_rule *rule = store_get(sizeof(retry_rule), FALSE);
*rchain = rule;
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"bad parameters for retry rule");
- while (isspace(*p)) p++;
- if (*p == ';')
+ if (Uskip_whitespace(&p) == ';')
{
p++;
- while (isspace(*p)) p++;
+ Uskip_whitespace(&p);
}
- else if (*p != 0)
+ else if (*p)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "semicolon expected");
}
}
while(acl_line)
{
- uschar name[64];
+ uschar name[EXIM_DRIVERNAME_MAX];
tree_node *node;
uschar *error;
p = readconf_readname(name, sizeof(name), acl_line);
if (isupper(*name) && *p == '=')
{
- if (!macro_read_assignment(acl_line)) exim_exit(EXIT_FAILURE, US"");
+ if (!macro_read_assignment(acl_line)) exim_exit(EXIT_FAILURE);
acl_line = get_config_line();
continue;
}