*************************************************/
/* 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
{ "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} },
#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} },
}
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))
- {
+
+if (isalpha(Uskip_whitespace(&s)))
while (isalnum(*s) || *s == '_')
{
if (p < len-1) name[p++] = *s;
s++;
}
- }
+
name[p] = 0;
-while (isspace(*s)) s++;
+Uskip_whitespace(&s);
return s;
}
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 == '$')
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_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:
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;
(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");
}
}
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;
}