gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-exchange] branch master updated (9efa30cdd -> f01cdeacd)


From: gnunet
Subject: [taler-exchange] branch master updated (9efa30cdd -> f01cdeacd)
Date: Fri, 13 Dec 2024 01:48:21 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a change to branch master
in repository exchange.

    from 9efa30cdd [exchange] fix auditor tests in container (actual)
     new 5e142edf6 improve timeout handling and fallback measure invocation as 
well as configuration sanity-checking on load
     new f01cdeacd -fix compiler warnings: use static

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/exchange/taler-exchange-aggregator.c           |  12 -
 src/exchange/taler-exchange-httpd.c                |   4 +-
 src/exchange/taler-exchange-httpd_common_kyc.c     |  44 +--
 src/exchange/taler-exchange-httpd_withdraw.c       |   9 +-
 src/exchangedb/exchangedb_aml.c                    |  97 +-----
 src/include/taler_kyclogic_lib.h                   |  18 ++
 src/kyclogic/kyclogic_api.c                        | 324 +++++++++++++++++----
 src/testing/test_exchange_api_age_restriction.conf |   7 +-
 8 files changed, 303 insertions(+), 212 deletions(-)

diff --git a/src/exchange/taler-exchange-aggregator.c 
b/src/exchange/taler-exchange-aggregator.c
index b67d002e9..3751ed47f 100644
--- a/src/exchange/taler-exchange-aggregator.c
+++ b/src/exchange/taler-exchange-aggregator.c
@@ -101,11 +101,6 @@ struct AggregationUnit
    */
   const struct TALER_EXCHANGEDB_AccountInfo *wa;
 
-  /**
-   * Handle for asynchronously running AML program.
-   */
-  struct TALER_KYCLOGIC_AmlProgramRunnerHandle *amlh;
-
   /**
    * Shard this aggregation unit is part of.
    */
@@ -268,13 +263,6 @@ static void
 cleanup_au (struct AggregationUnit *au)
 {
   GNUNET_assert (NULL != au);
-  if (NULL != au->amlh)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Aborting AML program during aggregation cleanup\n");
-    TALER_KYCLOGIC_run_aml_program_cancel (au->amlh);
-    au->amlh = NULL;
-  }
   if (NULL != au->ru)
   {
     GNUNET_break (0);
diff --git a/src/exchange/taler-exchange-httpd.c 
b/src/exchange/taler-exchange-httpd.c
index e269b0da9..b2e069035 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -2196,7 +2196,9 @@ exchange_serve_process_config (const char *cfg_fn)
       TALER_KYCLOGIC_kyc_init (TEH_cfg,
                                cfg_fn))
   {
-    GNUNET_break (0);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to load configuration `%s'. Exiting.\n",
+                cfg_fn);
     return GNUNET_SYSERR;
   }
   TEH_hard_limits
diff --git a/src/exchange/taler-exchange-httpd_common_kyc.c 
b/src/exchange/taler-exchange-httpd_common_kyc.c
index 3fba4192f..ab42ad01e 100644
--- a/src/exchange/taler-exchange-httpd_common_kyc.c
+++ b/src/exchange/taler-exchange-httpd_common_kyc.c
@@ -347,37 +347,6 @@ TEH_kyc_store_attributes (
 }
 
 
-/**
- * Task run when an AML program takes too long and runs into a
- * timeout. Kills the AML program and reports an error.
- *
- * @param cls a `struct TEH_KycMeasureRunContext *`
- */
-static void
-kyc_aml_timeout (void *cls)
-{
-  struct TEH_KycMeasureRunContext *kat = cls;
-  const char *prog_name
-    = TALER_KYCLOGIC_run_aml_program_get_name (kat->kyc_aml);
-  struct TALER_KYCLOGIC_AmlProgramResult apr = {
-    .status = TALER_KYCLOGIC_AMLR_FAILURE,
-    .details.failure.fallback_measure
-      = TALER_KYCLOGIC_get_aml_program_fallback (prog_name),
-    .details.failure.error_message = prog_name,
-    .details.failure.ec = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT
-  };
-
-  kat->async_task = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "AML program `%s' exceeded maximum runtime. Aborting it.\n",
-              prog_name);
-  TALER_KYCLOGIC_run_aml_program_cancel (kat->kyc_aml);
-  kat->kyc_aml = NULL;
-  kyc_aml_finished (kat,
-                    &apr);
-}
-
-
 struct TEH_KycMeasureRunContext *
 TEH_kyc_run_measure_for_attributes (
   const struct GNUNET_AsyncScopeId *scope,
@@ -421,11 +390,6 @@ TEH_kyc_run_measure_for_attributes (
       .attribute_key = &TEH_attribute_key
     };
 
-    GNUNET_assert (NULL == kat->async_task);
-    kat->async_task
-      = GNUNET_SCHEDULER_add_delayed (TEH_aml_program_timeout,
-                                      &kyc_aml_timeout,
-                                      kat);
     kat->kyc_aml
       = TALER_KYCLOGIC_run_aml_program (
           kat->jmeasures,
@@ -438,6 +402,7 @@ TEH_kyc_run_measure_for_attributes (
           &hbc,
           &TALER_EXCHANGEDB_kyc_history_builder,
           &hbc,
+          TEH_aml_program_timeout,
           &kyc_aml_finished,
           kat);
   }
@@ -556,11 +521,6 @@ TEH_kyc_run_measure_directly (
       .attribute_key = &TEH_attribute_key
     };
 
-    GNUNET_assert (NULL == kat->async_task);
-    kat->async_task
-      = GNUNET_SCHEDULER_add_delayed (TEH_aml_program_timeout,
-                                      &kyc_aml_timeout,
-                                      kat);
     kat->kyc_aml
       = TALER_KYCLOGIC_run_aml_program3 (
           instant_ms,
@@ -572,6 +532,7 @@ TEH_kyc_run_measure_directly (
           &hbc,
           &TALER_EXCHANGEDB_kyc_history_builder,
           &hbc,
+          TEH_aml_program_timeout,
           &kyc_aml_finished,
           kat);
   }
@@ -784,6 +745,7 @@ TEH_kyc_fallback (
           &hbc,
           &TALER_EXCHANGEDB_kyc_history_builder,
           &hbc,
+          TEH_aml_program_timeout,
           &handle_aml_fallback_result,
           fb);
     if (NULL == fb->aprh)
diff --git a/src/exchange/taler-exchange-httpd_withdraw.c 
b/src/exchange/taler-exchange-httpd_withdraw.c
index e316223fd..ecaa49b04 100644
--- a/src/exchange/taler-exchange-httpd_withdraw.c
+++ b/src/exchange/taler-exchange-httpd_withdraw.c
@@ -827,7 +827,7 @@ run_transaction (
  * @param wc context for request processing, with @e withdraw_type set to 
WITHDRAW_TYPE_BATCH
  * @return GNUNET_OK on success
  */
-enum GNUNET_GenericReturnValue
+static enum GNUNET_GenericReturnValue
 batch_withdraw_prepare_transaction (struct WithdrawContext *wc)
 {
   const struct TEH_RequestContext *rc = wc->rc;
@@ -880,7 +880,7 @@ batch_withdraw_prepare_transaction (struct WithdrawContext 
*wc)
  * @param wc The context for the current withdraw request, with @e 
withdraw_type set to WITHDRAW_TYPE_AGE
  * @return GNUNET_OK on success
  */
-enum GNUNET_GenericReturnValue
+static enum GNUNET_GenericReturnValue
 age_withdraw_prepare_transaction (
   struct WithdrawContext *wc)
 {
@@ -2056,9 +2056,8 @@ age_withdraw_new_request (
  * @param root uploaded JSON data
  * @param reserve_pub public key of the reserve
  * @return MHD result code
-  */
-MHD_RESULT
-static
+ */
+static MHD_RESULT
 handler_withdraw (
   struct TEH_RequestContext *rc,
   enum WithdrawType typ,
diff --git a/src/exchangedb/exchangedb_aml.c b/src/exchangedb/exchangedb_aml.c
index 98e879b34..0444e2217 100644
--- a/src/exchangedb/exchangedb_aml.c
+++ b/src/exchangedb/exchangedb_aml.c
@@ -235,8 +235,6 @@ aml_result_callback (
   enum GNUNET_GenericReturnValue res;
 
   ru->amlh = NULL;
-  GNUNET_SCHEDULER_cancel (ru->t);
-  ru->t = NULL;
   res = ru->plugin->start (ru->plugin->cls,
                            "aml-persist-aml-program-result");
   if (GNUNET_OK != res)
@@ -313,94 +311,6 @@ aml_result_callback (
 }
 
 
-/**
- * Task run when an AML program takes too long and runs into a
- * timeout. Kills the AML program and reports an error.
- *
- * @param cls a `struct TEH_KycMeasureRunContext *`
- */
-static void
-aml_program_timeout (void *cls)
-{
-  struct TALER_EXCHANGEDB_RuleUpdater *ru = cls;
-  struct TALER_KYCLOGIC_AmlProgramResult apr = {
-    .status = TALER_KYCLOGIC_AMLR_FAILURE,
-    .details.failure.fallback_measure
-      = TALER_KYCLOGIC_get_aml_program_fallback (ru->aml_program_name),
-    .details.failure.error_message = ru->aml_program_name,
-    .details.failure.ec = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT
-  };
-  enum GNUNET_GenericReturnValue res;
-  enum GNUNET_DB_QueryStatus qs;
-
-  ru->t = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "AML program hit timeout!\n");
-  TALER_KYCLOGIC_run_aml_program_cancel (ru->amlh);
-  ru->amlh = NULL;
-  GNUNET_assert (NULL != apr.details.failure.fallback_measure);
-  res = ru->plugin->start (ru->plugin->cls,
-                           "aml-persist-aml-program-timeout");
-  if (GNUNET_OK != res)
-  {
-    GNUNET_break (0);
-    fail_update (ru,
-                 TALER_EC_GENERIC_DB_START_FAILED,
-                 "aml-persist-aml-program-timeout");
-    return;
-  }
-  /* Update database update based on result */
-  qs = TALER_EXCHANGEDB_persist_aml_program_result (
-    ru->plugin,
-    0LLU, /* 0: no existing legitimization process, creates new row */
-    &ru->account,
-    &apr);
-  switch (qs)
-  {
-  case GNUNET_DB_STATUS_HARD_ERROR:
-    GNUNET_break (0);
-    fail_update (ru,
-                 TALER_EC_GENERIC_DB_STORE_FAILED,
-                 "persist_aml_program_timeout");
-    return;
-  case GNUNET_DB_STATUS_SOFT_ERROR:
-    /* Bad, couldn't persist AML result. Try again... */
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Serialization issue persisting timeout of AML program. 
Restarting.\n");
-    fail_update (ru,
-                 TALER_EC_GENERIC_DB_SOFT_FAILURE,
-                 "persist_aml_program_timeout");
-    return;
-  case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
-    /* Strange, but let's just continue */
-    break;
-  case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
-    /* normal case */
-    break;
-  }
-  {
-    const char *fmn = apr.details.failure.fallback_measure;
-    const struct TALER_KYCLOGIC_Measure *m;
-
-    m = TALER_KYCLOGIC_get_measure (ru->lrs,
-                                    fmn);
-    if (NULL == m)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Fallback measure `%s' does not exist (anymore?).\n",
-                  fmn);
-      TALER_KYCLOGIC_rules_free (ru->lrs);
-      ru->lrs = NULL;
-      return_result (ru);
-      return;
-    }
-    run_measure (ru,
-                 m);
-    return;
-  }
-}
-
-
 /**
  * Entrypoint that fetches the latest rules from the database
  * and starts processing them. Called without an open database
@@ -458,7 +368,7 @@ run_measure (struct TALER_EXCHANGEDB_RuleUpdater *ru,
   }
   if ( (NULL == m->check_name) ||
        (0 ==
-        strcasecmp ("skip",
+        strcasecmp ("SKIP",
                     m->check_name)) )
   {
     struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = {
@@ -513,10 +423,6 @@ run_measure (struct TALER_EXCHANGEDB_RuleUpdater *ru,
                 "Check is of type 'skip', running AML program %s.\n",
                 m->prog_name);
     GNUNET_assert (NULL == ru->t);
-    ru->t = GNUNET_SCHEDULER_add_delayed (
-      ru->plugin->max_aml_program_runtime,
-      &aml_program_timeout,
-      ru);
     ru->amlh = TALER_KYCLOGIC_run_aml_program3 (
       m,
       &TALER_EXCHANGEDB_current_attributes_builder,
@@ -527,6 +433,7 @@ run_measure (struct TALER_EXCHANGEDB_RuleUpdater *ru,
       &hbc,
       &TALER_EXCHANGEDB_kyc_history_builder,
       &hbc,
+      ru->plugin->max_aml_program_runtime,
       &aml_result_callback,
       ru);
     return;
diff --git a/src/include/taler_kyclogic_lib.h b/src/include/taler_kyclogic_lib.h
index 9cd6367ab..65babebfb 100644
--- a/src/include/taler_kyclogic_lib.h
+++ b/src/include/taler_kyclogic_lib.h
@@ -1001,6 +1001,11 @@ typedef json_t *
  * @param aml_history_cb_cls closure for @a aml_history_cb
  * @param kyc_history_cb callback to get the KYC history of the account
  * @param kyc_history_cb_cls closure for @a aml_history_cb
+ * @param timeout timeout for running the AML program;
+ *  terminates the AML program and runs the fallback measure immediately
+ *  once the timeout is reached; in this case, the result from the
+ *  fallback measure is returned; the fallback measure is also granted
+ *  the same amount of time (so after 2x @a timeout we will call @a aprc)
  * @param aprc function to call with the result
  * @param aprc_cls closure for @a aprc
  * @return NULL if @a jmeasures is invalid for the
@@ -1018,6 +1023,7 @@ TALER_KYCLOGIC_run_aml_program (
   void *aml_history_cb_cls,
   TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
   void *kyc_history_cb_cls,
+  struct GNUNET_TIME_Relative timeout,
   TALER_KYCLOGIC_AmlProgramResultCallback aprc,
   void *aprc_cls);
 
@@ -1035,6 +1041,11 @@ TALER_KYCLOGIC_run_aml_program (
  * @param aml_history_cb_cls closure for @a aml_history_cb
  * @param kyc_history_cb callback to get the KYC history of the account
  * @param kyc_history_cb_cls closure for @a aml_history_cb
+ * @param timeout timeout for running the AML program;
+ *  terminates the AML program and runs the fallback measure immediately
+ *  once the timeout is reached; in this case, the result from the
+ *  fallback measure is returned; the fallback measure is also granted
+ *  the same amount of time (so after 2x @a timeout we will call @a aprc)
  * @param aprc function to call with the result
  * @param aprc_cls closure for @a aprc
  * @return NULL if @a jmeasures is invalid for the
@@ -1052,6 +1063,7 @@ TALER_KYCLOGIC_run_aml_program2 (
   void *aml_history_cb_cls,
   TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
   void *kyc_history_cb_cls,
+  struct GNUNET_TIME_Relative timeout,
   TALER_KYCLOGIC_AmlProgramResultCallback aprc,
   void *aprc_cls);
 
@@ -1070,6 +1082,11 @@ TALER_KYCLOGIC_run_aml_program2 (
  * @param aml_history_cb_cls closure for @a aml_history_cb
  * @param kyc_history_cb callback to get the KYC history of the account
  * @param kyc_history_cb_cls closure for @a aml_history_cb
+ * @param timeout timeout for running the AML program;
+ *  terminates the AML program and runs the fallback measure immediately
+ *  once the timeout is reached; in this case, the result from the
+ *  fallback measure is returned; the fallback measure is also granted
+ *  the same amount of time (so after 2x @a timeout we will call @a aprc)
  * @param aprc function to call with the result
  * @param aprc_cls closure for @a aprc
  * @return NULL if @a jmeasures is invalid for the
@@ -1086,6 +1103,7 @@ TALER_KYCLOGIC_run_aml_program3 (
   void *aml_history_cb_cls,
   TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
   void *kyc_history_cb_cls,
+  struct GNUNET_TIME_Relative timeout,
   TALER_KYCLOGIC_AmlProgramResultCallback aprc,
   void *aprc_cls);
 
diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c
index cfada8a23..15275d4bb 100644
--- a/src/kyclogic/kyclogic_api.c
+++ b/src/kyclogic/kyclogic_api.c
@@ -406,7 +406,7 @@ find_program (const char *program_name)
                          program->program_name))
       return program;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
               "AML program `%s' unknown\n",
               program_name);
   return NULL;
@@ -451,18 +451,6 @@ check_measure (const struct TALER_KYCLOGIC_Measure 
*measure)
   const struct TALER_KYCLOGIC_KycCheck *check;
   const struct TALER_KYCLOGIC_AmlProgram *program;
 
-  if (0 == strcasecmp (measure->check_name,
-                       "SKIP"))
-    return true;
-  check = find_check (measure->check_name);
-  if (NULL == check)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Unknown check `%s' used in measure `%s'\n",
-                measure->check_name,
-                measure->measure_name);
-    return false;
-  }
   program = find_program (measure->prog_name);
   if (NULL == program)
   {
@@ -472,22 +460,6 @@ check_measure (const struct TALER_KYCLOGIC_Measure 
*measure)
                 measure->measure_name);
     return false;
   }
-  for (unsigned int j = 0; j<check->num_requires; j++)
-  {
-    const char *required_input = check->requires[j];
-
-    if (NULL ==
-        json_object_get (measure->context,
-                         required_input))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Measure `%s' lacks required context `%s' for check `%s'\n",
-                  measure->measure_name,
-                  required_input,
-                  check->check_name);
-      return false;
-    }
-  }
   for (unsigned int j = 0; j<program->num_required_contexts; j++)
   {
     const char *required_context = program->required_contexts[j];
@@ -504,6 +476,28 @@ check_measure (const struct TALER_KYCLOGIC_Measure 
*measure)
       return false;
     }
   }
+  if (0 == strcasecmp (measure->check_name,
+                       "SKIP"))
+  {
+    if (0 != program->num_required_attributes)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "AML program `%s' of measure `%s' has required attributes, 
but check is of type `SKIP' and thus cannot provide any!\n",
+                  program->program_name,
+                  measure->measure_name);
+      return false;
+    }
+    return true;
+  }
+  check = find_check (measure->check_name);
+  if (NULL == check)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unknown check `%s' used in measure `%s'\n",
+                measure->check_name,
+                measure->measure_name);
+    return false;
+  }
   for (unsigned int j = 0; j<program->num_required_attributes; j++)
   {
     const char *required_attribute = program->required_attributes[j];
@@ -529,6 +523,22 @@ check_measure (const struct TALER_KYCLOGIC_Measure 
*measure)
       return false;
     }
   }
+  for (unsigned int j = 0; j<check->num_requires; j++)
+  {
+    const char *required_input = check->requires[j];
+
+    if (NULL ==
+        json_object_get (measure->context,
+                         required_input))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Measure `%s' lacks required context `%s' for check `%s'\n",
+                  measure->measure_name,
+                  required_input,
+                  check->check_name);
+      return false;
+    }
+  }
   return true;
 }
 
@@ -1274,7 +1284,8 @@ TALER_KYCLOGIC_get_instant_measure (
     {
       continue;
     }
-    if (0 == strcasecmp ("SKIP", ms->check_name))
+    if (0 == strcasecmp ("SKIP",
+                         ms->check_name))
     {
       ret = ms;
       goto done;
@@ -2445,7 +2456,13 @@ add_program (const struct GNUNET_CONFIGURATION_Handle 
*cfg,
                                              "FALLBACK",
                                              &fallback))
   {
-    /* FIXME: Allow NULL to fall back to default rules? */
+    /* We do *not* allow NULL to fall back to default rules because fallbacks
+       are used when there is actually a serious error and thus some action
+       (usually an investigation) is always in order, and that's basically
+       never the default. And as fallbacks should be rare, we really insist on
+       them at least being explicitly configured. Otherwise these errors may
+       go undetected simply because someone forgot to configure a fallback and
+       then nothing happens. */
     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
                                section,
                                "FALLBACK",
@@ -2846,14 +2863,26 @@ TALER_KYCLOGIC_kyc_init (
                                       jkyc_rules)
         );
 
+  for (unsigned int i=0; i<default_rules.num_custom_measures; i++)
+  {
+    const struct TALER_KYCLOGIC_Measure *measure
+      = &default_rules.custom_measures[i];
+
+    if (! check_measure (measure))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Configuration of AML measures incorrect. Exiting.\n");
+      return GNUNET_SYSERR;
+    }
+  }
+
   for (unsigned int i=0; i<num_aml_programs; i++)
   {
     const struct TALER_KYCLOGIC_AmlProgram *program
       = aml_programs[i];
     const struct TALER_KYCLOGIC_Measure *m;
+    const struct TALER_KYCLOGIC_AmlProgram *fprogram;
 
-    if (NULL == program->fallback)
-      continue; /* default */
     m = find_measure (&default_rules,
                       program->fallback);
     if (NULL == m)
@@ -2864,41 +2893,69 @@ TALER_KYCLOGIC_kyc_init (
                   program->program_name);
       return GNUNET_SYSERR;
     }
+    if (0 != strcasecmp (m->check_name,
+                         "SKIP"))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Fallback measure `%s' used in AML program `%s' has a check 
`%s' but fallbacks must have a check of type 'SKIP'\n",
+                  program->fallback,
+                  program->program_name,
+                  m->check_name);
+      return GNUNET_SYSERR;
+    }
+    fprogram = find_program (m->prog_name);
+    GNUNET_assert (NULL != fprogram);
+    if (API_NONE != fprogram->input_mask)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Fallback program %s of fallback measure `%s' used in AML 
program `%s' has required inputs, but fallback measures must not require any 
inputs\n",
+                  m->prog_name,
+                  program->program_name,
+                  m->check_name);
+      return GNUNET_SYSERR;
+    }
   }
 
   for (unsigned int i = 0; i<num_kyc_checks; i++)
   {
     struct TALER_KYCLOGIC_KycCheck *kyc_check
       = kyc_checks[i];
+    const struct TALER_KYCLOGIC_Measure *measure;
+    const struct TALER_KYCLOGIC_AmlProgram *fprogram;
 
-    if (NULL != kyc_check->fallback)
+    measure = find_measure (&default_rules,
+                            kyc_check->fallback);
+    if (NULL == measure)
     {
-      const struct TALER_KYCLOGIC_Measure *measure;
-
-      measure = find_measure (&default_rules,
-                              kyc_check->fallback);
-      if (NULL == measure)
-      {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    "Unknown fallback measure `%s' used in check `%s'\n",
-                    kyc_check->fallback,
-                    kyc_check->check_name);
-        return GNUNET_SYSERR;
-      }
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Unknown fallback measure `%s' used in check `%s'\n",
+                  kyc_check->fallback,
+                  kyc_check->check_name);
+      return GNUNET_SYSERR;
     }
-  }
-
-  for (unsigned int i=0; i<default_rules.num_custom_measures; i++)
-  {
-    const struct TALER_KYCLOGIC_Measure *measure
-      = &default_rules.custom_measures[i];
-
-    if (! check_measure (measure))
+    if (0 != strcasecmp (measure->check_name,
+                         "SKIP"))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Fallback measure `%s' used in KYC check `%s' has a check 
`%s' but fallbacks must have a check of type 'SKIP'\n",
+                  kyc_check->fallback,
+                  kyc_check->check_name,
+                  measure->check_name);
+      return GNUNET_SYSERR;
+    }
+    fprogram = find_program (measure->prog_name);
+    GNUNET_assert (NULL != fprogram);
+    if (API_NONE != fprogram->input_mask)
     {
-      GNUNET_break_op (0);
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "AML program `%s' used fallback measure `%s' of KYC check 
`%s' has required inputs, but fallback measures must not require any inputs\n",
+                  measure->prog_name,
+                  kyc_check->fallback,
+                  kyc_check->check_name);
       return GNUNET_SYSERR;
     }
   }
+
   return GNUNET_OK;
 }
 
@@ -3816,8 +3873,14 @@ struct TALER_KYCLOGIC_AmlProgramRunnerHandle
    */
   struct TALER_KYCLOGIC_AmlProgramResult apr;
 
+  /**
+   * How long do we allow the AML program to run?
+   */
+  struct GNUNET_TIME_Relative timeout;
+
 };
 
+
 /**
  * Function that that receives a JSON @a result from
  * the AML program.
@@ -3841,6 +3904,11 @@ handle_aml_output (
   const char **evs = NULL;
 
   aprh->proc = NULL;
+  if (NULL != aprh->async_cb)
+  {
+    GNUNET_SCHEDULER_cancel (aprh->async_cb);
+    aprh->async_cb = NULL;
+  }
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "AML program output is:\n");
   json_dumpf (result,
@@ -3971,8 +4039,7 @@ ready:
 
 
 /**
- * Helper function to asynchronously return
- * the result.
+ * Helper function to asynchronously return the result.
  *
  * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return 
results for
  */
@@ -3988,6 +4055,140 @@ async_return_task (void *cls)
 }
 
 
+/**
+ * Helper function called on timeout on the fallback measure.
+ *
+ * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return 
results for
+ */
+static void
+handle_aml_timeout2 (void *cls)
+{
+  struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls;
+  struct TALER_KYCLOGIC_AmlProgramResult *apr = &aprh->apr;
+  const char *fallback_measure = aprh->program->fallback;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "Fallback measure %s ran into timeout (!)\n",
+              aprh->program->program_name);
+  if (NULL != aprh->proc)
+  {
+    TALER_JSON_external_conversion_stop (aprh->proc);
+    aprh->proc = NULL;
+  }
+  apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
+  apr->details.failure.fallback_measure
+    = fallback_measure;
+  apr->details.failure.error_message
+    = aprh->program->program_name;
+  apr->details.failure.ec
+    = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT;
+  async_return_task (aprh);
+}
+
+
+/**
+ * Helper function called on timeout of an AML program.
+ * Runs the fallback measure.
+ *
+ * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return 
results for
+ */
+static void
+handle_aml_timeout (void *cls)
+{
+  struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls;
+  struct TALER_KYCLOGIC_AmlProgramResult *apr = &aprh->apr;
+  const char *fallback_measure = aprh->program->fallback;
+  const struct TALER_KYCLOGIC_Measure *m;
+  const struct TALER_KYCLOGIC_AmlProgram *fprogram;
+
+  aprh->async_cb = NULL;
+  GNUNET_assert (NULL != fallback_measure);
+  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+              "AML program %s ran into timeout\n",
+              aprh->program->program_name);
+  if (NULL != aprh->proc)
+  {
+    TALER_JSON_external_conversion_stop (aprh->proc);
+    aprh->proc = NULL;
+  }
+
+  m = TALER_KYCLOGIC_get_measure (&default_rules,
+                                  fallback_measure);
+  /* Fallback program could have "disappeared" due to configuration change,
+     as we do not check all rule sets in the database when our configuration
+     is updated... */
+  if (NULL == m)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Fallback measure `%s' does not exist (anymore?).\n",
+                fallback_measure);
+    apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
+    apr->details.failure.fallback_measure
+      = fallback_measure;
+    apr->details.failure.error_message
+      = aprh->program->program_name;
+    apr->details.failure.ec
+      = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT;
+    async_return_task (aprh);
+    return;
+  }
+  /* We require fallback measures to have a 'SKIP' check */
+  GNUNET_break (0 ==
+                strcasecmp (m->check_name,
+                            "SKIP"));
+  fprogram = find_program (m->prog_name);
+  /* Program associated with an original measure must exist */
+  GNUNET_assert (NULL != fprogram);
+  if (API_NONE != fprogram->input_mask)
+  {
+    /* We might not have recognized the fallback measure as such
+       because it was not used as such in the plain configuration,
+       and legitimization rule sets might have referred to an older
+       configuration. So this should be super-rare but possible. */
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Program `%s' used in fallback measure `%s' requires inputs 
and is thus unsuitable as a fallback measure!\n",
+                m->prog_name,
+                fallback_measure);
+    apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
+    apr->details.failure.fallback_measure
+      = fallback_measure;
+    apr->details.failure.error_message
+      = aprh->program->program_name;
+    apr->details.failure.ec
+      = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT;
+    async_return_task (aprh);
+    return;
+  }
+  {
+    /* Run fallback AML program */
+    json_t *input = json_object ();
+    const char *extra_args[] = {
+      "-c",
+      cfg_filename,
+      NULL,
+    };
+    char **args;
+
+    args = split_words (fprogram->command,
+                        extra_args);
+    aprh->proc = TALER_JSON_external_conversion_start (
+      input,
+      &handle_aml_output,
+      aprh,
+      args[0],
+      (const char **) args);
+    destroy_words (args);
+    json_decref (input);
+  }
+  aprh->async_cb = GNUNET_SCHEDULER_add_delayed (aprh->timeout,
+                                                 &handle_aml_timeout2,
+                                                 aprh);
+  aprh->aprc (aprh->aprc_cls,
+              apr);
+  TALER_KYCLOGIC_run_aml_program_cancel (aprh);
+}
+
+
 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *
 TALER_KYCLOGIC_run_aml_program (
   const json_t *jmeasures,
@@ -4000,6 +4201,7 @@ TALER_KYCLOGIC_run_aml_program (
   void *aml_history_cb_cls,
   TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
   void *kyc_history_cb_cls,
+  struct GNUNET_TIME_Relative timeout,
   TALER_KYCLOGIC_AmlProgramResultCallback aprc,
   void *aprc_cls)
 {
@@ -4031,6 +4233,7 @@ TALER_KYCLOGIC_run_aml_program (
                                           aml_history_cb_cls,
                                           kyc_history_cb,
                                           kyc_history_cb_cls,
+                                          timeout,
                                           aprc,
                                           aprc_cls);
 }
@@ -4048,6 +4251,7 @@ TALER_KYCLOGIC_run_aml_program2 (
   void *aml_history_cb_cls,
   TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
   void *kyc_history_cb_cls,
+  struct GNUNET_TIME_Relative timeout,
   TALER_KYCLOGIC_AmlProgramResultCallback aprc,
   void *aprc_cls)
 {
@@ -4210,6 +4414,10 @@ TALER_KYCLOGIC_run_aml_program2 (
     destroy_words (args);
     json_decref (input);
   }
+  aprh->timeout = timeout;
+  aprh->async_cb = GNUNET_SCHEDULER_add_delayed (timeout,
+                                                 &handle_aml_timeout,
+                                                 aprh);
   return aprh;
 }
 
@@ -4225,6 +4433,7 @@ TALER_KYCLOGIC_run_aml_program3 (
   void *aml_history_cb_cls,
   TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
   void *kyc_history_cb_cls,
+  struct GNUNET_TIME_Relative timeout,
   TALER_KYCLOGIC_AmlProgramResultCallback aprc,
   void *aprc_cls)
 {
@@ -4239,6 +4448,7 @@ TALER_KYCLOGIC_run_aml_program3 (
     aml_history_cb_cls,
     kyc_history_cb,
     kyc_history_cb_cls,
+    timeout,
     aprc,
     aprc_cls);
 }
diff --git a/src/testing/test_exchange_api_age_restriction.conf 
b/src/testing/test_exchange_api_age_restriction.conf
index 9ce2acbb3..cd3508d60 100644
--- a/src/testing/test_exchange_api_age_restriction.conf
+++ b/src/testing/test_exchange_api_age_restriction.conf
@@ -165,6 +165,11 @@ PROGRAM = oauth-output-check
 # Context to provide for check and program; empty.
 CONTEXT = {}
 
+[aml-program-freeze]
+DESCRIPTION = "Freeze the account"
+COMMAND = taler-exchange-helper-measure-freeze
+FALLBACK = manual-freeze
+
 # This is a base-measure that is being triggered
 # whenever something goes wrong. We freeze the
 # account and ask AML staff to investigate.
@@ -172,7 +177,7 @@ CONTEXT = {}
 CHECK_NAME = skip
 # AML program that freezes the account and flags
 # it for investigation.
-PROGRAM = taler-exchange-helper-measure-freeze
+PROGRAM = freeze
 # Context to provide for check and program; empty.
 CONTEXT = {}
 

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]