Add a bunch of expandables and some DKIM ACL red tape
authorTom Kistner <tom@duncanthrax.net>
Mon, 8 Jun 2009 21:06:31 +0000 (21:06 +0000)
committerTom Kistner <tom@duncanthrax.net>
Mon, 8 Jun 2009 21:06:31 +0000 (21:06 +0000)
src/src/dkim.c
src/src/dkim.h
src/src/expand.c
src/src/receive.c

index f0805ac42372209f70ffb41fead695520519252c..a2beafd6cefcc1354a8a8ae9609e17f14f08b6ac 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/dkim.c,v 1.1.2.14 2009/05/27 17:29:35 tom Exp $ */
+/* $Cambridge: exim/src/src/dkim.c,v 1.1.2.15 2009/06/08 21:06:31 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -18,6 +18,7 @@
 
 pdkim_ctx       *dkim_verify_ctx = NULL;
 pdkim_signature *dkim_signatures = NULL;
+pdkim_signature *dkim_cur_sig    = NULL;
 
 int dkim_exim_query_dns_txt(char *name, char *answer) {
   dns_answer dnsa;
@@ -79,6 +80,7 @@ void dkim_exim_verify_feed(uschar *data, int len) {
 
 
 void dkim_exim_verify_finish(void) {
+  pdkim_signature *sig = NULL;
   int dkim_signing_domains_size = 0;
   int dkim_signing_domains_ptr = 0;
   dkim_signing_domains = NULL;
@@ -99,49 +101,49 @@ void dkim_exim_verify_finish(void) {
   /* Finish DKIM operation and fetch link to signatures chain */
   if (pdkim_feed_finish(dkim_verify_ctx,&dkim_signatures) != PDKIM_OK) return;
 
-
-  while (dkim_signatures != NULL) {
+  sig = dkim_signatures;
+  while (sig != NULL) {
     int size = 0;
     int ptr = 0;
     /* Log a line for each signature */
     uschar *logmsg = string_append(NULL, &size, &ptr, 5,
 
       string_sprintf( "DKIM: d=%s s=%s c=%s/%s a=%s ",
-                      dkim_signatures->domain,
-                      dkim_signatures->selector,
-                      (dkim_signatures->canon_headers == PDKIM_CANON_SIMPLE)?"simple":"relaxed",
-                      (dkim_signatures->canon_body    == PDKIM_CANON_SIMPLE)?"simple":"relaxed",
-                      (dkim_signatures->algo          == PDKIM_ALGO_RSA_SHA256)?"rsa-sha256":"rsa-sha1"
+                      sig->domain,
+                      sig->selector,
+                      (sig->canon_headers == PDKIM_CANON_SIMPLE)?"simple":"relaxed",
+                      (sig->canon_body    == PDKIM_CANON_SIMPLE)?"simple":"relaxed",
+                      (sig->algo          == PDKIM_ALGO_RSA_SHA256)?"rsa-sha256":"rsa-sha1"
                     ),
-      ((dkim_signatures->identity != NULL)?
-        string_sprintf("i=%s ", dkim_signatures->identity)
+      ((sig->identity != NULL)?
+        string_sprintf("i=%s ", sig->identity)
         :
         US""
       ),
-      ((dkim_signatures->created > 0)?
-        string_sprintf("t=%lu ", dkim_signatures->created)
+      ((sig->created > 0)?
+        string_sprintf("t=%lu ", sig->created)
         :
         US""
       ),
-      ((dkim_signatures->expires > 0)?
-        string_sprintf("x=%lu ", dkim_signatures->expires)
+      ((sig->expires > 0)?
+        string_sprintf("x=%lu ", sig->expires)
         :
         US""
       ),
-      ((dkim_signatures->bodylength > -1)?
-        string_sprintf("l=%lu ", dkim_signatures->bodylength)
+      ((sig->bodylength > -1)?
+        string_sprintf("l=%lu ", sig->bodylength)
         :
         US""
       )
     );
 
-    switch(dkim_signatures->verify_status) {
+    switch(sig->verify_status) {
       case PDKIM_VERIFY_NONE:
         logmsg = string_append(logmsg, &size, &ptr, 1, "[not verified]");
       break;
       case PDKIM_VERIFY_INVALID:
         logmsg = string_append(logmsg, &size, &ptr, 1, "[invalid - ");
-        switch (dkim_signatures->verify_ext_status) {
+        switch (sig->verify_ext_status) {
           case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
             logmsg = string_append(logmsg, &size, &ptr, 1, "public key record (currently?) unavailable]");
           break;
@@ -157,7 +159,7 @@ void dkim_exim_verify_finish(void) {
       break;
       case PDKIM_VERIFY_FAIL:
         logmsg = string_append(logmsg, &size, &ptr, 1, "[verification failed - ");
-        switch (dkim_signatures->verify_ext_status) {
+        switch (sig->verify_ext_status) {
           case PDKIM_VERIFY_FAIL_BODY:
             logmsg = string_append(logmsg, &size, &ptr, 1, "body hash mismatch (body probably modified in transit)]");
           break;
@@ -181,12 +183,12 @@ void dkim_exim_verify_finish(void) {
                                          &dkim_signing_domains_size,
                                          &dkim_signing_domains_ptr,
                                          2,
-                                         dkim_signatures->domain,
+                                         sig->domain,
                                          ":"
                                         );
 
     /* Process next signature */
-    dkim_signatures = dkim_signatures->next;
+    sig = sig->next;
   }
 
   /* Chop the last colon from the domain list */
@@ -196,9 +198,161 @@ void dkim_exim_verify_finish(void) {
 }
 
 
-void dkim_exim_verify_result(uschar *domain, uschar **result, uschar **error) {
-  if (dkim_verify_ctx) {
+void dkim_exim_acl_setup(uschar *id) {
+  pdkim_signature *sig = dkim_signatures;
+  dkim_cur_sig = NULL;
+  if (dkim_disable_verify ||
+      !id || !sig ||
+      !dkim_verify_ctx) return;
+  /* Find signature to run ACL on */
+  while (sig != NULL) {
+    uschar *cmp_val = NULL;
+    if (Ustrchr(id,'@') != NULL) cmp_val = (uschar *)sig->identity;
+                            else cmp_val = (uschar *)sig->domain;
+    if (cmp_val && (strcmpic(cmp_val,id) == 0)) {
+      dkim_cur_sig = sig;
+      /* The "dkim_domain" and "dkim_selector" expansion variables have
+         related globals, since they are used in the signing code too.
+         Instead of inventing separate names for verification, we set
+         them here. This is easy since a domain and selector is guaranteed
+         to be in a signature. The other dkim_* expansion items are
+         dynamically fetched from dkim_cur_sig at expansion time (see
+         function below). */
+      dkim_signing_domain   = (uschar *)sig->domain;
+      dkim_signing_selector = (uschar *)sig->selector;
+      return;
+    }
+    sig = sig->next;
+  }
+}
+
+
+uschar *dkim_exim_expand_query(int what) {
+
+  if (!dkim_verify_ctx ||
+      dkim_disable_verify ||
+      !dkim_cur_sig) return dkim_exim_expand_defaults(what);
+
+  switch(what) {
+    case DKIM_ALGO:
+      return dkim_cur_sig->algo?
+              (uschar *)(dkim_cur_sig->algo)
+              :dkim_exim_expand_defaults(what);
+    case DKIM_BODYLENGTH:
+      return (dkim_cur_sig->bodylength >= 0)?
+              (uschar *)string_sprintf(OFF_T_FMT,(LONGLONG_T)dkim_cur_sig->bodylength)
+              :dkim_exim_expand_defaults(what);
+    case DKIM_CANON_BODY:
+      return dkim_cur_sig->canon_body?
+              (uschar *)(dkim_cur_sig->canon_body)
+              :dkim_exim_expand_defaults(what);
+    case DKIM_CANON_HEADERS:
+      return dkim_cur_sig->canon_headers?
+              (uschar *)(dkim_cur_sig->canon_headers)
+              :dkim_exim_expand_defaults(what);
+    case DKIM_COPIEDHEADERS:
+      return dkim_cur_sig->copiedheaders?
+              (uschar *)(dkim_cur_sig->copiedheaders)
+              :dkim_exim_expand_defaults(what);
+    case DKIM_CREATED:
+      return (dkim_cur_sig->created > 0)?
+              (uschar *)string_sprintf("%llu",dkim_cur_sig->created)
+              :dkim_exim_expand_defaults(what);
+    case DKIM_EXPIRES:
+      return (dkim_cur_sig->expires > 0)?
+              (uschar *)string_sprintf("%llu",dkim_cur_sig->expires)
+              :dkim_exim_expand_defaults(what);
+    case DKIM_HEADERNAMES:
+      return dkim_cur_sig->headernames?
+              (uschar *)(dkim_cur_sig->headernames)
+              :dkim_exim_expand_defaults(what);
+    case DKIM_IDENTITY:
+      return dkim_cur_sig->identity?
+              (uschar *)(dkim_cur_sig->identity)
+              :dkim_exim_expand_defaults(what);
+    case DKIM_KEY_GRANULARITY:
+      return dkim_cur_sig->pubkey?
+              (dkim_cur_sig->pubkey->granularity?
+                (uschar *)(dkim_cur_sig->pubkey->granularity)
+                :dkim_exim_expand_defaults(what)
+              )
+              :dkim_exim_expand_defaults(what);
+    case DKIM_KEY_SRVTYPE:
+      return dkim_cur_sig->pubkey?
+              (dkim_cur_sig->pubkey->srvtype?
+                (uschar *)(dkim_cur_sig->pubkey->srvtype)
+                :dkim_exim_expand_defaults(what)
+              )
+              :dkim_exim_expand_defaults(what);
+    case DKIM_KEY_NOTES:
+      return dkim_cur_sig->pubkey?
+              (dkim_cur_sig->pubkey->notes?
+                (uschar *)(dkim_cur_sig->pubkey->notes)
+                :dkim_exim_expand_defaults(what)
+              )
+              :dkim_exim_expand_defaults(what);
+    case DKIM_KEY_TESTING:
+      return dkim_cur_sig->pubkey?
+              (dkim_cur_sig->pubkey->testing?
+                US"1"
+                :dkim_exim_expand_defaults(what)
+              )
+              :dkim_exim_expand_defaults(what);
+    case DKIM_NOSUBDOMAINS:
+      return dkim_cur_sig->pubkey?
+              (dkim_cur_sig->pubkey->no_subdomaining?
+                US"1"
+                :dkim_exim_expand_defaults(what)
+              )
+              :dkim_exim_expand_defaults(what);
+    case DKIM_VERIFY_STATUS:
+      switch(dkim_cur_sig->verify_status) {
+        case PDKIM_VERIFY_INVALID:
+          return US"invalid";
+        case PDKIM_VERIFY_FAIL:
+          return US"fail";
+        case PDKIM_VERIFY_PASS:
+          return US"pass";
+        case PDKIM_VERIFY_NONE:
+        default:
+          return US"none";
+      }
+    case DKIM_VERIFY_REASON:
+      switch (dkim_cur_sig->verify_ext_status) {
+        case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
+          return US"pubkey_unavailable";
+        case PDKIM_VERIFY_INVALID_PUBKEY_PARSING:
+          return US"pubkey_syntax";
+        case PDKIM_VERIFY_FAIL_BODY:
+          return US"bodyhash_mismatch";
+        case PDKIM_VERIFY_FAIL_MESSAGE:
+          return US"signature_incorrect";
+      }
+    default:
+      return US"";
+  }
+}
+
 
+uschar *dkim_exim_expand_defaults(int what) {
+  switch(what) {
+    case DKIM_ALGO:               return US"";
+    case DKIM_BODYLENGTH:         return US"9999999999999";
+    case DKIM_CANON_BODY:         return US"";
+    case DKIM_CANON_HEADERS:      return US"";
+    case DKIM_COPIEDHEADERS:      return US"";
+    case DKIM_CREATED:            return US"0";
+    case DKIM_EXPIRES:            return US"9999999999999";
+    case DKIM_HEADERNAMES:        return US"";
+    case DKIM_IDENTITY:           return US"";
+    case DKIM_KEY_GRANULARITY:    return US"*";
+    case DKIM_KEY_SRVTYPE:        return US"*";
+    case DKIM_KEY_NOTES:          return US"";
+    case DKIM_KEY_TESTING:        return US"0";
+    case DKIM_NOSUBDOMAINS:       return US"0";
+    case DKIM_VERIFY_STATUS:      return US"none";
+    case DKIM_VERIFY_REASON:      return US"";
+    default:                      return US"";
   }
 }
 
index c9c602fa6c1e388a513cb49a27f66bc51f29f8ba..f683914d50ff1e618d36dade71e0883fde256704 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/dkim.h,v 1.1.2.4 2009/05/20 14:30:14 tom Exp $ */
+/* $Cambridge: exim/src/src/dkim.h,v 1.1.2.5 2009/06/08 21:06:31 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -7,16 +7,27 @@
 /* Copyright (c) University of Cambridge 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 
-uschar *dkim_exim_sign(int,
-                       uschar *,
-                       uschar *,
-                       uschar *,
-                       uschar *,
-                       uschar *);
+uschar *dkim_exim_sign(int,uschar *,uschar *,uschar *,uschar *,uschar *);
+void    dkim_exim_verify_init(void);
+void    dkim_exim_verify_feed(uschar *, int);
+void    dkim_exim_verify_finish(void);
+void    dkim_exim_acl_setup(uschar *);
+uschar *dkim_exim_expand_query(int);
+uschar *dkim_exim_expand_defaults(int);
 
-void dkim_exim_verify_init(void);
-void dkim_exim_verify_feed(uschar *, int);
-void dkim_exim_verify_finish(void);
-void dkim_exim_verify_result(uschar *,
-                             uschar **,
-                             uschar **);
+#define DKIM_ALGO               1
+#define DKIM_BODYLENGTH         2
+#define DKIM_CANON_BODY         3
+#define DKIM_CANON_HEADERS      4
+#define DKIM_COPIEDHEADERS      5
+#define DKIM_CREATED            6
+#define DKIM_EXPIRES            7
+#define DKIM_HEADERNAMES        8
+#define DKIM_IDENTITY           9
+#define DKIM_KEY_GRANULARITY   10
+#define DKIM_KEY_SRVTYPE       11
+#define DKIM_KEY_NOTES         12
+#define DKIM_KEY_TESTING       13
+#define DKIM_NOSUBDOMAINS      14
+#define DKIM_VERIFY_STATUS     15
+#define DKIM_VERIFY_REASON     16
index f94503c43b1bf11fbc9318df799c4914e349cb91..7e957b1cd4c38baf2ff466ec836669b3d5abc364 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/expand.c,v 1.97.2.2 2009/05/27 17:26:54 tom Exp $ */
+/* $Cambridge: exim/src/src/expand.c,v 1.97.2.3 2009/06/08 21:06:31 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -364,6 +364,9 @@ enum {
   vtype_load_avg,       /* value not used; result is int from os_getloadavg */
   vtype_pspace,         /* partition space; value is T/F for spool/log */
   vtype_pinodes         /* partition inodes; value is T/F for spool/log */
+  #ifndef DISABLE_DKIM
+  ,vtype_dkim           /* Lookup of value in DKIM signature */
+  #endif
   };
 
 /* This table must be kept in alphabetical order. */
@@ -402,9 +405,25 @@ static var_entry var_table[] = {
   { "demime_reason",       vtype_stringptr,   &demime_reason },
 #endif
 #ifndef DISABLE_DKIM
+  { "dkim_algo",           vtype_dkim,        (void *)DKIM_ALGO },
+  { "dkim_bodylength",     vtype_dkim,        (void *)DKIM_BODYLENGTH },
+  { "dkim_canon_body",     vtype_dkim,        (void *)DKIM_CANON_BODY },
+  { "dkim_canon_headers",  vtype_dkim,        (void *)DKIM_CANON_HEADERS },
+  { "dkim_copiedheaders",  vtype_dkim,        (void *)DKIM_COPIEDHEADERS },
+  { "dkim_created",        vtype_dkim,        (void *)DKIM_CREATED },
   { "dkim_domain",         vtype_stringptr,   &dkim_signing_domain },
+  { "dkim_expires",        vtype_dkim,        (void *)DKIM_EXPIRES },
+  { "dkim_headernames",    vtype_dkim,        (void *)DKIM_HEADERNAMES },
+  { "dkim_identity",       vtype_dkim,        (void *)DKIM_IDENTITY },
+  { "dkim_key_granularity",vtype_dkim,        (void *)DKIM_KEY_GRANULARITY },
+  { "dkim_key_nosubdomains",vtype_dkim,       (void *)DKIM_NOSUBDOMAINS },
+  { "dkim_key_notes",      vtype_dkim,        (void *)DKIM_KEY_NOTES },
+  { "dkim_key_srvtype",    vtype_dkim,        (void *)DKIM_KEY_SRVTYPE },
+  { "dkim_key_testing",    vtype_dkim,        (void *)DKIM_KEY_TESTING },
   { "dkim_selector",       vtype_stringptr,   &dkim_signing_selector },
   { "dkim_signing_domains",vtype_stringptr,   &dkim_signing_domains },
+  { "dkim_verify_reason",  vtype_dkim,        (void *)DKIM_VERIFY_REASON },
+  { "dkim_verify_status",  vtype_dkim,        (void *)DKIM_VERIFY_STATUS},
 #endif
   { "dnslist_domain",      vtype_stringptr,   &dnslist_domain },
   { "dnslist_matched",     vtype_stringptr,   &dnslist_matched },
@@ -1546,6 +1565,11 @@ while (last > first)
       }
     return var_buffer;
 
+    #ifndef DKIM_DISABLE
+    case vtype_dkim:
+    return dkim_exim_expand_query((int)var_table[middle].value);
+    #endif
+
     }
   }
 
index 3ee596ee70d6eac5d93d2320f3591aa8765884f1..cb29e35da8a4f48a15cdd7a950a6ab400a8457bf 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/receive.c,v 1.45.2.4 2009/05/27 17:26:55 tom Exp $ */
+/* $Cambridge: exim/src/src/receive.c,v 1.45.2.5 2009/06/08 21:06:32 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -2998,20 +2998,35 @@ else
                                            itembuf,
                                            sizeof(itembuf))) != NULL)
             {
-
-
+            dkim_exim_acl_setup(item);
             rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, &user_msg, &log_msg);
             if (rc != OK) break;
             }
-
           add_acl_headers(US"DKIM");
+          if (rc == DISCARD)
+            {
+            recipients_count = 0;
+            blackholed_by = US"DKIM ACL";
+            if (log_msg != NULL)
+              blackhole_log_msg = string_sprintf(": %s", log_msg);
+            }
+          else if (rc != OK)
+            {
+            Uunlink(spool_name);
+            if (smtp_handle_acl_fail(ACL_WHERE_DKIM, rc, user_msg, log_msg) != 0)
+              smtp_yield = FALSE;    /* No more messsages after dropped connection */
+            smtp_reply = US"";       /* Indicate reply already sent */
+            message_id[0] = 0;       /* Indicate no message accepted */
+            goto TIDYUP;             /* Skip to end of function */
+            }
           }
         }
       }
 #endif /* DISABLE_DKIM */
 
 #ifdef WITH_CONTENT_SCAN
-    if (acl_smtp_mime != NULL &&
+    if (recipients_count > 0 &&
+        acl_smtp_mime != NULL &&
         !run_mime_acl(acl_smtp_mime, &smtp_yield, &smtp_reply, &blackholed_by))
       goto TIDYUP;
 #endif /* WITH_CONTENT_SCAN */