summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/OS/Makefile-Base79
-rw-r--r--src/exim_monitor/em_version.c13
-rw-r--r--src/src/acl.c51
-rw-r--r--src/src/configure.default3
-rwxr-xr-xsrc/src/convert4r3.src12
-rwxr-xr-xsrc/src/convert4r4.src12
-rw-r--r--src/src/dkim.c282
-rw-r--r--src/src/dkim.h3
-rw-r--r--src/src/exicyclog.src5
-rw-r--r--src/src/exigrep.src10
-rwxr-xr-xsrc/src/exim_checkaccess.src8
-rw-r--r--src/src/eximon.src7
-rw-r--r--src/src/eximstats.src8
-rw-r--r--src/src/exinext.src7
-rw-r--r--src/src/exipick.src9
-rw-r--r--src/src/exiqgrep.src9
-rw-r--r--src/src/exiqsumm.src8
-rw-r--r--src/src/exiwhat.src7
-rw-r--r--src/src/expand.c4
-rw-r--r--src/src/globals.c2
-rw-r--r--src/src/globals.h2
-rw-r--r--src/src/match.c238
-rw-r--r--src/src/pdkim/pdkim.c54
-rw-r--r--src/src/receive.c155
-rw-r--r--src/src/tls-gnu.c56
-rw-r--r--src/src/tls-openssl.c69
-rw-r--r--src/src/transport-filter.src8
27 files changed, 727 insertions, 394 deletions
diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base
index d64ed549f..dcd87c29c 100644
--- a/src/OS/Makefile-Base
+++ b/src/OS/Makefile-Base
@@ -36,9 +36,9 @@ FE = $(FULLECHO)
# are set up, and finally it goes to the main Exim target.
all: utils exim
-config: $(EDITME) checklocalmake Makefile os.c config.h version.h macro.c
+config: $(EDITME) checklocalmake Makefile os.c config.h version.h version.sh macro.c
-checklocalmake:
+checklocalmake:
@if $(SHELL) $(SCRIPTS)/newer $(EDITME)-$(OSTYPE) $(EDITME) || \
$(SHELL) $(SCRIPTS)/newer $(EDITME)-$(ARCHTYPE) $(EDITME) || \
$(SHELL) $(SCRIPTS)/newer $(EDITME)-$(OSTYPE)-$(ARCHTYPE) $(EDITME); \
@@ -260,7 +260,7 @@ buildconfig: buildconfig.c
# Target for the exicyclog utility script
exicyclog: config ../src/exicyclog.src
@rm -f exicyclog
- @sed \
+ @. ./version.sh && sed \
-e "s?PROCESSED_FLAG?This file has been so processed.?"\
-e "/^# /p" \
-e "/^# /d" \
@@ -277,6 +277,8 @@ exicyclog: config ../src/exicyclog.src
-e "s?MV_COMMAND?$(MV_COMMAND)?" \
-e "s?RM_COMMAND?$(RM_COMMAND)?" \
-e "s?TOUCH_COMMAND?$(TOUCH_COMMAND)?" \
+ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
+ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
../src/exicyclog.src > exicyclog-t
@mv exicyclog-t exicyclog
@chmod a+x exicyclog
@@ -285,13 +287,15 @@ exicyclog: config ../src/exicyclog.src
# Target for the exinext utility script
exinext: config ../src/exinext.src
@rm -f exinext
- @sed \
+ @. ./version.sh && sed \
-e "s?PROCESSED_FLAG?This file has been so processed.?"\
-e "/^# /p" \
-e "/^# /d" \
-e "s?CONFIGURE_FILE_USE_NODE?$(CONFIGURE_FILE_USE_NODE)?" \
-e "s?CONFIGURE_FILE?$(CONFIGURE_FILE)?" \
-e "s?BIN_DIRECTORY?$(BIN_DIRECTORY)?" \
+ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
+ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
../src/exinext.src > exinext-t
@mv exinext-t exinext
@chmod a+x exinext
@@ -300,7 +304,7 @@ exinext: config ../src/exinext.src
# Target for the exiwhat utility script
exiwhat: config ../src/exiwhat.src
@rm -f exiwhat
- @sed \
+ @. ./version.sh && sed \
-e "s?PROCESSED_FLAG?This file has been so processed.?"\
-e "/^# /p" \
-e "/^# /d" \
@@ -313,6 +317,8 @@ exiwhat: config ../src/exiwhat.src
-e "s?EXIWHAT_EGREP_ARG?$(EXIWHAT_EGREP_ARG)?" \
-e "s?EXIWHAT_MULTIKILL_CMD?$(EXIWHAT_MULTIKILL_CMD)?" \
-e "s?EXIWHAT_MULTIKILL_ARG?$(EXIWHAT_MULTIKILL_ARG)?" \
+ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
+ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
../src/exiwhat.src > exiwhat-t
@mv exiwhat-t exiwhat
@chmod a+x exiwhat
@@ -321,7 +327,7 @@ exiwhat: config ../src/exiwhat.src
# Target for the exim_checkaccess utility script
exim_checkaccess: config ../src/exim_checkaccess.src
@rm -f exim_checkaccess
- @sed \
+ @. ./version.sh && sed \
-e "s?PROCESSED_FLAG?This file has been so processed.?"\
-e "/^# /p" \
-e "/^# /d" \
@@ -329,6 +335,8 @@ exim_checkaccess: config ../src/exim_checkaccess.src
-e "s?CONFIGURE_FILE?$(CONFIGURE_FILE)?" \
-e "s?BIN_DIRECTORY?$(BIN_DIRECTORY)?" \
-e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
+ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
+ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
../src/exim_checkaccess.src > exim_checkaccess-t
@mv exim_checkaccess-t exim_checkaccess
@chmod a+x exim_checkaccess
@@ -339,7 +347,7 @@ eximon: config ../src/eximon.src ../OS/eximon.conf-Default \
../Local/eximon.conf
@rm -f eximon
$(SHELL) $(SCRIPTS)/Configure-eximon
- @sed \
+ @. ./version.sh && sed \
-e "s?PROCESSED_FLAG?This file has been so processed.?"\
-e "/^# /p" \
-e "/^# /d" \
@@ -349,85 +357,108 @@ eximon: config ../src/eximon.src ../OS/eximon.conf-Default \
-e "s?BASENAME_COMMAND?$(BASENAME_COMMAND)?" \
-e "s?HOSTNAME_COMMAND?$(HOSTNAME_COMMAND)?" \
-e "s?X11_LD_LIBRARY?$(X11_LD_LIB)?" \
+ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
+ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
../src/eximon.src >> eximon
@echo ">>> eximon script built"; echo ""
# Targets for utilities; these are all Perl scripts that have to get the
# location of Perl put in them. A few need other things as well.
-exigrep: Makefile ../src/exigrep.src
+exigrep: config ../src/exigrep.src
@rm -f exigrep
- @sed \
+ @. ./version.sh && sed \
-e "s?PROCESSED_FLAG?This file has been so processed.?"\
-e "/^# /p" \
-e "/^# /d" \
-e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
-e "s?ZCAT_COMMAND?$(ZCAT_COMMAND)?" \
-e "s?COMPRESS_SUFFIX?$(COMPRESS_SUFFIX)?" \
+ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
+ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
../src/exigrep.src > exigrep-t
@mv exigrep-t exigrep
@chmod a+x exigrep
@echo ">>> exigrep script built"
-eximstats: Makefile ../src/eximstats.src
+eximstats: config ../src/eximstats.src
@rm -f eximstats
- @sed \
+ @. ./version.sh && sed \
-e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
+ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
+ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
../src/eximstats.src > eximstats-t
@mv eximstats-t eximstats
@chmod a+x eximstats
@echo ">>> eximstats script built"
-exiqgrep: Makefile ../src/exiqgrep.src
+exiqgrep: config ../src/exiqgrep.src
@rm -f exiqgrep
- @sed \
+ @. ./version.sh && sed \
-e "s?PROCESSED_FLAG?This file has been so processed.?"\
-e "/^# /p" \
-e "/^# /d" \
-e "s?BIN_DIRECTORY?$(BIN_DIRECTORY)?" \
-e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
+ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
+ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
../src/exiqgrep.src > exiqgrep-t
@mv exiqgrep-t exiqgrep
@chmod a+x exiqgrep
@echo ">>> exiqgrep script built"
-exiqsumm: Makefile ../src/exiqsumm.src
+exiqsumm: config ../src/exiqsumm.src
@rm -f exiqsumm
- @sed -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
+ @. ./version.sh && sed \
+ -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
+ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
+ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
../src/exiqsumm.src > exiqsumm-t
@mv exiqsumm-t exiqsumm
@chmod a+x exiqsumm
@echo ">>> exiqsumm script built"
-exipick: Makefile ../src/exipick.src
+exipick: config ../src/exipick.src
@rm -f exipick
- @sed -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
+ @. ./version.sh && sed \
+ -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
-e "s?SPOOL_DIRECTORY?$(SPOOL_DIRECTORY)?" \
-e "s?BIN_DIRECTORY?$(BIN_DIRECTORY)?" \
+ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
+ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
../src/exipick.src > exipick-t
@mv exipick-t exipick
@chmod a+x exipick
@echo ">>> exipick script built"
-transport-filter.pl: Makefile ../src/transport-filter.src
+transport-filter.pl: config ../src/transport-filter.src
@rm -f transport-filter.pl
- @sed -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
+ @. ./version.sh && sed \
+ -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
+ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
+ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
../src/transport-filter.src > transport-filter.pl-t
@mv transport-filter.pl-t transport-filter.pl
@chmod a+x transport-filter.pl
@echo ">>> transport-filter.pl script built"
-convert4r3: Makefile ../src/convert4r3.src
+convert4r3: config ../src/convert4r3.src
@rm -f convert4r3
- @sed -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
+ @. ./version.sh && sed \
+ -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
+ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
+ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
../src/convert4r3.src > convert4r3-t
@mv convert4r3-t convert4r3
@chmod a+x convert4r3
@echo ">>> convert4r3 script built"
-convert4r4: Makefile ../src/convert4r4.src
+convert4r4: config ../src/convert4r4.src
@rm -f convert4r4
- @sed -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
+ @. ./version.sh && sed \
+ -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
+ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
+ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
../src/convert4r4.src > convert4r4-t
@mv convert4r4-t convert4r4
@chmod a+x convert4r4
@@ -635,7 +666,7 @@ PHDRS = ../config.h \
# Update Exim's version information and build the version object.
-version.h::
+version.h version.sh::
@../scripts/reversion
cnumber.h: version.h
diff --git a/src/exim_monitor/em_version.c b/src/exim_monitor/em_version.c
index a2edbfe8a..8228f9467 100644
--- a/src/exim_monitor/em_version.c
+++ b/src/exim_monitor/em_version.c
@@ -10,6 +10,8 @@
#include <string.h>
#include <stdlib.h>
+#include "version.h"
+
extern uschar *version_string;
extern uschar *version_date;
@@ -21,6 +23,16 @@ uschar today[20];
version_string = US"2.06";
+#ifdef EXIM_BUILD_DATE_OVERRIDE
+/* Reproducible build support; build tooling should have given us something looking like
+ * "25-Feb-2017 20:15:40" in EXIM_BUILD_DATE_OVERRIDE based on $SOURCE_DATE_EPOCH in environ
+ * per <https://reproducible-builds.org/specs/source-date-epoch/>
+ */
+version_date = US malloc(32);
+version_date[0] = 0;
+Ustrncat(version_date, EXIM_BUILD_DATE_OVERRIDE, 31);
+
+#else
Ustrcpy(today, __DATE__);
if (today[4] == ' ') i = 1;
today[3] = today[6] = '-';
@@ -32,6 +44,7 @@ Ustrncat(version_date, today, 4);
Ustrncat(version_date, today+7, 4);
Ustrcat(version_date, " ");
Ustrcat(version_date, __TIME__);
+#endif
}
/* End of em_version.c */
diff --git a/src/src/acl.c b/src/src/acl.c
index 640989997..739cd91ae 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -852,6 +852,26 @@ while ((s = (*func)()) != NULL)
compatibility. */
if (c == ACLC_SET)
+#ifndef DISABLE_DKIM
+ if ( Ustrncmp(s, "dkim_verify_status", 18) == 0
+ || Ustrncmp(s, "dkim_verify_reason", 18) == 0)
+ {
+ uschar * endptr = s+18;
+
+ if (isalnum(*endptr))
+ {
+ *error = string_sprintf("invalid variable name after \"set\" in ACL "
+ "modifier \"set %s\" "
+ "(only \"dkim_verify_status\" or \"dkim_verify_reason\" permitted)",
+ s);
+ return NULL;
+ }
+ cond->u.varname = string_copyn(s, 18);
+ s = endptr;
+ while (isspace(*s)) s++;
+ }
+ else
+#endif
{
uschar *endptr;
@@ -2899,8 +2919,19 @@ for (; cb != NULL; cb = cb->next)
if (cb->type == ACLC_SET)
{
- debug_printf("acl_%s ", cb->u.varname);
- lhswidth += 5 + Ustrlen(cb->u.varname);
+#ifndef DISABLE_DKIM
+ if ( Ustrcmp(cb->u.varname, "dkim_verify_status") == 0
+ || Ustrcmp(cb->u.varname, "dkim_verify_reason") == 0)
+ {
+ debug_printf("%s ", cb->u.varname);
+ lhswidth += 19;
+ }
+ else
+#endif
+ {
+ debug_printf("acl_%s ", cb->u.varname);
+ lhswidth += 5 + Ustrlen(cb->u.varname);
+ }
}
debug_printf("= %s\n", cb->arg);
@@ -3402,7 +3433,7 @@ for (; cb != NULL; cb = cb->next)
#ifndef DISABLE_DKIM
case ACLC_DKIM_SIGNER:
- if (dkim_cur_signer != NULL)
+ if (dkim_cur_signer)
rc = match_isinlist(dkim_cur_signer,
&arg,0,NULL,NULL,MCL_STRING,TRUE,NULL);
else
@@ -3410,7 +3441,7 @@ for (; cb != NULL; cb = cb->next)
break;
case ACLC_DKIM_STATUS:
- rc = match_isinlist(dkim_exim_expand_query(DKIM_VERIFY_STATUS),
+ rc = match_isinlist(dkim_verify_status,
&arg,0,NULL,NULL,MCL_STRING,TRUE,NULL);
break;
#endif
@@ -3609,12 +3640,22 @@ for (; cb != NULL; cb = cb->next)
{
int old_pool = store_pool;
if ( cb->u.varname[0] == 'c'
+#ifndef DISABLE_DKIM
+ || cb->u.varname[0] == 'd'
+#endif
#ifndef DISABLE_EVENT
|| event_name /* An event is being delivered */
#endif
)
store_pool = POOL_PERM;
- acl_var_create(cb->u.varname)->data.ptr = string_copy(arg);
+#ifndef DISABLE_DKIM /* Overwriteable dkim result variables */
+ if (Ustrcmp(cb->u.varname, "dkim_verify_status") == 0)
+ dkim_verify_status = string_copy(arg);
+ else if (Ustrcmp(cb->u.varname, "dkim_verify_reason") == 0)
+ dkim_verify_reason = string_copy(arg);
+ else
+#endif
+ acl_var_create(cb->u.varname)->data.ptr = string_copy(arg);
store_pool = old_pool;
}
break;
diff --git a/src/src/configure.default b/src/src/configure.default
index a294dc3e6..b828ca20a 100644
--- a/src/src/configure.default
+++ b/src/src/configure.default
@@ -153,6 +153,9 @@ acl_smtp_data = acl_check_data
# tls_certificate = /etc/ssl/exim.crt
# tls_privatekey = /etc/ssl/exim.pem
+# For OpenSSL, prefer EC- over RSA-authenticated ciphers
+# tls_require_ciphers = ECDSA:RSA:!COMPLEMENTOFDEFAILT
+
# In order to support roaming users who wish to send email from anywhere,
# you may want to make Exim listen on other ports as well as port 25, in
# case these users need to send email from a network that blocks port 25.
diff --git a/src/src/convert4r3.src b/src/src/convert4r3.src
index 632eb70d7..d0b94d15e 100755
--- a/src/src/convert4r3.src
+++ b/src/src/convert4r3.src
@@ -10,6 +10,18 @@
use warnings;
BEGIN { pop @INC if $INC[-1] eq '.' };
+use Getopt::Long;
+use File::Basename;
+
+GetOptions(
+ 'version' => sub {
+ print basename($0) . ": $0\n",
+ "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n",
+ "perl(runtime): $^V\n";
+ exit 0;
+ },
+);
+
##################################################
# Analyse one line #
##################################################
diff --git a/src/src/convert4r4.src b/src/src/convert4r4.src
index fff4e478b..47987fc8f 100755
--- a/src/src/convert4r4.src
+++ b/src/src/convert4r4.src
@@ -9,6 +9,18 @@
use warnings;
BEGIN { pop @INC if $INC[-1] eq '.' };
+use Getopt::Long;
+use File::Basename;
+
+GetOptions(
+ 'version' => sub {
+ print basename($0) . ": $0\n",
+ "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n",
+ "perl(runtime): $^V\n";
+ exit 0;
+ },
+);
+
# These are lists of main options which are abolished in Exim 4.
# The first contains options that are used to construct new options.
diff --git a/src/src/dkim.c b/src/src/dkim.c
index d31cae9c7..6bc711ac1 100644
--- a/src/src/dkim.c
+++ b/src/src/dkim.c
@@ -134,140 +134,159 @@ store_pool = dkim_verify_oldpool;
}
-void
-dkim_exim_verify_finish(void)
+/* Log the result for the given signature */
+static void
+dkim_exim_verify_log_sig(pdkim_signature * sig)
{
-pdkim_signature * sig = NULL;
-int rc;
-gstring * g = NULL;
-const uschar * errstr;
-
-store_pool = POOL_PERM;
-
-/* Delete eventual previous signature chain */
-
-dkim_signers = NULL;
-dkim_signatures = NULL;
-
-if (dkim_collect_error)
- {
- log_write(0, LOG_MAIN,
- "DKIM: Error during validation, disabling signature verification: %.100s",
- dkim_collect_error);
- dkim_disable_verify = TRUE;
- goto out;
- }
-
-dkim_collect_input = FALSE;
-
-/* Finish DKIM operation and fetch link to signatures chain */
-
-rc = pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures, &errstr);
-if (rc != PDKIM_OK)
- {
- log_write(0, LOG_MAIN, "DKIM: validation error: %.100s%s%s", pdkim_errstr(rc),
- errstr ? ": " : "", errstr ? errstr : US"");
- goto out;
- }
-
-for (sig = dkim_signatures; sig; sig = sig->next)
- {
- uschar * s;
- gstring * logmsg;
-
- /* Log a line for each signature */
-
- if (!(s = sig->domain)) s = US"<UNSET>";
- logmsg = string_append(NULL, 2, "d=", s);
- if (!(s = sig->selector)) s = US"<UNSET>";
- logmsg = string_append(logmsg, 2, " s=", s);
- logmsg = string_append(logmsg, 7,
- " c=", sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
- "/", sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
- " a=", dkim_sig_to_a_tag(sig),
- string_sprintf(" b=" SIZE_T_FMT,
- (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0));
- if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
- if (sig->created > 0) logmsg = string_cat(logmsg,
- string_sprintf(" t=%lu", sig->created));
- if (sig->expires > 0) logmsg = string_cat(logmsg,
- string_sprintf(" x=%lu", sig->expires));
- if (sig->bodylength > -1) logmsg = string_cat(logmsg,
- string_sprintf(" l=%lu", sig->bodylength));
-
+gstring * logmsg;
+uschar * s;
+
+if (!sig) return;
+
+logmsg = string_catn(NULL, US"DKIM: ", 6);
+if (!(s = sig->domain)) s = US"<UNSET>";
+logmsg = string_append(logmsg, 2, "d=", s);
+if (!(s = sig->selector)) s = US"<UNSET>";
+logmsg = string_append(logmsg, 2, " s=", s);
+logmsg = string_append(logmsg, 7,
+" c=", sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
+"/", sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
+" a=", dkim_sig_to_a_tag(sig),
+string_sprintf(" b=" SIZE_T_FMT,
+ (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0));
+if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
+if (sig->created > 0) logmsg = string_cat(logmsg,
+ string_sprintf(" t=%lu", sig->created));
+if (sig->expires > 0) logmsg = string_cat(logmsg,
+ string_sprintf(" x=%lu", sig->expires));
+if (sig->bodylength > -1) logmsg = string_cat(logmsg,
+ string_sprintf(" l=%lu", sig->bodylength));
+
+if ( !dkim_verify_status
+ || ( dkim_verify_status == dkim_exim_expand_query(DKIM_VERIFY_STATUS)
+ && dkim_verify_reason == dkim_exim_expand_query(DKIM_VERIFY_REASON)
+ ) )
switch (sig->verify_status)
{
case PDKIM_VERIFY_NONE:
- logmsg = string_cat(logmsg, " [not verified]");
+ logmsg = string_cat(logmsg, US" [not verified]");
break;
case PDKIM_VERIFY_INVALID:
- logmsg = string_cat(logmsg, " [invalid - ");
+ logmsg = string_cat(logmsg, US" [invalid - ");
switch (sig->verify_ext_status)
{
case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
logmsg = string_cat(logmsg,
- "public key record (currently?) unavailable]");
+ US"public key record (currently?) unavailable]");
break;
case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
- logmsg = string_cat(logmsg, "overlong public key record]");
+ logmsg = string_cat(logmsg, US"overlong public key record]");
break;
case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
- logmsg = string_cat(logmsg, "syntax error in public key record]");
+ logmsg = string_cat(logmsg, US"syntax error in public key record]");
break;
- case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
- logmsg = string_cat(logmsg, "signature tag missing or invalid]");
- break;
+ case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
+ logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
+ break;
- case PDKIM_VERIFY_INVALID_DKIM_VERSION:
- logmsg = string_cat(logmsg, "unsupported DKIM version]");
- break;
+ case PDKIM_VERIFY_INVALID_DKIM_VERSION:
+ logmsg = string_cat(logmsg, US"unsupported DKIM version]");
+ break;
default:
- logmsg = string_cat(logmsg, "unspecified problem]");
+ logmsg = string_cat(logmsg, US"unspecified problem]");
}
break;
case PDKIM_VERIFY_FAIL:
- logmsg =
- string_cat(logmsg, " [verification failed - ");
+ logmsg = string_cat(logmsg, US" [verification failed - ");
switch (sig->verify_ext_status)
{
case PDKIM_VERIFY_FAIL_BODY:
logmsg = string_cat(logmsg,
- "body hash mismatch (body probably modified in transit)]");
+ US"body hash mismatch (body probably modified in transit)]");
break;
case PDKIM_VERIFY_FAIL_MESSAGE:
logmsg = string_cat(logmsg,
- "signature did not verify (headers probably modified in transit)]");
+ US"signature did not verify "
+ "(headers probably modified in transit)]");
break;
default:
- logmsg = string_cat(logmsg, "unspecified reason]");
+ logmsg = string_cat(logmsg, US"unspecified reason]");
}
break;
case PDKIM_VERIFY_PASS:
- logmsg = string_cat(logmsg, " [verification succeeded]");
+ logmsg = string_cat(logmsg, US" [verification succeeded]");
break;
}
+else
+ logmsg = string_append(logmsg, 5,
+ US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
- log_write(0, LOG_MAIN, "DKIM: %s", string_from_gstring(logmsg));
+log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
+return;
+}
- /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
- if (sig->domain)
- g = string_append_listele(g, ':', sig->domain);
+/* Log a line for each signature */
+void
+dkim_exim_verify_log_all(void)
+{
+pdkim_signature * sig;
+for (sig = dkim_signatures; sig; sig = sig->next) dkim_exim_verify_log_sig(sig);
+}
+
+
+void
+dkim_exim_verify_finish(void)
+{
+pdkim_signature * sig;
+int rc;
+gstring * g = NULL;
+const uschar * errstr;
- if (sig->identity)
- g = string_append_listele(g, ':', sig->identity);
+store_pool = POOL_PERM;
- /* Process next signature */
+/* Delete eventual previous signature chain */
+
+dkim_signers = NULL;
+dkim_signatures = NULL;
+
+if (dkim_collect_error)
+ {
+ log_write(0, LOG_MAIN,
+ "DKIM: Error during validation, disabling signature verification: %.100s",
+ dkim_collect_error);
+ dkim_disable_verify = TRUE;
+ goto out;
+ }
+
+dkim_collect_input = FALSE;
+
+/* Finish DKIM operation and fetch link to signatures chain */
+
+rc = pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures, &errstr);
+if (rc != PDKIM_OK)
+ {
+ log_write(0, LOG_MAIN, "DKIM: validation error: %.100s%s%s", pdkim_errstr(rc),
+ errstr ? ": " : "", errstr ? errstr : US"");
+ goto out;
+ }
+
+/* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
+
+for (sig = dkim_signatures; sig; sig = sig->next)
+ {
+ if (sig->domain) g = string_append_listele(g, ':', sig->domain);
+ if (sig->identity) g = string_append_listele(g, ':', sig->identity);
}
if (g) dkim_signers = g->s;
@@ -277,40 +296,93 @@ store_pool = dkim_verify_oldpool;
}
-void
-dkim_exim_acl_setup(uschar * id)
+
+/* Args as per dkim_exim_acl_run() below */
+static int
+dkim_acl_call(uschar * id, gstring ** res_ptr,
+ uschar ** user_msgptr, uschar ** log_msgptr)
+{
+int rc;
+DEBUG(D_receive)
+ debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
+
+rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
+dkim_exim_verify_log_sig(dkim_cur_sig);
+*res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
+return rc;
+}
+
+
+
+/* For the given identity, run the DKIM ACL once for each matching signature.
+
+Arguments
+ id Identity to look for in dkim signatures
+ res_ptr ptr to growable string-list of status results,
+ appended to per ACL run
+ user_msgptr where to put a user error (for SMTP response)
+ log_msgptr where to put a logging message (not for SMTP response)
+
+Returns: OK access is granted by an ACCEPT verb
+ DISCARD access is granted by a DISCARD verb
+ FAIL access is denied
+ FAIL_DROP access is denied; drop the connection
+ DEFER can't tell at the moment
+ ERROR disaster
+*/
+
+int
+dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
+ uschar ** user_msgptr, uschar ** log_msgptr)
{
pdkim_signature * sig;
uschar * cmp_val;
+int rc = -1;
-dkim_cur_sig = NULL;
+dkim_verify_status = US"none";
+dkim_verify_reason = US"";
dkim_cur_signer = id;
if (dkim_disable_verify || !id || !dkim_verify_ctx)
- return;
+ return OK;
-/* Find signature to run ACL on */
+/* Find signatures to run ACL on */
for (sig = dkim_signatures; sig; sig = sig->next)
if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
&& strcmpic(cmp_val, id) == 0
)
{
- dkim_cur_sig = sig;
-
/* The "dkim_domain" and "dkim_selector" expansion variables have
- related globals, since they are used in the signing code too.
- Instead of inventing separate names for verification, we set
- them here. This is easy since a domain and selector is guaranteed
- to be in a signature. The other dkim_* expansion items are
- dynamically fetched from dkim_cur_sig at expansion time (see
- function below). */
+ related globals, since they are used in the signing code too.
+ Instead of inventing separate names for verification, we set
+ them here. This is easy since a domain and selector is guaranteed
+ to be in a signature. The other dkim_* expansion items are
+ dynamically fetched from dkim_cur_sig at expansion time (see
+ function below). */
+ dkim_cur_sig = sig;
dkim_signing_domain = US sig->domain;
dkim_signing_selector = US sig->selector;
dkim_key_length = sig->sighash.len * 8;
- return;
+
+ /* These two return static strings, so we can compare the addr
+ later to see if the ACL overwrote them. Check that when logging */
+
+ dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
+ dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
+
+ if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
+ return rc;
}
+
+if (rc != -1)
+ return rc;
+
+/* No matching sig found. Call ACL once anyway. */
+
+dkim_cur_sig = NULL;
+return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
}
@@ -365,12 +437,12 @@ switch (what)
}
case DKIM_CANON_HEADERS:
- switch (dkim_cur_sig->canon_headers)
- {
- case PDKIM_CANON_RELAXED: return US"relaxed";
- case PDKIM_CANON_SIMPLE:
- default: return US"simple";
- }
+ switch (dkim_cur_sig->canon_headers)
+ {
+ case PDKIM_CANON_RELAXED: return US"relaxed";
+ case PDKIM_CANON_SIMPLE:
+ default: return US"simple";
+ }
case DKIM_COPIEDHEADERS:
return dkim_cur_sig->copiedheaders
diff --git a/src/src/dkim.h b/src/src/dkim.h
index 735a1162a..c48241ce2 100644
--- a/src/src/dkim.h
+++ b/src/src/dkim.h
@@ -10,7 +10,8 @@ gstring * dkim_exim_sign(int, off_t, uschar *, struct ob_dkim *, const uschar **
void dkim_exim_verify_init(BOOL);
void dkim_exim_verify_feed(uschar *, int);
void dkim_exim_verify_finish(void);
-void dkim_exim_acl_setup(uschar *);
+void dkim_exim_verify_log_all(void);
+int dkim_exim_acl_run(uschar *, gstring **, uschar **, uschar **);
uschar *dkim_exim_expand_query(int);
#define DKIM_ALGO 1
diff --git a/src/src/exicyclog.src b/src/src/exicyclog.src
index 4fb160ac0..20bf9fcd4 100644
--- a/src/src/exicyclog.src
+++ b/src/src/exicyclog.src
@@ -72,6 +72,11 @@ while [ $# -gt 0 ] ; do
-k) keep=$2
shift
;;
+ --version)
+ echo "`basename $0`: $0"
+ echo "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION"
+ exit 0
+ ;;
*) echo "** exicyclog: unknown option $1"
exit 1
;;
diff --git a/src/src/exigrep.src b/src/src/exigrep.src
index bdeffae82..5db01fe08 100644
--- a/src/src/exigrep.src
+++ b/src/src/exigrep.src
@@ -6,6 +6,7 @@ BEGIN { pop @INC if $INC[-1] eq '.' };
use Pod::Usage;
use Getopt::Long;
+use File::Basename;
# Copyright (c) 2007-2017 University of Cambridge.
# See the file NOTICE for conditions of use and distribution.
@@ -229,6 +230,12 @@ GetOptions(
-noperldoc => system('perldoc -V 2>/dev/null >&2')
);
},
+ 'version' => sub {
+ print basename($0) . ": $0\n",
+ "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n",
+ "perl(runtime): $]\n";
+ exit 0;
+ },
) and @ARGV or pod2usage;
$pattern = shift @ARGV;
@@ -237,7 +244,8 @@ $pattern = quotemeta $pattern if $literal;
# Start a pager if output goes to a terminal
if (-t 1 and $use_pager)
{
- foreach ($ENV{PAGER}//(), 'less', 'more')
+ # for perl >= v5.10.x: foreach ($ENV{PAGER}//(), 'less', 'more')
+ foreach (defined $ENV{PAGER} ? $ENV{PAGER} : (), 'less', 'more')
{
local $ENV{LESS} .= ' --no-init --quit-if-one-screen';
open(my $pager, '|-', $_) or next;
diff --git a/src/src/exim_checkaccess.src b/src/src/exim_checkaccess.src
index a780a298a..360f307ba 100755
--- a/src/src/exim_checkaccess.src
+++ b/src/src/exim_checkaccess.src
@@ -65,8 +65,16 @@ PERL_COMMAND - $exim_path $args <<'End'
BEGIN { pop @INC if $INC[-1] eq '.' };
use FileHandle;
+use File::Basename;
use IPC::Open2;
+if ($ARGV[0] eq '--version') {
+ print basename($0) . ": $0\n",
+ "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n",
+ "perl(runtime): $]\n";
+ exit 0;
+}
+
if (scalar(@ARGV) < 3)
{
print "Usage: exim_checkaccess <IP address> <email address> [exim options]\n";
diff --git a/src/src/eximon.src b/src/src/eximon.src
index d461ccffa..6293a7cc2 100644
--- a/src/src/eximon.src
+++ b/src/src/eximon.src
@@ -18,6 +18,13 @@
# X11_LD_LIBRARY
# PROCESSED_FLAG
+#
+if test "x$1" = x--version
+then
+ echo "`basename $0`: $0"
+ echo "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION"
+ exit 0
+fi
# See if caller wants to invoke gdb
diff --git a/src/src/eximstats.src b/src/src/eximstats.src
index 80ac93372..76cfe7e97 100644
--- a/src/src/eximstats.src
+++ b/src/src/eximstats.src
@@ -552,10 +552,18 @@ use integer;
BEGIN { pop @INC if $INC[-1] eq '.' };
use strict;
use IO::File;
+use File::Basename;
# use Time::Local; # PH/FANF
use POSIX;
+if ($ARGV[0] eq '--version') {
+ print basename($0) . ": $0\n",
+ "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n",
+ "perl(runtime): $]\n";
+ exit 0;
+}
+
use vars qw($HAVE_GD_Graph_pie $HAVE_GD_Graph_linespoints $HAVE_Spreadsheet_WriteExcel);
eval { require GD::Graph::pie; };
$HAVE_GD_Graph_pie = $@ ? 0 : 1;
diff --git a/src/src/exinext.src b/src/src/exinext.src
index 9c427350b..913801867 100644
--- a/src/src/exinext.src
+++ b/src/src/exinext.src
@@ -25,6 +25,13 @@ config=
eximmacdef=
exim_path=
+if test "x$1" = x--version
+then
+ echo "`basename $0`: $0"
+ echo "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION"
+ exit 0
+fi
+
if expr -- $1 : '\-' >/dev/null ; then
while expr -- $1 : '\-' >/dev/null ; do
if [ "$1" = "-C" ]; then
diff --git a/src/src/exipick.src b/src/src/exipick.src
index a1aa79dc0..b6c28ef23 100644
--- a/src/src/exipick.src
+++ b/src/src/exipick.src
@@ -17,6 +17,7 @@ my $charset = 'ISO-8859-1';
use strict;
BEGIN { pop @INC if $INC[-1] eq '.' };
use Getopt::Long;
+use File::Basename;
my($p_name) = $0 =~ m|/?([^/]+)$|;
my $p_version = "20100323.0";
@@ -83,7 +84,13 @@ GetOptions(
'show-vars=s' => \$G::show_vars, # display the contents of these vars
'just-vars' => \$G::just_vars, # only display vars, no other info
'show-rules' => \$G::show_rules, # display compiled match rules
- 'show-tests' => \$G::show_tests # display tests as applied to each message
+ 'show-tests' => \$G::show_tests, # display tests as applied to each message
+ 'version' => sub {
+ print basename($0) . ": $0\n",
+ "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n",
+ "perl(runtime): $]\n";
+ exit 0;
+ },
) || exit(1);
# if both freeze and thaw specified, only thaw as it is less destructive
diff --git a/src/src/exiqgrep.src b/src/src/exiqgrep.src
index d900e9933..c4f7c4b58 100644
--- a/src/src/exiqgrep.src
+++ b/src/src/exiqgrep.src
@@ -19,7 +19,9 @@
use strict;
BEGIN { pop @INC if $INC[-1] eq '.' };
+
use Getopt::Std;
+use File::Basename;
# Have this variable point to your exim binary.
my $exim = 'BIN_DIRECTORY/exim';
@@ -44,6 +46,13 @@ if ($^O eq 'darwin') { # aka MacOS X
$base = 62;
};
+if ($ARGV[0] eq '--version') {
+ print basename($0) . ": $0\n",
+ "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n",
+ "perl(runtime): $]\n";
+ exit 0;
+}
+
getopts('hf:r:y:o:s:C:zxlibRca',\%opt);
if ($ARGV[0]) { &help; exit;}
if ($opt{h}) { &help; exit;}
diff --git a/src/src/exiqsumm.src b/src/src/exiqsumm.src
index 99a304fef..551ca97ca 100644
--- a/src/src/exiqsumm.src
+++ b/src/src/exiqsumm.src
@@ -43,6 +43,14 @@
use warnings;
BEGIN { pop @INC if $INC[-1] eq '.' };
+use File::Basename;
+
+if ($ARGV[0] eq '--version') {
+ print basename($0) . ": $0\n",
+ "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n",
+ "perl(runtime): $]\n";
+ exit 0;
+}
sub print_volume_rounded {
my($x) = pop @_;
diff --git a/src/src/exiwhat.src b/src/src/exiwhat.src
index 2542b0198..4fdc09f78 100644
--- a/src/src/exiwhat.src
+++ b/src/src/exiwhat.src
@@ -52,6 +52,13 @@ signal=EXIWHAT_KILL_SIGNAL
# See if this installation is using the esoteric "USE_NODE" feature of Exim,
# in which it uses the host's name as a suffix for the configuration file name.
+if test "x$1" = x--version
+then
+ echo "`basename $0`: $0"
+ echo "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION"
+ exit 0
+fi
+
if [ "CONFIGURE_FILE_USE_NODE" = "yes" ]; then
hostsuffix=.`uname -n`
fi
diff --git a/src/src/expand.c b/src/src/expand.c
index 782467ff7..f44ddf8b8 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -508,8 +508,8 @@ static var_entry var_table[] = {
{ "dkim_key_testing", vtype_dkim, (void *)DKIM_KEY_TESTING },
{ "dkim_selector", vtype_stringptr, &dkim_signing_selector },
{ "dkim_signers", vtype_stringptr, &dkim_signers },
- { "dkim_verify_reason", vtype_dkim, (void *)DKIM_VERIFY_REASON },
- { "dkim_verify_status", vtype_dkim, (void *)DKIM_VERIFY_STATUS},
+ { "dkim_verify_reason", vtype_stringptr, &dkim_verify_reason },
+ { "dkim_verify_status", vtype_stringptr, &dkim_verify_status },
#endif
#ifdef EXPERIMENTAL_DMARC
{ "dmarc_ar_header", vtype_stringptr, &dmarc_ar_header },
diff --git a/src/src/globals.c b/src/src/globals.c
index 2a53835e9..5df84bd10 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -668,6 +668,8 @@ uschar *dkim_signers = NULL;
uschar *dkim_signing_domain = NULL;
uschar *dkim_signing_selector = NULL;
uschar *dkim_verify_signers = US"$dkim_signers";
+uschar *dkim_verify_status = NULL;
+uschar *dkim_verify_reason = NULL;
#endif
#ifdef EXPERIMENTAL_DMARC
BOOL dmarc_has_been_checked = FALSE;
diff --git a/src/src/globals.h b/src/src/globals.h
index 62336c275..37d4cada3 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -393,6 +393,8 @@ extern uschar *dkim_signers; /* Expansion variable, holds colon-separa
extern uschar *dkim_signing_domain; /* Expansion variable, domain used for signing a message. */
extern uschar *dkim_signing_selector; /* Expansion variable, selector used for signing a message. */
extern uschar *dkim_verify_signers; /* Colon-separated list of domains for each of which we call the DKIM ACL */
+extern uschar *dkim_verify_status; /* result for this signature */
+extern uschar *dkim_verify_reason; /* result for this signature */
#endif
#ifdef EXPERIMENTAL_DMARC
extern BOOL dmarc_has_been_checked; /* Global variable to check if test has been called yet */
diff --git a/src/src/match.c b/src/src/match.c
index c21711410..08ec0eeab 100644
--- a/src/src/match.c
+++ b/src/src/match.c
@@ -461,12 +461,9 @@ HDEBUG(D_any)
/* If the list is empty, the answer is no. Skip the debugging output for
an unnamed list. */
-if (*listptr == NULL)
+if (!*listptr)
{
- HDEBUG(D_lists)
- {
- if (ot != NULL) debug_printf("%s no (option unset)\n", ot);
- }
+ HDEBUG(D_lists) if (ot) debug_printf("%s no (option unset)\n", ot);
return FAIL;
}
@@ -485,17 +482,17 @@ else
/* If we are searching a domain list, and $domain is not set, set it to the
subject that is being sought for the duration of the expansion. */
- if (type == MCL_DOMAIN && deliver_domain == NULL)
+ if (type == MCL_DOMAIN && !deliver_domain)
{
check_string_block *cb = (check_string_block *)arg;
deliver_domain = string_copy(cb->subject);
list = expand_cstring(*listptr);
deliver_domain = NULL;
}
+ else
+ list = expand_cstring(*listptr);
- else list = expand_cstring(*listptr);
-
- if (list == NULL)
+ if (!list)
{
if (expand_string_forcedfail)
{
@@ -511,17 +508,14 @@ else
/* For an unnamed list, use the expanded version in comments */
-HDEBUG(D_any)
- {
- if (ot == NULL) ot = string_sprintf("%s in \"%s\"?", name, list);
- }
+HDEBUG(D_any) if (ot == NULL) ot = string_sprintf("%s in \"%s\"?", name, list);
/* Now scan the list and process each item in turn, until one of them matches,
or we hit an error. */
-while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
+while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
{
- uschar *ss = sss;
+ uschar * ss = sss;
/* Address lists may contain +caseful, to restore caseful matching of the
local part. We have to know the layout of the control block, unfortunately.
@@ -534,7 +528,8 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
{
check_address_block *cb = (check_address_block *)arg;
uschar *at = Ustrrchr(cb->origaddress, '@');
- if (at != NULL)
+
+ if (at)
Ustrncpy(cb->address, cb->origaddress, at - cb->origaddress);
cb->caseless = FALSE;
continue;
@@ -594,7 +589,8 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
yield = FAIL;
while (isspace((*(++ss))));
}
- else yield = OK;
+ else
+ yield = OK;
/* If the item does not begin with '/', it might be a + item for a named
list. Otherwise, it is just a single list entry that has to be matched.
@@ -602,7 +598,7 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
if (*ss != '/')
{
- if (*ss == '+' && anchorptr != NULL)
+ if (*ss == '+' && anchorptr)
{
int bits = 0;
int offset = 0;
@@ -610,15 +606,18 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
unsigned int *use_cache_bits = original_cache_bits;
uschar *cached = US"";
namedlist_block *nb;
- tree_node *t = tree_search(*anchorptr, ss+1);
-
- if (t == NULL)
- log_write(0, LOG_MAIN|LOG_PANIC_DIE, "unknown named%s list \"%s\"",
- (type == MCL_DOMAIN)? " domain" :
- (type == MCL_HOST)? " host" :
- (type == MCL_ADDRESS)? " address" :
- (type == MCL_LOCALPART)? " local part" : "",
+ tree_node * t;
+
+ if (!(t = tree_search(*anchorptr, ss+1)))
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "unknown named%s list \"%s\"",
+ type == MCL_DOMAIN ? " domain" :
+ type == MCL_HOST ? " host" :
+ type == MCL_ADDRESS ? " address" :
+ type == MCL_LOCALPART ? " local part" : "",
ss);
+ return DEFER;
+ }
nb = t->data.ptr;
/* If the list number is negative, it means that this list is not
@@ -630,7 +629,7 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
because the pointer may be NULL from the start if caching is not
required. */
- if (use_cache_bits != NULL)
+ if (use_cache_bits)
{
offset = (nb->number)/16;
shift = ((nb->number)%16)*2;
@@ -654,15 +653,13 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
wasn't before. Ensure that this is passed up to the next level.
Otherwise, remember the result of the search in the cache. */
- if (use_cache_bits == NULL)
- {
+ if (!use_cache_bits)
*cache_ptr = NULL;
- }
else
{
use_cache_bits[offset] |= bits << shift;
- if (valueptr != NULL)
+ if (valueptr)
{
int old_pool = store_pool;
namedlist_cacheblock *p;
@@ -675,16 +672,14 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
p->key = string_copy(get_check_key(arg, type));
- p->data = (*valueptr == NULL)? NULL : string_copy(*valueptr);
+ p->data = *valueptr ? string_copy(*valueptr) : NULL;
store_pool = old_pool;
p->next = nb->cache_data;
nb->cache_data = p;
- if (*valueptr != NULL)
- {
+ if (*valueptr)
DEBUG(D_lists) debug_printf("data from lookup saved for "
"cache for %s: %s\n", ss, *valueptr);
- }
}
}
}
@@ -697,19 +692,18 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
{
DEBUG(D_lists) debug_printf("cached %s match for %s\n",
((bits & (-bits)) == bits)? "yes" : "no", ss);
+
cached = US" - cached";
- if (valueptr != NULL)
+ if (valueptr)
{
const uschar *key = get_check_key(arg, type);
namedlist_cacheblock *p;
- for (p = nb->cache_data; p != NULL; p = p->next)
- {
+ for (p = nb->cache_data; p; p = p->next)
if (Ustrcmp(key, p->key) == 0)
{
*valueptr = p->data;
break;
}
- }
DEBUG(D_lists) debug_printf("cached lookup data = %s\n", *valueptr);
}
}
@@ -729,30 +723,30 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
else
{
- uschar *error = NULL;
+ uschar * error = NULL;
switch ((func)(arg, ss, valueptr, &error))
{
case OK:
- HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\")\n", ot,
- (yield == OK)? "yes" : "no", sss);
- return yield;
+ HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\")\n", ot,
+ (yield == OK)? "yes" : "no", sss);
+ return yield;
case DEFER:
- if (error == NULL)
- error = string_sprintf("DNS lookup of \"%s\" deferred", ss);
- if (ignore_defer)
- {
- HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_defer\n",
- error);
- break;
- }
- if (include_defer)
- {
- log_write(0, LOG_MAIN, "%s: accepted by +include_defer", error);
- return OK;
- }
- if (!search_error_message) search_error_message = error;
- goto DEFER_RETURN;
+ if (!error)
+ error = string_sprintf("DNS lookup of \"%s\" deferred", ss);
+ if (ignore_defer)
+ {
+ HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_defer\n",
+ error);
+ break;
+ }
+ if (include_defer)
+ {
+ log_write(0, LOG_MAIN, "%s: accepted by +include_defer", error);
+ return OK;
+ }
+ if (!search_error_message) search_error_message = error;
+ goto DEFER_RETURN;
/* The ERROR return occurs when checking hosts, when either a forward
or reverse lookup has failed. It can also occur in a match_ip list if a
@@ -760,24 +754,24 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
which it was. */
case ERROR:
- if (ignore_unknown)
- {
- HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_unknown\n",
- error);
- }
- else
- {
- HDEBUG(D_lists) debug_printf("%s %s (%s)\n", ot,
- include_unknown? "yes":"no", error);
- if (!include_unknown)
- {
- if (LOGGING(unknown_in_list))
- log_write(0, LOG_MAIN, "list matching forced to fail: %s", error);
- return FAIL;
- }
- log_write(0, LOG_MAIN, "%s: accepted by +include_unknown", error);
- return OK;
- }
+ if (ignore_unknown)
+ {
+ HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_unknown\n",
+ error);
+ }
+ else
+ {
+ HDEBUG(D_lists) debug_printf("%s %s (%s)\n", ot,
+ include_unknown? "yes":"no", error);
+ if (!include_unknown)
+ {
+ if (LOGGING(unknown_in_list))
+ log_write(0, LOG_MAIN, "list matching forced to fail: %s", error);
+ return FAIL;
+ }
+ log_write(0, LOG_MAIN, "%s: accepted by +include_unknown", error);
+ return OK;
+ }
}
}
}
@@ -788,16 +782,16 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
else
{
int file_yield = yield; /* In case empty file */
- uschar *filename = ss;
- FILE *f = Ufopen(filename, "rb");
+ uschar * filename = ss;
+ FILE * f = Ufopen(filename, "rb");
uschar filebuffer[1024];
/* ot will be null in non-debugging cases, and anyway, we get better
wording by reworking it. */
- if (f == NULL)
+ if (!f)
{
- uschar *listname = readconf_find_option(listptr);
+ uschar * listname = readconf_find_option(listptr);
if (listname[0] == 0)
listname = string_sprintf("\"%s\"", *listptr);
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
@@ -845,48 +839,48 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
switch ((func)(arg, ss, valueptr, &error))
{
case OK:
- (void)fclose(f);
- HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\" in %s)\n", ot,
- (yield == OK)? "yes" : "no", sss, filename);
- return file_yield;
+ (void)fclose(f);
+ HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\" in %s)\n", ot,
+ yield == OK ? "yes" : "no", sss, filename);
+ return file_yield;
case DEFER:
- if (error == NULL)
- error = string_sprintf("DNS lookup of %s deferred", ss);
- if (ignore_defer)
- {
- HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_defer\n",
- error);
- break;
- }
- (void)fclose(f);
- if (include_defer)
- {
- log_write(0, LOG_MAIN, "%s: accepted by +include_defer", error);
- return OK;
- }
- goto DEFER_RETURN;
-
- case ERROR: /* host name lookup failed - this can only */
- if (ignore_unknown) /* be for an incoming host (not outgoing) */
- {
- HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_unknown\n",
- error);
- }
- else
- {
- HDEBUG(D_lists) debug_printf("%s %s (%s)\n", ot,
- include_unknown? "yes":"no", error);
- (void)fclose(f);
- if (!include_unknown)
- {
- if (LOGGING(unknown_in_list))
- log_write(0, LOG_MAIN, "list matching forced to fail: %s", error);
- return FAIL;
- }
- log_write(0, LOG_MAIN, "%s: accepted by +include_unknown", error);
- return OK;
- }
+ if (!error)
+ error = string_sprintf("DNS lookup of %s deferred", ss);
+ if (ignore_defer)
+ {
+ HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_defer\n",
+ error);
+ break;
+ }
+ (void)fclose(f);
+ if (include_defer)
+ {
+ log_write(0, LOG_MAIN, "%s: accepted by +include_defer", error);
+ return OK;
+ }
+ goto DEFER_RETURN;
+
+ case ERROR: /* host name lookup failed - this can only */
+ if (ignore_unknown) /* be for an incoming host (not outgoing) */
+ {
+ HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_unknown\n",
+ error);
+ }
+ else
+ {
+ HDEBUG(D_lists) debug_printf("%s %s (%s)\n", ot,
+ include_unknown? "yes":"no", error);
+ (void)fclose(f);
+ if (!include_unknown)
+ {
+ if (LOGGING(unknown_in_list))
+ log_write(0, LOG_MAIN, "list matching forced to fail: %s", error);
+ return FAIL;
+ }
+ log_write(0, LOG_MAIN, "%s: accepted by +include_unknown", error);
+ return OK;
+ }
}
}
@@ -901,8 +895,8 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
/* End of list reached: if the last item was negated yield OK, else FAIL. */
HDEBUG(D_lists)
- debug_printf("%s %s (end of list)\n", ot, (yield == OK)? "no":"yes");
-return (yield == OK)? FAIL : OK;
+ debug_printf("%s %s (end of list)\n", ot, yield == OK ? "no":"yes");
+return yield == OK ? FAIL : OK;
/* Something deferred */
diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c
index 1420b1a79..138861815 100644
--- a/src/src/pdkim/pdkim.c
+++ b/src/src/pdkim/pdkim.c
@@ -250,16 +250,19 @@ pdkim_free_ctx(pdkim_ctx *ctx)
/* -------------------------------------------------------------------------- */
/* Matches the name of the passed raw "header" against
the passed colon-separated "tick", and invalidates
- the entry in tick. Returns OK or fail-code */
-/*XXX might be safer done using a pdkim_stringlist for "tick" */
+ the entry in tick. Entries can be prefixed for multi- or over-signing,
+ in which case do not invalidate.
+
+ Returns OK for a match, or fail-code
+*/
static int
header_name_match(const uschar * header, uschar * tick)
{
-uschar * hname;
-uschar * lcopy;
-uschar * p;
-uschar * q;
+const uschar * ticklist = tick;
+int sep = ':';
+BOOL multisign;
+uschar * hname, * p, * ele;
uschar * hcolon = Ustrchr(header, ':'); /* Get header name */
if (!hcolon)
@@ -268,27 +271,22 @@ if (!hcolon)
/* if we had strncmpic() we wouldn't need this copy */
hname = string_copyn(header, hcolon-header);
-/* Copy tick-off list locally, so we can punch zeroes into it */
-p = lcopy = string_copy(tick);
-
-for (q = Ustrchr(p, ':'); q; q = Ustrchr(p, ':'))
+while (p = US ticklist, ele = string_nextinlist(&ticklist, &sep, NULL, 0))
{
- *q = '\0';
- if (strcmpic(p, hname) == 0)
- goto found;
-
- p = q+1;
+ switch (*ele)
+ {
+ case '=': case '+': multisign = TRUE; ele++; break;
+ default: multisign = FALSE; break;
}
-if (strcmpic(p, hname) == 0)
- goto found;
-
+ if (strcmpic(ele, hname) == 0)
+ {
+ if (!multisign)
+ *p = '_'; /* Invalidate this header name instance in tick-off list */
+ return PDKIM_OK;
+ }
+ }
return PDKIM_FAIL;
-
-found:
- /* Invalidate header name instance in tick-off list */
- tick[p-lcopy] = '_';
- return PDKIM_OK;
}
@@ -1445,11 +1443,17 @@ for (sig = ctx->sig; sig; sig = sig->next)
}
}
- /* Any headers we wanted to sign but were not present must also be listed */
+ /* Any headers we wanted to sign but were not present must also be listed.
+ Ignore elements that have been ticked-off or are marked as never-oversign. */
+
l = sig->sign_headers;
while((s = string_nextinlist(&l, &sep, NULL, 0)))
- if (*s != '_')
+ {
+ if (*s == '+') /* skip oversigning marker */
+ s++;
+ if (*s != '_' && *s != '=')
g = string_append_listele(g, ':', s);
+ }
sig->headernames = string_from_gstring(g);
/* Create signature header with b= omitted */
diff --git a/src/src/receive.c b/src/src/receive.c
index 31402925d..e7e518a92 100644
--- a/src/src/receive.c
+++ b/src/src/receive.c
@@ -3388,99 +3388,96 @@ else
#ifndef DISABLE_DKIM
if (!dkim_disable_verify)
{
- /* Finish verification, this will log individual signature results to
- the mainlog */
+ /* Finish verification */
dkim_exim_verify_finish();
/* Check if we must run the DKIM ACL */
if (acl_smtp_dkim && dkim_verify_signers && *dkim_verify_signers)
{
- uschar *dkim_verify_signers_expanded =
+ uschar * dkim_verify_signers_expanded =
expand_string(dkim_verify_signers);
- if (!dkim_verify_signers_expanded)
+ gstring * results = NULL;
+ int signer_sep = 0;
+ const uschar * ptr;
+ uschar * item;
+ gstring * seen_items = NULL;
+ int old_pool = store_pool;
+
+ store_pool = POOL_PERM; /* Allow created variables to live to data ACL */
+
+ if (!(ptr = dkim_verify_signers_expanded))
log_write(0, LOG_MAIN|LOG_PANIC,
"expansion of dkim_verify_signers option failed: %s",
expand_string_message);
- else
- {
- int sep = 0;
- const uschar *ptr = dkim_verify_signers_expanded;
- uschar *item = NULL;
- gstring * seen_items = NULL;
-
- /* Default to OK when no items are present */
- rc = OK;
- while ((item = string_nextinlist(&ptr, &sep, NULL, 0)))
- {
- /* Prevent running ACL for an empty item */
- if (!item || !*item) continue;
-
- /* Only run ACL once for each domain or identity,
- no matter how often it appears in the expanded list. */
- if (seen_items)
- {
- uschar *seen_item;
- const uschar *seen_items_list = string_from_gstring(seen_items);
- BOOL seen_this_item = FALSE;
-
- while ((seen_item = string_nextinlist(&seen_items_list, &sep,
- NULL, 0)))
- if (Ustrcmp(seen_item,item) == 0)
- {
- seen_this_item = TRUE;
- break;
- }
-
- if (seen_this_item)
- {
- DEBUG(D_receive)
- debug_printf("acl_smtp_dkim: skipping signer %s, "
- "already seen\n", item);
- continue;
- }
-
- seen_items = string_cat(seen_items, ":");
- }
-
- seen_items = string_cat(seen_items, item);
-
- DEBUG(D_receive)
- debug_printf("calling acl_smtp_dkim for dkim_cur_signer=%s\n",
- item);
-
- dkim_exim_acl_setup(item);
- rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim,
- &user_msg, &log_msg);
-
- if (rc != OK)
+ /* Default to OK when no items are present */
+ rc = OK;
+ while ((item = string_nextinlist(&ptr, &signer_sep, NULL, 0)))
+ {
+ /* Prevent running ACL for an empty item */
+ if (!item || !*item) continue;
+
+ /* Only run ACL once for each domain or identity,
+ no matter how often it appears in the expanded list. */
+ if (seen_items)
+ {
+ uschar * seen_item;
+ const uschar * seen_items_list = string_from_gstring(seen_items);
+ int seen_sep = ':';
+ BOOL seen_this_item = FALSE;
+
+ while ((seen_item = string_nextinlist(&seen_items_list, &seen_sep,
+ NULL, 0)))
+ if (Ustrcmp(seen_item,item) == 0)
+ {
+ seen_this_item = TRUE;
+ break;
+ }
+
+ if (seen_this_item)
{
DEBUG(D_receive)
- debug_printf("acl_smtp_dkim: acl_check returned %d on %s, "
- "skipping remaining items\n", rc, item);
- cancel_cutthrough_connection(TRUE, US"dkim acl not ok");
- break;
+ debug_printf("acl_smtp_dkim: skipping signer %s, "
+ "already seen\n", item);
+ continue;
}
- }
- add_acl_headers(ACL_WHERE_DKIM, US"DKIM");
- if (rc == DISCARD)
- {
- recipients_count = 0;
- blackholed_by = US"DKIM ACL";
- if (log_msg != NULL)
- blackhole_log_msg = string_sprintf(": %s", log_msg);
- }
- else if (rc != OK)
- {
- Uunlink(spool_name);
- if (smtp_handle_acl_fail(ACL_WHERE_DKIM, rc, user_msg, log_msg) != 0)
- smtp_yield = FALSE; /* No more messages after dropped connection */
- smtp_reply = US""; /* Indicate reply already sent */
- message_id[0] = 0; /* Indicate no message accepted */
- goto TIDYUP; /* Skip to end of function */
- }
- }
+
+ seen_items = string_catn(seen_items, ":", 1);
+ }
+ seen_items = string_cat(seen_items, item);
+
+ rc = dkim_exim_acl_run(item, &results, &user_msg, &log_msg);
+ if (rc != OK)
+ {
+ DEBUG(D_receive)
+ debug_printf("acl_smtp_dkim: acl_check returned %d on %s, "
+ "skipping remaining items\n", rc, item);
+ cancel_cutthrough_connection(TRUE, US"dkim acl not ok");
+ break;
+ }
+ }
+ dkim_verify_status = string_from_gstring(results);
+ store_pool = old_pool;
+ add_acl_headers(ACL_WHERE_DKIM, US"DKIM");
+ if (rc == DISCARD)
+ {
+ recipients_count = 0;
+ blackholed_by = US"DKIM ACL";
+ if (log_msg)
+ blackhole_log_msg = string_sprintf(": %s", log_msg);
+ }
+ else if (rc != OK)
+ {
+ Uunlink(spool_name);
+ if (smtp_handle_acl_fail(ACL_WHERE_DKIM, rc, user_msg, log_msg) != 0)
+ smtp_yield = FALSE; /* No more messages after dropped connection */
+ smtp_reply = US""; /* Indicate reply already sent */
+ message_id[0] = 0; /* Indicate no message accepted */
+ goto TIDYUP; /* Skip to end of function */
+ }
}
+ else
+ dkim_exim_verify_log_all();
}
#endif /* DISABLE_DKIM */
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index 43094f30d..898e37cd6 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -804,6 +804,18 @@ err:
+static int
+tls_add_certfile(exim_gnutls_state_st * state, const host_item * host,
+ uschar * certfile, uschar * keyfile, uschar ** errstr)
+{
+int rc = gnutls_certificate_set_x509_key_file(state->x509_cred,
+ CS certfile, CS keyfile, GNUTLS_X509_FMT_PEM);
+exim_gnutls_err_check(
+ string_sprintf("cert/key setup: cert=%s key=%s", certfile, keyfile));
+return OK;
+}
+
+
/*************************************************
* Variables re-expanded post-SNI *
*************************************************/
@@ -824,7 +836,7 @@ Returns: OK/DEFER/FAIL
*/
static int
-tls_expand_session_files(exim_gnutls_state_st *state, uschar ** errstr)
+tls_expand_session_files(exim_gnutls_state_st * state, uschar ** errstr)
{
struct stat statbuf;
int rc;
@@ -839,11 +851,11 @@ int cert_count;
if (!host) /* server */
if (!state->received_sni)
{
- if (state->tls_certificate &&
- (Ustrstr(state->tls_certificate, US"tls_sni") ||
- Ustrstr(state->tls_certificate, US"tls_in_sni") ||
- Ustrstr(state->tls_certificate, US"tls_out_sni")
- ))
+ if ( state->tls_certificate
+ && ( Ustrstr(state->tls_certificate, US"tls_sni")
+ || Ustrstr(state->tls_certificate, US"tls_in_sni")
+ || Ustrstr(state->tls_certificate, US"tls_out_sni")
+ ) )
{
DEBUG(D_tls) debug_printf("We will re-expand TLS session files if we receive SNI.\n");
state->trigger_sni_changes = TRUE;
@@ -910,13 +922,29 @@ if (state->exp_tls_certificate && *state->exp_tls_certificate)
DEBUG(D_tls) debug_printf("TLS SNI: have a changed cert/key pair.\n");
}
- rc = gnutls_certificate_set_x509_key_file(state->x509_cred,
- CS state->exp_tls_certificate, CS state->exp_tls_privatekey,
- GNUTLS_X509_FMT_PEM);
- exim_gnutls_err_check(
- string_sprintf("cert/key setup: cert=%s key=%s",
- state->exp_tls_certificate, state->exp_tls_privatekey));
- DEBUG(D_tls) debug_printf("TLS: cert/key registered\n");
+ if (!host) /* server */
+ {
+ const uschar * clist = state->exp_tls_certificate;
+ const uschar * klist = state->exp_tls_privatekey;
+ int csep = 0, ksep = 0;
+ uschar * cfile, * kfile;
+
+ while (cfile = string_nextinlist(&clist, &csep, NULL, 0))
+ if (!(kfile = string_nextinlist(&klist, &ksep, NULL, 0)))
+ return tls_error(US"cert/key setup: out of keys", NULL, host, errstr);
+ else if ((rc = tls_add_certfile(state, host, cfile, kfile, errstr)))
+ return rc;
+ else
+ DEBUG(D_tls) debug_printf("TLS: cert/key %s registered\n", cfile);
+ }
+ else
+ {
+ if ((rc = tls_add_certfile(state, host,
+ state->exp_tls_certificate, state->exp_tls_privatekey, errstr)))
+ return rc;
+ DEBUG(D_tls) debug_printf("TLS: cert/key registered\n");
+ }
+
} /* tls_certificate */
@@ -1276,7 +1304,7 @@ if (host)
}
else if (state->tls_sni)
DEBUG(D_tls) debug_printf("*** PROBABLY A BUG *** " \
- "have an SNI set for a client [%s]\n", state->tls_sni);
+ "have an SNI set for a server [%s]\n", state->tls_sni);
/* This is the priority string support,
http://www.gnutls.org/manual/html_node/Priority-Strings.html
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index 58401e932..f1176a63e 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -1024,6 +1024,30 @@ err:
+static int
+tls_add_certfile(SSL_CTX * sctx, tls_ext_ctx_cb * cbinfo, uschar * file,
+ uschar ** errstr)
+{
+DEBUG(D_tls) debug_printf("tls_certificate file %s\n", file);
+if (!SSL_CTX_use_certificate_chain_file(sctx, CS file))
+ return tls_error(string_sprintf(
+ "SSL_CTX_use_certificate_chain_file file=%s", file),
+ cbinfo->host, NULL, errstr);
+return 0;
+}
+
+static int
+tls_add_pkeyfile(SSL_CTX * sctx, tls_ext_ctx_cb * cbinfo, uschar * file,
+ uschar ** errstr)
+{
+DEBUG(D_tls) debug_printf("tls_privatekey file %s\n", file);
+if (!SSL_CTX_use_PrivateKey_file(sctx, CS file, SSL_FILETYPE_PEM))
+ return tls_error(string_sprintf(
+ "SSL_CTX_use_PrivateKey_file file=%s", file), cbinfo->host, NULL, errstr);
+return 0;
+}
+
+
/*************************************************
* Expand key and cert file specs *
*************************************************/
@@ -1048,7 +1072,7 @@ uschar *expanded;
if (!cbinfo->certificate)
{
- if (cbinfo->host) /* client */
+ if (!cbinfo->is_server) /* client */
return OK;
/* server */
if (tls_install_selfsign(sctx, errstr) != OK)
@@ -1056,6 +1080,8 @@ if (!cbinfo->certificate)
}
else
{
+ int err;
+
if (Ustrstr(cbinfo->certificate, US"tls_sni") ||
Ustrstr(cbinfo->certificate, US"tls_in_sni") ||
Ustrstr(cbinfo->certificate, US"tls_out_sni")
@@ -1065,14 +1091,20 @@ else
if (!expand_check(cbinfo->certificate, US"tls_certificate", &expanded, errstr))
return DEFER;
- if (expanded != NULL)
- {
- DEBUG(D_tls) debug_printf("tls_certificate file %s\n", expanded);
- if (!SSL_CTX_use_certificate_chain_file(sctx, CS expanded))
- return tls_error(string_sprintf(
- "SSL_CTX_use_certificate_chain_file file=%s", expanded),
- cbinfo->host, NULL, errstr);
- }
+ if (expanded)
+ if (cbinfo->is_server)
+ {
+ const uschar * file_list = expanded;
+ int sep = 0;
+ uschar * file;
+
+ while (file = string_nextinlist(&file_list, &sep, NULL, 0))
+ if ((err = tls_add_certfile(sctx, cbinfo, file, errstr)))
+ return err;
+ }
+ else /* would there ever be a need for multiple client certs? */
+ if ((err = tls_add_certfile(sctx, cbinfo, expanded, errstr)))
+ return err;
if (cbinfo->privatekey != NULL &&
!expand_check(cbinfo->privatekey, US"tls_privatekey", &expanded, errstr))
@@ -1083,12 +1115,19 @@ else
key is in the same file as the certificate. */
if (expanded && *expanded)
- {
- DEBUG(D_tls) debug_printf("tls_privatekey file %s\n", expanded);
- if (!SSL_CTX_use_PrivateKey_file(sctx, CS expanded, SSL_FILETYPE_PEM))
- return tls_error(string_sprintf(
- "SSL_CTX_use_PrivateKey_file file=%s", expanded), cbinfo->host, NULL, errstr);
- }
+ if (cbinfo->is_server)
+ {
+ const uschar * file_list = expanded;
+ int sep = 0;
+ uschar * file;
+
+ while (file = string_nextinlist(&file_list, &sep, NULL, 0))
+ if ((err = tls_add_pkeyfile(sctx, cbinfo, file, errstr)))
+ return err;
+ }
+ else /* would there ever be a need for multiple client certs? */
+ if ((err = tls_add_pkeyfile(sctx, cbinfo, expanded, errstr)))
+ return err;
}
#ifndef DISABLE_OCSP
diff --git a/src/src/transport-filter.src b/src/src/transport-filter.src
index 3f250e657..db00d877f 100644
--- a/src/src/transport-filter.src
+++ b/src/src/transport-filter.src
@@ -13,6 +13,14 @@
use warnings;
BEGIN { pop @INC if $INC[-1] eq '.' };
+use File::Basename;
+
+if ($ARGV[0] eq '--version') {
+ print basename($0) . ": $0\n",
+ "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n",
+ "perl(runtime): $]\n";
+ exit 0;
+}
# If the filter is called with any arguments, insert them into the message
# as X-Arg headers, just to verify what they are.