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


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