From 2d009132e2de39646108f9c5a829f0611735e730 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sun, 18 Sep 2016 22:47:22 +0100 Subject: [PATCH] ACL: merge the tables used for codition/modifier decode --- doc/doc-txt/ChangeLog | 3 +- src/scripts/source_checks | 2 +- src/src/acl.c | 620 +++++++++++++++----------------------- 3 files changed, 243 insertions(+), 382 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index a29974070..f2000b5d4 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -91,7 +91,8 @@ JH/23 Bug 1874: fix continued use of a connection for further deliveries. JH/24 Bug 1832: Log EHLO response on getting conn-close response for HELO. JH/25 Decoding ACL controls is now done using a binary search; the sourcecode - takes up less space and should be simpler to maintain. + takes up less space and should be simpler to maintain. Merge the ACL + condition decode tables also, with similar effect. Exim version 4.87 diff --git a/src/scripts/source_checks b/src/scripts/source_checks index 86aff13b1..6da8a8664 100644 --- a/src/scripts/source_checks +++ b/src/scripts/source_checks @@ -27,6 +27,7 @@ done <<-END transports/pipe.c pipe_transport_options transports/smtp.c smtp_transport_options expand.c var_table + acl.c conditions acl.c controls_list END @@ -46,6 +47,5 @@ done <<-END expand.c op_table_main expand.c cond_table acl.c verbs - acl.c conditions END diff --git a/src/src/acl.c b/src/src/acl.c index a1d1915fb..fb2a7da4b 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -46,7 +46,7 @@ static int msgcond[] = { }; /* ACL condition and modifier codes - keep in step with the table that -follows, and the cond_expand_at_top and uschar cond_modifiers tables lower +follows. down. */ enum { ACLC_ACL, @@ -113,402 +113,236 @@ enum { ACLC_ACL, modifiers that look like conditions but always return TRUE. They are used for their side effects. */ -static uschar *conditions[] = { - US"acl", - US"add_header", - US"authenticated", -#ifdef EXPERIMENTAL_BRIGHTMAIL - US"bmi_optin", -#endif - US"condition", - US"continue", - US"control", -#ifdef EXPERIMENTAL_DCC - US"dcc", -#endif -#ifdef WITH_CONTENT_SCAN - US"decode", -#endif - US"delay", -#ifndef DISABLE_DKIM - US"dkim_signers", - US"dkim_status", -#endif -#ifdef EXPERIMENTAL_DMARC - US"dmarc_status", -#endif - US"dnslists", - US"domains", - US"encrypted", - US"endpass", - US"hosts", - US"local_parts", - US"log_message", - US"log_reject_target", - US"logwrite", -#ifdef WITH_CONTENT_SCAN - US"malware", -#endif - US"message", -#ifdef WITH_CONTENT_SCAN - US"mime_regex", -#endif - US"queue", - US"ratelimit", - US"recipients", -#ifdef WITH_CONTENT_SCAN - US"regex", -#endif - US"remove_header", - US"sender_domains", - US"senders", - US"set", -#ifdef WITH_CONTENT_SCAN - US"spam", -#endif -#ifdef EXPERIMENTAL_SPF - US"spf", - US"spf_guess", -#endif - US"udpsend", - US"verify" }; - +typedef struct condition_def { + uschar *name; -/* Flags to indicate for which conditions/modifiers a string expansion is done +/* Flag to indicate the condition/modifier has a string expansion done at the outer level. In the other cases, expansion already occurs in the checking functions. */ + BOOL expand_at_top:1; -static uschar cond_expand_at_top[] = { - FALSE, /* acl */ - TRUE, /* add_header */ - FALSE, /* authenticated */ -#ifdef EXPERIMENTAL_BRIGHTMAIL - TRUE, /* bmi_optin */ -#endif - TRUE, /* condition */ - TRUE, /* continue */ - TRUE, /* control */ -#ifdef EXPERIMENTAL_DCC - TRUE, /* dcc */ -#endif -#ifdef WITH_CONTENT_SCAN - TRUE, /* decode */ -#endif - TRUE, /* delay */ -#ifndef DISABLE_DKIM - TRUE, /* dkim_signers */ - TRUE, /* dkim_status */ -#endif -#ifdef EXPERIMENTAL_DMARC - TRUE, /* dmarc_status */ -#endif - TRUE, /* dnslists */ - FALSE, /* domains */ - FALSE, /* encrypted */ - TRUE, /* endpass */ - FALSE, /* hosts */ - FALSE, /* local_parts */ - TRUE, /* log_message */ - TRUE, /* log_reject_target */ - TRUE, /* logwrite */ -#ifdef WITH_CONTENT_SCAN - TRUE, /* malware */ -#endif - TRUE, /* message */ -#ifdef WITH_CONTENT_SCAN - TRUE, /* mime_regex */ -#endif - TRUE, /* queue */ - TRUE, /* ratelimit */ - FALSE, /* recipients */ -#ifdef WITH_CONTENT_SCAN - TRUE, /* regex */ -#endif - TRUE, /* remove_header */ - FALSE, /* sender_domains */ - FALSE, /* senders */ - TRUE, /* set */ -#ifdef WITH_CONTENT_SCAN - TRUE, /* spam */ -#endif -#ifdef EXPERIMENTAL_SPF - TRUE, /* spf */ - TRUE, /* spf_guess */ -#endif - TRUE, /* udpsend */ - TRUE /* verify */ -}; + BOOL is_modifier:1; -/* Flags to identify the modifiers */ +/* Bit map vector of which conditions and modifiers are not allowed at certain +times. For each condition and modifier, there's a bitmap of dis-allowed times. +For some, it is easier to specify the negation of a small number of allowed +times. */ + unsigned forbids; + +} condition_def; + +static condition_def conditions[] = { + { US"acl", FALSE, FALSE, 0 }, + + { US"add_header", TRUE, TRUE, + (unsigned int) + ~((1<verb != ACL_DISCARD) { *error = string_sprintf("ACL error: \"%s\" is not allowed with \"%s\"", - conditions[c], verbs[this->verb]); + conditions[c].name, verbs[this->verb]); return NULL; } @@ -991,7 +853,7 @@ while ((s = (*func)()) != NULL) if (*s++ != '=') { *error = string_sprintf("\"=\" missing after ACL \"%s\" %s", name, - cond_modifiers[c]? US"modifier" : US"condition"); + conditions[c].is_modifier ? US"modifier" : US"condition"); return NULL; } while (isspace(*s)) s++; @@ -2983,7 +2845,7 @@ for (; cb != NULL; cb = cb->next) of them, but not for all, because expansion happens down in some lower level checking functions in some cases. */ - if (cond_expand_at_top[cb->type]) + if (conditions[cb->type].expand_at_top) { arg = expand_string(cb->arg); if (arg == NULL) @@ -3002,8 +2864,8 @@ for (; cb != NULL; cb = cb->next) { int lhswidth = 0; debug_printf("check %s%s %n", - (!cond_modifiers[cb->type] && cb->u.negated)? "!":"", - conditions[cb->type], &lhswidth); + (!conditions[cb->type].is_modifier && cb->u.negated)? "!":"", + conditions[cb->type].name, &lhswidth); if (cb->type == ACLC_SET) { @@ -3020,11 +2882,11 @@ for (; cb != NULL; cb = cb->next) /* Check that this condition makes sense at this time */ - if ((cond_forbids[cb->type] & (1 << where)) != 0) + if ((conditions[cb->type].forbids & (1 << where)) != 0) { *log_msgptr = string_sprintf("cannot %s %s condition in %s ACL", - cond_modifiers[cb->type]? "use" : "test", - conditions[cb->type], acl_wherenames[where]); + conditions[cb->type].is_modifier ? "use" : "test", + conditions[cb->type].name, acl_wherenames[where]); return ERROR; } @@ -3782,11 +3644,9 @@ for (; cb != NULL; cb = cb->next) /* If a condition was negated, invert OK/FAIL. */ - if (!cond_modifiers[cb->type] && cb->u.negated) - { + if (!conditions[cb->type].is_modifier && cb->u.negated) if (rc == OK) rc = FAIL; - else if (rc == FAIL || rc == FAIL_DROP) rc = OK; - } + else if (rc == FAIL || rc == FAIL_DROP) rc = OK; if (rc != OK) break; /* Conditions loop */ } -- 2.30.2