exchange

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

kyclogic_api.c (142577B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2022-2025 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 kyclogic_api.c
     18  * @brief server-side KYC API
     19  * @author Christian Grothoff
     20  */
     21 #include "taler/platform.h"
     22 #include "taler/taler_json_lib.h"
     23 #include "taler/taler_kyclogic_lib.h"
     24 
     25 /**
     26  * Log verbosely, including possibly privacy-sensitive data.
     27  */
     28 #define DEBUG 1
     29 
     30 /**
     31  * Name of the KYC measure that may never be passed. Useful if some
     32  * operations/amounts are categorically forbidden.
     33  */
     34 #define KYC_MEASURE_IMPOSSIBLE "verboten"
     35 
     36 /**
     37  * Information about a KYC provider.
     38  */
     39 struct TALER_KYCLOGIC_KycProvider
     40 {
     41 
     42   /**
     43    * Name of the provider.
     44    */
     45   char *provider_name;
     46 
     47   /**
     48    * Logic to run for this provider.
     49    */
     50   struct TALER_KYCLOGIC_Plugin *logic;
     51 
     52   /**
     53    * Provider-specific details to pass to the @e logic functions.
     54    */
     55   struct TALER_KYCLOGIC_ProviderDetails *pd;
     56 
     57 };
     58 
     59 
     60 /**
     61  * Rule that triggers some measure(s).
     62  */
     63 struct TALER_KYCLOGIC_KycRule
     64 {
     65 
     66   /**
     67    * Name of the rule (configuration section name).
     68    * NULL if not from the configuration.
     69    */
     70   char *rule_name;
     71 
     72   /**
     73    * Rule set with custom measures that this KYC rule
     74    * is part of.
     75    */
     76   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs;
     77 
     78   /**
     79    * Timeframe to consider for computing the amount
     80    * to compare against the @e limit.  Zero for the
     81    * wallet balance trigger (as not applicable).
     82    */
     83   struct GNUNET_TIME_Relative timeframe;
     84 
     85   /**
     86    * Maximum amount that can be transacted until
     87    * the rule triggers.
     88    */
     89   struct TALER_Amount threshold;
     90 
     91   /**
     92    * Array of names of measures to apply on this trigger.
     93    */
     94   char **next_measures;
     95 
     96   /**
     97    * Length of the @e next_measures array.
     98    */
     99   unsigned int num_measures;
    100 
    101   /**
    102    * Display priority for this rule.
    103    */
    104   uint32_t display_priority;
    105 
    106   /**
    107    * What operation type is this rule for?
    108    */
    109   enum TALER_KYCLOGIC_KycTriggerEvent trigger;
    110 
    111   /**
    112    * True if all @e next_measures will eventually need to
    113    * be satisfied, False if the user has a choice between them.
    114    */
    115   bool is_and_combinator;
    116 
    117   /**
    118    * True if this rule and the general nature of the next measures
    119    * should be exposed to the client.
    120    */
    121   bool exposed;
    122 
    123   /**
    124    * True if any of the measures is 'verboten' and
    125    * thus this rule cannot ever be satisfied.
    126    */
    127   bool verboten;
    128 
    129 };
    130 
    131 
    132 /**
    133  * Set of rules that applies to an account.
    134  */
    135 struct TALER_KYCLOGIC_LegitimizationRuleSet
    136 {
    137 
    138   /**
    139    * When does this rule set expire?
    140    */
    141   struct GNUNET_TIME_Timestamp expiration_time;
    142 
    143   /**
    144    * Name of the successor measure after expiration.
    145    * NULL to revert to default rules.
    146    */
    147   char *successor_measure;
    148 
    149   /**
    150    * Array of the rules.
    151    */
    152   struct TALER_KYCLOGIC_KycRule *kyc_rules;
    153 
    154   /**
    155    * Array of custom measures the @e kyc_rules may refer
    156    * to.
    157    */
    158   struct TALER_KYCLOGIC_Measure *custom_measures;
    159 
    160   /**
    161    * Length of the @e kyc_rules array.
    162    */
    163   unsigned int num_kyc_rules;
    164 
    165   /**
    166    * Length of the @e custom_measures array.
    167    */
    168   unsigned int num_custom_measures;
    169 
    170 };
    171 
    172 
    173 /**
    174  * AML program inputs as per "-i" option of the AML program.
    175  * This is a bitmask.
    176  */
    177 enum AmlProgramInputs
    178 {
    179   /**
    180    * No inputs are needed.
    181    */
    182   API_NONE = 0,
    183 
    184   /**
    185    * Context is needed.
    186    */
    187   API_CONTEXT = 1,
    188 
    189   /**
    190    * Current (just submitted) attributes needed.
    191    */
    192   API_ATTRIBUTES = 2,
    193 
    194   /**
    195    * Current AML rules are needed.
    196    */
    197   API_CURRENT_RULES = 4,
    198 
    199   /**
    200    * Default AML rules (that apply to fresh accounts) are needed.
    201    */
    202   API_DEFAULT_RULES = 8,
    203 
    204   /**
    205    * Account AML history is needed, possibly length-limited,
    206    * see ``aml_history_length_limit``.
    207    */
    208   API_AML_HISTORY = 16,
    209 
    210   /**
    211    * Account KYC history is needed, possibly length-limited,
    212    * see ``kyc_history_length_limit``
    213    */
    214   API_KYC_HISTORY = 32,
    215 
    216 };
    217 
    218 
    219 /**
    220  * AML programs.
    221  */
    222 struct TALER_KYCLOGIC_AmlProgram
    223 {
    224 
    225   /**
    226    * Name of the AML program configuration section.
    227    */
    228   char *program_name;
    229 
    230   /**
    231    * Name of the AML program (binary) to run.
    232    */
    233   char *command;
    234 
    235   /**
    236    * Human-readable description of what this AML helper
    237    * program will do.
    238    */
    239   char *description;
    240 
    241   /**
    242    * Name of an original measure to take in case the
    243    * @e command fails, NULL to fallback to default rules.
    244    */
    245   char *fallback;
    246 
    247   /**
    248    * Output of @e command "-r".
    249    */
    250   char **required_contexts;
    251 
    252   /**
    253    * Length of the @e required_contexts array.
    254    */
    255   unsigned int num_required_contexts;
    256 
    257   /**
    258    * Output of @e command "-a".
    259    */
    260   char **required_attributes;
    261 
    262   /**
    263    * Length of the @e required_attributes array.
    264    */
    265   unsigned int num_required_attributes;
    266 
    267   /**
    268    * Bitmask of inputs this AML program would like (based on '-i').
    269    */
    270   enum AmlProgramInputs input_mask;
    271 
    272   /**
    273    * How many entries of the AML history are requested;
    274    * negative number if we want the latest entries only.
    275    */
    276   long long aml_history_length_limit;
    277 
    278   /**
    279    * How many entries of the KYC history are requested;
    280    * negative number if we want the latest entries only.
    281    */
    282   long long kyc_history_length_limit;
    283 
    284 };
    285 
    286 
    287 /**
    288  * Array of @e num_kyc_logics KYC logic plugins we have loaded.
    289  */
    290 static struct TALER_KYCLOGIC_Plugin **kyc_logics;
    291 
    292 /**
    293  * Length of the #kyc_logics array.
    294  */
    295 static unsigned int num_kyc_logics;
    296 
    297 /**
    298  * Array of configured providers.
    299  */
    300 static struct TALER_KYCLOGIC_KycProvider **kyc_providers;
    301 
    302 /**
    303  * Length of the #kyc_providers array.
    304  */
    305 static unsigned int num_kyc_providers;
    306 
    307 /**
    308  * Array of @e num_kyc_checks known types of
    309  * KYC checks.
    310  */
    311 static struct TALER_KYCLOGIC_KycCheck **kyc_checks;
    312 
    313 /**
    314  * Length of the #kyc_checks array.
    315  */
    316 static unsigned int num_kyc_checks;
    317 
    318 /**
    319  * Rules that apply if we do not have an AMLA record.
    320  */
    321 static struct TALER_KYCLOGIC_LegitimizationRuleSet default_rules;
    322 
    323 /**
    324  * Array of available AML programs.
    325  */
    326 static struct TALER_KYCLOGIC_AmlProgram **aml_programs;
    327 
    328 /**
    329  * Length of the #aml_programs array.
    330  */
    331 static unsigned int num_aml_programs;
    332 
    333 /**
    334  * Name of our configuration file.
    335  */
    336 static char *cfg_filename;
    337 
    338 /**
    339  * Currency we expect to see in all rules.
    340  */
    341 static char *my_currency;
    342 
    343 /**
    344  * Default LegitimizationRuleSet for wallets.  Excludes *default* measures
    345  * even if these are the default rules.
    346  */
    347 static json_t *wallet_default_lrs;
    348 
    349 /**
    350  * Default LegitimizationRuleSet for bank accounts.  Excludes *default* measures
    351  * even if these are the default rules.
    352  */
    353 static json_t *bankaccount_default_lrs;
    354 
    355 
    356 struct GNUNET_TIME_Timestamp
    357 TALER_KYCLOGIC_rules_get_expiration (
    358   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs)
    359 {
    360   if (NULL == lrs)
    361     return GNUNET_TIME_UNIT_FOREVER_TS;
    362   return lrs->expiration_time;
    363 }
    364 
    365 
    366 const struct TALER_KYCLOGIC_Measure *
    367 TALER_KYCLOGIC_rules_get_successor (
    368   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs)
    369 {
    370   const char *successor_measure_name = lrs->successor_measure;
    371 
    372   if (NULL == successor_measure_name)
    373   {
    374     return NULL;
    375   }
    376   return TALER_KYCLOGIC_get_measure (
    377     lrs,
    378     successor_measure_name);
    379 }
    380 
    381 
    382 /**
    383  * Check if @a trigger applies to our context.
    384  *
    385  * @param trigger the trigger to evaluate
    386  * @param is_wallet #GNUNET_YES if this is for a wallet,
    387  *         #GNUNET_NO for account,
    388  *         #GNUNET_SYSERR for unknown (returns all rules)
    389  * @return true if @a trigger applies in this context
    390  */
    391 static bool
    392 trigger_applies (enum TALER_KYCLOGIC_KycTriggerEvent trigger,
    393                  enum GNUNET_GenericReturnValue is_wallet)
    394 {
    395   switch (trigger)
    396   {
    397   case TALER_KYCLOGIC_KYC_TRIGGER_NONE:
    398     GNUNET_break (0);
    399     break;
    400   case TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW:
    401     return GNUNET_YES != is_wallet;
    402   case TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT:
    403     return GNUNET_YES != is_wallet;
    404   case TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE:
    405     return GNUNET_NO != is_wallet;
    406   case TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE:
    407     return GNUNET_NO != is_wallet;
    408   case TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE:
    409     return GNUNET_YES != is_wallet;
    410   case TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE:
    411     return GNUNET_YES != is_wallet;
    412   case TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION:
    413     return true;
    414   case TALER_KYCLOGIC_KYC_TRIGGER_REFUND:
    415     return true;
    416   }
    417   GNUNET_break (0);
    418   return true;
    419 }
    420 
    421 
    422 /**
    423  * Lookup a KYC check by @a check_name
    424  *
    425  * @param check_name name to search for
    426  * @return NULL if not found
    427  */
    428 static struct TALER_KYCLOGIC_KycCheck *
    429 find_check (const char *check_name)
    430 {
    431   for (unsigned int i = 0; i<num_kyc_checks; i++)
    432   {
    433     struct TALER_KYCLOGIC_KycCheck *kyc_check
    434       = kyc_checks[i];
    435 
    436     if (0 == strcasecmp (check_name,
    437                          kyc_check->check_name))
    438       return kyc_check;
    439   }
    440   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    441               "Check `%s' unknown\n",
    442               check_name);
    443   return NULL;
    444 }
    445 
    446 
    447 /**
    448  * Lookup AML program by @a program_name
    449  *
    450  * @param program_name name to search for
    451  * @return NULL if not found
    452  */
    453 static struct TALER_KYCLOGIC_AmlProgram *
    454 find_program (const char *program_name)
    455 {
    456   if (NULL == program_name)
    457   {
    458     GNUNET_break (0);
    459     return NULL;
    460   }
    461   for (unsigned int i = 0; i<num_aml_programs; i++)
    462   {
    463     struct TALER_KYCLOGIC_AmlProgram *program
    464       = aml_programs[i];
    465 
    466     if (0 == strcasecmp (program_name,
    467                          program->program_name))
    468       return program;
    469   }
    470   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    471               "AML program `%s' unknown\n",
    472               program_name);
    473   return NULL;
    474 }
    475 
    476 
    477 /**
    478  * Lookup KYC provider by @a provider_name
    479  *
    480  * @param provider_name name to search for
    481  * @return NULL if not found
    482  */
    483 static struct TALER_KYCLOGIC_KycProvider *
    484 find_provider (const char *provider_name)
    485 {
    486   for (unsigned int i = 0; i<num_kyc_providers; i++)
    487   {
    488     struct TALER_KYCLOGIC_KycProvider *provider
    489       = kyc_providers[i];
    490 
    491     if (0 == strcasecmp (provider_name,
    492                          provider->provider_name))
    493       return provider;
    494   }
    495   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    496               "KYC provider `%s' unknown\n",
    497               provider_name);
    498   return NULL;
    499 }
    500 
    501 
    502 /**
    503  * Check that @a measure is well-formed and internally
    504  * consistent.
    505  *
    506  * @param measure measure to check
    507  * @return true if measure is well-formed
    508  */
    509 static bool
    510 check_measure (const struct TALER_KYCLOGIC_Measure *measure)
    511 {
    512   const struct TALER_KYCLOGIC_KycCheck *check;
    513 
    514   check = find_check (measure->check_name);
    515   if ( (NULL == check) &&
    516        (0 != strcasecmp (measure->check_name,
    517                          "SKIP")) )
    518   {
    519     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    520                 "Unknown check `%s' used in measure `%s'\n",
    521                 measure->check_name,
    522                 measure->measure_name);
    523     return false;
    524   }
    525   if ( (NULL == check) ||
    526        (TALER_KYCLOGIC_CT_INFO != check->type) )
    527   {
    528     const struct TALER_KYCLOGIC_AmlProgram *program;
    529 
    530     program = find_program (measure->prog_name);
    531     if (NULL == program)
    532     {
    533       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    534                   "Unknown program `%s' used in measure `%s'\n",
    535                   measure->prog_name,
    536                   measure->measure_name);
    537       return false;
    538     }
    539     for (unsigned int j = 0; j<program->num_required_contexts; j++)
    540     {
    541       const char *required_context = program->required_contexts[j];
    542 
    543       if (NULL ==
    544           json_object_get (measure->context,
    545                            required_context))
    546       {
    547         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    548                     "Measure `%s' lacks required context `%s' for AML program `%s'\n",
    549                     measure->measure_name,
    550                     required_context,
    551                     program->program_name);
    552         return false;
    553       }
    554     }
    555     if (0 == strcasecmp (measure->check_name,
    556                          "SKIP"))
    557     {
    558       if (0 != program->num_required_attributes)
    559       {
    560         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    561                     "AML program `%s' of measure `%s' has required attributes, but check is of type `SKIP' and thus cannot provide any!\n",
    562                     program->program_name,
    563                     measure->measure_name);
    564         return false;
    565       }
    566       return true;
    567     }
    568     for (unsigned int j = 0; j<program->num_required_attributes; j++)
    569     {
    570       const char *required_attribute = program->required_attributes[j];
    571       bool found = false;
    572 
    573       if (NULL != check)
    574       {
    575         for (unsigned int i = 0; i<check->num_outputs; i++)
    576         {
    577           if (0 == strcasecmp (required_attribute,
    578                                check->outputs[i]))
    579           {
    580             found = true;
    581             break;
    582           }
    583         }
    584       }
    585       if (! found)
    586       {
    587         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    588                     "Check `%s' of measure `%s' does not provide required output `%s' for AML program `%s'\n",
    589                     measure->check_name,
    590                     measure->measure_name,
    591                     required_attribute,
    592                     program->program_name);
    593         return false;
    594       }
    595     }
    596   }
    597   else
    598   {
    599     /* Check is of type "INFO" */
    600     if (NULL != measure->prog_name)
    601       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    602                   "Program `%s' used in INFO measure `%s' will never be used.\n",
    603                   measure->prog_name,
    604                   measure->measure_name);
    605     if (0 == strcasecmp (measure->check_name,
    606                          "SKIP"))
    607     {
    608       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    609                   "INFO check of measure `%s' should not be called 'SKIP'.\n",
    610                   measure->measure_name);
    611       return false;
    612     }
    613   }
    614   if (NULL != check)
    615   {
    616     for (unsigned int j = 0; j<check->num_requires; j++)
    617     {
    618       const char *required_input = check->requires[j];
    619 
    620       if (NULL ==
    621           json_object_get (measure->context,
    622                            required_input))
    623       {
    624         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    625                     "Measure `%s' lacks required context `%s' for check `%s'\n",
    626                     measure->measure_name,
    627                     required_input,
    628                     measure->check_name);
    629         return false;
    630       }
    631     }
    632   }
    633   return true;
    634 }
    635 
    636 
    637 /**
    638  * Find measure @a measure_name in @a lrs.
    639  * If measure is not found in @a lrs, fall back to
    640  * default measures.
    641  *
    642  * @param lrs rule set to search, can be NULL to only search default measures
    643  * @param measure_name name of measure to find
    644  * @return NULL if not found, otherwise the measure
    645  */
    646 static const struct TALER_KYCLOGIC_Measure *
    647 find_measure (
    648   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
    649   const char *measure_name)
    650 {
    651   if (NULL != lrs)
    652   {
    653     for (unsigned int i = 0; i<lrs->num_custom_measures; i++)
    654     {
    655       const struct TALER_KYCLOGIC_Measure *cm
    656         = &lrs->custom_measures[i];
    657 
    658       if (0 == strcasecmp (measure_name,
    659                            cm->measure_name))
    660         return cm;
    661     }
    662   }
    663   if (lrs != &default_rules)
    664   {
    665     /* Try measures from default rules */
    666     for (unsigned int i = 0; i<default_rules.num_custom_measures; i++)
    667     {
    668       const struct TALER_KYCLOGIC_Measure *cm
    669         = &default_rules.custom_measures[i];
    670 
    671       if (0 == strcasecmp (measure_name,
    672                            cm->measure_name))
    673         return cm;
    674     }
    675   }
    676   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    677               "Measure `%s' not found\n",
    678               measure_name);
    679   return NULL;
    680 }
    681 
    682 
    683 struct TALER_KYCLOGIC_LegitimizationRuleSet *
    684 TALER_KYCLOGIC_rules_parse (const json_t *jlrs)
    685 {
    686   struct GNUNET_TIME_Timestamp expiration_time;
    687   const char *successor_measure = NULL;
    688   const json_t *jrules;
    689   const json_t *jcustom_measures;
    690   struct GNUNET_JSON_Specification spec[] = {
    691     GNUNET_JSON_spec_timestamp (
    692       "expiration_time",
    693       &expiration_time),
    694     GNUNET_JSON_spec_mark_optional (
    695       GNUNET_JSON_spec_string (
    696         "successor_measure",
    697         &successor_measure),
    698       NULL),
    699     GNUNET_JSON_spec_array_const ("rules",
    700                                   &jrules),
    701     GNUNET_JSON_spec_object_const ("custom_measures",
    702                                    &jcustom_measures),
    703     GNUNET_JSON_spec_end ()
    704   };
    705   struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs;
    706   const char *err;
    707   unsigned int line;
    708 
    709   if (NULL == jlrs)
    710   {
    711     GNUNET_break_op (0);
    712     return NULL;
    713   }
    714   if (GNUNET_OK !=
    715       GNUNET_JSON_parse (jlrs,
    716                          spec,
    717                          &err,
    718                          &line))
    719   {
    720     GNUNET_break_op (0);
    721     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    722                 "Legitimization rules have incorrect input field `%s'\n",
    723                 err);
    724     json_dumpf (jlrs,
    725                 stderr,
    726                 JSON_INDENT (2));
    727     return NULL;
    728   }
    729   lrs = GNUNET_new (struct TALER_KYCLOGIC_LegitimizationRuleSet);
    730   lrs->expiration_time = expiration_time;
    731   lrs->successor_measure
    732     = (NULL == successor_measure)
    733     ? NULL
    734     : GNUNET_strdup (successor_measure);
    735   lrs->num_custom_measures
    736     = (unsigned int) json_object_size (jcustom_measures);
    737   if (((size_t) lrs->num_custom_measures) !=
    738       json_object_size (jcustom_measures))
    739   {
    740     GNUNET_break (0);
    741     goto cleanup;
    742   }
    743 
    744   if (0 != lrs->num_custom_measures)
    745   {
    746     lrs->custom_measures
    747       = GNUNET_new_array (lrs->num_custom_measures,
    748                           struct TALER_KYCLOGIC_Measure);
    749 
    750     {
    751       const json_t *jmeasure;
    752       const char *measure_name;
    753       unsigned int off = 0;
    754 
    755       json_object_foreach ((json_t *) jcustom_measures,
    756                            measure_name,
    757                            jmeasure)
    758       {
    759         const char *check_name;
    760         const char *prog_name = NULL;
    761         const json_t *context = NULL;
    762         bool voluntary = false;
    763         struct TALER_KYCLOGIC_Measure *measure
    764           = &lrs->custom_measures[off++];
    765         struct GNUNET_JSON_Specification ispec[] = {
    766           GNUNET_JSON_spec_string ("check_name",
    767                                    &check_name),
    768           GNUNET_JSON_spec_mark_optional (
    769             GNUNET_JSON_spec_string ("prog_name",
    770                                      &prog_name),
    771             NULL),
    772           GNUNET_JSON_spec_mark_optional (
    773             GNUNET_JSON_spec_object_const ("context",
    774                                            &context),
    775             NULL),
    776           GNUNET_JSON_spec_mark_optional (
    777             GNUNET_JSON_spec_bool ("voluntary",
    778                                    &voluntary),
    779             NULL),
    780           GNUNET_JSON_spec_end ()
    781         };
    782 
    783         if (GNUNET_OK !=
    784             GNUNET_JSON_parse (jmeasure,
    785                                ispec,
    786                                NULL, NULL))
    787         {
    788           GNUNET_break_op (0);
    789           goto cleanup;
    790         }
    791         measure->measure_name
    792           = GNUNET_strdup (measure_name);
    793         measure->check_name
    794           = GNUNET_strdup (check_name);
    795         if (NULL != prog_name)
    796           measure->prog_name
    797             = GNUNET_strdup (prog_name);
    798         measure->voluntary
    799           = voluntary;
    800         if (NULL != context)
    801           measure->context
    802             = json_incref ((json_t*) context);
    803         if (! check_measure (measure))
    804         {
    805           GNUNET_break_op (0);
    806           goto cleanup;
    807         }
    808       }
    809     }
    810   }
    811 
    812   lrs->num_kyc_rules
    813     = (unsigned int) json_array_size (jrules);
    814   if (((size_t) lrs->num_kyc_rules) !=
    815       json_array_size (jrules))
    816   {
    817     GNUNET_break (0);
    818     goto cleanup;
    819   }
    820   lrs->kyc_rules
    821     = GNUNET_new_array (lrs->num_kyc_rules,
    822                         struct TALER_KYCLOGIC_KycRule);
    823   {
    824     const json_t *jrule;
    825     size_t off;
    826 
    827     json_array_foreach ((json_t *) jrules,
    828                         off,
    829                         jrule)
    830     {
    831       struct TALER_KYCLOGIC_KycRule *rule
    832         = &lrs->kyc_rules[off];
    833       const json_t *jmeasures;
    834       const char *rn = NULL;
    835       struct GNUNET_JSON_Specification ispec[] = {
    836         TALER_JSON_spec_kycte ("operation_type",
    837                                &rule->trigger),
    838         TALER_JSON_spec_amount ("threshold",
    839                                 my_currency,
    840                                 &rule->threshold),
    841         GNUNET_JSON_spec_relative_time ("timeframe",
    842                                         &rule->timeframe),
    843         GNUNET_JSON_spec_array_const ("measures",
    844                                       &jmeasures),
    845         GNUNET_JSON_spec_uint32 ("display_priority",
    846                                  &rule->display_priority),
    847         GNUNET_JSON_spec_mark_optional (
    848           GNUNET_JSON_spec_bool ("exposed",
    849                                  &rule->exposed),
    850           NULL),
    851         GNUNET_JSON_spec_mark_optional (
    852           GNUNET_JSON_spec_string ("rule_name",
    853                                    &rn),
    854           NULL),
    855         GNUNET_JSON_spec_mark_optional (
    856           GNUNET_JSON_spec_bool ("is_and_combinator",
    857                                  &rule->is_and_combinator),
    858           NULL),
    859         GNUNET_JSON_spec_end ()
    860       };
    861 
    862       if (GNUNET_OK !=
    863           GNUNET_JSON_parse (jrule,
    864                              ispec,
    865                              NULL, NULL))
    866       {
    867         GNUNET_break_op (0);
    868         goto cleanup;
    869       }
    870       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    871                   "Parsed KYC rule %u for %d with threshold %s\n",
    872                   (unsigned int) off,
    873                   (int) rule->trigger,
    874                   TALER_amount2s (&rule->threshold));
    875       rule->lrs = lrs;
    876       if (NULL != rn)
    877         rule->rule_name = GNUNET_strdup (rn);
    878       rule->num_measures = json_array_size (jmeasures);
    879       rule->next_measures
    880         = GNUNET_new_array (rule->num_measures,
    881                             char *);
    882       if (((size_t) rule->num_measures) !=
    883           json_array_size (jmeasures))
    884       {
    885         GNUNET_break (0);
    886         goto cleanup;
    887       }
    888       {
    889         size_t j;
    890         json_t *jmeasure;
    891 
    892         json_array_foreach (jmeasures,
    893                             j,
    894                             jmeasure)
    895         {
    896           const char *str;
    897 
    898           str = json_string_value (jmeasure);
    899           if (NULL == str)
    900           {
    901             GNUNET_break (0);
    902             goto cleanup;
    903           }
    904           if (0 == strcasecmp (str,
    905                                KYC_MEASURE_IMPOSSIBLE))
    906           {
    907             rule->verboten = true;
    908             continue;
    909           }
    910           else if (NULL ==
    911                    find_measure (lrs,
    912                                  str))
    913           {
    914             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    915                         "Measure `%s' specified in rule set unknown\n",
    916                         str);
    917             GNUNET_break_op (0);
    918             goto cleanup;
    919           }
    920           rule->next_measures[j]
    921             = GNUNET_strdup (str);
    922         }
    923       }
    924     }
    925   }
    926   return lrs;
    927 cleanup:
    928   TALER_KYCLOGIC_rules_free (lrs);
    929   return NULL;
    930 }
    931 
    932 
    933 void
    934 TALER_KYCLOGIC_rules_free (struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs)
    935 {
    936   if (NULL == lrs)
    937     return;
    938   for (unsigned int i = 0; i<lrs->num_kyc_rules; i++)
    939   {
    940     struct TALER_KYCLOGIC_KycRule *rule
    941       = &lrs->kyc_rules[i];
    942 
    943     for (unsigned int j = 0; j<rule->num_measures; j++)
    944       GNUNET_free (rule->next_measures[j]);
    945     GNUNET_free (rule->next_measures);
    946     GNUNET_free (rule->rule_name);
    947   }
    948   for (unsigned int i = 0; i<lrs->num_custom_measures; i++)
    949   {
    950     struct TALER_KYCLOGIC_Measure *measure
    951       = &lrs->custom_measures[i];
    952 
    953     GNUNET_free (measure->measure_name);
    954     GNUNET_free (measure->check_name);
    955     GNUNET_free (measure->prog_name);
    956     json_decref (measure->context);
    957   }
    958   GNUNET_free (lrs->kyc_rules);
    959   GNUNET_free (lrs->custom_measures);
    960   GNUNET_free (lrs->successor_measure);
    961   GNUNET_free (lrs);
    962 }
    963 
    964 
    965 const char *
    966 TALER_KYCLOGIC_rule2s (
    967   const struct TALER_KYCLOGIC_KycRule *r)
    968 {
    969   return r->rule_name;
    970 }
    971 
    972 
    973 const char *
    974 TALER_KYCLOGIC_status2s (enum TALER_KYCLOGIC_KycStatus status)
    975 {
    976   switch (status)
    977   {
    978   case TALER_KYCLOGIC_STATUS_SUCCESS:
    979     return "success";
    980   case TALER_KYCLOGIC_STATUS_USER:
    981     return "user";
    982   case TALER_KYCLOGIC_STATUS_PROVIDER:
    983     return "provider";
    984   case TALER_KYCLOGIC_STATUS_FAILED:
    985     return "failed";
    986   case TALER_KYCLOGIC_STATUS_PENDING:
    987     return "pending";
    988   case TALER_KYCLOGIC_STATUS_ABORTED:
    989     return "aborted";
    990   case TALER_KYCLOGIC_STATUS_USER_PENDING:
    991     return "pending with user";
    992   case TALER_KYCLOGIC_STATUS_PROVIDER_PENDING:
    993     return "pending at provider";
    994   case TALER_KYCLOGIC_STATUS_USER_ABORTED:
    995     return "aborted by user";
    996   case TALER_KYCLOGIC_STATUS_PROVIDER_FAILED:
    997     return "failed by provider";
    998   case TALER_KYCLOGIC_STATUS_KEEP:
    999     return "keep";
   1000   case TALER_KYCLOGIC_STATUS_INTERNAL_ERROR:
   1001     return "internal error";
   1002   }
   1003   return "unknown status";
   1004 }
   1005 
   1006 
   1007 json_t *
   1008 TALER_KYCLOGIC_rules_to_limits (const json_t *jrules,
   1009                                 enum GNUNET_GenericReturnValue is_wallet)
   1010 {
   1011   if (NULL == jrules)
   1012   {
   1013     /* default limits apply */
   1014     const struct TALER_KYCLOGIC_KycRule *rules
   1015       = default_rules.kyc_rules;
   1016     unsigned int num_rules
   1017       = default_rules.num_kyc_rules;
   1018     json_t *jlimits;
   1019 
   1020     jlimits = json_array ();
   1021     GNUNET_assert (NULL != jlimits);
   1022     for (unsigned int i = 0; i<num_rules; i++)
   1023     {
   1024       const struct TALER_KYCLOGIC_KycRule *rule = &rules[i];
   1025       json_t *limit;
   1026 
   1027       if (! rule->exposed)
   1028         continue;
   1029       if (! trigger_applies (rule->trigger,
   1030                              is_wallet))
   1031         continue;
   1032       limit = GNUNET_JSON_PACK (
   1033         GNUNET_JSON_pack_allow_null (
   1034           GNUNET_JSON_pack_string ("rule_name",
   1035                                    rule->rule_name)),
   1036         GNUNET_JSON_pack_bool ("soft_limit",
   1037                                ! rule->verboten),
   1038         TALER_JSON_pack_kycte ("operation_type",
   1039                                rule->trigger),
   1040         GNUNET_JSON_pack_time_rel ("timeframe",
   1041                                    rule->timeframe),
   1042         TALER_JSON_pack_amount ("threshold",
   1043                                 &rule->threshold)
   1044         );
   1045       GNUNET_assert (0 ==
   1046                      json_array_append_new (jlimits,
   1047                                             limit));
   1048     }
   1049     return jlimits;
   1050   }
   1051 
   1052   {
   1053     const json_t *rules;
   1054     json_t *limits;
   1055     json_t *limit;
   1056     json_t *rule;
   1057     size_t idx;
   1058 
   1059     rules = json_object_get (jrules,
   1060                              "rules");
   1061     limits = json_array ();
   1062     GNUNET_assert (NULL != limits);
   1063     json_array_foreach ((json_t *) rules, idx, rule)
   1064     {
   1065       struct GNUNET_TIME_Relative timeframe;
   1066       struct TALER_Amount threshold;
   1067       bool exposed = false;
   1068       const json_t *jmeasures;
   1069       const char *rule_name;
   1070       enum TALER_KYCLOGIC_KycTriggerEvent operation_type;
   1071       struct GNUNET_JSON_Specification spec[] = {
   1072         TALER_JSON_spec_kycte ("operation_type",
   1073                                &operation_type),
   1074         GNUNET_JSON_spec_relative_time ("timeframe",
   1075                                         &timeframe),
   1076         TALER_JSON_spec_amount ("threshold",
   1077                                 my_currency,
   1078                                 &threshold),
   1079         GNUNET_JSON_spec_array_const ("measures",
   1080                                       &jmeasures),
   1081         GNUNET_JSON_spec_mark_optional (
   1082           GNUNET_JSON_spec_bool ("exposed",
   1083                                  &exposed),
   1084           NULL),
   1085         GNUNET_JSON_spec_mark_optional (
   1086           GNUNET_JSON_spec_string ("rule_name",
   1087                                    &rule_name),
   1088           NULL),
   1089         GNUNET_JSON_spec_end ()
   1090       };
   1091       bool forbidden = false;
   1092       size_t i;
   1093       json_t *jmeasure;
   1094 
   1095       if (GNUNET_OK !=
   1096           GNUNET_JSON_parse (rule,
   1097                              spec,
   1098                              NULL, NULL))
   1099       {
   1100         GNUNET_break_op (0);
   1101         json_decref (limits);
   1102         return NULL;
   1103       }
   1104       if (! exposed)
   1105         continue;
   1106       if (! trigger_applies (operation_type,
   1107                              is_wallet))
   1108       {
   1109         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1110                     "Skipping rule #%u that does not apply to %s\n",
   1111                     (unsigned int) idx,
   1112                     is_wallet ? "wallets" : "accounts");
   1113         json_dumpf (rule,
   1114                     stderr,
   1115                     JSON_INDENT (2));
   1116         continue;
   1117       }
   1118       json_array_foreach (jmeasures, i, jmeasure)
   1119       {
   1120         const char *val;
   1121 
   1122         val = json_string_value (jmeasure);
   1123         if (NULL == val)
   1124         {
   1125           GNUNET_break_op (0);
   1126           json_decref (limits);
   1127           return NULL;
   1128         }
   1129         if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE,
   1130                              val))
   1131           forbidden = true;
   1132       }
   1133 
   1134       limit = GNUNET_JSON_PACK (
   1135         GNUNET_JSON_pack_allow_null (
   1136           GNUNET_JSON_pack_string ("rule_name",
   1137                                    rule_name)),
   1138         TALER_JSON_pack_kycte (
   1139           "operation_type",
   1140           operation_type),
   1141         GNUNET_JSON_pack_time_rel (
   1142           "timeframe",
   1143           timeframe),
   1144         TALER_JSON_pack_amount (
   1145           "threshold",
   1146           &threshold),
   1147         /* optional since v21, defaults to 'false' */
   1148         GNUNET_JSON_pack_bool (
   1149           "soft_limit",
   1150           ! forbidden));
   1151       GNUNET_assert (0 ==
   1152                      json_array_append_new (limits,
   1153                                             limit));
   1154     }
   1155     return limits;
   1156   }
   1157 }
   1158 
   1159 
   1160 const struct TALER_KYCLOGIC_Measure *
   1161 TALER_KYCLOGIC_rule_get_instant_measure (
   1162   const struct TALER_KYCLOGIC_KycRule *r)
   1163 {
   1164   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs
   1165     = r->lrs;
   1166 
   1167   if (r->verboten)
   1168     return NULL;
   1169   for (unsigned int i = 0; i<r->num_measures; i++)
   1170   {
   1171     const char *measure_name = r->next_measures[i];
   1172     const struct TALER_KYCLOGIC_Measure *ms;
   1173 
   1174     if (0 == strcasecmp (measure_name,
   1175                          KYC_MEASURE_IMPOSSIBLE))
   1176     {
   1177       /* If any of the measures if verboten, we do not even
   1178       consider execution of the instant measure. */
   1179       return NULL;
   1180     }
   1181 
   1182     ms = find_measure (lrs,
   1183                        measure_name);
   1184     if (NULL == ms)
   1185     {
   1186       GNUNET_break (0);
   1187       return NULL;
   1188     }
   1189     if (0 == strcasecmp (ms->check_name,
   1190                          "SKIP"))
   1191       return ms;
   1192   }
   1193   return NULL;
   1194 }
   1195 
   1196 
   1197 json_t *
   1198 TALER_KYCLOGIC_rule_to_measures (
   1199   const struct TALER_KYCLOGIC_KycRule *r)
   1200 {
   1201   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs
   1202     = r->lrs;
   1203   json_t *jmeasures;
   1204 
   1205   jmeasures = json_array ();
   1206   GNUNET_assert (NULL != jmeasures);
   1207   if (! r->verboten)
   1208   {
   1209     for (unsigned int i = 0; i<r->num_measures; i++)
   1210     {
   1211       const char *measure_name = r->next_measures[i];
   1212       const struct TALER_KYCLOGIC_Measure *ms;
   1213       json_t *mi;
   1214 
   1215       if (0 ==
   1216           strcasecmp (measure_name,
   1217                       KYC_MEASURE_IMPOSSIBLE))
   1218       {
   1219         /* This case should be covered via the 'verboten' flag! */
   1220         GNUNET_break (0);
   1221         continue;
   1222       }
   1223       ms = find_measure (lrs,
   1224                          measure_name);
   1225       if (NULL == ms)
   1226       {
   1227         GNUNET_break (0);
   1228         json_decref (jmeasures);
   1229         return NULL;
   1230       }
   1231       mi = GNUNET_JSON_PACK (
   1232         GNUNET_JSON_pack_string ("check_name",
   1233                                  ms->check_name),
   1234         GNUNET_JSON_pack_allow_null (
   1235           GNUNET_JSON_pack_string ("prog_name",
   1236                                    ms->prog_name)),
   1237         GNUNET_JSON_pack_allow_null (
   1238           GNUNET_JSON_pack_object_incref ("context",
   1239                                           ms->context)));
   1240       GNUNET_assert (0 ==
   1241                      json_array_append_new (jmeasures,
   1242                                             mi));
   1243     }
   1244   }
   1245 
   1246   return GNUNET_JSON_PACK (
   1247     GNUNET_JSON_pack_array_steal ("measures",
   1248                                   jmeasures),
   1249     GNUNET_JSON_pack_bool ("is_and_combinator",
   1250                            r->is_and_combinator),
   1251     GNUNET_JSON_pack_bool ("verboten",
   1252                            r->verboten));
   1253 }
   1254 
   1255 
   1256 json_t *
   1257 TALER_KYCLOGIC_zero_measures (
   1258   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
   1259   enum GNUNET_GenericReturnValue is_wallet)
   1260 {
   1261   json_t *zero_measures;
   1262   const struct TALER_KYCLOGIC_KycRule *rules;
   1263   unsigned int num_zero_measures = 0;
   1264 
   1265   if (NULL == lrs)
   1266     lrs = &default_rules;
   1267   rules = lrs->kyc_rules;
   1268   zero_measures = json_array ();
   1269   GNUNET_assert (NULL != zero_measures);
   1270   for (unsigned int i = 0; i<lrs->num_kyc_rules; i++)
   1271   {
   1272     const struct TALER_KYCLOGIC_KycRule *rule = &rules[i];
   1273 
   1274     if (! rule->exposed)
   1275       continue;
   1276     if (rule->verboten)
   1277       continue; /* see: hard_limits */
   1278     if (! trigger_applies (rule->trigger,
   1279                            is_wallet))
   1280       continue;
   1281     if (! TALER_amount_is_zero (&rule->threshold))
   1282       continue;
   1283     for (unsigned int j = 0; j<rule->num_measures; j++)
   1284     {
   1285       const struct TALER_KYCLOGIC_Measure *ms;
   1286       json_t *mi;
   1287 
   1288       ms = find_measure (lrs,
   1289                          rule->next_measures[j]);
   1290       if (NULL == ms)
   1291       {
   1292         /* Error in the configuration, should've been
   1293          * caught before. We simply ignore the bad measure. */
   1294         GNUNET_break (0);
   1295         continue;
   1296       }
   1297       if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE,
   1298                            ms->check_name))
   1299         continue; /* not a measure to be selected */
   1300       mi = GNUNET_JSON_PACK (
   1301         GNUNET_JSON_pack_allow_null (
   1302           GNUNET_JSON_pack_string ("rule_name",
   1303                                    rule->rule_name)),
   1304         TALER_JSON_pack_kycte ("operation_type",
   1305                                rule->trigger),
   1306         GNUNET_JSON_pack_string ("check_name",
   1307                                  ms->check_name),
   1308         GNUNET_JSON_pack_allow_null (
   1309           GNUNET_JSON_pack_string ("prog_name",
   1310                                    ms->prog_name)),
   1311         GNUNET_JSON_pack_allow_null (
   1312           GNUNET_JSON_pack_object_incref ("context",
   1313                                           ms->context)));
   1314       GNUNET_assert (0 ==
   1315                      json_array_append_new (zero_measures,
   1316                                             mi));
   1317       num_zero_measures++;
   1318     }
   1319   }
   1320   if (0 == num_zero_measures)
   1321   {
   1322     json_decref (zero_measures);
   1323     return NULL;
   1324   }
   1325   return GNUNET_JSON_PACK (
   1326     GNUNET_JSON_pack_array_steal ("measures",
   1327                                   zero_measures),
   1328     /* Zero-measures are always OR */
   1329     GNUNET_JSON_pack_bool ("is_and_combinator",
   1330                            false),
   1331     /* OR means verboten measures do not matter */
   1332     GNUNET_JSON_pack_bool ("verboten",
   1333                            false));
   1334 }
   1335 
   1336 
   1337 /**
   1338  * Check if @a ms is a voluntary measure, and if so
   1339  * convert to JSON and append to @a voluntary_measures.
   1340  *
   1341  * @param[in,out] voluntary_measures JSON array of MeasureInformation
   1342  * @param ms a measure to possibly append
   1343  */
   1344 static void
   1345 append_voluntary_measure (
   1346   json_t *voluntary_measures,
   1347   const struct TALER_KYCLOGIC_Measure *ms)
   1348 {
   1349 #if 0
   1350   json_t *mj;
   1351 #endif
   1352 
   1353   if (! ms->voluntary)
   1354     return;
   1355   if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE,
   1356                        ms->check_name))
   1357     return; /* very strange configuration */
   1358 #if 0
   1359   /* FIXME: support vATTEST-#9048 (this API in kyclogic!) */
   1360   // NOTE: need to convert ms to "KycRequirementInformation"
   1361   // *and* in particular generate "id" values that
   1362   // are then understood to refer to the voluntary measures
   1363   // by the rest of the API (which is the hard part!)
   1364   // => need to change the API to encode the
   1365   // legitimization_outcomes row ID of the lrs from
   1366   // which the voluntary 'ms' originated, and
   1367   // then update the kyc-upload/kyc-start endpoints
   1368   // to recognize the new ID format!
   1369   mj = GNUNET_JSON_PACK (
   1370     GNUNET_JSON_pack_string ("check_name",
   1371                              ms->check_name),
   1372     GNUNET_JSON_pack_allow_null (
   1373       GNUNET_JSON_pack_string ("prog_name",
   1374                                ms->prog_name)),
   1375     GNUNET_JSON_pack_allow_null (
   1376       GNUNET_JSON_pack_object_incref ("context",
   1377                                       ms->context)));
   1378   GNUNET_assert (0 ==
   1379                  json_array_append_new (voluntary_measures,
   1380                                         mj));
   1381 #endif
   1382 }
   1383 
   1384 
   1385 json_t *
   1386 TALER_KYCLOGIC_voluntary_measures (
   1387   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs)
   1388 {
   1389   json_t *voluntary_measures;
   1390 
   1391   voluntary_measures = json_array ();
   1392   GNUNET_assert (NULL != voluntary_measures);
   1393   if (NULL != lrs)
   1394   {
   1395     for (unsigned int i = 0; i<lrs->num_custom_measures; i++)
   1396     {
   1397       const struct TALER_KYCLOGIC_Measure *ms
   1398         = &lrs->custom_measures[i];
   1399 
   1400       append_voluntary_measure (voluntary_measures,
   1401                                 ms);
   1402     }
   1403   }
   1404   for (unsigned int i = 0; i<default_rules.num_custom_measures; i++)
   1405   {
   1406     const struct TALER_KYCLOGIC_Measure *ms
   1407       = &default_rules.custom_measures[i];
   1408 
   1409     append_voluntary_measure (voluntary_measures,
   1410                               ms);
   1411   }
   1412   return voluntary_measures;
   1413 }
   1414 
   1415 
   1416 const struct TALER_KYCLOGIC_Measure *
   1417 TALER_KYCLOGIC_get_instant_measure (
   1418   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
   1419   const char *measures_spec)
   1420 {
   1421   char *nm;
   1422   const struct TALER_KYCLOGIC_Measure *ret = NULL;
   1423 
   1424   GNUNET_assert (NULL != measures_spec);
   1425 
   1426   if ('+' == measures_spec[0])
   1427   {
   1428     nm = GNUNET_strdup (&measures_spec[1]);
   1429   }
   1430   else
   1431   {
   1432     nm = GNUNET_strdup (measures_spec);
   1433   }
   1434   for (const char *tok = strtok (nm, " ");
   1435        NULL != tok;
   1436        tok = strtok (NULL, " "))
   1437   {
   1438     const struct TALER_KYCLOGIC_Measure *ms;
   1439 
   1440     if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE,
   1441                          tok))
   1442     {
   1443       continue;
   1444     }
   1445     ms = find_measure (lrs,
   1446                        tok);
   1447     if (NULL == ms)
   1448     {
   1449       GNUNET_break (0);
   1450       continue;
   1451     }
   1452     if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE,
   1453                          ms->check_name))
   1454     {
   1455       continue;
   1456     }
   1457     if (0 == strcasecmp ("SKIP",
   1458                          ms->check_name))
   1459     {
   1460       ret = ms;
   1461       goto done;
   1462     }
   1463   }
   1464 done:
   1465   GNUNET_free (nm);
   1466   return ret;
   1467 }
   1468 
   1469 
   1470 const struct TALER_KYCLOGIC_Measure *
   1471 TALER_KYCLOGIC_get_measure (
   1472   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
   1473   const char *measure_name)
   1474 {
   1475   return find_measure (lrs,
   1476                        measure_name);
   1477 }
   1478 
   1479 
   1480 json_t *
   1481 TALER_KYCLOGIC_get_jmeasures (
   1482   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
   1483   const char *measures_spec)
   1484 {
   1485   json_t *jmeasures;
   1486   char *nm;
   1487   bool verboten = false;
   1488   bool is_and = false;
   1489 
   1490   if ('+' == measures_spec[0])
   1491   {
   1492     nm = GNUNET_strdup (&measures_spec[1]);
   1493     is_and = true;
   1494   }
   1495   else
   1496   {
   1497     nm = GNUNET_strdup (measures_spec);
   1498   }
   1499   jmeasures = json_array ();
   1500   GNUNET_assert (NULL != jmeasures);
   1501   for (const char *tok = strtok (nm, " ");
   1502        NULL != tok;
   1503        tok = strtok (NULL, " "))
   1504   {
   1505     const struct TALER_KYCLOGIC_Measure *ms;
   1506     json_t *mi;
   1507 
   1508     if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE,
   1509                          tok))
   1510     {
   1511       verboten = true;
   1512       continue;
   1513     }
   1514     ms = find_measure (lrs,
   1515                        tok);
   1516     if (NULL == ms)
   1517     {
   1518       GNUNET_break (0);
   1519       GNUNET_free (nm);
   1520       json_decref (jmeasures);
   1521       return NULL;
   1522     }
   1523     mi = GNUNET_JSON_PACK (
   1524       GNUNET_JSON_pack_string ("check_name",
   1525                                ms->check_name),
   1526       GNUNET_JSON_pack_allow_null (
   1527         GNUNET_JSON_pack_string ("prog_name",
   1528                                  ms->prog_name)),
   1529       GNUNET_JSON_pack_allow_null (
   1530         GNUNET_JSON_pack_object_incref ("context",
   1531                                         ms->context)));
   1532     GNUNET_assert (0 ==
   1533                    json_array_append_new (jmeasures,
   1534                                           mi));
   1535   }
   1536   GNUNET_free (nm);
   1537   return GNUNET_JSON_PACK (
   1538     GNUNET_JSON_pack_array_steal ("measures",
   1539                                   jmeasures),
   1540     GNUNET_JSON_pack_bool ("is_and_combinator",
   1541                            is_and),
   1542     GNUNET_JSON_pack_bool ("verboten",
   1543                            verboten));
   1544 }
   1545 
   1546 
   1547 json_t *
   1548 TALER_KYCLOGIC_check_to_jmeasures (
   1549   const struct TALER_KYCLOGIC_KycCheckContext *kcc)
   1550 {
   1551   const struct TALER_KYCLOGIC_KycCheck *check
   1552     = kcc->check;
   1553   json_t *jmeasures;
   1554   json_t *mi;
   1555 
   1556   mi = GNUNET_JSON_PACK (
   1557     GNUNET_JSON_pack_string ("check_name",
   1558                              NULL == check
   1559                              ? "SKIP"
   1560                              : check->check_name),
   1561     GNUNET_JSON_pack_allow_null (
   1562       GNUNET_JSON_pack_string ("prog_name",
   1563                                kcc->prog_name)),
   1564     GNUNET_JSON_pack_allow_null (
   1565       GNUNET_JSON_pack_object_incref ("context",
   1566                                       (json_t *) kcc->context)));
   1567   jmeasures = json_array ();
   1568   GNUNET_assert (NULL != jmeasures);
   1569   GNUNET_assert (0 ==
   1570                  json_array_append_new (jmeasures,
   1571                                         mi));
   1572   return GNUNET_JSON_PACK (
   1573     GNUNET_JSON_pack_array_steal ("measures",
   1574                                   jmeasures),
   1575     GNUNET_JSON_pack_bool ("is_and_combinator",
   1576                            true),
   1577     GNUNET_JSON_pack_bool ("verboten",
   1578                            false));
   1579 }
   1580 
   1581 
   1582 json_t *
   1583 TALER_KYCLOGIC_measure_to_jmeasures (
   1584   const struct TALER_KYCLOGIC_Measure *m)
   1585 {
   1586   json_t *jmeasures;
   1587   json_t *mi;
   1588 
   1589   mi = GNUNET_JSON_PACK (
   1590     GNUNET_JSON_pack_string ("check_name",
   1591                              m->check_name),
   1592     GNUNET_JSON_pack_allow_null (
   1593       GNUNET_JSON_pack_string ("prog_name",
   1594                                m->prog_name)),
   1595     GNUNET_JSON_pack_allow_null (
   1596       GNUNET_JSON_pack_object_incref ("context",
   1597                                       (json_t *) m->context)));
   1598   jmeasures = json_array ();
   1599   GNUNET_assert (NULL != jmeasures);
   1600   GNUNET_assert (0 ==
   1601                  json_array_append_new (jmeasures,
   1602                                         mi));
   1603   return GNUNET_JSON_PACK (
   1604     GNUNET_JSON_pack_array_steal ("measures",
   1605                                   jmeasures),
   1606     GNUNET_JSON_pack_bool ("is_and_combinator",
   1607                            false),
   1608     GNUNET_JSON_pack_bool ("verboten",
   1609                            false));
   1610 }
   1611 
   1612 
   1613 uint32_t
   1614 TALER_KYCLOGIC_rule2priority (
   1615   const struct TALER_KYCLOGIC_KycRule *r)
   1616 {
   1617   return r->display_priority;
   1618 }
   1619 
   1620 
   1621 /**
   1622  * Perform very primitive word splitting of a command.
   1623  *
   1624  * @param command command to split
   1625  * @param extra_args extra arguments to append after the word
   1626  * @returns NULL-terminated array of words
   1627  */
   1628 static char **
   1629 split_words (const char *command,
   1630              const char **extra_args)
   1631 {
   1632   unsigned int i = 0;
   1633   unsigned int j = 0;
   1634   unsigned int n = 0;
   1635   char **res = NULL;
   1636 
   1637   /* Result is always NULL-terminated */
   1638   GNUNET_array_append (res, n, NULL);
   1639 
   1640   /* Split command into words */
   1641   while (1)
   1642   {
   1643     char *c;
   1644 
   1645     /* Skip initial whitespace before word */
   1646     while (' ' == command[i])
   1647       i++;
   1648 
   1649     /* Start of new word */
   1650     j = i;
   1651 
   1652     /* Scan to end of word */
   1653     while ( (0 != command[j]) && (' ' != command[j]) )
   1654       j++;
   1655 
   1656     /* No new word found */
   1657     if (i == j)
   1658       break;
   1659 
   1660     /* Append word to result */
   1661     c = GNUNET_malloc (j - i + 1);
   1662     memcpy (c, &command[i], j - i);
   1663     c[j - i] = 0;
   1664     res[n - 1] = c;
   1665     GNUNET_array_append (res, n, NULL);
   1666 
   1667     /* Continue at end of word */
   1668     i = j;
   1669   }
   1670 
   1671   /* Append extra args */
   1672   if (NULL != extra_args)
   1673   {
   1674     for (const char **m = extra_args; *m; m++)
   1675     {
   1676       res[n - 1] = GNUNET_strdup (*m);
   1677       GNUNET_array_append (res, n, NULL);
   1678     }
   1679   }
   1680 
   1681   return res;
   1682 }
   1683 
   1684 
   1685 /**
   1686  * Free arguments allocated with split_words.
   1687  *
   1688  * @param args NULL-terminated array of strings to free.
   1689  */
   1690 static void
   1691 destroy_words (char **args)
   1692 {
   1693   if (NULL == args)
   1694     return;
   1695   for (char **m = args; *m; m++)
   1696   {
   1697     GNUNET_free (*m);
   1698     *m = NULL;
   1699   }
   1700   GNUNET_free (args);
   1701 }
   1702 
   1703 
   1704 /**
   1705  * Run @a command with @a argument and return the
   1706  * respective output from stdout.
   1707  *
   1708  * @param command binary to run
   1709  * @param argument command-line argument to pass
   1710  * @return NULL if @a command failed
   1711  */
   1712 static char *
   1713 command_output (const char *command,
   1714                 const char *argument)
   1715 {
   1716   char *rval;
   1717   unsigned int sval;
   1718   size_t soff;
   1719   ssize_t ret;
   1720   int sout[2];
   1721   pid_t chld;
   1722   const char *extra_args[] = {
   1723     argument,
   1724     "-c",
   1725     cfg_filename,
   1726     NULL,
   1727   };
   1728 
   1729   if (0 != pipe (sout))
   1730   {
   1731     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
   1732                          "pipe");
   1733     return NULL;
   1734   }
   1735   chld = fork ();
   1736   if (-1 == chld)
   1737   {
   1738     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
   1739                          "fork");
   1740     return NULL;
   1741   }
   1742   if (0 == chld)
   1743   {
   1744     char **argv;
   1745 
   1746     argv = split_words (command,
   1747                         extra_args);
   1748 
   1749     GNUNET_break (0 ==
   1750                   close (sout[0]));
   1751     GNUNET_break (0 ==
   1752                   close (STDOUT_FILENO));
   1753     GNUNET_assert (STDOUT_FILENO ==
   1754                    dup2 (sout[1],
   1755                          STDOUT_FILENO));
   1756     GNUNET_break (0 ==
   1757                   close (sout[1]));
   1758     execvp (argv[0],
   1759             argv);
   1760     destroy_words (argv);
   1761     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
   1762                               "exec",
   1763                               command);
   1764     exit (EXIT_FAILURE);
   1765   }
   1766   GNUNET_break (0 ==
   1767                 close (sout[1]));
   1768   sval = 1024;
   1769   rval = GNUNET_malloc (sval);
   1770   soff = 0;
   1771   while (0 < (ret = read (sout[0],
   1772                           rval + soff,
   1773                           sval - soff)) )
   1774   {
   1775     soff += ret;
   1776     if (soff == sval)
   1777     {
   1778       GNUNET_array_grow (rval,
   1779                          sval,
   1780                          sval * 2);
   1781     }
   1782   }
   1783   GNUNET_break (0 == close (sout[0]));
   1784   {
   1785     int wstatus;
   1786 
   1787     GNUNET_break (chld ==
   1788                   waitpid (chld,
   1789                            &wstatus,
   1790                            0));
   1791     if ( (! WIFEXITED (wstatus)) ||
   1792          (0 != WEXITSTATUS (wstatus)) )
   1793     {
   1794       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1795                   "Command `%s' %s failed with status %d\n",
   1796                   command,
   1797                   argument,
   1798                   wstatus);
   1799       GNUNET_array_grow (rval,
   1800                          sval,
   1801                          0);
   1802       return NULL;
   1803     }
   1804   }
   1805   GNUNET_array_grow (rval,
   1806                      sval,
   1807                      soff + 1);
   1808   rval[soff] = '\0';
   1809   return rval;
   1810 }
   1811 
   1812 
   1813 /**
   1814  * Convert check type @a ctype_s into @a ctype.
   1815  *
   1816  * @param ctype_s check type as a string
   1817  * @param[out] ctype set to check type as enum
   1818  * @return #GNUNET_OK on success
   1819  */
   1820 static enum GNUNET_GenericReturnValue
   1821 check_type_from_string (
   1822   const char *ctype_s,
   1823   enum TALER_KYCLOGIC_CheckType *ctype)
   1824 {
   1825   struct
   1826   {
   1827     const char *in;
   1828     enum TALER_KYCLOGIC_CheckType out;
   1829   } map [] = {
   1830     { "INFO", TALER_KYCLOGIC_CT_INFO },
   1831     { "LINK", TALER_KYCLOGIC_CT_LINK },
   1832     { "FORM", TALER_KYCLOGIC_CT_FORM  },
   1833     { NULL, 0 }
   1834   };
   1835 
   1836   for (unsigned int i = 0; NULL != map[i].in; i++)
   1837     if (0 == strcasecmp (map[i].in,
   1838                          ctype_s))
   1839     {
   1840       *ctype = map[i].out;
   1841       return GNUNET_OK;
   1842     }
   1843   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1844               "Invalid check type `%s'\n",
   1845               ctype_s);
   1846   return GNUNET_SYSERR;
   1847 }
   1848 
   1849 
   1850 enum GNUNET_GenericReturnValue
   1851 TALER_KYCLOGIC_kyc_trigger_from_string (
   1852   const char *trigger_s,
   1853   enum TALER_KYCLOGIC_KycTriggerEvent *trigger)
   1854 {
   1855   /* NOTE: if you change this, also change
   1856      the code in src/json/json_helper.c! */
   1857   struct
   1858   {
   1859     const char *in;
   1860     enum TALER_KYCLOGIC_KycTriggerEvent out;
   1861   } map [] = {
   1862     { "WITHDRAW", TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW },
   1863     { "DEPOSIT", TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT  },
   1864     { "MERGE", TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE },
   1865     { "BALANCE", TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE },
   1866     { "CLOSE", TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE },
   1867     { "AGGREGATE", TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE },
   1868     { "TRANSACTION", TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION },
   1869     { "REFUND", TALER_KYCLOGIC_KYC_TRIGGER_REFUND },
   1870     { NULL, 0 }
   1871   };
   1872 
   1873   for (unsigned int i = 0; NULL != map[i].in; i++)
   1874     if (0 == strcasecmp (map[i].in,
   1875                          trigger_s))
   1876     {
   1877       *trigger = map[i].out;
   1878       return GNUNET_OK;
   1879     }
   1880   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1881               "Invalid KYC trigger `%s'\n",
   1882               trigger_s);
   1883   return GNUNET_SYSERR;
   1884 }
   1885 
   1886 
   1887 json_t *
   1888 TALER_KYCLOGIC_get_wallet_thresholds (void)
   1889 {
   1890   json_t *ret;
   1891 
   1892   ret = json_array ();
   1893   GNUNET_assert (NULL != ret);
   1894   for (unsigned int i = 0; i<default_rules.num_kyc_rules; i++)
   1895   {
   1896     struct TALER_KYCLOGIC_KycRule *rule
   1897       = &default_rules.kyc_rules[i];
   1898 
   1899     if (TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE != rule->trigger)
   1900       continue;
   1901     GNUNET_assert (
   1902       0 ==
   1903       json_array_append_new (
   1904         ret,
   1905         TALER_JSON_from_amount (
   1906           &rule->threshold)));
   1907   }
   1908   return ret;
   1909 }
   1910 
   1911 
   1912 /**
   1913  * Load KYC logic plugin.
   1914  *
   1915  * @param cfg configuration to use
   1916  * @param name name of the plugin
   1917  * @return NULL on error
   1918  */
   1919 static struct TALER_KYCLOGIC_Plugin *
   1920 load_logic (const struct GNUNET_CONFIGURATION_Handle *cfg,
   1921             const char *name)
   1922 {
   1923   char *lib_name;
   1924   struct TALER_KYCLOGIC_Plugin *plugin;
   1925 
   1926 
   1927   GNUNET_asprintf (&lib_name,
   1928                    "libtaler_plugin_kyclogic_%s",
   1929                    name);
   1930   for (unsigned int i = 0; i<num_kyc_logics; i++)
   1931     if (0 == strcasecmp (lib_name,
   1932                          kyc_logics[i]->library_name))
   1933     {
   1934       GNUNET_free (lib_name);
   1935       return kyc_logics[i];
   1936     }
   1937   plugin = GNUNET_PLUGIN_load (TALER_EXCHANGE_project_data (),
   1938                                lib_name,
   1939                                (void *) cfg);
   1940   if (NULL == plugin)
   1941   {
   1942     GNUNET_free (lib_name);
   1943     return NULL;
   1944   }
   1945   plugin->library_name = lib_name;
   1946   plugin->name = GNUNET_strdup (name);
   1947   GNUNET_array_append (kyc_logics,
   1948                        num_kyc_logics,
   1949                        plugin);
   1950   return plugin;
   1951 }
   1952 
   1953 
   1954 /**
   1955  * Parse configuration of a KYC provider.
   1956  *
   1957  * @param cfg configuration to parse
   1958  * @param section name of the section to analyze
   1959  * @return #GNUNET_OK on success
   1960  */
   1961 static enum GNUNET_GenericReturnValue
   1962 add_provider (const struct GNUNET_CONFIGURATION_Handle *cfg,
   1963               const char *section)
   1964 {
   1965   char *logic;
   1966   struct TALER_KYCLOGIC_Plugin *lp;
   1967   struct TALER_KYCLOGIC_ProviderDetails *pd;
   1968 
   1969   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1970               "Parsing KYC provider %s\n",
   1971               section);
   1972   if (GNUNET_OK !=
   1973       GNUNET_CONFIGURATION_get_value_string (cfg,
   1974                                              section,
   1975                                              "LOGIC",
   1976                                              &logic))
   1977   {
   1978     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   1979                                section,
   1980                                "LOGIC");
   1981     return GNUNET_SYSERR;
   1982   }
   1983   lp = load_logic (cfg,
   1984                    logic);
   1985   if (NULL == lp)
   1986   {
   1987     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   1988                                section,
   1989                                "LOGIC",
   1990                                "logic plugin could not be loaded");
   1991     GNUNET_free (logic);
   1992     return GNUNET_SYSERR;
   1993   }
   1994   GNUNET_free (logic);
   1995   pd = lp->load_configuration (lp->cls,
   1996                                section);
   1997   if (NULL == pd)
   1998     return GNUNET_SYSERR;
   1999 
   2000   {
   2001     struct TALER_KYCLOGIC_KycProvider *kp;
   2002 
   2003     kp = GNUNET_new (struct TALER_KYCLOGIC_KycProvider);
   2004     kp->provider_name
   2005       = GNUNET_strdup (&section[strlen ("kyc-provider-")]);
   2006     kp->logic = lp;
   2007     kp->pd = pd;
   2008     GNUNET_array_append (kyc_providers,
   2009                          num_kyc_providers,
   2010                          kp);
   2011   }
   2012   return GNUNET_OK;
   2013 }
   2014 
   2015 
   2016 /**
   2017  * Tokenize @a input along @a token
   2018  * and build an array of the tokens.
   2019  *
   2020  * @param[in,out] input the input to tokenize; clobbered
   2021  * @param sep separator between tokens to separate @a input on
   2022  * @param[out] p_strs where to put array of tokens
   2023  * @param[out] num_strs set to length of @a p_strs array
   2024  */
   2025 static void
   2026 add_tokens (char *input,
   2027             const char *sep,
   2028             char ***p_strs,
   2029             unsigned int *num_strs)
   2030 {
   2031   char *sptr;
   2032   char **rstr = NULL;
   2033   unsigned int num_rstr = 0;
   2034 
   2035   for (char *tok = strtok_r (input, sep, &sptr);
   2036        NULL != tok;
   2037        tok = strtok_r (NULL, sep, &sptr))
   2038   {
   2039     GNUNET_array_append (rstr,
   2040                          num_rstr,
   2041                          GNUNET_strdup (tok));
   2042   }
   2043   *p_strs = rstr;
   2044   *num_strs = num_rstr;
   2045 }
   2046 
   2047 
   2048 /**
   2049  * Closure for the handle_XXX_section functions
   2050  * that parse configuration sections matching certain
   2051  * prefixes.
   2052  */
   2053 struct SectionContext
   2054 {
   2055   /**
   2056    * Configuration to handle.
   2057    */
   2058   const struct GNUNET_CONFIGURATION_Handle *cfg;
   2059 
   2060   /**
   2061    * Result to return, set to false on failures.
   2062    */
   2063   bool result;
   2064 };
   2065 
   2066 
   2067 /**
   2068  * Function to iterate over configuration sections.
   2069  *
   2070  * @param cls a `struct SectionContext *`
   2071  * @param section name of the section
   2072  */
   2073 static void
   2074 handle_provider_section (void *cls,
   2075                          const char *section)
   2076 {
   2077   struct SectionContext *sc = cls;
   2078 
   2079   if (! sc->result)
   2080     return;
   2081   if (0 == strncasecmp (section,
   2082                         "kyc-provider-",
   2083                         strlen ("kyc-provider-")))
   2084   {
   2085     if (GNUNET_OK !=
   2086         add_provider (sc->cfg,
   2087                       section))
   2088     {
   2089       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2090                   "Setup failed in configuration section `%s'\n",
   2091                   section);
   2092       sc->result = false;
   2093     }
   2094     return;
   2095   }
   2096 }
   2097 
   2098 
   2099 /**
   2100  * Parse configuration @a cfg in section @a section for
   2101  * the specification of a KYC check.
   2102  *
   2103  * @param cfg configuration to parse
   2104  * @param section configuration section to parse
   2105  * @return #GNUNET_OK on success
   2106  */
   2107 static enum GNUNET_GenericReturnValue
   2108 add_check (const struct GNUNET_CONFIGURATION_Handle *cfg,
   2109            const char *section)
   2110 {
   2111   enum TALER_KYCLOGIC_CheckType ct;
   2112   char *description = NULL;
   2113   json_t *description_i18n = NULL;
   2114   char *requires = NULL;
   2115   char *outputs = NULL;
   2116   char *fallback = NULL;
   2117 
   2118   if (0 == strcasecmp (&section[strlen ("kyc-check-")],
   2119                        "SKIP"))
   2120   {
   2121     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2122                 "The kyc-check-skip section must not exist, 'skip' is reserved name for a built-in check\n");
   2123     return GNUNET_SYSERR;
   2124   }
   2125   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2126               "Parsing KYC check %s\n",
   2127               section);
   2128   {
   2129     char *type_s;
   2130 
   2131     if (GNUNET_OK !=
   2132         GNUNET_CONFIGURATION_get_value_string (cfg,
   2133                                                section,
   2134                                                "TYPE",
   2135                                                &type_s))
   2136     {
   2137       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2138                                  section,
   2139                                  "TYPE");
   2140       return GNUNET_SYSERR;
   2141     }
   2142     if (GNUNET_OK !=
   2143         check_type_from_string (type_s,
   2144                                 &ct))
   2145     {
   2146       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2147                                  section,
   2148                                  "TYPE",
   2149                                  "valid check type required");
   2150       GNUNET_free (type_s);
   2151       return GNUNET_SYSERR;
   2152     }
   2153     GNUNET_free (type_s);
   2154   }
   2155 
   2156   if (GNUNET_OK !=
   2157       GNUNET_CONFIGURATION_get_value_string (cfg,
   2158                                              section,
   2159                                              "DESCRIPTION",
   2160                                              &description))
   2161   {
   2162     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2163                                section,
   2164                                "DESCRIPTION");
   2165     goto fail;
   2166   }
   2167 
   2168   {
   2169     char *tmp;
   2170 
   2171     if (GNUNET_OK ==
   2172         GNUNET_CONFIGURATION_get_value_string (cfg,
   2173                                                section,
   2174                                                "DESCRIPTION_I18N",
   2175                                                &tmp))
   2176     {
   2177       json_error_t err;
   2178 
   2179       description_i18n = json_loads (tmp,
   2180                                      JSON_REJECT_DUPLICATES,
   2181                                      &err);
   2182       GNUNET_free (tmp);
   2183       if (NULL == description_i18n)
   2184       {
   2185         GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2186                                    section,
   2187                                    "DESCRIPTION_I18N",
   2188                                    err.text);
   2189         goto fail;
   2190       }
   2191       if (! TALER_JSON_check_i18n (description_i18n) )
   2192       {
   2193         GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2194                                    section,
   2195                                    "DESCRIPTION_I18N",
   2196                                    "JSON with internationalization map required");
   2197         goto fail;
   2198       }
   2199     }
   2200   }
   2201 
   2202   if (GNUNET_OK !=
   2203       GNUNET_CONFIGURATION_get_value_string (cfg,
   2204                                              section,
   2205                                              "REQUIRES",
   2206                                              &requires))
   2207   {
   2208     /* no requirements is OK */
   2209     requires = GNUNET_strdup ("");
   2210   }
   2211 
   2212   if (GNUNET_OK !=
   2213       GNUNET_CONFIGURATION_get_value_string (cfg,
   2214                                              section,
   2215                                              "OUTPUTS",
   2216                                              &outputs))
   2217   {
   2218     /* no outputs is OK */
   2219     outputs = GNUNET_strdup ("");
   2220   }
   2221 
   2222   if (GNUNET_OK !=
   2223       GNUNET_CONFIGURATION_get_value_string (cfg,
   2224                                              section,
   2225                                              "FALLBACK",
   2226                                              &fallback))
   2227   {
   2228     /* We do *not* allow NULL to fall back to default rules because fallbacks
   2229        are used when there is actually a serious error and thus some action
   2230        (usually an investigation) is always in order, and that's basically
   2231        never the default. And as fallbacks should be rare, we really insist on
   2232        them at least being explicitly configured. Otherwise these errors may
   2233        go undetected simply because someone forgot to configure a fallback and
   2234        then nothing happens. */
   2235     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2236                                section,
   2237                                "FALLBACK");
   2238     goto fail;
   2239   }
   2240 
   2241   {
   2242     struct TALER_KYCLOGIC_KycCheck *kc;
   2243 
   2244     kc = GNUNET_new (struct TALER_KYCLOGIC_KycCheck);
   2245     switch (ct)
   2246     {
   2247     case TALER_KYCLOGIC_CT_INFO:
   2248       /* nothing to do */
   2249       break;
   2250     case TALER_KYCLOGIC_CT_FORM:
   2251       {
   2252         char *form_name;
   2253 
   2254         if (GNUNET_OK !=
   2255             GNUNET_CONFIGURATION_get_value_string (cfg,
   2256                                                    section,
   2257                                                    "FORM_NAME",
   2258                                                    &form_name))
   2259         {
   2260           GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2261                                      section,
   2262                                      "FORM_NAME");
   2263           GNUNET_free (requires);
   2264           GNUNET_free (outputs);
   2265           GNUNET_free (kc);
   2266           return GNUNET_SYSERR;
   2267         }
   2268         kc->details.form.name = form_name;
   2269       }
   2270       break;
   2271     case TALER_KYCLOGIC_CT_LINK:
   2272       {
   2273         char *provider_id;
   2274 
   2275         if (GNUNET_OK !=
   2276             GNUNET_CONFIGURATION_get_value_string (cfg,
   2277                                                    section,
   2278                                                    "PROVIDER_ID",
   2279                                                    &provider_id))
   2280         {
   2281           GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2282                                      section,
   2283                                      "PROVIDER_ID");
   2284           GNUNET_free (requires);
   2285           GNUNET_free (outputs);
   2286           GNUNET_free (kc);
   2287           return GNUNET_SYSERR;
   2288         }
   2289         kc->details.link.provider = find_provider (provider_id);
   2290         if (NULL == kc->details.link.provider)
   2291         {
   2292           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2293                       "Unknown KYC provider `%s' used in check `%s'\n",
   2294                       provider_id,
   2295                       &section[strlen ("kyc-check-")]);
   2296           GNUNET_free (provider_id);
   2297           GNUNET_free (requires);
   2298           GNUNET_free (outputs);
   2299           GNUNET_free (kc);
   2300           return GNUNET_SYSERR;
   2301         }
   2302         GNUNET_free (provider_id);
   2303       }
   2304       break;
   2305     }
   2306     kc->check_name = GNUNET_strdup (&section[strlen ("kyc-check-")]);
   2307     kc->description = description;
   2308     kc->description_i18n = description_i18n;
   2309     kc->fallback = fallback;
   2310     kc->type = ct;
   2311     add_tokens (requires,
   2312                 "; \n\t",
   2313                 &kc->requires,
   2314                 &kc->num_requires);
   2315     GNUNET_free (requires);
   2316     add_tokens (outputs,
   2317                 "; \n\t",
   2318                 &kc->outputs,
   2319                 &kc->num_outputs);
   2320     GNUNET_free (outputs);
   2321     GNUNET_array_append (kyc_checks,
   2322                          num_kyc_checks,
   2323                          kc);
   2324   }
   2325 
   2326   return GNUNET_OK;
   2327 fail:
   2328   GNUNET_free (description);
   2329   json_decref (description_i18n);
   2330   GNUNET_free (requires);
   2331   GNUNET_free (outputs);
   2332   GNUNET_free (fallback);
   2333   return GNUNET_SYSERR;
   2334 }
   2335 
   2336 
   2337 /**
   2338  * Function to iterate over configuration sections.
   2339  *
   2340  * @param cls a `struct SectionContext *`
   2341  * @param section name of the section
   2342  */
   2343 static void
   2344 handle_check_section (void *cls,
   2345                       const char *section)
   2346 {
   2347   struct SectionContext *sc = cls;
   2348 
   2349   if (! sc->result)
   2350     return;
   2351   if (0 == strncasecmp (section,
   2352                         "kyc-check-",
   2353                         strlen ("kyc-check-")))
   2354   {
   2355     if (GNUNET_OK !=
   2356         add_check (sc->cfg,
   2357                    section))
   2358       sc->result = false;
   2359   }
   2360 }
   2361 
   2362 
   2363 /**
   2364  * Parse configuration @a cfg in section @a section for
   2365  * the specification of a KYC rule.
   2366  *
   2367  * @param cfg configuration to parse
   2368  * @param section configuration section to parse
   2369  * @return #GNUNET_OK on success
   2370  */
   2371 static enum GNUNET_GenericReturnValue
   2372 add_rule (const struct GNUNET_CONFIGURATION_Handle *cfg,
   2373           const char *section)
   2374 {
   2375   struct TALER_Amount threshold;
   2376   struct GNUNET_TIME_Relative timeframe;
   2377   enum TALER_KYCLOGIC_KycTriggerEvent ot;
   2378   char *measures;
   2379   bool exposed;
   2380   bool is_and;
   2381 
   2382   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2383               "Parsing KYC rule from %s\n",
   2384               section);
   2385   if (GNUNET_YES !=
   2386       GNUNET_CONFIGURATION_get_value_yesno (cfg,
   2387                                             section,
   2388                                             "ENABLED"))
   2389     return GNUNET_OK;
   2390   if (GNUNET_OK !=
   2391       TALER_config_get_amount (cfg,
   2392                                section,
   2393                                "THRESHOLD",
   2394                                &threshold))
   2395   {
   2396     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2397                                section,
   2398                                "THRESHOLD",
   2399                                "amount required");
   2400     return GNUNET_SYSERR;
   2401   }
   2402   exposed = (GNUNET_YES ==
   2403              GNUNET_CONFIGURATION_get_value_yesno (cfg,
   2404                                                    section,
   2405                                                    "EXPOSED"));
   2406   {
   2407     enum GNUNET_GenericReturnValue r;
   2408 
   2409     r = GNUNET_CONFIGURATION_get_value_yesno (cfg,
   2410                                               section,
   2411                                               "IS_AND_COMBINATOR");
   2412     if (GNUNET_SYSERR == r)
   2413     {
   2414       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2415                                  section,
   2416                                  "IS_AND_COMBINATOR",
   2417                                  "YES or NO required");
   2418       return GNUNET_SYSERR;
   2419     }
   2420     is_and = (GNUNET_YES == r);
   2421   }
   2422 
   2423   {
   2424     char *ot_s;
   2425 
   2426     if (GNUNET_OK !=
   2427         GNUNET_CONFIGURATION_get_value_string (cfg,
   2428                                                section,
   2429                                                "OPERATION_TYPE",
   2430                                                &ot_s))
   2431     {
   2432       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2433                                  section,
   2434                                  "OPERATION_TYPE");
   2435       return GNUNET_SYSERR;
   2436     }
   2437     if (GNUNET_OK !=
   2438         TALER_KYCLOGIC_kyc_trigger_from_string (ot_s,
   2439                                                 &ot))
   2440     {
   2441       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2442                                  section,
   2443                                  "OPERATION_TYPE",
   2444                                  "valid trigger type required");
   2445       GNUNET_free (ot_s);
   2446       return GNUNET_SYSERR;
   2447     }
   2448     GNUNET_free (ot_s);
   2449   }
   2450 
   2451   if (GNUNET_OK !=
   2452       GNUNET_CONFIGURATION_get_value_time (cfg,
   2453                                            section,
   2454                                            "TIMEFRAME",
   2455                                            &timeframe))
   2456   {
   2457     if (TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE == ot)
   2458     {
   2459       timeframe = GNUNET_TIME_UNIT_ZERO;
   2460     }
   2461     else
   2462     {
   2463       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2464                                  section,
   2465                                  "TIMEFRAME",
   2466                                  "duration required");
   2467       return GNUNET_SYSERR;
   2468     }
   2469   }
   2470   if (GNUNET_OK !=
   2471       GNUNET_CONFIGURATION_get_value_string (cfg,
   2472                                              section,
   2473                                              "NEXT_MEASURES",
   2474                                              &measures))
   2475   {
   2476     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2477                                section,
   2478                                "NEXT_MEASURES");
   2479     return GNUNET_SYSERR;
   2480   }
   2481 
   2482   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2483               "Adding KYC rule %s for trigger %d with threshold %s\n",
   2484               section,
   2485               (int) ot,
   2486               TALER_amount2s (&threshold));
   2487   {
   2488     struct TALER_KYCLOGIC_KycRule kt = {
   2489       .lrs = &default_rules,
   2490       .rule_name = GNUNET_strdup (&section[strlen ("kyc-rule-")]),
   2491       .timeframe = timeframe,
   2492       .threshold = threshold,
   2493       .trigger = ot,
   2494       .is_and_combinator = is_and,
   2495       .exposed = exposed,
   2496       .display_priority = 0,
   2497       .verboten = false
   2498     };
   2499 
   2500     add_tokens (measures,
   2501                 "; \n\t",
   2502                 &kt.next_measures,
   2503                 &kt.num_measures);
   2504     for (unsigned int i=0; i<kt.num_measures; i++)
   2505       if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE,
   2506                            kt.next_measures[i]))
   2507         kt.verboten = true;
   2508     GNUNET_free (measures);
   2509     GNUNET_array_append (default_rules.kyc_rules,
   2510                          default_rules.num_kyc_rules,
   2511                          kt);
   2512   }
   2513   return GNUNET_OK;
   2514 }
   2515 
   2516 
   2517 /**
   2518  * Function to iterate over configuration sections.
   2519  *
   2520  * @param cls a `struct SectionContext *`
   2521  * @param section name of the section
   2522  */
   2523 static void
   2524 handle_rule_section (void *cls,
   2525                      const char *section)
   2526 {
   2527   struct SectionContext *sc = cls;
   2528 
   2529   if (! sc->result)
   2530     return;
   2531   if (0 == strncasecmp (section,
   2532                         "kyc-rule-",
   2533                         strlen ("kyc-rule-")))
   2534   {
   2535     if (GNUNET_OK !=
   2536         add_rule (sc->cfg,
   2537                   section))
   2538       sc->result = false;
   2539   }
   2540 }
   2541 
   2542 
   2543 /**
   2544  * Parse array dimension argument of @a tok (if present)
   2545  * and store result in @a dimp. Does nothing if
   2546  * @a tok does not contain '['. Otherwise does some input
   2547  * validation.
   2548  *
   2549  * @param section name of configuration section for logging
   2550  * @param tok input to parse, of form "text[$DIM]"
   2551  * @param[out] dimp set to value of $DIM
   2552  * @return true on success
   2553  */
   2554 static bool
   2555 parse_dim (const char *section,
   2556            const char *tok,
   2557            long long *dimp)
   2558 {
   2559   const char *dim = strchr (tok,
   2560                             '[');
   2561   char dummy;
   2562 
   2563   if (NULL == dim)
   2564     return true;
   2565   if (1 !=
   2566       sscanf (dim,
   2567               "[%lld]%c",
   2568               dimp,
   2569               &dummy))
   2570   {
   2571     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2572                                section,
   2573                                "COMMAND",
   2574                                "output for -i invalid (bad dimension given)");
   2575     return false;
   2576   }
   2577   return true;
   2578 }
   2579 
   2580 
   2581 /**
   2582  * Parse configuration @a cfg in section @a section for
   2583  * the specification of an AML program.
   2584  *
   2585  * @param cfg configuration to parse
   2586  * @param section configuration section to parse
   2587  * @return #GNUNET_OK on success
   2588  */
   2589 static enum GNUNET_GenericReturnValue
   2590 add_program (const struct GNUNET_CONFIGURATION_Handle *cfg,
   2591              const char *section)
   2592 {
   2593   char *command = NULL;
   2594   char *description = NULL;
   2595   char *fallback = NULL;
   2596   char *required_contexts = NULL;
   2597   char *required_attributes = NULL;
   2598   char *required_inputs = NULL;
   2599   enum AmlProgramInputs input_mask = API_NONE;
   2600   long long aml_history_length_limit = INT64_MAX;
   2601   long long kyc_history_length_limit = INT64_MAX;
   2602 
   2603   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2604               "Parsing KYC program %s\n",
   2605               section);
   2606   if (GNUNET_OK !=
   2607       GNUNET_CONFIGURATION_get_value_string (cfg,
   2608                                              section,
   2609                                              "COMMAND",
   2610                                              &command))
   2611   {
   2612     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2613                                section,
   2614                                "COMMAND",
   2615                                "command required");
   2616     goto fail;
   2617   }
   2618   if (GNUNET_OK !=
   2619       GNUNET_CONFIGURATION_get_value_string (cfg,
   2620                                              section,
   2621                                              "DESCRIPTION",
   2622                                              &description))
   2623   {
   2624     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2625                                section,
   2626                                "DESCRIPTION",
   2627                                "description required");
   2628     goto fail;
   2629   }
   2630   if (GNUNET_OK !=
   2631       GNUNET_CONFIGURATION_get_value_string (cfg,
   2632                                              section,
   2633                                              "FALLBACK",
   2634                                              &fallback))
   2635   {
   2636     /* We do *not* allow NULL to fall back to default rules because fallbacks
   2637        are used when there is actually a serious error and thus some action
   2638        (usually an investigation) is always in order, and that's basically
   2639        never the default. And as fallbacks should be rare, we really insist on
   2640        them at least being explicitly configured. Otherwise these errors may
   2641        go undetected simply because someone forgot to configure a fallback and
   2642        then nothing happens. */
   2643     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2644                                section,
   2645                                "FALLBACK",
   2646                                "fallback measure name required");
   2647     goto fail;
   2648   }
   2649 
   2650   required_contexts = command_output (command,
   2651                                       "-r");
   2652   if (NULL == required_contexts)
   2653   {
   2654     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2655                                section,
   2656                                "COMMAND",
   2657                                "output for -r invalid");
   2658     goto fail;
   2659   }
   2660   required_attributes = command_output (command,
   2661                                         "-a");
   2662   if (NULL == required_attributes)
   2663   {
   2664     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2665                                section,
   2666                                "COMMAND",
   2667                                "output for -a invalid");
   2668     goto fail;
   2669   }
   2670 
   2671   required_inputs = command_output (command,
   2672                                     "-i");
   2673   if (NULL == required_inputs)
   2674   {
   2675     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2676                                section,
   2677                                "COMMAND",
   2678                                "output for -i invalid");
   2679     goto fail;
   2680   }
   2681   {
   2682     char *sptr;
   2683 
   2684     for (char *tok = strtok_r (required_inputs,
   2685                                ";\n \t",
   2686                                &sptr);
   2687          NULL != tok;
   2688          tok = strtok_r (NULL,
   2689                          ";\n \t",
   2690                          &sptr) )
   2691     {
   2692       if (0 == strcasecmp (tok,
   2693                            "context"))
   2694         input_mask |= API_CONTEXT;
   2695       else if (0 == strcasecmp (tok,
   2696                                 "attributes"))
   2697         input_mask |= API_ATTRIBUTES;
   2698       else if (0 == strcasecmp (tok,
   2699                                 "current_rules"))
   2700         input_mask |= API_CURRENT_RULES;
   2701       else if (0 == strcasecmp (tok,
   2702                                 "default_rules"))
   2703         input_mask |= API_DEFAULT_RULES;
   2704       else if (0 == strncasecmp (tok,
   2705                                  "aml_history",
   2706                                  strlen ("aml_history")))
   2707       {
   2708         input_mask |= API_AML_HISTORY;
   2709         if (! parse_dim (section,
   2710                          tok,
   2711                          &aml_history_length_limit))
   2712           goto fail;
   2713       }
   2714       else if (0 == strncasecmp (tok,
   2715                                  "kyc_history",
   2716                                  strlen ("kyc_history")))
   2717       {
   2718         input_mask |= API_KYC_HISTORY;
   2719         if (! parse_dim (section,
   2720                          tok,
   2721                          &kyc_history_length_limit))
   2722           goto fail;
   2723       }
   2724       else
   2725       {
   2726         GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2727                                    section,
   2728                                    "COMMAND",
   2729                                    "output for -i invalid (unsupported input)");
   2730         goto fail;
   2731       }
   2732     }
   2733   }
   2734   GNUNET_free (required_inputs);
   2735 
   2736   {
   2737     struct TALER_KYCLOGIC_AmlProgram *ap;
   2738 
   2739     ap = GNUNET_new (struct TALER_KYCLOGIC_AmlProgram);
   2740     ap->program_name = GNUNET_strdup (&section[strlen ("aml-program-")]);
   2741     ap->command = command;
   2742     ap->description = description;
   2743     ap->fallback = fallback;
   2744     ap->input_mask = input_mask;
   2745     ap->aml_history_length_limit = aml_history_length_limit;
   2746     ap->kyc_history_length_limit = kyc_history_length_limit;
   2747     add_tokens (required_contexts,
   2748                 "; \n\t",
   2749                 &ap->required_contexts,
   2750                 &ap->num_required_contexts);
   2751     GNUNET_free (required_contexts);
   2752     add_tokens (required_attributes,
   2753                 "; \n\t",
   2754                 &ap->required_attributes,
   2755                 &ap->num_required_attributes);
   2756     GNUNET_free (required_attributes);
   2757     GNUNET_array_append (aml_programs,
   2758                          num_aml_programs,
   2759                          ap);
   2760   }
   2761   return GNUNET_OK;
   2762 fail:
   2763   GNUNET_free (command);
   2764   GNUNET_free (description);
   2765   GNUNET_free (required_inputs);
   2766   GNUNET_free (required_contexts);
   2767   GNUNET_free (required_attributes);
   2768   GNUNET_free (fallback);
   2769   return GNUNET_SYSERR;
   2770 }
   2771 
   2772 
   2773 /**
   2774  * Function to iterate over configuration sections.
   2775  *
   2776  * @param cls a `struct SectionContext *`
   2777  * @param section name of the section
   2778  */
   2779 static void
   2780 handle_program_section (void *cls,
   2781                         const char *section)
   2782 {
   2783   struct SectionContext *sc = cls;
   2784 
   2785   if (! sc->result)
   2786     return;
   2787   if (0 == strncasecmp (section,
   2788                         "aml-program-",
   2789                         strlen ("aml-program-")))
   2790   {
   2791     if (GNUNET_OK !=
   2792         add_program (sc->cfg,
   2793                      section))
   2794       sc->result = false;
   2795   }
   2796 }
   2797 
   2798 
   2799 /**
   2800  * Parse configuration @a cfg in section @a section for
   2801  * the specification of a KYC measure.
   2802  *
   2803  * @param cfg configuration to parse
   2804  * @param section configuration section to parse
   2805  * @return #GNUNET_OK on success
   2806  */
   2807 static enum GNUNET_GenericReturnValue
   2808 add_measure (const struct GNUNET_CONFIGURATION_Handle *cfg,
   2809              const char *section)
   2810 {
   2811   bool voluntary;
   2812   char *check_name = NULL;
   2813   struct TALER_KYCLOGIC_KycCheck *kc = NULL;
   2814   char *context_str = NULL;
   2815   char *program = NULL;
   2816   json_t *context;
   2817   json_error_t err;
   2818 
   2819   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2820               "Parsing KYC measure %s\n",
   2821               section);
   2822   if (GNUNET_OK !=
   2823       GNUNET_CONFIGURATION_get_value_string (cfg,
   2824                                              section,
   2825                                              "CHECK_NAME",
   2826                                              &check_name))
   2827   {
   2828     check_name = GNUNET_strdup ("SKIP");
   2829   }
   2830   if (0 != strcasecmp (check_name,
   2831                        "SKIP"))
   2832   {
   2833     kc = find_check (check_name);
   2834     if (NULL == kc)
   2835     {
   2836       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2837                                  section,
   2838                                  "CHECK_NAME",
   2839                                  "check unknown");
   2840       goto fail;
   2841     }
   2842   }
   2843   if (GNUNET_OK !=
   2844       GNUNET_CONFIGURATION_get_value_string (cfg,
   2845                                              section,
   2846                                              "PROGRAM",
   2847                                              &program))
   2848   {
   2849     if ( (NULL == kc) ||
   2850          (TALER_KYCLOGIC_CT_INFO != kc->type) )
   2851     {
   2852       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2853                                  section,
   2854                                  "PROGRAM");
   2855       goto fail;
   2856     }
   2857   }
   2858   else
   2859   {
   2860     /* AML program given, but do we want one? */
   2861     if ( (NULL != kc) &&
   2862          (TALER_KYCLOGIC_CT_INFO == kc->type) )
   2863     {
   2864       GNUNET_log_config_invalid (
   2865         GNUNET_ERROR_TYPE_WARNING,
   2866         section,
   2867         "PROGRAM",
   2868         "AML program specified for a check of type INFO (ignored)");
   2869       GNUNET_free (program);
   2870     }
   2871   }
   2872   voluntary = (GNUNET_YES ==
   2873                GNUNET_CONFIGURATION_get_value_yesno (cfg,
   2874                                                      section,
   2875                                                      "VOLUNTARY"));
   2876   if (GNUNET_OK !=
   2877       GNUNET_CONFIGURATION_get_value_string (cfg,
   2878                                              section,
   2879                                              "CONTEXT",
   2880                                              &context_str))
   2881   {
   2882     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2883                                section,
   2884                                "CONTEXT");
   2885     goto fail;
   2886   }
   2887   context = json_loads (context_str,
   2888                         JSON_REJECT_DUPLICATES,
   2889                         &err);
   2890   GNUNET_free (context_str);
   2891   if (NULL == context)
   2892   {
   2893     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2894                                section,
   2895                                "CONTEXT",
   2896                                err.text);
   2897     goto fail;
   2898   }
   2899 
   2900   {
   2901     struct TALER_KYCLOGIC_Measure m;
   2902 
   2903     m.measure_name = GNUNET_strdup (&section[strlen ("kyc-measure-")]);
   2904     m.check_name = check_name;
   2905     m.prog_name = program;
   2906     m.context = context;
   2907     m.voluntary = voluntary;
   2908     GNUNET_array_append (default_rules.custom_measures,
   2909                          default_rules.num_custom_measures,
   2910                          m);
   2911   }
   2912   return GNUNET_OK;
   2913 fail:
   2914   GNUNET_free (check_name);
   2915   GNUNET_free (program);
   2916   GNUNET_free (context_str);
   2917   return GNUNET_SYSERR;
   2918 }
   2919 
   2920 
   2921 /**
   2922  * Function to iterate over configuration sections.
   2923  *
   2924  * @param cls a `struct SectionContext *`
   2925  * @param section name of the section
   2926  */
   2927 static void
   2928 handle_measure_section (void *cls,
   2929                         const char *section)
   2930 {
   2931   struct SectionContext *sc = cls;
   2932 
   2933   if (! sc->result)
   2934     return;
   2935   if (0 == strncasecmp (section,
   2936                         "kyc-measure-",
   2937                         strlen ("kyc-measure-")))
   2938   {
   2939     if (GNUNET_OK !=
   2940         add_measure (sc->cfg,
   2941                      section))
   2942       sc->result = false;
   2943   }
   2944 }
   2945 
   2946 
   2947 /**
   2948  * Comparator for qsort. Compares two rules
   2949  * by timeframe to sort rules by time.
   2950  *
   2951  * @param p1 first trigger to compare
   2952  * @param p2 second trigger to compare
   2953  * @return -1 if p1 < p2, 0 if p1==p2, 1 if p1 > p2.
   2954  */
   2955 static int
   2956 sort_by_timeframe (const void *p1,
   2957                    const void *p2)
   2958 {
   2959   struct TALER_KYCLOGIC_KycRule *r1
   2960     = (struct TALER_KYCLOGIC_KycRule *) p1;
   2961   struct TALER_KYCLOGIC_KycRule *r2
   2962     = (struct TALER_KYCLOGIC_KycRule *) p2;
   2963 
   2964   if (GNUNET_TIME_relative_cmp (r1->timeframe,
   2965                                 <,
   2966                                 r2->timeframe))
   2967     return -1;
   2968   if (GNUNET_TIME_relative_cmp (r1->timeframe,
   2969                                 >,
   2970                                 r2->timeframe))
   2971     return 1;
   2972   return 0;
   2973 }
   2974 
   2975 
   2976 enum GNUNET_GenericReturnValue
   2977 TALER_KYCLOGIC_kyc_init (
   2978   const struct GNUNET_CONFIGURATION_Handle *cfg,
   2979   const char *cfg_fn)
   2980 {
   2981   struct SectionContext sc = {
   2982     .cfg = cfg,
   2983     .result = true
   2984   };
   2985   json_t *jkyc_rules_w;
   2986   json_t *jkyc_rules_a;
   2987 
   2988   if (NULL != cfg_fn)
   2989     cfg_filename = GNUNET_strdup (cfg_fn);
   2990   GNUNET_assert (GNUNET_OK ==
   2991                  TALER_config_get_currency (cfg,
   2992                                             "exchange",
   2993                                             &my_currency));
   2994   GNUNET_CONFIGURATION_iterate_sections (cfg,
   2995                                          &handle_provider_section,
   2996                                          &sc);
   2997   if (! sc.result)
   2998   {
   2999     TALER_KYCLOGIC_kyc_done ();
   3000     return GNUNET_SYSERR;
   3001   }
   3002   GNUNET_CONFIGURATION_iterate_sections (cfg,
   3003                                          &handle_check_section,
   3004                                          &sc);
   3005   if (! sc.result)
   3006   {
   3007     TALER_KYCLOGIC_kyc_done ();
   3008     return GNUNET_SYSERR;
   3009   }
   3010   GNUNET_CONFIGURATION_iterate_sections (cfg,
   3011                                          &handle_rule_section,
   3012                                          &sc);
   3013   if (! sc.result)
   3014   {
   3015     TALER_KYCLOGIC_kyc_done ();
   3016     return GNUNET_SYSERR;
   3017   }
   3018   GNUNET_CONFIGURATION_iterate_sections (cfg,
   3019                                          &handle_program_section,
   3020                                          &sc);
   3021   if (! sc.result)
   3022   {
   3023     TALER_KYCLOGIC_kyc_done ();
   3024     return GNUNET_SYSERR;
   3025   }
   3026   GNUNET_CONFIGURATION_iterate_sections (cfg,
   3027                                          &handle_measure_section,
   3028                                          &sc);
   3029   if (! sc.result)
   3030   {
   3031     TALER_KYCLOGIC_kyc_done ();
   3032     return GNUNET_SYSERR;
   3033   }
   3034 
   3035   if (0 != default_rules.num_kyc_rules)
   3036     qsort (default_rules.kyc_rules,
   3037            default_rules.num_kyc_rules,
   3038            sizeof (struct TALER_KYCLOGIC_KycRule),
   3039            &sort_by_timeframe);
   3040   jkyc_rules_w = json_array ();
   3041   GNUNET_assert (NULL != jkyc_rules_w);
   3042   jkyc_rules_a = json_array ();
   3043   GNUNET_assert (NULL != jkyc_rules_a);
   3044 
   3045   for (unsigned int i=0; i<default_rules.num_kyc_rules; i++)
   3046   {
   3047     const struct TALER_KYCLOGIC_KycRule *rule
   3048       = &default_rules.kyc_rules[i];
   3049     json_t *jrule;
   3050     json_t *jmeasures;
   3051 
   3052     jmeasures = json_array ();
   3053     GNUNET_assert (NULL != jmeasures);
   3054     for (unsigned int j=0; j<rule->num_measures; j++)
   3055     {
   3056       const char *measure_name = rule->next_measures[j];
   3057       const struct TALER_KYCLOGIC_Measure *m;
   3058 
   3059       if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE,
   3060                            measure_name))
   3061       {
   3062         GNUNET_assert (
   3063           0 ==
   3064           json_array_append_new (jmeasures,
   3065                                  json_string (KYC_MEASURE_IMPOSSIBLE)));
   3066         continue;
   3067       }
   3068       m = find_measure (&default_rules,
   3069                         measure_name);
   3070       if (NULL == m)
   3071       {
   3072         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3073                     "Unknown measure `%s' used in rule `%s'\n",
   3074                     measure_name,
   3075                     rule->rule_name);
   3076         return GNUNET_SYSERR;
   3077       }
   3078       GNUNET_assert (0 ==
   3079                      json_array_append_new (jmeasures,
   3080                                             json_string (measure_name)));
   3081     }
   3082     jrule = GNUNET_JSON_PACK (
   3083       GNUNET_JSON_pack_allow_null (
   3084         GNUNET_JSON_pack_string ("rule_name",
   3085                                  rule->rule_name)),
   3086       TALER_JSON_pack_kycte ("operation_type",
   3087                              rule->trigger),
   3088       TALER_JSON_pack_amount ("threshold",
   3089                               &rule->threshold),
   3090       GNUNET_JSON_pack_time_rel ("timeframe",
   3091                                  rule->timeframe),
   3092       GNUNET_JSON_pack_array_steal ("measures",
   3093                                     jmeasures),
   3094       GNUNET_JSON_pack_uint64 ("display_priority",
   3095                                rule->display_priority),
   3096       GNUNET_JSON_pack_bool ("exposed",
   3097                              rule->exposed),
   3098       GNUNET_JSON_pack_bool ("is_and_combinator",
   3099                              rule->is_and_combinator)
   3100       );
   3101     switch (rule->trigger)
   3102     {
   3103     case TALER_KYCLOGIC_KYC_TRIGGER_NONE:
   3104       GNUNET_break (0);
   3105       break;
   3106     case TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW:
   3107       GNUNET_assert (0 ==
   3108                      json_array_append (jkyc_rules_a,
   3109                                         jrule));
   3110       break;
   3111     case TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT:
   3112       GNUNET_assert (0 ==
   3113                      json_array_append (jkyc_rules_a,
   3114                                         jrule));
   3115       break;
   3116     case TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE:
   3117       GNUNET_assert (0 ==
   3118                      json_array_append (jkyc_rules_w,
   3119                                         jrule));
   3120       break;
   3121     case TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE:
   3122       GNUNET_assert (0 ==
   3123                      json_array_append (jkyc_rules_w,
   3124                                         jrule));
   3125       break;
   3126     case TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE:
   3127       GNUNET_assert (0 ==
   3128                      json_array_append (jkyc_rules_a,
   3129                                         jrule));
   3130       break;
   3131     case TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE:
   3132       GNUNET_assert (0 ==
   3133                      json_array_append (jkyc_rules_a,
   3134                                         jrule));
   3135       break;
   3136     case TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION:
   3137       GNUNET_assert (0 ==
   3138                      json_array_append (jkyc_rules_a,
   3139                                         jrule));
   3140       GNUNET_assert (0 ==
   3141                      json_array_append (jkyc_rules_w,
   3142                                         jrule));
   3143       break;
   3144     case TALER_KYCLOGIC_KYC_TRIGGER_REFUND:
   3145       GNUNET_assert (0 ==
   3146                      json_array_append (jkyc_rules_a,
   3147                                         jrule));
   3148       GNUNET_assert (0 ==
   3149                      json_array_append (jkyc_rules_w,
   3150                                         jrule));
   3151       break;
   3152     }
   3153     json_decref (jrule);
   3154   }
   3155   {
   3156     json_t *empty = json_object ();
   3157 
   3158     GNUNET_assert (NULL != empty);
   3159     wallet_default_lrs
   3160       = GNUNET_JSON_PACK (
   3161           GNUNET_JSON_pack_timestamp ("expiration_time",
   3162                                       GNUNET_TIME_UNIT_FOREVER_TS),
   3163           GNUNET_JSON_pack_array_steal ("rules",
   3164                                         jkyc_rules_w),
   3165           GNUNET_JSON_pack_object_incref ("custom_measures",
   3166                                           empty)
   3167           );
   3168     bankaccount_default_lrs
   3169       = GNUNET_JSON_PACK (
   3170           GNUNET_JSON_pack_timestamp ("expiration_time",
   3171                                       GNUNET_TIME_UNIT_FOREVER_TS),
   3172           GNUNET_JSON_pack_array_steal ("rules",
   3173                                         jkyc_rules_a),
   3174           GNUNET_JSON_pack_object_incref ("custom_measures",
   3175                                           empty)
   3176           );
   3177     json_decref (empty);
   3178   }
   3179   for (unsigned int i=0; i<default_rules.num_custom_measures; i++)
   3180   {
   3181     const struct TALER_KYCLOGIC_Measure *measure
   3182       = &default_rules.custom_measures[i];
   3183 
   3184     if (! check_measure (measure))
   3185     {
   3186       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3187                   "Configuration of AML measures incorrect. Exiting.\n");
   3188       return GNUNET_SYSERR;
   3189     }
   3190   }
   3191 
   3192   for (unsigned int i=0; i<num_aml_programs; i++)
   3193   {
   3194     const struct TALER_KYCLOGIC_AmlProgram *program
   3195       = aml_programs[i];
   3196     const struct TALER_KYCLOGIC_Measure *m;
   3197 
   3198     m = find_measure (&default_rules,
   3199                       program->fallback);
   3200     if (NULL == m)
   3201     {
   3202       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3203                   "Unknown fallback measure `%s' used in program `%s'\n",
   3204                   program->fallback,
   3205                   program->program_name);
   3206       return GNUNET_SYSERR;
   3207     }
   3208     if (0 != strcasecmp (m->check_name,
   3209                          "SKIP"))
   3210     {
   3211       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3212                   "Fallback measure `%s' used in AML program `%s' has a check `%s' but fallbacks must have a check of type 'SKIP'\n",
   3213                   program->fallback,
   3214                   program->program_name,
   3215                   m->check_name);
   3216       return GNUNET_SYSERR;
   3217     }
   3218     if (NULL != m->prog_name)
   3219     {
   3220       const struct TALER_KYCLOGIC_AmlProgram *fprogram;
   3221 
   3222       fprogram = find_program (m->prog_name);
   3223       GNUNET_assert (NULL != fprogram);
   3224       if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES)))
   3225       {
   3226         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3227                     "Fallback program %s of fallback measure `%s' used in AML program `%s' has required inputs, but fallback measures must not require any inputs\n",
   3228                     m->prog_name,
   3229                     program->program_name,
   3230                     m->check_name);
   3231         return GNUNET_SYSERR;
   3232       }
   3233     }
   3234   }
   3235 
   3236   for (unsigned int i = 0; i<num_kyc_checks; i++)
   3237   {
   3238     struct TALER_KYCLOGIC_KycCheck *kyc_check
   3239       = kyc_checks[i];
   3240     const struct TALER_KYCLOGIC_Measure *measure;
   3241 
   3242     measure = find_measure (&default_rules,
   3243                             kyc_check->fallback);
   3244     if (NULL == measure)
   3245     {
   3246       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3247                   "Unknown fallback measure `%s' used in check `%s'\n",
   3248                   kyc_check->fallback,
   3249                   kyc_check->check_name);
   3250       return GNUNET_SYSERR;
   3251     }
   3252     if (0 != strcasecmp (measure->check_name,
   3253                          "SKIP"))
   3254     {
   3255       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3256                   "Fallback measure `%s' used in KYC check `%s' has a check `%s' but fallbacks must have a check of type 'SKIP'\n",
   3257                   kyc_check->fallback,
   3258                   kyc_check->check_name,
   3259                   measure->check_name);
   3260       return GNUNET_SYSERR;
   3261     }
   3262     if (NULL != measure->prog_name)
   3263     {
   3264       const struct TALER_KYCLOGIC_AmlProgram *fprogram;
   3265 
   3266       fprogram = find_program (measure->prog_name);
   3267       GNUNET_assert (NULL != fprogram);
   3268       if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES)))
   3269       {
   3270         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3271                     "AML program `%s' used fallback measure `%s' of KYC check `%s' has required inputs, but fallback measures must not require any inputs\n",
   3272                     measure->prog_name,
   3273                     kyc_check->fallback,
   3274                     kyc_check->check_name);
   3275         return GNUNET_SYSERR;
   3276       }
   3277     }
   3278   }
   3279 
   3280   return GNUNET_OK;
   3281 }
   3282 
   3283 
   3284 void
   3285 TALER_KYCLOGIC_kyc_done (void)
   3286 {
   3287   for (unsigned int i = 0; i<default_rules.num_kyc_rules; i++)
   3288   {
   3289     struct TALER_KYCLOGIC_KycRule *kt
   3290       = &default_rules.kyc_rules[i];
   3291 
   3292     for (unsigned int j = 0; j<kt->num_measures; j++)
   3293       GNUNET_free (kt->next_measures[j]);
   3294     GNUNET_array_grow (kt->next_measures,
   3295                        kt->num_measures,
   3296                        0);
   3297     GNUNET_free (kt->rule_name);
   3298   }
   3299   GNUNET_array_grow (default_rules.kyc_rules,
   3300                      default_rules.num_kyc_rules,
   3301                      0);
   3302   for (unsigned int i = 0; i<num_kyc_providers; i++)
   3303   {
   3304     struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
   3305 
   3306     kp->logic->unload_configuration (kp->pd);
   3307     GNUNET_free (kp->provider_name);
   3308     GNUNET_free (kp);
   3309   }
   3310   GNUNET_array_grow (kyc_providers,
   3311                      num_kyc_providers,
   3312                      0);
   3313   for (unsigned int i = 0; i<num_kyc_logics; i++)
   3314   {
   3315     struct TALER_KYCLOGIC_Plugin *lp = kyc_logics[i];
   3316     char *lib_name = lp->library_name;
   3317 
   3318     GNUNET_free (lp->name);
   3319     GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name,
   3320                                                  lp));
   3321     GNUNET_free (lib_name);
   3322   }
   3323   GNUNET_array_grow (kyc_logics,
   3324                      num_kyc_logics,
   3325                      0);
   3326   for (unsigned int i = 0; i<num_kyc_checks; i++)
   3327   {
   3328     struct TALER_KYCLOGIC_KycCheck *kc = kyc_checks[i];
   3329 
   3330     GNUNET_free (kc->check_name);
   3331     GNUNET_free (kc->description);
   3332     json_decref (kc->description_i18n);
   3333     for (unsigned int j = 0; j<kc->num_requires; j++)
   3334       GNUNET_free (kc->requires[j]);
   3335     GNUNET_array_grow (kc->requires,
   3336                        kc->num_requires,
   3337                        0);
   3338     GNUNET_free (kc->fallback);
   3339     for (unsigned int j = 0; j<kc->num_outputs; j++)
   3340       GNUNET_free (kc->outputs[j]);
   3341     GNUNET_array_grow (kc->outputs,
   3342                        kc->num_outputs,
   3343                        0);
   3344     switch (kc->type)
   3345     {
   3346     case TALER_KYCLOGIC_CT_INFO:
   3347       break;
   3348     case TALER_KYCLOGIC_CT_FORM:
   3349       GNUNET_free (kc->details.form.name);
   3350       break;
   3351     case TALER_KYCLOGIC_CT_LINK:
   3352       break;
   3353     }
   3354     GNUNET_free (kc);
   3355   }
   3356   GNUNET_array_grow (kyc_checks,
   3357                      num_kyc_checks,
   3358                      0);
   3359   for (unsigned int i = 0; i<num_aml_programs; i++)
   3360   {
   3361     struct TALER_KYCLOGIC_AmlProgram *ap = aml_programs[i];
   3362 
   3363     GNUNET_free (ap->program_name);
   3364     GNUNET_free (ap->command);
   3365     GNUNET_free (ap->description);
   3366     GNUNET_free (ap->fallback);
   3367     for (unsigned int j = 0; j<ap->num_required_contexts; j++)
   3368       GNUNET_free (ap->required_contexts[j]);
   3369     GNUNET_array_grow (ap->required_contexts,
   3370                        ap->num_required_contexts,
   3371                        0);
   3372     for (unsigned int j = 0; j<ap->num_required_attributes; j++)
   3373       GNUNET_free (ap->required_attributes[j]);
   3374     GNUNET_array_grow (ap->required_attributes,
   3375                        ap->num_required_attributes,
   3376                        0);
   3377     GNUNET_free (ap);
   3378   }
   3379   GNUNET_array_grow (aml_programs,
   3380                      num_aml_programs,
   3381                      0);
   3382   GNUNET_free (cfg_filename);
   3383 }
   3384 
   3385 
   3386 void
   3387 TALER_KYCLOGIC_provider_to_logic (
   3388   const struct TALER_KYCLOGIC_KycProvider *provider,
   3389   struct TALER_KYCLOGIC_Plugin **plugin,
   3390   struct TALER_KYCLOGIC_ProviderDetails **pd,
   3391   const char **provider_name)
   3392 {
   3393   *plugin = provider->logic;
   3394   *pd = provider->pd;
   3395   *provider_name = provider->provider_name;
   3396 }
   3397 
   3398 
   3399 enum GNUNET_GenericReturnValue
   3400 TALER_KYCLOGIC_get_original_measure (
   3401   const char *measure_name,
   3402   struct TALER_KYCLOGIC_KycCheckContext *kcc)
   3403 {
   3404   const struct TALER_KYCLOGIC_Measure *measure;
   3405 
   3406   measure = find_measure (&default_rules,
   3407                           measure_name);
   3408   if (NULL == measure)
   3409   {
   3410     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3411                 "Default measure `%s' unknown\n",
   3412                 measure_name);
   3413     return GNUNET_SYSERR;
   3414   }
   3415   if (0 == strcasecmp (measure->check_name,
   3416                        "SKIP"))
   3417   {
   3418     kcc->check = NULL;
   3419     kcc->prog_name = measure->prog_name;
   3420     kcc->context = measure->context;
   3421     return GNUNET_OK;
   3422   }
   3423 
   3424   for (unsigned int i = 0; i<num_kyc_checks; i++)
   3425     if (0 == strcasecmp (measure->check_name,
   3426                          kyc_checks[i]->check_name))
   3427     {
   3428       kcc->check = kyc_checks[i];
   3429       kcc->prog_name = measure->prog_name;
   3430       kcc->context = measure->context;
   3431       return GNUNET_OK;
   3432     }
   3433   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3434               "Check `%s' unknown (but required by measure %s)\n",
   3435               measure->check_name,
   3436               measure_name);
   3437   return GNUNET_SYSERR;
   3438 }
   3439 
   3440 
   3441 enum GNUNET_GenericReturnValue
   3442 TALER_KYCLOGIC_requirements_to_check (
   3443   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
   3444   const struct TALER_KYCLOGIC_KycRule *kyc_rule,
   3445   const char *measure_name,
   3446   struct TALER_KYCLOGIC_KycCheckContext *kcc)
   3447 {
   3448   bool found = false;
   3449   const struct TALER_KYCLOGIC_Measure *measure = NULL;
   3450 
   3451   if (NULL == lrs)
   3452     lrs = &default_rules;
   3453   if (NULL == measure_name)
   3454   {
   3455     GNUNET_break (0);
   3456     return GNUNET_SYSERR;
   3457   }
   3458   if (NULL != kyc_rule)
   3459   {
   3460     for (unsigned int i = 0; i<kyc_rule->num_measures; i++)
   3461     {
   3462       if (0 != strcasecmp (measure_name,
   3463                            kyc_rule->next_measures[i]))
   3464         continue;
   3465       found = true;
   3466       break;
   3467     }
   3468     if (! found)
   3469     {
   3470       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3471                   "Measure `%s' not allowed for rule `%s'\n",
   3472                   measure_name,
   3473                   kyc_rule->rule_name);
   3474       return GNUNET_SYSERR;
   3475     }
   3476     if (kyc_rule->verboten)
   3477     {
   3478       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3479                   "Rule says operation is categorically is verboten, cannot take measures\n");
   3480       return GNUNET_SYSERR;
   3481     }
   3482   }
   3483   measure = find_measure (lrs,
   3484                           measure_name);
   3485   if (NULL == measure)
   3486   {
   3487     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3488                 "Measure `%s' unknown (but allowed by rule `%s')\n",
   3489                 measure_name,
   3490                 NULL != kyc_rule
   3491                 ? kyc_rule->rule_name
   3492                 : "<NONE>");
   3493     return GNUNET_SYSERR;
   3494   }
   3495 
   3496   if (0 == strcasecmp (measure->check_name,
   3497                        "SKIP"))
   3498   {
   3499     kcc->check = NULL;
   3500     kcc->prog_name = measure->prog_name;
   3501     kcc->context = measure->context;
   3502     return GNUNET_OK;
   3503   }
   3504 
   3505   for (unsigned int i = 0; i<num_kyc_checks; i++)
   3506     if (0 == strcasecmp (measure->check_name,
   3507                          kyc_checks[i]->check_name))
   3508     {
   3509       kcc->check = kyc_checks[i];
   3510       kcc->prog_name = measure->prog_name;
   3511       kcc->context = measure->context;
   3512       return GNUNET_OK;
   3513     }
   3514   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3515               "Check `%s' unknown (but required by measure %s)\n",
   3516               measure->check_name,
   3517               measure_name);
   3518   return GNUNET_SYSERR;
   3519 }
   3520 
   3521 
   3522 enum GNUNET_GenericReturnValue
   3523 TALER_KYCLOGIC_lookup_logic (
   3524   const char *name,
   3525   struct TALER_KYCLOGIC_Plugin **plugin,
   3526   struct TALER_KYCLOGIC_ProviderDetails **pd,
   3527   const char **provider_name)
   3528 {
   3529   for (unsigned int i = 0; i<num_kyc_providers; i++)
   3530   {
   3531     struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
   3532 
   3533     if (0 !=
   3534         strcasecmp (name,
   3535                     kp->provider_name))
   3536       continue;
   3537     *plugin = kp->logic;
   3538     *pd = kp->pd;
   3539     *provider_name = kp->provider_name;
   3540     return GNUNET_OK;
   3541   }
   3542   for (unsigned int i = 0; i<num_kyc_logics; i++)
   3543   {
   3544     struct TALER_KYCLOGIC_Plugin *logic = kyc_logics[i];
   3545 
   3546     if (0 !=
   3547         strcasecmp (logic->name,
   3548                     name))
   3549       continue;
   3550     *plugin = logic;
   3551     *pd = NULL;
   3552     *provider_name = NULL;
   3553     return GNUNET_OK;
   3554   }
   3555   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3556               "Provider `%s' unknown\n",
   3557               name);
   3558   return GNUNET_SYSERR;
   3559 }
   3560 
   3561 
   3562 void
   3563 TALER_KYCLOGIC_kyc_get_details (
   3564   const char *logic_name,
   3565   TALER_KYCLOGIC_DetailsCallback cb,
   3566   void *cb_cls)
   3567 {
   3568   for (unsigned int i = 0; i<num_kyc_providers; i++)
   3569   {
   3570     struct TALER_KYCLOGIC_KycProvider *kp
   3571       = kyc_providers[i];
   3572 
   3573     if (0 !=
   3574         strcasecmp (kp->logic->name,
   3575                     logic_name))
   3576       continue;
   3577     if (GNUNET_OK !=
   3578         cb (cb_cls,
   3579             kp->pd,
   3580             kp->logic->cls))
   3581       return;
   3582   }
   3583 }
   3584 
   3585 
   3586 /**
   3587  * Closure for check_amount().
   3588  */
   3589 struct KycTestContext
   3590 {
   3591   /**
   3592    * Rule set we apply.
   3593    */
   3594   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs;
   3595 
   3596   /**
   3597    * Events we care about.
   3598    */
   3599   enum TALER_KYCLOGIC_KycTriggerEvent event;
   3600 
   3601   /**
   3602    * Total amount encountered so far, invalid if zero.
   3603    */
   3604   struct TALER_Amount sum;
   3605 
   3606   /**
   3607    * Set to the triggered rule.
   3608    */
   3609   const struct TALER_KYCLOGIC_KycRule *triggered_rule;
   3610 
   3611 };
   3612 
   3613 
   3614 /**
   3615  * Function called on each @a amount that was found to
   3616  * be relevant for a KYC check.  Evaluates the given
   3617  * @a amount and @a date against all the applicable
   3618  * rules in the legitimization rule set.
   3619  *
   3620  * @param cls our `struct KycTestContext *`
   3621  * @param amount encountered transaction amount
   3622  * @param date when was the amount encountered
   3623  * @return #GNUNET_OK to continue to iterate,
   3624  *         #GNUNET_NO to abort iteration,
   3625  *         #GNUNET_SYSERR on internal error (also abort itaration)
   3626  */
   3627 static enum GNUNET_GenericReturnValue
   3628 check_amount (
   3629   void *cls,
   3630   const struct TALER_Amount *amount,
   3631   struct GNUNET_TIME_Absolute date)
   3632 {
   3633   struct KycTestContext *ktc = cls;
   3634   struct GNUNET_TIME_Relative dur;
   3635 
   3636   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3637               "KYC checking transaction amount %s from %s against %u rules\n",
   3638               TALER_amount2s (amount),
   3639               GNUNET_TIME_absolute2s (date),
   3640               ktc->lrs->num_kyc_rules);
   3641   dur = GNUNET_TIME_absolute_get_duration (date);
   3642   if (GNUNET_OK !=
   3643       TALER_amount_is_valid (&ktc->sum))
   3644     ktc->sum = *amount;
   3645   else
   3646     GNUNET_assert (0 <=
   3647                    TALER_amount_add (&ktc->sum,
   3648                                      &ktc->sum,
   3649                                      amount));
   3650   for (unsigned int i=0; i<ktc->lrs->num_kyc_rules; i++)
   3651   {
   3652     const struct TALER_KYCLOGIC_KycRule *rule
   3653       = &ktc->lrs->kyc_rules[i];
   3654 
   3655     if (ktc->event != rule->trigger)
   3656     {
   3657       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3658                   "Wrong event type (%d) for rule %u (%d)\n",
   3659                   (int) ktc->event,
   3660                   i,
   3661                   (int) rule->trigger);
   3662       continue; /* wrong trigger event type */
   3663     }
   3664     if (GNUNET_TIME_relative_cmp (dur,
   3665                                   >,
   3666                                   rule->timeframe))
   3667     {
   3668       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3669                   "Out of time range for rule %u\n",
   3670                   i);
   3671       continue; /* out of time range for rule */
   3672     }
   3673     if (-1 == TALER_amount_cmp (&ktc->sum,
   3674                                 &rule->threshold))
   3675     {
   3676       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3677                   "Below threshold of %s for rule %u\n",
   3678                   TALER_amount2s (&rule->threshold),
   3679                   i);
   3680       continue; /* sum < threshold */
   3681     }
   3682     if ( (NULL != ktc->triggered_rule) &&
   3683          (1 == TALER_amount_cmp (&ktc->triggered_rule->threshold,
   3684                                  &rule->threshold)) )
   3685     {
   3686       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3687                   "Higher than threshold of already triggered rule\n");
   3688       continue; /* threshold of triggered_rule > rule */
   3689     }
   3690     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3691                 "Remembering rule %s as triggered\n",
   3692                 rule->rule_name);
   3693     ktc->triggered_rule = rule;
   3694   }
   3695   return GNUNET_OK;
   3696 }
   3697 
   3698 
   3699 enum GNUNET_DB_QueryStatus
   3700 TALER_KYCLOGIC_kyc_test_required (
   3701   enum TALER_KYCLOGIC_KycTriggerEvent event,
   3702   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
   3703   TALER_KYCLOGIC_KycAmountIterator ai,
   3704   void *ai_cls,
   3705   const struct TALER_KYCLOGIC_KycRule **triggered_rule,
   3706   struct TALER_Amount *next_threshold)
   3707 {
   3708   struct GNUNET_TIME_Relative range
   3709     = GNUNET_TIME_UNIT_ZERO;
   3710   enum GNUNET_DB_QueryStatus qs;
   3711   bool have_threshold = false;
   3712 
   3713   memset (next_threshold,
   3714           0,
   3715           sizeof (struct TALER_Amount));
   3716   if (NULL == lrs)
   3717     lrs = &default_rules;
   3718   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3719               "Testing %u KYC rules for trigger %d\n",
   3720               lrs->num_kyc_rules,
   3721               event);
   3722   for (unsigned int i=0; i<lrs->num_kyc_rules; i++)
   3723   {
   3724     const struct TALER_KYCLOGIC_KycRule *rule
   3725       = &lrs->kyc_rules[i];
   3726 
   3727     if (event != rule->trigger)
   3728     {
   3729       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3730                   "Rule %u is for a different trigger (%d/%d)\n",
   3731                   i,
   3732                   (int) event,
   3733                   (int) rule->trigger);
   3734       continue;
   3735     }
   3736     if (have_threshold)
   3737     {
   3738       GNUNET_assert (GNUNET_OK ==
   3739                      TALER_amount_min (next_threshold,
   3740                                        next_threshold,
   3741                                        &rule->threshold));
   3742     }
   3743     else
   3744     {
   3745       *next_threshold = rule->threshold;
   3746       have_threshold = true;
   3747     }
   3748     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3749                 "Matched rule %u with timeframe %s and threshold %s\n",
   3750                 i,
   3751                 GNUNET_TIME_relative2s (rule->timeframe,
   3752                                         true),
   3753                 TALER_amount2s (&rule->threshold));
   3754     range = GNUNET_TIME_relative_max (range,
   3755                                       rule->timeframe);
   3756   }
   3757 
   3758   if (! have_threshold)
   3759   {
   3760     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3761                 "No rules apply\n");
   3762     *triggered_rule = NULL;
   3763     return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
   3764   }
   3765 
   3766   {
   3767     struct GNUNET_TIME_Absolute now
   3768       = GNUNET_TIME_absolute_get ();
   3769     struct KycTestContext ktc = {
   3770       .lrs = lrs,
   3771       .event = event
   3772     };
   3773 
   3774     qs = ai (ai_cls,
   3775              GNUNET_TIME_absolute_subtract (now,
   3776                                             range),
   3777              &check_amount,
   3778              &ktc);
   3779     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3780                 "Triggered rule is %s\n",
   3781                 (NULL == ktc.triggered_rule)
   3782                 ? "NONE"
   3783                 : ktc.triggered_rule->rule_name);
   3784     *triggered_rule = ktc.triggered_rule;
   3785   }
   3786   return qs;
   3787 }
   3788 
   3789 
   3790 json_t *
   3791 TALER_KYCLOGIC_measure_to_requirement (
   3792   const char *check_name,
   3793   const json_t *context,
   3794   const struct TALER_AccountAccessTokenP *access_token,
   3795   size_t offset,
   3796   uint64_t legitimization_measure_row_id)
   3797 {
   3798   struct TALER_KYCLOGIC_KycCheck *kc;
   3799   json_t *kri;
   3800   struct TALER_KycMeasureAuthorizationHashP shv;
   3801   char *ids;
   3802   char *xids;
   3803 
   3804   kc = find_check (check_name);
   3805   if (NULL == kc)
   3806   {
   3807     GNUNET_break (0);
   3808     return NULL;
   3809   }
   3810   GNUNET_assert (offset <= UINT32_MAX);
   3811   TALER_kyc_measure_authorization_hash (access_token,
   3812                                         legitimization_measure_row_id,
   3813                                         (uint32_t) offset,
   3814                                         &shv);
   3815   switch (kc->type)
   3816   {
   3817   case TALER_KYCLOGIC_CT_INFO:
   3818     return GNUNET_JSON_PACK (
   3819       GNUNET_JSON_pack_string ("form",
   3820                                "INFO"),
   3821       GNUNET_JSON_pack_string ("description",
   3822                                kc->description),
   3823       GNUNET_JSON_pack_allow_null (
   3824         GNUNET_JSON_pack_object_incref ("description_i18n",
   3825                                         (json_t *) kc->description_i18n)));
   3826   case TALER_KYCLOGIC_CT_FORM:
   3827     GNUNET_assert (offset <= UINT_MAX);
   3828     ids = GNUNET_STRINGS_data_to_string_alloc (&shv,
   3829                                                sizeof (shv));
   3830     GNUNET_asprintf (&xids,
   3831                      "%s-%u-%llu",
   3832                      ids,
   3833                      (unsigned int) offset,
   3834                      (unsigned long long) legitimization_measure_row_id);
   3835     GNUNET_free (ids);
   3836     kri = GNUNET_JSON_PACK (
   3837       GNUNET_JSON_pack_string ("form",
   3838                                kc->details.form.name),
   3839       GNUNET_JSON_pack_string ("id",
   3840                                xids),
   3841       GNUNET_JSON_pack_allow_null (
   3842         GNUNET_JSON_pack_object_incref ("context",
   3843                                         (json_t *) context)),
   3844       GNUNET_JSON_pack_string ("description",
   3845                                kc->description),
   3846       GNUNET_JSON_pack_allow_null (
   3847         GNUNET_JSON_pack_object_incref ("description_i18n",
   3848                                         (json_t *) kc->description_i18n)));
   3849     GNUNET_free (xids);
   3850     return kri;
   3851   case TALER_KYCLOGIC_CT_LINK:
   3852     GNUNET_assert (offset <= UINT_MAX);
   3853     ids = GNUNET_STRINGS_data_to_string_alloc (&shv,
   3854                                                sizeof (shv));
   3855     GNUNET_asprintf (&xids,
   3856                      "%s-%u-%llu",
   3857                      ids,
   3858                      (unsigned int) offset,
   3859                      (unsigned long long) legitimization_measure_row_id);
   3860     GNUNET_free (ids);
   3861     kri = GNUNET_JSON_PACK (
   3862       GNUNET_JSON_pack_string ("form",
   3863                                "LINK"),
   3864       GNUNET_JSON_pack_string ("id",
   3865                                xids),
   3866       GNUNET_JSON_pack_string ("description",
   3867                                kc->description),
   3868       GNUNET_JSON_pack_allow_null (
   3869         GNUNET_JSON_pack_object_incref ("description_i18n",
   3870                                         (json_t *) kc->description_i18n)));
   3871     GNUNET_free (xids);
   3872     return kri;
   3873   }
   3874   GNUNET_break (0); /* invalid type */
   3875   return NULL;
   3876 }
   3877 
   3878 
   3879 void
   3880 TALER_KYCLOGIC_get_measure_configuration (
   3881   json_t **proots,
   3882   json_t **pprograms,
   3883   json_t **pchecks,
   3884   json_t **pdefault_rules)
   3885 {
   3886   json_t *roots;
   3887   json_t *programs;
   3888   json_t *checks;
   3889   json_t *drules;
   3890 
   3891   roots = json_object ();
   3892   GNUNET_assert (NULL != roots);
   3893   for (unsigned int i = 0; i<default_rules.num_custom_measures; i++)
   3894   {
   3895     const struct TALER_KYCLOGIC_Measure *m
   3896       = &default_rules.custom_measures[i];
   3897     json_t *jm;
   3898 
   3899     jm = GNUNET_JSON_PACK (
   3900       GNUNET_JSON_pack_string ("check_name",
   3901                                m->check_name),
   3902       GNUNET_JSON_pack_allow_null (
   3903         GNUNET_JSON_pack_string ("prog_name",
   3904                                  m->prog_name)),
   3905       GNUNET_JSON_pack_allow_null (
   3906         GNUNET_JSON_pack_object_incref ("context",
   3907                                         m->context)));
   3908     GNUNET_assert (0 ==
   3909                    json_object_set_new (roots,
   3910                                         m->measure_name,
   3911                                         jm));
   3912   }
   3913 
   3914   programs = json_object ();
   3915   GNUNET_assert (NULL != programs);
   3916   for (unsigned int i = 0; i<num_aml_programs; i++)
   3917   {
   3918     const struct TALER_KYCLOGIC_AmlProgram *ap
   3919       = aml_programs[i];
   3920     json_t *jp;
   3921     json_t *ctx;
   3922     json_t *inp;
   3923 
   3924     ctx = json_array ();
   3925     GNUNET_assert (NULL != ctx);
   3926     for (unsigned int j = 0; j<ap->num_required_contexts; j++)
   3927     {
   3928       const char *rc = ap->required_contexts[j];
   3929 
   3930       GNUNET_assert (0 ==
   3931                      json_array_append_new (ctx,
   3932                                             json_string (rc)));
   3933     }
   3934     inp = json_array ();
   3935     GNUNET_assert (NULL != inp);
   3936     for (unsigned int j = 0; j<ap->num_required_attributes; j++)
   3937     {
   3938       const char *ra = ap->required_attributes[j];
   3939 
   3940       GNUNET_assert (0 ==
   3941                      json_array_append_new (inp,
   3942                                             json_string (ra)));
   3943     }
   3944 
   3945     jp = GNUNET_JSON_PACK (
   3946       GNUNET_JSON_pack_string ("description",
   3947                                ap->description),
   3948       GNUNET_JSON_pack_array_steal ("context",
   3949                                     ctx),
   3950       GNUNET_JSON_pack_array_steal ("inputs",
   3951                                     inp));
   3952     GNUNET_assert (0 ==
   3953                    json_object_set_new (programs,
   3954                                         ap->program_name,
   3955                                         jp));
   3956   }
   3957 
   3958   checks = json_object ();
   3959   GNUNET_assert (NULL != checks);
   3960   for (unsigned int i = 0; i<num_kyc_checks; i++)
   3961   {
   3962     const struct TALER_KYCLOGIC_KycCheck *ck
   3963       = kyc_checks[i];
   3964     json_t *jc;
   3965     json_t *requires;
   3966     json_t *outputs;
   3967 
   3968     requires = json_array ();
   3969     GNUNET_assert (NULL != requires);
   3970     for (unsigned int j = 0; j<ck->num_requires; j++)
   3971     {
   3972       const char *ra = ck->requires[j];
   3973 
   3974       GNUNET_assert (0 ==
   3975                      json_array_append_new (requires,
   3976                                             json_string (ra)));
   3977     }
   3978     outputs = json_array ();
   3979     GNUNET_assert (NULL != outputs);
   3980     for (unsigned int j = 0; j<ck->num_outputs; j++)
   3981     {
   3982       const char *out = ck->outputs[j];
   3983 
   3984       GNUNET_assert (0 ==
   3985                      json_array_append_new (outputs,
   3986                                             json_string (out)));
   3987     }
   3988 
   3989     jc = GNUNET_JSON_PACK (
   3990       GNUNET_JSON_pack_string ("description",
   3991                                ck->description),
   3992       GNUNET_JSON_pack_allow_null (
   3993         GNUNET_JSON_pack_object_incref ("description_i18n",
   3994                                         ck->description_i18n)),
   3995       GNUNET_JSON_pack_array_steal ("requires",
   3996                                     requires),
   3997       GNUNET_JSON_pack_array_steal ("outputs",
   3998                                     outputs),
   3999       GNUNET_JSON_pack_string ("fallback",
   4000                                ck->fallback));
   4001     GNUNET_assert (0 ==
   4002                    json_object_set_new (checks,
   4003                                         ck->check_name,
   4004                                         jc));
   4005   }
   4006   drules = json_array ();
   4007   GNUNET_assert (NULL != drules);
   4008   {
   4009     const struct TALER_KYCLOGIC_KycRule *rules
   4010       = default_rules.kyc_rules;
   4011     unsigned int num_rules
   4012       = default_rules.num_kyc_rules;
   4013 
   4014     for (unsigned int i = 0; i<num_rules; i++)
   4015     {
   4016       const struct TALER_KYCLOGIC_KycRule *rule = &rules[i];
   4017       json_t *measures;
   4018       json_t *limit;
   4019 
   4020       measures = json_array ();
   4021       GNUNET_assert (NULL != measures);
   4022       for (unsigned int j = 0; j<rule->num_measures; j++)
   4023         GNUNET_assert (
   4024           0 ==
   4025           json_array_append_new (measures,
   4026                                  json_string (
   4027                                    rule->next_measures[j])));
   4028       limit = GNUNET_JSON_PACK (
   4029         GNUNET_JSON_pack_allow_null (
   4030           GNUNET_JSON_pack_string ("rule_name",
   4031                                    rule->rule_name)),
   4032         TALER_JSON_pack_kycte ("operation_type",
   4033                                rule->trigger),
   4034         TALER_JSON_pack_amount ("threshold",
   4035                                 &rule->threshold),
   4036         GNUNET_JSON_pack_time_rel ("timeframe",
   4037                                    rule->timeframe),
   4038         GNUNET_JSON_pack_array_steal ("measures",
   4039                                       measures),
   4040         GNUNET_JSON_pack_uint64 ("display_priority",
   4041                                  rule->display_priority),
   4042         GNUNET_JSON_pack_bool ("soft_limit",
   4043                                ! rule->verboten),
   4044         GNUNET_JSON_pack_bool ("exposed",
   4045                                rule->exposed),
   4046         GNUNET_JSON_pack_bool ("is_and_combinator",
   4047                                rule->is_and_combinator)
   4048         );
   4049       GNUNET_assert (0 ==
   4050                      json_array_append_new (drules,
   4051                                             limit));
   4052     }
   4053   }
   4054 
   4055   *proots = roots;
   4056   *pprograms = programs;
   4057   *pchecks = checks;
   4058   *pdefault_rules = drules;
   4059 }
   4060 
   4061 
   4062 enum TALER_ErrorCode
   4063 TALER_KYCLOGIC_select_measure (
   4064   const json_t *jmeasures,
   4065   size_t measure_index,
   4066   const char **check_name,
   4067   const char **prog_name,
   4068   const json_t **context)
   4069 {
   4070   const json_t *jmeasure_arr;
   4071   struct GNUNET_JSON_Specification spec[] = {
   4072     GNUNET_JSON_spec_array_const ("measures",
   4073                                   &jmeasure_arr),
   4074     GNUNET_JSON_spec_end ()
   4075   };
   4076   const json_t *jmeasure;
   4077   struct GNUNET_JSON_Specification ispec[] = {
   4078     GNUNET_JSON_spec_string ("check_name",
   4079                              check_name),
   4080     GNUNET_JSON_spec_mark_optional (
   4081       GNUNET_JSON_spec_string ("prog_name",
   4082                                prog_name),
   4083       NULL),
   4084     GNUNET_JSON_spec_mark_optional (
   4085       GNUNET_JSON_spec_object_const ("context",
   4086                                      context),
   4087       NULL),
   4088     GNUNET_JSON_spec_end ()
   4089   };
   4090 
   4091   *check_name = NULL;
   4092   *prog_name = NULL;
   4093   *context = NULL;
   4094   if (GNUNET_OK !=
   4095       GNUNET_JSON_parse (jmeasures,
   4096                          spec,
   4097                          NULL, NULL))
   4098   {
   4099     GNUNET_break (0);
   4100     return TALER_EC_EXCHANGE_KYC_MEASURES_MALFORMED;
   4101   }
   4102   if (measure_index >= json_array_size (jmeasure_arr))
   4103   {
   4104     GNUNET_break_op (0);
   4105     return TALER_EC_EXCHANGE_KYC_MEASURE_INDEX_INVALID;
   4106   }
   4107   jmeasure = json_array_get (jmeasure_arr,
   4108                              measure_index);
   4109   if (GNUNET_OK !=
   4110       GNUNET_JSON_parse (jmeasure,
   4111                          ispec,
   4112                          NULL, NULL))
   4113   {
   4114     GNUNET_break (0);
   4115     return TALER_EC_EXCHANGE_KYC_MEASURES_MALFORMED;
   4116   }
   4117   return TALER_EC_NONE;
   4118 }
   4119 
   4120 
   4121 enum TALER_ErrorCode
   4122 TALER_KYCLOGIC_check_form (
   4123   const json_t *jmeasures,
   4124   size_t measure_index,
   4125   const json_t *form_data,
   4126   char **form_name,
   4127   const char **error_message)
   4128 {
   4129   const char *check_name;
   4130   const char *prog_name;
   4131   const json_t *context;
   4132   struct TALER_KYCLOGIC_KycCheck *kc;
   4133   struct TALER_KYCLOGIC_AmlProgram *prog;
   4134 
   4135   *error_message = NULL;
   4136   *form_name = NULL;
   4137   if (TALER_EC_NONE !=
   4138       TALER_KYCLOGIC_select_measure (jmeasures,
   4139                                      measure_index,
   4140                                      &check_name,
   4141                                      &prog_name,
   4142                                      &context))
   4143   {
   4144     GNUNET_break_op (0);
   4145     return TALER_EC_EXCHANGE_KYC_MEASURE_INDEX_INVALID;
   4146   }
   4147   kc = find_check (check_name);
   4148   if (NULL == kc)
   4149   {
   4150     GNUNET_break (0);
   4151     *error_message = check_name;
   4152     return TALER_EC_EXCHANGE_KYC_GENERIC_CHECK_GONE;
   4153   }
   4154   if (TALER_KYCLOGIC_CT_FORM != kc->type)
   4155   {
   4156     GNUNET_break_op (0);
   4157     return TALER_EC_EXCHANGE_KYC_NOT_A_FORM;
   4158   }
   4159   if (NULL == prog_name)
   4160   {
   4161     /* non-INFO checks must have an AML program */
   4162     GNUNET_break (0);
   4163     return TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_BUG;
   4164   }
   4165   for (unsigned int i = 0; i<kc->num_outputs; i++)
   4166   {
   4167     const char *rattr = kc->outputs[i];
   4168 
   4169     if (NULL == json_object_get (form_data,
   4170                                  rattr))
   4171     {
   4172       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4173                   "Form data lacks required attribute `%s' for KYC check `%s'\n",
   4174                   rattr,
   4175                   check_name);
   4176       *error_message = rattr;
   4177       return TALER_EC_EXCHANGE_KYC_AML_FORM_INCOMPLETE;
   4178     }
   4179   }
   4180   prog = find_program (prog_name);
   4181   if (NULL == prog)
   4182   {
   4183     GNUNET_break (0);
   4184     *error_message = prog_name;
   4185     return TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_GONE;
   4186   }
   4187   for (unsigned int i = 0; i<prog->num_required_attributes; i++)
   4188   {
   4189     const char *rattr = prog->required_attributes[i];
   4190 
   4191     if (NULL == json_object_get (form_data,
   4192                                  rattr))
   4193     {
   4194       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4195                   "Form data lacks required attribute `%s' for AML program %s\n",
   4196                   rattr,
   4197                   prog_name);
   4198       *error_message = rattr;
   4199       return TALER_EC_EXCHANGE_KYC_AML_FORM_INCOMPLETE;
   4200     }
   4201   }
   4202   *form_name = GNUNET_strdup (kc->details.form.name);
   4203   return TALER_EC_NONE;
   4204 }
   4205 
   4206 
   4207 const char *
   4208 TALER_KYCLOGIC_get_aml_program_fallback (const char *prog_name)
   4209 {
   4210   struct TALER_KYCLOGIC_AmlProgram *prog;
   4211 
   4212   prog = find_program (prog_name);
   4213   if (NULL == prog)
   4214   {
   4215     GNUNET_break (0);
   4216     return NULL;
   4217   }
   4218   return prog->fallback;
   4219 }
   4220 
   4221 
   4222 const struct TALER_KYCLOGIC_KycProvider *
   4223 TALER_KYCLOGIC_check_to_provider (const char *check_name)
   4224 {
   4225   struct TALER_KYCLOGIC_KycCheck *kc;
   4226 
   4227   if (NULL == check_name)
   4228     return NULL;
   4229   if (0 == strcasecmp (check_name,
   4230                        "SKIP"))
   4231     return NULL;
   4232   kc = find_check (check_name);
   4233   if (NULL == kc)
   4234   {
   4235     GNUNET_break (0);
   4236     return NULL;
   4237   }
   4238   switch (kc->type)
   4239   {
   4240   case TALER_KYCLOGIC_CT_FORM:
   4241   case TALER_KYCLOGIC_CT_INFO:
   4242     return NULL;
   4243   case TALER_KYCLOGIC_CT_LINK:
   4244     break;
   4245   }
   4246   return kc->details.link.provider;
   4247 }
   4248 
   4249 
   4250 struct TALER_KYCLOGIC_AmlProgramRunnerHandle
   4251 {
   4252   /**
   4253    * Function to call back with the result.
   4254    */
   4255   TALER_KYCLOGIC_AmlProgramResultCallback aprc;
   4256 
   4257   /**
   4258    * Closure for @e aprc.
   4259    */
   4260   void *aprc_cls;
   4261 
   4262   /**
   4263    * Handle to an external process.
   4264    */
   4265   struct TALER_JSON_ExternalConversion *proc;
   4266 
   4267   /**
   4268    * AML program to turn.
   4269    */
   4270   const struct TALER_KYCLOGIC_AmlProgram *program;
   4271 
   4272   /**
   4273    * Task to return @e apr result asynchronously.
   4274    */
   4275   struct GNUNET_SCHEDULER_Task *async_cb;
   4276 
   4277   /**
   4278    * Result returned to the client.
   4279    */
   4280   struct TALER_KYCLOGIC_AmlProgramResult apr;
   4281 
   4282   /**
   4283    * How long do we allow the AML program to run?
   4284    */
   4285   struct GNUNET_TIME_Relative timeout;
   4286 
   4287 };
   4288 
   4289 
   4290 /**
   4291  * Function that that receives a JSON @a result from
   4292  * the AML program.
   4293  *
   4294  * @param cls closure of type `struct TALER_KYCLOGIC_AmlProgramRunnerHandle`
   4295  * @param status_type how did the process die
   4296  * @param code termination status code from the process,
   4297  *        non-zero if AML checks are required next
   4298  * @param result some JSON result, NULL if we failed to get an JSON output
   4299  */
   4300 static void
   4301 handle_aml_output (
   4302   void *cls,
   4303   enum GNUNET_OS_ProcessStatusType status_type,
   4304   unsigned long code,
   4305   const json_t *result)
   4306 {
   4307   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls;
   4308   const char *fallback_measure = aprh->program->fallback;
   4309   struct TALER_KYCLOGIC_AmlProgramResult *apr = &aprh->apr;
   4310   const char **evs = NULL;
   4311 
   4312   aprh->proc = NULL;
   4313   if (NULL != aprh->async_cb)
   4314   {
   4315     GNUNET_SCHEDULER_cancel (aprh->async_cb);
   4316     aprh->async_cb = NULL;
   4317   }
   4318 #if DEBUG
   4319   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4320               "AML program %s output is:\n",
   4321               aprh->program->program_name);
   4322   json_dumpf (result,
   4323               stderr,
   4324               JSON_INDENT (2));
   4325 #endif
   4326   memset (apr,
   4327           0,
   4328           sizeof (*apr));
   4329   if ( (GNUNET_OS_PROCESS_EXITED != status_type) ||
   4330        (0 != code) )
   4331   {
   4332     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   4333                 "AML program %s returned non-zero status %d/%d\n",
   4334                 aprh->program->program_name,
   4335                 (int) status_type,
   4336                 (int) code);
   4337     apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4338     apr->details.failure.fallback_measure
   4339       = fallback_measure;
   4340     apr->details.failure.error_message
   4341       = "AML program returned non-zero exit code";
   4342     apr->details.failure.ec
   4343       = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_FAILURE;
   4344     goto ready;
   4345   }
   4346 
   4347   {
   4348     const json_t *jevents = NULL;
   4349     struct GNUNET_JSON_Specification spec[] = {
   4350       GNUNET_JSON_spec_mark_optional (
   4351         GNUNET_JSON_spec_bool (
   4352           "to_investigate",
   4353           &apr->details.success.to_investigate),
   4354         NULL),
   4355       GNUNET_JSON_spec_mark_optional (
   4356         GNUNET_JSON_spec_object_const (
   4357           "properties",
   4358           &apr->details.success.account_properties),
   4359         NULL),
   4360       GNUNET_JSON_spec_mark_optional (
   4361         GNUNET_JSON_spec_array_const (
   4362           "events",
   4363           &jevents),
   4364         NULL),
   4365       GNUNET_JSON_spec_object_const (
   4366         "new_rules",
   4367         &apr->details.success.new_rules),
   4368       GNUNET_JSON_spec_mark_optional (
   4369         GNUNET_JSON_spec_string (
   4370           "new_measures",
   4371           &apr->details.success.new_measures),
   4372         NULL),
   4373       GNUNET_JSON_spec_end ()
   4374     };
   4375     const char *err;
   4376     unsigned int line;
   4377 
   4378     if (GNUNET_OK !=
   4379         GNUNET_JSON_parse (result,
   4380                            spec,
   4381                            &err,
   4382                            &line))
   4383     {
   4384       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4385                   "AML program output is malformed at `%s'\n",
   4386                   err);
   4387       json_dumpf (result,
   4388                   stderr,
   4389                   JSON_INDENT (2));
   4390       apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4391       apr->details.failure.fallback_measure
   4392         = fallback_measure;
   4393       apr->details.failure.error_message
   4394         = err;
   4395       apr->details.failure.ec
   4396         = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT;
   4397       goto ready;
   4398     }
   4399     apr->details.success.num_events
   4400       = json_array_size (jevents);
   4401 
   4402     GNUNET_assert (((size_t) apr->details.success.num_events) ==
   4403                    json_array_size (jevents));
   4404     evs = GNUNET_new_array (
   4405       apr->details.success.num_events,
   4406       const char *);
   4407     for (unsigned int i = 0; i<apr->details.success.num_events; i++)
   4408     {
   4409       evs[i] = json_string_value (
   4410         json_array_get (jevents,
   4411                         i));
   4412       if (NULL == evs[i])
   4413       {
   4414         apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4415         apr->details.failure.fallback_measure
   4416           = fallback_measure;
   4417         apr->details.failure.error_message
   4418           = "events";
   4419         apr->details.failure.ec
   4420           = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT;
   4421         goto ready;
   4422       }
   4423     }
   4424     apr->status = TALER_KYCLOGIC_AMLR_SUCCESS;
   4425     apr->details.success.events = evs;
   4426     {
   4427       /* check new_rules */
   4428       struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs;
   4429 
   4430       lrs = TALER_KYCLOGIC_rules_parse (
   4431         apr->details.success.new_rules);
   4432       if (NULL == lrs)
   4433       {
   4434         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4435                     "AML program output is malformed at `%s'\n",
   4436                     "new_rules");
   4437 
   4438         apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4439         apr->details.failure.fallback_measure
   4440           = fallback_measure;
   4441         apr->details.failure.error_message
   4442           = "new_rules";
   4443         apr->details.failure.ec
   4444           = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT;
   4445         goto ready;
   4446       }
   4447       apr->details.success.expiration_time
   4448         = lrs->expiration_time;
   4449       TALER_KYCLOGIC_rules_free (lrs);
   4450     }
   4451   }
   4452 ready:
   4453   aprh->aprc (aprh->aprc_cls,
   4454               &aprh->apr);
   4455   GNUNET_free (evs);
   4456   TALER_KYCLOGIC_run_aml_program_cancel (aprh);
   4457 }
   4458 
   4459 
   4460 /**
   4461  * Helper function to asynchronously return the result.
   4462  *
   4463  * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return results for
   4464  */
   4465 static void
   4466 async_return_task (void *cls)
   4467 {
   4468   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls;
   4469 
   4470   aprh->async_cb = NULL;
   4471   aprh->aprc (aprh->aprc_cls,
   4472               &aprh->apr);
   4473   TALER_KYCLOGIC_run_aml_program_cancel (aprh);
   4474 }
   4475 
   4476 
   4477 /**
   4478  * Helper function called on timeout on the fallback measure.
   4479  *
   4480  * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return results for
   4481  */
   4482 static void
   4483 handle_aml_timeout2 (void *cls)
   4484 {
   4485   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls;
   4486   struct TALER_KYCLOGIC_AmlProgramResult *apr = &aprh->apr;
   4487   const char *fallback_measure = aprh->program->fallback;
   4488 
   4489   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4490               "Fallback measure %s ran into timeout (!)\n",
   4491               aprh->program->program_name);
   4492   if (NULL != aprh->proc)
   4493   {
   4494     TALER_JSON_external_conversion_stop (aprh->proc);
   4495     aprh->proc = NULL;
   4496   }
   4497   apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4498   apr->details.failure.fallback_measure
   4499     = fallback_measure;
   4500   apr->details.failure.error_message
   4501     = aprh->program->program_name;
   4502   apr->details.failure.ec
   4503     = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT;
   4504   async_return_task (aprh);
   4505 }
   4506 
   4507 
   4508 /**
   4509  * Helper function called on timeout of an AML program.
   4510  * Runs the fallback measure.
   4511  *
   4512  * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return results for
   4513  */
   4514 static void
   4515 handle_aml_timeout (void *cls)
   4516 {
   4517   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls;
   4518   struct TALER_KYCLOGIC_AmlProgramResult *apr = &aprh->apr;
   4519   const char *fallback_measure = aprh->program->fallback;
   4520   const struct TALER_KYCLOGIC_Measure *m;
   4521   const struct TALER_KYCLOGIC_AmlProgram *fprogram;
   4522 
   4523   aprh->async_cb = NULL;
   4524   GNUNET_assert (NULL != fallback_measure);
   4525   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   4526               "AML program %s ran into timeout\n",
   4527               aprh->program->program_name);
   4528   if (NULL != aprh->proc)
   4529   {
   4530     TALER_JSON_external_conversion_stop (aprh->proc);
   4531     aprh->proc = NULL;
   4532   }
   4533 
   4534   m = TALER_KYCLOGIC_get_measure (&default_rules,
   4535                                   fallback_measure);
   4536   /* Fallback program could have "disappeared" due to configuration change,
   4537      as we do not check all rule sets in the database when our configuration
   4538      is updated... */
   4539   if (NULL == m)
   4540   {
   4541     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4542                 "Fallback measure `%s' does not exist (anymore?).\n",
   4543                 fallback_measure);
   4544     apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4545     apr->details.failure.fallback_measure
   4546       = fallback_measure;
   4547     apr->details.failure.error_message
   4548       = aprh->program->program_name;
   4549     apr->details.failure.ec
   4550       = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT;
   4551     async_return_task (aprh);
   4552     return;
   4553   }
   4554   /* We require fallback measures to have a 'SKIP' check */
   4555   GNUNET_break (0 ==
   4556                 strcasecmp (m->check_name,
   4557                             "SKIP"));
   4558   fprogram = find_program (m->prog_name);
   4559   /* Program associated with an original measure must exist */
   4560   GNUNET_assert (NULL != fprogram);
   4561   if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES)))
   4562   {
   4563     /* We might not have recognized the fallback measure as such
   4564        because it was not used as such in the plain configuration,
   4565        and legitimization rule sets might have referred to an older
   4566        configuration. So this should be super-rare but possible. */
   4567     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4568                 "Program `%s' used in fallback measure `%s' requires inputs and is thus unsuitable as a fallback measure!\n",
   4569                 m->prog_name,
   4570                 fallback_measure);
   4571     apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4572     apr->details.failure.fallback_measure
   4573       = fallback_measure;
   4574     apr->details.failure.error_message
   4575       = aprh->program->program_name;
   4576     apr->details.failure.ec
   4577       = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT;
   4578     async_return_task (aprh);
   4579     return;
   4580   }
   4581   {
   4582     /* Run fallback AML program */
   4583     json_t *input = json_object ();
   4584     const char *extra_args[] = {
   4585       "-c",
   4586       cfg_filename,
   4587       NULL,
   4588     };
   4589     char **args;
   4590 
   4591     args = split_words (fprogram->command,
   4592                         extra_args);
   4593     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4594                 "Running fallback measure `%s' (%s)\n",
   4595                 fallback_measure,
   4596                 fprogram->command);
   4597     aprh->proc = TALER_JSON_external_conversion_start (
   4598       input,
   4599       &handle_aml_output,
   4600       aprh,
   4601       args[0],
   4602       (const char **) args);
   4603     destroy_words (args);
   4604     json_decref (input);
   4605   }
   4606   aprh->async_cb = GNUNET_SCHEDULER_add_delayed (aprh->timeout,
   4607                                                  &handle_aml_timeout2,
   4608                                                  aprh);
   4609 }
   4610 
   4611 
   4612 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *
   4613 TALER_KYCLOGIC_run_aml_program (
   4614   const json_t *jmeasures,
   4615   bool is_wallet,
   4616   unsigned int measure_index,
   4617   TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb,
   4618   void *current_attributes_cb_cls,
   4619   TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb,
   4620   void *current_rules_cb_cls,
   4621   TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb,
   4622   void *aml_history_cb_cls,
   4623   TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
   4624   void *kyc_history_cb_cls,
   4625   struct GNUNET_TIME_Relative timeout,
   4626   TALER_KYCLOGIC_AmlProgramResultCallback aprc,
   4627   void *aprc_cls)
   4628 {
   4629   const json_t *context;
   4630   const char *check_name;
   4631   const char *prog_name;
   4632 
   4633   {
   4634     enum TALER_ErrorCode ec;
   4635 
   4636     ec = TALER_KYCLOGIC_select_measure (jmeasures,
   4637                                         measure_index,
   4638                                         &check_name,
   4639                                         &prog_name,
   4640                                         &context);
   4641     if (TALER_EC_NONE != ec)
   4642     {
   4643       GNUNET_break (0);
   4644       return NULL;
   4645     }
   4646   }
   4647   if (NULL == prog_name)
   4648   {
   4649     /* Trying to run AML program on a measure that does not
   4650        have one, and that should thus be an INFO check which
   4651        should never lead here. Very strange. */
   4652     GNUNET_break (0);
   4653     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4654                 "Measure %u with check `%s' does not have an AML program!\n",
   4655                 measure_index,
   4656                 check_name);
   4657     json_dumpf (jmeasures,
   4658                 stderr,
   4659                 JSON_INDENT (2));
   4660     return NULL;
   4661   }
   4662   return TALER_KYCLOGIC_run_aml_program2 (prog_name,
   4663                                           context,
   4664                                           is_wallet,
   4665                                           current_attributes_cb,
   4666                                           current_attributes_cb_cls,
   4667                                           current_rules_cb,
   4668                                           current_rules_cb_cls,
   4669                                           aml_history_cb,
   4670                                           aml_history_cb_cls,
   4671                                           kyc_history_cb,
   4672                                           kyc_history_cb_cls,
   4673                                           timeout,
   4674                                           aprc,
   4675                                           aprc_cls);
   4676 }
   4677 
   4678 
   4679 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *
   4680 TALER_KYCLOGIC_run_aml_program2 (
   4681   const char *prog_name,
   4682   const json_t *context,
   4683   bool is_wallet,
   4684   TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb,
   4685   void *current_attributes_cb_cls,
   4686   TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb,
   4687   void *current_rules_cb_cls,
   4688   TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb,
   4689   void *aml_history_cb_cls,
   4690   TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
   4691   void *kyc_history_cb_cls,
   4692   struct GNUNET_TIME_Relative timeout,
   4693   TALER_KYCLOGIC_AmlProgramResultCallback aprc,
   4694   void *aprc_cls)
   4695 {
   4696   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh;
   4697   struct TALER_KYCLOGIC_AmlProgram *prog;
   4698   const json_t *jdefault_rules;
   4699   json_t *current_rules;
   4700   json_t *aml_history;
   4701   json_t *kyc_history;
   4702   json_t *attributes;
   4703 
   4704   prog = find_program (prog_name);
   4705   if (NULL == prog)
   4706   {
   4707     GNUNET_break (0);
   4708     return NULL;
   4709   }
   4710   aprh = GNUNET_new (struct TALER_KYCLOGIC_AmlProgramRunnerHandle);
   4711   aprh->aprc = aprc;
   4712   aprh->aprc_cls = aprc_cls;
   4713   aprh->program = prog;
   4714   if (0 != (API_ATTRIBUTES & prog->input_mask))
   4715   {
   4716     attributes = current_attributes_cb (current_attributes_cb_cls);
   4717 #if DEBUG
   4718     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4719                 "KYC attributes for AML program %s are:\n",
   4720                 prog_name);
   4721     json_dumpf (attributes,
   4722                 stderr,
   4723                 JSON_INDENT (2));
   4724     fprintf (stderr,
   4725              "\n");
   4726 #endif
   4727     for (unsigned int i = 0; i<prog->num_required_attributes; i++)
   4728     {
   4729       const char *rattr = prog->required_attributes[i];
   4730 
   4731       if (NULL == json_object_get (attributes,
   4732                                    rattr))
   4733       {
   4734         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4735                     "KYC attributes lack required attribute `%s' for AML program %s\n",
   4736                     rattr,
   4737                     prog->program_name);
   4738 #if DEBUG
   4739         json_dumpf (attributes,
   4740                     stderr,
   4741                     JSON_INDENT (2));
   4742 #endif
   4743         aprh->apr.status = TALER_KYCLOGIC_AMLR_FAILURE;
   4744         aprh->apr.details.failure.fallback_measure
   4745           = prog->fallback;
   4746         aprh->apr.details.failure.error_message
   4747           = rattr;
   4748         aprh->apr.details.failure.ec
   4749           = TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_INCOMPLETE_REPLY;
   4750         aprh->async_cb
   4751           = GNUNET_SCHEDULER_add_now (&async_return_task,
   4752                                       aprh);
   4753         json_decref (attributes);
   4754         return aprh;
   4755       }
   4756     }
   4757   }
   4758   else
   4759   {
   4760     attributes = NULL;
   4761   }
   4762   if (0 != (API_CONTEXT & prog->input_mask))
   4763   {
   4764     for (unsigned int i = 0; i<prog->num_required_contexts; i++)
   4765     {
   4766       const char *rctx = prog->required_contexts[i];
   4767 
   4768       if (NULL == json_object_get (context,
   4769                                    rctx))
   4770       {
   4771         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4772                     "Context lacks required field `%s' for AML program %s\n",
   4773                     rctx,
   4774                     prog->program_name);
   4775 #if DEBUG
   4776         json_dumpf (context,
   4777                     stderr,
   4778                     JSON_INDENT (2));
   4779 #endif
   4780         aprh->apr.status = TALER_KYCLOGIC_AMLR_FAILURE;
   4781         aprh->apr.details.failure.fallback_measure
   4782           = prog->fallback;
   4783         aprh->apr.details.failure.error_message
   4784           = rctx;
   4785         aprh->apr.details.failure.ec
   4786           = TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_INCOMPLETE_CONTEXT;
   4787         aprh->async_cb
   4788           = GNUNET_SCHEDULER_add_now (&async_return_task,
   4789                                       aprh);
   4790         json_decref (attributes);
   4791         return aprh;
   4792       }
   4793     }
   4794   }
   4795   else
   4796   {
   4797     context = NULL;
   4798   }
   4799   if (0 == (API_AML_HISTORY & prog->input_mask))
   4800     aml_history = NULL;
   4801   else
   4802     aml_history = aml_history_cb (aml_history_cb_cls);
   4803   if (0 == (API_KYC_HISTORY & prog->input_mask))
   4804     kyc_history = NULL;
   4805   else
   4806     kyc_history = kyc_history_cb (kyc_history_cb_cls);
   4807   if (0 == (API_CURRENT_RULES & prog->input_mask))
   4808     current_rules = NULL;
   4809   else
   4810     current_rules = current_rules_cb (current_rules_cb_cls);
   4811   if (0 != (API_DEFAULT_RULES & prog->input_mask))
   4812     jdefault_rules =
   4813       (is_wallet
   4814        ? wallet_default_lrs
   4815        : bankaccount_default_lrs);
   4816   else
   4817     jdefault_rules = NULL;
   4818   {
   4819     json_t *input;
   4820     const char *extra_args[] = {
   4821       "-c",
   4822       cfg_filename,
   4823       NULL,
   4824     };
   4825     char **args;
   4826 
   4827     input = GNUNET_JSON_PACK (
   4828       GNUNET_JSON_pack_allow_null (
   4829         GNUNET_JSON_pack_object_steal ("current_rules",
   4830                                        current_rules)),
   4831       GNUNET_JSON_pack_allow_null (
   4832         GNUNET_JSON_pack_object_incref ("default_rules",
   4833                                         (json_t *) jdefault_rules)),
   4834       GNUNET_JSON_pack_allow_null (
   4835         GNUNET_JSON_pack_object_incref ("context",
   4836                                         (json_t *) context)),
   4837       GNUNET_JSON_pack_allow_null (
   4838         GNUNET_JSON_pack_object_steal ("attributes",
   4839                                        attributes)),
   4840       GNUNET_JSON_pack_allow_null (
   4841         GNUNET_JSON_pack_array_steal ("aml_history",
   4842                                       aml_history)),
   4843       GNUNET_JSON_pack_allow_null (
   4844         GNUNET_JSON_pack_array_steal ("kyc_history",
   4845                                       kyc_history))
   4846       );
   4847     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4848                 "Running AML program %s\n",
   4849                 prog->command);
   4850     args = split_words (prog->command,
   4851                         extra_args);
   4852     GNUNET_assert (NULL != args);
   4853     GNUNET_assert (NULL != args[0]);
   4854 #if DEBUG
   4855     json_dumpf (input,
   4856                 stderr,
   4857                 JSON_INDENT (2));
   4858 #endif
   4859     aprh->proc = TALER_JSON_external_conversion_start (
   4860       input,
   4861       &handle_aml_output,
   4862       aprh,
   4863       args[0],
   4864       (const char **) args);
   4865     destroy_words (args);
   4866     json_decref (input);
   4867   }
   4868   aprh->timeout = timeout;
   4869   aprh->async_cb = GNUNET_SCHEDULER_add_delayed (timeout,
   4870                                                  &handle_aml_timeout,
   4871                                                  aprh);
   4872   return aprh;
   4873 }
   4874 
   4875 
   4876 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *
   4877 TALER_KYCLOGIC_run_aml_program3 (
   4878   bool is_wallet,
   4879   const struct TALER_KYCLOGIC_Measure *measure,
   4880   TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb,
   4881   void *current_attributes_cb_cls,
   4882   TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb,
   4883   void *current_rules_cb_cls,
   4884   TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb,
   4885   void *aml_history_cb_cls,
   4886   TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
   4887   void *kyc_history_cb_cls,
   4888   struct GNUNET_TIME_Relative timeout,
   4889   TALER_KYCLOGIC_AmlProgramResultCallback aprc,
   4890   void *aprc_cls)
   4891 {
   4892   return TALER_KYCLOGIC_run_aml_program2 (
   4893     measure->prog_name,
   4894     measure->context,
   4895     is_wallet,
   4896     current_attributes_cb,
   4897     current_attributes_cb_cls,
   4898     current_rules_cb,
   4899     current_rules_cb_cls,
   4900     aml_history_cb,
   4901     aml_history_cb_cls,
   4902     kyc_history_cb,
   4903     kyc_history_cb_cls,
   4904     timeout,
   4905     aprc,
   4906     aprc_cls);
   4907 }
   4908 
   4909 
   4910 const char *
   4911 TALER_KYCLOGIC_run_aml_program_get_name (
   4912   const struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh)
   4913 {
   4914   return aprh->program->program_name;
   4915 }
   4916 
   4917 
   4918 void
   4919 TALER_KYCLOGIC_run_aml_program_cancel (
   4920   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh)
   4921 {
   4922   if (NULL != aprh->proc)
   4923   {
   4924     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   4925                 "Killing AML program\n");
   4926     TALER_JSON_external_conversion_stop (aprh->proc);
   4927     aprh->proc = NULL;
   4928   }
   4929   if (NULL != aprh->async_cb)
   4930   {
   4931     GNUNET_SCHEDULER_cancel (aprh->async_cb);
   4932     aprh->async_cb = NULL;
   4933   }
   4934   GNUNET_free (aprh);
   4935 }
   4936 
   4937 
   4938 json_t *
   4939 TALER_KYCLOGIC_get_hard_limits ()
   4940 {
   4941   const struct TALER_KYCLOGIC_KycRule *rules
   4942     = default_rules.kyc_rules;
   4943   unsigned int num_rules
   4944     = default_rules.num_kyc_rules;
   4945   json_t *hard_limits;
   4946 
   4947   hard_limits = json_array ();
   4948   GNUNET_assert (NULL != hard_limits);
   4949   for (unsigned int i = 0; i<num_rules; i++)
   4950   {
   4951     const struct TALER_KYCLOGIC_KycRule *rule = &rules[i];
   4952     json_t *hard_limit;
   4953 
   4954     if (! rule->verboten)
   4955       continue;
   4956     if (! rule->exposed)
   4957       continue;
   4958     hard_limit = GNUNET_JSON_PACK (
   4959       GNUNET_JSON_pack_allow_null (
   4960         GNUNET_JSON_pack_string ("rule_name",
   4961                                  rule->rule_name)),
   4962       TALER_JSON_pack_kycte ("operation_type",
   4963                              rule->trigger),
   4964       GNUNET_JSON_pack_time_rel ("timeframe",
   4965                                  rule->timeframe),
   4966       TALER_JSON_pack_amount ("threshold",
   4967                               &rule->threshold)
   4968       );
   4969     GNUNET_assert (0 ==
   4970                    json_array_append_new (hard_limits,
   4971                                           hard_limit));
   4972   }
   4973   return hard_limits;
   4974 }
   4975 
   4976 
   4977 json_t *
   4978 TALER_KYCLOGIC_get_zero_limits ()
   4979 {
   4980   const struct TALER_KYCLOGIC_KycRule *rules
   4981     = default_rules.kyc_rules;
   4982   unsigned int num_rules
   4983     = default_rules.num_kyc_rules;
   4984   json_t *zero_limits;
   4985 
   4986   zero_limits = json_array ();
   4987   GNUNET_assert (NULL != zero_limits);
   4988   for (unsigned int i = 0; i<num_rules; i++)
   4989   {
   4990     const struct TALER_KYCLOGIC_KycRule *rule = &rules[i];
   4991     json_t *zero_limit;
   4992 
   4993     if (! rule->exposed)
   4994       continue;
   4995     if (rule->verboten)
   4996       continue; /* see: hard_limits */
   4997     if (! TALER_amount_is_zero (&rule->threshold))
   4998       continue;
   4999     zero_limit = GNUNET_JSON_PACK (
   5000       GNUNET_JSON_pack_allow_null (
   5001         GNUNET_JSON_pack_string ("rule_name",
   5002                                  rule->rule_name)),
   5003       TALER_JSON_pack_kycte ("operation_type",
   5004                              rule->trigger));
   5005     GNUNET_assert (0 ==
   5006                    json_array_append_new (zero_limits,
   5007                                           zero_limit));
   5008   }
   5009   return zero_limits;
   5010 }
   5011 
   5012 
   5013 json_t *
   5014 TALER_KYCLOGIC_get_default_legi_rules (bool for_wallet)
   5015 {
   5016   const json_t *r;
   5017 
   5018   r = (for_wallet
   5019        ? wallet_default_lrs
   5020        : bankaccount_default_lrs);
   5021   return json_incref ((json_t *) r);
   5022 }
   5023 
   5024 
   5025 /* end of kyclogic_api.c */