From ef21c07db8048e09fadab639d8946c9358d3d464 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Thu, 25 Oct 2012 22:28:01 +0100 Subject: [PATCH 1/1] Save/restore $acl_arg1 ... across acl calls, making them local variables. --- doc/doc-docbook/spec.xfpt | 16 +++++++++------- src/src/acl.c | 23 ++++++++++++++++++++--- src/src/expand.c | 29 +++++++++++++++++++++++------ test/confs/0002 | 1 + 4 files changed, 53 insertions(+), 16 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 18cff9ed6..34518d3c4 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -8791,12 +8791,12 @@ arguments are assigned to the variables &$acl_arg1$& to &$acl_arg9$& in order. Any unused are made empty. The variable &$acl_narg$& is set to the number of arguments. The named ACL (see chapter &<>&) is called and may use the variables; if another acl expansion is used the values -are overwritten. If the ACL sets +are restored after it returns. If the ACL sets a value using a "message =" modifier and returns accept or deny, the value becomes the result of the expansion. -If no message was set and the ACL returned accept or deny -the value is an empty string. -If the ACL returned defer the result is a forced-fail. Otherwise the expansion fails. +If no message is set and the ACL returns accept or deny +the expansion result is an empty string. +If the ACL returns defer the result is a forced-fail. Otherwise the expansion fails. .vitem "&*${dlfunc{*&<&'file'&>&*}{*&<&'function'&>&*}{*&<&'arg'&>&*}&&& @@ -10107,7 +10107,7 @@ arguments are assigned to the variables &$acl_arg1$& to &$acl_arg9$& in order. Any unused are made empty. The variable &$acl_narg$& is set to the number of arguments. The named ACL (see chapter &<>&) is called and may use the variables; if another acl expansion is used the values -are overwritten. If the ACL sets +are restored after it returns. If the ACL sets a value using a "message =" modifier the variable $value becomes the result of the expansion, otherwise it is empty. If the ACL returns accept the condition is true; if deny, false. @@ -27518,8 +27518,10 @@ condition false. This means that further processing of the &%warn%& verb ceases, but processing of the ACL continues. If the argument is a named ACL, up to nine space-separated optional values -can be appended; they appear in $acl_arg1 to $acl_arg9, and $acl_narg is set -to the count of values. The name and values are expanded separately. +can be appended; they appear within the called ACL in $acl_arg1 to $acl_arg9, +and $acl_narg is set to the count of values. +Previous values of these variables are restored after the call returns. +The name and values are expanded separately. If the nested &%acl%& returns &"drop"& and the outer condition denies access, the connection is dropped. If it returns &"discard"&, the verb must be diff --git a/src/src/acl.c b/src/src/acl.c index 6ae3680b7..6c81d349d 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -3954,8 +3954,11 @@ acl_check_wargs(int where, address_item *addr, uschar *s, int level, { uschar * tmp; uschar * tmp_arg[9]; /* must match acl_arg[] */ +uschar * sav_arg[9]; /* must match acl_arg[] */ +int sav_narg; uschar * name; int i; +int ret; if (!(tmp = string_dequote(&s)) || !(name = expand_string(tmp))) goto bad; @@ -3970,11 +3973,25 @@ for (i = 0; i < 9; i++) goto bad; } } + +sav_narg = acl_narg; acl_narg = i; -for (i = 0; i < acl_narg; i++) acl_arg[i] = tmp_arg[i]; -while (i < 9) acl_arg[i++] = NULL; +for (i = 0; i < acl_narg; i++) + { + sav_arg[i] = acl_arg[i]; + acl_arg[i] = tmp_arg[i]; + } +while (i < 9) + { + sav_arg[i] = acl_arg[i]; + acl_arg[i++] = NULL; + } + +ret = acl_check_internal(where, addr, name, level, user_msgptr, log_msgptr); -return acl_check_internal(where, addr, name, level, user_msgptr, log_msgptr); +acl_narg = sav_narg; +for (i = 0; i < 9; i++) acl_arg[i] = sav_arg[i]; +return ret; bad: if (expand_string_forcedfail) return ERROR; diff --git a/src/src/expand.c b/src/src/expand.c index 0e969788a..4dea8b12d 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1853,6 +1853,7 @@ if (Ustrncmp(name, "acl_", 4) == 0) /* Load args from sub array to globals, and call acl_check(). +Sub array will be corrupted on return. Returns: OK access is granted by an ACCEPT verb DISCARD access is granted by a DISCARD verb @@ -1865,13 +1866,23 @@ static int eval_acl(uschar ** sub, int nsub, uschar ** user_msgp) { int i; -uschar *dummy_log_msg; +uschar *tmp; +int sav_narg = acl_narg; +int ret; -for (i = 1; i < nsub && sub[i]; i++) - acl_arg[i-1] = sub[i]; -acl_narg = i-1; +if(--nsub > sizeof(acl_arg)/sizeof(*acl_arg)) nsub = sizeof(acl_arg)/sizeof(*acl_arg); +for (i = 0; i < nsub && sub[i+1]; i++) + { + tmp = acl_arg[i]; + acl_arg[i] = sub[i+1]; /* place callers args in the globals */ + sub[i+1] = tmp; /* stash the old args using our caller's storage */ + } +acl_narg = i; while (i < nsub) - acl_arg[i++ - 1] = NULL; + { + sub[i+1] = acl_arg[i]; + acl_arg[i++] = NULL; + } DEBUG(D_expand) debug_printf("expanding: acl: %s arg: %s%s\n", @@ -1879,7 +1890,13 @@ DEBUG(D_expand) acl_narg>0 ? sub[1] : US"", acl_narg>1 ? " +more" : ""); -return acl_check(ACL_WHERE_EXPANSION, NULL, sub[0], user_msgp, &dummy_log_msg); +ret = acl_check(ACL_WHERE_EXPANSION, NULL, sub[0], user_msgp, &tmp); + +for (i = 0; i < nsub; i++) + acl_arg[i] = sub[i+1]; /* restore old args */ +acl_narg = sav_narg; + +return ret; } diff --git a/test/confs/0002 b/test/confs/0002 index eb473e6b9..409bd755f 100644 --- a/test/confs/0002 +++ b/test/confs/0002 @@ -57,6 +57,7 @@ a_defer: defer a_sub: + require acl = a_none foo bar baz barf require acl = a_deny "new arg1" $acl_arg1 # End -- 2.30.2