X-Git-Url: https://git.exim.org/users/jgh/exim.git/blobdiff_plain/d7bed7717e93c472282ed0e555fa64e0785d0172..f6ee24a2b56b9365b948dd9e501c0e4627e6fa4f:/src/src/acl.c diff --git a/src/src/acl.c b/src/src/acl.c index a1d1915fb..396e29965 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; + +/* 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; -/* Flags to identify the modifiers */ +} 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++; @@ -1339,7 +1201,7 @@ an odd configuration - why didn't the SRV record have a weight of 1 instead?) Arguments: dnsa the DNS answer block dnss a DNS scan block for us to use - reset option specifing what portion to scan, as described above + reset option specifying what portion to scan, as described above target the target hostname to use for matching RR names Returns: CSA_OK successfully authorized @@ -1421,7 +1283,6 @@ acl_verify_csa(const uschar *domain) { tree_node *t; const uschar *found; -uschar *p; int priority, weight, port; dns_answer dnsa; dns_scan dnss; @@ -1499,14 +1360,13 @@ switch (dns_special_lookup(&dnsa, domain, T_CSA, &found)) /* Scan the reply for well-formed CSA SRV records. */ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); - rr != NULL; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) + rr; + rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == T_SRV) { - if (rr->type != T_SRV) continue; + const uschar * p = rr->data; /* Extract the numerical SRV fields (p is incremented) */ - p = rr->data; GETSHORT(priority, p); GETSHORT(weight, p); GETSHORT(port, p); @@ -1525,12 +1385,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); SRV records of their own. */ if (Ustrcmp(found, domain) != 0) - { - if (port & 1) - return t->data.val = CSA_FAIL_EXPLICIT; - else - return t->data.val = CSA_UNKNOWN; - } + return t->data.val = port & 1 ? CSA_FAIL_EXPLICIT : CSA_UNKNOWN; /* This CSA SRV record refers directly to our domain, so we check the value in the weight field to work out the domain's authorization. 0 and 1 are @@ -2385,7 +2240,7 @@ while ((ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size)) else if (strcmpic(ss, US"per_byte") == 0) { /* If we have not yet received the message data and there was no SIZE - declaration on the MAIL comand, then it's safe to just use a value of + declaration on the MAIL command, then it's safe to just use a value of zero and let the recorded rate decay as if nothing happened. */ RATE_SET(mode, PER_MAIL); if (where > ACL_WHERE_NOTSMTP) badacl = TRUE; @@ -2751,7 +2606,7 @@ else size of the event per the period size, ignoring the lack of events outside the current period and regardless of where the event falls in the period. So, if the interval was so long that the calculated rate is unhelpfully small, we - re-intialize the rate. In the absence of higher-rate bursts, the condition + re-initialize the rate. In the absence of higher-rate bursts, the condition below is true if the interval is greater than the period. */ if (dbd->rate < count) dbd->rate = count; @@ -2834,17 +2689,17 @@ uschar * errstr; hostname = string_nextinlist(&arg, &sep, NULL, 0); portstr = string_nextinlist(&arg, &sep, NULL, 0); -if (hostname == NULL) +if (!hostname) { *log_msgptr = US"missing destination host in \"udpsend\" modifier"; return ERROR; } -if (portstr == NULL) +if (!portstr) { *log_msgptr = US"missing destination port in \"udpsend\" modifier"; return ERROR; } -if (arg == NULL) +if (!arg) { *log_msgptr = US"missing datagram payload in \"udpsend\" modifier"; return ERROR; @@ -2983,18 +2838,15 @@ 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 = cb->arg; + else if (!(arg = expand_string(cb->arg))) { - arg = expand_string(cb->arg); - if (arg == NULL) - { - if (expand_string_forcedfail) continue; - *log_msgptr = string_sprintf("failed to expand ACL string \"%s\": %s", - cb->arg, expand_string_message); - return search_find_defer? DEFER : ERROR; - } + if (expand_string_forcedfail) continue; + *log_msgptr = string_sprintf("failed to expand ACL string \"%s\": %s", + cb->arg, expand_string_message); + return search_find_defer ? DEFER : ERROR; } - else arg = cb->arg; /* Show condition, and expanded condition if it's different */ @@ -3002,8 +2854,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 +2872,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; } @@ -3424,12 +3276,12 @@ for (; cb != NULL; cb = cb->next) #ifdef EXPERIMENTAL_DCC case ACLC_DCC: { - /* Seperate the regular expression and any optional parameters. */ + /* Separate the regular expression and any optional parameters. */ const uschar * list = arg; uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size); /* Run the dcc backend. */ rc = dcc_process(&ss); - /* Modify return code based upon the existance of options. */ + /* Modify return code based upon the existence of options. */ while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))) if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER) rc = FAIL; /* FAIL so that the message is passed to the next ACL */ @@ -3730,12 +3582,12 @@ for (; cb != NULL; cb = cb->next) #ifdef WITH_CONTENT_SCAN case ACLC_SPAM: { - /* Seperate the regular expression and any optional parameters. */ + /* Separate the regular expression and any optional parameters. */ const uschar * list = arg; uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size); /* Run the spam backend. */ rc = spam(CUSS &ss); - /* Modify return code based upon the existance of options. */ + /* Modify return code based upon the existence of options. */ while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)) != NULL) { if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER) @@ -3782,11 +3634,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 */ } @@ -4294,7 +4144,7 @@ HDEBUG(D_acl) debug_printf("end of %s: implicit DENY\n", acl_name); return FAIL; badquit: - *log_msgptr = string_sprintf("QUIT or not-QUIT teplevel ACL may not fail " + *log_msgptr = string_sprintf("QUIT or not-QUIT toplevel ACL may not fail " "('%s' verb used incorrectly)", verbs[acl->verb]); return ERROR; }