LCOV - code coverage report
Current view: top level - exchangedb - exchangedb_aml.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 30.5 % 266 81
Test Date: 2025-12-28 14:06:02 Functions: 54.5 % 11 6

            Line data    Source code
       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 exchangedb_aml.c
      18              :  * @brief helper function to handle AML programs
      19              :  * @author Christian Grothoff
      20              :  */
      21              : #include "taler/taler_exchangedb_plugin.h"
      22              : #include "taler/taler_exchangedb_lib.h"
      23              : #include "taler/taler_kyclogic_lib.h"
      24              : #include "taler/taler_json_lib.h"
      25              : #include "taler/taler_dbevents.h"
      26              : #include <gnunet/gnunet_common.h>
      27              : 
      28              : /**
      29              :  * Maximum recursion depth we allow for AML programs.
      30              :  * Basically, after this number of "skip" processes
      31              :  * we forcefully terminate the recursion and fail hard.
      32              :  */
      33              : #define MAX_DEPTH 16
      34              : 
      35              : enum GNUNET_DB_QueryStatus
      36           10 : TALER_EXCHANGEDB_persist_aml_program_result (
      37              :   struct TALER_EXCHANGEDB_Plugin *plugin,
      38              :   uint64_t process_row,
      39              :   const struct TALER_NormalizedPaytoHashP *account_id,
      40              :   const struct TALER_KYCLOGIC_AmlProgramResult *apr,
      41              :   enum TALER_EXCHANGEDB_PersistProgramResultStatus *ret_pprs)
      42              : {
      43              :   enum GNUNET_DB_QueryStatus qs;
      44           10 :   json_t *jmeasures = NULL;
      45           10 :   struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs = NULL;
      46              : 
      47           10 :   GNUNET_assert (NULL != ret_pprs);
      48              : 
      49           10 :   *ret_pprs = TALER_EXCHANGEDB_PPRS_OK;
      50              : 
      51           10 :   if ( (TALER_KYCLOGIC_AMLR_SUCCESS == apr->status) &&
      52           10 :        (NULL != apr->details.success.new_measures) )
      53              :   {
      54            0 :     lrs = TALER_KYCLOGIC_rules_parse (apr->details.success.new_rules);
      55            0 :     if (NULL == lrs)
      56              :     {
      57            0 :       qs = plugin->insert_aml_program_failure (
      58              :         plugin->cls,
      59              :         process_row,
      60              :         account_id,
      61              :         "Failed to parse AML program output",
      62              :         TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT);
      63            0 :       GNUNET_break (qs > 0);
      64            0 :       return qs;
      65              :     }
      66            0 :     jmeasures = TALER_KYCLOGIC_get_jmeasures (
      67              :       lrs,
      68            0 :       apr->details.success.new_measures);
      69            0 :     if (NULL == jmeasures)
      70              :     {
      71              :       char *err;
      72              : 
      73            0 :       GNUNET_break (0);
      74            0 :       GNUNET_asprintf (&err,
      75              :                        "Failed to find measures `%s' specified in AML program output",
      76            0 :                        apr->details.success.new_measures);
      77            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
      78              :                   "AML program specified invalid measures `%s'\n",
      79              :                   apr->details.success.new_measures);
      80            0 :       qs = plugin->insert_aml_program_failure (
      81              :         plugin->cls,
      82              :         process_row,
      83              :         account_id,
      84              :         err,
      85              :         TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT);
      86            0 :       *ret_pprs = TALER_EXCHANGEDB_PPRS_BAD_OUTCOME;
      87            0 :       TALER_KYCLOGIC_rules_free (lrs);
      88            0 :       GNUNET_free (err);
      89            0 :       GNUNET_break (qs > 0);
      90            0 :       return qs;
      91              :     }
      92              :   }
      93              : 
      94           10 :   qs = plugin->clear_aml_lock (
      95              :     plugin->cls,
      96              :     account_id);
      97           10 :   switch (apr->status)
      98              :   {
      99            0 :   case TALER_KYCLOGIC_AMLR_FAILURE:
     100            0 :     qs = plugin->insert_aml_program_failure (
     101              :       plugin->cls,
     102              :       process_row,
     103              :       account_id,
     104            0 :       apr->details.failure.error_message,
     105            0 :       apr->details.failure.ec);
     106            0 :     GNUNET_break (qs > 0);
     107            0 :     goto cleanup;
     108           10 :   case TALER_KYCLOGIC_AMLR_SUCCESS:
     109              :     {
     110           10 :       struct TALER_FullPayto null_payto_uri = { 0 };
     111              :       bool invalid_officer;
     112              :       bool unknown_account;
     113              :       struct GNUNET_TIME_Timestamp last_date;
     114              :       uint64_t legitimization_measure_serial_id;
     115              :       bool is_wallet;
     116              : 
     117           10 :       qs = plugin->insert_aml_decision (
     118              :         plugin->cls,
     119              :         null_payto_uri,
     120              :         account_id,
     121              :         GNUNET_TIME_timestamp_get (),
     122              :         apr->details.success.expiration_time,
     123           10 :         apr->details.success.account_properties,
     124           10 :         apr->details.success.new_rules,
     125           10 :         apr->details.success.to_investigate,
     126           10 :         apr->details.success.new_measures,
     127              :         jmeasures,
     128              :         NULL, /* justification */
     129              :         NULL, /* decider_pub */
     130              :         NULL, /* decider_sig */
     131           10 :         apr->details.success.num_events,
     132           10 :         apr->details.success.events,
     133              :         NULL, /* form ID */
     134              :         0, /* enc_attributes_size*/
     135              :         NULL, /* enc_attributes*/
     136              :         NULL, /* attributes_hash */
     137           10 :         GNUNET_TIME_UNIT_ZERO_TS, /* attributes_expiration_time */
     138              :         &invalid_officer,
     139              :         &unknown_account,
     140              :         &last_date,
     141              :         &legitimization_measure_serial_id,
     142              :         &is_wallet);
     143           10 :       GNUNET_break (qs > 0);
     144           10 :       goto cleanup;
     145              :     }
     146              :   }
     147            0 :   GNUNET_break (0);
     148            0 :   qs = GNUNET_DB_STATUS_HARD_ERROR;
     149           10 : cleanup:
     150           10 :   TALER_KYCLOGIC_rules_free (lrs);
     151           10 :   json_decref (jmeasures);
     152           10 :   return qs;
     153              : }
     154              : 
     155              : 
     156              : struct TALER_EXCHANGEDB_RuleUpdater
     157              : {
     158              :   /**
     159              :    * database plugin to use
     160              :    */
     161              :   struct TALER_EXCHANGEDB_Plugin *plugin;
     162              : 
     163              :   /**
     164              :    * key to use to decrypt attributes
     165              :    */
     166              :   struct TALER_AttributeEncryptionKeyP attribute_key;
     167              : 
     168              :   /**
     169              :    * account to get the rule set for
     170              :    */
     171              :   struct TALER_NormalizedPaytoHashP account;
     172              : 
     173              :   /**
     174              :    * function to call with the result
     175              :    */
     176              :   TALER_EXCHANGEDB_CurrentRulesCallback cb;
     177              : 
     178              :   /**
     179              :    * Closure for @e cb.
     180              :    */
     181              :   void *cb_cls;
     182              : 
     183              :   /**
     184              :    * Current rule set we are working on.
     185              :    */
     186              :   struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs;
     187              : 
     188              :   /**
     189              :    * Task for asynchronous continuations.
     190              :    */
     191              :   struct GNUNET_SCHEDULER_Task *t;
     192              : 
     193              :   /**
     194              :    * Handler waiting notification that (previous) AML program
     195              :    * finished.
     196              :    */
     197              :   struct GNUNET_DB_EventHandler *eh;
     198              : 
     199              :   /**
     200              :    * Handle to running AML program.
     201              :    */
     202              :   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *amlh;
     203              : 
     204              :   /**
     205              :    * Name of the AML program we were running asynchronously,
     206              :    * for diagnostics.
     207              :    */
     208              :   char *aml_program_name;
     209              : 
     210              :   /**
     211              :    * Error hint to return with @e ec.
     212              :    */
     213              :   const char *hint;
     214              : 
     215              :   /**
     216              :    * Row the rule set in @a lrs is based on.
     217              :    */
     218              :   uint64_t legitimization_outcome_last_row;
     219              : 
     220              :   /**
     221              :    * Taler error code to return.
     222              :    */
     223              :   enum TALER_ErrorCode ec;
     224              : 
     225              :   /**
     226              :    * Counter used to limit recursion depth.
     227              :    */
     228              :   unsigned int depth;
     229              : 
     230              :   /**
     231              :    * True if @e account is for a wallet.
     232              :    */
     233              :   bool is_wallet;
     234              : };
     235              : 
     236              : 
     237              : /**
     238              :  * Function that finally returns the result to the application and cleans
     239              :  * up. Called with an open database transaction on success; on failure, the
     240              :  * transaction will have already been rolled back.
     241              :  *
     242              :  * @param[in,out] ru rule updater to return result for
     243              :  */
     244              : static void
     245           28 : return_result (struct TALER_EXCHANGEDB_RuleUpdater *ru)
     246              : {
     247           28 :   struct TALER_EXCHANGEDB_RuleUpdaterResult rur = {
     248           28 :     .legitimization_outcome_last_row = ru->legitimization_outcome_last_row,
     249           28 :     .lrs = ru->lrs,
     250           28 :     .ec = ru->ec,
     251              :   };
     252              : 
     253           28 :   ru->cb (ru->cb_cls,
     254              :           &rur);
     255           28 :   ru->lrs = NULL;
     256           28 :   TALER_EXCHANGEDB_update_rules_cancel (ru);
     257           28 : }
     258              : 
     259              : 
     260              : /**
     261              :  * Fail the update with the given @a ec and @a hint.
     262              :  * Called with an open database transaction, which will
     263              :  * be rolled back (!).
     264              :  *
     265              :  * @param[in,out] ru account we are processing
     266              :  * @param ec error code to fail with
     267              :  * @param hint hint to return, can be NULL
     268              :  */
     269              : static void
     270            0 : fail_update (struct TALER_EXCHANGEDB_RuleUpdater *ru,
     271              :              enum TALER_ErrorCode ec,
     272              :              const char *hint)
     273              : {
     274            0 :   GNUNET_assert (NULL == ru->t);
     275            0 :   ru->plugin->rollback (ru->plugin->cls);
     276            0 :   ru->ec = ec;
     277            0 :   ru->hint = hint;
     278            0 :   return_result (ru);
     279            0 : }
     280              : 
     281              : 
     282              : /**
     283              :  * Check the rules in @a ru to see if they are current, and
     284              :  * if not begin the updating process.  Called with an open
     285              :  * database transaction.
     286              :  *
     287              :  * @param[in] ru rule updater context
     288              :  */
     289              : static void
     290              : check_rules (struct TALER_EXCHANGEDB_RuleUpdater *ru);
     291              : 
     292              : 
     293              : /**
     294              :  * Run the measure @a m in the context of the legitimisation rules
     295              :  * of @a ru.  Called with an open database transaction.
     296              :  *
     297              :  * @param ru updating context we are using
     298              :  * @param m measure we need to run next
     299              :  */
     300              : static void
     301              : run_measure (struct TALER_EXCHANGEDB_RuleUpdater *ru,
     302              :              const struct TALER_KYCLOGIC_Measure *m);
     303              : 
     304              : 
     305              : /**
     306              :  * Function called after AML program was run.  Called
     307              :  * without an open database transaction, will start one!
     308              :  *
     309              :  * @param cls the `struct TALER_EXCHANGEDB_RuleUpdater *`
     310              :  * @param apr result of the AML program.
     311              :  */
     312              : static void
     313            0 : aml_result_callback (
     314              :   void *cls,
     315              :   const struct TALER_KYCLOGIC_AmlProgramResult *apr)
     316              : {
     317            0 :   struct TALER_EXCHANGEDB_RuleUpdater *ru = cls;
     318              :   enum GNUNET_DB_QueryStatus qs;
     319              :   enum GNUNET_GenericReturnValue res;
     320              :   enum TALER_EXCHANGEDB_PersistProgramResultStatus pprs;
     321              : 
     322            0 :   ru->amlh = NULL;
     323            0 :   res = ru->plugin->start (ru->plugin->cls,
     324              :                            "aml-persist-aml-program-result");
     325            0 :   if (GNUNET_OK != res)
     326              :   {
     327            0 :     GNUNET_break (0);
     328            0 :     fail_update (ru,
     329              :                  TALER_EC_GENERIC_DB_START_FAILED,
     330              :                  "aml-persist-aml-program-result");
     331            0 :     return;
     332              :   }
     333              :   /* Update database update based on result */
     334            0 :   qs = TALER_EXCHANGEDB_persist_aml_program_result (
     335              :     ru->plugin,
     336              :     0LLU, /* 0: no existing legitimization process, creates new row */
     337            0 :     &ru->account,
     338              :     apr,
     339              :     &pprs);
     340            0 :   switch (qs)
     341              :   {
     342            0 :   case GNUNET_DB_STATUS_HARD_ERROR:
     343            0 :     GNUNET_break (0);
     344            0 :     fail_update (ru,
     345              :                  TALER_EC_GENERIC_DB_STORE_FAILED,
     346              :                  "persist_aml_program_result");
     347            0 :     return;
     348            0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
     349              :     /* Bad, couldn't persist AML result. Try again... */
     350            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     351              :                 "Serialization issue persisting result of AML program. Restarting.\n");
     352            0 :     fail_update (ru,
     353              :                  TALER_EC_GENERIC_DB_SOFT_FAILURE,
     354              :                  "persist_aml_program_result");
     355            0 :     return;
     356            0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     357              :     /* Strange, but let's just continue */
     358            0 :     break;
     359            0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     360              :     /* normal case */
     361            0 :     break;
     362              :   }
     363            0 :   switch (pprs)
     364              :   {
     365            0 :   case TALER_EXCHANGEDB_PPRS_OK:
     366            0 :     break;
     367            0 :   case TALER_EXCHANGEDB_PPRS_BAD_OUTCOME:
     368            0 :     fail_update (ru,
     369              :                  TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT,
     370              :                  "persist_aml_program_result");
     371            0 :     return;
     372              :   }
     373            0 :   switch (apr->status)
     374              :   {
     375            0 :   case TALER_KYCLOGIC_AMLR_SUCCESS:
     376            0 :     TALER_KYCLOGIC_rules_free (ru->lrs);
     377            0 :     ru->lrs = NULL;
     378            0 :     ru->lrs = TALER_KYCLOGIC_rules_parse (apr->details.success.new_rules);
     379              :     /* Fall back to default rules on parse error! */
     380            0 :     GNUNET_break (NULL != ru->lrs);
     381            0 :     check_rules (ru);
     382            0 :     return;
     383            0 :   case TALER_KYCLOGIC_AMLR_FAILURE:
     384              :     {
     385            0 :       const char *fmn = apr->details.failure.fallback_measure;
     386              :       const struct TALER_KYCLOGIC_Measure *m;
     387              : 
     388            0 :       m = TALER_KYCLOGIC_get_measure (ru->lrs,
     389              :                                       fmn);
     390            0 :       if (NULL == m)
     391              :       {
     392            0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     393              :                     "Fallback measure `%s' does not exist (anymore?).\n",
     394              :                     fmn);
     395            0 :         TALER_KYCLOGIC_rules_free (ru->lrs);
     396            0 :         ru->lrs = NULL;
     397            0 :         return_result (ru);
     398            0 :         return;
     399              :       }
     400            0 :       run_measure (ru,
     401              :                    m);
     402            0 :       return;
     403              :     }
     404              :   }
     405              :   /* This should be impossible */
     406            0 :   GNUNET_assert (0);
     407              : }
     408              : 
     409              : 
     410              : /**
     411              :  * Entrypoint that fetches the latest rules from the database
     412              :  * and starts processing them. Called without an open database
     413              :  * transaction, will start one.
     414              :  *
     415              :  * @param[in] cls the `struct TALER_EXCHANGEDB_RuleUpdater *` to run
     416              :  */
     417              : static void
     418              : fetch_latest_rules (void *cls);
     419              : 
     420              : 
     421              : /**
     422              :  * Notification called when we either timeout on the AML program lock
     423              :  * or when the (previous) AML program finished and we can thus try again.
     424              :  *
     425              :  * @param cls  the `struct TALER_EXCHANGEDB_RuleUpdater *` to continue
     426              :  * @param extra additional event data provided (unused)
     427              :  * @param extra_size number of bytes in @a extra (unused)
     428              :  */
     429              : static void
     430            0 : trigger_fetch_latest_rules (void *cls,
     431              :                             const void *extra,
     432              :                             size_t extra_size)
     433              : {
     434            0 :   struct TALER_EXCHANGEDB_RuleUpdater *ru = cls;
     435              : 
     436              :   (void) extra;
     437              :   (void) extra_size;
     438            0 :   if (NULL != ru->t)
     439            0 :     return; /* multiple events triggered us, ignore */
     440            0 :   ru->t = GNUNET_SCHEDULER_add_now (&fetch_latest_rules,
     441              :                                     ru);
     442              : }
     443              : 
     444              : 
     445              : static void
     446            0 : run_measure (struct TALER_EXCHANGEDB_RuleUpdater *ru,
     447              :              const struct TALER_KYCLOGIC_Measure *m)
     448              : {
     449            0 :   if (NULL == m)
     450              :   {
     451              :     /* fall back to default rules */
     452            0 :     TALER_KYCLOGIC_rules_free (ru->lrs);
     453            0 :     ru->lrs = NULL;
     454            0 :     return_result (ru);
     455            0 :     return;
     456              :   }
     457            0 :   ru->depth++;
     458            0 :   if (ru->depth > MAX_DEPTH)
     459              :   {
     460            0 :     fail_update (ru,
     461              :                  TALER_EC_EXCHANGE_GENERIC_AML_PROGRAM_RECURSION_DETECTED,
     462              :                  NULL);
     463            0 :     return;
     464              :   }
     465            0 :   if ( (NULL == m->check_name) ||
     466              :        (0 ==
     467            0 :         strcasecmp ("SKIP",
     468            0 :                     m->check_name)) )
     469              :   {
     470            0 :     struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = {
     471            0 :       .account = &ru->account,
     472            0 :       .is_wallet = ru->is_wallet,
     473            0 :       .db_plugin = ru->plugin,
     474            0 :       .attribute_key = &ru->attribute_key
     475              :     };
     476              :     enum GNUNET_DB_QueryStatus qs;
     477              :     struct GNUNET_TIME_Absolute xlock;
     478              : 
     479              :     /* Free previous one, in case we are iterating... */
     480            0 :     GNUNET_free (ru->aml_program_name);
     481            0 :     if (NULL != m->prog_name)
     482              :     {
     483            0 :       ru->aml_program_name = GNUNET_strdup (m->prog_name);
     484              :     }
     485              :     else
     486              :     {
     487              :       /* How do we get to run a measure if the check type
     488              :          is INFO (which is the only case where prog_name
     489              :          is allowed to be NULL?) */
     490            0 :       GNUNET_break (0);
     491            0 :       ru->aml_program_name = NULL;
     492              :     }
     493            0 :     qs = ru->plugin->set_aml_lock (
     494            0 :       ru->plugin->cls,
     495            0 :       &ru->account,
     496            0 :       GNUNET_TIME_relative_multiply (ru->plugin->max_aml_program_runtime,
     497              :                                      2),
     498              :       &xlock);
     499            0 :     if (GNUNET_TIME_absolute_is_future (xlock))
     500              :     {
     501            0 :       struct TALER_KycCompletedEventP eh = {
     502            0 :         .header.size = htons (sizeof (eh)),
     503            0 :         .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED),
     504              :         .h_payto = ru->account
     505              :       };
     506              :       /* Wait for either timeout or notification */
     507            0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     508              :                   "AML program already running, waiting for it to finish\n");
     509            0 :       ru->plugin->rollback (ru->plugin->cls);
     510              :       ru->eh
     511            0 :         = ru->plugin->event_listen (
     512            0 :             ru->plugin->cls,
     513              :             GNUNET_TIME_absolute_get_remaining (xlock),
     514              :             &eh.header,
     515              :             &trigger_fetch_latest_rules,
     516              :             ru);
     517            0 :       return;
     518              :     }
     519            0 :     qs = ru->plugin->commit (ru->plugin->cls);
     520            0 :     if (qs < 0)
     521              :     {
     522            0 :       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
     523            0 :       fail_update (ru,
     524              :                    GNUNET_DB_STATUS_SOFT_ERROR == qs
     525              :                    ? TALER_EC_GENERIC_DB_SOFT_FAILURE
     526              :                    : TALER_EC_GENERIC_DB_COMMIT_FAILED,
     527              :                    "current-aml-rule-fetch");
     528            0 :       return;
     529              :     }
     530            0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     531              :                 "Check is of type 'SKIP', running AML program %s.\n",
     532              :                 m->prog_name);
     533            0 :     GNUNET_assert (NULL == ru->t);
     534            0 :     ru->amlh = TALER_KYCLOGIC_run_aml_program3 (
     535            0 :       ru->is_wallet,
     536              :       m,
     537              :       &TALER_EXCHANGEDB_current_attributes_builder,
     538              :       &hbc,
     539              :       &TALER_EXCHANGEDB_current_rule_builder,
     540              :       &hbc,
     541              :       &TALER_EXCHANGEDB_aml_history_builder,
     542              :       &hbc,
     543              :       &TALER_EXCHANGEDB_kyc_history_builder,
     544              :       &hbc,
     545            0 :       ru->plugin->max_aml_program_runtime,
     546              :       &aml_result_callback,
     547              :       ru);
     548            0 :     return;
     549              :   }
     550              : 
     551              :   /* User MUST pass interactive check */
     552            0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     553              :               "Measure %s involves check %s\n",
     554              :               m->measure_name,
     555              :               m->check_name);
     556              :   {
     557              :     /* activate the measure/check */
     558              :     json_t *succ_jmeasures
     559            0 :       = TALER_KYCLOGIC_get_jmeasures (
     560            0 :           ru->lrs,
     561            0 :           m->measure_name);
     562              :     bool unknown_account;
     563              :     struct GNUNET_TIME_Timestamp last_date;
     564              :     enum GNUNET_DB_QueryStatus qs;
     565              : 
     566            0 :     qs = ru->plugin->insert_successor_measure (
     567            0 :       ru->plugin->cls,
     568            0 :       &ru->account,
     569              :       GNUNET_TIME_timestamp_get (),
     570            0 :       m->measure_name,
     571              :       succ_jmeasures,
     572              :       &unknown_account,
     573              :       &last_date);
     574            0 :     json_decref (succ_jmeasures);
     575            0 :     switch (qs)
     576              :     {
     577            0 :     case GNUNET_DB_STATUS_SOFT_ERROR:
     578            0 :       GNUNET_log (
     579              :         GNUNET_ERROR_TYPE_INFO,
     580              :         "Serialization issue!\n");
     581            0 :       fail_update (ru,
     582              :                    TALER_EC_GENERIC_DB_SOFT_FAILURE,
     583              :                    "insert_successor_measure");
     584            0 :       return;
     585            0 :     case GNUNET_DB_STATUS_HARD_ERROR:
     586            0 :       GNUNET_break (0);
     587            0 :       fail_update (ru,
     588              :                    TALER_EC_GENERIC_DB_STORE_FAILED,
     589              :                    "insert_successor_measure");
     590            0 :       return;
     591            0 :     default:
     592            0 :       break;
     593              :     }
     594            0 :     if (unknown_account)
     595              :     {
     596            0 :       fail_update (ru,
     597              :                    TALER_EC_EXCHANGE_GENERIC_BANK_ACCOUNT_UNKNOWN,
     598              :                    NULL);
     599            0 :       return;
     600              :     }
     601              :   }
     602              :   /* The rules remain these rules until the user passes the check */
     603            0 :   return_result (ru);
     604              : }
     605              : 
     606              : 
     607              : /**
     608              :  * Update the expired legitimization rules in @a ru, checking for expiration
     609              :  * first.  Called with an open database transaction.
     610              :  *
     611              :  * @param[in,out] ru account we are processing
     612              :  */
     613              : static void
     614            0 : update_rules (struct TALER_EXCHANGEDB_RuleUpdater *ru)
     615              : {
     616              :   const struct TALER_KYCLOGIC_Measure *m;
     617              : 
     618            0 :   GNUNET_assert (NULL != ru->lrs);
     619            0 :   GNUNET_assert (GNUNET_TIME_absolute_is_past (
     620              :                    TALER_KYCLOGIC_rules_get_expiration (ru->lrs).abs_time));
     621            0 :   m = TALER_KYCLOGIC_rules_get_successor (ru->lrs);
     622            0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     623              :               "Successor measure is %s.\n",
     624              :               (NULL != m) ? m->measure_name : "(null)");
     625            0 :   run_measure (ru,
     626              :                m);
     627            0 : }
     628              : 
     629              : 
     630              : static void
     631           28 : check_rules (struct TALER_EXCHANGEDB_RuleUpdater *ru)
     632              : {
     633           28 :   ru->depth++;
     634           28 :   if (ru->depth > MAX_DEPTH)
     635              :   {
     636            0 :     fail_update (ru,
     637              :                  TALER_EC_EXCHANGE_GENERIC_AML_PROGRAM_RECURSION_DETECTED,
     638              :                  NULL);
     639            0 :     return;
     640              :   }
     641           28 :   if (NULL == ru->lrs)
     642              :   {
     643              :     /* return NULL, aka default rules */
     644           11 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     645              :                 "Default rules apply\n");
     646           11 :     return_result (ru);
     647           11 :     return;
     648              :   }
     649           17 :   if (! GNUNET_TIME_absolute_is_past
     650           17 :         (TALER_KYCLOGIC_rules_get_expiration (ru->lrs).abs_time) )
     651              :   {
     652              :     /* Rules did not expire, return them! */
     653           17 :     return_result (ru);
     654           17 :     return;
     655              :   }
     656            0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     657              :               "Custom rules expired, updating...\n");
     658            0 :   update_rules (ru);
     659              : }
     660              : 
     661              : 
     662              : static void
     663           28 : fetch_latest_rules (void *cls)
     664              : {
     665           28 :   struct TALER_EXCHANGEDB_RuleUpdater *ru = cls;
     666              :   enum GNUNET_DB_QueryStatus qs;
     667              :   json_t *jnew_rules;
     668              :   enum GNUNET_GenericReturnValue res;
     669              : 
     670           28 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     671              :               "Fetching latest rules.");
     672              : 
     673           28 :   ru->t = NULL;
     674           28 :   if (NULL != ru->eh)
     675              :   {
     676              :     /* cancel event listener, if we have one */
     677            0 :     ru->plugin->event_listen_cancel (ru->plugin->cls,
     678              :                                      ru->eh);
     679            0 :     ru->eh = NULL;
     680              :   }
     681           28 :   GNUNET_break (NULL == ru->lrs);
     682           28 :   res = ru->plugin->start (ru->plugin->cls,
     683              :                            "aml-begin-lookup-rules-by-access-token");
     684           28 :   if (GNUNET_OK != res)
     685              :   {
     686            0 :     GNUNET_break (0);
     687            0 :     fail_update (ru,
     688              :                  TALER_EC_GENERIC_DB_START_FAILED,
     689              :                  "aml-begin-lookup-rules-by-access-token");
     690            0 :     return;
     691              :   }
     692           28 :   qs = ru->plugin->lookup_rules_by_access_token (
     693           28 :     ru->plugin->cls,
     694           28 :     &ru->account,
     695              :     &jnew_rules,
     696              :     &ru->legitimization_outcome_last_row);
     697           28 :   if (qs < 0)
     698              :   {
     699            0 :     GNUNET_break (0);
     700            0 :     fail_update (ru,
     701              :                  TALER_EC_GENERIC_DB_FETCH_FAILED,
     702              :                  "lookup_rules_by_access_token");
     703            0 :     return;
     704              :   }
     705           28 :   if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) &&
     706           17 :        (NULL != jnew_rules) )
     707              :   {
     708           17 :     ru->lrs = TALER_KYCLOGIC_rules_parse (jnew_rules);
     709           17 :     GNUNET_break (NULL != ru->lrs);
     710           17 :     json_decref (jnew_rules);
     711              :   }
     712           28 :   check_rules (ru);
     713              : }
     714              : 
     715              : 
     716              : struct TALER_EXCHANGEDB_RuleUpdater *
     717           28 : TALER_EXCHANGEDB_update_rules (
     718              :   struct TALER_EXCHANGEDB_Plugin *plugin,
     719              :   const struct TALER_AttributeEncryptionKeyP *attribute_key,
     720              :   const struct TALER_NormalizedPaytoHashP *account,
     721              :   bool is_wallet,
     722              :   TALER_EXCHANGEDB_CurrentRulesCallback cb,
     723              :   void *cb_cls)
     724              : {
     725              :   struct TALER_EXCHANGEDB_RuleUpdater *ru;
     726              : 
     727           28 :   ru = GNUNET_new (struct TALER_EXCHANGEDB_RuleUpdater);
     728           28 :   ru->plugin = plugin;
     729           28 :   ru->attribute_key = *attribute_key;
     730           28 :   ru->account = *account;
     731           28 :   ru->is_wallet = is_wallet;
     732           28 :   ru->cb = cb;
     733           28 :   ru->cb_cls = cb_cls;
     734           28 :   ru->t = GNUNET_SCHEDULER_add_now (&fetch_latest_rules,
     735              :                                     ru);
     736           28 :   return ru;
     737              : }
     738              : 
     739              : 
     740              : void
     741           28 : TALER_EXCHANGEDB_update_rules_cancel (
     742              :   struct TALER_EXCHANGEDB_RuleUpdater *ru)
     743              : {
     744           28 :   if (NULL != ru->t)
     745              :   {
     746            0 :     GNUNET_SCHEDULER_cancel (ru->t);
     747            0 :     ru->t = NULL;
     748              :   }
     749           28 :   if (NULL != ru->amlh)
     750              :   {
     751            0 :     TALER_KYCLOGIC_run_aml_program_cancel (ru->amlh);
     752            0 :     ru->amlh = NULL;
     753              :   }
     754           28 :   if (NULL != ru->lrs)
     755              :   {
     756            0 :     TALER_KYCLOGIC_rules_free (ru->lrs);
     757            0 :     ru->lrs = NULL;
     758              :   }
     759           28 :   if (NULL != ru->eh)
     760              :   {
     761            0 :     ru->plugin->event_listen_cancel (ru->plugin->cls,
     762              :                                      ru->eh);
     763            0 :     ru->eh = NULL;
     764              :   }
     765           28 :   GNUNET_free (ru->aml_program_name);
     766           28 :   GNUNET_free (ru);
     767           28 : }
        

Generated by: LCOV version 2.0-1