summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2012-06-14 23:24:16 +0100
committerJeremy Harris <jgh146exb@wizmail.org>2012-06-14 23:24:16 +0100
commit333eea9c862f2368e61fee5ce7231011c19f04ec (patch)
tree1ffcf6f20ddcec8f1ac097d081294bce551bc73d
parent525239c16e35d7bf893e0e2232f4c4c4a7c75447 (diff)
Add acl call as an expansion condition
-rw-r--r--src/src/acl.c37
-rw-r--r--src/src/expand.c69
-rw-r--r--src/src/functions.h2
3 files changed, 95 insertions, 13 deletions
diff --git a/src/src/acl.c b/src/src/acl.c
index a721665d4..84b0609cf 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -3863,6 +3863,43 @@ 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,
+ uschar **user_msgptr, uschar **log_msgptr)
+{
+uschar * tmp;
+uschar * name;
+
+if (!(tmp = string_dequote(&s)) || !(name = expand_string(tmp)))
+ goto bad;
+
+for (acl_narg = 0; acl_narg < sizeof(acl_arg)/sizeof(*acl_arg); acl_narg++)
+ {
+ while (*s && isspace(*s)) s++;
+ if (!*s) break;
+ if (!(tmp = string_dequote(&s)) || !(acl_arg[acl_narg] = expand_string(tmp)))
+ {
+ tmp = name;
+ goto bad;
+ }
+ }
+
+return acl_check_internal(where, addr, name, level+1, user_msgptr, log_msgptr);
+
+bad:
+if (expand_string_forcedfail) return ERROR;
+*log_msgptr = string_sprintf("failed to expand ACL string \"%s\": %s",
+ tmp, expand_string_message);
+return search_find_defer?DEFER:ERROR;
+}
+
+
+
/*************************************************
* Check access using an ACL *
*************************************************/
diff --git a/src/src/expand.c b/src/src/expand.c
index 913a808b8..7529ad1ca 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -249,6 +249,7 @@ static uschar *cond_table[] = {
US"==", /* Backward compatibility */
US">",
US">=",
+ US"acl",
US"and",
US"bool",
US"bool_lax",
@@ -294,6 +295,7 @@ enum {
ECOND_NUM_EE,
ECOND_NUM_G,
ECOND_NUM_GE,
+ ECOND_ACL,
ECOND_AND,
ECOND_BOOL,
ECOND_BOOL_LAX,
@@ -2066,12 +2068,50 @@ switch(cond_type)
return s;
+ /* 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. */
+
+ case ECOND_ACL:
+ /* ${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))
+ {
+ 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;
+ }
+ }
+ return s;
+
+
/* saslauthd: does Cyrus saslauthd authentication. Four parameters are used:
${if saslauthd {{username}{password}{service}{realm}} {yes}[no}}
However, the last two are optional. That is why the whole set is enclosed
- in their own set or braces. */
+ in their own set of braces. */
case ECOND_SASLAUTHD:
#ifndef CYRUS_SASLAUTHD_SOCKET
@@ -3654,18 +3694,19 @@ while (*s != 0)
switch(item_type)
{
/* Call an ACL from an expansion. We feed data in via $acl_arg1 - $acl_arg9.
- If the ACL returns acceptance we return content set by "message ="
+ 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.
*/
case EITEM_ACL:
+ /* ${acl {name} {arg1}{arg2}...} */
{
- int rc;
- uschar *sub[10]; /* name + arg1-arg9, must match number of acl_arg[] */
- uschar *new_yield;
+ 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"))
{
case 1: goto EXPAND_FAILED_CURLY;
@@ -3674,11 +3715,11 @@ while (*s != 0)
}
if (skipping) continue;
- for (rc = 1; rc < sizeof(sub)/sizeof(*sub) && sub[rc]; rc++)
- acl_arg[rc-1] = sub[rc];
- acl_narg = rc-1;
- while (rc < sizeof(sub)/sizeof(*sub))
- acl_arg[rc++ - 1] = NULL;
+ 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",
@@ -3686,16 +3727,18 @@ while (*s != 0)
acl_narg>0 ? sub[1] : US"<none>",
acl_narg>1 ? " +more" : "");
- switch(rc = acl_check(ACL_WHERE_EXPANSION, NULL, sub[0], &user_msg, &log_msg))
+ switch(acl_check(ACL_WHERE_EXPANSION, NULL, sub[0], &user_msg, &log_msg))
{
case OK:
+ case FAIL:
if (user_msg)
yield = string_cat(yield, &size, &ptr, user_msg, Ustrlen(user_msg));
continue;
+
case DEFER:
- continue;
+ expand_string_forcedfail = TRUE;
default:
- expand_string_message = string_sprintf("acl \"%s\" did not accept", sub[0]);
+ expand_string_message = string_sprintf("error from acl \"%s\"", sub[0]);
goto EXPAND_FAILED;
}
}
diff --git a/src/src/functions.h b/src/src/functions.h
index 09f7ab95c..2257a3d7c 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -49,6 +49,8 @@ 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 *);
extern uschar *auth_b64encode(uschar *, int);