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


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