exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

taler-exchange-httpd_common_kyc.c (47138B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2023, 2024 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file taler-exchange-httpd_common_kyc.c
     18  * @brief shared logic for finishing a KYC process
     19  * @author Christian Grothoff
     20  */
     21 #include "taler-exchange-httpd.h"
     22 #include "exchange-database/do_trigger_kyc_rule_for_account.h"
     23 #include "taler-exchange-httpd_common_kyc.h"
     24 #include "taler/taler_attributes.h"
     25 #include "taler/taler_error_codes.h"
     26 #include "taler/taler_kyclogic_lib.h"
     27 #include "exchangedb_lib.h"
     28 #include <gnunet/gnunet_common.h>
     29 #include "exchange-database/commit.h"
     30 #include "exchange-database/get_kyc_rules.h"
     31 #include "exchange-database/insert_aml_decision.h"
     32 #include "exchange-database/insert_kyc_failure.h"
     33 #include "exchange-database/insert_legitimization_process.h"
     34 #include "exchange-database/get_active_legitimization.h"
     35 #include "exchange-database/do_insert_kyc_attributes.h"
     36 #include "exchange-database/preflight.h"
     37 #include "exchange-database/rollback.h"
     38 #include "exchange-database/start.h"
     39 struct TEH_LegitimizationCheckHandle;
     40 #define TALER_EXCHANGEDB_CURRENT_RULES_RESULT_CLOSURE \
     41         struct TEH_LegitimizationCheckHandle
     42 #include "exchange-database/begin_rule_update.h"
     43 #include "exchange-database/account_history.h"
     44 #include "exchange-database/do_persist_aml_program_result.h"
     45 
     46 
     47 /**
     48  * How often do we allow a legitimization rule to
     49  * automatically trigger the next rule before bailing
     50  * out?
     51  */
     52 #define MAX_LEGI_LOOPS 5
     53 
     54 /**
     55  * Enable additional sanity-checks for debugging?
     56  */
     57 #define EXTRA_CHECK 0
     58 
     59 /**
     60  * Enable extra logging that may include sensitive data?
     61  */
     62 #define DEBUG 1
     63 
     64 
     65 struct TEH_KycMeasureRunContext
     66 {
     67 
     68   /**
     69    * Our logging scope.
     70    */
     71   struct GNUNET_AsyncScopeId scope;
     72 
     73   /**
     74    * account the operation is about
     75    */
     76   struct TALER_NormalizedPaytoHashP account_id;
     77 
     78   /**
     79    * legitimization process the KYC data is about
     80    */
     81   uint64_t process_row;
     82 
     83   /**
     84    * function to call with the result
     85    */
     86   TEH_KycMeasureRunContextCallback cb;
     87 
     88   /**
     89    * closure for @e cb
     90    */
     91   void *cb_cls;
     92 
     93   /**
     94    * Handle to fallback processing.
     95    */
     96   struct TEH_KycAmlFallback *fb;
     97 
     98   /**
     99    * Name of the fallback @e fb is running (or NULL).
    100    */
    101   char *fallback_name;
    102 
    103   /**
    104    * Measures this KYC process is responding to.
    105    */
    106   json_t *jmeasures;
    107 
    108   /**
    109    * Handle to an external process that evaluates the
    110    * need to run AML on the account.
    111    */
    112   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *kyc_aml;
    113 
    114   /**
    115    * Task scheduled to return a result asynchronously.
    116    */
    117   struct GNUNET_SCHEDULER_Task *async_task;
    118 
    119   /**
    120    * KYC measure the client is (trying to) satisfy.
    121    */
    122   uint32_t measure_index;
    123 
    124   /**
    125    * True if @e account_id is for a wallet.
    126    */
    127   bool is_wallet;
    128 };
    129 
    130 
    131 /**
    132  * Function called with the result of activating a
    133  * fallback measure.
    134  *
    135  * @param cls a `struct TEH_KycMeasureRunContext *`
    136  * @param fallback_ok true if the fallback was activated
    137  *    successfully
    138  * @param requirement_row row of
    139  *    new KYC requirement that was created, 0 for none
    140  */
    141 static void
    142 fallback_result_cb (void *cls,
    143                     bool fallback_ok,
    144                     uint64_t requirement_row)
    145 {
    146   struct TEH_KycMeasureRunContext *kat = cls;
    147   struct GNUNET_AsyncScopeSave old_scope;
    148 
    149   kat->fb = NULL;
    150   (void) requirement_row;
    151   GNUNET_async_scope_enter (&kat->scope,
    152                             &old_scope);
    153   if (fallback_ok)
    154   {
    155     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    156                 "Fallback completed (row %llu)\n",
    157                 (unsigned long long) requirement_row);
    158     /* For the HTTP client, us running the fallback
    159        should not become a visible failure, after all
    160        the fallback should put the account back into
    161        a "correct" state (even if that is a deny-all
    162        or manual review). Hence we do not return an
    163        error here. */
    164     kat->cb (kat->cb_cls,
    165              TALER_EC_NONE,
    166              NULL);
    167   }
    168   else
    169   {
    170     GNUNET_break (0);
    171     kat->cb (kat->cb_cls,
    172              TALER_EC_EXCHANGE_GENERIC_KYC_FALLBACK_FAILED,
    173              kat->fallback_name);
    174   }
    175   TEH_kyc_run_measure_cancel (kat);
    176   GNUNET_async_scope_restore (&old_scope);
    177 }
    178 
    179 
    180 /**
    181  * Handle the AML program result @a apr for the KYC measure in @a cls.
    182  *
    183  * @param cls closure of type `struct TEH_KycMeasureRunContext *`
    184  * @param apr AML program result
    185  */
    186 static void
    187 kyc_aml_finished (
    188   void *cls,
    189   const struct TALER_KYCLOGIC_AmlProgramResult *apr)
    190 {
    191   struct TEH_KycMeasureRunContext *kat = cls;
    192   enum GNUNET_DB_QueryStatus qs;
    193   struct GNUNET_AsyncScopeSave old_scope;
    194   enum TALER_EXCHANGEDB_PersistProgramResultStatus pprs;
    195 
    196   kat->kyc_aml = NULL;
    197   if (NULL != kat->async_task)
    198   {
    199     GNUNET_SCHEDULER_cancel (kat->async_task);
    200     kat->async_task = NULL;
    201   }
    202   GNUNET_async_scope_enter (&kat->scope,
    203                             &old_scope);
    204   GNUNET_break (GNUNET_OK ==
    205                 TALER_EXCHANGEDB_preflight (TEH_pg));
    206   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    207               "AML program finished with status %d\n",
    208               (int) apr->status);
    209   qs = TALER_EXCHANGEDB_do_persist_aml_program_result (
    210     TEH_pg,
    211     kat->process_row,
    212     &kat->account_id,
    213     apr,
    214     &pprs);
    215   switch (qs)
    216   {
    217   case GNUNET_DB_STATUS_HARD_ERROR:
    218   case GNUNET_DB_STATUS_SOFT_ERROR:
    219   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    220     GNUNET_break (0);
    221     kat->cb (kat->cb_cls,
    222              TALER_EC_GENERIC_DB_STORE_FAILED,
    223              "persist_aml_program_result");
    224     TEH_kyc_run_measure_cancel (kat);
    225     GNUNET_async_scope_restore (&old_scope);
    226     return;
    227   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    228     break;
    229   }
    230   switch (pprs)
    231   {
    232   case TALER_EXCHANGEDB_PPRS_OK:
    233     break;
    234   case TALER_EXCHANGEDB_PPRS_BAD_OUTCOME:
    235     GNUNET_break (0);
    236     kat->cb (kat->cb_cls,
    237              TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT,
    238              "persist_aml_program_result");
    239     TEH_kyc_run_measure_cancel (kat);
    240     GNUNET_async_scope_restore (&old_scope);
    241     return;
    242   }
    243   switch (apr->status)
    244   {
    245   case TALER_KYCLOGIC_AMLR_FAILURE:
    246     if (NULL == apr->details.failure.fallback_measure)
    247     {
    248       /* Not sure this can happen (fallback required?),
    249          but report AML program failure to client */
    250       GNUNET_break (0);
    251       kat->cb (kat->cb_cls,
    252                TALER_EC_EXCHANGE_KYC_AML_PROGRAM_FAILURE,
    253                NULL);
    254       break;
    255     }
    256     kat->fallback_name
    257       = GNUNET_strdup (
    258           apr->details.failure.fallback_measure);
    259     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    260                 "AML program failed, running fallback %s\n",
    261                 kat->fallback_name);
    262     kat->fb
    263       = TEH_kyc_fallback (
    264           &kat->scope,
    265           &kat->account_id,
    266           kat->is_wallet,
    267           kat->process_row,
    268           kat->fallback_name,
    269           &fallback_result_cb,
    270           kat);
    271     if (NULL == kat->fb)
    272     {
    273       GNUNET_break (0);
    274       kat->cb (kat->cb_cls,
    275                TALER_EC_EXCHANGE_GENERIC_KYC_FALLBACK_UNKNOWN,
    276                kat->fallback_name);
    277       break;
    278     }
    279     /* continued in fallback_result_cb */
    280     GNUNET_async_scope_restore (&old_scope);
    281     return;
    282   case TALER_KYCLOGIC_AMLR_SUCCESS:
    283     /* Finally, return result to main handler */
    284     kat->cb (kat->cb_cls,
    285              TALER_EC_NONE,
    286              0);
    287     break;
    288   }
    289   TEH_kyc_run_measure_cancel (kat);
    290   GNUNET_async_scope_restore (&old_scope);
    291 }
    292 
    293 
    294 void
    295 TEH_kyc_run_measure_cancel (struct TEH_KycMeasureRunContext *kat)
    296 {
    297   if (NULL != kat->kyc_aml)
    298   {
    299     TALER_KYCLOGIC_run_aml_program_cancel (kat->kyc_aml);
    300     kat->kyc_aml = NULL;
    301   }
    302   if (NULL != kat->fb)
    303   {
    304     TEH_kyc_fallback_cancel (kat->fb);
    305     kat->fb = NULL;
    306   }
    307   if (NULL != kat->async_task)
    308   {
    309     GNUNET_SCHEDULER_cancel (kat->async_task);
    310     kat->async_task = NULL;
    311   }
    312   GNUNET_free (kat->fallback_name);
    313   json_decref (kat->jmeasures);
    314   GNUNET_free (kat);
    315 }
    316 
    317 
    318 enum GNUNET_DB_QueryStatus
    319 TEH_kyc_store_attributes (
    320   uint64_t process_row,
    321   const struct TALER_NormalizedPaytoHashP *account_id,
    322   const char *provider_name,
    323   const char *provider_user_id,
    324   const char *provider_legitimization_id,
    325   struct GNUNET_TIME_Absolute expiration,
    326   const json_t *new_attributes)
    327 {
    328   enum GNUNET_DB_QueryStatus qs;
    329   unsigned int birthday = 0;
    330   size_t eas = 0;
    331   void *ea = NULL;
    332   const char *form_id = NULL;
    333 
    334   if (TEH_age_restriction_enabled)
    335   {
    336     const char *birthdate;
    337 
    338     birthdate = json_string_value (
    339       json_object_get (new_attributes,
    340                        TALER_ATTRIBUTE_BIRTHDATE));
    341     if (NULL != birthdate)
    342     {
    343       enum GNUNET_GenericReturnValue ret;
    344 
    345       ret = TALER_parse_coarse_date (birthdate,
    346                                      &TEH_age_restriction_mask,
    347                                      &birthday);
    348 
    349       if (GNUNET_OK != ret)
    350       {
    351         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    352                     "Failed to parse birthdate `%s' from KYC attributes of %s\n",
    353                     birthdate,
    354                     provider_name);
    355       }
    356     }
    357   }
    358 
    359   if (NULL != new_attributes)
    360   {
    361     form_id = json_string_value (json_object_get (new_attributes,
    362                                                   "FORM_ID"));
    363     if (NULL == form_id)
    364     {
    365       /* invalid input, FORM_ID is mandatory, caller is bad */
    366       GNUNET_break (0);
    367       return GNUNET_DB_STATUS_HARD_ERROR;
    368     }
    369     TALER_CRYPTO_kyc_attributes_encrypt (&TEH_attribute_key,
    370                                          new_attributes,
    371                                          &ea,
    372                                          &eas);
    373   }
    374   qs = TALER_EXCHANGEDB_do_insert_kyc_attributes (
    375     TEH_pg,
    376     process_row,
    377     account_id,
    378     provider_name,
    379     provider_user_id,
    380     provider_legitimization_id,
    381     birthday,
    382     expiration,
    383     form_id,
    384     eas,
    385     ea);
    386   GNUNET_free (ea);
    387   switch (qs)
    388   {
    389   case GNUNET_DB_STATUS_HARD_ERROR:
    390     GNUNET_break (0);
    391     break;
    392   case GNUNET_DB_STATUS_SOFT_ERROR:
    393     GNUNET_break (0);
    394     break;
    395   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    396     GNUNET_break (0);
    397     break;
    398   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    399     break;
    400   }
    401   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    402               "Stored encrypted KYC process #%llu attributes: %d\n",
    403               (unsigned long long) process_row,
    404               qs);
    405   return qs;
    406 }
    407 
    408 
    409 struct TEH_KycMeasureRunContext *
    410 TEH_kyc_run_measure_for_attributes (
    411   const struct GNUNET_AsyncScopeId *scope,
    412   uint64_t process_row,
    413   const struct TALER_NormalizedPaytoHashP *account_id,
    414   bool is_wallet,
    415   TEH_KycMeasureRunContextCallback cb,
    416   void *cb_cls)
    417 {
    418   struct TEH_KycMeasureRunContext *kat;
    419   enum GNUNET_DB_QueryStatus qs;
    420 
    421   kat = GNUNET_new (struct TEH_KycMeasureRunContext);
    422   kat->scope = *scope;
    423   kat->process_row = process_row;
    424   kat->account_id = *account_id;
    425   kat->is_wallet = is_wallet;
    426   kat->cb = cb;
    427   kat->cb_cls = cb_cls;
    428   qs = TALER_EXCHANGEDB_get_active_legitimization (
    429     TEH_pg,
    430     process_row,
    431     &kat->measure_index,
    432     &kat->jmeasures);
    433   switch (qs)
    434   {
    435   case GNUNET_DB_STATUS_HARD_ERROR:
    436   case GNUNET_DB_STATUS_SOFT_ERROR:
    437     GNUNET_break (0);
    438     TEH_kyc_run_measure_cancel (kat);
    439     return NULL;
    440   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    441     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    442                 "No active legitimization for %llu\n",
    443                 (unsigned long long) process_row);
    444     TEH_kyc_run_measure_cancel (kat);
    445     return NULL;
    446   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    447     break;
    448   }
    449   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    450               "Running AML program on for current measures\n");
    451 #if DEBUG
    452   json_dumpf (kat->jmeasures,
    453               stderr,
    454               JSON_INDENT (2));
    455   fprintf (stderr,
    456            "\n");
    457 #endif
    458   {
    459     struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = {
    460       .account = &kat->account_id,
    461       .is_wallet = kat->is_wallet,
    462       .pg = TEH_pg,
    463       .attribute_key = &TEH_attribute_key
    464     };
    465 
    466     kat->kyc_aml
    467       = TALER_KYCLOGIC_run_aml_program (
    468           kat->jmeasures,
    469           kat->is_wallet,
    470           kat->measure_index,
    471           &TALER_EXCHANGEDB_current_attributes_builder,
    472           &hbc,
    473           &TALER_EXCHANGEDB_current_rule_builder,
    474           &hbc,
    475           &TALER_EXCHANGEDB_aml_history_builder,
    476           &hbc,
    477           &TALER_EXCHANGEDB_kyc_history_builder,
    478           &hbc,
    479           TEH_aml_program_timeout,
    480           &kyc_aml_finished,
    481           kat);
    482   }
    483   if (NULL == kat->kyc_aml)
    484   {
    485     GNUNET_break (0);
    486     TEH_kyc_run_measure_cancel (kat);
    487     return NULL;
    488   }
    489   return kat;
    490 }
    491 
    492 
    493 /**
    494  * Helper task that asynchronously calls the result
    495  * callback and then cleans up.
    496  *
    497  * @param[in] cls a `struct TEH_KycMeasureRunContext *`
    498  */
    499 static void
    500 async_return_measure_result (void *cls)
    501 {
    502   struct TEH_KycMeasureRunContext *kat = cls;
    503 
    504   kat->async_task = NULL;
    505   kat->cb (kat->cb_cls,
    506            TALER_EC_NONE,
    507            NULL);
    508   TEH_kyc_run_measure_cancel (kat);
    509 }
    510 
    511 
    512 struct TEH_KycMeasureRunContext *
    513 TEH_kyc_run_measure_directly (
    514   const struct GNUNET_AsyncScopeId *scope,
    515   const struct TALER_KYCLOGIC_Measure *instant_ms,
    516   const struct TALER_NormalizedPaytoHashP *account_id,
    517   bool is_wallet,
    518   TEH_KycMeasureRunContextCallback cb,
    519   void *cb_cls)
    520 {
    521   struct TEH_KycMeasureRunContext *kat;
    522   uint64_t legi_measure_serial_id;
    523   bool bad_kyc_auth;
    524   enum GNUNET_DB_QueryStatus qs;
    525   struct TALER_FullPayto null_account = {
    526     .full_payto = NULL
    527   };
    528 
    529   kat = GNUNET_new (struct TEH_KycMeasureRunContext);
    530   kat->jmeasures = TALER_KYCLOGIC_measure_to_jmeasures (instant_ms);
    531   kat->measure_index = 0;
    532   kat->scope = *scope;
    533   kat->account_id = *account_id;
    534   kat->is_wallet = is_wallet;
    535   kat->cb = cb;
    536   kat->cb_cls = cb_cls;
    537 
    538   GNUNET_assert (NULL != kat->jmeasures);
    539 
    540   qs = TALER_EXCHANGEDB_do_trigger_kyc_rule_for_account (
    541     TEH_pg,
    542     null_account,
    543     account_id,
    544     NULL,
    545     NULL,
    546     kat->jmeasures,
    547     0, /* no particular priority */
    548     &legi_measure_serial_id,
    549     &bad_kyc_auth);
    550   switch (qs)
    551   {
    552   case GNUNET_DB_STATUS_HARD_ERROR:
    553   case GNUNET_DB_STATUS_SOFT_ERROR:
    554     GNUNET_break (0);
    555     TEH_kyc_run_measure_cancel (kat);
    556     return NULL;
    557   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    558     GNUNET_break (0);
    559     TEH_kyc_run_measure_cancel (kat);
    560     return NULL;
    561   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    562     break;
    563   }
    564 
    565   if (0 !=
    566       strcasecmp (instant_ms->check_name,
    567                   "SKIP"))
    568   {
    569     /* Not an instant measure, it's enough to trigger it.
    570        The AMP will be run later. */
    571     kat->async_task
    572       = GNUNET_SCHEDULER_add_now (
    573           &async_return_measure_result,
    574           kat);
    575     return kat;
    576   }
    577 
    578   qs = TALER_EXCHANGEDB_insert_legitimization_process (
    579     TEH_pg,
    580     account_id,
    581     0, /* measure index */
    582     legi_measure_serial_id,
    583     "SKIP",
    584     NULL, /* provider_account_id */
    585     NULL, /* provider_legitimziation_id */
    586     &kat->process_row);
    587   if (qs < 0)
    588   {
    589     GNUNET_break (0);
    590     TEH_kyc_run_measure_cancel (kat);
    591     return NULL;
    592   }
    593   {
    594     struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = {
    595       .account = &kat->account_id,
    596       .is_wallet = kat->is_wallet,
    597       .pg = TEH_pg,
    598       .attribute_key = &TEH_attribute_key
    599     };
    600 
    601     kat->kyc_aml
    602       = TALER_KYCLOGIC_run_aml_program3 (
    603           kat->is_wallet,
    604           instant_ms,
    605           &TALER_EXCHANGEDB_current_attributes_builder,
    606           &hbc,
    607           &TALER_EXCHANGEDB_current_rule_builder,
    608           &hbc,
    609           &TALER_EXCHANGEDB_aml_history_builder,
    610           &hbc,
    611           &TALER_EXCHANGEDB_kyc_history_builder,
    612           &hbc,
    613           TEH_aml_program_timeout,
    614           &kyc_aml_finished,
    615           kat);
    616   }
    617   if (NULL == kat->kyc_aml)
    618   {
    619     GNUNET_break (0);
    620     TEH_kyc_run_measure_cancel (kat);
    621     return NULL;
    622   }
    623   return kat;
    624 }
    625 
    626 
    627 struct TEH_KycAmlFallback
    628 {
    629 
    630   /**
    631    * Our logging scope.
    632    */
    633   struct GNUNET_AsyncScopeId scope;
    634 
    635   /**
    636    * Account this is for.
    637    */
    638   struct TALER_NormalizedPaytoHashP account_id;
    639 
    640   /**
    641    * Function to call when done.
    642    */
    643   TEH_KycAmlFallbackCallback cb;
    644 
    645   /**
    646    * Closure for @e cb.
    647    */
    648   void *cb_cls;
    649 
    650   /**
    651    * Handle for asynchronously running AML program.
    652    */
    653   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh;
    654 
    655   /**
    656    * Task for asynchronously returning of the result.
    657    */
    658   struct GNUNET_SCHEDULER_Task *task;
    659 
    660   /**
    661    * New requirement row we created, 0 if none.
    662    */
    663   uint64_t requirement_row;
    664 
    665   /**
    666    * Original requirement row the fallback is for.
    667    */
    668   uint64_t orig_requirement_row;
    669 
    670   /**
    671    * True if we failed.
    672    */
    673   bool failure;
    674 
    675 };
    676 
    677 
    678 /**
    679  * Handle result from AML fallback program.
    680  *
    681  * @param cls a `struct TEH_KycAmlFallback`
    682  * @param apr AML program result to handle
    683  */
    684 static void
    685 handle_aml_fallback_result (
    686   void *cls,
    687   const struct TALER_KYCLOGIC_AmlProgramResult *apr)
    688 {
    689   struct TEH_KycAmlFallback *fb = cls;
    690   enum GNUNET_DB_QueryStatus qs;
    691   struct GNUNET_AsyncScopeSave old_scope;
    692   json_t *jmeasures = NULL;
    693   struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs = NULL;
    694 
    695   fb->aprh = NULL;
    696   GNUNET_async_scope_enter (&fb->scope,
    697                             &old_scope);
    698   if (TALER_KYCLOGIC_AMLR_SUCCESS != apr->status)
    699   {
    700     if (! TEH_kyc_failed (
    701           fb->orig_requirement_row,
    702           &fb->account_id,
    703           "FALLBACK",
    704           NULL,
    705           NULL,
    706           apr->details.failure.error_message,
    707           apr->details.failure.ec))
    708     {
    709       /* triple-bad: error during error handling of fallback */
    710       GNUNET_break (0);
    711       fb->cb (fb->cb_cls,
    712               false,
    713               0);
    714       goto cleanup;
    715     }
    716     /* Fallback not allowed on fallback */
    717     GNUNET_break (0);
    718     fb->cb (fb->cb_cls,
    719             false,
    720             0);
    721     goto cleanup;
    722   }
    723 
    724   if (NULL != apr->details.success.new_measures)
    725   {
    726     lrs = TALER_KYCLOGIC_rules_parse (apr->details.success.new_rules);
    727     GNUNET_assert (NULL != lrs);
    728     jmeasures = TALER_KYCLOGIC_get_jmeasures (
    729       lrs,
    730       apr->details.success.new_measures);
    731     GNUNET_assert (NULL != jmeasures);
    732   }
    733 
    734   {
    735     struct TALER_FullPayto null_payto_uri = { 0 };
    736     bool invalid_officer;
    737     bool unknown_account;
    738     struct GNUNET_TIME_Timestamp last_date;
    739     uint64_t legitimization_measure_serial_id;
    740     bool is_wallet;
    741 
    742     qs = TALER_EXCHANGEDB_insert_aml_decision (
    743       TEH_pg,
    744       null_payto_uri,
    745       &fb->account_id,
    746       GNUNET_TIME_timestamp_get (),
    747       apr->details.success.expiration_time,
    748       apr->details.success.account_properties,
    749       apr->details.success.new_rules,
    750       apr->details.success.to_investigate,
    751       apr->details.success.new_measures,
    752       jmeasures,
    753       NULL, /* justification */
    754       NULL, /* decider_pub */
    755       NULL, /* decider_sig */
    756       apr->details.success.num_events,
    757       apr->details.success.events,
    758       NULL, /* form_id */
    759       0, /* enc_attributes_size*/
    760       NULL, /* enc_attributes*/
    761       NULL, /* attributes_hash */
    762       GNUNET_TIME_UNIT_ZERO_TS, /* attributes_expiration_time */
    763       &invalid_officer,
    764       &unknown_account,
    765       &last_date,
    766       &legitimization_measure_serial_id,
    767       &is_wallet);
    768   }
    769 
    770   if (qs < 0)
    771   {
    772     GNUNET_break (0);
    773     fb->cb (fb->cb_cls,
    774             false,
    775             0);
    776     goto cleanup;
    777   }
    778   /* Finally, return result to main handler */
    779   fb->cb (fb->cb_cls,
    780           true,
    781           0);
    782 cleanup:
    783   TEH_kyc_fallback_cancel (fb);
    784   GNUNET_async_scope_restore (&old_scope);
    785   TALER_KYCLOGIC_rules_free (lrs);
    786   json_decref (jmeasures);
    787 }
    788 
    789 
    790 /**
    791  * Helper task function to asynchronously return
    792  * the result of the operation.
    793  *
    794  * @param cls a `struct TEH_KycAmlFallback`.
    795  */
    796 static void
    797 return_fallback_result (void *cls)
    798 {
    799   struct TEH_KycAmlFallback *fb = cls;
    800   struct GNUNET_AsyncScopeSave old_scope;
    801 
    802   fb->task = NULL;
    803   GNUNET_async_scope_enter (&fb->scope,
    804                             &old_scope);
    805   fb->cb (fb->cb_cls,
    806           ! fb->failure,
    807           fb->requirement_row);
    808   TEH_kyc_fallback_cancel (fb);
    809   GNUNET_async_scope_restore (&old_scope);
    810 }
    811 
    812 
    813 struct TEH_KycAmlFallback*
    814 TEH_kyc_fallback (
    815   const struct GNUNET_AsyncScopeId *scope,
    816   const struct TALER_NormalizedPaytoHashP *account_id,
    817   bool is_wallet,
    818   uint64_t orig_requirement_row,
    819   const char *fallback_measure,
    820   TEH_KycAmlFallbackCallback cb,
    821   void *cb_cls)
    822 {
    823   struct TEH_KycAmlFallback *fb;
    824   struct TALER_KYCLOGIC_KycCheckContext kcc;
    825 
    826   if (GNUNET_OK !=
    827       TALER_KYCLOGIC_get_original_measure (
    828         fallback_measure,
    829         &kcc))
    830   {
    831     /* very bad, could not find fallback measure!? */
    832     GNUNET_break (0);
    833     return NULL;
    834   }
    835   fb = GNUNET_new (struct TEH_KycAmlFallback);
    836   fb->scope = *scope;
    837   fb->account_id = *account_id;
    838   fb->orig_requirement_row = orig_requirement_row;
    839   fb->cb = cb;
    840   fb->cb_cls = cb_cls;
    841   if (NULL == kcc.check)
    842   {
    843     struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = {
    844       .account = &fb->account_id,
    845       .is_wallet = is_wallet,
    846       .pg = TEH_pg,
    847       .attribute_key = &TEH_attribute_key
    848     };
    849 
    850     /* check was set to 'SKIP', run program immediately */
    851     fb->aprh
    852       = TALER_KYCLOGIC_run_aml_program2 (
    853           kcc.prog_name,
    854           kcc.context,
    855           is_wallet,
    856           &TALER_EXCHANGEDB_current_attributes_builder,
    857           &hbc,
    858           &TALER_EXCHANGEDB_current_rule_builder,
    859           &hbc,
    860           &TALER_EXCHANGEDB_aml_history_builder,
    861           &hbc,
    862           &TALER_EXCHANGEDB_kyc_history_builder,
    863           &hbc,
    864           TEH_aml_program_timeout,
    865           &handle_aml_fallback_result,
    866           fb);
    867     if (NULL == fb->aprh)
    868     {
    869       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    870                   "Fallback AML program `%s' unknown\n",
    871                   kcc.prog_name);
    872       TEH_kyc_fallback_cancel (fb);
    873       return NULL;
    874     }
    875     return fb;
    876   }
    877   /* activate given check */
    878   {
    879     json_t *jmeasures;
    880     enum GNUNET_DB_QueryStatus qs;
    881     bool bad_kyc_auth;
    882     struct TALER_FullPayto null_account = {
    883       .full_payto = NULL
    884     };
    885 
    886     jmeasures = TALER_KYCLOGIC_check_to_jmeasures (&kcc);
    887     qs = TALER_EXCHANGEDB_do_trigger_kyc_rule_for_account (
    888       TEH_pg,
    889       null_account, /* account_id is already in wire targets */
    890       account_id,
    891       NULL, /* account_pub */
    892       NULL, /* merchant_pub */
    893       jmeasures,
    894       65536, /* high priority (does it matter?) */
    895       &fb->requirement_row,
    896       &bad_kyc_auth);
    897     json_decref (jmeasures);
    898     fb->failure = (qs <= 0);
    899     fb->task = GNUNET_SCHEDULER_add_now (&return_fallback_result,
    900                                          fb);
    901   }
    902   return fb;
    903 }
    904 
    905 
    906 void
    907 TEH_kyc_fallback_cancel (
    908   struct TEH_KycAmlFallback *fb)
    909 {
    910   if (NULL != fb->task)
    911   {
    912     GNUNET_SCHEDULER_cancel (fb->task);
    913     fb->task = NULL;
    914   }
    915   if (NULL != fb->aprh)
    916   {
    917     TALER_KYCLOGIC_run_aml_program_cancel (fb->aprh);
    918     fb->aprh = NULL;
    919   }
    920   GNUNET_free (fb);
    921 }
    922 
    923 
    924 bool
    925 TEH_kyc_failed (
    926   uint64_t process_row,
    927   const struct TALER_NormalizedPaytoHashP *account_id,
    928   const char *provider_name,
    929   const char *provider_user_id,
    930   const char *provider_legitimization_id,
    931   const char *error_message,
    932   enum TALER_ErrorCode ec)
    933 {
    934   enum GNUNET_DB_QueryStatus qs;
    935 
    936   qs = TALER_EXCHANGEDB_insert_kyc_failure (
    937     TEH_pg,
    938     process_row,
    939     account_id,
    940     provider_name,
    941     provider_user_id,
    942     provider_legitimization_id,
    943     error_message,
    944     ec);
    945   if (qs <= 0)
    946   {
    947     GNUNET_break (0);
    948     return false;
    949   }
    950   return true;
    951 }
    952 
    953 
    954 struct TEH_LegitimizationCheckHandle
    955 {
    956   /**
    957    * Function to call with the result.
    958    */
    959   TEH_LegitimizationCheckCallback result_cb;
    960 
    961   /**
    962    * Closure for @e result_cb.
    963    */
    964   void *result_cb_cls;
    965 
    966   /**
    967    * Task scheduled to return a result asynchronously.
    968    */
    969   struct GNUNET_SCHEDULER_Task *async_task;
    970 
    971   /**
    972    * Handle to asynchronously running instant measure.
    973    */
    974   struct TEH_KycMeasureRunContext *kat;
    975 
    976   /**
    977    * Handle for the task that gets us the latest
    978    * applicable rules.
    979    */
    980   struct TALER_EXCHANGEDB_RuleUpdater *ru;
    981 
    982   /**
    983    * Payto-URI of the account.
    984    */
    985   struct TALER_FullPayto payto_uri;
    986 
    987   /**
    988    * Amount iterator to call to check for amounts.
    989    */
    990   TALER_KYCLOGIC_KycAmountIterator ai;
    991 
    992   /**
    993    * Closure for @e ai.
    994    */
    995   void *ai_cls;
    996 
    997   /**
    998    * Hash of @e payto_uri.
    999    */
   1000   struct TALER_NormalizedPaytoHashP h_payto;
   1001 
   1002   /**
   1003    * Public key of the account. We should associate this public
   1004    * key with the account if @e have_account_pub is true.  Do not
   1005    * confuse with @e lcr.kyc.have_account_pub which refers to us
   1006    * already having an @e lcr.kyc.account_pub in the database for
   1007    * the given @e h_payto.
   1008    */
   1009   union TALER_AccountPublicKeyP account_pub;
   1010 
   1011   /**
   1012    * Public key of the merchant.  Checks that the KYC
   1013    * data was actually provided for this merchant if
   1014    * @e have_merchant_pub is true, and if not rejects
   1015    * the operation.
   1016    */
   1017   struct TALER_MerchantPublicKeyP merchant_pub;
   1018 
   1019   /**
   1020    * Our request scope for logging.
   1021    */
   1022   struct GNUNET_AsyncScopeId scope;
   1023 
   1024   /**
   1025    * Legitimization result we have been building and
   1026    * should return.
   1027    */
   1028   struct TEH_LegitimizationCheckResult lcr;
   1029 
   1030   /**
   1031    * Event we were triggered for.
   1032    */
   1033   enum TALER_KYCLOGIC_KycTriggerEvent et;
   1034 
   1035   /**
   1036    * Number of instant rule triggers we have experienced
   1037    * in this check already.
   1038    */
   1039   unsigned int rerun;
   1040 
   1041   /**
   1042    * Do we have @e account_pub?
   1043    */
   1044   bool have_account_pub;
   1045 
   1046   /**
   1047    * Do we have @e merchant_pub?
   1048    */
   1049   bool have_merchant_pub;
   1050 
   1051   /**
   1052    * Is our @e h_payto for a wallet?
   1053    */
   1054   bool is_wallet;
   1055 
   1056   /**
   1057    * Set to true if the merchant public key does not
   1058    * match the public key we have on file for this
   1059    * target account *and* a rule actually triggered
   1060    * for this operation (and thus a new KYC AUTH is
   1061    * required).
   1062    */
   1063   bool bad_kyc_auth;
   1064 
   1065 };
   1066 
   1067 
   1068 /**
   1069  * Helper task that asynchronously calls the result
   1070  * callback and then cleans up.
   1071  *
   1072  * @param[in] cls a `struct TEH_LegitimizationCheckHandle *`
   1073  */
   1074 static void
   1075 async_return_legi_result (void *cls)
   1076 {
   1077   struct TEH_LegitimizationCheckHandle *lch = cls;
   1078   struct GNUNET_AsyncScopeSave old_scope;
   1079 
   1080   lch->async_task = NULL;
   1081   GNUNET_async_scope_enter (&lch->scope,
   1082                             &old_scope);
   1083   lch->result_cb (lch->result_cb_cls,
   1084                   &lch->lcr);
   1085   lch->lcr.response = NULL;
   1086   TEH_legitimization_check_cancel (lch);
   1087   GNUNET_async_scope_restore (&old_scope);
   1088 }
   1089 
   1090 
   1091 /**
   1092  * The legitimization process failed, return an error
   1093  * response.
   1094  *
   1095  * @param[in,out] lch legitimization check that failed
   1096  * @param ec error code to return
   1097  * @param details error details to return (can be NULL)
   1098  */
   1099 static void
   1100 legi_fail (struct TEH_LegitimizationCheckHandle *lch,
   1101            enum TALER_ErrorCode ec,
   1102            const char *details)
   1103 {
   1104   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1105               "Legitimziation process failed: %s (%s)\n",
   1106               TALER_ErrorCode_get_hint (ec),
   1107               details);
   1108   lch->lcr.http_status
   1109     = TALER_ErrorCode_get_http_status (ec);
   1110   lch->lcr.response
   1111     = TALER_MHD_make_error (
   1112         ec,
   1113         details);
   1114   lch->async_task
   1115     = GNUNET_SCHEDULER_add_now (
   1116         &async_return_legi_result,
   1117         lch);
   1118 }
   1119 
   1120 
   1121 /**
   1122  * Actually (re)-run the legitimization check @a lch.
   1123  *
   1124  * @param[in,out] lch legitimization check to run
   1125  */
   1126 static void
   1127 legitimization_check_run (
   1128   struct TEH_LegitimizationCheckHandle *lch);
   1129 
   1130 
   1131 /**
   1132  * Function called after the KYC-AML trigger is done.
   1133  *
   1134  * @param cls must be a `struct TEH_LegitimizationCheckHandle *`
   1135  * @param ec error code or 0 on success
   1136  * @param detail error message or NULL on success / no info
   1137  */
   1138 static void
   1139 legi_check_aml_trigger_cb (
   1140   void *cls,
   1141   enum TALER_ErrorCode ec,
   1142   const char *detail)
   1143 {
   1144   struct TEH_LegitimizationCheckHandle *lch = cls;
   1145 
   1146   lch->kat = NULL;
   1147   if (TALER_EC_NONE != ec)
   1148   {
   1149     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1150                 "AML program failed: %s (%s, %d)\n",
   1151                 TALER_ErrorCode_get_hint (ec),
   1152                 detail,
   1153                 (int) ec);
   1154     lch->lcr.http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   1155     lch->lcr.response = TALER_MHD_make_error (
   1156       ec,
   1157       detail);
   1158     lch->async_task
   1159       = GNUNET_SCHEDULER_add_now (
   1160           &async_return_legi_result,
   1161           lch);
   1162     return;
   1163   }
   1164   /* re-run the check, we got new rules! */
   1165   if (lch->rerun > MAX_LEGI_LOOPS)
   1166   {
   1167     /* deep recursion not allowed, abort! */
   1168     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1169                 "Deep recursion (> %u) detected in AML programs, aborting\n",
   1170                 (unsigned int) MAX_LEGI_LOOPS);
   1171     legi_fail (lch,
   1172                TALER_EC_EXCHANGE_KYC_RECURSIVE_RULE_DETECTED,
   1173                NULL);
   1174     return;
   1175   }
   1176   lch->rerun++;
   1177   legitimization_check_run (lch);
   1178 }
   1179 
   1180 
   1181 /**
   1182  * Setup legitimization check.
   1183  *
   1184  * @param scope scope for logging
   1185  * @param et type of event we are checking
   1186  * @param payto_uri account we are checking for
   1187  * @param h_payto hash of @a payto_uri
   1188  * @param account_pub public key to enable for the
   1189  *    KYC authorization, NULL if not known
   1190  * @param ai callback to get amounts involved historically
   1191  * @param ai_cls closure for @a ai
   1192  * @param result_cb function to call with the result
   1193  * @param result_cb_cls closure for @a result_cb
   1194  * @return handle for the operation
   1195  */
   1196 static struct TEH_LegitimizationCheckHandle *
   1197 setup_legitimization_check (
   1198   const struct GNUNET_AsyncScopeId *scope,
   1199   enum TALER_KYCLOGIC_KycTriggerEvent et,
   1200   const struct TALER_FullPayto payto_uri,
   1201   const struct TALER_NormalizedPaytoHashP *h_payto,
   1202   const union TALER_AccountPublicKeyP *account_pub,
   1203   TALER_KYCLOGIC_KycAmountIterator ai,
   1204   void *ai_cls,
   1205   TEH_LegitimizationCheckCallback result_cb,
   1206   void *result_cb_cls)
   1207 {
   1208   struct TEH_LegitimizationCheckHandle *lch;
   1209 
   1210 #if EXTRA_CHECK
   1211   {
   1212     struct TALER_NormalizedPaytoHashP npt;
   1213 
   1214     TALER_full_payto_normalize_and_hash (payto_uri,
   1215                                          &npt);
   1216     GNUNET_assert (0 ==
   1217                    GNUNET_memcmp (&npt,
   1218                                   h_payto));
   1219   }
   1220 #endif
   1221   lch = GNUNET_new (struct TEH_LegitimizationCheckHandle);
   1222   lch->scope = *scope;
   1223   lch->et = et;
   1224   lch->payto_uri.full_payto
   1225     = GNUNET_strdup (payto_uri.full_payto);
   1226   lch->is_wallet
   1227     = TALER_payto_is_wallet (payto_uri.full_payto);
   1228   lch->h_payto = *h_payto;
   1229   if (NULL != account_pub)
   1230   {
   1231     lch->account_pub = *account_pub;
   1232     lch->have_account_pub = true;
   1233   }
   1234   lch->ai = ai;
   1235   lch->ai_cls = ai_cls;
   1236   lch->result_cb = result_cb;
   1237   lch->result_cb_cls = result_cb_cls;
   1238   return lch;
   1239 }
   1240 
   1241 
   1242 struct TEH_LegitimizationCheckHandle *
   1243 TEH_legitimization_check (
   1244   const struct GNUNET_AsyncScopeId *scope,
   1245   enum TALER_KYCLOGIC_KycTriggerEvent et,
   1246   const struct TALER_FullPayto payto_uri,
   1247   const struct TALER_NormalizedPaytoHashP *h_payto,
   1248   const union TALER_AccountPublicKeyP *account_pub,
   1249   TALER_KYCLOGIC_KycAmountIterator ai,
   1250   void *ai_cls,
   1251   TEH_LegitimizationCheckCallback result_cb,
   1252   void *result_cb_cls)
   1253 {
   1254   struct TEH_LegitimizationCheckHandle *lch;
   1255 
   1256   lch = setup_legitimization_check (scope,
   1257                                     et,
   1258                                     payto_uri,
   1259                                     h_payto,
   1260                                     account_pub,
   1261                                     ai,
   1262                                     ai_cls,
   1263                                     result_cb,
   1264                                     result_cb_cls);
   1265   legitimization_check_run (lch);
   1266   return lch;
   1267 }
   1268 
   1269 
   1270 struct TEH_LegitimizationCheckHandle *
   1271 TEH_legitimization_check2 (
   1272   const struct GNUNET_AsyncScopeId *scope,
   1273   enum TALER_KYCLOGIC_KycTriggerEvent et,
   1274   const struct TALER_FullPayto payto_uri,
   1275   const struct TALER_NormalizedPaytoHashP *h_payto,
   1276   const struct TALER_MerchantPublicKeyP *merchant_pub,
   1277   TALER_KYCLOGIC_KycAmountIterator ai,
   1278   void *ai_cls,
   1279   TEH_LegitimizationCheckCallback result_cb,
   1280   void *result_cb_cls)
   1281 {
   1282   struct TEH_LegitimizationCheckHandle *lch;
   1283 
   1284   lch = setup_legitimization_check (scope,
   1285                                     et,
   1286                                     payto_uri,
   1287                                     h_payto,
   1288                                     NULL,
   1289                                     ai,
   1290                                     ai_cls,
   1291                                     result_cb,
   1292                                     result_cb_cls);
   1293   lch->merchant_pub = *merchant_pub;
   1294   lch->have_merchant_pub = true;
   1295   legitimization_check_run (lch);
   1296   return lch;
   1297 }
   1298 
   1299 
   1300 /**
   1301  * The KYC check failed because KYC auth is required
   1302  * to match and it does not.
   1303  *
   1304  * @param[in,out] lch legitimization check to fail
   1305  */
   1306 static void
   1307 fail_kyc_auth (struct TEH_LegitimizationCheckHandle *lch)
   1308 {
   1309   lch->lcr.kyc.requirement_row = 0;
   1310   lch->lcr.kyc.ok = false;
   1311   lch->lcr.bad_kyc_auth = true;
   1312   lch->lcr.expiration_date
   1313     = GNUNET_TIME_UNIT_FOREVER_TS;
   1314   memset (&lch->lcr.next_threshold,
   1315           0,
   1316           sizeof (struct TALER_Amount));
   1317   lch->lcr.http_status = 0;
   1318   lch->lcr.response = NULL;
   1319   lch->async_task
   1320     = GNUNET_SCHEDULER_add_now (
   1321         &async_return_legi_result,
   1322         lch);
   1323 }
   1324 
   1325 
   1326 /**
   1327  * Function called to iterate over KYC-relevant
   1328  * transaction amounts for a particular time range.
   1329  * Called within a database transaction, so must
   1330  * not start a new one.
   1331  *
   1332  * Given that there *is* a KYC requirement, we also
   1333  * check if the kyc_auth_bad is set and react
   1334  * accordingly.
   1335  *
   1336  * @param cls closure, a `struct TEH_LegitimizationCheckHandle *`
   1337  * @param limit maximum time-range for which events
   1338  *        should be fetched (timestamp in the past)
   1339  * @param cb function to call on each event found,
   1340  *        events must be returned in reverse chronological
   1341  *        order
   1342  * @param cb_cls closure for @a cb
   1343  * @return transaction status
   1344  */
   1345 static enum GNUNET_DB_QueryStatus
   1346 amount_iterator_wrapper_cb (
   1347   void *cls,
   1348   struct GNUNET_TIME_Absolute limit,
   1349   TALER_KYCLOGIC_KycAmountCallback cb,
   1350   void *cb_cls)
   1351 {
   1352   struct TEH_LegitimizationCheckHandle *lch = cls;
   1353 
   1354   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1355               "KYC: Checking amounts until %s\n",
   1356               GNUNET_TIME_absolute2s (limit));
   1357   if (lch->lcr.bad_kyc_auth)
   1358   {
   1359     /* We *do* have applicable KYC rules *and* the
   1360        target_pub does not match the merchant_pub,
   1361        so we indeed have a problem! */
   1362     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1363                 "KYC: Mismatch between merchant_pub and target_pub is relevant!\n");
   1364     lch->bad_kyc_auth = true;
   1365   }
   1366   return lch->ai (lch->ai_cls,
   1367                   limit,
   1368                   cb,
   1369                   cb_cls);
   1370 }
   1371 
   1372 
   1373 /**
   1374  * Function called with the current rule set. Called with an open
   1375  * database transaction.
   1376  *
   1377  * @param lch a `struct TEH_LegitimizationCheckHandle *`
   1378  * @param rur includes legitimziation rule set that applies to the account
   1379  *   (owned by callee, callee must free the lrs!)
   1380  */
   1381 static void
   1382 current_rules_cb (
   1383   struct TEH_LegitimizationCheckHandle *lch,
   1384   struct TALER_EXCHANGEDB_RuleUpdaterResult *rur)
   1385 {
   1386   struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs = rur->lrs;
   1387   struct GNUNET_AsyncScopeSave old_scope;
   1388   enum GNUNET_DB_QueryStatus qs;
   1389   const struct TALER_KYCLOGIC_KycRule *requirement;
   1390   const struct TALER_KYCLOGIC_Measure *instant_ms;
   1391 
   1392   GNUNET_async_scope_enter (&lch->scope,
   1393                             &old_scope);
   1394   if (TALER_EC_NONE != rur->ec)
   1395   {
   1396     /* rollback should not be needed, but better be safe */
   1397     TALER_EXCHANGEDB_rollback (TEH_pg);
   1398     legi_fail (lch,
   1399                rur->ec,
   1400                rur->hint);
   1401     goto cleanup;
   1402   }
   1403 
   1404   qs = TALER_KYCLOGIC_kyc_test_required (
   1405     lch->et,
   1406     lrs,
   1407     &amount_iterator_wrapper_cb,
   1408     lch,
   1409     &requirement,
   1410     &lch->lcr.next_threshold);
   1411   if (qs < 0)
   1412   {
   1413     GNUNET_break (0);
   1414     TALER_EXCHANGEDB_rollback (TEH_pg);
   1415     legi_fail (lch,
   1416                TALER_EC_GENERIC_DB_FETCH_FAILED,
   1417                "kyc_test_required");
   1418     goto cleanup;
   1419   }
   1420   if (lch->bad_kyc_auth)
   1421   {
   1422     qs = TALER_EXCHANGEDB_commit (TEH_pg);
   1423     if (0 > qs)
   1424     {
   1425       legi_fail (lch,
   1426                  TALER_EC_GENERIC_DB_COMMIT_FAILED,
   1427                  "kyc_test_required");
   1428       goto cleanup;
   1429     }
   1430     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1431                 "KYC auth required\n");
   1432     fail_kyc_auth (lch);
   1433     goto cleanup;
   1434   }
   1435 
   1436   if (NULL == requirement)
   1437   {
   1438     qs = TALER_EXCHANGEDB_commit (TEH_pg);
   1439     if (0 > qs)
   1440     {
   1441       legi_fail (lch,
   1442                  TALER_EC_GENERIC_DB_COMMIT_FAILED,
   1443                  "kyc_test_required");
   1444       goto cleanup;
   1445     }
   1446     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1447                 "KYC check passed\n");
   1448     lch->lcr.kyc.ok = true;
   1449     lch->lcr.expiration_date
   1450       = TALER_KYCLOGIC_rules_get_expiration (lrs);
   1451     /* return success! */
   1452     lch->async_task
   1453       = GNUNET_SCHEDULER_add_now (
   1454           &async_return_legi_result,
   1455           lch);
   1456     goto cleanup;
   1457   }
   1458 
   1459   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1460               "KYC requirement is %s\n",
   1461               TALER_KYCLOGIC_rule2s (requirement));
   1462   instant_ms
   1463     = TALER_KYCLOGIC_rule_get_instant_measure (
   1464         requirement);
   1465   if (NULL != instant_ms)
   1466   {
   1467     /* We have an 'instant' measure which means we must run the
   1468        AML program immediately instead of waiting for the account owner
   1469        to select some measure and contribute their KYC data. */
   1470 
   1471     lch->kat = TEH_kyc_run_measure_directly (
   1472       &lch->scope,
   1473       instant_ms,
   1474       &lch->h_payto,
   1475       lch->is_wallet,
   1476       &legi_check_aml_trigger_cb,
   1477       lch);
   1478     if (NULL == lch->kat)
   1479     {
   1480       GNUNET_break (0);
   1481       TALER_EXCHANGEDB_rollback (TEH_pg);
   1482       legi_fail (lch,
   1483                  TALER_EC_EXCHANGE_KYC_AML_PROGRAM_FAILURE,
   1484                  NULL);
   1485       goto cleanup;
   1486     }
   1487     qs = TALER_EXCHANGEDB_commit (TEH_pg);
   1488     if (0 > qs)
   1489     {
   1490       legi_fail (lch,
   1491                  TALER_EC_GENERIC_DB_COMMIT_FAILED,
   1492                  "kyc_test_required");
   1493       goto cleanup;
   1494     }
   1495     goto cleanup;
   1496   }
   1497 
   1498   /* No instant measure, store all measures in the database and
   1499      wait for the user to select one (via /kyc-info) and to then
   1500      provide the data. */
   1501   lch->lcr.kyc.ok = false;
   1502   {
   1503     json_t *jmeasures;
   1504 
   1505     jmeasures = TALER_KYCLOGIC_rule_to_measures (requirement);
   1506     qs = TALER_EXCHANGEDB_do_trigger_kyc_rule_for_account (
   1507       TEH_pg,
   1508       lch->payto_uri,
   1509       &lch->h_payto,
   1510       lch->have_account_pub ? &lch->account_pub : NULL,
   1511       lch->have_merchant_pub ? &lch->merchant_pub : NULL,
   1512       jmeasures,
   1513       TALER_KYCLOGIC_rule2priority (requirement),
   1514       &lch->lcr.kyc.requirement_row,
   1515       &lch->lcr.bad_kyc_auth);
   1516     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1517                 "trigger_kyc_rule_for_account-1 on %d/%d returned %d/%llu/%d\n",
   1518                 lch->have_account_pub,
   1519                 lch->have_merchant_pub,
   1520                 (int) qs,
   1521                 (unsigned long long) lch->lcr.kyc.requirement_row,
   1522                 lch->lcr.bad_kyc_auth);
   1523     json_decref (jmeasures);
   1524   }
   1525   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   1526   {
   1527     GNUNET_break (0);
   1528     TALER_EXCHANGEDB_rollback (TEH_pg);
   1529     legi_fail (lch,
   1530                TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
   1531                "trigger_kyc_rule_for_account");
   1532     goto cleanup;
   1533   }
   1534   if (GNUNET_DB_STATUS_HARD_ERROR == qs)
   1535   {
   1536     GNUNET_break (0);
   1537     TALER_EXCHANGEDB_rollback (TEH_pg);
   1538     legi_fail (lch,
   1539                TALER_EC_GENERIC_DB_STORE_FAILED,
   1540                "trigger_kyc_rule_for_account");
   1541     goto cleanup;
   1542   }
   1543   if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
   1544   {
   1545     /* Serialization failure or a lost connection.  This used to fall
   1546        through to the commit below, which PostgreSQL happily accepted on the
   1547        already-aborted transaction, so the client was told its legitimization
   1548        measure had been registered when nothing had been written.  There is
   1549        no retry loop in this file (the transaction is hand-rolled rather than
   1550        run through TEH_DB_run_transaction), so all we can do here is fail
   1551        visibly and let the client repeat the request. */
   1552     TALER_EXCHANGEDB_rollback (TEH_pg);
   1553     legi_fail (lch,
   1554                TALER_EC_GENERIC_DB_SOFT_FAILURE,
   1555                "trigger_kyc_rule_for_account");
   1556     goto cleanup;
   1557   }
   1558   qs = TALER_EXCHANGEDB_commit (TEH_pg);
   1559   if (0 > qs)
   1560   {
   1561     legi_fail (lch,
   1562                TALER_EC_GENERIC_DB_COMMIT_FAILED,
   1563                "kyc_test_required");
   1564     goto cleanup;
   1565   }
   1566   /* return success! */
   1567   GNUNET_break (GNUNET_OK ==
   1568                 TALER_EXCHANGEDB_preflight (TEH_pg));
   1569   lch->async_task
   1570     = GNUNET_SCHEDULER_add_now (
   1571         &async_return_legi_result,
   1572         lch);
   1573 cleanup:
   1574   TALER_KYCLOGIC_rules_free (lrs);
   1575   GNUNET_async_scope_restore (&old_scope);
   1576 }
   1577 
   1578 
   1579 static void
   1580 legitimization_check_run (
   1581   struct TEH_LegitimizationCheckHandle *lch)
   1582 {
   1583   struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs = NULL;
   1584   enum GNUNET_DB_QueryStatus qs;
   1585   struct GNUNET_AsyncScopeSave old_scope;
   1586   enum GNUNET_GenericReturnValue res;
   1587 
   1588   if (! TEH_enable_kyc)
   1589   {
   1590     /* AML/KYC disabled, just immediately return success! */
   1591     lch->lcr.kyc.requirement_row = 0;
   1592     lch->lcr.kyc.ok = true;
   1593     lch->lcr.bad_kyc_auth = false;
   1594     lch->lcr.expiration_date
   1595       = GNUNET_TIME_UNIT_FOREVER_TS;
   1596     memset (&lch->lcr.next_threshold,
   1597             0,
   1598             sizeof (struct TALER_Amount));
   1599     lch->lcr.http_status = 0;
   1600     lch->lcr.response = NULL;
   1601     lch->async_task
   1602       = GNUNET_SCHEDULER_add_now (
   1603           &async_return_legi_result,
   1604           lch);
   1605     return;
   1606   }
   1607   GNUNET_async_scope_enter (&lch->scope,
   1608                             &old_scope);
   1609   res = TALER_EXCHANGEDB_start (TEH_pg,
   1610                                 "legi-check-run-start-precheck");
   1611   if (GNUNET_OK != res)
   1612   {
   1613     GNUNET_break (0);
   1614     legi_fail (lch,
   1615                TALER_EC_GENERIC_DB_START_FAILED,
   1616                "legi-check-run-start-precheck");
   1617     GNUNET_async_scope_restore (&old_scope);
   1618     return;
   1619   }
   1620   {
   1621     json_t *jrules;
   1622     bool no_account_pub;
   1623     bool no_reserve_pub;
   1624 
   1625     qs = TALER_EXCHANGEDB_get_kyc_rules_with_account (
   1626       TEH_pg,
   1627       &lch->h_payto,
   1628       lch->have_merchant_pub
   1629       ? &lch->merchant_pub
   1630       : NULL,
   1631       &no_account_pub,
   1632       &lch->lcr.kyc.account_pub,
   1633       &no_reserve_pub,
   1634       &lch->lcr.reserve_pub.reserve_pub,
   1635       &jrules);
   1636     switch (qs)
   1637     {
   1638     case GNUNET_DB_STATUS_HARD_ERROR:
   1639     case GNUNET_DB_STATUS_SOFT_ERROR:
   1640       GNUNET_break (0);
   1641       TALER_EXCHANGEDB_rollback (TEH_pg);
   1642       legi_fail (lch,
   1643                  TALER_EC_GENERIC_DB_FETCH_FAILED,
   1644                  "get_kyc_rules_with_account");
   1645       GNUNET_async_scope_restore (&old_scope);
   1646       return;
   1647     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1648     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1649       break;
   1650     }
   1651     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1652                 "get_kyc_rules returned %d/%d/%d/%d(%d)\n",
   1653                 (int) qs,
   1654                 ! no_account_pub,
   1655                 ! no_reserve_pub,
   1656                 NULL != jrules,
   1657                 (int) lch->have_merchant_pub);
   1658 
   1659     lch->lcr.kyc.have_account_pub
   1660       = ! no_account_pub;
   1661     lch->lcr.have_reserve_pub
   1662       = ! no_reserve_pub;
   1663     if ( (lch->have_merchant_pub) &&
   1664          ( (! lch->lcr.kyc.have_account_pub) ||
   1665            (0 !=
   1666             GNUNET_memcmp (&lch->merchant_pub,
   1667                            &lch->lcr.kyc.account_pub.merchant_pub)) ) &&
   1668          ( (! lch->lcr.have_reserve_pub) ||
   1669            (0 !=
   1670             GNUNET_memcmp (&lch->merchant_pub,
   1671                            &lch->lcr.reserve_pub.merchant_pub)) ) )
   1672     {
   1673       if (NULL == jrules)
   1674       {
   1675         /* We do not have custom rules, defer enforcing merchant_pub
   1676            match until we actually have deposit constraints */
   1677         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1678                     "KYC: merchant_pub given but no known target_pub(%d)/reserve_pub(%d) match (%d)!\n",
   1679                     lch->lcr.kyc.have_account_pub,
   1680                     lch->lcr.have_reserve_pub,
   1681                     (int) qs);
   1682         lch->lcr.bad_kyc_auth = true;
   1683       }
   1684       else
   1685       {
   1686         /* We have custom rules, but the target_pub for
   1687            those custom rules does not match the
   1688            merchant_pub. Fail the KYC process! */
   1689         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1690                     "KYC: merchant_pub does not match target_pub of custom rules!\n");
   1691         TALER_EXCHANGEDB_rollback (TEH_pg);
   1692         json_decref (jrules);
   1693         fail_kyc_auth (lch);
   1694         goto cleanup;
   1695       }
   1696     }
   1697 
   1698     /* parse and free jrules (if we had any) */
   1699     if (NULL != jrules)
   1700     {
   1701       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1702                   "KYC: have custom KYC rules for this account!\n");
   1703       lrs = TALER_KYCLOGIC_rules_parse (jrules);
   1704       GNUNET_break (NULL != lrs);
   1705       /* Fall back to default rules on parse error! */
   1706       json_decref (jrules);
   1707     }
   1708     else
   1709     {
   1710       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1711                   "KYC: default KYC rules apply to this account!\n");
   1712     }
   1713   }
   1714 
   1715   /* NOTE-CG: I don't recall why we need to make this distinction
   1716      and re-fetch the rules this way. The main difference is that
   1717      we fetch the "legitimization_outcome_last_row" on the true
   1718      path, but we could presumably fetch it above as well. Not
   1719      doing another transaction would seem more efficient. So why
   1720      exactly do we do this here? */
   1721   if (NULL != lrs)
   1722   {
   1723     /* Stop the current transaction and start a new
   1724        asynchronous task with a new transaction to
   1725        fetch the rules for the account. */
   1726     TALER_EXCHANGEDB_rollback (TEH_pg);
   1727     TALER_KYCLOGIC_rules_free (lrs);
   1728     lch->ru = TALER_EXCHANGEDB_begin_rule_update (TEH_pg,
   1729                                                   &TEH_attribute_key,
   1730                                                   &lch->h_payto,
   1731                                                   lch->is_wallet,
   1732                                                   &current_rules_cb,
   1733                                                   lch);
   1734   }
   1735   else
   1736   {
   1737     struct TALER_EXCHANGEDB_RuleUpdaterResult rur = { 0 };
   1738 
   1739     /* Simplified case, just default rules apply, we can
   1740        continue in this transaction */
   1741     current_rules_cb (lch,
   1742                       &rur);
   1743   }
   1744 cleanup:
   1745   GNUNET_async_scope_restore (&old_scope);
   1746 }
   1747 
   1748 
   1749 void
   1750 TEH_legitimization_check_cancel (
   1751   struct TEH_LegitimizationCheckHandle *lch)
   1752 {
   1753   if (NULL != lch->async_task)
   1754   {
   1755     GNUNET_SCHEDULER_cancel (lch->async_task);
   1756     lch->async_task = NULL;
   1757   }
   1758   if (NULL != lch->kat)
   1759   {
   1760     TEH_kyc_run_measure_cancel (lch->kat);
   1761     lch->kat = NULL;
   1762   }
   1763   if (NULL != lch->lcr.response)
   1764   {
   1765     MHD_destroy_response (lch->lcr.response);
   1766     lch->lcr.response = NULL;
   1767   }
   1768   GNUNET_free (lch->payto_uri.full_payto);
   1769   GNUNET_free (lch);
   1770 }