* Exim - an Internet mail transport agent *
*************************************************/
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Functions for reading the configuration file, and for displaying
overall configuration values. Thanks to Brian Candler for the original
# include "macro_predef.h"
#endif
+#define READCONF_DEBUG if (FALSE) /* Change to TRUE to enable */
+
+
static uschar * syslog_facility_str;
-static void fn_smtp_receive_timeout(const uschar *, const uschar *);
+static void fn_smtp_receive_timeout(const uschar *, const uschar *, unsigned);
/*************************************************
* Main configuration options *
must be in alphabetic order because it is searched by binary chop. */
static optionlist optionlist_config[] = {
- { "*set_exim_group", opt_bool|opt_hidden, &exim_gid_set },
- { "*set_exim_user", opt_bool|opt_hidden, &exim_uid_set },
- { "*set_system_filter_group", opt_bool|opt_hidden, &system_filter_gid_set },
- { "*set_system_filter_user", opt_bool|opt_hidden, &system_filter_uid_set },
- { "accept_8bitmime", opt_bool, &accept_8bitmime },
- { "acl_not_smtp", opt_stringptr, &acl_not_smtp },
+ { "*set_exim_group", opt_bool|opt_hidden, {&exim_gid_set} },
+ { "*set_exim_user", opt_bool|opt_hidden, {&exim_uid_set} },
+ { "*set_system_filter_group", opt_bool|opt_hidden, {&system_filter_gid_set} },
+ { "*set_system_filter_user", opt_bool|opt_hidden, {&system_filter_uid_set} },
+ { "accept_8bitmime", opt_bool, {&accept_8bitmime} },
+ { "acl_not_smtp", opt_stringptr, {&acl_not_smtp} },
#ifdef WITH_CONTENT_SCAN
- { "acl_not_smtp_mime", opt_stringptr, &acl_not_smtp_mime },
+ { "acl_not_smtp_mime", opt_stringptr, {&acl_not_smtp_mime} },
#endif
- { "acl_not_smtp_start", opt_stringptr, &acl_not_smtp_start },
- { "acl_smtp_auth", opt_stringptr, &acl_smtp_auth },
- { "acl_smtp_connect", opt_stringptr, &acl_smtp_connect },
- { "acl_smtp_data", opt_stringptr, &acl_smtp_data },
+ { "acl_not_smtp_start", opt_stringptr, {&acl_not_smtp_start} },
+ { "acl_smtp_auth", opt_stringptr, {&acl_smtp_auth} },
+ { "acl_smtp_connect", opt_stringptr, {&acl_smtp_connect} },
+ { "acl_smtp_data", opt_stringptr, {&acl_smtp_data} },
#ifndef DISABLE_PRDR
- { "acl_smtp_data_prdr", opt_stringptr, &acl_smtp_data_prdr },
+ { "acl_smtp_data_prdr", opt_stringptr, {&acl_smtp_data_prdr} },
#endif
#ifndef DISABLE_DKIM
- { "acl_smtp_dkim", opt_stringptr, &acl_smtp_dkim },
+ { "acl_smtp_dkim", opt_stringptr, {&acl_smtp_dkim} },
#endif
- { "acl_smtp_etrn", opt_stringptr, &acl_smtp_etrn },
- { "acl_smtp_expn", opt_stringptr, &acl_smtp_expn },
- { "acl_smtp_helo", opt_stringptr, &acl_smtp_helo },
- { "acl_smtp_mail", opt_stringptr, &acl_smtp_mail },
- { "acl_smtp_mailauth", opt_stringptr, &acl_smtp_mailauth },
+ { "acl_smtp_etrn", opt_stringptr, {&acl_smtp_etrn} },
+ { "acl_smtp_expn", opt_stringptr, {&acl_smtp_expn} },
+ { "acl_smtp_helo", opt_stringptr, {&acl_smtp_helo} },
+ { "acl_smtp_mail", opt_stringptr, {&acl_smtp_mail} },
+ { "acl_smtp_mailauth", opt_stringptr, {&acl_smtp_mailauth} },
#ifdef WITH_CONTENT_SCAN
- { "acl_smtp_mime", opt_stringptr, &acl_smtp_mime },
+ { "acl_smtp_mime", opt_stringptr, {&acl_smtp_mime} },
#endif
- { "acl_smtp_notquit", opt_stringptr, &acl_smtp_notquit },
- { "acl_smtp_predata", opt_stringptr, &acl_smtp_predata },
- { "acl_smtp_quit", opt_stringptr, &acl_smtp_quit },
- { "acl_smtp_rcpt", opt_stringptr, &acl_smtp_rcpt },
-#ifdef SUPPORT_TLS
- { "acl_smtp_starttls", opt_stringptr, &acl_smtp_starttls },
+ { "acl_smtp_notquit", opt_stringptr, {&acl_smtp_notquit} },
+ { "acl_smtp_predata", opt_stringptr, {&acl_smtp_predata} },
+ { "acl_smtp_quit", opt_stringptr, {&acl_smtp_quit} },
+ { "acl_smtp_rcpt", opt_stringptr, {&acl_smtp_rcpt} },
+#ifndef DISABLE_TLS
+ { "acl_smtp_starttls", opt_stringptr, {&acl_smtp_starttls} },
#endif
- { "acl_smtp_vrfy", opt_stringptr, &acl_smtp_vrfy },
- { "add_environment", opt_stringptr, &add_environment },
- { "admin_groups", opt_gidlist, &admin_groups },
- { "allow_domain_literals", opt_bool, &allow_domain_literals },
- { "allow_mx_to_ip", opt_bool, &allow_mx_to_ip },
- { "allow_utf8_domains", opt_bool, &allow_utf8_domains },
- { "auth_advertise_hosts", opt_stringptr, &auth_advertise_hosts },
- { "auto_thaw", opt_time, &auto_thaw },
+ { "acl_smtp_vrfy", opt_stringptr, {&acl_smtp_vrfy} },
+ { "add_environment", opt_stringptr, {&add_environment} },
+ { "admin_groups", opt_gidlist, {&admin_groups} },
+ { "allow_domain_literals", opt_bool, {&allow_domain_literals} },
+ { "allow_mx_to_ip", opt_bool, {&allow_mx_to_ip} },
+ { "allow_utf8_domains", opt_bool, {&allow_utf8_domains} },
+ { "auth_advertise_hosts", opt_stringptr, {&auth_advertise_hosts} },
+ { "auto_thaw", opt_time, {&auto_thaw} },
#ifdef WITH_CONTENT_SCAN
- { "av_scanner", opt_stringptr, &av_scanner },
+ { "av_scanner", opt_stringptr, {&av_scanner} },
#endif
- { "bi_command", opt_stringptr, &bi_command },
+ { "bi_command", opt_stringptr, {&bi_command} },
#ifdef EXPERIMENTAL_BRIGHTMAIL
- { "bmi_config_file", opt_stringptr, &bmi_config_file },
+ { "bmi_config_file", opt_stringptr, {&bmi_config_file} },
#endif
- { "bounce_message_file", opt_stringptr, &bounce_message_file },
- { "bounce_message_text", opt_stringptr, &bounce_message_text },
- { "bounce_return_body", opt_bool, &bounce_return_body },
- { "bounce_return_linesize_limit", opt_mkint, &bounce_return_linesize_limit },
- { "bounce_return_message", opt_bool, &bounce_return_message },
- { "bounce_return_size_limit", opt_mkint, &bounce_return_size_limit },
- { "bounce_sender_authentication",opt_stringptr,&bounce_sender_authentication },
- { "callout_domain_negative_expire", opt_time, &callout_cache_domain_negative_expire },
- { "callout_domain_positive_expire", opt_time, &callout_cache_domain_positive_expire },
- { "callout_negative_expire", opt_time, &callout_cache_negative_expire },
- { "callout_positive_expire", opt_time, &callout_cache_positive_expire },
- { "callout_random_local_part",opt_stringptr, &callout_random_local_part },
- { "check_log_inodes", opt_int, &check_log_inodes },
- { "check_log_space", opt_Kint, &check_log_space },
- { "check_rfc2047_length", opt_bool, &check_rfc2047_length },
- { "check_spool_inodes", opt_int, &check_spool_inodes },
- { "check_spool_space", opt_Kint, &check_spool_space },
- { "chunking_advertise_hosts", opt_stringptr, &chunking_advertise_hosts },
- { "commandline_checks_require_admin", opt_bool,&commandline_checks_require_admin },
- { "daemon_smtp_port", opt_stringptr|opt_hidden, &daemon_smtp_port },
- { "daemon_smtp_ports", opt_stringptr, &daemon_smtp_port },
- { "daemon_startup_retries", opt_int, &daemon_startup_retries },
- { "daemon_startup_sleep", opt_time, &daemon_startup_sleep },
+ { "bounce_message_file", opt_stringptr, {&bounce_message_file} },
+ { "bounce_message_text", opt_stringptr, {&bounce_message_text} },
+ { "bounce_return_body", opt_bool, {&bounce_return_body} },
+ { "bounce_return_linesize_limit", opt_mkint, {&bounce_return_linesize_limit} },
+ { "bounce_return_message", opt_bool, {&bounce_return_message} },
+ { "bounce_return_size_limit", opt_mkint, {&bounce_return_size_limit} },
+ { "bounce_sender_authentication",opt_stringptr,{&bounce_sender_authentication} },
+ { "callout_domain_negative_expire", opt_time, {&callout_cache_domain_negative_expire} },
+ { "callout_domain_positive_expire", opt_time, {&callout_cache_domain_positive_expire} },
+ { "callout_negative_expire", opt_time, {&callout_cache_negative_expire} },
+ { "callout_positive_expire", opt_time, {&callout_cache_positive_expire} },
+ { "callout_random_local_part",opt_stringptr, {&callout_random_local_part} },
+ { "check_log_inodes", opt_int, {&check_log_inodes} },
+ { "check_log_space", opt_Kint, {&check_log_space} },
+ { "check_rfc2047_length", opt_bool, {&check_rfc2047_length} },
+ { "check_spool_inodes", opt_int, {&check_spool_inodes} },
+ { "check_spool_space", opt_Kint, {&check_spool_space} },
+ { "chunking_advertise_hosts", opt_stringptr, {&chunking_advertise_hosts} },
+ { "commandline_checks_require_admin", opt_bool,{&commandline_checks_require_admin} },
+ { "daemon_smtp_port", opt_stringptr|opt_hidden, {&daemon_smtp_port} },
+ { "daemon_smtp_ports", opt_stringptr, {&daemon_smtp_port} },
+ { "daemon_startup_retries", opt_int, {&daemon_startup_retries} },
+ { "daemon_startup_sleep", opt_time, {&daemon_startup_sleep} },
#ifdef EXPERIMENTAL_DCC
- { "dcc_direct_add_header", opt_bool, &dcc_direct_add_header },
- { "dccifd_address", opt_stringptr, &dccifd_address },
- { "dccifd_options", opt_stringptr, &dccifd_options },
+ { "dcc_direct_add_header", opt_bool, {&dcc_direct_add_header} },
+ { "dccifd_address", opt_stringptr, {&dccifd_address} },
+ { "dccifd_options", opt_stringptr, {&dccifd_options} },
#endif
- { "debug_store", opt_bool, &debug_store },
- { "delay_warning", opt_timelist, &delay_warning },
- { "delay_warning_condition", opt_stringptr, &delay_warning_condition },
- { "deliver_drop_privilege", opt_bool, &deliver_drop_privilege },
- { "deliver_queue_load_max", opt_fixed, &deliver_queue_load_max },
- { "delivery_date_remove", opt_bool, &delivery_date_remove },
+ { "debug_store", opt_bool, {&debug_store} },
+ { "delay_warning", opt_timelist, {&delay_warning} },
+ { "delay_warning_condition", opt_stringptr, {&delay_warning_condition} },
+ { "deliver_drop_privilege", opt_bool, {&deliver_drop_privilege} },
+ { "deliver_queue_load_max", opt_fixed, {&deliver_queue_load_max} },
+ { "delivery_date_remove", opt_bool, {&delivery_date_remove} },
#ifdef ENABLE_DISABLE_FSYNC
- { "disable_fsync", opt_bool, &disable_fsync },
+ { "disable_fsync", opt_bool, {&disable_fsync} },
#endif
- { "disable_ipv6", opt_bool, &disable_ipv6 },
+ { "disable_ipv6", opt_bool, {&disable_ipv6} },
#ifndef DISABLE_DKIM
- { "dkim_verify_signers", opt_stringptr, &dkim_verify_signers },
+ { "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 EXPERIMENTAL_DMARC
- { "dmarc_forensic_sender", opt_stringptr, &dmarc_forensic_sender },
- { "dmarc_history_file", opt_stringptr, &dmarc_history_file },
- { "dmarc_tld_file", opt_stringptr, &dmarc_tld_file },
+#ifdef SUPPORT_DMARC
+ { "dmarc_forensic_sender", opt_stringptr, {&dmarc_forensic_sender} },
+ { "dmarc_history_file", opt_stringptr, {&dmarc_history_file} },
+ { "dmarc_tld_file", opt_stringptr, {&dmarc_tld_file} },
#endif
- { "dns_again_means_nonexist", opt_stringptr, &dns_again_means_nonexist },
- { "dns_check_names_pattern", opt_stringptr, &check_dns_names_pattern },
- { "dns_csa_search_limit", opt_int, &dns_csa_search_limit },
- { "dns_csa_use_reverse", opt_bool, &dns_csa_use_reverse },
- { "dns_dnssec_ok", opt_int, &dns_dnssec_ok },
- { "dns_ipv4_lookup", opt_stringptr, &dns_ipv4_lookup },
- { "dns_retrans", opt_time, &dns_retrans },
- { "dns_retry", opt_int, &dns_retry },
- { "dns_trust_aa", opt_stringptr, &dns_trust_aa },
- { "dns_use_edns0", opt_int, &dns_use_edns0 },
+ { "dns_again_means_nonexist", opt_stringptr, {&dns_again_means_nonexist} },
+ { "dns_check_names_pattern", opt_stringptr, {&check_dns_names_pattern} },
+ { "dns_cname_loops", opt_int, {&dns_cname_loops} },
+ { "dns_csa_search_limit", opt_int, {&dns_csa_search_limit} },
+ { "dns_csa_use_reverse", opt_bool, {&dns_csa_use_reverse} },
+ { "dns_dnssec_ok", opt_int, {&dns_dnssec_ok} },
+ { "dns_ipv4_lookup", opt_stringptr, {&dns_ipv4_lookup} },
+ { "dns_retrans", opt_time, {&dns_retrans} },
+ { "dns_retry", opt_int, {&dns_retry} },
+ { "dns_trust_aa", opt_stringptr, {&dns_trust_aa} },
+ { "dns_use_edns0", opt_int, {&dns_use_edns0} },
/* This option is now a no-op, retained for compatibility */
- { "drop_cr", opt_bool, &drop_cr },
+ { "drop_cr", opt_bool, {&drop_cr} },
/*********************************************************/
- { "dsn_advertise_hosts", opt_stringptr, &dsn_advertise_hosts },
- { "dsn_from", opt_stringptr, &dsn_from },
- { "envelope_to_remove", opt_bool, &envelope_to_remove },
- { "errors_copy", opt_stringptr, &errors_copy },
- { "errors_reply_to", opt_stringptr, &errors_reply_to },
+ { "dsn_advertise_hosts", opt_stringptr, {&dsn_advertise_hosts} },
+ { "dsn_from", opt_stringptr, {&dsn_from} },
+ { "envelope_to_remove", opt_bool, {&envelope_to_remove} },
+ { "errors_copy", opt_stringptr, {&errors_copy} },
+ { "errors_reply_to", opt_stringptr, {&errors_reply_to} },
#ifndef DISABLE_EVENT
- { "event_action", opt_stringptr, &event_action },
+ { "event_action", opt_stringptr, {&event_action} },
#endif
- { "exim_group", opt_gid, &exim_gid },
- { "exim_path", opt_stringptr, &exim_path },
- { "exim_user", opt_uid, &exim_uid },
- { "extra_local_interfaces", opt_stringptr, &extra_local_interfaces },
- { "extract_addresses_remove_arguments", opt_bool, &extract_addresses_remove_arguments },
- { "finduser_retries", opt_int, &finduser_retries },
- { "freeze_tell", opt_stringptr, &freeze_tell },
- { "gecos_name", opt_stringptr, &gecos_name },
- { "gecos_pattern", opt_stringptr, &gecos_pattern },
-#ifdef SUPPORT_TLS
- { "gnutls_allow_auto_pkcs11", opt_bool, &gnutls_allow_auto_pkcs11 },
- { "gnutls_compat_mode", opt_bool, &gnutls_compat_mode },
+ { "exim_group", opt_gid, {&exim_gid} },
+ { "exim_path", opt_stringptr, {&exim_path} },
+ { "exim_user", opt_uid, {&exim_uid} },
+ { "exim_version", opt_stringptr, {&version_string} },
+ { "extra_local_interfaces", opt_stringptr, {&extra_local_interfaces} },
+ { "extract_addresses_remove_arguments", opt_bool, {&extract_addresses_remove_arguments} },
+ { "finduser_retries", opt_int, {&finduser_retries} },
+ { "freeze_tell", opt_stringptr, {&freeze_tell} },
+ { "gecos_name", opt_stringptr, {&gecos_name} },
+ { "gecos_pattern", opt_stringptr, {&gecos_pattern} },
+#ifndef DISABLE_TLS
+ { "gnutls_allow_auto_pkcs11", opt_bool, {&gnutls_allow_auto_pkcs11} },
+ { "gnutls_compat_mode", opt_bool, {&gnutls_compat_mode} },
#endif
- { "header_line_maxsize", opt_int, &header_line_maxsize },
- { "header_maxsize", opt_int, &header_maxsize },
- { "headers_charset", opt_stringptr, &headers_charset },
- { "helo_accept_junk_hosts", opt_stringptr, &helo_accept_junk_hosts },
- { "helo_allow_chars", opt_stringptr, &helo_allow_chars },
- { "helo_lookup_domains", opt_stringptr, &helo_lookup_domains },
- { "helo_try_verify_hosts", opt_stringptr, &helo_try_verify_hosts },
- { "helo_verify_hosts", opt_stringptr, &helo_verify_hosts },
- { "hold_domains", opt_stringptr, &hold_domains },
- { "host_lookup", opt_stringptr, &host_lookup },
- { "host_lookup_order", opt_stringptr, &host_lookup_order },
- { "host_reject_connection", opt_stringptr, &host_reject_connection },
- { "hosts_connection_nolog", opt_stringptr, &hosts_connection_nolog },
+ { "header_line_maxsize", opt_int, {&header_line_maxsize} },
+ { "header_maxsize", opt_int, {&header_maxsize} },
+ { "headers_charset", opt_stringptr, {&headers_charset} },
+ { "helo_accept_junk_hosts", opt_stringptr, {&helo_accept_junk_hosts} },
+ { "helo_allow_chars", opt_stringptr, {&helo_allow_chars} },
+ { "helo_lookup_domains", opt_stringptr, {&helo_lookup_domains} },
+ { "helo_try_verify_hosts", opt_stringptr, {&helo_try_verify_hosts} },
+ { "helo_verify_hosts", opt_stringptr, {&helo_verify_hosts} },
+ { "hold_domains", opt_stringptr, {&hold_domains} },
+ { "host_lookup", opt_stringptr, {&host_lookup} },
+ { "host_lookup_order", opt_stringptr, {&host_lookup_order} },
+ { "host_reject_connection", opt_stringptr, {&host_reject_connection} },
+ { "hosts_connection_nolog", opt_stringptr, {&hosts_connection_nolog} },
#ifdef SUPPORT_PROXY
- { "hosts_proxy", opt_stringptr, &hosts_proxy },
+ { "hosts_proxy", opt_stringptr, {&hosts_proxy} },
+#endif
+#ifndef DISABLE_TLS
+ { "hosts_require_alpn", opt_stringptr, {&hosts_require_alpn} },
+#endif
+ { "hosts_require_helo", opt_stringptr, {&hosts_require_helo} },
+ { "hosts_treat_as_local", opt_stringptr, {&hosts_treat_as_local} },
+#ifdef EXPERIMENTAL_XCLIENT
+ { "hosts_xclient", opt_stringptr, {&hosts_xclient} },
#endif
- { "hosts_treat_as_local", opt_stringptr, &hosts_treat_as_local },
#ifdef LOOKUP_IBASE
- { "ibase_servers", opt_stringptr, &ibase_servers },
+ { "ibase_servers", opt_stringptr, {&ibase_servers} },
#endif
- { "ignore_bounce_errors_after", opt_time, &ignore_bounce_errors_after },
- { "ignore_fromline_hosts", opt_stringptr, &ignore_fromline_hosts },
- { "ignore_fromline_local", opt_bool, &ignore_fromline_local },
- { "keep_environment", opt_stringptr, &keep_environment },
- { "keep_malformed", opt_time, &keep_malformed },
+ { "ignore_bounce_errors_after", opt_time, {&ignore_bounce_errors_after} },
+ { "ignore_fromline_hosts", opt_stringptr, {&ignore_fromline_hosts} },
+ { "ignore_fromline_local", opt_bool, {&ignore_fromline_local} },
+ { "keep_environment", opt_stringptr, {&keep_environment} },
+ { "keep_malformed", opt_time, {&keep_malformed} },
#ifdef LOOKUP_LDAP
- { "ldap_ca_cert_dir", opt_stringptr, &eldap_ca_cert_dir },
- { "ldap_ca_cert_file", opt_stringptr, &eldap_ca_cert_file },
- { "ldap_cert_file", opt_stringptr, &eldap_cert_file },
- { "ldap_cert_key", opt_stringptr, &eldap_cert_key },
- { "ldap_cipher_suite", opt_stringptr, &eldap_cipher_suite },
- { "ldap_default_servers", opt_stringptr, &eldap_default_servers },
- { "ldap_require_cert", opt_stringptr, &eldap_require_cert },
- { "ldap_start_tls", opt_bool, &eldap_start_tls },
- { "ldap_version", opt_int, &eldap_version },
+ { "ldap_ca_cert_dir", opt_stringptr, {&eldap_ca_cert_dir} },
+ { "ldap_ca_cert_file", opt_stringptr, {&eldap_ca_cert_file} },
+ { "ldap_cert_file", opt_stringptr, {&eldap_cert_file} },
+ { "ldap_cert_key", opt_stringptr, {&eldap_cert_key} },
+ { "ldap_cipher_suite", opt_stringptr, {&eldap_cipher_suite} },
+ { "ldap_default_servers", opt_stringptr, {&eldap_default_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 },
- { "local_from_suffix", opt_stringptr, &local_from_suffix },
- { "local_interfaces", opt_stringptr, &local_interfaces },
+ { "local_from_check", opt_bool, {&local_from_check} },
+ { "local_from_prefix", opt_stringptr, {&local_from_prefix} },
+ { "local_from_suffix", opt_stringptr, {&local_from_suffix} },
+ { "local_interfaces", opt_stringptr, {&local_interfaces} },
#ifdef HAVE_LOCAL_SCAN
- { "local_scan_timeout", opt_time, &local_scan_timeout },
+ { "local_scan_timeout", opt_time, {&local_scan_timeout} },
#endif
- { "local_sender_retain", opt_bool, &local_sender_retain },
- { "localhost_number", opt_stringptr, &host_number_string },
- { "log_file_path", opt_stringptr, &log_file_path },
- { "log_selector", opt_stringptr, &log_selector_string },
- { "log_timezone", opt_bool, &log_timezone },
- { "lookup_open_max", opt_int, &lookup_open_max },
- { "max_username_length", opt_int, &max_username_length },
- { "message_body_newlines", opt_bool, &message_body_newlines },
- { "message_body_visible", opt_mkint, &message_body_visible },
- { "message_id_header_domain", opt_stringptr, &message_id_domain },
- { "message_id_header_text", opt_stringptr, &message_id_text },
- { "message_logs", opt_bool, &message_logs },
- { "message_size_limit", opt_stringptr, &message_size_limit },
+ { "local_sender_retain", opt_bool, {&local_sender_retain} },
+ { "localhost_number", opt_stringptr, {&host_number_string} },
+ { "log_file_path", opt_stringptr, {&log_file_path} },
+ { "log_selector", opt_stringptr, {&log_selector_string} },
+ { "log_timezone", opt_bool, {&log_timezone} },
+ { "lookup_open_max", opt_int, {&lookup_open_max} },
+ { "max_username_length", opt_int, {&max_username_length} },
+ { "message_body_newlines", opt_bool, {&message_body_newlines} },
+ { "message_body_visible", opt_mkint, {&message_body_visible} },
+ { "message_id_header_domain", opt_stringptr, {&message_id_domain} },
+ { "message_id_header_text", opt_stringptr, {&message_id_text} },
+ { "message_logs", opt_bool, {&message_logs} },
+ { "message_size_limit", opt_stringptr, {&message_size_limit} },
#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
- { "move_frozen_messages", opt_bool, &move_frozen_messages },
+ { "move_frozen_messages", opt_bool, {&move_frozen_messages} },
#endif
- { "mua_wrapper", opt_bool, &mua_wrapper },
+ { "mua_wrapper", opt_bool, {&mua_wrapper} },
#ifdef LOOKUP_MYSQL
- { "mysql_servers", opt_stringptr, &mysql_servers },
+ { "mysql_servers", opt_stringptr, {&mysql_servers} },
#endif
- { "never_users", opt_uidlist, &never_users },
-#ifdef SUPPORT_TLS
- { "openssl_options", opt_stringptr, &openssl_options },
+ { "never_users", opt_uidlist, {&never_users} },
+ { "notifier_socket", opt_stringptr, {¬ifier_socket} },
+#ifndef DISABLE_TLS
+ { "openssl_options", opt_stringptr, {&openssl_options} },
#endif
#ifdef LOOKUP_ORACLE
- { "oracle_servers", opt_stringptr, &oracle_servers },
+ { "oracle_servers", opt_stringptr, {&oracle_servers} },
#endif
- { "percent_hack_domains", opt_stringptr, &percent_hack_domains },
+ { "panic_coredump", opt_bool, {&panic_coredump} },
+ { "percent_hack_domains", opt_stringptr, {&percent_hack_domains} },
#ifdef EXIM_PERL
- { "perl_at_start", opt_bool, &opt_perl_at_start },
- { "perl_startup", opt_stringptr, &opt_perl_startup },
- { "perl_taintmode", opt_bool, &opt_perl_taintmode },
+ { "perl_at_start", opt_bool, {&opt_perl_at_start} },
+ { "perl_startup", opt_stringptr, {&opt_perl_startup} },
+ { "perl_taintmode", opt_bool, {&opt_perl_taintmode} },
#endif
#ifdef LOOKUP_PGSQL
- { "pgsql_servers", opt_stringptr, &pgsql_servers },
+ { "pgsql_servers", opt_stringptr, {&pgsql_servers} },
+#endif
+ { "pid_file_path", opt_stringptr, {&pid_file_path} },
+ { "pipelining_advertise_hosts", opt_stringptr, {&pipelining_advertise_hosts} },
+#ifndef DISABLE_PIPE_CONNECT
+ { "pipelining_connect_advertise_hosts", opt_stringptr,
+ {&pipe_connect_advertise_hosts} },
#endif
- { "pid_file_path", opt_stringptr, &pid_file_path },
- { "pipelining_advertise_hosts", opt_stringptr, &pipelining_advertise_hosts },
#ifndef DISABLE_PRDR
- { "prdr_enable", opt_bool, &prdr_enable },
+ { "prdr_enable", opt_bool, {&prdr_enable} },
#endif
- { "preserve_message_logs", opt_bool, &preserve_message_logs },
- { "primary_hostname", opt_stringptr, &primary_hostname },
- { "print_topbitchars", opt_bool, &print_topbitchars },
- { "process_log_path", opt_stringptr, &process_log_path },
- { "prod_requires_admin", opt_bool, &prod_requires_admin },
- { "qualify_domain", opt_stringptr, &qualify_domain_sender },
- { "qualify_recipient", opt_stringptr, &qualify_domain_recipient },
- { "queue_domains", opt_stringptr, &queue_domains },
- { "queue_list_requires_admin",opt_bool, &queue_list_requires_admin },
- { "queue_only", opt_bool, &queue_only },
- { "queue_only_file", opt_stringptr, &queue_only_file },
- { "queue_only_load", opt_fixed, &queue_only_load },
- { "queue_only_load_latch", opt_bool, &queue_only_load_latch },
- { "queue_only_override", opt_bool, &queue_only_override },
- { "queue_run_in_order", opt_bool, &queue_run_in_order },
- { "queue_run_max", opt_stringptr, &queue_run_max },
- { "queue_smtp_domains", opt_stringptr, &queue_smtp_domains },
- { "receive_timeout", opt_time, &receive_timeout },
- { "received_header_text", opt_stringptr, &received_header_text },
- { "received_headers_max", opt_int, &received_headers_max },
- { "recipient_unqualified_hosts", opt_stringptr, &recipient_unqualified_hosts },
- { "recipients_max", opt_int, &recipients_max },
- { "recipients_max_reject", opt_bool, &recipients_max_reject },
+ { "preserve_message_logs", opt_bool, {&preserve_message_logs} },
+ { "primary_hostname", opt_stringptr, {&primary_hostname} },
+ { "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} },
+#ifndef DISABLE_QUEUE_RAMP
+ { "queue_fast_ramp", opt_bool, {&queue_fast_ramp} },
+#endif
+ { "queue_list_requires_admin",opt_bool, {&queue_list_requires_admin} },
+ { "queue_only", opt_bool, {&queue_only} },
+ { "queue_only_file", opt_stringptr, {&queue_only_file} },
+ { "queue_only_load", opt_fixed, {&queue_only_load} },
+ { "queue_only_load_latch", opt_bool, {&queue_only_load_latch} },
+ { "queue_only_override", opt_bool, {&queue_only_override} },
+ { "queue_run_in_order", opt_bool, {&queue_run_in_order} },
+ { "queue_run_max", opt_stringptr, {&queue_run_max} },
+ { "queue_smtp_domains", opt_stringptr, {&queue_smtp_domains} },
+ { "receive_timeout", opt_time, {&receive_timeout} },
+ { "received_header_text", opt_stringptr, {&received_header_text} },
+ { "received_headers_max", opt_int, {&received_headers_max} },
+ { "recipient_unqualified_hosts", opt_stringptr, {&recipient_unqualified_hosts} },
+ { "recipients_max", opt_int, {&recipients_max} },
+ { "recipients_max_reject", opt_bool, {&recipients_max_reject} },
#ifdef LOOKUP_REDIS
- { "redis_servers", opt_stringptr, &redis_servers },
+ { "redis_servers", opt_stringptr, {&redis_servers} },
#endif
- { "remote_max_parallel", opt_int, &remote_max_parallel },
- { "remote_sort_domains", opt_stringptr, &remote_sort_domains },
- { "retry_data_expire", opt_time, &retry_data_expire },
- { "retry_interval_max", opt_time, &retry_interval_max },
- { "return_path_remove", opt_bool, &return_path_remove },
- { "return_size_limit", opt_mkint|opt_hidden, &bounce_return_size_limit },
- { "rfc1413_hosts", opt_stringptr, &rfc1413_hosts },
- { "rfc1413_query_timeout", opt_time, &rfc1413_query_timeout },
- { "sender_unqualified_hosts", opt_stringptr, &sender_unqualified_hosts },
- { "slow_lookup_log", opt_int, &slow_lookup_log },
- { "smtp_accept_keepalive", opt_bool, &smtp_accept_keepalive },
- { "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_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_banner", opt_stringptr, &smtp_banner },
- { "smtp_check_spool_space", opt_bool, &smtp_check_spool_space },
- { "smtp_connect_backlog", opt_int, &smtp_connect_backlog },
- { "smtp_enforce_sync", opt_bool, &smtp_enforce_sync },
- { "smtp_etrn_command", opt_stringptr, &smtp_etrn_command },
- { "smtp_etrn_serialize", opt_bool, &smtp_etrn_serialize },
- { "smtp_load_reserve", opt_fixed, &smtp_load_reserve },
- { "smtp_max_synprot_errors", opt_int, &smtp_max_synprot_errors },
- { "smtp_max_unknown_commands",opt_int, &smtp_max_unknown_commands },
- { "smtp_ratelimit_hosts", opt_stringptr, &smtp_ratelimit_hosts },
- { "smtp_ratelimit_mail", opt_stringptr, &smtp_ratelimit_mail },
- { "smtp_ratelimit_rcpt", opt_stringptr, &smtp_ratelimit_rcpt },
- { "smtp_receive_timeout", opt_func, &fn_smtp_receive_timeout },
- { "smtp_reserve_hosts", opt_stringptr, &smtp_reserve_hosts },
- { "smtp_return_error_details",opt_bool, &smtp_return_error_details },
+ { "remote_max_parallel", opt_int, {&remote_max_parallel} },
+ { "remote_sort_domains", opt_stringptr, {&remote_sort_domains} },
+ { "retry_data_expire", opt_time, {&retry_data_expire} },
+ { "retry_interval_max", opt_time, {&retry_interval_max} },
+ { "return_path_remove", opt_bool, {&return_path_remove} },
+ { "return_size_limit", opt_mkint|opt_hidden, {&bounce_return_size_limit} },
+ { "rfc1413_hosts", opt_stringptr, {&rfc1413_hosts} },
+ { "rfc1413_query_timeout", opt_time, {&rfc1413_query_timeout} },
+ { "sender_unqualified_hosts", opt_stringptr, {&sender_unqualified_hosts} },
+ { "slow_lookup_log", opt_int, {&slow_lookup_log} },
+ { "smtp_accept_keepalive", opt_bool, {&smtp_accept_keepalive} },
+ { "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_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} },
+ { "smtp_enforce_sync", opt_bool, {&smtp_enforce_sync} },
+ { "smtp_etrn_command", opt_stringptr, {&smtp_etrn_command} },
+ { "smtp_etrn_serialize", opt_bool, {&smtp_etrn_serialize} },
+ { "smtp_load_reserve", opt_fixed, {&smtp_load_reserve} },
+ { "smtp_max_synprot_errors", opt_int, {&smtp_max_synprot_errors} },
+ { "smtp_max_unknown_commands",opt_int, {&smtp_max_unknown_commands} },
+ { "smtp_ratelimit_hosts", opt_stringptr, {&smtp_ratelimit_hosts} },
+ { "smtp_ratelimit_mail", opt_stringptr, {&smtp_ratelimit_mail} },
+ { "smtp_ratelimit_rcpt", opt_stringptr, {&smtp_ratelimit_rcpt} },
+ { "smtp_receive_timeout", opt_func, {.fn = &fn_smtp_receive_timeout} },
+ { "smtp_reserve_hosts", opt_stringptr, {&smtp_reserve_hosts} },
+ { "smtp_return_error_details",opt_bool, {&smtp_return_error_details} },
#ifdef SUPPORT_I18N
- { "smtputf8_advertise_hosts", opt_stringptr, &smtputf8_advertise_hosts },
+ { "smtputf8_advertise_hosts", opt_stringptr, {&smtputf8_advertise_hosts} },
#endif
#ifdef WITH_CONTENT_SCAN
- { "spamd_address", opt_stringptr, &spamd_address },
+ { "spamd_address", opt_stringptr, {&spamd_address} },
#endif
#ifdef SUPPORT_SPF
- { "spf_guess", opt_stringptr, &spf_guess },
+ { "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 },
+ { "split_spool_directory", opt_bool, {&split_spool_directory} },
+ { "spool_directory", opt_stringptr, {&spool_directory} },
+ { "spool_wireformat", opt_bool, {&spool_wireformat} },
#ifdef LOOKUP_SQLITE
- { "sqlite_lock_timeout", opt_int, &sqlite_lock_timeout },
+ { "sqlite_dbfile", opt_stringptr, {&sqlite_dbfile} },
+ { "sqlite_lock_timeout", opt_int, {&sqlite_lock_timeout} },
#endif
-#ifdef EXPERIMENTAL_SRS
- { "srs_config", opt_stringptr, &srs_config },
- { "srs_hashlength", opt_int, &srs_hashlength },
- { "srs_hashmin", opt_int, &srs_hashmin },
- { "srs_maxage", opt_int, &srs_maxage },
- { "srs_secrets", opt_stringptr, &srs_secrets },
- { "srs_usehash", opt_bool, &srs_usehash },
- { "srs_usetimestamp", opt_bool, &srs_usetimestamp },
-#endif
- { "strict_acl_vars", opt_bool, &strict_acl_vars },
- { "strip_excess_angle_brackets", opt_bool, &strip_excess_angle_brackets },
- { "strip_trailing_dot", opt_bool, &strip_trailing_dot },
- { "syslog_duplication", opt_bool, &syslog_duplication },
- { "syslog_facility", opt_stringptr, &syslog_facility_str },
- { "syslog_pid", opt_bool, &syslog_pid },
- { "syslog_processname", opt_stringptr, &syslog_processname },
- { "syslog_timestamp", opt_bool, &syslog_timestamp },
- { "system_filter", opt_stringptr, &system_filter },
- { "system_filter_directory_transport", opt_stringptr,&system_filter_directory_transport },
- { "system_filter_file_transport",opt_stringptr,&system_filter_file_transport },
- { "system_filter_group", opt_gid, &system_filter_gid },
- { "system_filter_pipe_transport",opt_stringptr,&system_filter_pipe_transport },
- { "system_filter_reply_transport",opt_stringptr,&system_filter_reply_transport },
- { "system_filter_user", opt_uid, &system_filter_uid },
- { "tcp_nodelay", opt_bool, &tcp_nodelay },
+ { "strict_acl_vars", opt_bool, {&strict_acl_vars} },
+ { "strip_excess_angle_brackets", opt_bool, {&strip_excess_angle_brackets} },
+ { "strip_trailing_dot", opt_bool, {&strip_trailing_dot} },
+ { "syslog_duplication", opt_bool, {&syslog_duplication} },
+ { "syslog_facility", opt_stringptr, {&syslog_facility_str} },
+ { "syslog_pid", opt_bool, {&syslog_pid} },
+ { "syslog_processname", opt_stringptr, {&syslog_processname} },
+ { "syslog_timestamp", opt_bool, {&syslog_timestamp} },
+ { "system_filter", opt_stringptr, {&system_filter} },
+ { "system_filter_directory_transport", opt_stringptr,{&system_filter_directory_transport} },
+ { "system_filter_file_transport",opt_stringptr,{&system_filter_file_transport} },
+ { "system_filter_group", opt_gid, {&system_filter_gid} },
+ { "system_filter_pipe_transport",opt_stringptr,{&system_filter_pipe_transport} },
+ { "system_filter_reply_transport",opt_stringptr,{&system_filter_reply_transport} },
+ { "system_filter_user", opt_uid, {&system_filter_uid} },
+ { "tcp_nodelay", opt_bool, {&tcp_nodelay} },
#ifdef USE_TCP_WRAPPERS
- { "tcp_wrappers_daemon_name", opt_stringptr, &tcp_wrappers_daemon_name },
+ { "tcp_wrappers_daemon_name", opt_stringptr, {&tcp_wrappers_daemon_name} },
#endif
- { "timeout_frozen_after", opt_time, &timeout_frozen_after },
- { "timezone", opt_stringptr, &timezone_string },
- { "tls_advertise_hosts", opt_stringptr, &tls_advertise_hosts },
-#ifdef SUPPORT_TLS
- { "tls_certificate", opt_stringptr, &tls_certificate },
- { "tls_crl", opt_stringptr, &tls_crl },
- { "tls_dh_max_bits", opt_int, &tls_dh_max_bits },
- { "tls_dhparam", opt_stringptr, &tls_dhparam },
- { "tls_eccurve", opt_stringptr, &tls_eccurve },
+ { "timeout_frozen_after", opt_time, {&timeout_frozen_after} },
+ { "timezone", opt_stringptr, {&timezone_string} },
+ { "tls_advertise_hosts", opt_stringptr, {&tls_advertise_hosts} },
+#ifndef DISABLE_TLS
+ { "tls_alpn", opt_stringptr, {&tls_alpn} },
+ { "tls_certificate", opt_stringptr, {&tls_certificate} },
+ { "tls_crl", opt_stringptr, {&tls_crl} },
+ { "tls_dh_max_bits", opt_int, {&tls_dh_max_bits} },
+ { "tls_dhparam", opt_stringptr, {&tls_dhparam} },
+ { "tls_eccurve", opt_stringptr, {&tls_eccurve} },
# ifndef DISABLE_OCSP
- { "tls_ocsp_file", opt_stringptr, &tls_ocsp_file },
+ { "tls_ocsp_file", opt_stringptr, {&tls_ocsp_file} },
+# endif
+ { "tls_on_connect_ports", opt_stringptr, {&tls_in.on_connect_ports} },
+ { "tls_privatekey", opt_stringptr, {&tls_privatekey} },
+ { "tls_remember_esmtp", opt_bool, {&tls_remember_esmtp} },
+ { "tls_require_ciphers", opt_stringptr, {&tls_require_ciphers} },
+# ifndef DISABLE_TLS_RESUME
+ { "tls_resumption_hosts", opt_stringptr, {&tls_resumption_hosts} },
# endif
- { "tls_on_connect_ports", opt_stringptr, &tls_in.on_connect_ports },
- { "tls_privatekey", opt_stringptr, &tls_privatekey },
- { "tls_remember_esmtp", opt_bool, &tls_remember_esmtp },
- { "tls_require_ciphers", opt_stringptr, &tls_require_ciphers },
- { "tls_try_verify_hosts", opt_stringptr, &tls_try_verify_hosts },
- { "tls_verify_certificates", opt_stringptr, &tls_verify_certificates },
- { "tls_verify_hosts", opt_stringptr, &tls_verify_hosts },
+ { "tls_try_verify_hosts", opt_stringptr, {&tls_try_verify_hosts} },
+ { "tls_verify_certificates", opt_stringptr, {&tls_verify_certificates} },
+ { "tls_verify_hosts", opt_stringptr, {&tls_verify_hosts} },
#endif
- { "trusted_groups", opt_gidlist, &trusted_groups },
- { "trusted_users", opt_uidlist, &trusted_users },
- { "unknown_login", opt_stringptr, &unknown_login },
- { "unknown_username", opt_stringptr, &unknown_username },
- { "untrusted_set_sender", opt_stringptr, &untrusted_set_sender },
- { "uucp_from_pattern", opt_stringptr, &uucp_from_pattern },
- { "uucp_from_sender", opt_stringptr, &uucp_from_sender },
- { "warn_message_file", opt_stringptr, &warn_message_file },
- { "write_rejectlog", opt_bool, &write_rejectlog }
+ { "trusted_groups", opt_gidlist, {&trusted_groups} },
+ { "trusted_users", opt_uidlist, {&trusted_users} },
+ { "unknown_login", opt_stringptr, {&unknown_login} },
+ { "unknown_username", opt_stringptr, {&unknown_username} },
+ { "untrusted_set_sender", opt_stringptr, {&untrusted_set_sender} },
+ { "uucp_from_pattern", opt_stringptr, {&uucp_from_pattern} },
+ { "uucp_from_sender", opt_stringptr, {&uucp_from_sender} },
+ { "warn_message_file", opt_stringptr, {&warn_message_file} },
+ { "write_rejectlog", opt_bool, {&write_rejectlog} },
};
#ifndef MACRO_PREDEF
#ifdef MACRO_PREDEF
-static void fn_smtp_receive_timeout(const uschar * name, const uschar * str) {/*Dummy*/}
+static void
+fn_smtp_receive_timeout(const uschar * name, const uschar * str, unsigned flags) {/*Dummy*/}
void
options_main(void)
void
options_auths(void)
{
-struct auth_info * ai;
-uschar buf[64];
+uschar buf[EXIM_DRIVERNAME_MAX];
options_from_list(optionlist_auths, optionlist_auths_size, US"AUTHENTICATORS", NULL);
-for (ai = auths_available; ai->driver_name[0]; ai++)
+for (struct auth_info * ai = auths_available; ai->driver_name[0]; ai++)
{
spf(buf, sizeof(buf), US"_DRIVER_AUTHENTICATOR_%T", ai->driver_name);
builtin_macro_create(buf);
options_from_list(ai->options, (unsigned)*ai->options_count, US"AUTHENTICATOR", ai->driver_name);
+
+ if (ai->macros_create) (ai->macros_create)();
+ }
+}
+
+void
+options_logging(void)
+{
+uschar buf[EXIM_DRIVERNAME_MAX];
+
+for (bit_table * bp = log_options; bp < log_options + log_options_count; bp++)
+ {
+ spf(buf, sizeof(buf), US"_LOG_%T", bp->name);
+ builtin_macro_create(buf);
}
}
} syslog_fac_item;
/* constants */
-static const char * const hidden = "<value not displayable>";
+static const uschar * const hidden = US"<value not displayable>";
/* Static variables */
static int syslog_list_size = sizeof(syslog_list)/sizeof(syslog_fac_item);
+#define opt_fn_print BIT(0)
+#define opt_fn_print_label BIT(1)
/*************************************************
uschar *
readconf_find_option(void *p)
{
-int i;
-router_instance *r;
-transport_instance *t;
+for (int i = 0; i < nelem(optionlist_config); i++)
+ if (p == optionlist_config[i].v.value) return US optionlist_config[i].name;
-for (i = 0; i < nelem(optionlist_config); i++)
- if (p == optionlist_config[i].value) return US optionlist_config[i].name;
-
-for (r = routers; r; r = r->next)
+for (router_instance * r = routers; r; r = r->next)
{
router_info *ri = r->info;
- for (i = 0; i < *ri->options_count; i++)
+ for (int i = 0; i < *ri->options_count; i++)
{
if ((ri->options[i].type & opt_mask) != opt_stringptr) continue;
- if (p == CS (r->options_block) + (long int)(ri->options[i].value))
+ if (p == CS (r->options_block) + ri->options[i].v.offset)
return US ri->options[i].name;
}
}
-for (t = transports; t; t = t->next)
+for (transport_instance * t = transports; t; t = t->next)
{
transport_info *ti = t->info;
- for (i = 0; i < *ti->options_count; i++)
+ for (int i = 0; i < *ti->options_count; i++)
{
optionlist * op = &ti->options[i];
if ((op->type & opt_mask) != opt_stringptr) continue;
? CS t
: CS t->options_block
)
- + (long int)op->value)
+ + op->v.offset)
return US op->name;
}
}
macro_item *
macro_create(const uschar * name, const uschar * val, BOOL command_line)
{
-macro_item * m = store_get(sizeof(macro_item));
+macro_item * m = store_get(sizeof(macro_item), GET_UNTAINTED);
-/* fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val); */
+READCONF_DEBUG fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val);
m->next = NULL;
m->command_line = command_line;
m->namelen = Ustrlen(name);
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
if (!m->command_line && !redef)
{
log_write(0, LOG_CONFIG|LOG_PANIC, "macro \"%s\" is already "
- "defined (use \"==\" if you want to redefine it", name);
+ "defined (use \"==\" if you want to redefine it)", name);
return FALSE;
}
break;
{
uschar * ss = big_buffer + len;
uschar * s;
-macro_item * m;
/* 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
replacing all occurrences of the macro. */
*macro_found = FALSE;
-if (*s) for (m = *s == '_' ? macros : macros_user; m; m = m->next)
+if (*s) for (macro_item * m = *s == '_' ? macros : macros_user; m; m = m->next)
{
uschar * p, *pp;
uschar * t;
{
int moveby;
-/* fprintf(stderr, "%s: matched '%s' in '%s'\n", __FUNCTION__, m->name, ss); */
+ READCONF_DEBUG fprintf(stderr, "%s: matched '%s' in '%.*s'\n", __FUNCTION__,
+ m->name, (int) Ustrlen(ss)-1, ss);
/* Expand the buffer if necessary */
while (*newlen - m->namelen + m->replen + 1 > big_buffer_size)
/* 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;
}
/* Handle conditionals, which are also applied to physical lines. Conditions
are of the form ".ifdef ANYTEXT" and are treated as true if any macro
- expansion occured on the rest of the line. A preliminary test for the leading
+ expansion occurred on the rest of the line. A preliminary test for the leading
'.' saves effort on most lines. */
if (*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 (config_lines)
save_config_position(config_filename, config_lineno);
- save = store_get(sizeof(config_file_item));
+ save = store_get(sizeof(config_file_item), GET_UNTAINTED);
save->next = config_file_stack;
config_file_stack = save;
save->file = config_file;
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);
Returns: new input pointer
*/
-uschar *
-readconf_readname(uschar *name, int len, uschar *s)
+const uschar *
+readconf_readname(uschar * name, int len, const 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);
-ol = find_option(name2, oltop, last);
-if (ol == NULL) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
- "Exim internal error: missing set flag for %s", name);
-return (data_block == NULL)? (BOOL *)(ol->value) :
- (BOOL *)(US data_block + (long int)(ol->value));
+if (!(ol = find_option(name2, oltop, last)))
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+ "Exim internal error: missing set flag for %s", name);
+return data_block
+ ? (BOOL *)(US data_block + ol->v.offset) : (BOOL *)ol->v.value;
}
static rewrite_rule *
readconf_one_rewrite(const uschar *p, int *existflags, BOOL isglobal)
{
-rewrite_rule *next = store_get(sizeof(rewrite_rule));
+rewrite_rule * next = store_get(sizeof(rewrite_rule), GET_UNTAINTED);
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;
* Custom-handler options *
*************************************************/
static void
-fn_smtp_receive_timeout(const uschar * name, const uschar * str)
+fn_smtp_receive_timeout(const uschar * name, const uschar * str, unsigned flags)
{
-if (*str == '$')
+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, SP_TAB)
+ : readconf_printtime(smtp_receive_timeout));
+ }
+else if (*str == '$')
smtp_receive_timeout_s = string_copy(str);
else
{
{
int ptr = 0;
int offset = 0;
-int n, count, type, value;
+int count, type, value;
int issecure = 0;
uid_t uid;
gid_t gid;
BOOL freesptr = TRUE;
optionlist *ol, *ol2;
struct passwd *pw;
-void *reset_point;
+rmark reset_point;
int intbase = 0;
uschar *inttype = US"";
uschar *sptr;
-uschar *s = buffer;
+const 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. */
it turns out that what we read was "hide", set the flag indicating that
this is a secure option, and loop to read the next word. */
-for (n = 0; n < 2; n++)
+for (int n = 0; n < 2; n++)
{
while (isalnum(*s) || *s == '_')
{
if (!(ol = find_option(name + offset, oltop, last)))
{
- if (unknown_txt == NULL) return FALSE;
+ if (!unknown_txt) return FALSE;
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, CS unknown_txt, name);
}
if (offset != 0)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"negation prefix applied to a non-boolean option");
- if (*s == 0)
+ if (!*s)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"unexpected end of line (data missing) after %s", name);
if (*s != '=')
true/false/yes/no, or, in the case of opt_expand_bool, a general string that
ultimately expands to one of those values. */
-else if (*s != 0 && (offset != 0 || *s != '='))
+else if (*s && (offset != 0 || *s != '='))
extra_chars_error(s, US"boolean option ", name, US"");
/* Skip white space after = */
/* If there is a data block and the opt_public flag is not set, change
the data block pointer to the private options block. */
-if (data_block != NULL && (ol->type & opt_public) == 0)
+if (data_block && !(ol->type & opt_public))
data_block = (void *)(((driver_instance *)data_block)->options_block);
/* Now get the data according to the type. */
case opt_gidlist:
case opt_rewrite:
- reset_point = sptr = read_string(s, name);
-
- /* Having read a string, we now have several different ways of using it,
- depending on the data type, so do another switch. If keeping the actual
- string is not required (because it is interpreted), freesptr is set TRUE,
- and at the end we reset the pool. */
-
- switch (type)
- {
- /* If this was a string, set the variable to point to the new string,
- and set the flag so its store isn't reclaimed. If it was a list of rewrite
- rules, we still keep the string (for printing), and parse the rules into a
- control block and flags word. */
-
- case opt_stringptr:
- str_target = data_block ? USS (US data_block + (long int)(ol->value))
- : USS (ol->value);
- if (ol->type & opt_rep_con)
- {
- uschar * saved_condition;
- /* We already have a condition, we're conducting a crude hack to let
- multiple condition rules be chained together, despite storing them in
- text form. */
- *str_target = string_copy_malloc( (saved_condition = *str_target)
- ? string_sprintf("${if and{{bool_lax{%s}}{bool_lax{%s}}}}",
- saved_condition, sptr)
- : sptr);
- /* TODO(pdp): there is a memory leak here and just below
- when we set 3 or more conditions; I still don't
- understand the store mechanism enough to know
- what's the safe way to free content from an earlier store.
- AFAICT, stores stack, so freeing an early stored item also stores
- all data alloc'd after it. If we knew conditions were adjacent,
- we could survive that, but we don't. So I *think* we need to take
- another bit from opt_type to indicate "malloced"; this seems like
- quite a hack, especially for this one case. It also means that
- we can't ever reclaim the store from the *first* condition.
-
- Because we only do this once, near process start-up, I'm prepared to
- let this slide for the time being, even though it rankles. */
- }
- else if (ol->type & opt_rep_str)
- {
- uschar sep_o = Ustrncmp(name, "headers_add", 11)==0 ? '\n' : ':';
- int sep_i = -(int)sep_o;
- const uschar * list = sptr;
- uschar * s;
- gstring * list_o = NULL;
-
- if (*str_target)
- {
- list_o = string_get(Ustrlen(*str_target) + Ustrlen(sptr));
- list_o = string_cat(list_o, *str_target);
- }
-
- while ((s = string_nextinlist(&list, &sep_i, NULL, 0)))
- list_o = string_append_listele(list_o, sep_o, s);
-
- if (list_o)
- *str_target = string_copy_malloc(string_from_gstring(list_o));
- }
- else
- {
- *str_target = sptr;
- freesptr = FALSE;
- }
- break;
-
- case opt_rewrite:
- if (data_block)
- *USS (US data_block + (long int)(ol->value)) = sptr;
- else
- *USS (ol->value) = sptr;
- freesptr = FALSE;
- if (type == opt_rewrite)
- {
- int sep = 0;
- int *flagptr;
- uschar *p = sptr;
- rewrite_rule **chain;
- optionlist *ol3;
-
- sprintf(CS name2, "*%.50s_rules", name);
- ol2 = find_option(name2, oltop, last);
- sprintf(CS name2, "*%.50s_flags", name);
- ol3 = find_option(name2, oltop, last);
-
- if (ol2 == NULL || ol3 == NULL)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
- "rewrite rules not available for driver");
-
- if (data_block == NULL)
- {
- chain = (rewrite_rule **)(ol2->value);
- flagptr = (int *)(ol3->value);
- }
- else
- {
- chain = (rewrite_rule **)(US data_block + (long int)(ol2->value));
- flagptr = (int *)(US data_block + (long int)(ol3->value));
- }
-
- while ((p = string_nextinlist(CUSS &sptr, &sep, big_buffer, BIG_BUFFER_SIZE)))
- {
- rewrite_rule *next = readconf_one_rewrite(p, flagptr, FALSE);
- *chain = next;
- chain = &(next->next);
- }
-
- if ((*flagptr & (rewrite_all_envelope | rewrite_smtp)) != 0)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "rewrite rule specifies a "
- "non-header rewrite - not allowed at transport time -");
- }
- break;
-
- /* If it was an expanded uid, see if there is any expansion to be
- done by checking for the presence of a $ character. If there is, save it
- in the corresponding *expand_user option field. Otherwise, fall through
- to treat it as a fixed uid. Ensure mutual exclusivity of the two kinds
- of data. */
-
- case opt_expand_uid:
- sprintf(CS name2, "*expand_%.50s", name);
- ol2 = find_option(name2, oltop, last);
- if (ol2 != NULL)
- {
- uschar *ss = (Ustrchr(sptr, '$') != NULL)? sptr : NULL;
-
- if (data_block == NULL)
- *((uschar **)(ol2->value)) = ss;
- else
- *((uschar **)(US data_block + (long int)(ol2->value))) = ss;
-
- if (ss != NULL)
- {
- *(get_set_flag(name, oltop, last, data_block)) = FALSE;
- freesptr = FALSE;
- break;
- }
- }
-
- /* Look up a fixed uid, and also make use of the corresponding gid
- if a passwd entry is returned and the gid has not been set. */
-
- case opt_uid:
- if (!route_finduser(sptr, &pw, &uid))
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "user %s was not found", sptr);
- if (data_block == NULL)
- *((uid_t *)(ol->value)) = uid;
- else
- *((uid_t *)(US data_block + (long int)(ol->value))) = uid;
-
- /* Set the flag indicating a fixed value is set */
-
- *(get_set_flag(name, oltop, last, data_block)) = TRUE;
-
- /* Handle matching gid if we have a passwd entry: done by finding the
- same name with terminating "user" changed to "group"; if not found,
- ignore. Also ignore if the value is already set. */
+ reset_point = store_mark();
+ sptr = read_string(s, name);
- if (pw == NULL) break;
- Ustrcpy(name+Ustrlen(name)-4, "group");
- ol2 = find_option(name, oltop, last);
- if (ol2 != NULL && ((ol2->type & opt_mask) == opt_gid ||
- (ol2->type & opt_mask) == opt_expand_gid))
- {
- BOOL *set_flag = get_set_flag(name, oltop, last, data_block);
- if (! *set_flag)
- {
- if (data_block == NULL)
- *((gid_t *)(ol2->value)) = pw->pw_gid;
- else
- *((gid_t *)(US data_block + (long int)(ol2->value))) = pw->pw_gid;
- *set_flag = TRUE;
- }
- }
- break;
+ /* Having read a string, we now have several different ways of using it,
+ depending on the data type, so do another switch. If keeping the actual
+ string is not required (because it is interpreted), freesptr is set TRUE,
+ and at the end we reset the pool. */
- /* If it was an expanded gid, see if there is any expansion to be
- done by checking for the presence of a $ character. If there is, save it
- in the corresponding *expand_user option field. Otherwise, fall through
- to treat it as a fixed gid. Ensure mutual exclusivity of the two kinds
- of data. */
-
- case opt_expand_gid:
- sprintf(CS name2, "*expand_%.50s", name);
- ol2 = find_option(name2, oltop, last);
- if (ol2 != NULL)
+ switch (type)
{
- uschar *ss = (Ustrchr(sptr, '$') != NULL)? sptr : NULL;
+ /* If this was a string, set the variable to point to the new string,
+ and set the flag so its store isn't reclaimed. If it was a list of rewrite
+ rules, we still keep the string (for printing), and parse the rules into a
+ control block and flags word. */
+
+ case opt_stringptr:
+ str_target = data_block ? USS (US data_block + ol->v.offset)
+ : USS ol->v.value;
+ if (ol->type & opt_rep_con)
+ {
+ uschar * saved_condition;
+ /* We already have a condition, we're conducting a crude hack to let
+ multiple condition rules be chained together, despite storing them in
+ text form. */
+ *str_target = string_copy_perm( (saved_condition = *str_target)
+ ? string_sprintf("${if and{{bool_lax{%s}}{bool_lax{%s}}}}",
+ saved_condition, sptr)
+ : sptr,
+ FALSE);
+ /* TODO(pdp): there is a memory leak here and just below
+ when we set 3 or more conditions; I still don't
+ understand the store mechanism enough to know
+ what's the safe way to free content from an earlier store.
+ AFAICT, stores stack, so freeing an early stored item also stores
+ all data alloc'd after it. If we knew conditions were adjacent,
+ we could survive that, but we don't. So I *think* we need to take
+ another bit from opt_type to indicate "malloced"; this seems like
+ quite a hack, especially for this one case. It also means that
+ we can't ever reclaim the store from the *first* condition.
+
+ Because we only do this once, near process start-up, I'm prepared to
+ let this slide for the time being, even though it rankles. */
+ }
+ else if (ol->type & opt_rep_str)
+ {
+ uschar sep_o =
+ Ustrncmp(name, "headers_add", 11) == 0 ? '\n'
+ : Ustrncmp(name, "set", 3) == 0 ? ';'
+ : ':';
+ int sep_i = -(int)sep_o;
+ const uschar * list = sptr;
+ uschar * s;
+ gstring * list_o = NULL;
+
+ if (*str_target)
+ {
+ list_o = string_get(Ustrlen(*str_target) + Ustrlen(sptr));
+ list_o = string_cat(list_o, *str_target);
+ }
+
+ while ((s = string_nextinlist(&list, &sep_i, NULL, 0)))
+ list_o = string_append_listele(list_o, sep_o, s);
+
+ if (list_o)
+ *str_target = string_copy_perm(string_from_gstring(list_o), FALSE);
+ }
+ else
+ {
+ *str_target = sptr;
+ freesptr = FALSE;
+ }
+ break;
- if (data_block == NULL)
- *((uschar **)(ol2->value)) = ss;
- else
- *((uschar **)(US data_block + (long int)(ol2->value))) = ss;
+ case opt_rewrite:
+ if (data_block)
+ *USS (US data_block + ol->v.offset) = sptr;
+ else
+ *USS ol->v.value = sptr;
+ freesptr = FALSE;
+ if (type == opt_rewrite)
+ {
+ int sep = 0;
+ int *flagptr;
+ uschar *p = sptr;
+ rewrite_rule **chain;
+ optionlist *ol3;
+
+ sprintf(CS name2, "*%.50s_rules", name);
+ ol2 = find_option(name2, oltop, last);
+ sprintf(CS name2, "*%.50s_flags", name);
+ ol3 = find_option(name2, oltop, last);
+
+ if (!ol2 || !ol3)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
+ "rewrite rules not available for driver");
+
+ if (data_block)
+ {
+ chain = (rewrite_rule **)(US data_block + ol2->v.offset);
+ flagptr = (int *)(US data_block + ol3->v.offset);
+ }
+ else
+ {
+ chain = (rewrite_rule **)ol2->v.value;
+ 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);
+ *chain = next;
+ chain = &(next->next);
+ }
+
+ if ((*flagptr & (rewrite_all_envelope | rewrite_smtp)) != 0)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "rewrite rule specifies a "
+ "non-header rewrite - not allowed at transport time -");
+ }
+ break;
- if (ss != NULL)
- {
- *(get_set_flag(name, oltop, last, data_block)) = FALSE;
- freesptr = FALSE;
- break;
- }
- }
+ /* If it was an expanded uid, see if there is any expansion to be
+ done by checking for the presence of a $ character. If there is, save it
+ in the corresponding *expand_user option field. Otherwise, fall through
+ to treat it as a fixed uid. Ensure mutual exclusivity of the two kinds
+ of data. */
+
+ case opt_expand_uid:
+ sprintf(CS name2, "*expand_%.50s", name);
+ if ((ol2 = find_option(name2, oltop, last)))
+ {
+ uschar *ss = (Ustrchr(sptr, '$') != NULL) ? sptr : NULL;
+
+ if (data_block)
+ *(USS(US data_block + ol2->v.offset)) = ss;
+ else
+ *(USS ol2->v.value) = ss;
+
+ if (ss)
+ {
+ *(get_set_flag(name, oltop, last, data_block)) = FALSE;
+ freesptr = FALSE;
+ break;
+ }
+ }
+
+ /* Look up a fixed uid, and also make use of the corresponding gid
+ if a passwd entry is returned and the gid has not been set. */
+
+ case opt_uid:
+ if (!route_finduser(sptr, &pw, &uid))
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "user %s was not found", sptr);
+ if (data_block)
+ *(uid_t *)(US data_block + ol->v.offset) = uid;
+ else
+ *(uid_t *)ol->v.value = uid;
+
+ /* Set the flag indicating a fixed value is set */
+
+ *(get_set_flag(name, oltop, last, data_block)) = TRUE;
+
+ /* Handle matching gid if we have a passwd entry: done by finding the
+ same name with terminating "user" changed to "group"; if not found,
+ ignore. Also ignore if the value is already set. */
+
+ if (pw == NULL) break;
+ Ustrcpy(name+Ustrlen(name)-4, US"group");
+ ol2 = find_option(name, oltop, last);
+ if (ol2 && ((ol2->type & opt_mask) == opt_gid ||
+ (ol2->type & opt_mask) == opt_expand_gid))
+ {
+ BOOL *set_flag = get_set_flag(name, oltop, last, data_block);
+ if (!*set_flag)
+ {
+ if (data_block)
+ *((gid_t *)(US data_block + ol2->v.offset)) = pw->pw_gid;
+ else
+ *((gid_t *)ol2->v.value) = pw->pw_gid;
+ *set_flag = TRUE;
+ }
+ }
+ break;
- /* Handle freestanding gid */
+ /* If it was an expanded gid, see if there is any expansion to be
+ done by checking for the presence of a $ character. If there is, save it
+ in the corresponding *expand_user option field. Otherwise, fall through
+ to treat it as a fixed gid. Ensure mutual exclusivity of the two kinds
+ of data. */
+
+ case opt_expand_gid:
+ sprintf(CS name2, "*expand_%.50s", name);
+ if ((ol2 = find_option(name2, oltop, last)))
+ {
+ uschar *ss = (Ustrchr(sptr, '$') != NULL) ? sptr : NULL;
+
+ if (data_block)
+ *(USS(US data_block + ol2->v.offset)) = ss;
+ else
+ *(USS ol2->v.value) = ss;
+
+ if (ss)
+ {
+ *(get_set_flag(name, oltop, last, data_block)) = FALSE;
+ freesptr = FALSE;
+ break;
+ }
+ }
+
+ /* Handle freestanding gid */
+
+ case opt_gid:
+ if (!route_findgroup(sptr, &gid))
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "group %s was not found", sptr);
+ if (data_block)
+ *((gid_t *)(US data_block + ol->v.offset)) = gid;
+ else
+ *((gid_t *)ol->v.value) = gid;
+ *(get_set_flag(name, oltop, last, data_block)) = TRUE;
+ break;
- case opt_gid:
- if (!route_findgroup(sptr, &gid))
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "group %s was not found", sptr);
- if (data_block == NULL)
- *((gid_t *)(ol->value)) = gid;
- else
- *((gid_t *)(US data_block + (long int)(ol->value))) = gid;
- *(get_set_flag(name, oltop, last, data_block)) = TRUE;
- break;
+ /* If it was a uid list, look up each individual entry, and build
+ a vector of uids, with a count in the first element. Put the vector
+ in malloc store so we can free the string. (We are reading into
+ permanent store already.) */
- /* If it was a uid list, look up each individual entry, and build
- a vector of uids, with a count in the first element. Put the vector
- in malloc store so we can free the string. (We are reading into
- permanent store already.) */
+ case opt_uidlist:
+ {
+ int count = 1;
+ uid_t *list;
+ int ptr = 0;
+ const uschar *p;
+ const uschar *op = expand_string (sptr);
+
+ if (op == NULL)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "failed to expand %s: %s",
+ name, expand_string_message);
+
+ p = op;
+ if (*p != 0) count++;
+ while (*p != 0) if (*p++ == ':' && *p != 0) count++;
+ list = store_malloc(count*sizeof(uid_t));
+ list[ptr++] = (uid_t)(count - 1);
+
+ if (data_block)
+ *((uid_t **)(US data_block + ol->v.offset)) = list;
+ else
+ *((uid_t **)ol->v.value) = list;
+
+ p = op;
+ 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",
+ big_buffer);
+ list[ptr++] = uid;
+ }
+ break;
+ }
- case opt_uidlist:
- {
- int count = 1;
- uid_t *list;
- int ptr = 0;
- const uschar *p;
- const uschar *op = expand_string (sptr);
-
- if (op == NULL)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "failed to expand %s: %s",
- name, expand_string_message);
-
- p = op;
- if (*p != 0) count++;
- while (*p != 0) if (*p++ == ':' && *p != 0) count++;
- list = store_malloc(count*sizeof(uid_t));
- list[ptr++] = (uid_t)(count - 1);
-
- if (data_block == NULL)
- *((uid_t **)(ol->value)) = list;
- else
- *((uid_t **)(US data_block + (long int)(ol->value))) = list;
+ /* If it was a gid list, look up each individual entry, and build
+ a vector of gids, with a count in the first element. Put the vector
+ in malloc store so we can free the string. (We are reading into permanent
+ store already.) */
- p = op;
- while (count-- > 1)
- {
- int sep = 0;
- (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",
- big_buffer);
- list[ptr++] = uid;
- }
+ case opt_gidlist:
+ {
+ int count = 1;
+ gid_t *list;
+ int ptr = 0;
+ const uschar *p;
+ const uschar *op = expand_string (sptr);
+
+ if (!op)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "failed to expand %s: %s",
+ name, expand_string_message);
+
+ p = op;
+ if (*p != 0) count++;
+ while (*p != 0) if (*p++ == ':' && *p != 0) count++;
+ list = store_malloc(count*sizeof(gid_t));
+ list[ptr++] = (gid_t)(count - 1);
+
+ if (data_block)
+ *((gid_t **)(US data_block + ol->v.offset)) = list;
+ else
+ *((gid_t **)ol->v.value) = list;
+
+ p = op;
+ 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",
+ big_buffer);
+ list[ptr++] = gid;
+ }
+ break;
+ }
}
- break;
-
- /* If it was a gid list, look up each individual entry, and build
- a vector of gids, with a count in the first element. Put the vector
- in malloc store so we can free the string. (We are reading into permanent
- store already.) */
- case opt_gidlist:
- {
- int count = 1;
- gid_t *list;
- int ptr = 0;
- const uschar *p;
- const uschar *op = expand_string (sptr);
-
- if (op == NULL)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "failed to expand %s: %s",
- name, expand_string_message);
-
- p = op;
- if (*p != 0) count++;
- while (*p != 0) if (*p++ == ':' && *p != 0) count++;
- list = store_malloc(count*sizeof(gid_t));
- list[ptr++] = (gid_t)(count - 1);
-
- if (data_block == NULL)
- *((gid_t **)(ol->value)) = list;
- else
- *((gid_t **)(US data_block + (long int)(ol->value))) = list;
+ /* Release store if the value of the string doesn't need to be kept. */
- p = op;
- while (count-- > 1)
- {
- int sep = 0;
- (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",
- big_buffer);
- list[ptr++] = gid;
- }
- }
+ if (freesptr) reset_point = store_reset(reset_point);
break;
- }
-
- /* Release store if the value of the string doesn't need to be kept. */
-
- if (freesptr) store_reset(reset_point);
- break;
/* Expanded boolean: if no characters follow, or if there are no dollar
characters, this is a fixed-valued boolean, and we fall through. Otherwise,
save the string for later expansion in the alternate place. */
case opt_expand_bool:
- if (*s != 0 && Ustrchr(s, '$') != 0)
- {
- sprintf(CS name2, "*expand_%.50s", name);
- ol2 = find_option(name2, oltop, last);
- if (ol2 != NULL)
+ if (*s && Ustrchr(s, '$') != 0)
{
- reset_point = sptr = read_string(s, name);
- if (data_block == NULL)
- *((uschar **)(ol2->value)) = sptr;
- else
- *((uschar **)(US data_block + (long int)(ol2->value))) = sptr;
- freesptr = FALSE;
- break;
+ sprintf(CS name2, "*expand_%.50s", name);
+ if ((ol2 = find_option(name2, oltop, last)))
+ {
+ reset_point = store_mark();
+ sptr = read_string(s, name);
+ if (data_block)
+ *(USS(US data_block + ol2->v.offset)) = sptr;
+ else
+ *(USS ol2->v.value) = sptr;
+ freesptr = FALSE;
+ break;
+ }
}
- }
- /* Fall through */
+ /* Fall through */
/* Boolean: if no characters follow, the value is boolvalue. Otherwise
look for yes/not/true/false. Some booleans are stored in a single bit in
case opt_bit:
case opt_bool_verify:
case opt_bool_set:
- if (*s != 0)
- {
- s = readconf_readname(name2, 64, 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)
- boolvalue = FALSE;
- else log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
- "\"%s\" is not a valid value for the \"%s\" option", name2, name);
- if (*s != 0) extra_chars_error(s, string_sprintf("\"%s\" ", name2),
- US"for boolean option ", name);
- }
+ if (*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)
+ boolvalue = FALSE;
+ else log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
+ "\"%s\" is not a valid value for the \"%s\" option", name2, name);
+ if (*s != 0) extra_chars_error(s, string_sprintf("\"%s\" ", name2),
+ US"for boolean option ", name);
+ }
- /* Handle single-bit type. */
+ /* Handle single-bit type. */
- if (type == opt_bit)
- {
- int bit = 1 << ((ol->type >> 16) & 31);
- int *ptr = (data_block == NULL)?
- (int *)(ol->value) :
- (int *)(US data_block + (long int)ol->value);
- if (boolvalue) *ptr |= bit; else *ptr &= ~bit;
- break;
- }
+ if (type == opt_bit)
+ {
+ int bit = 1 << ((ol->type >> 16) & 31);
+ int * ptr = data_block
+ ? (int *)(US data_block + ol->v.offset)
+ : (int *)ol->v.value;
+ if (boolvalue) *ptr |= bit; else *ptr &= ~bit;
+ break;
+ }
- /* Handle full BOOL types */
+ /* Handle full BOOL types */
- if (data_block == NULL)
- *((BOOL *)(ol->value)) = boolvalue;
- else
- *((BOOL *)(US data_block + (long int)(ol->value))) = boolvalue;
+ if (data_block)
+ *((BOOL *)(US data_block + ol->v.offset)) = boolvalue;
+ else
+ *((BOOL *)ol->v.value) = boolvalue;
- /* Verify fudge */
+ /* Verify fudge */
- if (type == opt_bool_verify)
- {
- sprintf(CS name2, "%.50s_recipient", name + offset);
- ol2 = find_option(name2, oltop, last);
- if (ol2 != NULL)
+ if (type == opt_bool_verify)
{
- if (data_block == NULL)
- *((BOOL *)(ol2->value)) = boolvalue;
- else
- *((BOOL *)(US data_block + (long int)(ol2->value))) = boolvalue;
+ sprintf(CS name2, "%.50s_recipient", name + offset);
+ if ((ol2 = find_option(name2, oltop, last)))
+ if (data_block)
+ *((BOOL *)(US data_block + ol2->v.offset)) = boolvalue;
+ else
+ *((BOOL *)ol2->v.value) = boolvalue;
}
- }
- /* Note that opt_bool_set type is set, if there is somewhere to do so */
+ /* Note that opt_bool_set type is set, if there is somewhere to do so */
- else if (type == opt_bool_set)
- {
- sprintf(CS name2, "*set_%.50s", name + offset);
- ol2 = find_option(name2, oltop, last);
- if (ol2 != NULL)
+ else if (type == opt_bool_set)
{
- if (data_block == NULL)
- *((BOOL *)(ol2->value)) = TRUE;
- else
- *((BOOL *)(US data_block + (long int)(ol2->value))) = TRUE;
+ sprintf(CS name2, "*set_%.50s", name + offset);
+ if ((ol2 = find_option(name2, oltop, last)))
+ if (data_block)
+ *((BOOL *)(US data_block + ol2->v.offset)) = TRUE;
+ else
+ *((BOOL *)ol2->v.value) = TRUE;
}
- }
- break;
+ break;
/* Octal integer */
case opt_octint:
- intbase = 8;
- inttype = US"octal ";
+ intbase = 8;
+ inttype = US"octal ";
/* Integer: a simple(ish) case; allow octal and hex formats, and
- suffixes K, M and G. The different types affect output, not input. */
+ suffixes K, M, G, and T. The different types affect output, not input. */
case opt_mkint:
case opt_int:
- {
- uschar *endptr;
- long int lvalue;
+ {
+ uschar *endptr;
+ long int lvalue;
- errno = 0;
- lvalue = strtol(CS s, CSS &endptr, intbase);
+ errno = 0;
+ lvalue = strtol(CS s, CSS &endptr, intbase);
- if (endptr == s)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "%sinteger expected for %s",
- inttype, name);
+ if (endptr == s)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "%sinteger expected for %s",
+ inttype, name);
- if (errno != ERANGE)
- if (tolower(*endptr) == 'k')
- {
- if (lvalue > INT_MAX/1024 || lvalue < INT_MIN/1024) errno = ERANGE;
- else lvalue *= 1024;
- endptr++;
- }
- else if (tolower(*endptr) == 'm')
- {
- if (lvalue > INT_MAX/(1024*1024) || lvalue < INT_MIN/(1024*1024))
- errno = ERANGE;
- else lvalue *= 1024*1024;
- endptr++;
- }
- else if (tolower(*endptr) == 'g')
- {
- if (lvalue > INT_MAX/(1024*1024*1024) || lvalue < INT_MIN/(1024*1024*1024))
- errno = ERANGE;
- else lvalue *= 1024*1024*1024;
- endptr++;
- }
+ if (errno != ERANGE && *endptr)
+ {
+ uschar * mp = US"TtGgMmKk\0"; /* YyZzEePpTtGgMmKk */
+
+ if ((mp = Ustrchr(mp, *endptr)))
+ {
+ endptr++;
+ do
+ {
+ if (lvalue > INT_MAX/1024 || lvalue < INT_MIN/1024)
+ {
+ errno = ERANGE;
+ break;
+ }
+ lvalue *= 1024;
+ }
+ while (*(mp += 2));
+ }
+ }
- if (errno == ERANGE || lvalue > INT_MAX || lvalue < INT_MIN)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
- "absolute value of integer \"%s\" is too large (overflow)", s);
+ if (errno == ERANGE || lvalue > INT_MAX || lvalue < INT_MIN)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
+ "absolute value of integer \"%s\" is too large (overflow)", s);
- while (isspace(*endptr)) endptr++;
- if (*endptr != 0)
- extra_chars_error(endptr, inttype, US"integer value for ", name);
+ while (isspace(*endptr)) endptr++;
+ if (*endptr)
+ extra_chars_error(endptr, inttype, US"integer value for ", name);
- value = (int)lvalue;
- }
+ value = (int)lvalue;
+ }
- if (data_block == NULL)
- *((int *)(ol->value)) = value;
- else
- *((int *)(US data_block + (long int)(ol->value))) = value;
- break;
+ if (data_block)
+ *(int *)(US data_block + ol->v.offset) = value;
+ else
+ *(int *)ol->v.value = value;
+ break;
- /* Integer held in K: again, allow octal and hex formats, and suffixes K, M
- and G. */
- /*XXX consider moving to int_eximarith_t (but mind the overflow test 0415) */
+ /* Integer held in K: again, allow formats and suffixes as above. */
case opt_Kint:
{
uschar *endptr;
errno = 0;
- value = strtol(CS s, CSS &endptr, intbase);
+ int_eximarith_t lvalue = strtol(CS s, CSS &endptr, intbase);
if (endptr == s)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "%sinteger expected for %s",
inttype, name);
- if (errno != ERANGE)
- if (tolower(*endptr) == 'g')
- {
- if (value > INT_MAX/(1024*1024) || value < INT_MIN/(1024*1024))
- errno = ERANGE;
- else
- value *= 1024*1024;
- endptr++;
- }
- else if (tolower(*endptr) == 'm')
- {
- if (value > INT_MAX/1024 || value < INT_MIN/1024)
- errno = ERANGE;
- else
- value *= 1024;
- endptr++;
- }
- else if (tolower(*endptr) == 'k')
- endptr++;
+ if (errno != ERANGE && *endptr)
+ {
+ uschar * mp = US"ZzEePpTtGgMmKk\0"; /* YyZzEePpTtGgMmKk */
+
+ if ((mp = Ustrchr(mp, *endptr)))
+ {
+ endptr++;
+ while (*(mp += 2))
+ {
+ if (lvalue > EXIM_ARITH_MAX/1024 || lvalue < EXIM_ARITH_MIN/1024)
+ {
+ errno = ERANGE;
+ break;
+ }
+ lvalue *= 1024;
+ }
+ }
else
- value = (value + 512)/1024;
+ lvalue = (lvalue + 512)/1024;
+ }
if (errno == ERANGE) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"absolute value of integer \"%s\" is too large (overflow)", s);
while (isspace(*endptr)) endptr++;
if (*endptr != 0)
extra_chars_error(endptr, inttype, US"integer value for ", name);
- }
- if (data_block == NULL)
- *((int *)(ol->value)) = value;
- else
- *((int *)(US data_block + (long int)(ol->value))) = value;
- break;
+ if (data_block)
+ *(int_eximarith_t *)(US data_block + ol->v.offset) = lvalue;
+ else
+ *(int_eximarith_t *)ol->v.value = lvalue;
+ break;
+ }
/* Fixed-point number: held to 3 decimal places. */
case opt_fixed:
- if (sscanf(CS s, "%d%n", &value, &count) != 1)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
- "fixed-point number expected for %s", name);
+ if (sscanf(CS s, "%d%n", &value, &count) != 1)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
+ "fixed-point number expected for %s", name);
- if (value < 0) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
- "integer \"%s\" is too large (overflow)", s);
+ if (value < 0) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
+ "integer \"%s\" is too large (overflow)", s);
- value *= 1000;
+ value *= 1000;
- if (value < 0) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
- "integer \"%s\" is too large (overflow)", s);
+ if (value < 0) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
+ "integer \"%s\" is too large (overflow)", s);
- /* We get a coverity error here for using count, as it derived
- from the tainted buffer pointed to by s, as parsed by sscanf().
- By the definition of sscanf we must be accessing between start
- and end of s (assuming it is nul-terminated...) so ignore the error. */
- /* coverity[tainted_data] */
- if (s[count] == '.')
- {
- int d = 100;
- while (isdigit(s[++count]))
+ /* We get a coverity error here for using count, as it derived
+ from the tainted buffer pointed to by s, as parsed by sscanf().
+ By the definition of sscanf we must be accessing between start
+ and end of s (assuming it is nul-terminated...) so ignore the error. */
+ /* coverity[tainted_data] */
+ if (s[count] == '.')
{
- value += (s[count] - '0') * d;
- d /= 10;
+ int d = 100;
+ while (isdigit(s[++count]))
+ {
+ value += (s[count] - '0') * d;
+ d /= 10;
+ }
}
- }
- while (isspace(s[count])) count++;
+ while (isspace(s[count])) count++;
- if (s[count] != 0)
- extra_chars_error(s+count, US"fixed-point value for ", name, US"");
+ if (s[count] != 0)
+ extra_chars_error(s+count, US"fixed-point value for ", name, US"");
- if (data_block == NULL)
- *((int *)(ol->value)) = value;
- else
- *((int *)(US data_block + (long int)(ol->value))) = value;
- break;
+ if (data_block)
+ *((int *)(US data_block + ol->v.offset)) = value;
+ else
+ *((int *)ol->v.value) = value;
+ break;
/* There's a special routine to read time values. */
case opt_time:
- value = readconf_readtime(s, 0, FALSE);
- if (value < 0)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "invalid time value for %s",
- name);
- if (data_block == NULL)
- *((int *)(ol->value)) = value;
- else
- *((int *)(US data_block + (long int)(ol->value))) = value;
- break;
+ value = readconf_readtime(s, 0, FALSE);
+ if (value < 0)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "invalid time value for %s",
+ name);
+ if (data_block)
+ *((int *)(US data_block + ol->v.offset)) = value;
+ else
+ *((int *)ol->v.value) = value;
+ break;
/* A time list is a list of colon-separated times, with the first
element holding the size of the list and the second the number of
case opt_timelist:
{
int count = 0;
- int *list = (data_block == NULL)?
- (int *)(ol->value) :
- (int *)(US data_block + (long int)(ol->value));
+ int * list = data_block
+ ? (int *)(US data_block + ol->v.offset)
+ : (int *)ol->v.value;
if (*s != 0) for (count = 1; count <= list[0] - 2; count++)
{
}
case opt_func:
- {
- void (*fn)() = ol->value;
- fn(name, s);
+ ol->v.fn(name, s, 0);
break;
- }
}
return TRUE;
int s, m, h, d, w;
uschar *p = time_buffer;
-if (t < 0)
- {
- *p++ = '-';
- t = -t;
- }
+if (t < 0) *p++ = '-', t = -t;
s = t % 60;
t /= 60;
*/
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)
{
/* Non-admin callers cannot see options that have been flagged secure by the
"hide" prefix. */
-if (!admin_user && ol->type & opt_secure)
+if (!f.admin_user && ol->type & opt_secure)
{
if (no_labels)
- printf("%s\n", hidden);
+ printf("%s\n", CCS hidden);
else
- printf("%s = %s\n", name, hidden);
+ printf("%s = %s\n", name, CCS hidden);
return TRUE;
}
/* Else show the value of the option */
-value = ol->value;
+value = ol->v.value;
if (options_block)
{
if (!(ol->type & opt_public))
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:
case opt_Kint:
{
- int x = *((int *)value);
+ int_eximarith_t x = *((int_eximarith_t *)value);
if (!no_labels) printf("%s = ", name);
if (x == 0) printf("0\n");
- else if ((x & 1023) == 0) printf("%dM\n", x >> 10);
- else printf("%dK\n", x);
+ else if ((x & ((1<<30)-1)) == 0) printf(PR_EXIM_ARITH "T\n", x >> 30);
+ else if ((x & ((1<<20)-1)) == 0) printf(PR_EXIM_ARITH "G\n", x >> 20);
+ else if ((x & ((1<<10)-1)) == 0) printf(PR_EXIM_ARITH "M\n", x >> 10);
+ else printf(PR_EXIM_ARITH "K\n", x);
}
break;
sprintf(CS name2, "*expand_%.50s", name);
if ((ol2 = find_option(name2, oltop, last)))
{
- void *value2 = ol2->value;
if (options_block)
- value2 = (void *)(US options_block + (long int)value2);
- s = *(USS value2);
+ s = *USS (US options_block + ol2->v.offset);
+ else
+ s = *USS ol2->v.value;
if (!no_labels) printf("%s = ", name);
printf("%s\n", s ? string_printing(s) : US"");
break;
if ( (ol2 = find_option(name2, oltop, last))
&& (ol2->type & opt_mask) == opt_stringptr)
{
- void *value2 = ol2->value;
if (options_block)
- value2 = (void *)(US options_block + (long int)value2);
- s = *(USS value2);
+ s = *USS (US options_block + ol2->v.offset);
+ else
+ s = *USS ol2->v.value;
if (!no_labels) printf("%s = ", name);
printf("%s\n", s ? string_printing(s) : US"");
break;
if (!no_labels) printf("%s =", name);
if (uidlist)
{
- int i;
uschar sep = no_labels ? '\0' : ' ';
- for (i = 1; i <= (int)(uidlist[0]); i++)
+ for (int i = 1; i <= (int)(uidlist[0]); i++)
{
uschar *name = NULL;
if ((pw = getpwuid(uidlist[i]))) name = US pw->pw_name;
if (!no_labels) printf("%s =", name);
if (gidlist)
{
- int i;
uschar sep = no_labels ? '\0' : ' ';
- for (i = 1; i <= (int)(gidlist[0]); i++)
+ for (int i = 1; i <= (int)(gidlist[0]); i++)
{
uschar *name = NULL;
if ((gr = getgrgid(gidlist[i]))) name = US gr->gr_name;
case opt_timelist:
{
- int i;
int *list = (int *)value;
if (!no_labels) printf("%s = ", name);
- for (i = 0; i < list[1]; i++)
+ for (int i = 0; i < list[1]; i++)
printf("%s%s", i == 0 ? "" : ":", readconf_printtime(list[i+2]));
printf("\n");
}
break;
case opt_bit:
- printf("%s%s\n", ((*((int *)value)) & (1 << ((ol->type >> 16) & 31)))?
- "" : "no_", name);
+ printf("%s%s\n", (*((int *)value)) & (1 << ((ol->type >> 16) & 31))
+ ? "" : "no_", name);
break;
case opt_expand_bool:
sprintf(CS name2, "*expand_%.50s", name);
- if ((ol2 = find_option(name2, oltop, last)) && ol2->value)
+ if ((ol2 = find_option(name2, oltop, last)) && ol2->v.value)
{
- void *value2 = ol2->value;
if (options_block)
- value2 = (void *)(US options_block + (long int)value2);
- s = *(USS value2);
+ s = *USS (US options_block + ol2->v.offset);
+ else
+ s = *USS ol2->v.value;
if (s)
{
if (!no_labels) printf("%s = ", name);
case opt_bool:
case opt_bool_verify:
case opt_bool_set:
- printf("%s%s\n", (*((BOOL *)value))? "" : "no_", name);
+ printf("%s%s\n", *((BOOL *)value) ? "" : "no_", name);
+ break;
+
+ case opt_func:
+ ol->v.fn(name, NULL, no_labels ? opt_fn_print : opt_fn_print|opt_fn_print_label);
break;
}
return TRUE;
*/
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 *ol;
optionlist *ol2 = NULL;
driver_instance *d = NULL;
-macro_item *m;
int size = 0;
if (!type)
{
if (*name == '+')
{
- int i;
tree_node *t;
BOOL found = FALSE;
static uschar *types[] = { US"address", US"domain", US"host",
static tree_node **anchors[] = { &addresslist_anchor, &domainlist_anchor,
&hostlist_anchor, &localpartlist_anchor };
- for (i = 0; i < 4; i++)
+ for (int i = 0; i < 4; i++)
if ((t = tree_search(*(anchors[i]), name+1)))
{
+ namedlist_block * nb = t->data.ptr;
+ const uschar * s = nb->hide ? hidden : nb->string;
found = TRUE;
if (no_labels)
- printf("%s\n", ((namedlist_block *)(t->data.ptr))->string);
+ printf("%s\n", CCS s);
else
- printf("%slist %s = %s\n", types[i], name+1,
- ((namedlist_block *)(t->data.ptr))->string);
+ printf("%slist %s = %s\n", types[i], name+1, CCS s);
}
if (!found)
if (Ustrcmp(name, "all") == 0)
{
- for (ol = optionlist_config;
+ for (optionlist * ol = optionlist_config;
ol < optionlist_config + nelem(optionlist_config); ol++)
if (!(ol->type & opt_hidden))
(void) print_ol(ol, US ol->name, NULL,
printf("local_scan() options are not supported\n");
return FALSE;
#else
- for (ol = local_scan_options;
+ for (optionlist * ol = local_scan_options;
ol < local_scan_options + local_scan_options_count; ol++)
(void) print_ol(ol, US ol->name, NULL, local_scan_options,
local_scan_options_count, no_labels);
if (Ustrcmp(name, "config") == 0)
{
- print_config(admin_user, no_labels);
+ print_config(f.admin_user, no_labels);
return TRUE;
}
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);
}
{
/* People store passwords in macros and they were previously not available
for printing. So we have an admin_users restriction. */
- if (!admin_user)
+ if (!f.admin_user)
{
fprintf(stderr, "exim: permission denied\n");
return FALSE;
}
- for (m = macros; m; m = m->next)
+ for (macro_item * m = macros; m; m = m->next)
if (!name || Ustrcmp(name, m->name) == 0)
{
if (names_only)
printf("%s\n", CS m->name);
+ else if (no_labels)
+ printf("%s\n", CS m->replacement);
else
printf("%s=%s\n", CS m->name, CS m->replacement);
if (name)
printf("\n%s %s:\n", d->name, type);
else if (Ustrcmp(d->name, name) != 0) continue;
- for (ol = ol2; ol < ol2 + size; ol++)
+ for (optionlist * ol = ol2; ol < ol2 + size; ol++)
if (!(ol->type & opt_hidden))
rc |= print_ol(ol, US ol->name, d, ol2, size, no_labels);
- for (ol = d->info->options;
+ for (optionlist * ol = d->info->options;
ol < d->info->options + *(d->info->options_count); ol++)
if (!(ol->type & opt_hidden))
rc |= print_ol(ol, US ol->name, d, d->info->options,
s the text of the option line, starting immediately after the name
of the list type
tname the name of the list type, for messages
+ hide do not output value on "-bP"
Returns: nothing
*/
static void
read_named_list(tree_node **anchorp, int *numberp, int max, uschar *s,
- uschar *tname)
+ uschar *tname, BOOL hide)
{
BOOL forcecache = FALSE;
uschar *ss;
tree_node *t;
-namedlist_block *nb = store_get(sizeof(namedlist_block));
+namedlist_block * nb = store_get_perm(sizeof(namedlist_block), FALSE);
if (Ustrncmp(s, "_cache", 6) == 0)
{
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);
+t = store_get(sizeof(tree_node) + s-ss, 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,
t->data.ptr = nb;
nb->number = *numberp;
*numberp += 1;
+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;
-/*************************************************
-* Drop privs for checking TLS config *
-*************************************************/
-
-/* We want to validate TLS options during readconf, but do not want to be
-root when we call into the TLS library, in case of library linkage errors
-which cause segfaults; before this check, those were always done as the Exim
-runtime user and it makes sense to continue with that.
-
-Assumes: tls_require_ciphers has been set, if it will be
- exim_user has been set, if it will be
- exim_group has been set, if it will be
-
-Returns: bool for "okay"; false will cause caller to immediately exit.
-*/
-
-#ifdef SUPPORT_TLS
-static BOOL
-tls_dropprivs_validate_require_cipher(BOOL nowarn)
-{
-const uschar *errmsg;
-pid_t pid;
-int rc, status;
-void (*oldsignal)(int);
-
-/* If TLS will never be used, no point checking ciphers */
-
-if ( !tls_advertise_hosts
- || !*tls_advertise_hosts
- || Ustrcmp(tls_advertise_hosts, ":") == 0
- )
- return TRUE;
-else if (!nowarn && !tls_certificate)
- log_write(0, LOG_MAIN,
- "Warning: No server certificate defined; will use a selfsigned one.\n"
- " Suggested action: either install a certificate or change tls_advertise_hosts option");
-
-oldsignal = signal(SIGCHLD, SIG_DFL);
-
-fflush(NULL);
-if ((pid = fork()) < 0)
- log_write(0, LOG_MAIN|LOG_PANIC_DIE, "fork failed for TLS check");
-
-if (pid == 0)
- {
- /* in some modes, will have dropped privilege already */
- if (!geteuid())
- exim_setugid(exim_uid, exim_gid, FALSE,
- US"calling tls_validate_require_cipher");
-
- if ((errmsg = tls_validate_require_cipher()))
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
- "tls_require_ciphers invalid: %s", errmsg);
- fflush(NULL);
- _exit(0);
- }
-
-do {
- rc = waitpid(pid, &status, 0);
-} while (rc < 0 && errno == EINTR);
-
-DEBUG(D_tls)
- debug_printf("tls_validate_require_cipher child %d ended: status=0x%x\n",
- (int)pid, status);
-
-signal(SIGCHLD, oldsignal);
-
-return status == 0;
-}
-#endif /* SUPPORT_TLS */
-
-
-
-
/*************************************************
* Read main configuration options *
*************************************************/
/* Loop through the possible file names */
+/* Should never be a tainted list */
while((filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
{
/* Cut out all the fancy processing unless specifically wanted */
- #if defined(CONFIGURE_FILE_USE_NODE) || defined(CONFIGURE_FILE_USE_EUID)
+#if defined(CONFIGURE_FILE_USE_NODE) || defined(CONFIGURE_FILE_USE_EUID)
uschar *suffix = filename + Ustrlen(filename);
/* Try for the node-specific file if a node name exists */
- #ifdef CONFIGURE_FILE_USE_NODE
+# ifdef CONFIGURE_FILE_USE_NODE
struct utsname uts;
if (uname(&uts) >= 0)
{
- #ifdef CONFIGURE_FILE_USE_EUID
+# ifdef CONFIGURE_FILE_USE_EUID
sprintf(CS suffix, ".%ld.%.256s", (long int)original_euid, uts.nodename);
- config_file = Ufopen(filename, "rb");
- if (config_file == NULL)
- #endif /* CONFIGURE_FILE_USE_EUID */
+ if (!(config_file = Ufopen(filename, "rb")))
+# endif /* CONFIGURE_FILE_USE_EUID */
{
sprintf(CS suffix, ".%.256s", uts.nodename);
config_file = Ufopen(filename, "rb");
}
}
- #endif /* CONFIGURE_FILE_USE_NODE */
+# endif /* CONFIGURE_FILE_USE_NODE */
/* Otherwise, try the generic name, possibly with the euid added */
- #ifdef CONFIGURE_FILE_USE_EUID
- if (config_file == NULL)
+# ifdef CONFIGURE_FILE_USE_EUID
+ if (!config_file)
{
sprintf(CS suffix, ".%ld", (long int)original_euid);
config_file = Ufopen(filename, "rb");
}
- #endif /* CONFIGURE_FILE_USE_EUID */
+# endif /* CONFIGURE_FILE_USE_EUID */
/* Finally, try the unadorned name */
- if (config_file == NULL)
+ if (!config_file)
{
*suffix = 0;
config_file = Ufopen(filename, "rb");
}
- #else /* if neither defined */
+#else /* if neither defined */
/* This is the common case when the fancy processing is not included. */
config_file = Ufopen(filename, "rb");
- #endif
+#endif
/* If the file does not exist, continue to try any others. For any other
error, break out (and die). */
- if (config_file != NULL || errno != ENOENT) break;
+ if (config_file || errno != ENOENT) break;
}
/* On success, save the name for verification; config_filename is used when
config_main_directory = last_slash == filename ? US"/" : string_copyn(filename, last_slash - filename);
else
{
- /* relative configuration file name: working dir + / + basename(filename) */
+ /* relative configuration file name: working dir + / + basename(filename) */
- uschar buf[PATH_MAX];
- gstring * g;
+ uschar buf[PATH_MAX];
+ gstring * g;
- if (os_getcwd(buf, PATH_MAX) == NULL)
- {
- perror("exim: getcwd");
- exit(EXIT_FAILURE);
- }
- g = string_cat(NULL, buf);
+ if (os_getcwd(buf, PATH_MAX) == NULL)
+ {
+ perror("exim: getcwd");
+ exit(EXIT_FAILURE);
+ }
+ g = string_cat(NULL, buf);
- /* If the dir does not end with a "/", append one */
- if (g->s[g->ptr-1] != '/')
- g = string_catn(g, US"/", 1);
+ /* If the dir does not end with a "/", append one */
+ if (gstring_last_char(g) != '/')
+ g = string_catn(g, US"/", 1);
- /* If the config file contains a "/", extract the directory part */
- if (last_slash)
- g = string_catn(g, filename, last_slash - filename);
+ /* If the config file contains a "/", extract the directory part */
+ if (last_slash)
+ g = string_catn(g, filename, last_slash - filename);
- config_main_directory = string_from_gstring(g);
+ config_main_directory = string_from_gstring(g);
}
config_directory = config_main_directory;
}
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
to a safe place. Later we change to $spool_directory. */
/* Check the status of the file we have opened, if we have retained root
privileges and the file isn't /dev/null (which *should* be 0666). */
-if (trusted_config && Ustrcmp(filename, US"/dev/null"))
+if (f.trusted_config && Ustrcmp(filename, US"/dev/null"))
{
if (fstat(fileno(config_file), &statbuf) != 0)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to stat configuration file %s",
big_buffer);
- if ((statbuf.st_uid != root_uid /* owner not root */
- #ifdef CONFIGURE_OWNER
- && statbuf.st_uid != config_uid /* owner not the special one */
- #endif
- ) || /* or */
- (statbuf.st_gid != root_gid /* group not root & */
- #ifdef CONFIGURE_GROUP
- && statbuf.st_gid != config_gid /* group not the special one */
- #endif
- && (statbuf.st_mode & 020) != 0) || /* group writeable */
- /* or */
- ((statbuf.st_mode & 2) != 0)) /* world writeable */
-
+ if ( statbuf.st_uid != root_uid /* owner not root */
+#ifdef CONFIGURE_OWNER
+ && statbuf.st_uid != config_uid /* owner not the special one */
+#endif
+ || /* or */
+ statbuf.st_gid != root_gid /* group not root & */
+#ifdef CONFIGURE_GROUP
+ && statbuf.st_gid != config_gid /* group not the special one */
+#endif
+ && (statbuf.st_mode & 020) != 0 /* group writeable */
+ || /* or */
+ (statbuf.st_mode & 2) != 0 /* world writeable */
+ )
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Exim configuration file %s has the "
"wrong owner, group, or mode", big_buffer);
+
+ /* Do a dummy store-allocation of a size related to the (toplevel) file size.
+ This assumes we will need this much storage to handle all the allocations
+ during startup; it won't help when .include is being used. When it does, it
+ will cut down on the number of store blocks (and malloc calls, and sbrk
+ syscalls). It also assume we're on the relevant pool. */
+
+ if (statbuf.st_size > 8192)
+ {
+ rmark r = store_mark();
+ void * dummy = store_get((int)statbuf.st_size, GET_UNTAINTED);
+ store_reset(r);
+ }
}
/* Process the main configuration settings. They all begin with a lower case
while ((s = get_config_line()))
{
+ BOOL hide;
+ uschar * t;
+
if (config_lineno == 1 && Ustrstr(s, "\xef\xbb\xbf") == s)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"found unexpected BOM (Byte Order Mark)");
- if (isupper(s[0]))
- { if (!macro_read_assignment(s)) exim_exit(EXIT_FAILURE, US""); }
+ if (isupper(*s))
+ {
+ if (!macro_read_assignment(s)) exim_exit(EXIT_FAILURE);
+ continue;
+ }
+
+ t = (hide = Ustrncmp(s, "hide", 4) == 0 && isspace(s[4])) ? s + 5 : s;
- else if (Ustrncmp(s, "domainlist", 10) == 0)
+ if (Ustrncmp(t, "domainlist", 10) == 0)
read_named_list(&domainlist_anchor, &domainlist_count,
- MAX_NAMED_LIST, s+10, US"domain list");
+ MAX_NAMED_LIST, t+10, US"domain list", hide);
- else if (Ustrncmp(s, "hostlist", 8) == 0)
+ else if (Ustrncmp(t, "hostlist", 8) == 0)
read_named_list(&hostlist_anchor, &hostlist_count,
- MAX_NAMED_LIST, s+8, US"host list");
+ MAX_NAMED_LIST, t+8, US"host list", hide);
- else if (Ustrncmp(s, US"addresslist", 11) == 0)
+ else if (Ustrncmp(t, "addresslist", 11) == 0)
read_named_list(&addresslist_anchor, &addresslist_count,
- MAX_NAMED_LIST, s+11, US"address list");
+ MAX_NAMED_LIST, t+11, US"address list", hide);
- else if (Ustrncmp(s, US"localpartlist", 13) == 0)
+ else if (Ustrncmp(t, "localpartlist", 13) == 0)
read_named_list(&localpartlist_anchor, &localpartlist_count,
- MAX_NAMED_LIST, s+13, US"local part list");
+ MAX_NAMED_LIST, t+13, US"local part list", hide);
else
(void) readconf_handle_option(s, optionlist_config, optionlist_config_size,
/* If the timezone string is empty, set it to NULL, implying no TZ variable
wanted. */
-if (timezone_string != NULL && *timezone_string == 0) timezone_string = NULL;
+if (timezone_string && !*timezone_string) timezone_string = NULL;
/* The max retry interval must not be greater than 24 hours. */
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;
got set above. Of course, writing to the log may not work if log_file_path is
not set, but it will at least get to syslog or somewhere, with any luck. */
-if (*spool_directory == 0)
+if (!*spool_directory)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "spool_directory undefined: cannot "
"proceed");
/* Expand the spool directory name; it may, for example, contain the primary
host name. Same comment about failure. */
-s = expand_string(spool_directory);
-if (s == NULL)
+if (!(s = expand_string(spool_directory)))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand spool_directory "
"\"%s\": %s", spool_directory, expand_string_message);
spool_directory = s;
the null string or "syslog". It is also allowed to contain one instance of %D
or %M. However, it must NOT contain % followed by anything else. */
-if (*log_file_path != 0)
+if (*log_file_path)
{
const uschar *ss, *sss;
int sep = ':'; /* Fixed for log file path */
- s = expand_string(log_file_path);
- if (s == NULL)
+ if (!(s = expand_string(log_file_path)))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand log_file_path "
"\"%s\": %s", log_file_path, expand_string_message);
ss = s;
- while ((sss = string_nextinlist(&ss,&sep,big_buffer,big_buffer_size)) != NULL)
+ /* should never be a tainted list */
+ while ((sss = string_nextinlist(&ss, &sep, big_buffer, big_buffer_size)))
{
uschar *t;
if (sss[0] == 0 || Ustrcmp(sss, "syslog") == 0) continue;
- t = Ustrstr(sss, "%s");
- if (t == NULL)
+ if (!(t = Ustrstr(sss, "%s")))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "log_file_path \"%s\" does not "
"contain \"%%s\"", sss);
*t = 'X';
- t = Ustrchr(sss, '%');
- if (t != NULL)
- {
+ if ((t = Ustrchr(sss, '%')))
if ((t[1] != 'D' && t[1] != 'M') || Ustrchr(t+2, '%') != NULL)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "log_file_path \"%s\" contains "
"unexpected \"%%\" character", s);
- }
}
log_file_path = s;
/* Expand pid_file_path */
-if (*pid_file_path != 0)
+if (*pid_file_path)
{
if (!(s = expand_string(pid_file_path)))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand pid_file_path "
/* Set default value of process_log_path */
-if (!process_log_path || *process_log_path =='\0')
+if (!process_log_path || !*process_log_path)
process_log_path = string_sprintf("%s/exim-process.info", spool_directory);
/* Compile the regex for matching a UUCP-style "From_" line in an incoming
message. */
-regex_From = regex_must_compile(uucp_from_pattern, FALSE, TRUE);
+regex_From = regex_must_compile(uucp_from_pattern, MCS_NOFLAGS, TRUE);
/* Unpick the SMTP rate limiting options, if set */
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"error in errors_reply_to (%s): %s", errors_reply_to, errmess);
- if (domain == 0)
+ if (!domain)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"errors_reply_to (%s) does not contain a domain", errors_reply_to);
}
/* If smtp_accept_queue or smtp_accept_max_per_host is set, then
smtp_accept_max must also be set. */
-if (smtp_accept_max == 0 &&
- (smtp_accept_queue > 0 || smtp_accept_max_per_host != NULL))
+if (smtp_accept_max == 0 && (smtp_accept_queue > 0 || smtp_accept_max_per_host))
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"smtp_accept_max must be set if smtp_accept_queue or "
"smtp_accept_max_per_host is set");
host_number_string, expand_string_message);
n = Ustrtol(s, &end, 0);
while (isspace(*end)) end++;
- if (*end != 0)
+ if (*end)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"localhost_number value is not a number: %s", s);
if (n > LOCALHOST_MAX)
host_number = n;
}
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
/* If tls_verify_hosts is set, tls_verify_certificates must also be set */
if ((tls_verify_hosts || tls_try_verify_hosts) && !tls_verify_certificates)
"tls_%sverify_hosts is set, but tls_verify_certificates is not set",
tls_verify_hosts ? "" : "try_");
-/* This also checks that the library linkage is working and we can call
-routines in it, so call even if tls_require_ciphers is unset */
-if (!tls_dropprivs_validate_require_cipher(nowarn))
- exit(1);
-
/* Magic number: at time of writing, 1024 has been the long-standing value
used by so many clients, and what Exim used to use always, that it makes
sense to just min-clamp this max-clamp at that. */
"openssl_options parse error: %s", openssl_options);
# endif
}
-#endif /*SUPPORT_TLS*/
+#endif /*DISABLE_TLS*/
if (!nowarn && !keep_environment && environ && *environ)
log_write(0, LOG_MAIN,
init_driver(driver_instance *d, driver_info *drivers_available,
int size_of_info, uschar *class)
{
-driver_info *dd;
-
-for (dd = drivers_available; dd->driver_name[0] != 0;
+for (driver_info * dd = drivers_available; dd->driver_name[0] != 0;
dd = (driver_info *)((US dd) + size_of_info))
- {
if (Ustrcmp(d->driver_name, dd->driver_name) == 0)
{
- int i;
int len = dd->options_len;
d->info = dd;
- d->options_block = store_get(len);
+ d->options_block = store_get_perm(len, FALSE);
memcpy(d->options_block, dd->options_block, len);
- for (i = 0; i < *(dd->options_count); i++)
+ for (int i = 0; i < *(dd->options_count); i++)
dd->options[i].type &= ~opt_set;
return dd;
}
- }
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"%s %s: cannot find %s driver \"%s\"", class, d->name, class, d->driver_name);
+static void
+driver_init_fini(driver_instance * d, const uschar * class)
+{
+if (!d->driver_name)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
+ "no driver defined for %s \"%s\"", class, d->name);
+(d->info->init)(d);
+}
+
+
/*************************************************
* Initialize driver list *
*************************************************/
optionlist *driver_optionlist,
int driver_optionlist_count)
{
-driver_instance **p = anchor;
-driver_instance *d = NULL;
-uschar *buffer;
+driver_instance ** p = anchor;
+driver_instance * d = NULL;
+uschar * buffer;
-while ((buffer = get_config_line()) != NULL)
+while ((buffer = get_config_line()))
{
- uschar name[64];
- uschar *s;
+ uschar name[EXIM_DRIVERNAME_MAX];
+ const uschar * s;
/* Read the first name on the line and test for the start of a new driver. A
macro definition indicates the end of the previous driver. If this isn't the
{
if (d)
{
- if (!d->driver_name)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
- "no driver defined for %s \"%s\"", class, d->name);
- (d->info->init)(d);
+ /* s is using big_buffer, so this call had better not */
+ driver_init_fini(d, class);
d = NULL;
}
- if (!macro_read_assignment(buffer)) exim_exit(EXIT_FAILURE, US"");
+ if (!macro_read_assignment(buffer)) exim_exit(EXIT_FAILURE);
continue;
}
if (*s++ == ':')
{
- int i;
-
/* Finish off initializing the previous driver. */
if (d)
- {
- if (!d->driver_name)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
- "no driver defined for %s \"%s\"", class, d->name);
- (d->info->init)(d);
- }
+ driver_init_fini(d, class);
/* Check that we haven't already got a driver of this name */
/* Set up a new driver instance data block on the chain, with
its default values installed. */
- d = store_get(instance_size);
+ d = store_get_perm(instance_size, FALSE);
memcpy(d, instance_default, instance_size);
*p = d;
p = &d->next;
d->name = string_copy(name);
+ d->srcfile = config_filename;
+ d->srcline = config_lineno;
/* Clear out the "set" bits in the generic options */
- for (i = 0; i < driver_optionlist_count; i++)
+ for (int i = 0; i < driver_optionlist_count; i++)
driver_optionlist[i].type &= ~opt_set;
/* Check nothing more on this line, then do the next loop iteration. */
- while (isspace(*s)) s++;
- if (*s != 0) extra_chars_error(s, US"driver name ", name, US"");
+ Uskip_whitespace(&s);
+ if (*s) extra_chars_error(s, US"driver name ", name, US"");
continue;
}
/* Run the initialization function for the final driver. */
if (d)
- {
- if (!d->driver_name)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
- "no driver defined for %s \"%s\"", class, d->name);
- (d->info->init)(d);
- }
+ driver_init_fini(d, class);
}
readconf_depends(driver_instance *d, uschar *s)
{
int count = *(d->info->options_count);
-optionlist *ol;
uschar *ss;
-for (ol = d->info->options; ol < d->info->options + count; ol++)
- {
- void *options_block;
- uschar *value;
- int type = ol->type & opt_mask;
- if (type != opt_stringptr) continue;
- options_block = ((ol->type & opt_public) == 0)? d->options_block : (void *)d;
- value = *(uschar **)(US options_block + (long int)(ol->value));
- if (value != NULL && (ss = Ustrstr(value, s)) != NULL)
+for (optionlist * ol = d->info->options; ol < d->info->options + count; ol++)
+ if ((ol->type & opt_mask) == opt_stringptr)
{
- if (ss <= value || (ss[-1] != '$' && ss[-1] != '{') ||
- isalnum(ss[Ustrlen(s)])) continue;
- DEBUG(D_transport) debug_printf("driver %s: \"%s\" option depends on %s\n",
- d->name, ol->name, s);
- return TRUE;
+ void * options_block = ol->type & opt_public ? (void *)d : d->options_block;
+ uschar * value = *USS(US options_block + ol->v.offset);
+
+ if (value && (ss = Ustrstr(value, s)) != NULL)
+ {
+ if (ss <= value || (ss[-1] != '$' && ss[-1] != '{') ||
+ isalnum(ss[Ustrlen(s)])) continue;
+ DEBUG(D_transport) debug_printf("driver %s: \"%s\" option depends on %s\n",
+ d->name, ol->name, s);
+ return TRUE;
+ }
}
- }
DEBUG(D_transport) debug_printf("driver %s does not depend on %s\n", d->name, s);
return FALSE;
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++;
const uschar *pp;
uschar *error;
- next = store_get(sizeof(retry_config));
+ next = store_get(sizeof(retry_config), GET_UNTAINTED);
next->next = NULL;
*chain = next;
chain = &(next->next);
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));
+ retry_rule * rule = store_get(sizeof(retry_rule), GET_UNTAINTED);
*rchain = rule;
rchain = &(rule->next);
rule->next = NULL;
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");
}
}
static void
auths_init(void)
{
-auth_instance *au, *bu;
+#ifndef DISABLE_PIPE_CONNECT
+int nauths = 0;
+#endif
readconf_driver_init(US"authenticator",
(driver_instance **)(&auths), /* chain anchor */
optionlist_auths, /* generic options */
optionlist_auths_size);
-for (au = auths; au; au = au->next)
+for (auth_instance * au = auths; au; au = au->next)
{
if (!au->public_name)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "no public name specified for "
"the %s authenticator", au->name);
- for (bu = au->next; bu; bu = bu->next)
+ for (auth_instance * bu = au->next; bu; bu = bu->next)
if (strcmpic(au->public_name, bu->public_name) == 0)
- if ((au->client && bu->client) || (au->server && bu->server))
+ if ( au->client && bu->client
+ || au->server && bu->server)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "two %s authenticators "
"(%s and %s) have the same public name (%s)",
- au->client ? US"client" : US"server", au->name, bu->name,
- au->public_name);
+ au->client && bu->client ? US"client" : US"server",
+ au->name, bu->name, au->public_name);
+#ifndef DISABLE_PIPE_CONNECT
+ nauths++;
+#endif
}
+#ifndef DISABLE_PIPE_CONNECT
+f.smtp_in_early_pipe_no_auth = nauths > 16;
+#endif
+}
+
+
+/* For error messages, a string describing the config location associated
+with current processing. NULL if we are not in an authenticator. */
+
+uschar *
+authenticator_current_name(void)
+{
+if (!authenticator_name) return NULL;
+return string_sprintf(" (authenticator %s, %s %d)", authenticator_name, driver_srcfile, driver_srcline);
}
+
/*************************************************
* Read ACL information *
*************************************************/
static void
readconf_acl(void)
{
-uschar *p;
-
/* Read each ACL and add it into the tree. Macro (re)definitions are allowed
between ACLs. */
while(acl_line)
{
- uschar name[64];
- tree_node *node;
- uschar *error;
+ uschar name[EXIM_DRIVERNAME_MAX];
+ tree_node * node;
+ uschar * error;
+ const uschar * p = readconf_readname(name, sizeof(name), acl_line);
- 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;
}
if (*p != ':' || name[0] == 0)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "missing or malformed ACL name");
- node = store_get(sizeof(tree_node) + Ustrlen(name));
+ node = store_get_perm(sizeof(tree_node) + Ustrlen(name), name);
Ustrcpy(node->name, name);
if (!tree_insertnode(&acl_anchor, node))
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
uschar *p;
while ((p = get_config_line()))
- {
(void) readconf_handle_option(p, local_scan_options, local_scan_options_count,
NULL, US"local_scan option \"%s\" unknown");
- }
#endif
}
int mid = last/2;
int n = Ustrlen(next_section);
- if (tolower(next_section[n-1]) != 's') Ustrcpy(next_section+n, "s");
+ if (tolower(next_section[n-1]) != 's') Ustrcpy(next_section+n, US"s");
for (;;)
{
readconf_save_config(const uschar *s)
{
save_config_line(string_sprintf("# Exim Configuration (%s)",
- running_in_test_harness ? US"X" : s));
+ f.running_in_test_harness ? US"X" : s));
}
static void
static config_line_item *current;
config_line_item *next;
-next = (config_line_item*) store_get(sizeof(config_line_item));
+next = (config_line_item*) store_get(sizeof(config_line_item), GET_UNTAINTED);
next->line = string_copy(line);
next->next = NULL;
void
print_config(BOOL admin, BOOL terse)
{
-config_line_item *i;
const int TS = terse ? 0 : 2;
int indent = 0;
+rmark r = NULL;
-for (i = config_lines; i; i = i->next)
+for (const config_line_item * i = config_lines; i; i = i->next)
{
- uschar *current;
- uschar *p;
+ uschar * current, * p;
+
+ if (r) store_reset(r);
+ r = store_mark();
/* skip over to the first non-space */
- for (current = i->line; *current && isspace(*current); ++current)
+ for (current = string_copy(i->line); *current && isspace(*current); ++current)
;
- if (*current == '\0')
+ if (!*current)
continue;
/* Collapse runs of spaces. We stop this if we encounter one of the
- * following characters: "'$, as this may indicate careful formatting */
- for (p = current; *p; ++p)
+ following characters: "'$, as this may indicate careful formatting */
+
+ for (p = current; *p; p++) if (isspace(*p))
{
uschar *next;
- if (!isspace(*p)) continue;
if (*p != ' ') *p = ' ';
for (next = p; isspace(*next); ++next)
if ((p = Ustrchr(current, '=')))
{
*p = '\0';
- printf("%*s%s= %s\n", indent, "", current, hidden);
+ printf("%*s%s= %s\n", indent, "", current, CCS hidden);
}
/* e.g.: hide split_spool_directory */
else
- printf("%*s\n", indent, hidden);
+ printf("%*s\n", indent, CCS hidden);
}
else
/* rest is public */
printf("%*s%s\n", indent, "", current);
}
+if (r) store_reset(r);
}
#endif /*!MACRO_PREDEF*/