X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/46d2a5e6f6e7709d172903b13945d23fc0a2c888..a1108b5118d32e969c5fe91b2110944f7483a7cb:/src/src/readconf.c diff --git a/src/src/readconf.c b/src/src/readconf.c index 1243e9082..e8e310beb 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -3,6 +3,7 @@ *************************************************/ /* 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 @@ -119,6 +120,7 @@ static optionlist optionlist_config[] = { #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 @@ -198,6 +200,9 @@ static optionlist optionlist_config[] = { { "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} }, @@ -257,10 +262,13 @@ static optionlist optionlist_config[] = { { "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} }, @@ -295,7 +303,7 @@ static optionlist optionlist_config[] = { { "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} }, @@ -324,14 +332,16 @@ static optionlist optionlist_config[] = { #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} }, @@ -375,7 +385,7 @@ static optionlist optionlist_config[] = { { "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} }, @@ -691,7 +701,7 @@ while (isalnum(*s) || *s == '_') } name[namelen] = 0; -while (isspace(*s)) s++; +Uskip_whitespace(&s); if (*s++ != '=') { log_write(0, LOG_PANIC|LOG_CONFIG_IN, "malformed macro definition"); @@ -703,7 +713,7 @@ if (*s == '=') 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 @@ -795,7 +805,7 @@ uschar * s; /* 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 @@ -807,8 +817,7 @@ s = ss; 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 @@ -871,7 +880,7 @@ if (*s) for (macro_item * m = *s == '_' ? macros : macros_user; m; m = m->next) /* 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; } @@ -1044,7 +1053,7 @@ for (;;) 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] == '\"') @@ -1135,7 +1144,7 @@ if (config_lines) 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); @@ -1169,17 +1178,16 @@ uschar * 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; } @@ -1415,15 +1423,15 @@ rewrite_rule *next = store_get(sizeof(rewrite_rule), FALSE); 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; @@ -1544,7 +1552,7 @@ if (flags & opt_fn_print) { 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 == '$') @@ -1843,6 +1851,7 @@ switch (type) 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); @@ -1987,6 +1996,7 @@ switch (type) 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", @@ -2028,6 +2038,7 @@ switch (type) 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", @@ -2461,7 +2472,7 @@ switch(ol->type & opt_mask) 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: @@ -3000,13 +3011,13 @@ if (*numberp >= max) 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, @@ -3019,7 +3030,7 @@ nb->hide = hide; 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; @@ -3110,6 +3121,7 @@ const uschar *list = config_main_filelist; /* Loop through the possible file names */ +/* Should never be a tainted list */ while((filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))) { @@ -3212,12 +3224,12 @@ if (config_file) } 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 @@ -3341,10 +3353,11 @@ but if that yields an unqualified value, make a FQDN by using gethostbyname to 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; @@ -3354,33 +3367,29 @@ if (primary_hostname == NULL) 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; @@ -3423,6 +3432,7 @@ if (*log_file_path) "\"%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; @@ -3762,7 +3772,7 @@ while ((buffer = get_config_line())) /* 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; } @@ -4015,7 +4025,7 @@ const uschar *pp; 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++; @@ -4056,7 +4066,7 @@ while ((p = get_config_line())) 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, @@ -4073,22 +4083,22 @@ while ((p = get_config_line())) 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; @@ -4121,13 +4131,12 @@ while ((p = get_config_line())) 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"); } }