LCOV - code coverage report
Current view: top level - kyclogic - kyclogic_api.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 57.0 % 1804 1029
Test Date: 2026-06-14 14:19:22 Functions: 75.3 % 73 55

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

Generated by: LCOV version 2.0-1