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


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2022-2025 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file kyclogic_api.c
     18  * @brief server-side KYC API
     19  * @author Christian Grothoff
     20  */
     21 #include "platform.h"  /* UNNECESSARY? */
     22 #include "taler/taler_json_lib.h"
     23 #include "taler/taler_kyclogic_lib.h"
     24 
     25 /**
     26  * Log verbosely, including possibly privacy-sensitive data.
     27  */
     28 #define DEBUG 1
     29 
     30 /**
     31  * Name of the KYC measure that may never be passed. Useful if some
     32  * operations/amounts are categorically forbidden.
     33  */
     34 #define KYC_MEASURE_IMPOSSIBLE "verboten"
     35 
     36 /**
     37  * Information about a KYC provider.
     38  */
     39 struct TALER_KYCLOGIC_KycProvider
     40 {
     41 
     42   /**
     43    * Name of the provider.
     44    */
     45   char *provider_name;
     46 
     47   /**
     48    * Logic to run for this provider.
     49    */
     50   struct TALER_KYCLOGIC_Plugin *logic;
     51 
     52   /**
     53    * Provider-specific details to pass to the @e logic functions.
     54    */
     55   struct TALER_KYCLOGIC_ProviderDetails *pd;
     56 
     57 };
     58 
     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  * Run @a command with @a argument and return the
   1772  * respective output from stdout.
   1773  *
   1774  * @param command binary to run
   1775  * @param argument command-line argument to pass
   1776  * @return NULL if @a command failed
   1777  */
   1778 static char *
   1779 command_output (const char *command,
   1780                 const char *argument)
   1781 {
   1782   char *rval;
   1783   unsigned int sval;
   1784   size_t soff;
   1785   ssize_t ret;
   1786   int sout[2];
   1787   pid_t chld;
   1788   const char *extra_args[] = {
   1789     argument,
   1790     "-c",
   1791     cfg_filename,
   1792     NULL,
   1793   };
   1794 
   1795   if (0 != pipe (sout))
   1796   {
   1797     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
   1798                          "pipe");
   1799     return NULL;
   1800   }
   1801   chld = fork ();
   1802   if (-1 == chld)
   1803   {
   1804     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
   1805                          "fork");
   1806     return NULL;
   1807   }
   1808   if (0 == chld)
   1809   {
   1810     char **argv;
   1811 
   1812     argv = TALER_words_split (command,
   1813                               extra_args);
   1814 
   1815     GNUNET_break (0 ==
   1816                   close (sout[0]));
   1817     GNUNET_break (0 ==
   1818                   close (STDOUT_FILENO));
   1819     GNUNET_assert (STDOUT_FILENO ==
   1820                    dup2 (sout[1],
   1821                          STDOUT_FILENO));
   1822     GNUNET_break (0 ==
   1823                   close (sout[1]));
   1824     execvp (argv[0],
   1825             argv);
   1826     TALER_words_destroy (argv);
   1827     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
   1828                               "exec",
   1829                               command);
   1830     exit (EXIT_FAILURE);
   1831   }
   1832   GNUNET_break (0 ==
   1833                 close (sout[1]));
   1834   sval = 1024;
   1835   rval = GNUNET_malloc (sval);
   1836   soff = 0;
   1837   while (0 < (ret = read (sout[0],
   1838                           rval + soff,
   1839                           sval - soff)) )
   1840   {
   1841     soff += ret;
   1842     if (soff == sval)
   1843     {
   1844       GNUNET_array_grow (rval,
   1845                          sval,
   1846                          sval * 2);
   1847     }
   1848   }
   1849   GNUNET_break (0 == close (sout[0]));
   1850   {
   1851     int wstatus;
   1852 
   1853     GNUNET_break (chld ==
   1854                   waitpid (chld,
   1855                            &wstatus,
   1856                            0));
   1857     if ( (! WIFEXITED (wstatus)) ||
   1858          (0 != WEXITSTATUS (wstatus)) )
   1859     {
   1860       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1861                   "Command `%s' %s failed with status %d\n",
   1862                   command,
   1863                   argument,
   1864                   wstatus);
   1865       GNUNET_array_grow (rval,
   1866                          sval,
   1867                          0);
   1868       return NULL;
   1869     }
   1870   }
   1871   GNUNET_array_grow (rval,
   1872                      sval,
   1873                      soff + 1);
   1874   rval[soff] = '\0';
   1875   return rval;
   1876 }
   1877 
   1878 
   1879 /**
   1880  * Convert check type @a ctype_s into @a ctype.
   1881  *
   1882  * @param ctype_s check type as a string
   1883  * @param[out] ctype set to check type as enum
   1884  * @return #GNUNET_OK on success
   1885  */
   1886 static enum GNUNET_GenericReturnValue
   1887 check_type_from_string (
   1888   const char *ctype_s,
   1889   enum TALER_KYCLOGIC_CheckType *ctype)
   1890 {
   1891   struct
   1892   {
   1893     const char *in;
   1894     enum TALER_KYCLOGIC_CheckType out;
   1895   } map [] = {
   1896     { "INFO", TALER_KYCLOGIC_CT_INFO },
   1897     { "LINK", TALER_KYCLOGIC_CT_LINK },
   1898     { "FORM", TALER_KYCLOGIC_CT_FORM  },
   1899     { NULL, 0 }
   1900   };
   1901 
   1902   for (unsigned int i = 0; NULL != map[i].in; i++)
   1903     if (0 == strcasecmp (map[i].in,
   1904                          ctype_s))
   1905     {
   1906       *ctype = map[i].out;
   1907       return GNUNET_OK;
   1908     }
   1909   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1910               "Invalid check type `%s'\n",
   1911               ctype_s);
   1912   return GNUNET_SYSERR;
   1913 }
   1914 
   1915 
   1916 enum GNUNET_GenericReturnValue
   1917 TALER_KYCLOGIC_kyc_trigger_from_string (
   1918   const char *trigger_s,
   1919   enum TALER_KYCLOGIC_KycTriggerEvent *trigger)
   1920 {
   1921   /* NOTE: if you change this, also change
   1922      the code in src/json/json_helper.c! */
   1923   struct
   1924   {
   1925     const char *in;
   1926     enum TALER_KYCLOGIC_KycTriggerEvent out;
   1927   } map [] = {
   1928     { "WITHDRAW", TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW },
   1929     { "DEPOSIT", TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT  },
   1930     { "MERGE", TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE },
   1931     { "BALANCE", TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE },
   1932     { "CLOSE", TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE },
   1933     { "AGGREGATE", TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE },
   1934     { "TRANSACTION", TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION },
   1935     { "REFUND", TALER_KYCLOGIC_KYC_TRIGGER_REFUND },
   1936     { NULL, 0 }
   1937   };
   1938 
   1939   for (unsigned int i = 0; NULL != map[i].in; i++)
   1940     if (0 == strcasecmp (map[i].in,
   1941                          trigger_s))
   1942     {
   1943       *trigger = map[i].out;
   1944       return GNUNET_OK;
   1945     }
   1946   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1947               "Invalid KYC trigger `%s'\n",
   1948               trigger_s);
   1949   return GNUNET_SYSERR;
   1950 }
   1951 
   1952 
   1953 json_t *
   1954 TALER_KYCLOGIC_get_wallet_thresholds (void)
   1955 {
   1956   json_t *ret;
   1957 
   1958   ret = json_array ();
   1959   GNUNET_assert (NULL != ret);
   1960   for (unsigned int i = 0; i<default_rules.num_kyc_rules; i++)
   1961   {
   1962     struct TALER_KYCLOGIC_KycRule *rule
   1963       = &default_rules.kyc_rules[i];
   1964 
   1965     if (TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE != rule->trigger)
   1966       continue;
   1967     GNUNET_assert (
   1968       0 ==
   1969       json_array_append_new (
   1970         ret,
   1971         TALER_JSON_from_amount (
   1972           &rule->threshold)));
   1973   }
   1974   return ret;
   1975 }
   1976 
   1977 
   1978 /**
   1979  * Load KYC logic plugin.
   1980  *
   1981  * @param cfg configuration to use
   1982  * @param name name of the plugin
   1983  * @return NULL on error
   1984  */
   1985 static struct TALER_KYCLOGIC_Plugin *
   1986 load_logic (const struct GNUNET_CONFIGURATION_Handle *cfg,
   1987             const char *name)
   1988 {
   1989   char *lib_name;
   1990   struct TALER_KYCLOGIC_Plugin *plugin;
   1991 
   1992 
   1993   GNUNET_asprintf (&lib_name,
   1994                    "libtaler_plugin_kyclogic_%s",
   1995                    name);
   1996   if (! ascii_lower (lib_name))
   1997   {
   1998     GNUNET_free (lib_name);
   1999     return NULL;
   2000   }
   2001   for (unsigned int i = 0; i<num_kyc_logics; i++)
   2002     if (0 == strcasecmp (lib_name,
   2003                          kyc_logics[i]->library_name))
   2004     {
   2005       GNUNET_free (lib_name);
   2006       return kyc_logics[i];
   2007     }
   2008   plugin = GNUNET_PLUGIN_load (TALER_EXCHANGE_project_data (),
   2009                                lib_name,
   2010                                (void *) cfg);
   2011   if (NULL == plugin)
   2012   {
   2013     GNUNET_free (lib_name);
   2014     return NULL;
   2015   }
   2016   plugin->library_name = lib_name;
   2017   plugin->name = GNUNET_strdup (name);
   2018   GNUNET_array_append (kyc_logics,
   2019                        num_kyc_logics,
   2020                        plugin);
   2021   return plugin;
   2022 }
   2023 
   2024 
   2025 /**
   2026  * Parse configuration of a KYC provider.
   2027  *
   2028  * @param cfg configuration to parse
   2029  * @param section name of the section to analyze
   2030  * @return #GNUNET_OK on success
   2031  */
   2032 static enum GNUNET_GenericReturnValue
   2033 add_provider (const struct GNUNET_CONFIGURATION_Handle *cfg,
   2034               const char *section)
   2035 {
   2036   char *logic;
   2037   struct TALER_KYCLOGIC_Plugin *lp;
   2038   struct TALER_KYCLOGIC_ProviderDetails *pd;
   2039 
   2040   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2041               "Parsing KYC provider %s\n",
   2042               section);
   2043   if (GNUNET_OK !=
   2044       GNUNET_CONFIGURATION_get_value_string (cfg,
   2045                                              section,
   2046                                              "LOGIC",
   2047                                              &logic))
   2048   {
   2049     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2050                                section,
   2051                                "LOGIC");
   2052     return GNUNET_SYSERR;
   2053   }
   2054   if (! ascii_lower (logic))
   2055   {
   2056     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2057                                section,
   2058                                "LOGIC",
   2059                                "Only [a-zA-Z0-9_0] are allowed");
   2060     return GNUNET_SYSERR;
   2061   }
   2062   lp = load_logic (cfg,
   2063                    logic);
   2064   if (NULL == lp)
   2065   {
   2066     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2067                                section,
   2068                                "LOGIC",
   2069                                "logic plugin could not be loaded");
   2070     GNUNET_free (logic);
   2071     return GNUNET_SYSERR;
   2072   }
   2073   GNUNET_free (logic);
   2074   pd = lp->load_configuration (lp->cls,
   2075                                section);
   2076   if (NULL == pd)
   2077     return GNUNET_SYSERR;
   2078 
   2079   {
   2080     struct TALER_KYCLOGIC_KycProvider *kp;
   2081 
   2082     kp = GNUNET_new (struct TALER_KYCLOGIC_KycProvider);
   2083     kp->provider_name
   2084       = GNUNET_strdup (&section[strlen ("kyc-provider-")]);
   2085     kp->logic = lp;
   2086     kp->pd = pd;
   2087     GNUNET_array_append (kyc_providers,
   2088                          num_kyc_providers,
   2089                          kp);
   2090   }
   2091   return GNUNET_OK;
   2092 }
   2093 
   2094 
   2095 /**
   2096  * Tokenize @a input along @a token
   2097  * and build an array of the tokens.
   2098  *
   2099  * @param[in,out] input the input to tokenize; clobbered
   2100  * @param sep separator between tokens to separate @a input on
   2101  * @param[out] p_strs where to put array of tokens
   2102  * @param[out] num_strs set to length of @a p_strs array
   2103  */
   2104 static void
   2105 add_tokens (char *input,
   2106             const char *sep,
   2107             char ***p_strs,
   2108             unsigned int *num_strs)
   2109 {
   2110   char *sptr;
   2111   char **rstr = NULL;
   2112   unsigned int num_rstr = 0;
   2113 
   2114   for (char *tok = strtok_r (input, sep, &sptr);
   2115        NULL != tok;
   2116        tok = strtok_r (NULL, sep, &sptr))
   2117   {
   2118     GNUNET_array_append (rstr,
   2119                          num_rstr,
   2120                          GNUNET_strdup (tok));
   2121   }
   2122   *p_strs = rstr;
   2123   *num_strs = num_rstr;
   2124 }
   2125 
   2126 
   2127 /**
   2128  * Closure for the handle_XXX_section functions
   2129  * that parse configuration sections matching certain
   2130  * prefixes.
   2131  */
   2132 struct SectionContext
   2133 {
   2134   /**
   2135    * Configuration to handle.
   2136    */
   2137   const struct GNUNET_CONFIGURATION_Handle *cfg;
   2138 
   2139   /**
   2140    * Result to return, set to false on failures.
   2141    */
   2142   bool result;
   2143 };
   2144 
   2145 
   2146 /**
   2147  * Function to iterate over configuration sections.
   2148  *
   2149  * @param cls a `struct SectionContext *`
   2150  * @param section name of the section
   2151  */
   2152 static void
   2153 handle_provider_section (void *cls,
   2154                          const char *section)
   2155 {
   2156   struct SectionContext *sc = cls;
   2157   char *s;
   2158 
   2159   if (! sc->result)
   2160     return;
   2161   s = normalize_section_with_prefix ("kyc-provider-",
   2162                                      section);
   2163   if (NULL == s)
   2164     return;
   2165   if (GNUNET_OK !=
   2166       add_provider (sc->cfg,
   2167                     s))
   2168   {
   2169     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2170                 "Setup failed in configuration section `%s'\n",
   2171                 section);
   2172     sc->result = false;
   2173   }
   2174   GNUNET_free (s);
   2175 }
   2176 
   2177 
   2178 /**
   2179  * Parse configuration @a cfg in section @a section for
   2180  * the specification of a KYC check.
   2181  *
   2182  * @param cfg configuration to parse
   2183  * @param section configuration section to parse
   2184  * @return #GNUNET_OK on success
   2185  */
   2186 static enum GNUNET_GenericReturnValue
   2187 add_check (const struct GNUNET_CONFIGURATION_Handle *cfg,
   2188            const char *section)
   2189 {
   2190   enum TALER_KYCLOGIC_CheckType ct;
   2191   char *description = NULL;
   2192   json_t *description_i18n = NULL;
   2193   char *requires = NULL;
   2194   char *outputs = NULL;
   2195   char *fallback = NULL;
   2196 
   2197   if (0 == strcasecmp (&section[strlen ("kyc-check-")],
   2198                        "skip"))
   2199   {
   2200     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2201                 "The kyc-check-skip section must not exist, 'skip' is reserved name for a built-in check\n");
   2202     return GNUNET_SYSERR;
   2203   }
   2204   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2205               "Parsing KYC check %s\n",
   2206               section);
   2207   {
   2208     char *type_s;
   2209 
   2210     if (GNUNET_OK !=
   2211         GNUNET_CONFIGURATION_get_value_string (cfg,
   2212                                                section,
   2213                                                "TYPE",
   2214                                                &type_s))
   2215     {
   2216       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2217                                  section,
   2218                                  "TYPE");
   2219       return GNUNET_SYSERR;
   2220     }
   2221     if (GNUNET_OK !=
   2222         check_type_from_string (type_s,
   2223                                 &ct))
   2224     {
   2225       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2226                                  section,
   2227                                  "TYPE",
   2228                                  "valid check type required");
   2229       GNUNET_free (type_s);
   2230       return GNUNET_SYSERR;
   2231     }
   2232     GNUNET_free (type_s);
   2233   }
   2234 
   2235   if (GNUNET_OK !=
   2236       GNUNET_CONFIGURATION_get_value_string (cfg,
   2237                                              section,
   2238                                              "DESCRIPTION",
   2239                                              &description))
   2240   {
   2241     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2242                                section,
   2243                                "DESCRIPTION");
   2244     goto fail;
   2245   }
   2246 
   2247   {
   2248     char *tmp;
   2249 
   2250     if (GNUNET_OK ==
   2251         GNUNET_CONFIGURATION_get_value_string (cfg,
   2252                                                section,
   2253                                                "DESCRIPTION_I18N",
   2254                                                &tmp))
   2255     {
   2256       json_error_t err;
   2257 
   2258       description_i18n = json_loads (tmp,
   2259                                      JSON_REJECT_DUPLICATES,
   2260                                      &err);
   2261       GNUNET_free (tmp);
   2262       if (NULL == description_i18n)
   2263       {
   2264         GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2265                                    section,
   2266                                    "DESCRIPTION_I18N",
   2267                                    err.text);
   2268         goto fail;
   2269       }
   2270       if (! TALER_JSON_check_i18n (description_i18n) )
   2271       {
   2272         GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2273                                    section,
   2274                                    "DESCRIPTION_I18N",
   2275                                    "JSON with internationalization map required");
   2276         goto fail;
   2277       }
   2278     }
   2279   }
   2280 
   2281   if (GNUNET_OK !=
   2282       GNUNET_CONFIGURATION_get_value_string (cfg,
   2283                                              section,
   2284                                              "REQUIRES",
   2285                                              &requires))
   2286   {
   2287     /* no requirements is OK */
   2288     requires = GNUNET_strdup ("");
   2289   }
   2290 
   2291   if (GNUNET_OK !=
   2292       GNUNET_CONFIGURATION_get_value_string (cfg,
   2293                                              section,
   2294                                              "OUTPUTS",
   2295                                              &outputs))
   2296   {
   2297     /* no outputs is OK */
   2298     outputs = GNUNET_strdup ("");
   2299   }
   2300 
   2301   if (GNUNET_OK !=
   2302       GNUNET_CONFIGURATION_get_value_string (cfg,
   2303                                              section,
   2304                                              "FALLBACK",
   2305                                              &fallback))
   2306   {
   2307     /* We do *not* allow NULL to fall back to default rules because fallbacks
   2308        are used when there is actually a serious error and thus some action
   2309        (usually an investigation) is always in order, and that's basically
   2310        never the default. And as fallbacks should be rare, we really insist on
   2311        them at least being explicitly configured. Otherwise these errors may
   2312        go undetected simply because someone forgot to configure a fallback and
   2313        then nothing happens. */
   2314     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2315                                section,
   2316                                "FALLBACK");
   2317     goto fail;
   2318   }
   2319   if (! ascii_lower (fallback))
   2320   {
   2321     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2322                                section,
   2323                                "FALLBACK",
   2324                                "Only [a-zA-Z0-9_0] are allowed");
   2325     goto fail;
   2326   }
   2327 
   2328   {
   2329     struct TALER_KYCLOGIC_KycCheck *kc;
   2330 
   2331     kc = GNUNET_new (struct TALER_KYCLOGIC_KycCheck);
   2332     switch (ct)
   2333     {
   2334     case TALER_KYCLOGIC_CT_INFO:
   2335       /* nothing to do */
   2336       break;
   2337     case TALER_KYCLOGIC_CT_FORM:
   2338       {
   2339         char *form_name;
   2340 
   2341         if (GNUNET_OK !=
   2342             GNUNET_CONFIGURATION_get_value_string (cfg,
   2343                                                    section,
   2344                                                    "FORM_NAME",
   2345                                                    &form_name))
   2346         {
   2347           GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2348                                      section,
   2349                                      "FORM_NAME");
   2350           GNUNET_free (requires);
   2351           GNUNET_free (outputs);
   2352           GNUNET_free (kc);
   2353           return GNUNET_SYSERR;
   2354         }
   2355         if (! ascii_lower (form_name))
   2356         {
   2357           GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2358                                      section,
   2359                                      "FORM_NAME",
   2360                                      "Only [a-zA-Z0-9_0] are allowed");
   2361           goto fail;
   2362         }
   2363         kc->details.form.name = form_name;
   2364       }
   2365       break;
   2366     case TALER_KYCLOGIC_CT_LINK:
   2367       {
   2368         char *provider_id;
   2369 
   2370         if (GNUNET_OK !=
   2371             GNUNET_CONFIGURATION_get_value_string (cfg,
   2372                                                    section,
   2373                                                    "PROVIDER_ID",
   2374                                                    &provider_id))
   2375         {
   2376           GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2377                                      section,
   2378                                      "PROVIDER_ID");
   2379           GNUNET_free (requires);
   2380           GNUNET_free (outputs);
   2381           GNUNET_free (kc);
   2382           return GNUNET_SYSERR;
   2383         }
   2384         if (! ascii_lower (provider_id))
   2385         {
   2386           GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2387                                      section,
   2388                                      "PROVIDER_ID",
   2389                                      "Only [a-zA-Z0-9_0] are allowed");
   2390           goto fail;
   2391         }
   2392         kc->details.link.provider = find_provider (provider_id);
   2393         if (NULL == kc->details.link.provider)
   2394         {
   2395           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2396                       "Unknown KYC provider `%s' used in check `%s'\n",
   2397                       provider_id,
   2398                       &section[strlen ("kyc-check-")]);
   2399           GNUNET_free (provider_id);
   2400           GNUNET_free (requires);
   2401           GNUNET_free (outputs);
   2402           GNUNET_free (kc);
   2403           return GNUNET_SYSERR;
   2404         }
   2405         GNUNET_free (provider_id);
   2406       }
   2407       break;
   2408     }
   2409     kc->check_name = GNUNET_strdup (&section[strlen ("kyc-check-")]);
   2410     kc->description = description;
   2411     kc->description_i18n = description_i18n;
   2412     kc->fallback = fallback;
   2413     kc->type = ct;
   2414     add_tokens (requires,
   2415                 "; \n\t",
   2416                 &kc->requires,
   2417                 &kc->num_requires);
   2418     GNUNET_free (requires);
   2419     add_tokens (outputs,
   2420                 "; \n\t",
   2421                 &kc->outputs,
   2422                 &kc->num_outputs);
   2423     GNUNET_free (outputs);
   2424     GNUNET_array_append (kyc_checks,
   2425                          num_kyc_checks,
   2426                          kc);
   2427   }
   2428 
   2429   return GNUNET_OK;
   2430 fail:
   2431   GNUNET_free (description);
   2432   json_decref (description_i18n);
   2433   GNUNET_free (requires);
   2434   GNUNET_free (outputs);
   2435   GNUNET_free (fallback);
   2436   return GNUNET_SYSERR;
   2437 }
   2438 
   2439 
   2440 /**
   2441  * Function to iterate over configuration sections.
   2442  *
   2443  * @param cls a `struct SectionContext *`
   2444  * @param section name of the section
   2445  */
   2446 static void
   2447 handle_check_section (void *cls,
   2448                       const char *section)
   2449 {
   2450   struct SectionContext *sc = cls;
   2451   char *s;
   2452 
   2453   if (! sc->result)
   2454     return;
   2455   s = normalize_section_with_prefix ("kyc-check-",
   2456                                      section);
   2457   if (NULL == s)
   2458     return;
   2459   if (GNUNET_OK !=
   2460       add_check (sc->cfg,
   2461                  s))
   2462     sc->result = false;
   2463   GNUNET_free (s);
   2464 }
   2465 
   2466 
   2467 /**
   2468  * Parse configuration @a cfg in section @a section for
   2469  * the specification of a KYC rule.
   2470  *
   2471  * @param cfg configuration to parse
   2472  * @param section configuration section to parse
   2473  * @return #GNUNET_OK on success
   2474  */
   2475 static enum GNUNET_GenericReturnValue
   2476 add_rule (const struct GNUNET_CONFIGURATION_Handle *cfg,
   2477           const char *section)
   2478 {
   2479   struct TALER_Amount threshold;
   2480   struct GNUNET_TIME_Relative timeframe;
   2481   enum TALER_KYCLOGIC_KycTriggerEvent ot;
   2482   char *measures;
   2483   bool exposed;
   2484   bool is_and;
   2485 
   2486   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2487               "Parsing KYC rule from %s\n",
   2488               section);
   2489   if (GNUNET_YES !=
   2490       GNUNET_CONFIGURATION_get_value_yesno (cfg,
   2491                                             section,
   2492                                             "ENABLED"))
   2493     return GNUNET_OK;
   2494   if (GNUNET_OK !=
   2495       TALER_config_get_amount (cfg,
   2496                                section,
   2497                                "THRESHOLD",
   2498                                &threshold))
   2499   {
   2500     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2501                                section,
   2502                                "THRESHOLD",
   2503                                "amount required");
   2504     return GNUNET_SYSERR;
   2505   }
   2506   exposed = (GNUNET_YES ==
   2507              GNUNET_CONFIGURATION_get_value_yesno (cfg,
   2508                                                    section,
   2509                                                    "EXPOSED"));
   2510   {
   2511     enum GNUNET_GenericReturnValue r;
   2512 
   2513     r = GNUNET_CONFIGURATION_get_value_yesno (cfg,
   2514                                               section,
   2515                                               "IS_AND_COMBINATOR");
   2516     if (GNUNET_SYSERR == r)
   2517     {
   2518       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2519                                  section,
   2520                                  "IS_AND_COMBINATOR",
   2521                                  "YES or NO required");
   2522       return GNUNET_SYSERR;
   2523     }
   2524     is_and = (GNUNET_YES == r);
   2525   }
   2526 
   2527   {
   2528     char *ot_s;
   2529 
   2530     if (GNUNET_OK !=
   2531         GNUNET_CONFIGURATION_get_value_string (cfg,
   2532                                                section,
   2533                                                "OPERATION_TYPE",
   2534                                                &ot_s))
   2535     {
   2536       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2537                                  section,
   2538                                  "OPERATION_TYPE");
   2539       return GNUNET_SYSERR;
   2540     }
   2541     if (GNUNET_OK !=
   2542         TALER_KYCLOGIC_kyc_trigger_from_string (ot_s,
   2543                                                 &ot))
   2544     {
   2545       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2546                                  section,
   2547                                  "OPERATION_TYPE",
   2548                                  "valid trigger type required");
   2549       GNUNET_free (ot_s);
   2550       return GNUNET_SYSERR;
   2551     }
   2552     GNUNET_free (ot_s);
   2553   }
   2554 
   2555   if (GNUNET_OK !=
   2556       GNUNET_CONFIGURATION_get_value_time (cfg,
   2557                                            section,
   2558                                            "TIMEFRAME",
   2559                                            &timeframe))
   2560   {
   2561     if (TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE == ot)
   2562     {
   2563       timeframe = GNUNET_TIME_UNIT_ZERO;
   2564     }
   2565     else
   2566     {
   2567       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2568                                  section,
   2569                                  "TIMEFRAME",
   2570                                  "duration required");
   2571       return GNUNET_SYSERR;
   2572     }
   2573   }
   2574   if (GNUNET_OK !=
   2575       GNUNET_CONFIGURATION_get_value_string (cfg,
   2576                                              section,
   2577                                              "NEXT_MEASURES",
   2578                                              &measures))
   2579   {
   2580     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2581                                section,
   2582                                "NEXT_MEASURES");
   2583     return GNUNET_SYSERR;
   2584   }
   2585   if (! token_list_lower (measures))
   2586   {
   2587     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2588                                section,
   2589                                "NEXT_MEASURES",
   2590                                "Only [a-zA-Z0-9 _-] are allowed");
   2591     GNUNET_free (measures);
   2592     return GNUNET_SYSERR;
   2593   }
   2594 
   2595   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2596               "Adding KYC rule %s for trigger %d with threshold %s\n",
   2597               section,
   2598               (int) ot,
   2599               TALER_amount2s (&threshold));
   2600   {
   2601     struct TALER_KYCLOGIC_KycRule kt = {
   2602       .lrs = &default_rules,
   2603       .rule_name = GNUNET_strdup (&section[strlen ("kyc-rule-")]),
   2604       .timeframe = timeframe,
   2605       .threshold = threshold,
   2606       .trigger = ot,
   2607       .is_and_combinator = is_and,
   2608       .exposed = exposed,
   2609       .display_priority = 0,
   2610       .verboten = false
   2611     };
   2612 
   2613     add_tokens (measures,
   2614                 "; \n\t",
   2615                 &kt.next_measures,
   2616                 &kt.num_measures);
   2617     for (unsigned int i=0; i<kt.num_measures; i++)
   2618       if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE,
   2619                            kt.next_measures[i]))
   2620         kt.verboten = true;
   2621     GNUNET_free (measures);
   2622     GNUNET_array_append (default_rules.kyc_rules,
   2623                          default_rules.num_kyc_rules,
   2624                          kt);
   2625   }
   2626   return GNUNET_OK;
   2627 }
   2628 
   2629 
   2630 /**
   2631  * Function to iterate over configuration sections.
   2632  *
   2633  * @param cls a `struct SectionContext *`
   2634  * @param section name of the section
   2635  */
   2636 static void
   2637 handle_rule_section (void *cls,
   2638                      const char *section)
   2639 {
   2640   struct SectionContext *sc = cls;
   2641   char *s;
   2642 
   2643   if (! sc->result)
   2644     return;
   2645   s = normalize_section_with_prefix ("kyc-rule-",
   2646                                      section);
   2647   if (NULL == s)
   2648     return;
   2649   if (GNUNET_OK !=
   2650       add_rule (sc->cfg,
   2651                 s))
   2652     sc->result = false;
   2653   GNUNET_free (s);
   2654 }
   2655 
   2656 
   2657 /**
   2658  * Parse array dimension argument of @a tok (if present)
   2659  * and store result in @a dimp. Does nothing if
   2660  * @a tok does not contain '['. Otherwise does some input
   2661  * validation.
   2662  *
   2663  * @param section name of configuration section for logging
   2664  * @param tok input to parse, of form "text[$DIM]"
   2665  * @param[out] dimp set to value of $DIM
   2666  * @return true on success
   2667  */
   2668 static bool
   2669 parse_dim (const char *section,
   2670            const char *tok,
   2671            long long *dimp)
   2672 {
   2673   const char *dim = strchr (tok,
   2674                             '[');
   2675   char dummy;
   2676 
   2677   if (NULL == dim)
   2678     return true;
   2679   if (1 !=
   2680       sscanf (dim,
   2681               "[%lld]%c",
   2682               dimp,
   2683               &dummy))
   2684   {
   2685     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2686                                section,
   2687                                "COMMAND",
   2688                                "output for -i invalid (bad dimension given)");
   2689     return false;
   2690   }
   2691   return true;
   2692 }
   2693 
   2694 
   2695 /**
   2696  * Parse configuration @a cfg in section @a section for
   2697  * the specification of an AML program.
   2698  *
   2699  * @param cfg configuration to parse
   2700  * @param section configuration section to parse
   2701  * @return #GNUNET_OK on success
   2702  */
   2703 static enum GNUNET_GenericReturnValue
   2704 add_program (const struct GNUNET_CONFIGURATION_Handle *cfg,
   2705              const char *section)
   2706 {
   2707   char *command = NULL;
   2708   char *description = NULL;
   2709   char *fallback = NULL;
   2710   char *required_contexts = NULL;
   2711   char *required_attributes = NULL;
   2712   char *required_inputs = NULL;
   2713   enum AmlProgramInputs input_mask = API_NONE;
   2714   long long aml_history_length_limit = INT64_MAX;
   2715   long long kyc_history_length_limit = INT64_MAX;
   2716 
   2717   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2718               "Parsing KYC program %s\n",
   2719               section);
   2720   if (GNUNET_OK !=
   2721       GNUNET_CONFIGURATION_get_value_string (cfg,
   2722                                              section,
   2723                                              "COMMAND",
   2724                                              &command))
   2725   {
   2726     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2727                                section,
   2728                                "COMMAND",
   2729                                "command required");
   2730     goto fail;
   2731   }
   2732   if (GNUNET_OK !=
   2733       GNUNET_CONFIGURATION_get_value_string (cfg,
   2734                                              section,
   2735                                              "DESCRIPTION",
   2736                                              &description))
   2737   {
   2738     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2739                                section,
   2740                                "DESCRIPTION",
   2741                                "description required");
   2742     goto fail;
   2743   }
   2744   if (GNUNET_OK !=
   2745       GNUNET_CONFIGURATION_get_value_string (cfg,
   2746                                              section,
   2747                                              "FALLBACK",
   2748                                              &fallback))
   2749   {
   2750     /* We do *not* allow NULL to fall back to default rules because fallbacks
   2751        are used when there is actually a serious error and thus some action
   2752        (usually an investigation) is always in order, and that's basically
   2753        never the default. And as fallbacks should be rare, we really insist on
   2754        them at least being explicitly configured. Otherwise these errors may
   2755        go undetected simply because someone forgot to configure a fallback and
   2756        then nothing happens. */
   2757     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2758                                section,
   2759                                "FALLBACK",
   2760                                "fallback measure name required");
   2761     goto fail;
   2762   }
   2763 
   2764   required_contexts = command_output (command,
   2765                                       "-r");
   2766   if (NULL == required_contexts)
   2767   {
   2768     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2769                                section,
   2770                                "COMMAND",
   2771                                "output for -r invalid");
   2772     goto fail;
   2773   }
   2774 
   2775   required_attributes = command_output (command,
   2776                                         "-a");
   2777   if (NULL == required_attributes)
   2778   {
   2779     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2780                                section,
   2781                                "COMMAND",
   2782                                "output for -a invalid");
   2783     goto fail;
   2784   }
   2785 
   2786   required_inputs = command_output (command,
   2787                                     "-i");
   2788   if (NULL == required_inputs)
   2789   {
   2790     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2791                                section,
   2792                                "COMMAND",
   2793                                "output for -i invalid");
   2794     goto fail;
   2795   }
   2796 
   2797   {
   2798     char *sptr;
   2799 
   2800     for (char *tok = strtok_r (required_inputs,
   2801                                ";\n \t",
   2802                                &sptr);
   2803          NULL != tok;
   2804          tok = strtok_r (NULL,
   2805                          ";\n \t",
   2806                          &sptr) )
   2807     {
   2808       if (0 == strcasecmp (tok,
   2809                            "context"))
   2810         input_mask |= API_CONTEXT;
   2811       else if (0 == strcasecmp (tok,
   2812                                 "attributes"))
   2813         input_mask |= API_ATTRIBUTES;
   2814       else if (0 == strcasecmp (tok,
   2815                                 "current_rules"))
   2816         input_mask |= API_CURRENT_RULES;
   2817       else if (0 == strcasecmp (tok,
   2818                                 "default_rules"))
   2819         input_mask |= API_DEFAULT_RULES;
   2820       else if (0 == strncasecmp (tok,
   2821                                  "aml_history",
   2822                                  strlen ("aml_history")))
   2823       {
   2824         input_mask |= API_AML_HISTORY;
   2825         if (! parse_dim (section,
   2826                          tok,
   2827                          &aml_history_length_limit))
   2828           goto fail;
   2829       }
   2830       else if (0 == strncasecmp (tok,
   2831                                  "kyc_history",
   2832                                  strlen ("kyc_history")))
   2833       {
   2834         input_mask |= API_KYC_HISTORY;
   2835         if (! parse_dim (section,
   2836                          tok,
   2837                          &kyc_history_length_limit))
   2838           goto fail;
   2839       }
   2840       else
   2841       {
   2842         GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2843                                    section,
   2844                                    "COMMAND",
   2845                                    "output for -i invalid (unsupported input)");
   2846         goto fail;
   2847       }
   2848     }
   2849   }
   2850   GNUNET_free (required_inputs);
   2851 
   2852   {
   2853     struct TALER_KYCLOGIC_AmlProgram *ap;
   2854 
   2855     ap = GNUNET_new (struct TALER_KYCLOGIC_AmlProgram);
   2856     ap->program_name = GNUNET_strdup (&section[strlen ("aml-program-")]);
   2857     ap->command = command;
   2858     ap->description = description;
   2859     ap->fallback = fallback;
   2860     ap->input_mask = input_mask;
   2861     ap->aml_history_length_limit = aml_history_length_limit;
   2862     ap->kyc_history_length_limit = kyc_history_length_limit;
   2863     add_tokens (required_contexts,
   2864                 "; \n\t",
   2865                 &ap->required_contexts,
   2866                 &ap->num_required_contexts);
   2867     GNUNET_free (required_contexts);
   2868     add_tokens (required_attributes,
   2869                 "; \n\t",
   2870                 &ap->required_attributes,
   2871                 &ap->num_required_attributes);
   2872     GNUNET_free (required_attributes);
   2873     GNUNET_array_append (aml_programs,
   2874                          num_aml_programs,
   2875                          ap);
   2876   }
   2877   return GNUNET_OK;
   2878 fail:
   2879   GNUNET_free (command);
   2880   GNUNET_free (description);
   2881   GNUNET_free (required_inputs);
   2882   GNUNET_free (required_contexts);
   2883   GNUNET_free (required_attributes);
   2884   GNUNET_free (fallback);
   2885   return GNUNET_SYSERR;
   2886 }
   2887 
   2888 
   2889 /**
   2890  * Function to iterate over configuration sections.
   2891  *
   2892  * @param cls a `struct SectionContext *`
   2893  * @param section name of the section
   2894  */
   2895 static void
   2896 handle_program_section (void *cls,
   2897                         const char *section)
   2898 {
   2899   struct SectionContext *sc = cls;
   2900   char *s;
   2901 
   2902   if (! sc->result)
   2903     return;
   2904   s = normalize_section_with_prefix ("aml-program-",
   2905                                      section);
   2906   if (NULL == s)
   2907     return;
   2908   if (GNUNET_OK !=
   2909       add_program (sc->cfg,
   2910                    s))
   2911     sc->result = false;
   2912   GNUNET_free (s);
   2913 }
   2914 
   2915 
   2916 /**
   2917  * Parse configuration @a cfg in section @a section for
   2918  * the specification of a KYC measure.
   2919  *
   2920  * @param cfg configuration to parse
   2921  * @param section configuration section to parse
   2922  * @return #GNUNET_OK on success
   2923  */
   2924 static enum GNUNET_GenericReturnValue
   2925 add_measure (const struct GNUNET_CONFIGURATION_Handle *cfg,
   2926              const char *section)
   2927 {
   2928   bool voluntary;
   2929   char *check_name = NULL;
   2930   struct TALER_KYCLOGIC_KycCheck *kc = NULL;
   2931   char *context_str = NULL;
   2932   char *program = NULL;
   2933   json_t *context;
   2934   json_error_t err;
   2935 
   2936   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2937               "Parsing KYC measure %s\n",
   2938               section);
   2939   if (GNUNET_OK !=
   2940       GNUNET_CONFIGURATION_get_value_string (cfg,
   2941                                              section,
   2942                                              "CHECK_NAME",
   2943                                              &check_name))
   2944   {
   2945     check_name = GNUNET_strdup ("skip");
   2946   }
   2947   if (0 != strcasecmp (check_name,
   2948                        "skip"))
   2949   {
   2950     kc = find_check (check_name);
   2951     if (NULL == kc)
   2952     {
   2953       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2954                                  section,
   2955                                  "CHECK_NAME",
   2956                                  "check unknown");
   2957       goto fail;
   2958     }
   2959   }
   2960   if (GNUNET_OK !=
   2961       GNUNET_CONFIGURATION_get_value_string (cfg,
   2962                                              section,
   2963                                              "PROGRAM",
   2964                                              &program))
   2965   {
   2966     if ( (NULL == kc) ||
   2967          (TALER_KYCLOGIC_CT_INFO != kc->type) )
   2968     {
   2969       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2970                                  section,
   2971                                  "PROGRAM");
   2972       goto fail;
   2973     }
   2974   }
   2975   else
   2976   {
   2977     /* AML program given, but do we want one? */
   2978     if ( (NULL != kc) &&
   2979          (TALER_KYCLOGIC_CT_INFO == kc->type) )
   2980     {
   2981       GNUNET_log_config_invalid (
   2982         GNUNET_ERROR_TYPE_WARNING,
   2983         section,
   2984         "PROGRAM",
   2985         "AML program specified for a check of type INFO (ignored)");
   2986       GNUNET_free (program);
   2987     }
   2988   }
   2989   voluntary = (GNUNET_YES ==
   2990                GNUNET_CONFIGURATION_get_value_yesno (cfg,
   2991                                                      section,
   2992                                                      "VOLUNTARY"));
   2993   if (GNUNET_OK !=
   2994       GNUNET_CONFIGURATION_get_value_string (cfg,
   2995                                              section,
   2996                                              "CONTEXT",
   2997                                              &context_str))
   2998   {
   2999     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   3000                                section,
   3001                                "CONTEXT");
   3002     goto fail;
   3003   }
   3004   context = json_loads (context_str,
   3005                         JSON_REJECT_DUPLICATES,
   3006                         &err);
   3007   GNUNET_free (context_str);
   3008   if (NULL == context)
   3009   {
   3010     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   3011                                section,
   3012                                "CONTEXT",
   3013                                err.text);
   3014     goto fail;
   3015   }
   3016 
   3017   {
   3018     struct TALER_KYCLOGIC_Measure m;
   3019 
   3020     m.measure_name = GNUNET_strdup (&section[strlen ("kyc-measure-")]);
   3021     m.check_name = check_name;
   3022     m.prog_name = program;
   3023     m.context = context;
   3024     m.voluntary = voluntary;
   3025     GNUNET_array_append (default_rules.custom_measures,
   3026                          default_rules.num_custom_measures,
   3027                          m);
   3028   }
   3029   return GNUNET_OK;
   3030 fail:
   3031   GNUNET_free (check_name);
   3032   GNUNET_free (program);
   3033   GNUNET_free (context_str);
   3034   return GNUNET_SYSERR;
   3035 }
   3036 
   3037 
   3038 /**
   3039  * Function to iterate over configuration sections.
   3040  *
   3041  * @param cls a `struct SectionContext *`
   3042  * @param section name of the section
   3043  */
   3044 static void
   3045 handle_measure_section (void *cls,
   3046                         const char *section)
   3047 {
   3048   struct SectionContext *sc = cls;
   3049   char *s;
   3050 
   3051   if (! sc->result)
   3052     return;
   3053   s = normalize_section_with_prefix ("kyc-measure-",
   3054                                      section);
   3055   if (NULL == s)
   3056     return;
   3057   if (GNUNET_OK !=
   3058       add_measure (sc->cfg,
   3059                    s))
   3060     sc->result = false;
   3061   GNUNET_free (s);
   3062 }
   3063 
   3064 
   3065 /**
   3066  * Comparator for qsort. Compares two rules
   3067  * by timeframe to sort rules by time.
   3068  *
   3069  * @param p1 first trigger to compare
   3070  * @param p2 second trigger to compare
   3071  * @return -1 if p1 < p2, 0 if p1==p2, 1 if p1 > p2.
   3072  */
   3073 static int
   3074 sort_by_timeframe (const void *p1,
   3075                    const void *p2)
   3076 {
   3077   struct TALER_KYCLOGIC_KycRule *r1
   3078     = (struct TALER_KYCLOGIC_KycRule *) p1;
   3079   struct TALER_KYCLOGIC_KycRule *r2
   3080     = (struct TALER_KYCLOGIC_KycRule *) p2;
   3081 
   3082   if (GNUNET_TIME_relative_cmp (r1->timeframe,
   3083                                 <,
   3084                                 r2->timeframe))
   3085     return -1;
   3086   if (GNUNET_TIME_relative_cmp (r1->timeframe,
   3087                                 >,
   3088                                 r2->timeframe))
   3089     return 1;
   3090   return 0;
   3091 }
   3092 
   3093 
   3094 enum GNUNET_GenericReturnValue
   3095 TALER_KYCLOGIC_kyc_init (
   3096   const struct GNUNET_CONFIGURATION_Handle *cfg,
   3097   const char *cfg_fn)
   3098 {
   3099   struct SectionContext sc = {
   3100     .cfg = cfg,
   3101     .result = true
   3102   };
   3103   json_t *jkyc_rules_w;
   3104   json_t *jkyc_rules_a;
   3105 
   3106   if (NULL != cfg_fn)
   3107     cfg_filename = GNUNET_strdup (cfg_fn);
   3108   GNUNET_assert (GNUNET_OK ==
   3109                  TALER_config_get_currency (cfg,
   3110                                             "exchange",
   3111                                             &my_currency));
   3112   GNUNET_CONFIGURATION_iterate_sections (cfg,
   3113                                          &handle_provider_section,
   3114                                          &sc);
   3115   if (! sc.result)
   3116   {
   3117     TALER_KYCLOGIC_kyc_done ();
   3118     return GNUNET_SYSERR;
   3119   }
   3120   GNUNET_CONFIGURATION_iterate_sections (cfg,
   3121                                          &handle_check_section,
   3122                                          &sc);
   3123   if (! sc.result)
   3124   {
   3125     TALER_KYCLOGIC_kyc_done ();
   3126     return GNUNET_SYSERR;
   3127   }
   3128   GNUNET_CONFIGURATION_iterate_sections (cfg,
   3129                                          &handle_rule_section,
   3130                                          &sc);
   3131   if (! sc.result)
   3132   {
   3133     TALER_KYCLOGIC_kyc_done ();
   3134     return GNUNET_SYSERR;
   3135   }
   3136   GNUNET_CONFIGURATION_iterate_sections (cfg,
   3137                                          &handle_program_section,
   3138                                          &sc);
   3139   if (! sc.result)
   3140   {
   3141     TALER_KYCLOGIC_kyc_done ();
   3142     return GNUNET_SYSERR;
   3143   }
   3144   GNUNET_CONFIGURATION_iterate_sections (cfg,
   3145                                          &handle_measure_section,
   3146                                          &sc);
   3147   if (! sc.result)
   3148   {
   3149     TALER_KYCLOGIC_kyc_done ();
   3150     return GNUNET_SYSERR;
   3151   }
   3152 
   3153   if (0 != default_rules.num_kyc_rules)
   3154     qsort (default_rules.kyc_rules,
   3155            default_rules.num_kyc_rules,
   3156            sizeof (struct TALER_KYCLOGIC_KycRule),
   3157            &sort_by_timeframe);
   3158   jkyc_rules_w = json_array ();
   3159   GNUNET_assert (NULL != jkyc_rules_w);
   3160   jkyc_rules_a = json_array ();
   3161   GNUNET_assert (NULL != jkyc_rules_a);
   3162 
   3163   for (unsigned int i=0; i<default_rules.num_kyc_rules; i++)
   3164   {
   3165     const struct TALER_KYCLOGIC_KycRule *rule
   3166       = &default_rules.kyc_rules[i];
   3167     json_t *jrule;
   3168     json_t *jmeasures;
   3169 
   3170     jmeasures = json_array ();
   3171     GNUNET_assert (NULL != jmeasures);
   3172     for (unsigned int j=0; j<rule->num_measures; j++)
   3173     {
   3174       const char *measure_name = rule->next_measures[j];
   3175       const struct TALER_KYCLOGIC_Measure *m;
   3176 
   3177       if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE,
   3178                            measure_name))
   3179       {
   3180         GNUNET_assert (
   3181           0 ==
   3182           json_array_append_new (jmeasures,
   3183                                  json_string (KYC_MEASURE_IMPOSSIBLE)));
   3184         continue;
   3185       }
   3186       m = find_measure (&default_rules,
   3187                         measure_name);
   3188       if (NULL == m)
   3189       {
   3190         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3191                     "Unknown measure `%s' used in rule `%s'\n",
   3192                     measure_name,
   3193                     rule->rule_name);
   3194         return GNUNET_SYSERR;
   3195       }
   3196       GNUNET_assert (0 ==
   3197                      json_array_append_new (jmeasures,
   3198                                             json_string (measure_name)));
   3199     }
   3200     jrule = GNUNET_JSON_PACK (
   3201       GNUNET_JSON_pack_allow_null (
   3202         GNUNET_JSON_pack_string ("rule_name",
   3203                                  rule->rule_name)),
   3204       TALER_JSON_pack_kycte ("operation_type",
   3205                              rule->trigger),
   3206       TALER_JSON_pack_amount ("threshold",
   3207                               &rule->threshold),
   3208       GNUNET_JSON_pack_time_rel ("timeframe",
   3209                                  rule->timeframe),
   3210       GNUNET_JSON_pack_array_steal ("measures",
   3211                                     jmeasures),
   3212       GNUNET_JSON_pack_uint64 ("display_priority",
   3213                                rule->display_priority),
   3214       GNUNET_JSON_pack_bool ("exposed",
   3215                              rule->exposed),
   3216       GNUNET_JSON_pack_bool ("is_and_combinator",
   3217                              rule->is_and_combinator)
   3218       );
   3219     switch (rule->trigger)
   3220     {
   3221     case TALER_KYCLOGIC_KYC_TRIGGER_NONE:
   3222       GNUNET_break (0);
   3223       break;
   3224     case TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW:
   3225       GNUNET_assert (0 ==
   3226                      json_array_append (jkyc_rules_a,
   3227                                         jrule));
   3228       break;
   3229     case TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT:
   3230       GNUNET_assert (0 ==
   3231                      json_array_append (jkyc_rules_a,
   3232                                         jrule));
   3233       break;
   3234     case TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE:
   3235       GNUNET_assert (0 ==
   3236                      json_array_append (jkyc_rules_w,
   3237                                         jrule));
   3238       break;
   3239     case TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE:
   3240       GNUNET_assert (0 ==
   3241                      json_array_append (jkyc_rules_w,
   3242                                         jrule));
   3243       break;
   3244     case TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE:
   3245       GNUNET_assert (0 ==
   3246                      json_array_append (jkyc_rules_a,
   3247                                         jrule));
   3248       break;
   3249     case TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE:
   3250       GNUNET_assert (0 ==
   3251                      json_array_append (jkyc_rules_a,
   3252                                         jrule));
   3253       break;
   3254     case TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION:
   3255       GNUNET_assert (0 ==
   3256                      json_array_append (jkyc_rules_a,
   3257                                         jrule));
   3258       GNUNET_assert (0 ==
   3259                      json_array_append (jkyc_rules_w,
   3260                                         jrule));
   3261       break;
   3262     case TALER_KYCLOGIC_KYC_TRIGGER_REFUND:
   3263       GNUNET_assert (0 ==
   3264                      json_array_append (jkyc_rules_a,
   3265                                         jrule));
   3266       GNUNET_assert (0 ==
   3267                      json_array_append (jkyc_rules_w,
   3268                                         jrule));
   3269       break;
   3270     }
   3271     json_decref (jrule);
   3272   }
   3273   {
   3274     json_t *empty = json_object ();
   3275 
   3276     GNUNET_assert (NULL != empty);
   3277     wallet_default_lrs
   3278       = GNUNET_JSON_PACK (
   3279           GNUNET_JSON_pack_timestamp ("expiration_time",
   3280                                       GNUNET_TIME_UNIT_FOREVER_TS),
   3281           GNUNET_JSON_pack_array_steal ("rules",
   3282                                         jkyc_rules_w),
   3283           GNUNET_JSON_pack_object_incref ("custom_measures",
   3284                                           empty)
   3285           );
   3286     bankaccount_default_lrs
   3287       = GNUNET_JSON_PACK (
   3288           GNUNET_JSON_pack_timestamp ("expiration_time",
   3289                                       GNUNET_TIME_UNIT_FOREVER_TS),
   3290           GNUNET_JSON_pack_array_steal ("rules",
   3291                                         jkyc_rules_a),
   3292           GNUNET_JSON_pack_object_incref ("custom_measures",
   3293                                           empty)
   3294           );
   3295     json_decref (empty);
   3296   }
   3297   for (unsigned int i=0; i<default_rules.num_custom_measures; i++)
   3298   {
   3299     const struct TALER_KYCLOGIC_Measure *measure
   3300       = &default_rules.custom_measures[i];
   3301 
   3302     if (! check_measure (measure))
   3303     {
   3304       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3305                   "Configuration of AML measures incorrect. Exiting.\n");
   3306       return GNUNET_SYSERR;
   3307     }
   3308   }
   3309 
   3310   for (unsigned int i=0; i<num_aml_programs; i++)
   3311   {
   3312     const struct TALER_KYCLOGIC_AmlProgram *program
   3313       = aml_programs[i];
   3314     const struct TALER_KYCLOGIC_Measure *m;
   3315 
   3316     m = find_measure (&default_rules,
   3317                       program->fallback);
   3318     if (NULL == m)
   3319     {
   3320       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3321                   "Unknown fallback measure `%s' used in program `%s'\n",
   3322                   program->fallback,
   3323                   program->program_name);
   3324       return GNUNET_SYSERR;
   3325     }
   3326     if (0 != strcasecmp (m->check_name,
   3327                          "skip"))
   3328     {
   3329       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3330                   "Fallback measure `%s' used in AML program `%s' has a check `%s' but fallbacks must have a check of type 'skip'\n",
   3331                   program->fallback,
   3332                   program->program_name,
   3333                   m->check_name);
   3334       return GNUNET_SYSERR;
   3335     }
   3336     if (NULL != m->prog_name)
   3337     {
   3338       const struct TALER_KYCLOGIC_AmlProgram *fprogram;
   3339 
   3340       fprogram = find_program (m->prog_name);
   3341       GNUNET_assert (NULL != fprogram);
   3342       if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES)))
   3343       {
   3344         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3345                     "Fallback program %s of fallback measure `%s' used in AML program `%s' has required inputs, but fallback measures must not require any inputs\n",
   3346                     m->prog_name,
   3347                     program->program_name,
   3348                     m->check_name);
   3349         return GNUNET_SYSERR;
   3350       }
   3351     }
   3352   }
   3353 
   3354   for (unsigned int i = 0; i<num_kyc_checks; i++)
   3355   {
   3356     struct TALER_KYCLOGIC_KycCheck *kyc_check
   3357       = kyc_checks[i];
   3358     const struct TALER_KYCLOGIC_Measure *measure;
   3359 
   3360     measure = find_measure (&default_rules,
   3361                             kyc_check->fallback);
   3362     if (NULL == measure)
   3363     {
   3364       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3365                   "Unknown fallback measure `%s' used in check `%s'\n",
   3366                   kyc_check->fallback,
   3367                   kyc_check->check_name);
   3368       return GNUNET_SYSERR;
   3369     }
   3370     if (0 != strcasecmp (measure->check_name,
   3371                          "skip"))
   3372     {
   3373       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3374                   "Fallback measure `%s' used in KYC check `%s' has a check `%s' but fallbacks must have a check of type 'skip'\n",
   3375                   kyc_check->fallback,
   3376                   kyc_check->check_name,
   3377                   measure->check_name);
   3378       return GNUNET_SYSERR;
   3379     }
   3380     if (NULL != measure->prog_name)
   3381     {
   3382       const struct TALER_KYCLOGIC_AmlProgram *fprogram;
   3383 
   3384       fprogram = find_program (measure->prog_name);
   3385       GNUNET_assert (NULL != fprogram);
   3386       if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES)))
   3387       {
   3388         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3389                     "AML program `%s' used fallback measure `%s' of KYC check `%s' has required inputs, but fallback measures must not require any inputs\n",
   3390                     measure->prog_name,
   3391                     kyc_check->fallback,
   3392                     kyc_check->check_name);
   3393         return GNUNET_SYSERR;
   3394       }
   3395     }
   3396   }
   3397 
   3398   return GNUNET_OK;
   3399 }
   3400 
   3401 
   3402 void
   3403 TALER_KYCLOGIC_kyc_done (void)
   3404 {
   3405   for (unsigned int i = 0; i<default_rules.num_kyc_rules; i++)
   3406   {
   3407     struct TALER_KYCLOGIC_KycRule *kt
   3408       = &default_rules.kyc_rules[i];
   3409 
   3410     for (unsigned int j = 0; j<kt->num_measures; j++)
   3411       GNUNET_free (kt->next_measures[j]);
   3412     GNUNET_array_grow (kt->next_measures,
   3413                        kt->num_measures,
   3414                        0);
   3415     GNUNET_free (kt->rule_name);
   3416   }
   3417   GNUNET_array_grow (default_rules.kyc_rules,
   3418                      default_rules.num_kyc_rules,
   3419                      0);
   3420   for (unsigned int i = 0; i<num_kyc_providers; i++)
   3421   {
   3422     struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
   3423 
   3424     kp->logic->unload_configuration (kp->pd);
   3425     GNUNET_free (kp->provider_name);
   3426     GNUNET_free (kp);
   3427   }
   3428   GNUNET_array_grow (kyc_providers,
   3429                      num_kyc_providers,
   3430                      0);
   3431   for (unsigned int i = 0; i<num_kyc_logics; i++)
   3432   {
   3433     struct TALER_KYCLOGIC_Plugin *lp = kyc_logics[i];
   3434     char *lib_name = lp->library_name;
   3435 
   3436     GNUNET_free (lp->name);
   3437     GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name,
   3438                                                  lp));
   3439     GNUNET_free (lib_name);
   3440   }
   3441   GNUNET_array_grow (kyc_logics,
   3442                      num_kyc_logics,
   3443                      0);
   3444   for (unsigned int i = 0; i<num_kyc_checks; i++)
   3445   {
   3446     struct TALER_KYCLOGIC_KycCheck *kc = kyc_checks[i];
   3447 
   3448     GNUNET_free (kc->check_name);
   3449     GNUNET_free (kc->description);
   3450     json_decref (kc->description_i18n);
   3451     for (unsigned int j = 0; j<kc->num_requires; j++)
   3452       GNUNET_free (kc->requires[j]);
   3453     GNUNET_array_grow (kc->requires,
   3454                        kc->num_requires,
   3455                        0);
   3456     GNUNET_free (kc->fallback);
   3457     for (unsigned int j = 0; j<kc->num_outputs; j++)
   3458       GNUNET_free (kc->outputs[j]);
   3459     GNUNET_array_grow (kc->outputs,
   3460                        kc->num_outputs,
   3461                        0);
   3462     switch (kc->type)
   3463     {
   3464     case TALER_KYCLOGIC_CT_INFO:
   3465       break;
   3466     case TALER_KYCLOGIC_CT_FORM:
   3467       GNUNET_free (kc->details.form.name);
   3468       break;
   3469     case TALER_KYCLOGIC_CT_LINK:
   3470       break;
   3471     }
   3472     GNUNET_free (kc);
   3473   }
   3474   GNUNET_array_grow (kyc_checks,
   3475                      num_kyc_checks,
   3476                      0);
   3477   for (unsigned int i = 0; i<num_aml_programs; i++)
   3478   {
   3479     struct TALER_KYCLOGIC_AmlProgram *ap = aml_programs[i];
   3480 
   3481     GNUNET_free (ap->program_name);
   3482     GNUNET_free (ap->command);
   3483     GNUNET_free (ap->description);
   3484     GNUNET_free (ap->fallback);
   3485     for (unsigned int j = 0; j<ap->num_required_contexts; j++)
   3486       GNUNET_free (ap->required_contexts[j]);
   3487     GNUNET_array_grow (ap->required_contexts,
   3488                        ap->num_required_contexts,
   3489                        0);
   3490     for (unsigned int j = 0; j<ap->num_required_attributes; j++)
   3491       GNUNET_free (ap->required_attributes[j]);
   3492     GNUNET_array_grow (ap->required_attributes,
   3493                        ap->num_required_attributes,
   3494                        0);
   3495     GNUNET_free (ap);
   3496   }
   3497   GNUNET_array_grow (aml_programs,
   3498                      num_aml_programs,
   3499                      0);
   3500   GNUNET_free (cfg_filename);
   3501 }
   3502 
   3503 
   3504 void
   3505 TALER_KYCLOGIC_provider_to_logic (
   3506   const struct TALER_KYCLOGIC_KycProvider *provider,
   3507   struct TALER_KYCLOGIC_Plugin **plugin,
   3508   struct TALER_KYCLOGIC_ProviderDetails **pd,
   3509   const char **provider_name)
   3510 {
   3511   *plugin = provider->logic;
   3512   *pd = provider->pd;
   3513   *provider_name = provider->provider_name;
   3514 }
   3515 
   3516 
   3517 enum GNUNET_GenericReturnValue
   3518 TALER_KYCLOGIC_get_original_measure (
   3519   const char *measure_name,
   3520   struct TALER_KYCLOGIC_KycCheckContext *kcc)
   3521 {
   3522   const struct TALER_KYCLOGIC_Measure *measure;
   3523 
   3524   measure = find_measure (&default_rules,
   3525                           measure_name);
   3526   if (NULL == measure)
   3527   {
   3528     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3529                 "Default measure `%s' unknown\n",
   3530                 measure_name);
   3531     return GNUNET_SYSERR;
   3532   }
   3533   if (0 == strcasecmp (measure->check_name,
   3534                        "skip"))
   3535   {
   3536     kcc->check = NULL;
   3537     kcc->prog_name = measure->prog_name;
   3538     kcc->context = measure->context;
   3539     return GNUNET_OK;
   3540   }
   3541 
   3542   for (unsigned int i = 0; i<num_kyc_checks; i++)
   3543     if (0 == strcasecmp (measure->check_name,
   3544                          kyc_checks[i]->check_name))
   3545     {
   3546       kcc->check = kyc_checks[i];
   3547       kcc->prog_name = measure->prog_name;
   3548       kcc->context = measure->context;
   3549       return GNUNET_OK;
   3550     }
   3551   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3552               "Check `%s' unknown (but required by measure `%s')\n",
   3553               measure->check_name,
   3554               measure_name);
   3555   return GNUNET_SYSERR;
   3556 }
   3557 
   3558 
   3559 enum GNUNET_GenericReturnValue
   3560 TALER_KYCLOGIC_requirements_to_check (
   3561   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
   3562   const struct TALER_KYCLOGIC_KycRule *kyc_rule,
   3563   const char *measure_name,
   3564   struct TALER_KYCLOGIC_KycCheckContext *kcc)
   3565 {
   3566   bool found = false;
   3567   const struct TALER_KYCLOGIC_Measure *measure = NULL;
   3568 
   3569   if (NULL == lrs)
   3570     lrs = &default_rules;
   3571   if (NULL == measure_name)
   3572   {
   3573     GNUNET_break (0);
   3574     return GNUNET_SYSERR;
   3575   }
   3576   if (NULL != kyc_rule)
   3577   {
   3578     for (unsigned int i = 0; i<kyc_rule->num_measures; i++)
   3579     {
   3580       if (0 != strcasecmp (measure_name,
   3581                            kyc_rule->next_measures[i]))
   3582         continue;
   3583       found = true;
   3584       break;
   3585     }
   3586     if (! found)
   3587     {
   3588       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3589                   "Measure `%s' not allowed for rule `%s'\n",
   3590                   measure_name,
   3591                   kyc_rule->rule_name);
   3592       return GNUNET_SYSERR;
   3593     }
   3594     if (kyc_rule->verboten)
   3595     {
   3596       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3597                   "Rule says operation is categorically is verboten, cannot take measures\n");
   3598       return GNUNET_SYSERR;
   3599     }
   3600   }
   3601   measure = find_measure (lrs,
   3602                           measure_name);
   3603   if (NULL == measure)
   3604   {
   3605     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3606                 "Measure `%s' unknown (but allowed by rule `%s')\n",
   3607                 measure_name,
   3608                 NULL != kyc_rule
   3609                 ? kyc_rule->rule_name
   3610                 : "<NONE>");
   3611     return GNUNET_SYSERR;
   3612   }
   3613 
   3614   if (0 == strcasecmp (measure->check_name,
   3615                        "skip"))
   3616   {
   3617     kcc->check = NULL;
   3618     kcc->prog_name = measure->prog_name;
   3619     kcc->context = measure->context;
   3620     return GNUNET_OK;
   3621   }
   3622 
   3623   for (unsigned int i = 0; i<num_kyc_checks; i++)
   3624     if (0 == strcasecmp (measure->check_name,
   3625                          kyc_checks[i]->check_name))
   3626     {
   3627       kcc->check = kyc_checks[i];
   3628       kcc->prog_name = measure->prog_name;
   3629       kcc->context = measure->context;
   3630       return GNUNET_OK;
   3631     }
   3632   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3633               "Check `%s' unknown (but required by measure `%s')\n",
   3634               measure->check_name,
   3635               measure_name);
   3636   return GNUNET_SYSERR;
   3637 }
   3638 
   3639 
   3640 enum GNUNET_GenericReturnValue
   3641 TALER_KYCLOGIC_lookup_logic (
   3642   const char *name,
   3643   struct TALER_KYCLOGIC_Plugin **plugin,
   3644   struct TALER_KYCLOGIC_ProviderDetails **pd,
   3645   const char **provider_name)
   3646 {
   3647   for (unsigned int i = 0; i<num_kyc_providers; i++)
   3648   {
   3649     struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
   3650 
   3651     if (0 !=
   3652         strcasecmp (name,
   3653                     kp->provider_name))
   3654       continue;
   3655     *plugin = kp->logic;
   3656     *pd = kp->pd;
   3657     *provider_name = kp->provider_name;
   3658     return GNUNET_OK;
   3659   }
   3660   for (unsigned int i = 0; i<num_kyc_logics; i++)
   3661   {
   3662     struct TALER_KYCLOGIC_Plugin *logic = kyc_logics[i];
   3663 
   3664     if (0 !=
   3665         strcasecmp (logic->name,
   3666                     name))
   3667       continue;
   3668     *plugin = logic;
   3669     *pd = NULL;
   3670     *provider_name = NULL;
   3671     return GNUNET_OK;
   3672   }
   3673   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3674               "Provider `%s' unknown\n",
   3675               name);
   3676   return GNUNET_SYSERR;
   3677 }
   3678 
   3679 
   3680 void
   3681 TALER_KYCLOGIC_kyc_get_details (
   3682   const char *logic_name,
   3683   TALER_KYCLOGIC_DetailsCallback cb,
   3684   void *cb_cls)
   3685 {
   3686   for (unsigned int i = 0; i<num_kyc_providers; i++)
   3687   {
   3688     struct TALER_KYCLOGIC_KycProvider *kp
   3689       = kyc_providers[i];
   3690 
   3691     if (0 !=
   3692         strcasecmp (kp->logic->name,
   3693                     logic_name))
   3694       continue;
   3695     if (GNUNET_OK !=
   3696         cb (cb_cls,
   3697             kp->pd,
   3698             kp->logic->cls))
   3699       return;
   3700   }
   3701 }
   3702 
   3703 
   3704 /**
   3705  * Closure for check_amount().
   3706  */
   3707 struct KycTestContext
   3708 {
   3709   /**
   3710    * Rule set we apply.
   3711    */
   3712   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs;
   3713 
   3714   /**
   3715    * Events we care about.
   3716    */
   3717   enum TALER_KYCLOGIC_KycTriggerEvent event;
   3718 
   3719   /**
   3720    * Total amount encountered so far, invalid if zero.
   3721    */
   3722   struct TALER_Amount sum;
   3723 
   3724   /**
   3725    * Set to the triggered rule.
   3726    */
   3727   const struct TALER_KYCLOGIC_KycRule *triggered_rule;
   3728 
   3729 };
   3730 
   3731 
   3732 /**
   3733  * Function called on each @a amount that was found to
   3734  * be relevant for a KYC check.  Evaluates the given
   3735  * @a amount and @a date against all the applicable
   3736  * rules in the legitimization rule set.
   3737  *
   3738  * @param cls our `struct KycTestContext *`
   3739  * @param amount encountered transaction amount
   3740  * @param date when was the amount encountered
   3741  * @return #GNUNET_OK to continue to iterate,
   3742  *         #GNUNET_NO to abort iteration,
   3743  *         #GNUNET_SYSERR on internal error (also abort itaration)
   3744  */
   3745 static enum GNUNET_GenericReturnValue
   3746 check_amount (
   3747   void *cls,
   3748   const struct TALER_Amount *amount,
   3749   struct GNUNET_TIME_Absolute date)
   3750 {
   3751   struct KycTestContext *ktc = cls;
   3752   struct GNUNET_TIME_Relative dur;
   3753 
   3754   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3755               "KYC checking transaction amount %s from %s against %u rules\n",
   3756               TALER_amount2s (amount),
   3757               GNUNET_TIME_absolute2s (date),
   3758               ktc->lrs->num_kyc_rules);
   3759   dur = GNUNET_TIME_absolute_get_duration (date);
   3760   if (GNUNET_OK !=
   3761       TALER_amount_is_valid (&ktc->sum))
   3762     ktc->sum = *amount;
   3763   else
   3764     GNUNET_assert (0 <=
   3765                    TALER_amount_add (&ktc->sum,
   3766                                      &ktc->sum,
   3767                                      amount));
   3768   for (unsigned int i=0; i<ktc->lrs->num_kyc_rules; i++)
   3769   {
   3770     const struct TALER_KYCLOGIC_KycRule *rule
   3771       = &ktc->lrs->kyc_rules[i];
   3772 
   3773     if (ktc->event != rule->trigger)
   3774     {
   3775       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3776                   "Wrong event type (%d) for rule %u (%d)\n",
   3777                   (int) ktc->event,
   3778                   i,
   3779                   (int) rule->trigger);
   3780       continue; /* wrong trigger event type */
   3781     }
   3782     if (GNUNET_TIME_relative_cmp (dur,
   3783                                   >,
   3784                                   rule->timeframe))
   3785     {
   3786       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3787                   "Out of time range for rule %u\n",
   3788                   i);
   3789       continue; /* out of time range for rule */
   3790     }
   3791     if (-1 == TALER_amount_cmp (&ktc->sum,
   3792                                 &rule->threshold))
   3793     {
   3794       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3795                   "Below threshold of %s for rule %u\n",
   3796                   TALER_amount2s (&rule->threshold),
   3797                   i);
   3798       continue; /* sum < threshold */
   3799     }
   3800     if ( (NULL != ktc->triggered_rule) &&
   3801          (1 == TALER_amount_cmp (&ktc->triggered_rule->threshold,
   3802                                  &rule->threshold)) )
   3803     {
   3804       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3805                   "Higher than threshold of already triggered rule\n");
   3806       continue; /* threshold of triggered_rule > rule */
   3807     }
   3808     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3809                 "Remembering rule %s as triggered\n",
   3810                 rule->rule_name);
   3811     ktc->triggered_rule = rule;
   3812   }
   3813   return GNUNET_OK;
   3814 }
   3815 
   3816 
   3817 enum GNUNET_DB_QueryStatus
   3818 TALER_KYCLOGIC_kyc_test_required (
   3819   enum TALER_KYCLOGIC_KycTriggerEvent event,
   3820   const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
   3821   TALER_KYCLOGIC_KycAmountIterator ai,
   3822   void *ai_cls,
   3823   const struct TALER_KYCLOGIC_KycRule **triggered_rule,
   3824   struct TALER_Amount *next_threshold)
   3825 {
   3826   struct GNUNET_TIME_Relative range
   3827     = GNUNET_TIME_UNIT_ZERO;
   3828   enum GNUNET_DB_QueryStatus qs;
   3829   bool have_threshold = false;
   3830 
   3831   memset (next_threshold,
   3832           0,
   3833           sizeof (struct TALER_Amount));
   3834   if (NULL == lrs)
   3835     lrs = &default_rules;
   3836   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3837               "Testing %u KYC rules for trigger %d\n",
   3838               lrs->num_kyc_rules,
   3839               event);
   3840   for (unsigned int i=0; i<lrs->num_kyc_rules; i++)
   3841   {
   3842     const struct TALER_KYCLOGIC_KycRule *rule
   3843       = &lrs->kyc_rules[i];
   3844 
   3845     if (event != rule->trigger)
   3846     {
   3847       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3848                   "Rule %u is for a different trigger (%d/%d)\n",
   3849                   i,
   3850                   (int) event,
   3851                   (int) rule->trigger);
   3852       continue;
   3853     }
   3854     if (have_threshold)
   3855     {
   3856       GNUNET_assert (GNUNET_OK ==
   3857                      TALER_amount_min (next_threshold,
   3858                                        next_threshold,
   3859                                        &rule->threshold));
   3860     }
   3861     else
   3862     {
   3863       *next_threshold = rule->threshold;
   3864       have_threshold = true;
   3865     }
   3866     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3867                 "Matched rule %u with timeframe %s and threshold %s\n",
   3868                 i,
   3869                 GNUNET_TIME_relative2s (rule->timeframe,
   3870                                         true),
   3871                 TALER_amount2s (&rule->threshold));
   3872     range = GNUNET_TIME_relative_max (range,
   3873                                       rule->timeframe);
   3874   }
   3875 
   3876   if (! have_threshold)
   3877   {
   3878     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3879                 "No rules apply\n");
   3880     *triggered_rule = NULL;
   3881     return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
   3882   }
   3883 
   3884   {
   3885     struct GNUNET_TIME_Absolute now
   3886       = GNUNET_TIME_absolute_get ();
   3887     struct KycTestContext ktc = {
   3888       .lrs = lrs,
   3889       .event = event
   3890     };
   3891 
   3892     qs = ai (ai_cls,
   3893              GNUNET_TIME_absolute_subtract (now,
   3894                                             range),
   3895              &check_amount,
   3896              &ktc);
   3897     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3898                 "Triggered rule is %s\n",
   3899                 (NULL == ktc.triggered_rule)
   3900                 ? "NONE"
   3901                 : ktc.triggered_rule->rule_name);
   3902     *triggered_rule = ktc.triggered_rule;
   3903   }
   3904   return qs;
   3905 }
   3906 
   3907 
   3908 json_t *
   3909 TALER_KYCLOGIC_measure_to_requirement (
   3910   const char *check_name,
   3911   const json_t *context,
   3912   const struct TALER_AccountAccessTokenP *access_token,
   3913   size_t offset,
   3914   uint64_t legitimization_measure_row_id)
   3915 {
   3916   struct TALER_KYCLOGIC_KycCheck *kc;
   3917   json_t *kri;
   3918   struct TALER_KycMeasureAuthorizationHashP shv;
   3919   char *ids;
   3920   char *xids;
   3921 
   3922   kc = find_check (check_name);
   3923   if (NULL == kc)
   3924   {
   3925     GNUNET_break (0);
   3926     return NULL;
   3927   }
   3928   GNUNET_assert (offset <= UINT32_MAX);
   3929   TALER_kyc_measure_authorization_hash (access_token,
   3930                                         legitimization_measure_row_id,
   3931                                         (uint32_t) offset,
   3932                                         &shv);
   3933   switch (kc->type)
   3934   {
   3935   case TALER_KYCLOGIC_CT_INFO:
   3936     return GNUNET_JSON_PACK (
   3937       GNUNET_JSON_pack_string ("form",
   3938                                "INFO"),
   3939       GNUNET_JSON_pack_string ("description",
   3940                                kc->description),
   3941       GNUNET_JSON_pack_allow_null (
   3942         GNUNET_JSON_pack_object_incref ("description_i18n",
   3943                                         (json_t *) kc->description_i18n)));
   3944   case TALER_KYCLOGIC_CT_FORM:
   3945     GNUNET_assert (offset <= UINT_MAX);
   3946     ids = GNUNET_STRINGS_data_to_string_alloc (&shv,
   3947                                                sizeof (shv));
   3948     GNUNET_asprintf (&xids,
   3949                      "%s-%u-%llu",
   3950                      ids,
   3951                      (unsigned int) offset,
   3952                      (unsigned long long) legitimization_measure_row_id);
   3953     GNUNET_free (ids);
   3954     kri = GNUNET_JSON_PACK (
   3955       GNUNET_JSON_pack_string ("form",
   3956                                kc->details.form.name),
   3957       GNUNET_JSON_pack_string ("id",
   3958                                xids),
   3959       GNUNET_JSON_pack_allow_null (
   3960         GNUNET_JSON_pack_object_incref ("context",
   3961                                         (json_t *) context)),
   3962       GNUNET_JSON_pack_string ("description",
   3963                                kc->description),
   3964       GNUNET_JSON_pack_allow_null (
   3965         GNUNET_JSON_pack_object_incref ("description_i18n",
   3966                                         (json_t *) kc->description_i18n)));
   3967     GNUNET_free (xids);
   3968     return kri;
   3969   case TALER_KYCLOGIC_CT_LINK:
   3970     GNUNET_assert (offset <= UINT_MAX);
   3971     ids = GNUNET_STRINGS_data_to_string_alloc (&shv,
   3972                                                sizeof (shv));
   3973     GNUNET_asprintf (&xids,
   3974                      "%s-%u-%llu",
   3975                      ids,
   3976                      (unsigned int) offset,
   3977                      (unsigned long long) legitimization_measure_row_id);
   3978     GNUNET_free (ids);
   3979     kri = GNUNET_JSON_PACK (
   3980       GNUNET_JSON_pack_string ("form",
   3981                                "LINK"),
   3982       GNUNET_JSON_pack_string ("id",
   3983                                xids),
   3984       GNUNET_JSON_pack_string ("description",
   3985                                kc->description),
   3986       GNUNET_JSON_pack_allow_null (
   3987         GNUNET_JSON_pack_object_incref ("description_i18n",
   3988                                         (json_t *) kc->description_i18n)));
   3989     GNUNET_free (xids);
   3990     return kri;
   3991   }
   3992   GNUNET_break (0); /* invalid type */
   3993   return NULL;
   3994 }
   3995 
   3996 
   3997 void
   3998 TALER_KYCLOGIC_get_measure_configuration (
   3999   json_t **proots,
   4000   json_t **pprograms,
   4001   json_t **pchecks,
   4002   json_t **pdefault_rules)
   4003 {
   4004   json_t *roots;
   4005   json_t *programs;
   4006   json_t *checks;
   4007   json_t *drules;
   4008 
   4009   roots = json_object ();
   4010   GNUNET_assert (NULL != roots);
   4011   for (unsigned int i = 0; i<default_rules.num_custom_measures; i++)
   4012   {
   4013     const struct TALER_KYCLOGIC_Measure *m
   4014       = &default_rules.custom_measures[i];
   4015     json_t *jm;
   4016 
   4017     jm = GNUNET_JSON_PACK (
   4018       GNUNET_JSON_pack_string ("check_name",
   4019                                m->check_name),
   4020       GNUNET_JSON_pack_allow_null (
   4021         GNUNET_JSON_pack_string ("prog_name",
   4022                                  m->prog_name)),
   4023       GNUNET_JSON_pack_allow_null (
   4024         GNUNET_JSON_pack_object_incref ("context",
   4025                                         m->context)));
   4026     GNUNET_assert (0 ==
   4027                    json_object_set_new (roots,
   4028                                         m->measure_name,
   4029                                         jm));
   4030   }
   4031 
   4032   programs = json_object ();
   4033   GNUNET_assert (NULL != programs);
   4034   for (unsigned int i = 0; i<num_aml_programs; i++)
   4035   {
   4036     const struct TALER_KYCLOGIC_AmlProgram *ap
   4037       = aml_programs[i];
   4038     json_t *jp;
   4039     json_t *ctx;
   4040     json_t *inp;
   4041 
   4042     ctx = json_array ();
   4043     GNUNET_assert (NULL != ctx);
   4044     for (unsigned int j = 0; j<ap->num_required_contexts; j++)
   4045     {
   4046       const char *rc = ap->required_contexts[j];
   4047 
   4048       GNUNET_assert (0 ==
   4049                      json_array_append_new (ctx,
   4050                                             json_string (rc)));
   4051     }
   4052     inp = json_array ();
   4053     GNUNET_assert (NULL != inp);
   4054     for (unsigned int j = 0; j<ap->num_required_attributes; j++)
   4055     {
   4056       const char *ra = ap->required_attributes[j];
   4057 
   4058       GNUNET_assert (0 ==
   4059                      json_array_append_new (inp,
   4060                                             json_string (ra)));
   4061     }
   4062 
   4063     jp = GNUNET_JSON_PACK (
   4064       GNUNET_JSON_pack_string ("description",
   4065                                ap->description),
   4066       GNUNET_JSON_pack_array_steal ("context",
   4067                                     ctx),
   4068       GNUNET_JSON_pack_array_steal ("inputs",
   4069                                     inp));
   4070     GNUNET_assert (0 ==
   4071                    json_object_set_new (programs,
   4072                                         ap->program_name,
   4073                                         jp));
   4074   }
   4075 
   4076   checks = json_object ();
   4077   GNUNET_assert (NULL != checks);
   4078   for (unsigned int i = 0; i<num_kyc_checks; i++)
   4079   {
   4080     const struct TALER_KYCLOGIC_KycCheck *ck
   4081       = kyc_checks[i];
   4082     json_t *jc;
   4083     json_t *requires;
   4084     json_t *outputs;
   4085 
   4086     requires = json_array ();
   4087     GNUNET_assert (NULL != requires);
   4088     for (unsigned int j = 0; j<ck->num_requires; j++)
   4089     {
   4090       const char *ra = ck->requires[j];
   4091 
   4092       GNUNET_assert (0 ==
   4093                      json_array_append_new (requires,
   4094                                             json_string (ra)));
   4095     }
   4096     outputs = json_array ();
   4097     GNUNET_assert (NULL != outputs);
   4098     for (unsigned int j = 0; j<ck->num_outputs; j++)
   4099     {
   4100       const char *out = ck->outputs[j];
   4101 
   4102       GNUNET_assert (0 ==
   4103                      json_array_append_new (outputs,
   4104                                             json_string (out)));
   4105     }
   4106 
   4107     jc = GNUNET_JSON_PACK (
   4108       GNUNET_JSON_pack_string ("description",
   4109                                ck->description),
   4110       GNUNET_JSON_pack_allow_null (
   4111         GNUNET_JSON_pack_object_incref ("description_i18n",
   4112                                         ck->description_i18n)),
   4113       GNUNET_JSON_pack_array_steal ("requires",
   4114                                     requires),
   4115       GNUNET_JSON_pack_array_steal ("outputs",
   4116                                     outputs),
   4117       GNUNET_JSON_pack_string ("fallback",
   4118                                ck->fallback));
   4119     GNUNET_assert (0 ==
   4120                    json_object_set_new (checks,
   4121                                         ck->check_name,
   4122                                         jc));
   4123   }
   4124   drules = json_array ();
   4125   GNUNET_assert (NULL != drules);
   4126   {
   4127     const struct TALER_KYCLOGIC_KycRule *rules
   4128       = default_rules.kyc_rules;
   4129     unsigned int num_rules
   4130       = default_rules.num_kyc_rules;
   4131 
   4132     for (unsigned int i = 0; i<num_rules; i++)
   4133     {
   4134       const struct TALER_KYCLOGIC_KycRule *rule = &rules[i];
   4135       json_t *measures;
   4136       json_t *limit;
   4137 
   4138       measures = json_array ();
   4139       GNUNET_assert (NULL != measures);
   4140       for (unsigned int j = 0; j<rule->num_measures; j++)
   4141         GNUNET_assert (
   4142           0 ==
   4143           json_array_append_new (measures,
   4144                                  json_string (
   4145                                    rule->next_measures[j])));
   4146       limit = GNUNET_JSON_PACK (
   4147         GNUNET_JSON_pack_allow_null (
   4148           GNUNET_JSON_pack_string ("rule_name",
   4149                                    rule->rule_name)),
   4150         TALER_JSON_pack_kycte ("operation_type",
   4151                                rule->trigger),
   4152         TALER_JSON_pack_amount ("threshold",
   4153                                 &rule->threshold),
   4154         GNUNET_JSON_pack_time_rel ("timeframe",
   4155                                    rule->timeframe),
   4156         GNUNET_JSON_pack_array_steal ("measures",
   4157                                       measures),
   4158         GNUNET_JSON_pack_uint64 ("display_priority",
   4159                                  rule->display_priority),
   4160         GNUNET_JSON_pack_bool ("soft_limit",
   4161                                ! rule->verboten),
   4162         GNUNET_JSON_pack_bool ("exposed",
   4163                                rule->exposed),
   4164         GNUNET_JSON_pack_bool ("is_and_combinator",
   4165                                rule->is_and_combinator)
   4166         );
   4167       GNUNET_assert (0 ==
   4168                      json_array_append_new (drules,
   4169                                             limit));
   4170     }
   4171   }
   4172 
   4173   *proots = roots;
   4174   *pprograms = programs;
   4175   *pchecks = checks;
   4176   *pdefault_rules = drules;
   4177 }
   4178 
   4179 
   4180 enum TALER_ErrorCode
   4181 TALER_KYCLOGIC_select_measure (
   4182   const json_t *jmeasures,
   4183   size_t measure_index,
   4184   const char **check_name,
   4185   const char **prog_name,
   4186   const json_t **context)
   4187 {
   4188   const json_t *jmeasure_arr;
   4189   struct GNUNET_JSON_Specification spec[] = {
   4190     GNUNET_JSON_spec_array_const ("measures",
   4191                                   &jmeasure_arr),
   4192     GNUNET_JSON_spec_end ()
   4193   };
   4194   const json_t *jmeasure;
   4195   struct GNUNET_JSON_Specification ispec[] = {
   4196     GNUNET_JSON_spec_string ("check_name",
   4197                              check_name),
   4198     GNUNET_JSON_spec_mark_optional (
   4199       GNUNET_JSON_spec_string ("prog_name",
   4200                                prog_name),
   4201       NULL),
   4202     GNUNET_JSON_spec_mark_optional (
   4203       GNUNET_JSON_spec_object_const ("context",
   4204                                      context),
   4205       NULL),
   4206     GNUNET_JSON_spec_end ()
   4207   };
   4208 
   4209   *check_name = NULL;
   4210   *prog_name = NULL;
   4211   *context = NULL;
   4212   if (GNUNET_OK !=
   4213       GNUNET_JSON_parse (jmeasures,
   4214                          spec,
   4215                          NULL, NULL))
   4216   {
   4217     GNUNET_break (0);
   4218     return TALER_EC_EXCHANGE_KYC_MEASURES_MALFORMED;
   4219   }
   4220   if (measure_index >= json_array_size (jmeasure_arr))
   4221   {
   4222     GNUNET_break_op (0);
   4223     return TALER_EC_EXCHANGE_KYC_MEASURE_INDEX_INVALID;
   4224   }
   4225   jmeasure = json_array_get (jmeasure_arr,
   4226                              measure_index);
   4227   if (GNUNET_OK !=
   4228       GNUNET_JSON_parse (jmeasure,
   4229                          ispec,
   4230                          NULL, NULL))
   4231   {
   4232     GNUNET_break (0);
   4233     return TALER_EC_EXCHANGE_KYC_MEASURES_MALFORMED;
   4234   }
   4235   return TALER_EC_NONE;
   4236 }
   4237 
   4238 
   4239 enum TALER_ErrorCode
   4240 TALER_KYCLOGIC_check_form (
   4241   const json_t *jmeasures,
   4242   size_t measure_index,
   4243   const json_t *form_data,
   4244   char **form_name,
   4245   const char **error_message)
   4246 {
   4247   const char *check_name;
   4248   const char *prog_name;
   4249   const json_t *context;
   4250   struct TALER_KYCLOGIC_KycCheck *kc;
   4251   struct TALER_KYCLOGIC_AmlProgram *prog;
   4252 
   4253   *error_message = NULL;
   4254   *form_name = NULL;
   4255   if (TALER_EC_NONE !=
   4256       TALER_KYCLOGIC_select_measure (jmeasures,
   4257                                      measure_index,
   4258                                      &check_name,
   4259                                      &prog_name,
   4260                                      &context))
   4261   {
   4262     GNUNET_break_op (0);
   4263     return TALER_EC_EXCHANGE_KYC_MEASURE_INDEX_INVALID;
   4264   }
   4265   kc = find_check (check_name);
   4266   if (NULL == kc)
   4267   {
   4268     GNUNET_break (0);
   4269     *error_message = check_name;
   4270     return TALER_EC_EXCHANGE_KYC_GENERIC_CHECK_GONE;
   4271   }
   4272   if (TALER_KYCLOGIC_CT_FORM != kc->type)
   4273   {
   4274     GNUNET_break_op (0);
   4275     return TALER_EC_EXCHANGE_KYC_NOT_A_FORM;
   4276   }
   4277   if (NULL == prog_name)
   4278   {
   4279     /* non-INFO checks must have an AML program */
   4280     GNUNET_break (0);
   4281     return TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_BUG;
   4282   }
   4283   for (unsigned int i = 0; i<kc->num_outputs; i++)
   4284   {
   4285     const char *rattr = kc->outputs[i];
   4286 
   4287     if (NULL == json_object_get (form_data,
   4288                                  rattr))
   4289     {
   4290       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4291                   "Form data lacks required attribute `%s' for KYC check `%s'\n",
   4292                   rattr,
   4293                   check_name);
   4294       *error_message = rattr;
   4295       return TALER_EC_EXCHANGE_KYC_AML_FORM_INCOMPLETE;
   4296     }
   4297   }
   4298   prog = find_program (prog_name);
   4299   if (NULL == prog)
   4300   {
   4301     GNUNET_break (0);
   4302     *error_message = prog_name;
   4303     return TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_GONE;
   4304   }
   4305   for (unsigned int i = 0; i<prog->num_required_attributes; i++)
   4306   {
   4307     const char *rattr = prog->required_attributes[i];
   4308 
   4309     if (NULL == json_object_get (form_data,
   4310                                  rattr))
   4311     {
   4312       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4313                   "Form data lacks required attribute `%s' for AML program %s\n",
   4314                   rattr,
   4315                   prog_name);
   4316       *error_message = rattr;
   4317       return TALER_EC_EXCHANGE_KYC_AML_FORM_INCOMPLETE;
   4318     }
   4319   }
   4320   *form_name = GNUNET_strdup (kc->details.form.name);
   4321   return TALER_EC_NONE;
   4322 }
   4323 
   4324 
   4325 const char *
   4326 TALER_KYCLOGIC_get_aml_program_fallback (const char *prog_name)
   4327 {
   4328   struct TALER_KYCLOGIC_AmlProgram *prog;
   4329 
   4330   prog = find_program (prog_name);
   4331   if (NULL == prog)
   4332   {
   4333     GNUNET_break (0);
   4334     return NULL;
   4335   }
   4336   return prog->fallback;
   4337 }
   4338 
   4339 
   4340 const struct TALER_KYCLOGIC_KycProvider *
   4341 TALER_KYCLOGIC_check_to_provider (const char *check_name)
   4342 {
   4343   struct TALER_KYCLOGIC_KycCheck *kc;
   4344 
   4345   if (NULL == check_name)
   4346     return NULL;
   4347   if (0 == strcasecmp (check_name,
   4348                        "skip"))
   4349     return NULL;
   4350   kc = find_check (check_name);
   4351   if (NULL == kc)
   4352   {
   4353     GNUNET_break (0);
   4354     return NULL;
   4355   }
   4356   switch (kc->type)
   4357   {
   4358   case TALER_KYCLOGIC_CT_FORM:
   4359   case TALER_KYCLOGIC_CT_INFO:
   4360     return NULL;
   4361   case TALER_KYCLOGIC_CT_LINK:
   4362     break;
   4363   }
   4364   return kc->details.link.provider;
   4365 }
   4366 
   4367 
   4368 struct TALER_KYCLOGIC_AmlProgramRunnerHandle
   4369 {
   4370   /**
   4371    * Function to call back with the result.
   4372    */
   4373   TALER_KYCLOGIC_AmlProgramResultCallback aprc;
   4374 
   4375   /**
   4376    * Closure for @e aprc.
   4377    */
   4378   void *aprc_cls;
   4379 
   4380   /**
   4381    * Handle to an external process.
   4382    */
   4383   struct TALER_JSON_ExternalConversion *proc;
   4384 
   4385   /**
   4386    * AML program to turn.
   4387    */
   4388   const struct TALER_KYCLOGIC_AmlProgram *program;
   4389 
   4390   /**
   4391    * Task to return @e apr result asynchronously.
   4392    */
   4393   struct GNUNET_SCHEDULER_Task *async_cb;
   4394 
   4395   /**
   4396    * Result returned to the client.
   4397    */
   4398   struct TALER_KYCLOGIC_AmlProgramResult apr;
   4399 
   4400   /**
   4401    * How long do we allow the AML program to run?
   4402    */
   4403   struct GNUNET_TIME_Relative timeout;
   4404 
   4405 };
   4406 
   4407 
   4408 /**
   4409  * Function that that receives a JSON @a result from
   4410  * the AML program.
   4411  *
   4412  * @param cls closure of type `struct TALER_KYCLOGIC_AmlProgramRunnerHandle`
   4413  * @param status_type how did the process die
   4414  * @param code termination status code from the process,
   4415  *        non-zero if AML checks are required next
   4416  * @param result some JSON result, NULL if we failed to get an JSON output
   4417  */
   4418 static void
   4419 handle_aml_output (
   4420   void *cls,
   4421   enum GNUNET_OS_ProcessStatusType status_type,
   4422   unsigned long code,
   4423   const json_t *result)
   4424 {
   4425   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls;
   4426   const char *fallback_measure = aprh->program->fallback;
   4427   struct TALER_KYCLOGIC_AmlProgramResult *apr = &aprh->apr;
   4428   const char **evs = NULL;
   4429 
   4430   aprh->proc = NULL;
   4431   if (NULL != aprh->async_cb)
   4432   {
   4433     GNUNET_SCHEDULER_cancel (aprh->async_cb);
   4434     aprh->async_cb = NULL;
   4435   }
   4436 #if DEBUG
   4437   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4438               "AML program %s output is:\n",
   4439               aprh->program->program_name);
   4440   json_dumpf (result,
   4441               stderr,
   4442               JSON_INDENT (2));
   4443 #endif
   4444   memset (apr,
   4445           0,
   4446           sizeof (*apr));
   4447   if ( (GNUNET_OS_PROCESS_EXITED != status_type) ||
   4448        (0 != code) )
   4449   {
   4450     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   4451                 "AML program %s returned non-zero status %d/%d\n",
   4452                 aprh->program->program_name,
   4453                 (int) status_type,
   4454                 (int) code);
   4455     apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4456     apr->details.failure.fallback_measure
   4457       = fallback_measure;
   4458     apr->details.failure.error_message
   4459       = "AML program returned non-zero exit code";
   4460     apr->details.failure.ec
   4461       = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_FAILURE;
   4462     goto ready;
   4463   }
   4464 
   4465   {
   4466     const json_t *jevents = NULL;
   4467     struct GNUNET_JSON_Specification spec[] = {
   4468       GNUNET_JSON_spec_mark_optional (
   4469         GNUNET_JSON_spec_bool (
   4470           "to_investigate",
   4471           &apr->details.success.to_investigate),
   4472         NULL),
   4473       GNUNET_JSON_spec_mark_optional (
   4474         GNUNET_JSON_spec_object_const (
   4475           "properties",
   4476           &apr->details.success.account_properties),
   4477         NULL),
   4478       GNUNET_JSON_spec_mark_optional (
   4479         GNUNET_JSON_spec_array_const (
   4480           "events",
   4481           &jevents),
   4482         NULL),
   4483       GNUNET_JSON_spec_object_const (
   4484         "new_rules",
   4485         &apr->details.success.new_rules),
   4486       GNUNET_JSON_spec_mark_optional (
   4487         GNUNET_JSON_spec_string (
   4488           "new_measures",
   4489           &apr->details.success.new_measures),
   4490         NULL),
   4491       GNUNET_JSON_spec_end ()
   4492     };
   4493     const char *err;
   4494     unsigned int line;
   4495 
   4496     if (GNUNET_OK !=
   4497         GNUNET_JSON_parse (result,
   4498                            spec,
   4499                            &err,
   4500                            &line))
   4501     {
   4502       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4503                   "AML program output is malformed at `%s'\n",
   4504                   err);
   4505       json_dumpf (result,
   4506                   stderr,
   4507                   JSON_INDENT (2));
   4508       apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4509       apr->details.failure.fallback_measure
   4510         = fallback_measure;
   4511       apr->details.failure.error_message
   4512         = err;
   4513       apr->details.failure.ec
   4514         = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT;
   4515       goto ready;
   4516     }
   4517     apr->details.success.num_events
   4518       = json_array_size (jevents);
   4519 
   4520     GNUNET_assert (((size_t) apr->details.success.num_events) ==
   4521                    json_array_size (jevents));
   4522     evs = GNUNET_new_array (
   4523       apr->details.success.num_events,
   4524       const char *);
   4525     for (unsigned int i = 0; i<apr->details.success.num_events; i++)
   4526     {
   4527       evs[i] = json_string_value (
   4528         json_array_get (jevents,
   4529                         i));
   4530       if (NULL == evs[i])
   4531       {
   4532         apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4533         apr->details.failure.fallback_measure
   4534           = fallback_measure;
   4535         apr->details.failure.error_message
   4536           = "events";
   4537         apr->details.failure.ec
   4538           = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT;
   4539         goto ready;
   4540       }
   4541     }
   4542     apr->status = TALER_KYCLOGIC_AMLR_SUCCESS;
   4543     apr->details.success.events = evs;
   4544     {
   4545       /* check new_rules */
   4546       struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs;
   4547 
   4548       lrs = TALER_KYCLOGIC_rules_parse (
   4549         apr->details.success.new_rules);
   4550       if (NULL == lrs)
   4551       {
   4552         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4553                     "AML program output is malformed at `%s'\n",
   4554                     "new_rules");
   4555 
   4556         apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4557         apr->details.failure.fallback_measure
   4558           = fallback_measure;
   4559         apr->details.failure.error_message
   4560           = "new_rules";
   4561         apr->details.failure.ec
   4562           = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT;
   4563         goto ready;
   4564       }
   4565       apr->details.success.expiration_time
   4566         = lrs->expiration_time;
   4567       TALER_KYCLOGIC_rules_free (lrs);
   4568     }
   4569   }
   4570 ready:
   4571   aprh->aprc (aprh->aprc_cls,
   4572               &aprh->apr);
   4573   GNUNET_free (evs);
   4574   TALER_KYCLOGIC_run_aml_program_cancel (aprh);
   4575 }
   4576 
   4577 
   4578 /**
   4579  * Helper function to asynchronously return the result.
   4580  *
   4581  * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return results for
   4582  */
   4583 static void
   4584 async_return_task (void *cls)
   4585 {
   4586   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls;
   4587 
   4588   aprh->async_cb = NULL;
   4589   aprh->aprc (aprh->aprc_cls,
   4590               &aprh->apr);
   4591   TALER_KYCLOGIC_run_aml_program_cancel (aprh);
   4592 }
   4593 
   4594 
   4595 /**
   4596  * Helper function called on timeout on the fallback measure.
   4597  *
   4598  * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return results for
   4599  */
   4600 static void
   4601 handle_aml_timeout2 (void *cls)
   4602 {
   4603   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls;
   4604   struct TALER_KYCLOGIC_AmlProgramResult *apr = &aprh->apr;
   4605   const char *fallback_measure = aprh->program->fallback;
   4606 
   4607   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4608               "Fallback measure %s ran into timeout (!)\n",
   4609               aprh->program->program_name);
   4610   if (NULL != aprh->proc)
   4611   {
   4612     TALER_JSON_external_conversion_stop (aprh->proc);
   4613     aprh->proc = NULL;
   4614   }
   4615   apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4616   apr->details.failure.fallback_measure
   4617     = fallback_measure;
   4618   apr->details.failure.error_message
   4619     = aprh->program->program_name;
   4620   apr->details.failure.ec
   4621     = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT;
   4622   async_return_task (aprh);
   4623 }
   4624 
   4625 
   4626 /**
   4627  * Helper function called on timeout of an AML program.
   4628  * Runs the fallback measure.
   4629  *
   4630  * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return results for
   4631  */
   4632 static void
   4633 handle_aml_timeout (void *cls)
   4634 {
   4635   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls;
   4636   struct TALER_KYCLOGIC_AmlProgramResult *apr = &aprh->apr;
   4637   const char *fallback_measure = aprh->program->fallback;
   4638   const struct TALER_KYCLOGIC_Measure *m;
   4639   const struct TALER_KYCLOGIC_AmlProgram *fprogram;
   4640 
   4641   aprh->async_cb = NULL;
   4642   GNUNET_assert (NULL != fallback_measure);
   4643   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   4644               "AML program %s ran into timeout\n",
   4645               aprh->program->program_name);
   4646   if (NULL != aprh->proc)
   4647   {
   4648     TALER_JSON_external_conversion_stop (aprh->proc);
   4649     aprh->proc = NULL;
   4650   }
   4651 
   4652   m = TALER_KYCLOGIC_get_measure (&default_rules,
   4653                                   fallback_measure);
   4654   /* Fallback program could have "disappeared" due to configuration change,
   4655      as we do not check all rule sets in the database when our configuration
   4656      is updated... */
   4657   if (NULL == m)
   4658   {
   4659     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4660                 "Fallback measure `%s' does not exist (anymore?).\n",
   4661                 fallback_measure);
   4662     apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4663     apr->details.failure.fallback_measure
   4664       = fallback_measure;
   4665     apr->details.failure.error_message
   4666       = aprh->program->program_name;
   4667     apr->details.failure.ec
   4668       = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT;
   4669     async_return_task (aprh);
   4670     return;
   4671   }
   4672   /* We require fallback measures to have a 'skip' check */
   4673   GNUNET_break (0 ==
   4674                 strcasecmp (m->check_name,
   4675                             "skip"));
   4676   fprogram = find_program (m->prog_name);
   4677   /* Program associated with an original measure must exist */
   4678   GNUNET_assert (NULL != fprogram);
   4679   if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES)))
   4680   {
   4681     /* We might not have recognized the fallback measure as such
   4682        because it was not used as such in the plain configuration,
   4683        and legitimization rule sets might have referred to an older
   4684        configuration. So this should be super-rare but possible. */
   4685     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4686                 "Program `%s' used in fallback measure `%s' requires inputs and is thus unsuitable as a fallback measure!\n",
   4687                 m->prog_name,
   4688                 fallback_measure);
   4689     apr->status = TALER_KYCLOGIC_AMLR_FAILURE;
   4690     apr->details.failure.fallback_measure
   4691       = fallback_measure;
   4692     apr->details.failure.error_message
   4693       = aprh->program->program_name;
   4694     apr->details.failure.ec
   4695       = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT;
   4696     async_return_task (aprh);
   4697     return;
   4698   }
   4699   {
   4700     /* Run fallback AML program */
   4701     json_t *input = json_object ();
   4702     const char *extra_args[] = {
   4703       "-c",
   4704       cfg_filename,
   4705       NULL,
   4706     };
   4707     char **args;
   4708 
   4709     args = TALER_words_split (fprogram->command,
   4710                               extra_args);
   4711     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4712                 "Running fallback measure `%s' (%s)\n",
   4713                 fallback_measure,
   4714                 fprogram->command);
   4715     aprh->proc = TALER_JSON_external_conversion_start (
   4716       input,
   4717       &handle_aml_output,
   4718       aprh,
   4719       args[0],
   4720       (const char **) args);
   4721     TALER_words_destroy (args);
   4722     json_decref (input);
   4723   }
   4724   aprh->async_cb = GNUNET_SCHEDULER_add_delayed (aprh->timeout,
   4725                                                  &handle_aml_timeout2,
   4726                                                  aprh);
   4727 }
   4728 
   4729 
   4730 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *
   4731 TALER_KYCLOGIC_run_aml_program (
   4732   const json_t *jmeasures,
   4733   bool is_wallet,
   4734   unsigned int measure_index,
   4735   TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb,
   4736   void *current_attributes_cb_cls,
   4737   TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb,
   4738   void *current_rules_cb_cls,
   4739   TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb,
   4740   void *aml_history_cb_cls,
   4741   TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
   4742   void *kyc_history_cb_cls,
   4743   struct GNUNET_TIME_Relative timeout,
   4744   TALER_KYCLOGIC_AmlProgramResultCallback aprc,
   4745   void *aprc_cls)
   4746 {
   4747   const json_t *context;
   4748   const char *check_name;
   4749   const char *prog_name;
   4750 
   4751   {
   4752     enum TALER_ErrorCode ec;
   4753 
   4754     ec = TALER_KYCLOGIC_select_measure (jmeasures,
   4755                                         measure_index,
   4756                                         &check_name,
   4757                                         &prog_name,
   4758                                         &context);
   4759     if (TALER_EC_NONE != ec)
   4760     {
   4761       GNUNET_break (0);
   4762       return NULL;
   4763     }
   4764   }
   4765   if (NULL == prog_name)
   4766   {
   4767     /* Trying to run AML program on a measure that does not
   4768        have one, and that should thus be an INFO check which
   4769        should never lead here. Very strange. */
   4770     GNUNET_break (0);
   4771     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4772                 "Measure %u with check `%s' does not have an AML program!\n",
   4773                 measure_index,
   4774                 check_name);
   4775     json_dumpf (jmeasures,
   4776                 stderr,
   4777                 JSON_INDENT (2));
   4778     return NULL;
   4779   }
   4780   return TALER_KYCLOGIC_run_aml_program2 (prog_name,
   4781                                           context,
   4782                                           is_wallet,
   4783                                           current_attributes_cb,
   4784                                           current_attributes_cb_cls,
   4785                                           current_rules_cb,
   4786                                           current_rules_cb_cls,
   4787                                           aml_history_cb,
   4788                                           aml_history_cb_cls,
   4789                                           kyc_history_cb,
   4790                                           kyc_history_cb_cls,
   4791                                           timeout,
   4792                                           aprc,
   4793                                           aprc_cls);
   4794 }
   4795 
   4796 
   4797 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *
   4798 TALER_KYCLOGIC_run_aml_program2 (
   4799   const char *prog_name,
   4800   const json_t *context,
   4801   bool is_wallet,
   4802   TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb,
   4803   void *current_attributes_cb_cls,
   4804   TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb,
   4805   void *current_rules_cb_cls,
   4806   TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb,
   4807   void *aml_history_cb_cls,
   4808   TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
   4809   void *kyc_history_cb_cls,
   4810   struct GNUNET_TIME_Relative timeout,
   4811   TALER_KYCLOGIC_AmlProgramResultCallback aprc,
   4812   void *aprc_cls)
   4813 {
   4814   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh;
   4815   struct TALER_KYCLOGIC_AmlProgram *prog;
   4816   const json_t *jdefault_rules;
   4817   json_t *current_rules;
   4818   json_t *aml_history;
   4819   json_t *kyc_history;
   4820   json_t *attributes;
   4821 
   4822   prog = find_program (prog_name);
   4823   if (NULL == prog)
   4824   {
   4825     GNUNET_break (0);
   4826     return NULL;
   4827   }
   4828   aprh = GNUNET_new (struct TALER_KYCLOGIC_AmlProgramRunnerHandle);
   4829   aprh->aprc = aprc;
   4830   aprh->aprc_cls = aprc_cls;
   4831   aprh->program = prog;
   4832   if (0 != (API_ATTRIBUTES & prog->input_mask))
   4833   {
   4834     attributes = current_attributes_cb (current_attributes_cb_cls);
   4835 #if DEBUG
   4836     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4837                 "KYC attributes for AML program %s are:\n",
   4838                 prog_name);
   4839     json_dumpf (attributes,
   4840                 stderr,
   4841                 JSON_INDENT (2));
   4842     fprintf (stderr,
   4843              "\n");
   4844 #endif
   4845     for (unsigned int i = 0; i<prog->num_required_attributes; i++)
   4846     {
   4847       const char *rattr = prog->required_attributes[i];
   4848 
   4849       if (NULL == json_object_get (attributes,
   4850                                    rattr))
   4851       {
   4852         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4853                     "KYC attributes lack required attribute `%s' for AML program %s\n",
   4854                     rattr,
   4855                     prog->program_name);
   4856 #if DEBUG
   4857         json_dumpf (attributes,
   4858                     stderr,
   4859                     JSON_INDENT (2));
   4860 #endif
   4861         aprh->apr.status = TALER_KYCLOGIC_AMLR_FAILURE;
   4862         aprh->apr.details.failure.fallback_measure
   4863           = prog->fallback;
   4864         aprh->apr.details.failure.error_message
   4865           = rattr;
   4866         aprh->apr.details.failure.ec
   4867           = TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_INCOMPLETE_REPLY;
   4868         aprh->async_cb
   4869           = GNUNET_SCHEDULER_add_now (&async_return_task,
   4870                                       aprh);
   4871         json_decref (attributes);
   4872         return aprh;
   4873       }
   4874     }
   4875   }
   4876   else
   4877   {
   4878     attributes = NULL;
   4879   }
   4880   if (0 != (API_CONTEXT & prog->input_mask))
   4881   {
   4882     for (unsigned int i = 0; i<prog->num_required_contexts; i++)
   4883     {
   4884       const char *rctx = prog->required_contexts[i];
   4885 
   4886       if (NULL == json_object_get (context,
   4887                                    rctx))
   4888       {
   4889         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4890                     "Context lacks required field `%s' for AML program %s\n",
   4891                     rctx,
   4892                     prog->program_name);
   4893 #if DEBUG
   4894         json_dumpf (context,
   4895                     stderr,
   4896                     JSON_INDENT (2));
   4897 #endif
   4898         aprh->apr.status = TALER_KYCLOGIC_AMLR_FAILURE;
   4899         aprh->apr.details.failure.fallback_measure
   4900           = prog->fallback;
   4901         aprh->apr.details.failure.error_message
   4902           = rctx;
   4903         aprh->apr.details.failure.ec
   4904           = TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_INCOMPLETE_CONTEXT;
   4905         aprh->async_cb
   4906           = GNUNET_SCHEDULER_add_now (&async_return_task,
   4907                                       aprh);
   4908         json_decref (attributes);
   4909         return aprh;
   4910       }
   4911     }
   4912   }
   4913   else
   4914   {
   4915     context = NULL;
   4916   }
   4917   if (0 == (API_AML_HISTORY & prog->input_mask))
   4918     aml_history = NULL;
   4919   else
   4920     aml_history = aml_history_cb (aml_history_cb_cls);
   4921   if (0 == (API_KYC_HISTORY & prog->input_mask))
   4922     kyc_history = NULL;
   4923   else
   4924     kyc_history = kyc_history_cb (kyc_history_cb_cls);
   4925   if (0 == (API_CURRENT_RULES & prog->input_mask))
   4926     current_rules = NULL;
   4927   else
   4928     current_rules = current_rules_cb (current_rules_cb_cls);
   4929   if (0 != (API_DEFAULT_RULES & prog->input_mask))
   4930     jdefault_rules =
   4931       (is_wallet
   4932        ? wallet_default_lrs
   4933        : bankaccount_default_lrs);
   4934   else
   4935     jdefault_rules = NULL;
   4936   {
   4937     json_t *input;
   4938     const char *extra_args[] = {
   4939       "-c",
   4940       cfg_filename,
   4941       NULL,
   4942     };
   4943     char **args;
   4944 
   4945     input = GNUNET_JSON_PACK (
   4946       GNUNET_JSON_pack_allow_null (
   4947         GNUNET_JSON_pack_object_steal ("current_rules",
   4948                                        current_rules)),
   4949       GNUNET_JSON_pack_allow_null (
   4950         GNUNET_JSON_pack_object_incref ("default_rules",
   4951                                         (json_t *) jdefault_rules)),
   4952       GNUNET_JSON_pack_allow_null (
   4953         GNUNET_JSON_pack_object_incref ("context",
   4954                                         (json_t *) context)),
   4955       GNUNET_JSON_pack_allow_null (
   4956         GNUNET_JSON_pack_object_steal ("attributes",
   4957                                        attributes)),
   4958       GNUNET_JSON_pack_allow_null (
   4959         GNUNET_JSON_pack_array_steal ("aml_history",
   4960                                       aml_history)),
   4961       GNUNET_JSON_pack_allow_null (
   4962         GNUNET_JSON_pack_array_steal ("kyc_history",
   4963                                       kyc_history))
   4964       );
   4965     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4966                 "Running AML program %s\n",
   4967                 prog->command);
   4968     args = TALER_words_split (prog->command,
   4969                               extra_args);
   4970     GNUNET_assert (NULL != args);
   4971     GNUNET_assert (NULL != args[0]);
   4972 #if DEBUG
   4973     json_dumpf (input,
   4974                 stderr,
   4975                 JSON_INDENT (2));
   4976 #endif
   4977     aprh->proc = TALER_JSON_external_conversion_start (
   4978       input,
   4979       &handle_aml_output,
   4980       aprh,
   4981       args[0],
   4982       (const char **) args);
   4983     TALER_words_destroy (args);
   4984     json_decref (input);
   4985   }
   4986   aprh->timeout = timeout;
   4987   aprh->async_cb = GNUNET_SCHEDULER_add_delayed (timeout,
   4988                                                  &handle_aml_timeout,
   4989                                                  aprh);
   4990   return aprh;
   4991 }
   4992 
   4993 
   4994 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *
   4995 TALER_KYCLOGIC_run_aml_program3 (
   4996   bool is_wallet,
   4997   const struct TALER_KYCLOGIC_Measure *measure,
   4998   TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb,
   4999   void *current_attributes_cb_cls,
   5000   TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb,
   5001   void *current_rules_cb_cls,
   5002   TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb,
   5003   void *aml_history_cb_cls,
   5004   TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
   5005   void *kyc_history_cb_cls,
   5006   struct GNUNET_TIME_Relative timeout,
   5007   TALER_KYCLOGIC_AmlProgramResultCallback aprc,
   5008   void *aprc_cls)
   5009 {
   5010   return TALER_KYCLOGIC_run_aml_program2 (
   5011     measure->prog_name,
   5012     measure->context,
   5013     is_wallet,
   5014     current_attributes_cb,
   5015     current_attributes_cb_cls,
   5016     current_rules_cb,
   5017     current_rules_cb_cls,
   5018     aml_history_cb,
   5019     aml_history_cb_cls,
   5020     kyc_history_cb,
   5021     kyc_history_cb_cls,
   5022     timeout,
   5023     aprc,
   5024     aprc_cls);
   5025 }
   5026 
   5027 
   5028 const char *
   5029 TALER_KYCLOGIC_run_aml_program_get_name (
   5030   const struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh)
   5031 {
   5032   return aprh->program->program_name;
   5033 }
   5034 
   5035 
   5036 void
   5037 TALER_KYCLOGIC_run_aml_program_cancel (
   5038   struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh)
   5039 {
   5040   if (NULL != aprh->proc)
   5041   {
   5042     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   5043                 "Killing AML program\n");
   5044     TALER_JSON_external_conversion_stop (aprh->proc);
   5045     aprh->proc = NULL;
   5046   }
   5047   if (NULL != aprh->async_cb)
   5048   {
   5049     GNUNET_SCHEDULER_cancel (aprh->async_cb);
   5050     aprh->async_cb = NULL;
   5051   }
   5052   GNUNET_free (aprh);
   5053 }
   5054 
   5055 
   5056 json_t *
   5057 TALER_KYCLOGIC_get_hard_limits ()
   5058 {
   5059   const struct TALER_KYCLOGIC_KycRule *rules
   5060     = default_rules.kyc_rules;
   5061   unsigned int num_rules
   5062     = default_rules.num_kyc_rules;
   5063   json_t *hard_limits;
   5064 
   5065   hard_limits = json_array ();
   5066   GNUNET_assert (NULL != hard_limits);
   5067   for (unsigned int i = 0; i<num_rules; i++)
   5068   {
   5069     const struct TALER_KYCLOGIC_KycRule *rule = &rules[i];
   5070     json_t *hard_limit;
   5071 
   5072     if (! rule->verboten)
   5073       continue;
   5074     if (! rule->exposed)
   5075       continue;
   5076     hard_limit = GNUNET_JSON_PACK (
   5077       GNUNET_JSON_pack_allow_null (
   5078         GNUNET_JSON_pack_string ("rule_name",
   5079                                  rule->rule_name)),
   5080       TALER_JSON_pack_kycte ("operation_type",
   5081                              rule->trigger),
   5082       GNUNET_JSON_pack_time_rel ("timeframe",
   5083                                  rule->timeframe),
   5084       TALER_JSON_pack_amount ("threshold",
   5085                               &rule->threshold)
   5086       );
   5087     GNUNET_assert (0 ==
   5088                    json_array_append_new (hard_limits,
   5089                                           hard_limit));
   5090   }
   5091   return hard_limits;
   5092 }
   5093 
   5094 
   5095 json_t *
   5096 TALER_KYCLOGIC_get_zero_limits ()
   5097 {
   5098   const struct TALER_KYCLOGIC_KycRule *rules
   5099     = default_rules.kyc_rules;
   5100   unsigned int num_rules
   5101     = default_rules.num_kyc_rules;
   5102   json_t *zero_limits;
   5103 
   5104   zero_limits = json_array ();
   5105   GNUNET_assert (NULL != zero_limits);
   5106   for (unsigned int i = 0; i<num_rules; i++)
   5107   {
   5108     const struct TALER_KYCLOGIC_KycRule *rule = &rules[i];
   5109     json_t *zero_limit;
   5110 
   5111     if (! rule->exposed)
   5112       continue;
   5113     if (rule->verboten)
   5114       continue; /* see: hard_limits */
   5115     if (! TALER_amount_is_zero (&rule->threshold))
   5116       continue;
   5117     zero_limit = GNUNET_JSON_PACK (
   5118       GNUNET_JSON_pack_allow_null (
   5119         GNUNET_JSON_pack_string ("rule_name",
   5120                                  rule->rule_name)),
   5121       TALER_JSON_pack_kycte ("operation_type",
   5122                              rule->trigger));
   5123     GNUNET_assert (0 ==
   5124                    json_array_append_new (zero_limits,
   5125                                           zero_limit));
   5126   }
   5127   return zero_limits;
   5128 }
   5129 
   5130 
   5131 json_t *
   5132 TALER_KYCLOGIC_get_default_legi_rules (bool for_wallet)
   5133 {
   5134   const json_t *r;
   5135 
   5136   r = (for_wallet
   5137        ? wallet_default_lrs
   5138        : bankaccount_default_lrs);
   5139   return json_incref ((json_t *) r);
   5140 }
   5141 
   5142 
   5143 /* end of kyclogic_api.c */