From d7bed7717e93c472282ed0e555fa64e0785d0172 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sun, 18 Sep 2016 18:14:29 +0100 Subject: ACL: bsearch for controls --- doc/doc-txt/ChangeLog | 3 + src/scripts/source_checks | 1 + src/src/acl.c | 403 ++++++++++++++++++++-------------------------- src/src/readconf.c | 20 ++- 4 files changed, 192 insertions(+), 235 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 40f06dc29..a29974070 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -90,6 +90,9 @@ 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. + Exim version 4.87 ----------------- diff --git a/src/scripts/source_checks b/src/scripts/source_checks index eac4b8d1b..86aff13b1 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 controls_list END # Tables with just string items diff --git a/src/src/acl.c b/src/src/acl.c index eff698b34..a1d1915fb 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -174,90 +174,6 @@ static uschar *conditions[] = { US"verify" }; -/* Return values from decode_control(); keep in step with the table of names -that follows! */ - -enum { - CONTROL_AUTH_UNADVERTISED, -#ifdef EXPERIMENTAL_BRIGHTMAIL - CONTROL_BMI_RUN, -#endif - CONTROL_DEBUG, -#ifndef DISABLE_DKIM - CONTROL_DKIM_VERIFY, -#endif -#ifdef EXPERIMENTAL_DMARC - CONTROL_DMARC_VERIFY, - CONTROL_DMARC_FORENSIC, -#endif - CONTROL_DSCP, - CONTROL_ERROR, - CONTROL_CASEFUL_LOCAL_PART, - CONTROL_CASELOWER_LOCAL_PART, - CONTROL_CUTTHROUGH_DELIVERY, - CONTROL_ENFORCE_SYNC, - CONTROL_NO_ENFORCE_SYNC, - CONTROL_FREEZE, - CONTROL_QUEUE_ONLY, - CONTROL_SUBMISSION, - CONTROL_SUPPRESS_LOCAL_FIXUPS, -#ifdef WITH_CONTENT_SCAN - CONTROL_NO_MBOX_UNSPOOL, -#endif - CONTROL_FAKEDEFER, - CONTROL_FAKEREJECT, -#ifdef SUPPORT_I18N - CONTROL_UTF8_DOWNCONVERT, -#endif - CONTROL_NO_MULTILINE, - CONTROL_NO_PIPELINING, - CONTROL_NO_DELAY_FLUSH, - CONTROL_NO_CALLOUT_FLUSH -}; - -/* ACL control names; keep in step with the table above! This list is used for -turning ids into names. The actual list of recognized names is in the variable -control_def controls_list[] below. The fact that there are two lists is a mess -and should be tidied up. */ - -static uschar *controls[] = { - US"allow_auth_unadvertised", -#ifdef EXPERIMENTAL_BRIGHTMAIL - US"bmi_run", -#endif - US"debug", -#ifndef DISABLE_DKIM - US"dkim_disable_verify", -#endif -#ifdef EXPERIMENTAL_DMARC - US"dmarc_disable_verify", - US"dmarc_enable_forensic", -#endif - US"dscp", - US"error", - US"caseful_local_part", - US"caselower_local_part", - US"cutthrough_delivery", - US"enforce_sync", - US"no_enforce_sync", - US"freeze", - US"queue_only", - US"submission", - US"suppress_local_fixups", -#ifdef WITH_CONTENT_SCAN - US"no_mbox_unspool", -#endif - US"fakedefer", - US"fakereject", -#ifdef SUPPORT_I18N - US"utf8_downconvert", -#endif - US"no_multiline_responses", - US"no_pipelining", - US"no_delay_flush", - US"no_callout_flush" -}; - /* Flags to indicate for which conditions/modifiers a string expansion is done at the outer level. In the other cases, expansion already occurs in the checking functions. */ @@ -593,162 +509,175 @@ static unsigned int cond_forbids[] = { }; -/* Bit map vector of which controls are not allowed at certain times. For -each control, there's a bitmap of dis-allowed times. For some, it is easier to -specify the negation of a small number of allowed times. */ - -static unsigned int control_forbids[] = { - (unsigned int) - ~((1< first) + { + int middle = (first + last)/2; + uschar * s = ol[middle].name; + int c = Ustrncmp(name, s, Ustrlen(s)); + if (c == 0) return middle; + else if (c > 0) first = middle + 1; + else last = middle; + } +return -1; +} + + + /************************************************* * Pick out name from list * *************************************************/ @@ -2256,26 +2217,20 @@ Returns: CONTROL_xxx value static int decode_control(const uschar *arg, const uschar **pptr, int where, uschar **log_msgptr) { -int len; -control_def *d; - -for (d = controls_list; - d < controls_list + sizeof(controls_list)/sizeof(control_def); - d++) - { - len = Ustrlen(d->name); - if (Ustrncmp(d->name, arg, len) == 0) break; - } +int idx, len; +control_def * d; -if (d >= controls_list + sizeof(controls_list)/sizeof(control_def) || - (arg[len] != 0 && (!d->has_option || arg[len] != '/'))) +if ( (idx = find_control(arg, controls_list, nelem(controls_list))) < 0 + || ( arg[len = Ustrlen((d = controls_list+idx)->name)] != 0 + && (!d->has_option || arg[len] != '/') + ) ) { *log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg); return CONTROL_ERROR; } *pptr = arg + len; -return d->value; +return idx; } @@ -3140,10 +3095,10 @@ for (; cb != NULL; cb = cb->next) /* Check if this control makes sense at this time */ - if ((control_forbids[control_type] & (1 << where)) != 0) + if (controls_list[control_type].forbids & (1 << where)) { *log_msgptr = string_sprintf("cannot use \"control=%s\" in %s ACL", - controls[control_type], acl_wherenames[where]); + controls_list[control_type].name, acl_wherenames[where]); return ERROR; } diff --git a/src/src/readconf.c b/src/src/readconf.c index 26da6ba65..0a06559f4 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -488,8 +488,7 @@ static optionlist optionlist_config[] = { { "write_rejectlog", opt_bool, &write_rejectlog } }; -static int optionlist_config_size = - sizeof(optionlist_config)/sizeof(optionlist); +static int optionlist_config_size = nelem(optionlist_config); @@ -517,7 +516,7 @@ transport_instance *t; for (i = 0; i < optionlist_config_size; i++) if (p == optionlist_config[i].value) return US optionlist_config[i].name; -for (r = routers; r != NULL; r = r->next) +for (r = routers; r; r = r->next) { router_info *ri = r->info; for (i = 0; i < *ri->options_count; i++) @@ -528,7 +527,7 @@ for (r = routers; r != NULL; r = r->next) } } -for (t = transports; t != NULL; t = t->next) +for (t = transports; t; t = t->next) { transport_info *ti = t->info; for (i = 0; i < *ti->options_count; i++) @@ -1163,9 +1162,10 @@ while (last > first) { int middle = (first + last)/2; int c = Ustrcmp(name, ol[middle].name); + if (c == 0) return ol + middle; - else if (c > 0) first = middle + 1; - else last = middle; + else if (c > 0) first = middle + 1; + else last = middle; } return NULL; } @@ -1509,9 +1509,7 @@ if (Ustrncmp(name, "not_", 4) == 0) /* Search the list for the given name. A non-existent name, or an option that is set twice, is a disaster. */ -ol = find_option(name + offset, oltop, last); - -if (ol == NULL) +if (!(ol = find_option(name + offset, oltop, last))) { if (unknown_txt == NULL) return FALSE; log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, CS unknown_txt, name); @@ -2618,8 +2616,8 @@ if (type == NULL) return; } - if ( Ustrcmp(name, "configure_file") == 0 - ||Ustrcmp(name, "config_file") == 0) + if ( Ustrcmp(name, "configure_file") == 0 + || Ustrcmp(name, "config_file") == 0) { printf("%s\n", CS config_main_filename); return; -- cgit v1.2.3