LCOV - code coverage report
Current view: top level - kyclogic - kyclogic_api.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 57.2 % 1831 1047
Test Date: 2026-09-09 15:11:34 Functions: 76.0 % 75 57

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

Generated by: LCOV version 2.0-1