X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Freadconf.c;h=c62235916328e62ff46f5ad3f24359389cb325be;hp=c3514aba5ddac919d3925e0af5c514f519fdf59e;hb=d641a34087b20f3f6026eeaf35ddebfdf70cbf65;hpb=83da1223921fe30362e8374951360dcc8f21c4e7 diff --git a/src/src/readconf.c b/src/src/readconf.c index c3514aba5..c62235916 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -1,10 +1,8 @@ -/* $Cambridge: exim/src/src/readconf.c,v 1.27 2007/01/18 15:35:42 ph10 Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2007 */ +/* Copyright (c) University of Cambridge 1995 - 2009 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions for reading the configuration file, and for displaying @@ -142,6 +140,9 @@ static optionlist optionlist_config[] = { { "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_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 }, @@ -150,6 +151,7 @@ static optionlist optionlist_config[] = { #ifdef WITH_CONTENT_SCAN { "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 }, @@ -190,12 +192,23 @@ static optionlist optionlist_config[] = { { "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 }, +#endif { "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 }, +#endif { "disable_ipv6", opt_bool, &disable_ipv6 }, +#ifndef DISABLE_DKIM + { "dkim_verify_signers", opt_stringptr, &dkim_verify_signers }, +#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 }, @@ -203,9 +216,11 @@ static optionlist optionlist_config[] = { { "dns_ipv4_lookup", opt_stringptr, &dns_ipv4_lookup }, { "dns_retrans", opt_time, &dns_retrans }, { "dns_retry", opt_int, &dns_retry }, + { "dns_use_edns0", opt_int, &dns_use_edns0 }, /* This option is now a no-op, retained for compability */ { "drop_cr", opt_bool, &drop_cr }, /*********************************************************/ + { "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 }, @@ -219,6 +234,7 @@ static optionlist optionlist_config[] = { { "gecos_name", opt_stringptr, &gecos_name }, { "gecos_pattern", opt_stringptr, &gecos_pattern }, #ifdef SUPPORT_TLS + { "gnutls_compat_mode", opt_bool, &gnutls_compat_mode }, { "gnutls_require_kx", opt_stringptr, &gnutls_require_kx }, { "gnutls_require_mac", opt_stringptr, &gnutls_require_mac }, { "gnutls_require_protocols", opt_stringptr, &gnutls_require_proto }, @@ -245,7 +261,14 @@ static optionlist optionlist_config[] = { { "ignore_fromline_local", opt_bool, &ignore_fromline_local }, { "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 }, #endif { "local_from_check", opt_bool, &local_from_check }, @@ -260,6 +283,7 @@ static optionlist optionlist_config[] = { { "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 }, @@ -273,6 +297,9 @@ static optionlist optionlist_config[] = { { "mysql_servers", opt_stringptr, &mysql_servers }, #endif { "never_users", opt_uidlist, &never_users }, +#ifdef SUPPORT_TLS + { "openssl_options", opt_stringptr, &openssl_options }, +#endif #ifdef LOOKUP_ORACLE { "oracle_servers", opt_stringptr, &oracle_servers }, #endif @@ -298,6 +325,7 @@ static optionlist optionlist_config[] = { { "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_int, &queue_run_max }, @@ -344,6 +372,9 @@ static optionlist optionlist_config[] = { { "smtp_return_error_details",opt_bool, &smtp_return_error_details }, #ifdef WITH_CONTENT_SCAN { "spamd_address", opt_stringptr, &spamd_address }, +#endif +#ifdef EXPERIMENTAL_SPF + { "spf_guess", opt_stringptr, &spf_guess }, #endif { "split_spool_directory", opt_bool, &split_spool_directory }, { "spool_directory", opt_stringptr, &spool_directory }, @@ -374,6 +405,9 @@ static optionlist optionlist_config[] = { { "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 }, +#endif { "timeout_frozen_after", opt_time, &timeout_frozen_after }, { "timezone", opt_stringptr, &timezone_string }, #ifdef SUPPORT_TLS @@ -1333,6 +1367,7 @@ uid_t uid; gid_t gid; BOOL boolvalue = TRUE; BOOL freesptr = TRUE; +BOOL extra_condition = FALSE; optionlist *ol, *ol2; struct passwd *pw; void *reset_point; @@ -1340,6 +1375,8 @@ int intbase = 0; uschar *inttype = US""; uschar *sptr; uschar *s = buffer; +uschar *saved_condition, *strtemp; +uschar **str_target; uschar name[64]; uschar name2[64]; @@ -1397,8 +1434,11 @@ if ((ol->type & opt_set) != 0) { uschar *mname = name; if (Ustrncmp(mname, "no_", 3) == 0) mname += 3; - log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, - "\"%s\" option set for the second time", mname); + if (Ustrcmp(mname, "condition") == 0) + extra_condition = TRUE; + else + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, + "\"%s\" option set for the second time", mname); } ol->type |= opt_set | issecure; @@ -1479,6 +1519,39 @@ switch (type) control block and flags word. */ case opt_stringptr: + if (data_block == NULL) + str_target = (uschar **)(ol->value); + else + str_target = (uschar **)((uschar *)data_block + (long int)(ol->value)); + if (extra_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. */ + saved_condition = *str_target; + strtemp = string_sprintf("${if and{{bool_lax{%s}}{bool_lax{%s}}}}", + saved_condition, sptr); + *str_target = string_copy_malloc(strtemp); + /* TODO(pdp): there is a memory leak here 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 + { + *str_target = sptr; + freesptr = FALSE; + } + break; + case opt_rewrite: if (data_block == NULL) *((uschar **)(ol->value)) = sptr; @@ -1825,8 +1898,10 @@ switch (type) case opt_int: { uschar *endptr; + long int lvalue; + errno = 0; - value = strtol(CS s, CSS &endptr, intbase); + lvalue = strtol(CS s, CSS &endptr, intbase); if (endptr == s) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "%sinteger expected for %s", @@ -1836,25 +1911,28 @@ switch (type) { if (tolower(*endptr) == 'k') { - if (value > INT_MAX/1024 || value < INT_MIN/1024) errno = ERANGE; - else value *= 1024; + if (lvalue > INT_MAX/1024 || lvalue < INT_MIN/1024) errno = ERANGE; + else lvalue *= 1024; endptr++; } else if (tolower(*endptr) == 'm') { - if (value > INT_MAX/(1024*1024) || value < INT_MIN/(1024*1024)) + if (lvalue > INT_MAX/(1024*1024) || lvalue < INT_MIN/(1024*1024)) errno = ERANGE; - else value *= 1024*1024; + else lvalue *= 1024*1024; endptr++; } } - if (errno == ERANGE) 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); + + value = (int)lvalue; } if (data_block == NULL) @@ -2340,15 +2418,17 @@ second argument is NULL. There are some special values: routers print the routers' configurations transports print the transports' configuration authenticators print the authenticators' configuration + macros print the macros' configuration router_list print a list of router names transport_list print a list of transport names authenticator_list print a list of authentication mechanism names + macro_list print a list of macro names +name print a named list item local_scan print the local_scan options -If the second argument is not NULL, it must be one of "router", "transport", or -"authenticator" in which case the first argument identifies the driver whose -options are to be printed. +If the second argument is not NULL, it must be one of "router", "transport", +"authenticator" or "macro" in which case the first argument identifies the +driver whose options are to be printed. Arguments: name option name if type == NULL; else driver name @@ -2364,6 +2444,7 @@ BOOL names_only = FALSE; optionlist *ol; optionlist *ol2 = NULL; driver_instance *d = NULL; +macro_item *m; int size = 0; if (type == NULL) @@ -2445,11 +2526,10 @@ if (type == NULL) name = NULL; } - else if (Ustrcmp(name, "authenticator_list") == 0) + else if (Ustrcmp(name, "macros") == 0) { - type = US"authenticator"; + type = US"macro"; name = NULL; - names_only = TRUE; } else if (Ustrcmp(name, "router_list") == 0) @@ -2458,12 +2538,28 @@ if (type == NULL) name = NULL; names_only = TRUE; } + else if (Ustrcmp(name, "transport_list") == 0) { type = US"transport"; name = NULL; names_only = TRUE; } + + else if (Ustrcmp(name, "authenticator_list") == 0) + { + type = US"authenticator"; + name = NULL; + names_only = TRUE; + } + + else if (Ustrcmp(name, "macro_list") == 0) + { + type = US"macro"; + name = NULL; + names_only = TRUE; + } + else { print_ol(find_option(name, optionlist_config, optionlist_config_size), @@ -2497,6 +2593,32 @@ else if (Ustrcmp(type, "authenticator") == 0) size = optionlist_auths_size; } +else if (Ustrcmp(type, "macro") == 0) + { + /* People store passwords in macros and they were previously not available + for printing. So we have an admin_users restriction. */ + if (!admin_user) + { + fprintf(stderr, "exim: permission denied\n"); + exit(EXIT_FAILURE); + } + for (m = macros; m != NULL; m = m->next) + { + if (name == NULL || Ustrcmp(name, m->name) == 0) + { + if (names_only) + printf("%s\n", CS m->name); + else + printf("%s=%s\n", CS m->name, CS m->replacement); + if (name != NULL) + return; + } + } + if (name != NULL) + printf("%s %s not found\n", type, name); + return; + } + if (names_only) { for (; d != NULL; d = d->next) printf("%s\n", CS d->name); @@ -2758,22 +2880,21 @@ else "configuration file %s", filename)); } -/* Check the status of the file we have opened, unless it was specified on -the command line, in which case privilege was given away at the start. */ +/* 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 (!config_changed) +if (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 */ - statbuf.st_uid != exim_uid /* owner not exim */ + 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 != exim_gid /* group not exim & */ + (statbuf.st_gid != root_gid /* group not root & */ #ifdef CONFIGURE_GROUP && statbuf.st_gid != config_gid /* group not the special one */ #endif @@ -2916,8 +3037,8 @@ if (s == NULL) spool_directory = s; /* Expand log_file_path, which must contain "%s" in any component that isn't -the null string or "syslog". It is also allowed to contain one instance of %D. -However, it must NOT contain % followed by anything else. */ +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) { @@ -2941,7 +3062,7 @@ if (*log_file_path != 0) t = Ustrchr(sss, '%'); if (t != NULL) { - if (t[1] != 'D' || Ustrchr(t+2, '%') != NULL) + 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); } @@ -2990,6 +3111,11 @@ if (*pid_file_path != 0) pid_file_path = s; } +/* Set default value of process_log_path */ + +if (process_log_path == NULL || *process_log_path =='\0') + 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. */ @@ -3085,6 +3211,20 @@ if ((tls_verify_hosts != NULL || tls_try_verify_hosts != NULL) && log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "tls_%sverify_hosts is set, but tls_verify_certificates is not set", (tls_verify_hosts != NULL)? "" : "try_"); + +/* If openssl_options is set, validate it */ +if (openssl_options != NULL) + { +# ifdef USE_GNUTLS + log_write(0, LOG_PANIC_DIE|LOG_CONFIG, + "openssl_options is set but we're using GnuTLS"); +# else + long dummy; + if (!(tls_openssl_options_parse(openssl_options, &dummy))) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG, + "openssl_options parse error: %s", openssl_options); +# endif + } #endif }