exchange

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

update_rules.c (18182B)


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