LCOV - code coverage report
Current view: top level - kyclogic - kyclogic_api.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 58.6 % 1808 1059
Test Date: 2025-12-28 14:06:02 Functions: 77.0 % 74 57

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

Generated by: LCOV version 2.0-1