LCOV - code coverage report
Current view: top level - kyclogic - kyclogic_api.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 977 1669 58.5 %
Date: 2025-06-05 21:03:14 Functions: 54 71 76.1 %

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

Generated by: LCOV version 1.16