ARC: add $arc_domains variable, for verify pass
[exim.git] / src / src / arc.c
index c860aed366cc33b4e41f878e01d1e7664fdcdd78..7ad00fc9fa60df4a339df67717814cba70c0081f 100644 (file)
@@ -93,6 +93,7 @@ static time_t now;
 static time_t expire;
 static hdr_rlist * headers_rlist;
 static arc_ctx arc_sign_ctx = { NULL };
+static arc_ctx arc_verify_ctx = { NULL };
 
 
 /******************************************************************************/
@@ -382,7 +383,7 @@ static uschar *
 arc_insert_hdr(arc_ctx * ctx, header_line * h, unsigned off, unsigned hoff,
   BOOL instance_only)
 {
-int i;
+unsigned i;
 arc_set * as;
 arc_line * al = store_get(sizeof(arc_line)), ** alp;
 uschar * e;
@@ -395,6 +396,7 @@ if ((e = arc_parse_line(al, h, off, instance_only)))
   return US"line parse";
   }
 if (!(i = arc_instance_from_hdr(al)))  return US"instance find";
+if (i > 50)                            return US"overlarge instance number";
 if (!(as = arc_find_set(ctx, i)))      return US"set find";
 if (*(alp = (arc_line **)(US as + hoff))) return US"dup hdr";
 
@@ -767,7 +769,6 @@ arc_headers_check(arc_ctx * ctx)
 arc_set * as;
 int inst;
 BOOL ams_fail_found = FALSE;
-uschar * ret = NULL;
 
 if (!(as = ctx->arcset_chain))
   return US"none";
@@ -799,20 +800,20 @@ for(inst = 0; as; as = as->next)
 
 arc_received = ctx->arcset_chain_last;
 arc_received_instance = inst;
-if (ret)
-  return ret;
 
 /* We can skip the latest-AMS validation, if we already did it. */
 
 as = ctx->arcset_chain_last;
-if (as->ams_verify_done && !as->ams_verify_passed)
+if (!as->ams_verify_passed)
   {
-  arc_state_reason = as->ams_verify_done;
-  return US"fail";
+  if (as->ams_verify_done)
+    {
+    arc_state_reason = as->ams_verify_done;
+    return US"fail";
+    }
+  if (!!arc_ams_verify(ctx, as))
+    return US"fail";
   }
-if (!!arc_ams_verify(ctx, as))
-  return US"fail";
-
 return NULL;
 }
 
@@ -998,9 +999,10 @@ Return:  The ARC state, or NULL on error.
 const uschar *
 acl_verify_arc(void)
 {
-arc_ctx ctx = { NULL };
 const uschar * res;
 
+memset(&arc_verify_ctx, 0, sizeof(arc_verify_ctx));
+
 if (!dkim_verify_ctx)
   {
   DEBUG(D_acl) debug_printf("ARC: no DKIM verify context\n");
@@ -1014,7 +1016,7 @@ https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-10#section-6
        none, the ARC state is "none" and the algorithm stops here.
 */
 
-if ((res = arc_vfy_collect_hdrs(&ctx)))
+if ((res = arc_vfy_collect_hdrs(&arc_verify_ctx)))
   goto out;
 
 /* 2.  If the form of any ARC set is invalid (e.g., does not contain
@@ -1032,7 +1034,7 @@ if ((res = arc_vfy_collect_hdrs(&ctx)))
        then the chain state is "fail" and the algorithm stops here.
 */
 
-if ((res = arc_headers_check(&ctx)))
+if ((res = arc_headers_check(&arc_verify_ctx)))
   goto out;
 
 /* 4.  For each ARC-Seal from the "N"th instance to the first, apply the
@@ -1074,7 +1076,7 @@ if ((res = arc_headers_check(&ctx)))
        the algorithm is complete.
 */
 
-if ((res = arc_verify_seals(&ctx)))
+if ((res = arc_verify_seals(&arc_verify_ctx)))
   goto out;
 
 res = US"pass";
@@ -1569,7 +1571,7 @@ expire = now = 0;
 
 identity = string_nextinlist(&signspec, &sep, NULL, 0);
 selector = string_nextinlist(&signspec, &sep, NULL, 0);
-if (  !*identity | !*selector
+if (  !*identity || !*selector
    || !(privkey = string_nextinlist(&signspec, &sep, NULL, 0)) || !*privkey)
   {
   log_write(0, LOG_MAIN, "ARC: bad signing-specification (%s)",
@@ -1618,18 +1620,17 @@ string_from_gstring(sigheaders);
 if ((rheaders = arc_sign_scan_headers(&arc_sign_ctx, sigheaders)))
   {
   hdr_rlist ** rp;
-  for (rp = &rheaders; *rp; ) rp = &(*rp)->prev;
-  *rp = headers_rlist;
-  headers_rlist = rheaders;
+  for (rp = &headers_rlist; *rp; ) rp = &(*rp)->prev;
+  *rp = rheaders;
   }
-else
-  rheaders = headers_rlist;
 
 /* Finally, build a normal-order headers list */
 /*XXX only needed for hunt-the-AR? */
+/*XXX also, we really should be accepting any number of ADMD-matching ARs */
   {
   header_line * hnext = NULL;
-  for (; rheaders; hnext = rheaders->h, rheaders = rheaders->prev)
+  for (rheaders = headers_rlist; rheaders;
+       hnext = rheaders->h, rheaders = rheaders->prev)
     rheaders->h->next = hnext;
   headers = hnext;
   }
@@ -1773,6 +1774,26 @@ return is_vfy ? arc_header_vfy_feed(g) : arc_header_sign_feed(g);
 
 /******************************************************************************/
 
+/* Construct the list of domains from the ARC chain after validation */
+
+uschar *
+fn_arc_domains(void)
+{
+arc_set * as;
+gstring * g = NULL;
+
+if (!arc_state || Ustrcmp(arc_state, "pass") != 0)
+  return US"";
+
+for(as = arc_verify_ctx.arcset_chain; as; as = as->next)
+  {
+  blob * d = &as->hdr_as->d;
+  g = string_append_listele_n(g, ':', d->data, d->len);
+  }
+return g ? g->s : US"";
+}
+
+
 /* Construct an Authenticate-Results header portion, for the ARC module */
 
 gstring *