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 (150513B)


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