diff options
Diffstat (limited to '')
-rw-r--r-- | src/global/mail_params.c | 1038 |
1 files changed, 1038 insertions, 0 deletions
diff --git a/src/global/mail_params.c b/src/global/mail_params.c new file mode 100644 index 0000000..81aee73 --- /dev/null +++ b/src/global/mail_params.c @@ -0,0 +1,1038 @@ +/*++ +/* NAME +/* mail_params 3 +/* SUMMARY +/* global mail configuration parameters +/* SYNOPSIS +/* #include <mail_params.h> +/* +/* char *var_myhostname; +/* char *var_mydomain; +/* char *var_myorigin; +/* char *var_mydest; +/* char *var_relayhost; +/* char *var_transit_origin; +/* char *var_transit_dest; +/* char *var_mail_name; +/* int var_helpful_warnings; +/* char *var_syslog_name; +/* char *var_mail_owner; +/* uid_t var_owner_uid; +/* gid_t var_owner_gid; +/* char *var_sgid_group; +/* gid_t var_sgid_gid; +/* char *var_default_privs; +/* uid_t var_default_uid; +/* gid_t var_default_gid; +/* char *var_config_dir; +/* char *var_daemon_dir; +/* char *var_data_dir; +/* char *var_command_dir; +/* char *var_meta_dir; +/* char *var_queue_dir; +/* char *var_shlib_dir; +/* int var_use_limit; +/* int var_idle_limit; +/* int var_event_drain; +/* int var_bundle_rcpt; +/* char *var_procname; +/* char *var_servname; +/* int var_pid; +/* int var_ipc_timeout; +/* char *var_pid_dir; +/* int var_dont_remove; +/* char *var_inet_interfaces; +/* char *var_proxy_interfaces; +/* char *var_inet_protocols; +/* char *var_mynetworks; +/* char *var_double_bounce_sender; +/* int var_line_limit; +/* char *var_alias_db_map; +/* long var_message_limit; +/* char *var_mail_release; +/* char *var_mail_version; +/* int var_ipc_idle_limit; +/* int var_ipc_ttl_limit; +/* char *var_db_type; +/* char *var_hash_queue_names; +/* int var_hash_queue_depth; +/* int var_trigger_timeout; +/* char *var_rcpt_delim; +/* int var_fork_tries; +/* int var_fork_delay; +/* int var_flock_tries; +/* int var_flock_delay; +/* int var_flock_stale; +/* int var_disable_dns; +/* int var_soft_bounce; +/* time_t var_starttime; +/* int var_ownreq_special; +/* int var_daemon_timeout; +/* char *var_syslog_facility; +/* char *var_relay_domains; +/* char *var_fflush_domains; +/* char *var_mynetworks_style; +/* char *var_verp_delims; +/* char *var_verp_filter; +/* char *var_par_dom_match; +/* char *var_config_dirs; +/* +/* int var_inet_windowsize; +/* char *var_import_environ; +/* char *var_export_environ; +/* char *var_debug_peer_list; +/* int var_debug_peer_level; +/* int var_in_flow_delay; +/* int var_fault_inj_code; +/* char *var_bounce_service; +/* char *var_cleanup_service; +/* char *var_defer_service; +/* char *var_pickup_service; +/* char *var_queue_service; +/* char *var_rewrite_service; +/* char *var_showq_service; +/* char *var_error_service; +/* char *var_flush_service; +/* char *var_verify_service; +/* char *var_trace_service; +/* char *var_proxymap_service; +/* char *var_proxywrite_service; +/* int var_db_create_buf; +/* int var_db_read_buf; +/* long var_lmdb_map_size; +/* int var_proc_limit; +/* int var_mime_maxdepth; +/* int var_mime_bound_len; +/* int var_header_limit; +/* int var_token_limit; +/* int var_disable_mime_input; +/* int var_disable_mime_oconv; +/* int var_strict_8bitmime; +/* int var_strict_7bit_hdrs; +/* int var_strict_8bit_body; +/* int var_strict_encoding; +/* int var_verify_neg_cache; +/* int var_oldlog_compat; +/* int var_delay_max_res; +/* char *var_int_filt_classes; +/* int var_cyrus_sasl_authzid; +/* +/* char *var_multi_conf_dirs; +/* char *var_multi_wrapper; +/* char *var_multi_group; +/* char *var_multi_name; +/* bool var_multi_enable; +/* bool var_long_queue_ids; +/* bool var_daemon_open_fatal; +/* char *var_dsn_filter; +/* int var_smtputf8_enable +/* int var_strict_smtputf8; +/* char *var_smtputf8_autoclass; +/* int var_idna2003_compat; +/* char *var_compatibility_level; +/* char *var_drop_hdrs; +/* char *var_info_log_addr_form; +/* bool var_enable_orcpt; +/* +/* void mail_params_init() +/* +/* const char null_format_string[1]; +/* +/* long compatibility_level; +/* +/* int warn_compat_break_app_dot_mydomain; +/* int warn_compat_break_smtputf8_enable; +/* int warn_compat_break_chroot; +/* int warn_compat_break_relay_restrictions; +/* +/* int warn_compat_break_relay_domains; +/* int warn_compat_break_flush_domains; +/* int warn_compat_break_mynetworks_style; +/* +/* int warn_compat_break_smtpd_tls_fpt_dgst; +/* int warn_compat_break_smtp_tls_fpt_dgst; +/* int warn_compat_break_lmtp_tls_fpt_dgst; +/* int warn_compat_relay_before_rcpt_checks; +/* int warn_compat_respectful_logging; +/* +/* char *var_maillog_file; +/* char *var_maillog_file_pfxs; +/* char *var_maillog_file_comp; +/* char *var_maillog_file_stamp; +/* char *var_postlog_service; +/* +/* char *var_dnssec_probe; +/* bool var_relay_before_rcpt_checks; +/* bool var_respectful_logging; +/* char *var_known_tcp_ports; +/* DESCRIPTION +/* This module (actually the associated include file) defines +/* the names and defaults of all mail configuration parameters. +/* +/* mail_params_init() initializes the built-in parameters listed above. +/* These parameters are relied upon by library routines, so they are +/* initialized globally so as to avoid hard-to-find errors due to +/* missing initialization. This routine must be called early, at +/* least before entering a chroot jail. +/* +/* null_format_string is a workaround for gcc compilers that complain +/* about empty or null format strings. +/* +/* The warn_compat_XXX variables enable warnings for the use +/* of legacy default settings after an incompatible change. +/* DIAGNOSTICS +/* Fatal errors: out of memory; null system or domain name. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <pwd.h> +#include <grp.h> +#include <time.h> +#include <ctype.h> + +/* Utility library. */ + +#include <msg.h> +#include <msg_syslog.h> +#include <get_hostname.h> +#include <valid_hostname.h> +#include <stringops.h> +#include <safe.h> +#include <safe_open.h> +#include <mymalloc.h> +#include <dict.h> +#include <dict_db.h> +#include <dict_lmdb.h> +#include <inet_proto.h> +#include <vstring_vstream.h> +#include <iostuff.h> +#include <midna_domain.h> + +/* Global library. */ + +#include <mynetworks.h> +#include <mail_conf.h> +#include <mail_version.h> +#include <mail_proto.h> +#include <verp_sender.h> +#include <own_inet_addr.h> +#include <mail_params.h> +#include <compat_level.h> +#include <config_known_tcp_ports.h> + + /* + * Special configuration variables. + */ +char *var_myhostname; +char *var_mydomain; +char *var_myorigin; +char *var_mydest; +char *var_relayhost; +char *var_transit_origin; +char *var_transit_dest; +char *var_mail_name; +int var_helpful_warnings; +char *var_syslog_name; +char *var_mail_owner; +uid_t var_owner_uid; +gid_t var_owner_gid; +char *var_sgid_group; +gid_t var_sgid_gid; +char *var_default_privs; +uid_t var_default_uid; +gid_t var_default_gid; +char *var_config_dir; +char *var_daemon_dir; +char *var_data_dir; +char *var_command_dir; +char *var_meta_dir; +char *var_queue_dir; +char *var_shlib_dir; +int var_use_limit; +int var_event_drain; +int var_idle_limit; +int var_bundle_rcpt; +char *var_procname; +char *var_servname; +int var_pid; +int var_ipc_timeout; +char *var_pid_dir; +int var_dont_remove; +char *var_inet_interfaces; +char *var_proxy_interfaces; +char *var_inet_protocols; +char *var_mynetworks; +char *var_double_bounce_sender; +int var_line_limit; +char *var_alias_db_map; +long var_message_limit; +char *var_mail_release; +char *var_mail_version; +int var_ipc_idle_limit; +int var_ipc_ttl_limit; +char *var_db_type; +char *var_hash_queue_names; +int var_hash_queue_depth; +int var_trigger_timeout; +char *var_rcpt_delim; +int var_fork_tries; +int var_fork_delay; +int var_flock_tries; +int var_flock_delay; +int var_flock_stale; +int var_disable_dns; +int var_soft_bounce; +time_t var_starttime; +int var_ownreq_special; +int var_daemon_timeout; +char *var_syslog_facility; +char *var_relay_domains; +char *var_fflush_domains; +char *var_mynetworks_style; +char *var_verp_delims; +char *var_verp_filter; +int var_in_flow_delay; +char *var_par_dom_match; +char *var_config_dirs; + +int var_inet_windowsize; +char *var_import_environ; +char *var_export_environ; +char *var_debug_peer_list; +int var_debug_peer_level; +int var_fault_inj_code; +char *var_bounce_service; +char *var_cleanup_service; +char *var_defer_service; +char *var_pickup_service; +char *var_queue_service; +char *var_rewrite_service; +char *var_showq_service; +char *var_error_service; +char *var_flush_service; +char *var_verify_service; +char *var_trace_service; +char *var_proxymap_service; +char *var_proxywrite_service; +int var_db_create_buf; +int var_db_read_buf; +long var_lmdb_map_size; +int var_proc_limit; +int var_mime_maxdepth; +int var_mime_bound_len; +int var_header_limit; +int var_token_limit; +int var_disable_mime_input; +int var_disable_mime_oconv; +int var_strict_8bitmime; +int var_strict_7bit_hdrs; +int var_strict_8bit_body; +int var_strict_encoding; +int var_verify_neg_cache; +int var_oldlog_compat; +int var_delay_max_res; +char *var_int_filt_classes; +int var_cyrus_sasl_authzid; + +char *var_multi_conf_dirs; +char *var_multi_wrapper; +char *var_multi_group; +char *var_multi_name; +bool var_multi_enable; +bool var_long_queue_ids; +bool var_daemon_open_fatal; +bool var_dns_ncache_ttl_fix; +char *var_dsn_filter; +int var_smtputf8_enable; +int var_strict_smtputf8; +char *var_smtputf8_autoclass; +int var_idna2003_compat; +char *var_compatibility_level; +char *var_drop_hdrs; +char *var_info_log_addr_form; +bool var_enable_orcpt; + +char *var_maillog_file; +char *var_maillog_file_pfxs; +char *var_maillog_file_comp; +char *var_maillog_file_stamp; +char *var_postlog_service; + +char *var_dnssec_probe; +bool var_respectful_logging; +char *var_known_tcp_ports; + +const char null_format_string[1] = ""; + + /* + * Compatibility level 3.6. + */ +int warn_compat_break_smtpd_tls_fpt_dgst; +int warn_compat_break_smtp_tls_fpt_dgst; +int warn_compat_break_lmtp_tls_fpt_dgst; +int warn_compat_relay_before_rcpt_checks; +int warn_compat_respectful_logging; + + /* + * Compatibility level 2. + */ +int warn_compat_break_relay_domains; +int warn_compat_break_flush_domains; +int warn_compat_break_mynetworks_style; + + /* + * Compatibility level 1. + */ +int warn_compat_break_app_dot_mydomain; +int warn_compat_break_smtputf8_enable; +int warn_compat_break_chroot; +int warn_compat_break_relay_restrictions; + + /* + * Parsed from var_compatibility_level; + */ +long compat_level; + +/* check_myhostname - lookup hostname and validate */ + +static const char *check_myhostname(void) +{ + static const char *name; + const char *dot; + const char *domain; + + /* + * Use cached result. + */ + if (name) + return (name); + + /* + * If the local machine name is not in FQDN form, try to append the + * contents of $mydomain. Use a default domain as a final workaround. + * + * DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - IT MAKES EVERY POSTFIX + * PROGRAM HANG WHEN DNS SERVICE IS UNAVAILABLE. IF YOU DON'T LIKE THE + * DEFAULT, THEN EDIT MAIN.CF. + */ + name = get_hostname(); + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ + if ((dot = strchr(name, '.')) == 0) { + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ + if ((domain = mail_conf_lookup_eval(VAR_MYDOMAIN)) == 0) + domain = DEF_MYDOMAIN; + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ + name = concatenate(name, ".", domain, (char *) 0); + } + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ + return (name); +} + +/* check_mydomainname - lookup domain name and validate */ + +static const char *check_mydomainname(void) +{ + char *dot; + + /* + * Use a default domain when the hostname is not a FQDN ("foo"). + * + * DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - IT MAKES EVERY POSTFIX + * PROGRAM HANG WHEN DNS SERVICE IS UNAVAILABLE. IF YOU DON'T LIKE THE + * DEFAULT, THEN EDIT MAIN.CF. + */ + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ + if ((dot = strchr(var_myhostname, '.')) == 0) + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ + return (DEF_MYDOMAIN); + /* DO NOT CALL GETHOSTBYNAME OR GETNAMEINFO HERE - EDIT MAIN.CF */ + return (dot + 1); +} + +/* check_default_privs - lookup default user attributes and validate */ + +static void check_default_privs(void) +{ + struct passwd *pwd; + + if ((pwd = getpwnam(var_default_privs)) == 0) + msg_fatal("file %s/%s: parameter %s: unknown user name value: %s", + var_config_dir, MAIN_CONF_FILE, + VAR_DEFAULT_PRIVS, var_default_privs); + if ((var_default_uid = pwd->pw_uid) == 0) + msg_fatal("file %s/%s: parameter %s: user %s has privileged user ID", + var_config_dir, MAIN_CONF_FILE, + VAR_DEFAULT_PRIVS, var_default_privs); + if ((var_default_gid = pwd->pw_gid) == 0) + msg_fatal("file %s/%s: parameter %s: user %s has privileged group ID", + var_config_dir, MAIN_CONF_FILE, + VAR_DEFAULT_PRIVS, var_default_privs); +} + +/* check_mail_owner - lookup owner user attributes and validate */ + +static void check_mail_owner(void) +{ + struct passwd *pwd; + + if ((pwd = getpwnam(var_mail_owner)) == 0) + msg_fatal("file %s/%s: parameter %s: unknown user name value: %s", + var_config_dir, MAIN_CONF_FILE, + VAR_MAIL_OWNER, var_mail_owner); + if ((var_owner_uid = pwd->pw_uid) == 0) + msg_fatal("file %s/%s: parameter %s: user %s has privileged user ID", + var_config_dir, MAIN_CONF_FILE, + VAR_MAIL_OWNER, var_mail_owner); + if ((var_owner_gid = pwd->pw_gid) == 0) + msg_fatal("file %s/%s: parameter %s: user %s has privileged group ID", + var_config_dir, MAIN_CONF_FILE, + VAR_MAIL_OWNER, var_mail_owner); + + /* + * This detects only some forms of sharing. Enumerating the entire + * password file name space could be expensive. The purpose of this code + * is to discourage user ID sharing by developers and package + * maintainers. + */ + if ((pwd = getpwuid(var_owner_uid)) != 0 + && strcmp(pwd->pw_name, var_mail_owner) != 0) + msg_fatal("file %s/%s: parameter %s: user %s has same user ID as %s", + var_config_dir, MAIN_CONF_FILE, + VAR_MAIL_OWNER, var_mail_owner, pwd->pw_name); +} + +/* check_sgid_group - lookup setgid group attributes and validate */ + +static void check_sgid_group(void) +{ + struct group *grp; + + if ((grp = getgrnam(var_sgid_group)) == 0) + msg_fatal("file %s/%s: parameter %s: unknown group name: %s", + var_config_dir, MAIN_CONF_FILE, + VAR_SGID_GROUP, var_sgid_group); + if ((var_sgid_gid = grp->gr_gid) == 0) + msg_fatal("file %s/%s: parameter %s: group %s has privileged group ID", + var_config_dir, MAIN_CONF_FILE, + VAR_SGID_GROUP, var_sgid_group); + + /* + * This detects only some forms of sharing. Enumerating the entire group + * file name space could be expensive. The purpose of this code is to + * discourage group ID sharing by developers and package maintainers. + */ + if ((grp = getgrgid(var_sgid_gid)) != 0 + && strcmp(grp->gr_name, var_sgid_group) != 0) + msg_fatal("file %s/%s: parameter %s: group %s has same group ID as %s", + var_config_dir, MAIN_CONF_FILE, + VAR_SGID_GROUP, var_sgid_group, grp->gr_name); +} + +/* check_overlap - disallow UID or GID sharing */ + +static void check_overlap(void) +{ + if (strcmp(var_default_privs, var_mail_owner) == 0) + msg_fatal("file %s/%s: parameters %s and %s specify the same user %s", + var_config_dir, MAIN_CONF_FILE, + VAR_DEFAULT_PRIVS, VAR_MAIL_OWNER, + var_default_privs); + if (var_default_uid == var_owner_uid) + msg_fatal("file %s/%s: parameters %s and %s: users %s and %s have the same user ID: %ld", + var_config_dir, MAIN_CONF_FILE, + VAR_DEFAULT_PRIVS, VAR_MAIL_OWNER, + var_default_privs, var_mail_owner, + (long) var_owner_uid); + if (var_default_gid == var_owner_gid) + msg_fatal("file %s/%s: parameters %s and %s: users %s and %s have the same group ID: %ld", + var_config_dir, MAIN_CONF_FILE, + VAR_DEFAULT_PRIVS, VAR_MAIL_OWNER, + var_default_privs, var_mail_owner, + (long) var_owner_gid); + if (var_default_gid == var_sgid_gid) + msg_fatal("file %s/%s: parameters %s and %s: user %s and group %s have the same group ID: %ld", + var_config_dir, MAIN_CONF_FILE, + VAR_DEFAULT_PRIVS, VAR_SGID_GROUP, + var_default_privs, var_sgid_group, + (long) var_sgid_gid); + if (var_owner_gid == var_sgid_gid) + msg_fatal("file %s/%s: parameters %s and %s: user %s and group %s have the same group ID: %ld", + var_config_dir, MAIN_CONF_FILE, + VAR_MAIL_OWNER, VAR_SGID_GROUP, + var_mail_owner, var_sgid_group, + (long) var_sgid_gid); +} + +#ifdef MYORIGIN_FROM_FILE + +/* read_param_from_file - read parameter value from file */ + +static char *read_param_from_file(const char *path) +{ + VSTRING *why = vstring_alloc(100); + VSTRING *buf = vstring_alloc(100); + VSTREAM *fp; + char *bp; + char *result; + + /* + * Ugly macros to make complex expressions less unreadable. + */ +#define SKIP(start, var, cond) do { \ + for (var = start; *var && (cond); var++) \ + /* void */; \ + } while (0) + +#define TRIM(s) do { \ + char *p; \ + for (p = (s) + strlen(s); p > (s) && ISSPACE(p[-1]); p--) \ + /* void */; \ + *p = 0; \ + } while (0) + + fp = safe_open(path, O_RDONLY, 0, (struct stat *) 0, -1, -1, why); + if (fp == 0) + msg_fatal("%s: %s", path, vstring_str(why)); + vstring_get_nonl(buf, fp); + if (vstream_ferror(fp)) /* FIX 20070501 */ + msg_fatal("%s: read error: %m", path); + vstream_fclose(fp); + SKIP(vstring_str(buf), bp, ISSPACE(*bp)); + TRIM(bp); + result = mystrdup(bp); + + vstring_free(why); + vstring_free(buf); + return (result); +} + +#endif + +/* check_legacy_defaults - flag parameters that require safety-net logging */ + +static void check_legacy_defaults(void) +{ + + /* + * Basic idea: when an existing parameter default is changed, or a new + * parameter is introduced with incompatible default behavior, force + * Postfix to run with backwards-compatible default settings and log a + * warning when the backwards-compatible behavior is used. + * + * Based on a review of Postfix logging the system administrator can decide + * whether or not to make backwards-compatible default settings permanent + * in main.cf or master.cf. + * + * To turn off further warnings and deploy the new default settings, the + * system administrator should update the compatibility_level setting as + * recommended in the RELEASE_NOTES file. + * + * Each incompatible change has its own flag variable, instead of bit in a + * shared variable. We don't want to rip up code when we need more flag + * bits. + */ + + /* + * Look for specific parameters whose default changed when the + * compatibility level changed to 3.6. + */ + if (compat_level < compat_level_from_string(COMPAT_LEVEL_3_6, msg_panic)) { + if (mail_conf_lookup(VAR_SMTPD_TLS_FPT_DGST) == 0) + warn_compat_break_smtpd_tls_fpt_dgst = 1; + if (mail_conf_lookup(VAR_SMTP_TLS_FPT_DGST) == 0) + warn_compat_break_smtp_tls_fpt_dgst = 1; + if (mail_conf_lookup(VAR_LMTP_TLS_FPT_DGST) == 0) + warn_compat_break_lmtp_tls_fpt_dgst = 1; + if (mail_conf_lookup(VAR_RELAY_BEFORE_RCPT_CHECKS) == 0) + warn_compat_relay_before_rcpt_checks = 1; + if (mail_conf_lookup(VAR_RESPECTFUL_LOGGING) == 0) + warn_compat_respectful_logging = 1; + } + + /* + * Look for specific parameters whose default changed when the + * compatibility level changed to 2. + */ + if (compat_level < compat_level_from_string(COMPAT_LEVEL_2, msg_panic)) { + if (mail_conf_lookup(VAR_RELAY_DOMAINS) == 0) { + warn_compat_break_relay_domains = 1; + if (mail_conf_lookup(VAR_FFLUSH_DOMAINS) == 0) + warn_compat_break_flush_domains = 1; + } + if (mail_conf_lookup(VAR_MYNETWORKS) == 0 + && mail_conf_lookup(VAR_MYNETWORKS_STYLE) == 0) + warn_compat_break_mynetworks_style = 1; + } + + /* + * Look for specific parameters whose default changed when the + * compatibility level changed from 0 to 1. + */ + if (compat_level < compat_level_from_string(COMPAT_LEVEL_1, msg_panic)) { + if (mail_conf_lookup(VAR_APP_DOT_MYDOMAIN) == 0) + warn_compat_break_app_dot_mydomain = 1; + + /* + * Not: #ifndef NO_EAI. They must configure SMTPUTF8_ENABLE=no if a + * warning message is logged, so that they don't suddenly start to + * lose mail after Postfix is built with EAI support. + */ + if (mail_conf_lookup(VAR_SMTPUTF8_ENABLE) == 0) + warn_compat_break_smtputf8_enable = 1; + warn_compat_break_chroot = 1; + + /* + * Grandfathered in to help sites migrating from Postfix <2.10. + */ + if (mail_conf_lookup(VAR_RELAY_CHECKS) == 0) + warn_compat_break_relay_restrictions = 1; + } +} + +/* mail_params_init - configure built-in parameters */ + +void mail_params_init() +{ + static const CONFIG_STR_TABLE compat_level_defaults[] = { + VAR_COMPAT_LEVEL, DEF_COMPAT_LEVEL, &var_compatibility_level, 0, 0, + 0, + }; + static const CONFIG_STR_TABLE first_str_defaults[] = { + /* $mail_version may appear in other parameters. */ + VAR_MAIL_VERSION, DEF_MAIL_VERSION, &var_mail_version, 1, 0, + VAR_SYSLOG_FACILITY, DEF_SYSLOG_FACILITY, &var_syslog_facility, 1, 0, + VAR_INET_PROTOCOLS, DEF_INET_PROTOCOLS, &var_inet_protocols, 0, 0, + VAR_MULTI_CONF_DIRS, DEF_MULTI_CONF_DIRS, &var_multi_conf_dirs, 0, 0, + /* multi_instance_wrapper may have dependencies but not dependents. */ + VAR_MULTI_GROUP, DEF_MULTI_GROUP, &var_multi_group, 0, 0, + VAR_MULTI_NAME, DEF_MULTI_NAME, &var_multi_name, 0, 0, + VAR_MAILLOG_FILE, DEF_MAILLOG_FILE, &var_maillog_file, 0, 0, + VAR_MAILLOG_FILE_PFXS, DEF_MAILLOG_FILE_PFXS, &var_maillog_file_pfxs, 1, 0, + VAR_MAILLOG_FILE_COMP, DEF_MAILLOG_FILE_COMP, &var_maillog_file_comp, 1, 0, + VAR_MAILLOG_FILE_STAMP, DEF_MAILLOG_FILE_STAMP, &var_maillog_file_stamp, 1, 0, + VAR_POSTLOG_SERVICE, DEF_POSTLOG_SERVICE, &var_postlog_service, 1, 0, + VAR_DNSSEC_PROBE, DEF_DNSSEC_PROBE, &var_dnssec_probe, 0, 0, + VAR_KNOWN_TCP_PORTS, DEF_KNOWN_TCP_PORTS, &var_known_tcp_ports, 0, 0, + 0, + }; + static const CONFIG_BOOL_TABLE first_bool_defaults[] = { + /* read and process the following before opening tables. */ + VAR_DAEMON_OPEN_FATAL, DEF_DAEMON_OPEN_FATAL, &var_daemon_open_fatal, + VAR_DNS_NCACHE_TTL_FIX, DEF_DNS_NCACHE_TTL_FIX, &var_dns_ncache_ttl_fix, + 0, + }; + static const CONFIG_NBOOL_TABLE first_nbool_defaults[] = { + /* read and process the following before opening tables. */ + VAR_SMTPUTF8_ENABLE, DEF_SMTPUTF8_ENABLE, &var_smtputf8_enable, + VAR_IDNA2003_COMPAT, DEF_IDNA2003_COMPAT, &var_idna2003_compat, + VAR_RESPECTFUL_LOGGING, DEF_RESPECTFUL_LOGGING, &var_respectful_logging, + 0, + }; + static const CONFIG_STR_FN_TABLE function_str_defaults[] = { + VAR_MYHOSTNAME, check_myhostname, &var_myhostname, 1, 0, + VAR_MYDOMAIN, check_mydomainname, &var_mydomain, 1, 0, + 0, + }; + static const CONFIG_STR_TABLE other_str_defaults[] = { + VAR_MAIL_NAME, DEF_MAIL_NAME, &var_mail_name, 1, 0, + VAR_SYSLOG_NAME, DEF_SYSLOG_NAME, &var_syslog_name, 1, 0, + VAR_MAIL_OWNER, DEF_MAIL_OWNER, &var_mail_owner, 1, 0, + VAR_SGID_GROUP, DEF_SGID_GROUP, &var_sgid_group, 1, 0, + VAR_MYDEST, DEF_MYDEST, &var_mydest, 0, 0, + VAR_MYORIGIN, DEF_MYORIGIN, &var_myorigin, 1, 0, + VAR_RELAYHOST, DEF_RELAYHOST, &var_relayhost, 0, 0, + VAR_DAEMON_DIR, DEF_DAEMON_DIR, &var_daemon_dir, 1, 0, + VAR_DATA_DIR, DEF_DATA_DIR, &var_data_dir, 1, 0, + VAR_COMMAND_DIR, DEF_COMMAND_DIR, &var_command_dir, 1, 0, + VAR_META_DIR, DEF_META_DIR, &var_meta_dir, 1, 0, + VAR_QUEUE_DIR, DEF_QUEUE_DIR, &var_queue_dir, 1, 0, + VAR_SHLIB_DIR, DEF_SHLIB_DIR, &var_shlib_dir, 1, 0, + VAR_PID_DIR, DEF_PID_DIR, &var_pid_dir, 1, 0, + VAR_INET_INTERFACES, DEF_INET_INTERFACES, &var_inet_interfaces, 0, 0, + VAR_PROXY_INTERFACES, DEF_PROXY_INTERFACES, &var_proxy_interfaces, 0, 0, + VAR_DOUBLE_BOUNCE, DEF_DOUBLE_BOUNCE, &var_double_bounce_sender, 1, 0, + VAR_DEFAULT_PRIVS, DEF_DEFAULT_PRIVS, &var_default_privs, 1, 0, + VAR_ALIAS_DB_MAP, DEF_ALIAS_DB_MAP, &var_alias_db_map, 0, 0, + VAR_MAIL_RELEASE, DEF_MAIL_RELEASE, &var_mail_release, 1, 0, + VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 1, 0, + VAR_HASH_QUEUE_NAMES, DEF_HASH_QUEUE_NAMES, &var_hash_queue_names, 1, 0, + VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 0, + VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0, + VAR_FFLUSH_DOMAINS, DEF_FFLUSH_DOMAINS, &var_fflush_domains, 0, 0, + VAR_EXPORT_ENVIRON, DEF_EXPORT_ENVIRON, &var_export_environ, 0, 0, + VAR_IMPORT_ENVIRON, DEF_IMPORT_ENVIRON, &var_import_environ, 0, 0, + VAR_MYNETWORKS_STYLE, DEF_MYNETWORKS_STYLE, &var_mynetworks_style, 1, 0, + VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0, + VAR_VERP_DELIMS, DEF_VERP_DELIMS, &var_verp_delims, 2, 2, + VAR_VERP_FILTER, DEF_VERP_FILTER, &var_verp_filter, 1, 0, + VAR_PAR_DOM_MATCH, DEF_PAR_DOM_MATCH, &var_par_dom_match, 0, 0, + VAR_CONFIG_DIRS, DEF_CONFIG_DIRS, &var_config_dirs, 0, 0, + VAR_BOUNCE_SERVICE, DEF_BOUNCE_SERVICE, &var_bounce_service, 1, 0, + VAR_CLEANUP_SERVICE, DEF_CLEANUP_SERVICE, &var_cleanup_service, 1, 0, + VAR_DEFER_SERVICE, DEF_DEFER_SERVICE, &var_defer_service, 1, 0, + VAR_PICKUP_SERVICE, DEF_PICKUP_SERVICE, &var_pickup_service, 1, 0, + VAR_QUEUE_SERVICE, DEF_QUEUE_SERVICE, &var_queue_service, 1, 0, + VAR_REWRITE_SERVICE, DEF_REWRITE_SERVICE, &var_rewrite_service, 1, 0, + VAR_SHOWQ_SERVICE, DEF_SHOWQ_SERVICE, &var_showq_service, 1, 0, + VAR_ERROR_SERVICE, DEF_ERROR_SERVICE, &var_error_service, 1, 0, + VAR_FLUSH_SERVICE, DEF_FLUSH_SERVICE, &var_flush_service, 1, 0, + VAR_VERIFY_SERVICE, DEF_VERIFY_SERVICE, &var_verify_service, 1, 0, + VAR_TRACE_SERVICE, DEF_TRACE_SERVICE, &var_trace_service, 1, 0, + VAR_PROXYMAP_SERVICE, DEF_PROXYMAP_SERVICE, &var_proxymap_service, 1, 0, + VAR_PROXYWRITE_SERVICE, DEF_PROXYWRITE_SERVICE, &var_proxywrite_service, 1, 0, + VAR_INT_FILT_CLASSES, DEF_INT_FILT_CLASSES, &var_int_filt_classes, 0, 0, + /* multi_instance_wrapper may have dependencies but not dependents. */ + VAR_MULTI_WRAPPER, DEF_MULTI_WRAPPER, &var_multi_wrapper, 0, 0, + VAR_DSN_FILTER, DEF_DSN_FILTER, &var_dsn_filter, 0, 0, + VAR_SMTPUTF8_AUTOCLASS, DEF_SMTPUTF8_AUTOCLASS, &var_smtputf8_autoclass, 1, 0, + VAR_DROP_HDRS, DEF_DROP_HDRS, &var_drop_hdrs, 0, 0, + VAR_INFO_LOG_ADDR_FORM, DEF_INFO_LOG_ADDR_FORM, &var_info_log_addr_form, 1, 0, + 0, + }; + static const CONFIG_STR_FN_TABLE function_str_defaults_2[] = { + VAR_MYNETWORKS, mynetworks, &var_mynetworks, 0, 0, + 0, + }; + static const CONFIG_INT_TABLE other_int_defaults[] = { + VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0, + VAR_MAX_USE, DEF_MAX_USE, &var_use_limit, 1, 0, + VAR_DONT_REMOVE, DEF_DONT_REMOVE, &var_dont_remove, 0, 0, + VAR_LINE_LIMIT, DEF_LINE_LIMIT, &var_line_limit, 512, 0, + VAR_HASH_QUEUE_DEPTH, DEF_HASH_QUEUE_DEPTH, &var_hash_queue_depth, 1, 0, + VAR_FORK_TRIES, DEF_FORK_TRIES, &var_fork_tries, 1, 0, + VAR_FLOCK_TRIES, DEF_FLOCK_TRIES, &var_flock_tries, 1, 0, + VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0, + VAR_FAULT_INJ_CODE, DEF_FAULT_INJ_CODE, &var_fault_inj_code, 0, 0, + VAR_DB_CREATE_BUF, DEF_DB_CREATE_BUF, &var_db_create_buf, 1, 0, + VAR_DB_READ_BUF, DEF_DB_READ_BUF, &var_db_read_buf, 1, 0, + VAR_HEADER_LIMIT, DEF_HEADER_LIMIT, &var_header_limit, 1, 0, + VAR_TOKEN_LIMIT, DEF_TOKEN_LIMIT, &var_token_limit, 1, 0, + VAR_MIME_MAXDEPTH, DEF_MIME_MAXDEPTH, &var_mime_maxdepth, 1, 0, + VAR_MIME_BOUND_LEN, DEF_MIME_BOUND_LEN, &var_mime_bound_len, 1, 0, + VAR_DELAY_MAX_RES, DEF_DELAY_MAX_RES, &var_delay_max_res, MIN_DELAY_MAX_RES, MAX_DELAY_MAX_RES, + VAR_INET_WINDOW, DEF_INET_WINDOW, &var_inet_windowsize, 0, 0, + 0, + }; + static const CONFIG_LONG_TABLE long_defaults[] = { + VAR_MESSAGE_LIMIT, DEF_MESSAGE_LIMIT, &var_message_limit, 0, 0, + VAR_LMDB_MAP_SIZE, DEF_LMDB_MAP_SIZE, &var_lmdb_map_size, 1, 0, + 0, + }; + static const CONFIG_TIME_TABLE time_defaults[] = { + VAR_EVENT_DRAIN, DEF_EVENT_DRAIN, &var_event_drain, 1, 0, + VAR_MAX_IDLE, DEF_MAX_IDLE, &var_idle_limit, 1, 0, + VAR_IPC_TIMEOUT, DEF_IPC_TIMEOUT, &var_ipc_timeout, 1, 0, + VAR_IPC_IDLE, DEF_IPC_IDLE, &var_ipc_idle_limit, 1, 0, + VAR_IPC_TTL, DEF_IPC_TTL, &var_ipc_ttl_limit, 1, 0, + VAR_TRIGGER_TIMEOUT, DEF_TRIGGER_TIMEOUT, &var_trigger_timeout, 1, 0, + VAR_FORK_DELAY, DEF_FORK_DELAY, &var_fork_delay, 1, 0, + VAR_FLOCK_DELAY, DEF_FLOCK_DELAY, &var_flock_delay, 1, 0, + VAR_FLOCK_STALE, DEF_FLOCK_STALE, &var_flock_stale, 1, 0, + VAR_DAEMON_TIMEOUT, DEF_DAEMON_TIMEOUT, &var_daemon_timeout, 1, 0, + VAR_IN_FLOW_DELAY, DEF_IN_FLOW_DELAY, &var_in_flow_delay, 0, 10, + 0, + }; + static const CONFIG_BOOL_TABLE bool_defaults[] = { + VAR_DISABLE_DNS, DEF_DISABLE_DNS, &var_disable_dns, + VAR_SOFT_BOUNCE, DEF_SOFT_BOUNCE, &var_soft_bounce, + VAR_OWNREQ_SPECIAL, DEF_OWNREQ_SPECIAL, &var_ownreq_special, + VAR_STRICT_8BITMIME, DEF_STRICT_8BITMIME, &var_strict_8bitmime, + VAR_STRICT_7BIT_HDRS, DEF_STRICT_7BIT_HDRS, &var_strict_7bit_hdrs, + VAR_STRICT_8BIT_BODY, DEF_STRICT_8BIT_BODY, &var_strict_8bit_body, + VAR_STRICT_ENCODING, DEF_STRICT_ENCODING, &var_strict_encoding, + VAR_DISABLE_MIME_INPUT, DEF_DISABLE_MIME_INPUT, &var_disable_mime_input, + VAR_DISABLE_MIME_OCONV, DEF_DISABLE_MIME_OCONV, &var_disable_mime_oconv, + VAR_VERIFY_NEG_CACHE, DEF_VERIFY_NEG_CACHE, &var_verify_neg_cache, + VAR_OLDLOG_COMPAT, DEF_OLDLOG_COMPAT, &var_oldlog_compat, + VAR_HELPFUL_WARNINGS, DEF_HELPFUL_WARNINGS, &var_helpful_warnings, + VAR_CYRUS_SASL_AUTHZID, DEF_CYRUS_SASL_AUTHZID, &var_cyrus_sasl_authzid, + VAR_MULTI_ENABLE, DEF_MULTI_ENABLE, &var_multi_enable, + VAR_LONG_QUEUE_IDS, DEF_LONG_QUEUE_IDS, &var_long_queue_ids, + VAR_STRICT_SMTPUTF8, DEF_STRICT_SMTPUTF8, &var_strict_smtputf8, + VAR_ENABLE_ORCPT, DEF_ENABLE_ORCPT, &var_enable_orcpt, + 0, + }; + const char *cp; + + /* + * Extract compatibility level first, so that we can determine what + * parameters of interest are left at their legacy defaults. + */ + if (var_compatibility_level == 0) + compat_level_relop_register(); + get_mail_conf_str_table(compat_level_defaults); + compat_level = compat_level_from_string(var_compatibility_level, msg_fatal); + check_legacy_defaults(); + + /* + * Extract syslog_facility early, so that from here on all errors are + * logged with the proper facility. + */ + get_mail_conf_str_table(first_str_defaults); + + if (!msg_syslog_set_facility(var_syslog_facility)) + msg_fatal("file %s/%s: parameter %s: unrecognized value: %s", + var_config_dir, MAIN_CONF_FILE, + VAR_SYSLOG_FACILITY, var_syslog_facility); + + /* + * Should daemons terminate after table open error, or should they + * continue execution with reduced functionality? + */ + get_mail_conf_bool_table(first_bool_defaults); + if (var_daemon_open_fatal) + dict_allow_surrogate = 0; + + /* + * Should we open tables with UTF8 support, or in the legacy 8-bit clean + * mode with ASCII-only casefolding? + */ + get_mail_conf_nbool_table(first_nbool_defaults); + + /* + * Report run-time versus compile-time discrepancies. + */ +#ifdef NO_EAI + if (var_smtputf8_enable) + msg_warn("%s is true, but EAI support is not compiled in", + VAR_SMTPUTF8_ENABLE); + var_smtputf8_enable = 0; +#else + midna_domain_transitional = var_idna2003_compat; + if (var_smtputf8_enable) + midna_domain_pre_chroot(); +#endif + util_utf8_enable = var_smtputf8_enable; + + /* + * Configure the known TCP port mappings. + */ + config_known_tcp_ports(VAR_KNOWN_TCP_PORTS, var_known_tcp_ports); + + /* + * What protocols should we attempt to support? The result is stored in + * the global inet_proto_table variable. + */ + (void) inet_proto_init(VAR_INET_PROTOCOLS, var_inet_protocols); + + /* + * Variables whose defaults are determined at runtime. Some sites use + * short hostnames in the host table; some sites name their system after + * the domain. + */ + get_mail_conf_str_fn_table(function_str_defaults); + if (!valid_hostname(var_myhostname, DO_GRIPE)) + msg_fatal("file %s/%s: parameter %s: bad parameter value: %s", + var_config_dir, MAIN_CONF_FILE, + VAR_MYHOSTNAME, var_myhostname); + if (!valid_hostname(var_mydomain, DO_GRIPE)) + msg_fatal("file %s/%s: parameter %s: bad parameter value: %s", + var_config_dir, MAIN_CONF_FILE, + VAR_MYDOMAIN, var_mydomain); + + /* + * Variables that are needed by almost every program. + * + * XXX Reading the myorigin value from file is originally a Debian Linux + * feature. This code is not enabled by default because of problems: 1) + * it re-implements its own parameter syntax checks, and 2) it does not + * implement $name expansions. + */ + get_mail_conf_str_table(other_str_defaults); +#ifdef MYORIGIN_FROM_FILE + if (*var_myorigin == '/') { + char *origin = read_param_from_file(var_myorigin); + + if (*origin == 0) + msg_fatal("%s file %s is empty", VAR_MYORIGIN, var_myorigin); + myfree(var_myorigin); /* FIX 20070501 */ + var_myorigin = origin; + } +#endif + get_mail_conf_int_table(other_int_defaults); + get_mail_conf_long_table(long_defaults); + get_mail_conf_bool_table(bool_defaults); + get_mail_conf_time_table(time_defaults); + check_default_privs(); + check_mail_owner(); + check_sgid_group(); + check_overlap(); + dict_db_cache_size = var_db_read_buf; + dict_lmdb_map_size = var_lmdb_map_size; + inet_windowsize = var_inet_windowsize; + + /* + * Variables whose defaults are determined at runtime, after other + * variables have been set. This dependency is admittedly a bit tricky. + * XXX Perhaps we should just register variables, and let the evaluator + * figure out in what order to evaluate things. + */ + get_mail_conf_str_fn_table(function_str_defaults_2); + + /* + * FIX 200412 The IPv6 patch did not call own_inet_addr_list() before + * entering the chroot jail on Linux IPv6 systems. Linux has the IPv6 + * interface list in /proc, which is not available after chrooting. + */ + (void) own_inet_addr_list(); + + /* + * The PID variable cannot be set from the configuration file!! + */ + set_mail_conf_int(VAR_PID, var_pid = getpid()); + + /* + * Neither can the start time variable. It isn't even visible. + */ + time(&var_starttime); + + /* + * Export the syslog name so children can inherit and use it before they + * have initialized. + */ + if ((cp = safe_getenv(CONF_ENV_LOGTAG)) == 0 + || strcmp(cp, var_syslog_name) != 0) + if (setenv(CONF_ENV_LOGTAG, var_syslog_name, 1) < 0) + msg_fatal("setenv %s %s: %m", CONF_ENV_LOGTAG, var_syslog_name); + + /* + * I have seen this happen just too often. + */ + if (strcasecmp_utf8(var_myhostname, var_relayhost) == 0) + msg_fatal("%s and %s parameter settings must not be identical: %s", + VAR_MYHOSTNAME, VAR_RELAYHOST, var_myhostname); + + /* + * XXX These should be caught by a proper parameter parsing algorithm. + */ + if (var_myorigin[strcspn(var_myorigin, CHARS_COMMA_SP)]) + msg_fatal("%s parameter setting must not contain multiple values: %s", + VAR_MYORIGIN, var_myorigin); + + /* + * One more sanity check. + */ + if ((cp = verp_delims_verify(var_verp_delims)) != 0) + msg_fatal("file %s/%s: parameters %s and %s: %s", + var_config_dir, MAIN_CONF_FILE, + VAR_VERP_DELIMS, VAR_VERP_FILTER, cp); +} |