Add ${acl {name}{arg}} expansion item.
authorJeremy Harris <jgh146exb@wizmail.org>
Mon, 11 Jun 2012 21:00:11 +0000 (22:00 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 12 Jun 2012 20:48:59 +0000 (21:48 +0100)
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
src/src/expand.c
src/src/globals.c
src/src/macros.h
test/confs/0002
test/scripts/0000-Basic/0002
test/stdout/0002

index dcf6b6cfb0a2bbecc9a059cb67c4162ee89286f2..cde80a17c10cda91eb142d0016646b4158b062a5 100644 (file)
@@ -8758,6 +8758,20 @@ string easier to understand.
 This item inserts &"basic"& header lines. It is described with the &%header%&
 expansion item below.
 
+
+.vitem "&*${acl{*&<&'name'&>&*}{*&<&'string'&>&*}}*&"
+.cindex "expansion" "calling an acl"
+.cindex "&%acl%&" "call from expansion"
+The name and <&'string'&> are first expanded separately.  The expanded
+<&'string'&> is assigned to the &$address_data$& variable.  If {<&'string'&>}
+is omitted, &$address_data$& is made empty.  The named ACL (see chapter
+&<<CHAPACL>>&) is called and may use &$address_data$&.  If the ACL sets
+a value using a "message =" modifier and returns accept, the value becomes
+the result of the expansion.
+If no message was set but the ACL returned accept, or if the ACL returned defer,
+the value is an empty string.  Otherwise the expansion fails.
+
+
 .vitem "&*${dlfunc{*&<&'file'&>&*}{*&<&'function'&>&*}{*&<&'arg'&>&*}&&&
        {*&<&'arg'&>&*}...}*&"
 .cindex &%dlfunc%&
index 34521098e3dbfde4bf6153a35f947dedd951e7c4..4a2215956814a545d422b6cbfbf76c5262067dce 100644 (file)
@@ -44,6 +44,8 @@ NM/01 Bugzilla 1197 - Spec typo
 
 JH/03 Add expansion operators ${listnamed:name} and ${listcount:string}
 
+JH/04 Add expansion item ${acl {name}{argument}}
+
 Exim version 4.80
 -----------------
 
index 6d64faa00a9e084f07def4125751dccf300b695f..b13a5a0f2061682238e5a818a26cf99f7415835a 100644 (file)
@@ -87,6 +87,10 @@ Version 4.81
  8. New expansion operators ${listnamed:name} to get the content of a named list
     and ${listcount:string} to count the items in a list.
 
+ 9. New expansion item ${acl {name}{argument}} to call an ACL.  The argument can
+    be accessed by the ACL in $address_data.  The expansion result is set by
+    a "message =" modifier and an "accept" return from the ACL.
+
 Version 4.80
 ------------
 
index 9658426113d3ffc003fb37807184dea99d9cc4e9..16d5d74abb1f12b5ef25378b8198c048e0d6cb9e 100644 (file)
@@ -102,6 +102,7 @@ bcrypt ({CRYPT}$2a$).
 alphabetical order. */
 
 static uschar *item_table[] = {
+  US"acl",
   US"dlfunc",
   US"extract",
   US"filter",
@@ -124,6 +125,7 @@ static uschar *item_table[] = {
   US"tr" };
 
 enum {
+  EITEM_ACL,
   EITEM_DLFUNC,
   EITEM_EXTRACT,
   EITEM_FILTER,
@@ -3641,6 +3643,45 @@ while (*s != 0)
 
   switch(item_type)
     {
+    /* Call an ACL from an expansion.  We feed data in via $address_data.
+    If the ACL returns acceptance 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:
+      {
+      int rc;
+      uschar *sub[2];
+      uschar *new_yield;
+      uschar *user_msg;
+      uschar *log_msg;
+      switch(read_subs(sub, 2, 1, &s, skipping, TRUE, US"acl"))
+        {
+        case 1: goto EXPAND_FAILED_CURLY;
+        case 2:
+        case 3: goto EXPAND_FAILED;
+        }
+      if (skipping) continue;
+
+      DEBUG(D_expand)
+        debug_printf("expanding: acl: %s  arg: %s\n", sub[0], sub[1]?sub[1]:US"<none>");
+
+      deliver_address_data = sub[1];
+      switch(rc = acl_check(ACL_WHERE_EXPANSION, NULL, sub[0], &user_msg, &log_msg))
+       {
+       case OK:
+         if (user_msg)
+            yield = string_cat(yield, &size, &ptr, user_msg, Ustrlen(user_msg));
+         continue;
+       case DEFER:
+         continue;
+       default:
+          expand_string_message = string_sprintf("acl \"%s\" did not accept", sub[0]);
+         goto EXPAND_FAILED;
+       }
+      }
+
     /* Handle conditionals - preserve the values of the numerical expansion
     variables in case they get changed by a regular expression match in the
     condition. If not, they retain their external settings. At the end
@@ -5533,7 +5574,6 @@ while (*s != 0)
          goto EXPAND_FAILED;
          }
 
-       if (skipping) continue;
        list = ((namedlist_block *)(t->data.ptr))->string;
 
        while ((item = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
index 97c7166abe52fb25d7ce7c2e1f51ab0e6a382aae..3ad38d39da3ef1480a3dd77066aee01771eaf1eb 100644 (file)
@@ -192,7 +192,6 @@ uschar *acl_not_smtp           = NULL;
 uschar *acl_not_smtp_mime      = NULL;
 #endif
 uschar *acl_not_smtp_start     = NULL;
-
 uschar *acl_smtp_auth          = NULL;
 uschar *acl_smtp_connect       = NULL;
 uschar *acl_smtp_data          = NULL;
@@ -240,7 +239,8 @@ uschar *acl_wherenames[]       = { US"RCPT",
                                    US"NOTQUIT",
                                    US"QUIT",
                                    US"STARTTLS",
-                                   US"VRFY"
+                                   US"VRFY",
+                                  US"expansion"
                                  };
 
 uschar *acl_wherecodes[]       = { US"550",     /* RCPT */
@@ -260,7 +260,8 @@ uschar *acl_wherecodes[]       = { US"550",     /* RCPT */
                                    US"0",       /* NOTQUIT; not relevant */
                                    US"0",       /* QUIT; not relevant */
                                    US"550",     /* STARTTLS */
-                                   US"252"      /* VRFY */
+                                   US"252",     /* VRFY */
+                                  US"0"        /* unknown; not relevant */
                                  };
 
 BOOL    active_local_from_check = FALSE;
index b17a80e103beccba5072e042c3c80bcd4b9de1f4..d25071aae1c8dd6ca827d5747dba01910c17a2bf 100644 (file)
@@ -820,7 +820,9 @@ enum { ACL_WHERE_RCPT,       /* Some controls are for RCPT only */
        ACL_WHERE_NOTQUIT,
        ACL_WHERE_QUIT,
        ACL_WHERE_STARTTLS,
-       ACL_WHERE_VRFY
+       ACL_WHERE_VRFY,
+
+       ACL_WHERE_EXPANSION   /* Currently used by a ${acl:name} expansion */
      };
 
 /* Situations for spool_write_header() */
index 6983fd87f18385aaad761e9948f19625798ec95c..317c4a27daafcb8df1e2e7aa3856272a749aaca3 100644 (file)
@@ -44,4 +44,12 @@ check_data:
   warn  logwrite = Subject is: "$h_subject:"
   deny  message = reply_address=<$reply_address>
 
+a_ret:
+  accept message = [$address_data]
+
+a_none:
+  accept
+
+a_deny:
+
 # End
index 652891615b54e7acd42d2e08c03157196fedc30c..d567f84868bfee15fddb4ea2194fdd60431f2038 100644 (file)
@@ -86,6 +86,17 @@ reduce: ${reduce {<\x7f 1\x7f2\177 3}{0}{${eval:$value+$item}}}
 
 # Operators
 
+acl: ${acl
+acl: ${acl}
+acl: ${acl {a_bad}}
+acl: ${acl {a_ret}}
+acl: ${acl {a_ret}{person@dom.ain}}
+acl: ${acl {a_none}}
+acl: ${acl {a_none}{person@dom.ain}}
+acl: ${acl {a_deny}}
+acl: ${acl {a_deny}{person@dom.ain}}
+acl: ${reduce {1:2:3:4} {} {$value ${acl {a_ret}{$item}}}}
+
 addrss: ${address:local-part@dom.ain}
 addrss: ${address:Exim Person <local-part@dom.ain> (that's me)}
 domain: ${domain:local-part@dom.ain}
index de67f99fc21565987af4c405d97193b2a24e19e7..377fe02cd417bd5fd20d2b9843c00da7d148c899 100644 (file)
 > 
 > # Operators
 > 
+> Failed: missing or misplaced { or }
+> Failed: missing or misplaced { or }
+> Failed: acl "a_bad" did not accept
+> acl: []
+> acl: [person@dom.ain]
+> acl: 
+> acl: 
+> Failed: acl "a_deny" did not accept
+> Failed: acl "a_deny" did not accept
+> acl:  [1] [2] [3] [4]
+> 
 > addrss: local-part@dom.ain
 > addrss: local-part@dom.ain
 > domain: dom.ain