Gitweb:
https://git.exim.org/exim.git/commitdiff/7dc8d146a675f52b441310e731314d86c66b2114
Commit: 7dc8d146a675f52b441310e731314d86c66b2114
Parent: e93ae25c007845adff89736d7d292fe75b8a0c7a
Author: Jeremy Harris <jgh146exb@???>
AuthorDate: Wed Aug 28 22:01:24 2024 +0100
Committer: Jeremy Harris <jgh146exb@???>
CommitDate: Thu Aug 29 09:33:26 2024 +0100
dmarc dynamic module
---
doc/doc-docbook/spec.xfpt | 14 ++++-
src/OS/Makefile-Base | 2 -
src/scripts/Configure-Makefile | 12 +++-
src/scripts/MakeLinks | 4 +-
src/src/EDITME | 7 +++
src/src/acl.c | 51 +++++++++++++---
src/src/arc.c | 2 +-
src/src/daemon.c | 3 -
src/src/drtables.c | 56 ++++++++++++++++--
src/src/exim.c | 6 +-
src/src/exim.h | 2 +-
src/src/expand.c | 21 +++++--
src/src/functions.h | 8 ++-
src/src/globals.c | 9 ---
src/src/globals.h | 9 ---
src/src/lookups/spf.c | 6 +-
src/src/miscmods/Makefile | 3 +-
src/src/{ => miscmods}/dmarc.c | 128 ++++++++++++++++++++++++++++++++---------
src/src/{ => miscmods}/dmarc.h | 13 +----
src/src/miscmods/spf.c | 27 ++++-----
src/src/moan.c | 3 +-
src/src/readconf.c | 21 ++++---
src/src/receive.c | 16 ++++--
src/src/smtp_in.c | 35 +++--------
src/src/structs.h | 3 +
test/runtest | 4 +-
test/stderr/0437 | 1 +
27 files changed, 312 insertions(+), 154 deletions(-)
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 428cbc079..90fb6dd47 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -32055,12 +32055,20 @@ This control turns off DKIM verification processing entirely. For details on
the operation and configuration of DKIM, see section &<<SECDKIM>>&.
-.vitem &*control&~=&~dmarc_disable_verify*&
+.vitem &*control&~=&~enforce_sync*& &&&
+ &*control&~=&~no_enforce_sync*&
+
+.vitem &*control&~=&~dmarc_disable_verify*& &&&
+ &*control&~=&~dmarc_enable_forensic*&
.cindex "disable DMARC verify"
-.cindex "DMARC" "disable verify"
-This control turns off DMARC verification processing entirely. For details on
+.cindex DMARC "disable verify"
+.cindex DMARC controls
+.cindex DMARC "forensic mails"
+These control affect DMARC processing. For details on
the operation and configuration of DMARC, see section &<<SECDMARC>>&.
+The &"disable"& turns off DMARC verification processing entirely.
+
.vitem &*control&~=&~dscp/*&<&'value'&>
.cindex "&ACL;" "setting DSCP value"
diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base
index caae1e536..43cec361c 100644
--- a/src/OS/Makefile-Base
+++ b/src/OS/Makefile-Base
@@ -499,7 +499,6 @@ OBJ_EXPERIMENTAL = arc.o \
bmi_spam.o \
dane.o \
dcc.o \
- dmarc.o \
imap_utf7.o \
utf8.o \
xclient.o
@@ -901,7 +900,6 @@ arc.o: $(HDRS) pdkim/pdkim.h arc.c
bmi_spam.o: $(HDRS) bmi_spam.c
dane.o: $(HDRS) dane.c dane-openssl.c
dcc.o: $(HDRS) dcc.h dcc.c
-dmarc.o: $(HDRS) pdkim/pdkim.h dmarc.h dmarc.c
imap_utf7.o: $(HDRS) imap_utf7.c
utf8.o: $(HDRS) utf8.c
xclient.o: $(HDRS) xclient.c
diff --git a/src/scripts/Configure-Makefile b/src/scripts/Configure-Makefile
index af0de26e4..2b8a9bcb5 100755
--- a/src/scripts/Configure-Makefile
+++ b/src/scripts/Configure-Makefile
@@ -29,6 +29,16 @@ fi
archtype=`../scripts/arch-type` || exit 1
+# Linux now whines about egrep, saying "use grep -E".
+# Solarix doesn't support -E on grep. Thanks so much for
+# going non-back-compatible, Linux.
+if echo 1 | grep -E 1 >/dev/null; then
+ egrep="grep -E"
+else
+ egrep="egrep"
+fi
+
+
# Now test for either the non-existence of Makefile, or for any of its
# components being newer. Note that the "newer" script gives the right
# answer (for our purposes) when the first file is non-existent.
@@ -311,7 +321,7 @@ done <<-END
routers ROUTER ACCEPT DNSLOOKUP IPLITERAL IPLOOKUP MANUALROUTE QUERYPROGRAM REDIRECT
transports TRANSPORT APPENDFILE AUTOREPLY LMTP PIPE QUEUEFILE SMTP
auths AUTH CRAM_MD5 CYRUS_SASL DOVECOT EXTERNAL GSASL HEIMDAL_GSSAPI PLAINTEXT SPA TLS
- miscmods SUPPORT SPF
+ miscmods SUPPORT SPF DMARC
END
# See if there is a definition of EXIM_PERL in what we have built so far.
diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks
index 09d18b63c..e45097243 100755
--- a/src/scripts/MakeLinks
+++ b/src/scripts/MakeLinks
@@ -94,7 +94,7 @@ d="miscmods"
mkdir $d
cd $d
# Makefile is generated
-for f in spf.c spf.h
+for f in dmarc.c dmarc.h spf.c spf.h
do
ln -s ../../src/$d/$f $f
done
@@ -140,7 +140,7 @@ for f in blob.h dbfunctions.h exim.h functions.h globals.h \
string.c tls.c tlscert-gnu.c tlscert-openssl.c tls-cipher-stdname.c \
tls-gnu.c tls-openssl.c \
tod.c transport.c tree.c verify.c version.c xtextencode.c \
- dkim.c dkim.h dkim_transport.c dmarc.c dmarc.h \
+ dkim.c dkim.h dkim_transport.c \
valgrind.h memcheck.h \
macro_predef.c macro_predef.h
do
diff --git a/src/src/EDITME b/src/src/EDITME
index e507ab3cd..35c497697 100644
--- a/src/src/EDITME
+++ b/src/src/EDITME
@@ -642,9 +642,16 @@ DISABLE_MAL_MKS=yes
# Uncomment the following line to add DMARC checking capability, implemented
# using libopendmarc libraries. You must have SPF and DKIM support enabled also.
+#
+# If set to "2" instead of "yes" then the support will be
+# built as a module and must be installed into LOOKUP_MODULE_DIR (the name
+# is historic). The same rules as for other module builds apply; use
+# SUPPORT_DMARC_{INCLUDE,LIBS}.
+#
# SUPPORT_DMARC=yes
# CFLAGS += -I/usr/local/include
# LDFLAGS += -lopendmarc
+#
# Uncomment the following if you need to change the default. You can
# override it at runtime (main config option dmarc_tld_file)
# DMARC_TLD_FILE=/etc/exim/opendmarc.tlds
diff --git a/src/src/acl.c b/src/src/acl.c
index e285da65c..30fc09174 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -218,7 +218,11 @@ static condition_def conditions[] = {
},
#endif
#ifdef SUPPORT_DMARC
- [ACLC_DMARC_STATUS] = { US"dmarc_status", ACD_EXP,
+ [ACLC_DMARC_STATUS] = { US"dmarc_status",
+# if SUPPORT_DMARC==2
+ ACD_LOAD |
+# endif
+ ACD_EXP,
PERMITTED(ACL_BIT_DATA) },
#endif
@@ -393,6 +397,9 @@ for (condition_def * c = conditions; c < conditions + nelem(conditions); c++)
#ifndef MACRO_PREDEF
+/* These tables support loading of dynamic modules triggered by an ACL
+condition use, spotted during readconf. See acl_read(). */
+
# ifdef LOOKUP_MODULE_DIR
typedef struct condition_module {
const uschar * mod_name; /* module for the givien conditions */
@@ -403,11 +410,17 @@ typedef struct condition_module {
# if SUPPORT_SPF==2
static int spf_condx[] = { ACLC_SPF, ACLC_SPF_GUESS, -1 };
# endif
+# if SUPPORT_DMARC==2
+static int dmarc_condx[] = { ACLC_DMARC_STATUS, -1 };
+# endif
static condition_module condition_modules[] = {
# if SUPPORT_SPF==2
{.mod_name = US"spf", .conditions = spf_condx},
# endif
+# if SUPPORT_SPF==2
+ {.mod_name = US"dmarc", .conditions = dmarc_condx},
+# endif
};
# endif
@@ -3942,14 +3955,36 @@ for (; cb; cb = cb->next)
#ifdef SUPPORT_DMARC
case ACLC_DMARC_STATUS:
+ /* See comment on ACLC_SPF wrt. coding issues */
+ {
+ misc_module_info * mi = misc_mod_find(US"dmarc", &log_message);
+ typedef uschar * (*efn_t)(int);
+ uschar * expanded_query;
+
+debug_printf("%s %d\n", __FUNCTION__, __LINE__);
+ if (!mi)
+ { rc = DEFER; break; } /* shouldn't happen */
+
+debug_printf("%s %d: mi %p\n", __FUNCTION__, __LINE__, mi);
if (!f.dmarc_has_been_checked)
- dmarc_process();
- f.dmarc_has_been_checked = TRUE;
+ {
+ typedef int (*pfn_t)(void);
+ (void) (((pfn_t *) mi->functions)[0]) (); /* dmarc_process */
+ f.dmarc_has_been_checked = TRUE;
+ }
+debug_printf("%s %d\n", __FUNCTION__, __LINE__);
/* used long way of dmarc_exim_expand_query() in case we need more
view into the process in the future. */
- rc = match_isinlist(dmarc_exim_expand_query(DMARC_VERIFY_STATUS),
+
+ /*XXX is this call used with any other arg? */
+ expanded_query = (((efn_t *) mi->functions)[1]) (DMARC_VERIFY_STATUS);
+
+debug_printf("%s %d\n", __FUNCTION__, __LINE__);
+ rc = match_isinlist(expanded_query,
&arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL);
+debug_printf("%s %d\n", __FUNCTION__, __LINE__);
+ }
break;
#endif
@@ -4185,8 +4220,10 @@ for (; cb; cb = cb->next)
#ifdef SUPPORT_SPF
case ACLC_SPF:
case ACLC_SPF_GUESS:
- /* Hardwire the offset of the function in the module functions table
- for now. Work out a more general mech later. */
+ /* We have hardwired function-call numbers, and also prototypes for the
+ functions. We could do a function name table search for the number
+ but I can't see how to deal with prototypes. Is a K&R non-prototyped
+ function still usable with today's compilers? */
{
misc_module_info * mi = misc_mod_find(US"spf", &log_message);
typedef int (*fn_t)(const uschar **, const uschar *, int);
@@ -4195,7 +4232,7 @@ for (; cb; cb = cb->next)
if (!mi)
{ rc = DEFER; break; } /* shouldn't happen */
- fn = ((fn_t *) mi->functions)[1];
+ fn = ((fn_t *) mi->functions)[0]; /* spf_process() */
rc = fn(&arg, sender_address,
cb->type == ACLC_SPF ? SPF_PROCESS_NORMAL : SPF_PROCESS_GUESS);
diff --git a/src/src/arc.c b/src/src/arc.c
index 48f69a8cf..2dcbf2efb 100644
--- a/src/src/arc.c
+++ b/src/src/arc.c
@@ -19,7 +19,7 @@
# include "pdkim/signing.h"
# ifdef SUPPORT_DMARC
-# include "dmarc.h"
+# include "miscmods/dmarc.h"
# endif
extern pdkim_ctx * dkim_verify_ctx;
diff --git a/src/src/daemon.c b/src/src/daemon.c
index 49bf74a11..456c586da 100644
--- a/src/src/daemon.c
+++ b/src/src/daemon.c
@@ -2578,9 +2578,6 @@ smtp_deliver_init(); /* Used for callouts */
#ifdef WITH_CONTENT_SCAN
malware_init();
#endif
-#ifdef SUPPORT_DMARC
-dmarc_init();
-#endif
#ifndef DISABLE_TLS
tls_daemon_init();
#endif
diff --git a/src/src/drtables.c b/src/src/drtables.c
index 35a376dd1..9ed55e29a 100644
--- a/src/src/drtables.c
+++ b/src/src/drtables.c
@@ -432,8 +432,8 @@ static void
misc_mod_add(misc_module_info * mi)
{
if (mi->init) mi->init(mi);
-DEBUG(D_lookup) if (mi->lib_vers_report)
- debug_printf_indent("%Y\n", mi->lib_vers_report(NULL));
+DEBUG(D_any) if (mi->lib_vers_report)
+ debug_printf_indent("%Y", mi->lib_vers_report(NULL));
mi->next = misc_module_list;
misc_module_list = mi;
@@ -459,8 +459,10 @@ mi = (struct misc_module_info *) dlsym(dl,
CS string_sprintf("%s_module_info", name));
if ((errormsg = dlerror()))
{
- fprintf(stderr, "%s does not appear to be an spf module (%s)\n", name, errormsg);
- log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be an spf module (%s)", name, errormsg);
+ fprintf(stderr, "%s does not appear to be a '%s' module (%s)\n",
+ name, name, errormsg);
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "%s does not contain the expected module info symbol (%s)", name, errormsg);
dlclose(dl);
return NULL;
}
@@ -491,6 +493,7 @@ misc_mod_findonly(const uschar * name)
for (misc_module_info * mi = misc_module_list; mi; mi = mi->next)
if (Ustrcmp(name, mi->name) == 0)
return mi;
+return NULL;
}
/* Find a "misc" module, possibly already loaded, by name. */
@@ -508,6 +511,42 @@ return NULL;
}
+/* For any "misc" module having a connection-init routine, call it. */
+
+int
+misc_mod_conn_init(const uschar * sender_helo_name,
+ const uschar * sender_host_address)
+{
+for (const misc_module_info * mi = misc_module_list; mi; mi = mi->next)
+ if (mi->conn_init)
+ if ((mi->conn_init) (sender_helo_name, sender_host_address) != OK)
+ return FAIL;
+return OK;
+}
+
+/* Ditto, smtp-reset */
+
+void
+misc_mod_smtp_reset(void)
+{
+for (const misc_module_info * mi = misc_module_list; mi; mi = mi->next)
+ if (mi->smtp_reset)
+ (mi->smtp_reset)();
+}
+
+/* Ditto, msg-init */
+
+int
+misc_mod_msg_init(void)
+{
+for (const misc_module_info * mi = misc_module_list; mi; mi = mi->next)
+ if (mi->msg_init)
+ if ((mi->msg_init)() != OK)
+ return FAIL;
+return OK;
+}
+
+
@@ -658,6 +697,9 @@ DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
}
+#if defined(SUPPORT_DMARC) && SUPPORT_DMARC!=2
+extern misc_module_info dmarc_module_info;
+#endif
#if defined(SUPPORT_SPF) && SUPPORT_SPF!=2
extern misc_module_info spf_module_info;
#endif
@@ -667,9 +709,15 @@ init_misc_mod_list(void)
{
static BOOL onetime = FALSE;
if (onetime) return;
+
#if defined(SUPPORT_SPF) && SUPPORT_SPF!=2
+/* dmarc depends on spf so this add must go first, for the dmarc-static case */
misc_mod_add(&spf_module_info);
#endif
+#if defined(SUPPORT_DMARC) && SUPPORT_DMARC!=2
+misc_mod_add(&dmarc_module_info);
+#endif
+
onetime = TRUE;
}
diff --git a/src/src/exim.c b/src/src/exim.c
index ecc25d6bc..5ad54ffc1 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -1395,9 +1395,9 @@ DEBUG(D_any)
#ifdef SUPPORT_I18N
g = utf8_version_report(g);
#endif
-#ifdef SUPPORT_DMARC
- g = dmarc_version_report(g);
-#endif
+
+/*XXX do we need a "show misc-mods version-report" ?
+Currently they are output in misc_mod_add() */
show_string(is_stdout, g);
g = NULL;
diff --git a/src/src/exim.h b/src/src/exim.h
index 470adb351..284748c5d 100644
--- a/src/src/exim.h
+++ b/src/src/exim.h
@@ -549,7 +549,7 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly.
# include "dkim.h"
#endif
#ifdef SUPPORT_DMARC
-# include "dmarc.h"
+# include "miscmods/dmarc.h"
# include <opendmarc/dmarc.h>
#endif
diff --git a/src/src/expand.c b/src/src/expand.c
index b3a1575a7..a6b05bd87 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -513,10 +513,10 @@ static var_entry var_table[] = {
{ "dkim_verify_status", vtype_stringptr, &dkim_verify_status },
#endif
#ifdef SUPPORT_DMARC
- { "dmarc_domain_policy", vtype_stringptr, &dmarc_domain_policy },
- { "dmarc_status", vtype_stringptr, &dmarc_status },
- { "dmarc_status_text", vtype_stringptr, &dmarc_status_text },
- { "dmarc_used_domain", vtype_stringptr, &dmarc_used_domain },
+ { "dmarc_domain_policy", vtype_module, US"dmarc" },
+ { "dmarc_status", vtype_module, US"dmarc" },
+ { "dmarc_status_text", vtype_module, US"dmarc" },
+ { "dmarc_used_domain", vtype_module, US"dmarc" },
#endif
{ "dnslist_domain", vtype_stringptr, &dnslist_domain },
{ "dnslist_matched", vtype_stringptr, &dnslist_matched },
@@ -4888,7 +4888,7 @@ while (*s)
if (mi)
{
typedef gstring * (*fn_t)(gstring *);
- fn_t fn = ((fn_t *) mi->functions)[2]; /* authres_spf */
+ fn_t fn = ((fn_t *) mi->functions)[1]; /* authres_spf */
yield = fn(yield);
}
}
@@ -4897,7 +4897,16 @@ while (*s)
yield = authres_dkim(yield);
#endif
#ifdef SUPPORT_DMARC
- yield = authres_dmarc(yield);
+ {
+ misc_module_info * mi = misc_mod_findonly(US"dmarc");
+ if (mi)
+ {
+ /*XXX is authres common enough to be generic? */
+ typedef gstring * (*fn_t)(gstring *);
+ fn_t fn = ((fn_t *) mi->functions)[2]; /* authres_dmarc*/
+ yield = fn(yield);
+ }
+ }
#endif
#ifdef EXPERIMENTAL_ARC
yield = authres_arc(yield);
diff --git a/src/src/functions.h b/src/src/functions.h
index aaec6461f..3a980318f 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -147,9 +147,6 @@ extern gstring *authres_arc(gstring *);
#ifndef DISABLE_DKIM
extern gstring *authres_dkim(gstring *);
#endif
-#ifdef SUPPORT_DMARC
-extern gstring *authres_dmarc(gstring *);
-#endif
extern gstring *authres_smtpauth(gstring *);
extern uschar *b64encode(const uschar *, int);
@@ -377,8 +374,13 @@ extern ssize_t mime_decode_base64(FILE *, FILE *, uschar *);
extern int mime_regex(const uschar **, BOOL);
extern void mime_set_anomaly(int);
#endif
+
+extern int misc_mod_conn_init(const uschar *, const uschar *);
extern misc_module_info * misc_mod_find(const uschar * modname, uschar **);
extern misc_module_info * misc_mod_findonly(const uschar * modname);
+extern int misc_mod_msg_init(void);
+extern void misc_mod_smtp_reset(void);
+
extern uschar *moan_check_errorcopy(const uschar *);
extern BOOL moan_skipped_syntax_errors(uschar *, error_block *, uschar *,
BOOL, uschar *);
diff --git a/src/src/globals.c b/src/src/globals.c
index f2287d41c..cfa75f1d7 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -882,15 +882,6 @@ uschar *dkim_verify_signers = US"$dkim_signers";
uschar *dkim_verify_status = NULL;
uschar *dkim_verify_reason = NULL;
#endif
-#ifdef SUPPORT_DMARC
-uschar *dmarc_domain_policy = NULL;
-uschar *dmarc_forensic_sender = NULL;
-uschar *dmarc_history_file = NULL;
-uschar *dmarc_status = NULL;
-uschar *dmarc_status_text = NULL;
-uschar *dmarc_tld_file = NULL;
-uschar *dmarc_used_domain = NULL;
-#endif
uschar *dns_again_means_nonexist = NULL;
int dns_csa_search_limit = 5;
diff --git a/src/src/globals.h b/src/src/globals.h
index 9b30e502c..8173d771e 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -563,15 +563,6 @@ extern uschar *dkim_verify_signers; /* Colon-separated list of domains for ea
extern uschar *dkim_verify_status; /* result for this signature */
extern uschar *dkim_verify_reason; /* result for this signature */
#endif
-#ifdef SUPPORT_DMARC
-extern uschar *dmarc_domain_policy; /* Expansion for declared policy of used domain */
-extern uschar *dmarc_forensic_sender; /* Set sender address for forensic reports */
-extern uschar *dmarc_history_file; /* Expansion variable, file to store dmarc results */
-extern uschar *dmarc_status; /* Expansion variable, one word value */
-extern uschar *dmarc_status_text; /* Expansion variable, human readable value */
-extern uschar *dmarc_tld_file; /* Mozilla TLDs text file */
-extern uschar *dmarc_used_domain; /* Expansion variable, domain libopendmarc chose for DMARC policy lookup */
-#endif
extern uschar *dns_again_means_nonexist; /* Domains that are badly set up */
extern int dns_csa_search_limit; /* How deep to search for CSA SRV records */
diff --git a/src/src/lookups/spf.c b/src/src/lookups/spf.c
index 4e0824911..a06f9117d 100644
--- a/src/src/lookups/spf.c
+++ b/src/src/lookups/spf.c
@@ -39,7 +39,7 @@ misc_module_info * mi = misc_mod_find(US"spf", errmsg);
if (mi)
{
typedef void * (*fn_t)(const uschar *, uschar **);
- return (((fn_t *) mi->functions)[5]) (filename, errmsg);
+ return (((fn_t *) mi->functions)[3]) (filename, errmsg);
}
return NULL;
}
@@ -52,7 +52,7 @@ misc_module_info * mi = misc_mod_find(US"spf", NULL);
if (mi)
{
typedef void (*fn_t)(void *);
- return (((fn_t *) mi->functions)[6]) (handle);
+ return (((fn_t *) mi->functions)[4]) (handle);
}
}
@@ -67,7 +67,7 @@ if (mi)
{
typedef int (*fn_t) (void *, const uschar *, const uschar *,
int, uschar **, uschar **, uint *, const uschar *);
- return (((fn_t *) mi->functions)[7]) (handle, filename, keystring, key_len,
+ return (((fn_t *) mi->functions)[5]) (handle, filename, keystring, key_len,
result, errmsg, do_cache, opts);
}
return FAIL;
diff --git a/src/src/miscmods/Makefile b/src/src/miscmods/Makefile
index 59bf29836..d20b7a9f1 100644
--- a/src/src/miscmods/Makefile
+++ b/src/src/miscmods/Makefile
@@ -26,6 +26,7 @@ miscmods.a: $(OBJ)
.c.so:; @echo "$(CC) -shared $*.c"
$(FE)$(CC) $(SUPPORT_$*_INCLUDE) $(SUPPORT_$*_LIBS) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) $*.c -o $@
-spf.o spf.so: $(HDRS) spf.h spf.c
+spf.o spf.so: $(HDRS) spf.h spf.c
+dmarc.o dmarc.so: $(HDRS) ../pdkim/pdkim.h dmarc.h dmarc.c
# End
diff --git a/src/src/dmarc.c b/src/src/miscmods/dmarc.c
similarity index 87%
rename from src/src/dmarc.c
rename to src/src/miscmods/dmarc.c
index 664daa737..0a97bf6b7 100644
--- a/src/src/dmarc.c
+++ b/src/src/miscmods/dmarc.c
@@ -12,7 +12,7 @@
/* Code for calling dmarc checks via libopendmarc. Called from acl.c. */
-#include "exim.h"
+#include "../exim.h"
#ifdef SUPPORT_DMARC
# if !defined SUPPORT_SPF
# error SPF must also be enabled for DMARC
@@ -20,9 +20,9 @@
# error DKIM must also be enabled for DMARC
# else
-# include "functions.h"
+# include "../functions.h"
# include "dmarc.h"
-# include "pdkim/pdkim.h"
+# include "../pdkim/pdkim.h"
OPENDMARC_LIB_T dmarc_ctx;
DMARC_POLICY_T *dmarc_pctx = NULL;
@@ -55,8 +55,22 @@ static dmarc_exim_p dmarc_policy_description[] = {
};
-int
-dmarc_init(void)
+/* $variables */
+uschar * dmarc_domain_policy = NULL; /* Declared policy of used domain */
+uschar * dmarc_status = NULL; /* One word value */
+uschar * dmarc_status_text = NULL; /* Human readable value */
+uschar * dmarc_used_domain = NULL; /* Domain libopendmarc chose for DMARC policy lookup */
+
+/* options */
+uschar * dmarc_forensic_sender = NULL; /* Set sender address for forensic reports */
+uschar * dmarc_history_file = NULL; /* File to store dmarc results */
+uschar * dmarc_tld_file = NULL; /* Mozilla TLDs text file */
+
+
+/* One-time initialisation for dmarc. Ensure the spf module is available. */
+
+static BOOL
+dmarc_init(void *)
{
uschar * errstr;
if (!(spf_mod_info = misc_mod_find(US"spf", &errstr)))
@@ -65,12 +79,14 @@ if (!(spf_mod_info = misc_mod_find(US"spf", &errstr)))
return TRUE;
}
-gstring *
+static gstring *
dmarc_version_report(gstring * g)
{
return string_fmt_append(g, "Library version: dmarc: Compile: %d.%d.%d.%d\n",
- (OPENDMARC_LIB_VERSION & 0xff000000) >> 24, (OPENDMARC_LIB_VERSION & 0x00ff0000) >> 16,
- (OPENDMARC_LIB_VERSION & 0x0000ff00) >> 8, OPENDMARC_LIB_VERSION & 0x000000ff);
+ (OPENDMARC_LIB_VERSION & 0xff000000) >> 24,
+ (OPENDMARC_LIB_VERSION & 0x00ff0000) >> 16,
+ (OPENDMARC_LIB_VERSION & 0x0000ff00) >> 8,
+ (OPENDMARC_LIB_VERSION & 0x000000ff));
}
@@ -98,12 +114,14 @@ eb->next = NULL;
return eblock;
}
-/* dmarc_conn_init sets up a context that can be re-used for several
+/* dmarc_msg_init sets up a context that can be re-used for several
messages on the same SMTP connection (that come from the
-same host with the same HELO string) */
+same host with the same HELO string).
+However, we seem to only use it for one; we destroy some sort of context
+at the tail end of dmarc_process(). */
-int
-dmarc_conn_init(void)
+static int
+dmarc_msg_init()
{
int *netmask = NULL; /* Ignored */
int is_ipv6 = 0;
@@ -167,11 +185,19 @@ return OK;
}
+static void
+dmarc_smtp_reset(void)
+{
+dmarc_domain_policy = dmarc_status = dmarc_status_text =
+dmarc_used_domain = NULL;
+}
+
+
/* dmarc_store_data stores the header data so that subsequent dmarc_process can
access the data.
Called after the entire message has been received, with the From: header. */
-int
+static int
dmarc_store_data(header_line * hdr)
{
/* No debug output because would change every test debug output */
@@ -362,7 +388,7 @@ context (if any), retrieves the result, sets up expansion
strings and evaluates the condition outcome.
Called for the first ACL dmarc= condition. */
-int
+static int
dmarc_process(void)
{
int sr, origin; /* used in SPF section */
@@ -433,10 +459,9 @@ if (!dmarc_abort && !sender_host_authenticated)
spf_sender_domain = expand_string(US"$sender_address_domain");
{
- misc_module_info * mi = misc_mod_findonly(US"spf");
typedef SPF_response_t * (*fn_t)(void);
- if (mi)
- spf_response_p = ((fn_t *) mi->functions)[3](); /* spf_get_response */
+ if (spf_mod_info)
+ spf_response_p = ((fn_t *) spf_mod_info->functions)[2](); /* spf_get_response */
}
if (!spf_response_p)
@@ -673,27 +698,27 @@ if (!f.dmarc_disable_verify)
return OK;
}
-uschar *
-dmarc_exim_expand_query(int what)
+static uschar *
+dmarc_exim_expand_defaults(int what)
{
-if (f.dmarc_disable_verify || !dmarc_pctx)
- return dmarc_exim_expand_defaults(what);
-
if (what == DMARC_VERIFY_STATUS)
- return dmarc_status;
+ return f.dmarc_disable_verify ? US"off" : US"none";
return US"";
}
-uschar *
-dmarc_exim_expand_defaults(int what)
+static uschar *
+dmarc_exim_expand_query(int what)
{
+if (f.dmarc_disable_verify || !dmarc_pctx)
+ return dmarc_exim_expand_defaults(what);
+
if (what == DMARC_VERIFY_STATUS)
- return f.dmarc_disable_verify ? US"off" : US"none";
+ return dmarc_status;
return US"";
}
-gstring *
+static gstring *
authres_dmarc(gstring * g)
{
if (f.dmarc_has_been_checked)
@@ -711,6 +736,55 @@ else
return g;
}
+/******************************************************************************/
+/* Module API */
+
+static optionlist dmarc_options[] = {
+ { "dmarc_forensic_sender", opt_stringptr, {&dmarc_forensic_sender} },
+ { "dmarc_history_file", opt_stringptr, {&dmarc_history_file} },
+ { "dmarc_tld_file", opt_stringptr, {&dmarc_tld_file} },
+};
+
+static void * dmarc_functions[] = {
+ dmarc_process,
+ dmarc_exim_expand_query,
+ authres_dmarc,
+ dmarc_store_data,
+};
+
+/* dmarc_forensic_sender is provided for visibility of the the option setting
+by moan_send_message. We do not document it as a config-visible $variable.
+We could provide it via a function but there's little advantage. */
+
+static var_entry dmarc_variables[] = {
+ { "dmarc_domain_policy", vtype_stringptr, &dmarc_domain_policy },
+ { "dmarc_forensic_sender", vtype_stringptr, &dmarc_forensic_sender },
+ { "dmarc_status", vtype_stringptr, &dmarc_status },
+ { "dmarc_status_text", vtype_stringptr, &dmarc_status_text },
+ { "dmarc_used_domain", vtype_stringptr, &dmarc_used_domain },
+};
+
+misc_module_info dmarc_module_info =
+{
+ .name = US"dmarc",
+# if SUPPORT_SPF==2
+ .dyn_magic = MISC_MODULE_MAGIC,
+# endif
+ .init = dmarc_init,
+ .lib_vers_report = dmarc_version_report,
+ .smtp_reset = dmarc_smtp_reset,
+ .msg_init = dmarc_msg_init,
+
+ .options = dmarc_options,
+ .options_count = nelem(dmarc_options),
+
+ .functions = dmarc_functions,
+ .functions_count = nelem(dmarc_functions),
+
+ .variables = dmarc_variables,
+ .variables_count = nelem(dmarc_variables),
+};
+
# endif /* SUPPORT_SPF */
#endif /* SUPPORT_DMARC */
/* vi: aw ai sw=2
diff --git a/src/src/dmarc.h b/src/src/miscmods/dmarc.h
similarity index 84%
rename from src/src/dmarc.h
rename to src/src/miscmods/dmarc.h
index dcf289f2d..c1cafd0d1 100644
--- a/src/src/dmarc.h
+++ b/src/src/miscmods/dmarc.h
@@ -13,20 +13,11 @@
#ifdef SUPPORT_DMARC
-# include "opendmarc/dmarc.h"
+# include <opendmarc/dmarc.h>
# ifdef SUPPORT_SPF
-# include "spf2/spf.h"
+# include <spf2/spf.h>
# endif /* SUPPORT_SPF */
-/* prototypes */
-gstring * dmarc_version_report(gstring *);
-int dmarc_init(void);
-int dmarc_conn_init(void);
-int dmarc_store_data(header_line *);
-int dmarc_process(void);
-uschar *dmarc_exim_expand_query(int);
-uschar *dmarc_exim_expand_defaults(int);
-
#define DMARC_VERIFY_STATUS 1
#define DMARC_HIST_OK 1
diff --git a/src/src/miscmods/spf.c b/src/src/miscmods/spf.c
index a7b6c6a8d..f28fd0cbf 100644
--- a/src/src/miscmods/spf.c
+++ b/src/src/miscmods/spf.c
@@ -287,29 +287,30 @@ return TRUE;
messages on the same SMTP connection (that come from the
same host with the same HELO string).
-Return: Boolean success
+Return: OK/FAIL
*/
-static BOOL
-spf_conn_init(uschar * spf_helo_domain, uschar * spf_remote_addr)
+static int
+spf_conn_init(const uschar * spf_helo_domain, const uschar * spf_remote_addr)
{
DEBUG(D_receive)
debug_printf("spf_conn_init: %s %s\n", spf_helo_domain, spf_remote_addr);
-if (!spf_server && !spf_init(NULL)) return FALSE;
+if (!spf_server && !spf_init(NULL))
+ return FAIL;
if (SPF_server_set_rec_dom(spf_server, CS primary_hostname))
{
DEBUG(D_receive) debug_printf("spf: SPF_server_set_rec_dom(\"%s\") failed.\n",
primary_hostname);
spf_server = NULL;
- return FALSE;
+ return FAIL;
}
spf_request = SPF_request_new(spf_server);
-if ( SPF_request_set_ipv4_str(spf_request, CS spf_remote_addr)
- && SPF_request_set_ipv6_str(spf_request, CS spf_remote_addr)
+if ( SPF_request_set_ipv4_str(spf_request, CCS spf_remote_addr)
+ && SPF_request_set_ipv6_str(spf_request, CCS spf_remote_addr)
)
{
DEBUG(D_receive)
@@ -317,19 +318,19 @@ if ( SPF_request_set_ipv4_str(spf_request, CS spf_remote_addr)
"SPF_request_set_ipv6_str() failed [%s]\n", spf_remote_addr);
spf_server = NULL;
spf_request = NULL;
- return FALSE;
+ return FAIL;
}
-if (SPF_request_set_helo_dom(spf_request, CS spf_helo_domain))
+if (SPF_request_set_helo_dom(spf_request, CCS spf_helo_domain))
{
DEBUG(D_receive) debug_printf("spf: SPF_set_helo_dom(\"%s\") failed.\n",
spf_helo_domain);
spf_server = NULL;
spf_request = NULL;
- return FALSE;
+ return FAIL;
}
-return TRUE;
+return OK;
}
static void
@@ -564,11 +565,9 @@ static optionlist spf_options[] = {
};
static void * spf_functions[] = {
- spf_conn_init,
spf_process,
authres_spf,
spf_get_response, /* ugly; for dmarc */
- spf_smtp_reset,
spf_lookup_open,
spf_lookup_close,
@@ -592,6 +591,8 @@ misc_module_info spf_module_info =
# endif
.init = spf_init,
.lib_vers_report = spf_lib_version_report,
+ .conn_init = spf_conn_init,
+ .smtp_reset = spf_smtp_reset,
.options = spf_options,
.options_count = nelem(spf_options),
diff --git a/src/src/moan.c b/src/src/moan.c
index 19d29190b..08258f5d1 100644
--- a/src/src/moan.c
+++ b/src/src/moan.c
@@ -178,8 +178,7 @@ header From: and grab the address from that for the envelope FROM. */
GET_OPTION("dmarc_forensic_sender");
if ( ident == ERRMESS_DMARC_FORENSIC
- && dmarc_forensic_sender
- && (s = expand_string(dmarc_forensic_sender))
+ && (s = expand_string(US"$dmarc_forensic_sender")) /* a hack... */
&& *s
&& (s2 = expand_string(string_sprintf("${address:%s}", s)))
&& *s2
diff --git a/src/src/readconf.c b/src/src/readconf.c
index 1fe6b7341..ae7073229 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -129,9 +129,9 @@ static optionlist optionlist_config[] = {
{ "dkim_verify_signers", opt_stringptr, {&dkim_verify_signers} },
#endif
#ifdef SUPPORT_DMARC
- { "dmarc_forensic_sender", opt_stringptr, {&dmarc_forensic_sender} },
- { "dmarc_history_file", opt_stringptr, {&dmarc_history_file} },
- { "dmarc_tld_file", opt_stringptr, {&dmarc_tld_file} },
+ { "dmarc_forensic_sender", opt_module, {US"dmarc"} },
+ { "dmarc_history_file", opt_module, {US"dmarc"} },
+ { "dmarc_tld_file", opt_module, {US"dmarc"} },
#endif
{ "dns_again_means_nonexist", opt_stringptr, {&dns_again_means_nonexist} },
{ "dns_check_names_pattern", opt_stringptr, {&check_dns_names_pattern} },
@@ -1707,7 +1707,7 @@ static BOOL
readconf_handle_option(uschar *buffer, optionlist *oltop, int last,
void *data_block, uschar *unknown_txt)
{
-int ptr = 0;
+int ptr;
int offset = 0;
int count, type, value;
int issecure = 0;
@@ -1721,11 +1721,16 @@ rmark reset_point;
int intbase = 0;
uschar *inttype = US"";
uschar *sptr;
-const uschar * s = buffer;
+const uschar * s;
uschar **str_target;
uschar name[EXIM_DRIVERNAME_MAX];
uschar name2[EXIM_DRIVERNAME_MAX];
+sublist:
+
+s = buffer;
+ptr = 0;
+
/* There may be leading spaces; thereafter, we expect an option name starting
with a letter. */
@@ -1764,8 +1769,6 @@ if (Ustrncmp(name, "not_", 4) == 0)
offset = 4;
}
-sublist:
-
/* Search the list for the given name. A non-existent name, or an option that
is set twice, is a disaster. */
@@ -2454,7 +2457,6 @@ switch (type)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"failed to find %s module for %s: %s", US ol->v.value, name, errstr);
-debug_printf("hunting for option %s in module %s\n", name, mi->name);
oltop = mi->options;
last = mi->options_count;
goto sublist;
@@ -3516,6 +3518,9 @@ if (!*spool_directory)
/* Expand the spool directory name; it may, for example, contain the primary
host name. Same comment about failure. */
+DEBUG(D_any) if (Ustrchr(spool_directory, '$'))
+ debug_printf("Expanding spool_directory option\n");
+
if (!(s = expand_string(spool_directory)))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand spool_directory "
"\"%s\": %s", spool_directory, expand_string_message);
diff --git a/src/src/receive.c b/src/src/receive.c
index 336b37410..37b152f48 100644
--- a/src/src/receive.c
+++ b/src/src/receive.c
@@ -17,7 +17,7 @@ extern int dcc_ok;
#endif
#ifdef SUPPORT_DMARC
-# include "dmarc.h"
+# include "miscmods/dmarc.h"
#endif
/*************************************************
@@ -1835,9 +1835,8 @@ if (smtp_input && !smtp_batched_input && !f.dkim_disable_verify)
dkim_exim_verify_init(chunking_state <= CHUNKING_OFFERED);
#endif
-#ifdef SUPPORT_DMARC
-if (sender_host_address) dmarc_conn_init(); /* initialize libopendmarc */
-#endif
+if (misc_mod_msg_init() != OK)
+ goto TIDYUP;
/* In SMTP sessions we may receive several messages in one connection. Before
each subsequent one, we wait for the clock to tick at the level of message-id
@@ -3627,7 +3626,14 @@ else
#endif /* WITH_CONTENT_SCAN */
#ifdef SUPPORT_DMARC
- dmarc_store_data(dmarc_from_header);
+ {
+ misc_module_info * mi = misc_mod_findonly(US"dmarc");
+ if (mi)
+ {
+ typedef int (*fn_t)(header_line *);
+ (((fn_t *) mi->functions)[3]) (dmarc_from_header);
+ }
+ }
#endif
#ifndef DISABLE_PRDR
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index f9bd3ece8..adf6c59cb 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -1681,16 +1681,6 @@ bmi_run = 0;
bmi_verdicts = NULL;
#endif
dnslist_domain = dnslist_matched = NULL;
-#ifdef SUPPORT_SPF
- {
- misc_module_info * mi = misc_mod_findonly(US"spf");
- if (mi)
- {
- typedef void (*fn_t)(void);
- (((fn_t *) mi->functions)[4])(); /* spf_smtp_reset*/
- }
- }
-#endif
#ifndef DISABLE_DKIM
dkim_cur_signer = dkim_signers =
dkim_signing_domain = dkim_signing_selector = dkim_signatures = NULL;
@@ -1701,8 +1691,6 @@ dkim_key_length = 0;
#endif
#ifdef SUPPORT_DMARC
f.dmarc_has_been_checked = f.dmarc_disable_verify = f.dmarc_enable_forensic = FALSE;
-dmarc_domain_policy = dmarc_status = dmarc_status_text =
-dmarc_used_domain = NULL;
#endif
#ifdef EXPERIMENTAL_ARC
arc_state = arc_state_reason = NULL;
@@ -1742,6 +1730,7 @@ while (acl_warn_logged)
store_free(this);
}
+misc_mod_smtp_reset();
message_tidyup();
store_reset(reset_point);
@@ -4025,24 +4014,14 @@ while (done <= 0)
}
}
-#ifdef SUPPORT_SPF
- /* If we have an spf module, set up SPF context */
- {
- misc_module_info * mi = misc_mod_findonly(US"spf");
- if (mi)
+ /* For any misc-module having a connection-init routine, call it. */
+
+ if (misc_mod_conn_init(sender_helo_name, sender_host_address) != OK)
{
- /* We have hardwired function-call numbers, and also prototypes for the
- functions. We could do a function name table search for the number
- but I can't see how to deal with prototypes. Is a K&R non-prototyped
- function still usable with today's compilers? */
-
- typedef BOOL (*fn_t)(uschar *, uschar *);
- fn_t fn = ((fn_t *) mi->functions)[0]; /* spf_conn_init */
-
- (void) fn(sender_helo_name, sender_host_address);
+ DEBUG(D_receive) debug_printf("A module conn-init routine failed\n");
+ done = 1;
+ break;
}
- }
-#endif
/* Apply an ACL check if one is defined; afterwards, recheck
synchronization in case the client started sending in a delay. */
diff --git a/src/src/structs.h b/src/src/structs.h
index 2c8c77c43..46abac728 100644
--- a/src/src/structs.h
+++ b/src/src/structs.h
@@ -1023,6 +1023,9 @@ typedef struct misc_module_info {
unsigned dyn_magic;
BOOL (*init)(void *); /* arg is the misc_module_info ptr */
gstring * (*lib_vers_report)(gstring *); /* underlying library */
+ int (*conn_init)(const uschar *, const uschar *);
+ void (*smtp_reset)(void);
+ int (*msg_init)(void);
void * options;
unsigned options_count;
diff --git a/test/runtest b/test/runtest
index dcf6d76b2..ae227810c 100755
--- a/test/runtest
+++ b/test/runtest
@@ -1561,8 +1561,8 @@ RESET_AFTER_EXTRA_LINE_READ:
# Not all platforms build with SPF enabled
next if /(^$time_pid?spf_conn_init|spf_compile\.c)/;
next if /try option spf_smtp_comment_template$/;
- next if /loading module 'spf'$/;
- next if /^Loaded "spf"$/;
+ next if /loading module '(?:dmarc|spf)'$/;
+ next if /^$time_pid?Loaded "(?:dmarc|spf)"$/;
# Not all platforms have sendfile support
next if /^cannot use sendfile for body: no support$/;
diff --git a/test/stderr/0437 b/test/stderr/0437
index 29241cfd3..514a770f8 100644
--- a/test/stderr/0437
+++ b/test/stderr/0437
@@ -1,5 +1,6 @@
Exim version x.yz ....
Hints DB:
+Expanding spool_directory option
search_open: lsearch "TESTSUITE/aux-fixed/0437.ls"
search_find: file="TESTSUITE/aux-fixed/0437.ls"
key="spool" partial=-1 affix=NULL starflags=0 opts=NULL
--
## subscription configuration (requires account):
##
https://lists.exim.org/mailman3/postorius/lists/exim-cvs.lists.exim.org/
## unsubscribe (doesn't require an account):
## exim-cvs-unsubscribe@???
## Exim details at
http://www.exim.org/
## Please use the Wiki with this list -
http://wiki.exim.org/