diff options
Diffstat (limited to 'src/exchange/taler-exchange-httpd_kyc.c')
-rw-r--r-- | src/exchange/taler-exchange-httpd_kyc.c | 1019 |
1 files changed, 0 insertions, 1019 deletions
diff --git a/src/exchange/taler-exchange-httpd_kyc.c b/src/exchange/taler-exchange-httpd_kyc.c deleted file mode 100644 index ea90c08a6..000000000 --- a/src/exchange/taler-exchange-httpd_kyc.c +++ /dev/null @@ -1,1019 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-exchange-httpd_kyc.c - * @brief KYC API for the exchange - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler-exchange-httpd.h" -#include "taler-exchange-httpd_kyc.h" -#include "taler_exchangedb_plugin.h" - -/** - * Information about a KYC provider. - */ -struct TEH_KycProvider; - - -/** - * Abstract representation of a KYC check. - */ -struct TEH_KycCheck -{ - /** - * Human-readable name given to the KYC check. - */ - char *name; - - /** - * Array of @e num_providers providers that offer this type of KYC check. - */ - struct TEH_KycProvider **providers; - - /** - * Length of the @e providers array. - */ - unsigned int num_providers; - -}; - - -struct TEH_KycProvider -{ - /** - * Name of the provider (configuration section name). - */ - const char *provider_section_name; - - /** - * Array of @e num_checks checks performed by this provider. - */ - struct TEH_KycCheck **provided_checks; - - /** - * Logic to run for this provider. - */ - struct TALER_KYCLOGIC_Plugin *logic; - - /** - * @e provider_section_name specific details to - * pass to the @e logic functions. - */ - struct TALER_KYCLOGIC_ProviderDetails *pd; - - /** - * Cost of running this provider's KYC. - */ - unsigned long long cost; - - /** - * Length of the @e checks array. - */ - unsigned int num_checks; - - /** - * Type of user this provider supports. - */ - enum TEH_KycUserType user_type; -}; - - -/** - * Condition that triggers a need to perform KYC. - */ -struct TEH_KycTrigger -{ - - /** - * Timeframe to consider for computing the amount - * to compare against the @e limit. Zero for the - * wallet balance trigger (as not applicable). - */ - struct GNUNET_TIME_Relative timeframe; - - /** - * Maximum amount that can be transacted until - * the rule triggers. - */ - struct TALER_Amount threshold; - - /** - * Array of @e num_checks checks to apply on this trigger. - */ - struct TEH_KycCheck **required_checks; - - /** - * Length of the @e checks array. - */ - unsigned int num_checks; - - /** - * What event is this trigger for? - */ - enum TEH_KycTriggerEvent trigger; - -}; - - -/** - * Array of @e num_kyc_logics KYC logic plugins we have loaded. - */ -static struct TALER_KYCLOGIC_Plugin **kyc_logics; - -/** - * Length of the #kyc_logics array. - */ -static unsigned int num_kyc_logics; - -/** - * Array of @e num_kyc_checks known types of - * KYC checks. - */ -static struct TEH_KycCheck **kyc_checks; - -/** - * Length of the #kyc_checks array. - */ -static unsigned int num_kyc_checks; - -/** - * Array of configured triggers. - */ -static struct TEH_KycTrigger **kyc_triggers; - -/** - * Length of the #kyc_triggers array. - */ -static unsigned int num_kyc_triggers; - -/** - * Array of configured providers. - */ -static struct TEH_KycProvider **kyc_providers; - -/** - * Length of the #kyc_providers array. - */ -static unsigned int num_kyc_providers; - - -enum GNUNET_GenericReturnValue -TEH_kyc_trigger_from_string (const char *trigger_s, - enum TEH_KycTriggerEvent *trigger) -{ - struct - { - const char *in; - enum TEH_KycTriggerEvent out; - } map [] = { - { "withdraw", TEH_KYC_TRIGGER_WITHDRAW }, - { "deposit", TEH_KYC_TRIGGER_DEPOSIT }, - { "merge", TEH_KYC_TRIGGER_P2P_RECEIVE }, - { "balance", TEH_KYC_TRIGGER_WALLET_BALANCE }, - { NULL, 0 } - }; - - for (unsigned int i = 0; NULL != map[i].in; i++) - if (0 == strcasecmp (map[i].in, - trigger_s)) - { - *trigger = map[i].out; - return GNUNET_OK; - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid KYC trigger `%s'\n", - trigger_s); - return GNUNET_SYSERR; -} - - -const char * -TEH_kyc_trigger2s (enum TEH_KycTriggerEvent trigger) -{ - switch (trigger) - { - case TEH_KYC_TRIGGER_WITHDRAW: - return "withdraw"; - case TEH_KYC_TRIGGER_DEPOSIT: - return "deposit"; - case TEH_KYC_TRIGGER_P2P_RECEIVE: - return "merge"; - case TEH_KYC_TRIGGER_WALLET_BALANCE: - return "balance"; - } - GNUNET_break (0); - return NULL; -} - - -enum GNUNET_GenericReturnValue -TEH_kyc_user_type_from_string (const char *ut_s, - enum TEH_KycUserType *ut) -{ - struct - { - const char *in; - enum TEH_KycTriggerEvent out; - } map [] = { - { "individual", TEH_KYC_UT_INDIVIDUAL }, - { "business", TEH_KYC_UT_BUSINESS }, - { NULL, 0 } - }; - - for (unsigned int i = 0; NULL != map[i].in; i++) - if (0 == strcasecmp (map[i].in, - ut_s)) - { - *ut = map[i].out; - return GNUNET_OK; - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid user type `%s'\n", - ut_s); - return GNUNET_SYSERR; -} - - -const char * -TEH_kyc_user_type2s (enum TEH_KycUserType ut) -{ - switch (ut) - { - case TEH_KYC_UT_INDIVIDUAL: - return "individual"; - case TEH_KYC_UT_BUSINESS: - return "business"; - } - GNUNET_break (0); - return NULL; -} - - -/** - * Load KYC logic plugin. - * - * @param name name of the plugin - * @return NULL on error - */ -static struct TALER_KYCLOGIC_Plugin * -load_logic (const char *name) -{ - char *lib_name; - struct TALER_KYCLOGIC_Plugin *plugin; - - GNUNET_asprintf (&lib_name, - "libtaler_plugin_kyclogic_%s", - name); - plugin = GNUNET_PLUGIN_load (lib_name, - (void *) TEH_cfg); - if (NULL != plugin) - plugin->library_name = lib_name; - else - GNUNET_free (lib_name); - return plugin; -} - - -/** - * Add check type to global array of checks. - * First checks if the type already exists, otherwise - * adds a new one. - * - * @param check name of the check - * @return pointer into the global list - */ -static struct TEH_KycCheck * -add_check (const char *check) -{ - struct TEH_KycCheck *kc; - - for (unsigned int i = 0; i<num_kyc_checks; i++) - if (0 == strcasecmp (check, - kyc_checks[i]->name)) - return kyc_checks[i]; - kc = GNUNET_new (struct TEH_KycCheck); - kc->name = GNUNET_strdup (check); - GNUNET_array_append (kyc_checks, - num_kyc_checks, - kc); - return kc; -} - - -/** - * Parse list of checks from @a checks and build an - * array of aliases into the global checks array - * in @a provided_checks. - * - * @param[in,out] checks list of checks; clobbered - * @param[out] p_checks where to put array of aliases - * @param[out] num_p_checks set to length of @a p_checks array - */ -static void -add_checks (char *checks, - struct TEH_KycCheck ***p_checks, - unsigned int *num_p_checks) -{ - char *sptr; - struct TEH_KycCheck **rchecks = NULL; - unsigned int num_rchecks = 0; - - for (char *tok = strtok_r (checks, " ", &sptr); - NULL != tok; - tok = strtok_r (NULL, " ", &sptr)) - { - struct TEH_KycCheck *kc; - - kc = add_check (tok); - GNUNET_array_append (rchecks, - num_rchecks, - kc); - } - *p_checks = rchecks; - *num_p_checks = num_rchecks; -} - - -/** - * Parse configuration of a KYC provider. - * - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -add_provider (const char *section) -{ - unsigned long long cost; - char *logic; - char *ut_s; - enum TEH_KycUserType ut; - char *checks; - struct TALER_KYCLOGIC_Plugin *lp; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (TEH_cfg, - section, - "COST", - &cost)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "COST", - "number required"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (TEH_cfg, - section, - "USER_TYPE", - &ut_s)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - section, - "USER_TYPE"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TEH_kyc_user_type_from_string (ut_s, - &ut)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "USER_TYPE", - "valid user type required"); - GNUNET_free (ut_s); - return GNUNET_SYSERR; - } - GNUNET_free (ut_s); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (TEH_cfg, - section, - "LOGIC", - &logic)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - section, - "LOGIC"); - return GNUNET_SYSERR; - } - lp = load_logic (logic); - if (NULL == lp) - { - GNUNET_free (logic); - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "LOGIC", - "logic plugin could not be loaded"); - return GNUNET_SYSERR; - } - GNUNET_free (logic); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (TEH_cfg, - section, - "PROVIDED_CHECKS", - &checks)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - section, - "PROVIDED_CHECKS"); - return GNUNET_SYSERR; - } - { - struct TEH_KycProvider *kp; - - kp = GNUNET_new (struct TEH_KycProvider); - kp->provider_section_name = section; - kp->user_type = ut; - kp->logic = lp; - kp->cost = cost; - add_checks (checks, - &kp->provided_checks, - &kp->num_checks); - GNUNET_free (checks); - kp->pd = lp->load_configuration (lp->cls, - section); - if (NULL == kp->pd) - { - GNUNET_free (kp); - return GNUNET_SYSERR; - } - GNUNET_array_append (kyc_providers, - num_kyc_providers, - kp); - for (unsigned int i = 0; i<kp->num_checks; i++) - { - struct TEH_KycCheck *kc = kp->provided_checks[i]; - - GNUNET_array_append (kc->providers, - kc->num_providers, - kp); - } - } - return GNUNET_OK; -} - - -static enum GNUNET_GenericReturnValue -add_trigger (const char *section) -{ - char *ot_s; - struct TALER_Amount threshold; - struct GNUNET_TIME_Relative timeframe; - char *checks; - enum TEH_KycTriggerEvent ot; - - if (GNUNET_OK != - TALER_config_get_amount (TEH_cfg, - section, - "THRESHOLD", - &threshold)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "THRESHOLD", - "amount required"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (TEH_cfg, - section, - "OPERATION_TYPE", - &ot_s)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - section, - "OPERATION_TYPE"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TEH_kyc_trigger_from_string (ot_s, - &ot)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "OPERATION_TYPE", - "valid trigger type required"); - GNUNET_free (ot_s); - return GNUNET_SYSERR; - } - GNUNET_free (ot_s); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (TEH_cfg, - section, - "TIMEFRAME", - &timeframe)) - { - if (TEH_KYC_TRIGGER_WALLET_BALANCE == ot) - { - timeframe = GNUNET_TIME_UNIT_ZERO; - } - else - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "TIMEFRAME", - "duration required"); - return GNUNET_SYSERR; - } - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (TEH_cfg, - section, - "REQUIRED_CHECKS", - &checks)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - section, - "REQUIRED_CHECKS"); - return GNUNET_SYSERR; - } - - { - struct TEH_KycTrigger *kt; - - kt = GNUNET_new (struct TEH_KycTrigger); - kt->timeframe = timeframe; - kt->threshold = threshold; - kt->trigger = ot; - add_checks (checks, - &kt->required_checks, - &kt->num_checks); - GNUNET_free (checks); - GNUNET_array_append (kyc_triggers, - num_kyc_triggers, - kt); - } - return GNUNET_OK; -} - - -/** - * Function to iterate over configuration sections. - * - * @param cls closure, `boolean *`, set to false on failure - * @param section name of the section - */ -static void -handle_section (void *cls, - const char *section) -{ - bool *ok = cls; - - if (0 == strncasecmp (section, - "kyc-provider-", - strlen ("kyc-provider-"))) - { - if (GNUNET_OK != - add_provider (section)) - *ok = false; - return; - } - if (0 == strncasecmp (section, - "kyc-legitimization-", - strlen ("kyc-legitimization-"))) - { - if (GNUNET_OK != - add_trigger (section)) - *ok = false; - return; - } -} - - -/** - * Comparator for qsort. Compares two triggers - * by timeframe to sort triggers by time. - * - * @param p1 first trigger to compare - * @param p2 second trigger to compare - * @return -1 if p1 < p2, 0 if p1==p2, 1 if p1 > p2. - */ -static int -sort_by_timeframe (const void *p1, - const void *p2) -{ - struct TEH_KycTrigger **t1 = (struct TEH_KycTrigger **) p1; - struct TEH_KycTrigger **t2 = (struct TEH_KycTrigger **) p2; - - if (GNUNET_TIME_relative_cmp ((*t1)->timeframe, - <, - (*t2)->timeframe)) - return -1; - if (GNUNET_TIME_relative_cmp ((*t1)->timeframe, - >, - (*t2)->timeframe)) - return 1; - return 0; -} - - -enum GNUNET_GenericReturnValue -TEH_kyc_init (void) -{ - bool ok = true; - - GNUNET_CONFIGURATION_iterate_sections (TEH_cfg, - &handle_section, - &ok); - if (! ok) - { - TEH_kyc_done (); - return GNUNET_SYSERR; - } - - /* sanity check: ensure at least one provider exists - for any trigger and indidivual or business. */ - for (unsigned int i = 0; i<num_kyc_checks; i++) - if (0 == kyc_checks[i]->num_providers) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No provider available for required KYC check `%s'\n", - kyc_checks[i]->name); - TEH_kyc_done (); - return GNUNET_SYSERR; - } - qsort (kyc_triggers, - num_kyc_triggers, - sizeof (struct TEH_KycTrigger *), - &sort_by_timeframe); - return GNUNET_OK; -} - - -void -TEH_kyc_done (void) -{ - for (unsigned int i = 0; i<num_kyc_triggers; i++) - { - struct TEH_KycTrigger *kt = kyc_triggers[i]; - - GNUNET_array_grow (kt->required_checks, - kt->num_checks, - 0); - GNUNET_free (kt); - } - GNUNET_array_grow (kyc_triggers, - num_kyc_triggers, - 0); - for (unsigned int i = 0; i<num_kyc_providers; i++) - { - struct TEH_KycProvider *kp = kyc_providers[i]; - - kp->logic->unload_configuration (kp->pd); - GNUNET_array_grow (kp->provided_checks, - kp->num_checks, - 0); - GNUNET_free (kp); - } - GNUNET_array_grow (kyc_providers, - num_kyc_providers, - 0); - for (unsigned int i = 0; i<num_kyc_logics; i++) - { - struct TALER_KYCLOGIC_Plugin *lp = kyc_logics[i]; - char *lib_name = lp->library_name; - - GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name, - lp)); - GNUNET_free (lib_name); - } - GNUNET_array_grow (kyc_logics, - num_kyc_logics, - 0); - for (unsigned int i = 0; i<num_kyc_checks; i++) - { - struct TEH_KycCheck *kc = kyc_checks[i]; - - GNUNET_free (kc->name); - GNUNET_free (kc); - } - GNUNET_array_grow (kyc_checks, - num_kyc_checks, - 0); -} - - -/** - * Closure for the #eval_trigger(). - */ -struct ThresholdTestContext -{ - /** - * Total amount so far. - */ - struct TALER_Amount total; - - /** - * Trigger event to evaluate triggers of. - */ - enum TEH_KycTriggerEvent event; - - /** - * Offset in the triggers array where we need to start - * checking for triggers. All trigges below this - * offset were already hit. - */ - unsigned int start; - - /** - * Array of checks needed so far. - */ - struct TEH_KycCheck **needed; - - /** - * Pointer to number of entries used in @a needed. - */ - unsigned int *needed_cnt; - -}; - - -/** - * Function called on each @a amount that was found to - * be relevant for a KYC check. - * - * @param cls closure to allow the KYC module to - * total up amounts and evaluate rules - * @param amount encountered transaction amount - * @param date when was the amount encountered - * @return #GNUNET_OK to continue to iterate, - * #GNUNET_NO to abort iteration - * #GNUNET_SYSERR on internal error (also abort itaration) - */ -static enum GNUNET_GenericReturnValue -eval_trigger (void *cls, - const struct TALER_Amount *amount, - struct GNUNET_TIME_Absolute date) -{ - struct ThresholdTestContext *ttc = cls; - struct GNUNET_TIME_Relative duration; - bool bump = true; - - duration = GNUNET_TIME_absolute_get_duration (date); - if (0 > - TALER_amount_add (&ttc->total, - &ttc->total, - amount)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - for (unsigned int i = ttc->start; i<num_kyc_triggers; i++) - { - const struct TEH_KycTrigger *kt = kyc_triggers[i]; - - if (ttc->event != kt->trigger) - continue; - duration = GNUNET_TIME_relative_max (duration, - kt->timeframe); - if (GNUNET_TIME_relative_cmp (kt->timeframe, - >, - duration)) - { - if (bump) - ttc->start = i; - return GNUNET_OK; - } - if (-1 == - TALER_amount_cmp (&ttc->total, - &kt->threshold)) - { - if (bump) - ttc->start = i; - bump = false; - continue; /* amount too low to trigger */ - } - /* add check to list of required checks, unless - already present... */ - for (unsigned int j = 0; j<kt->num_checks; j++) - { - struct TEH_KycCheck *rc = kt->required_checks[j]; - bool found = false; - - for (unsigned int k = 0; k<*ttc->needed_cnt; k++) - if (ttc->needed[k] == rc) - { - found = true; - break; - } - if (! found) - { - ttc->needed[*ttc->needed_cnt] = rc; - (*ttc->needed_cnt)++; - } - } - } - if (bump) - return GNUNET_NO; /* we hit all possible triggers! */ - return GNUNET_OK; -} - - -/** - * Closure for the #remove_satisfied(). - */ -struct RemoveContext -{ - - /** - * Array of checks needed so far. - */ - struct TEH_KycCheck **needed; - - /** - * Pointer to number of entries used in @a needed. - */ - unsigned int *needed_cnt; - -}; - - -/** - * Remove all checks satisfied by @a provider_name from - * our list of checks. - * - * @param cls a `struct RemoveContext` - * @param provider_name section name of provider that was already run previously - */ -static void -remove_satisfied (void *cls, - const char *provider_name) -{ - struct RemoveContext *rc = cls; - - for (unsigned int i = 0; i<num_kyc_providers; i++) - { - const struct TEH_KycProvider *kp = kyc_providers[i]; - - if (0 != strcasecmp (provider_name, - kp->provider_section_name)) - continue; - for (unsigned int j = 0; j<kp->num_checks; j++) - { - const struct TEH_KycCheck *kc = kp->provided_checks[j]; - - for (unsigned int k = 0; k<*rc->needed_cnt; k++) - if (kc == rc->needed[k]) - { - rc->needed[k] = rc->needed[*rc->needed_cnt - 1]; - (*rc->needed_cnt)--; - if (0 == *rc->needed_cnt) - return; /* for sure finished */ - break; - } - } - break; - } -} - - -const char * -TEH_kyc_test_required (enum TEH_KycTriggerEvent event, - const struct TALER_PaytoHashP *h_payto, - TEH_KycAmountIterator ai, - void *ai_cls) -{ - struct TEH_KycCheck *needed[num_kyc_checks]; - unsigned int needed_cnt = 0; - struct GNUNET_TIME_Relative timeframe; - unsigned long long min_cost = ULONG_LONG_MAX; - unsigned int max_checks = 0; - const struct TEH_KycProvider *kp_best = NULL; - - timeframe = GNUNET_TIME_UNIT_ZERO; - for (unsigned int i = 0; i<num_kyc_triggers; i++) - { - const struct TEH_KycTrigger *kt = kyc_triggers[i]; - - if (event != kt->trigger) - continue; - timeframe = GNUNET_TIME_relative_max (timeframe, - kt->timeframe); - } - { - struct GNUNET_TIME_Absolute now; - struct ThresholdTestContext ttc = { - .event = event, - .needed = needed, - .needed_cnt = &needed_cnt - }; - - TALER_amount_set_zero (TEH_currency, - &ttc.total); - now = GNUNET_TIME_absolute_get (); - ai (ai_cls, - GNUNET_TIME_absolute_subtract (now, - timeframe), - &eval_trigger, - &ttc); - } - if (0 == needed_cnt) - return NULL; - { - struct RemoveContext rc = { - .needed = needed, - .needed_cnt = &needed_cnt - }; - enum GNUNET_DB_QueryStatus qs; - - /* Check what provider checks are already satisfied for h_payto (with - database), remove those from the 'needed' array. */ - GNUNET_break (0); - qs = TEH_plugin->select_satisfied_kyc_processes (TEH_plugin->cls, - h_payto, - &remove_satisfied, - &rc); - GNUNET_break (qs >= 0); // FIXME: handle DB failure more nicely? - } - - /* Count maximum number of remaining checks covered by any - provider */ - for (unsigned int i = 0; i<num_kyc_providers; i++) - { - const struct TEH_KycProvider *kp = kyc_providers[i]; - unsigned int matched = 0; - - for (unsigned int j = 0; j<kp->num_checks; j++) - { - const struct TEH_KycCheck *kc = kp->provided_checks[j]; - - for (unsigned int k = 0; k<needed_cnt; k++) - if (kc == needed[k]) - { - matched++; - break; - } - } - max_checks = GNUNET_MAX (max_checks, - matched); - } - - /* Find min-cost provider covering max_checks. */ - for (unsigned int i = 0; i<num_kyc_providers; i++) - { - const struct TEH_KycProvider *kp = kyc_providers[i]; - unsigned int matched = 0; - - for (unsigned int j = 0; j<kp->num_checks; j++) - { - const struct TEH_KycCheck *kc = kp->provided_checks[j]; - - for (unsigned int k = 0; k<needed_cnt; k++) - if (kc == needed[k]) - { - matched++; - break; - } - } - if ( (max_checks == matched) && - (kp->cost < min_cost) ) - { - min_cost = kp->cost; - kp_best = kp; - } - } - - GNUNET_assert (NULL != kp_best); - return kp_best->provider_section_name; -} - - -enum GNUNET_GenericReturnValue -TEH_kyc_get_logic (const char *provider_section_name, - struct TALER_KYCLOGIC_Plugin **plugin, - struct TALER_KYCLOGIC_ProviderDetails **pd) -{ - for (unsigned int i = 0; i<num_kyc_providers; i++) - { - struct TEH_KycProvider *kp = kyc_providers[i]; - - if (0 != - strcasecmp (provider_section_name, - kp->provider_section_name)) - continue; - *plugin = kp->logic; - *pd = kp->pd; - return GNUNET_OK; - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Provider `%s' unknown\n", - provider_section_name); - return GNUNET_SYSERR; -} - - -/* end of taler-exchange-httpd_kyc.c */ |