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

Generated by: LCOV version 1.16