From f60d98e8a1d3f9ca2805fdeee7c8062b44c5362d Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sun, 24 Jun 2012 17:14:48 +0100 Subject: [PATCH 1/1] Change acl expansion-condition syntax to "acl {{name} {arg1}{arg2}...}" to match saslauthd condition. --- src/src/acl.c | 37 ++------------- src/src/expand.c | 108 +++++++++++++++++++++++++++++--------------- src/src/functions.h | 1 - 3 files changed, 76 insertions(+), 70 deletions(-) diff --git a/src/src/acl.c b/src/src/acl.c index 5101267c2..d0db7171e 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -696,8 +696,8 @@ static uschar *ratelimit_option_string[] = { /* Enable recursion between acl_check_internal() and acl_check_condition() */ -static int acl_check_internal(int, address_item *, uschar *, int, uschar **, - uschar **); +static int acl_check_wargs(int, address_item *, uschar *, int, uschar **, + uschar **); /************************************************* @@ -2785,33 +2785,7 @@ for (; cb != NULL; cb = cb->next) "discard" verb. */ case ACLC_ACL: - { - uschar * cp = arg; - uschar * tmp; - uschar * name; - - if (!(tmp = string_dequote(&cp)) || !(name = expand_string(tmp))) - { - if (expand_string_forcedfail) continue; - *log_msgptr = string_sprintf("failed to expand ACL string \"%s\": %s", - tmp, expand_string_message); - return search_find_defer? DEFER : ERROR; - } - - for (acl_narg = 0; acl_narg < sizeof(acl_arg)/sizeof(*acl_arg); acl_narg++) - { - while (*cp && isspace(*cp)) cp++; - if (!*cp) break; - if (!(tmp = string_dequote(&cp)) || !(acl_arg[acl_narg] = expand_string(tmp))) - { - if (expand_string_forcedfail) continue; - *log_msgptr = string_sprintf("failed to expand ACL string \"%s\": %s", - arg, expand_string_message); - return search_find_defer? DEFER : ERROR; - } - } - - rc = acl_check_internal(where, addr, name, level+1, user_msgptr, log_msgptr); + rc = acl_check_wargs(where, addr, arg, level+1, user_msgptr, log_msgptr); if (rc == DISCARD && verb != ACL_ACCEPT && verb != ACL_DISCARD) { *log_msgptr = string_sprintf("nested ACL returned \"discard\" for " @@ -2819,7 +2793,6 @@ for (; cb != NULL; cb = cb->next) verbs[verb]); return ERROR; } - } break; case ACLC_AUTHENTICATED: @@ -3895,8 +3868,8 @@ return FAIL; /* Same args as acl_check_internal() above, but the string s is the name of an ACL followed optionally by up to 9 space-separated arguments. The name and args are separately expanded. Args go into $acl_arg globals. */ -int -acl_check_args(int where, address_item *addr, uschar *s, int level, +static int +acl_check_wargs(int where, address_item *addr, uschar *s, int level, uschar **user_msgptr, uschar **log_msgptr) { uschar * tmp; diff --git a/src/src/expand.c b/src/src/expand.c index 7529ad1ca..60552a85c 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1836,6 +1836,40 @@ if (Ustrncmp(name, "acl_", 4) == 0) +/* +Load args from sub array to globals, and call acl_check(). + +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 +*/ +static int +eval_acl(uschar ** sub, int nsub, uschar ** user_msgp) +{ +int i; +uschar *dummy_log_msg; + +for (i = 1; i < nsub && sub[i]; i++) + acl_arg[i-1] = sub[i]; +acl_narg = i-1; +while (i < sizeof(sub)/sizeof(*sub)) + acl_arg[i++ - 1] = NULL; + +DEBUG(D_expand) + debug_printf("expanding: acl: %s arg: %s%s\n", + sub[0], + acl_narg>0 ? sub[1] : US"", + acl_narg>1 ? " +more" : ""); + +return acl_check(ACL_WHERE_EXPANSION, NULL, sub[0], user_msgp, &dummy_log_msg); +} + + + + /************************************************* * Read and evaluate a condition * *************************************************/ @@ -1863,7 +1897,7 @@ int i, rc, cond_type, roffset; int_eximarith_t num[2]; struct stat statbuf; uschar name[256]; -uschar *sub[4]; +uschar *sub[10]; const pcre *re; const uschar *rerror; @@ -2070,40 +2104,52 @@ switch(cond_type) /* call ACL (in a conditional context). Accept true, deny false. Defer is a forced-fail. Anything set by message= goes to $value. - See also the expansion-item version EITEM_ACL. */ + Up to ten parameters are used; we use the braces round the name+args + like the saslauthd condition does, to permit a variable number of args. + See also the expansion-item version EITEM_ACL and the traditional + acl modifier ACLC_ACL. + */ case ECOND_ACL: - /* ${if acl {name arg1 arg2...} {yes}{no}} + /* ${if acl {{name}{arg1}{arg2}...} {yes}{no}} { uschar *nameargs; uschar *user_msg; - uschar *log_msg; BOOL cond = FALSE; - int size = 0; while (isspace(*s)) s++; if (*s++ != '{') goto COND_FAILED_CURLY_START; - if (!(nameargs = expand_string_internal(s, TRUE, &s, FALSE, FALSE)) return NULL; - if (*s++ != '}') goto COND_FAILED_CURLY_END; - switch(acl_check_args(ACL_WHERE_EXPANSION, NULL, nameargs, &user_msg, &log_msg)) + switch(read_subs(sub, sizeof(sub)/sizeof(*sub), 1, + &s, yield == NULL, TRUE, US"acl")) { - case OK: - cond = TRUE; - case FAIL: - if (user_msg) - lookup_value = string_cat(NULL, &size, &ptr, user_msg, Ustrlen(user_msg)); - if (yield != NULL) *yield = cond; - return s; - - case DEFER: - expand_string_forcedfail = TRUE; - default: - expand_string_message = string_sprintf("error from acl \"%s\"", nameargs); - return NULL; + case 1: expand_string_message = US"too few arguments or bracketing " + "error for acl"; + case 2: + case 3: return NULL; } + + if (yield != NULL) + switch(eval_acl(sub, sizeof(sub)/sizeof(*sub), &user_msg)) + { + case OK: + cond = TRUE; + case FAIL: + if (user_msg) + lookup_value = string_cat(NULL, &size, &ptr, user_msg, Ustrlen(user_msg)); + else + lookup_value = NULL; + *yield = cond; + break; + + case DEFER: + expand_string_forcedfail = TRUE; + default: + expand_string_message = string_sprintf("error from acl \"%s\"", sub[0]); + return NULL; + } + return s; } - return s; /* saslauthd: does Cyrus saslauthd authentication. Four parameters are used: @@ -3697,15 +3743,15 @@ while (*s != 0) If the ACL returns accept or reject we return content set by "message =" There is currently no limit on recursion; this would have us call acl_check_internal() directly and get a current level from somewhere. + See also the acl expansion condition ECOND_ACL and the traditional + acl modifier ACLC_ACL. */ case EITEM_ACL: /* ${acl {name} {arg1}{arg2}...} */ { - int i; uschar *sub[10]; /* name + arg1-arg9 (which must match number of acl_arg[]) */ uschar *user_msg; - uschar *log_msg; switch(read_subs(sub, 10, 1, &s, skipping, TRUE, US"acl")) { @@ -3715,19 +3761,7 @@ while (*s != 0) } if (skipping) continue; - for (i = 1; i < sizeof(sub)/sizeof(*sub) && sub[i]; i++) - acl_arg[i-1] = sub[i]; - acl_narg = i-1; - while (i < sizeof(sub)/sizeof(*sub)) - acl_arg[i++ - 1] = NULL; - - DEBUG(D_expand) - debug_printf("expanding: acl: %s arg: %s%s\n", - sub[0], - acl_narg>0 ? sub[1] : US"", - acl_narg>1 ? " +more" : ""); - - switch(acl_check(ACL_WHERE_EXPANSION, NULL, sub[0], &user_msg, &log_msg)) + switch(eval_acl(sub, sizeof(sub)/sizeof(*sub), &user_msg)) { case OK: case FAIL: diff --git a/src/src/functions.h b/src/src/functions.h index 2257a3d7c..bc791fcdb 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -49,7 +49,6 @@ extern BOOL tls_openssl_options_parse(uschar *, long *); extern acl_block *acl_read(uschar *(*)(void), uschar **); extern int acl_check(int, uschar *, uschar *, uschar **, uschar **); -extern int acl_check_args(int, address_item *, uschar *, int, uschar **, uschar **); extern tree_node *acl_var_create(uschar *); extern void acl_var_write(uschar *, uschar *, void *); -- 2.30.2