merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

taler-merchant-kyccheck.c (45707B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2024 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 taler-merchant-kyccheck.c
     18  * @brief Process that check the KYC status of our bank accounts at all exchanges
     19  * @author Christian Grothoff
     20  */
     21 #include "taler/platform.h"
     22 #include "microhttpd.h"
     23 #include <gnunet/gnunet_util_lib.h>
     24 #include <jansson.h>
     25 #include <pthread.h>
     26 #include <regex.h>
     27 #include <taler/taler_dbevents.h>
     28 #include <taler/taler_json_lib.h>
     29 #include <taler/taler_exchange_service.h>
     30 #include "taler/taler_merchant_util.h"
     31 #include "taler/taler_merchant_bank_lib.h"
     32 #include "taler/taler_merchantdb_lib.h"
     33 #include "taler/taler_merchantdb_plugin.h"
     34 
     35 /**
     36  * Timeout for the exchange interaction.  Rather long as we should do
     37  * long-polling and do not want to wake up too often.
     38  */
     39 #define EXCHANGE_TIMEOUT GNUNET_TIME_relative_multiply ( \
     40           GNUNET_TIME_UNIT_MINUTES, \
     41           30)
     42 
     43 /**
     44  * How long do we wait between requests if all we wait
     45  * for is a change in the AML investigation status?
     46  * Default value.
     47  */
     48 #define AML_FREQ GNUNET_TIME_relative_multiply ( \
     49           GNUNET_TIME_UNIT_HOURS, \
     50           6)
     51 
     52 /**
     53  * How long do we wait between requests if all we wait
     54  * for is a change in the AML investigation status?
     55  */
     56 static struct GNUNET_TIME_Relative aml_freq;
     57 
     58 /**
     59  * How frequently do we check for updates to our KYC status
     60  * if there is no actual reason to check? Set to a very low
     61  * frequency, just to ensure we eventually notice.
     62  * Default value.
     63  */
     64 #define AML_LOW_FREQ GNUNET_TIME_relative_multiply ( \
     65           GNUNET_TIME_UNIT_DAYS, \
     66           7)
     67 
     68 /**
     69  * How frequently do we check for updates to our KYC status
     70  * if there is no actual reason to check? Set to a very low
     71  * frequency, just to ensure we eventually notice.
     72  */
     73 static struct GNUNET_TIME_Relative aml_low_freq;
     74 
     75 
     76 /**
     77  * How many inquiries do we process concurrently at most.
     78  */
     79 #define OPEN_INQUIRY_LIMIT 1024
     80 
     81 
     82 /**
     83  * Information about an exchange.
     84  */
     85 struct Exchange
     86 {
     87   /**
     88    * Kept in a DLL.
     89    */
     90   struct Exchange *next;
     91 
     92   /**
     93    * Kept in a DLL.
     94    */
     95   struct Exchange *prev;
     96 
     97   /**
     98    * The keys of this exchange
     99    */
    100   struct TALER_EXCHANGE_Keys *keys;
    101 
    102 };
    103 
    104 
    105 /**
    106  * Information about an Account.
    107  */
    108 struct Account
    109 {
    110   /**
    111    * Kept in a DLL.
    112    */
    113   struct Account *next;
    114 
    115   /**
    116    * Kept in a DLL.
    117    */
    118   struct Account *prev;
    119 
    120   /**
    121    * Head of inquiries for this account.
    122    */
    123   struct Inquiry *i_head;
    124 
    125   /**
    126    * Tail of inquiries for this account.
    127    */
    128   struct Inquiry *i_tail;
    129 
    130   /**
    131    * Merchant instance this account belongs to.
    132    */
    133   char *instance_id;
    134 
    135   /**
    136    * The payto-URI of this account.
    137    */
    138   struct TALER_FullPayto merchant_account_uri;
    139 
    140   /**
    141    * Wire hash of the merchant bank account (with the
    142    * respective salt).
    143    */
    144   struct TALER_MerchantWireHashP h_wire;
    145 
    146   /**
    147    * Private key of the instance.
    148    */
    149   union TALER_AccountPrivateKeyP ap;
    150 
    151   /**
    152    * Hash of the @e merchant_account_uri.
    153    */
    154   struct TALER_NormalizedPaytoHashP h_payto;
    155 
    156   /**
    157    * Database generation when this account
    158    * was last active.
    159    */
    160   uint64_t account_gen;
    161 
    162 };
    163 
    164 
    165 /**
    166  * Information about an inquiry job.
    167  */
    168 struct Inquiry
    169 {
    170   /**
    171    * Kept in a DLL.
    172    */
    173   struct Inquiry *next;
    174 
    175   /**
    176    * Kept in a DLL.
    177    */
    178   struct Inquiry *prev;
    179 
    180   /**
    181    * Main task for this inquiry.
    182    */
    183   struct GNUNET_SCHEDULER_Task *task;
    184 
    185   /**
    186    * Which exchange is this inquiry about.
    187    */
    188   struct Exchange *e;
    189 
    190   /**
    191    * Which account is this inquiry about.
    192    */
    193   struct Account *a;
    194 
    195   /**
    196    * AccountLimits that apply to the account, NULL
    197    * if unknown.
    198    */
    199   json_t *jlimits;
    200 
    201   /**
    202    * Handle for the actual HTTP request to the exchange.
    203    */
    204   struct TALER_EXCHANGE_GetKycCheckHandle *kyc;
    205 
    206   /**
    207    * Access token for the /kyc-info API.
    208    */
    209   struct TALER_AccountAccessTokenP access_token;
    210 
    211   /**
    212    * Last time we called the /kyc-check endpoint.
    213    */
    214   struct GNUNET_TIME_Timestamp last_kyc_check;
    215 
    216   /**
    217    * When is the next KYC check due?
    218    */
    219   struct GNUNET_TIME_Absolute due;
    220 
    221   /**
    222    * When should the current KYC time out?
    223    */
    224   struct GNUNET_TIME_Absolute timeout;
    225 
    226   /**
    227    * Current exponential backoff.
    228    */
    229   struct GNUNET_TIME_Relative backoff;
    230 
    231   /**
    232    * Rule generation known to the client, 0 for none.
    233    * Corresponds to the decision row in the exchange.
    234    */
    235   uint64_t rule_gen;
    236 
    237   /**
    238    * Last HTTP status returned by the exchange from
    239    * the /kyc-check endpoint.
    240    */
    241   unsigned int last_http_status;
    242 
    243   /**
    244    * Last Taler error code returned by the exchange from
    245    * the /kyc-check endpoint.
    246    */
    247   enum TALER_ErrorCode last_ec;
    248 
    249   /**
    250    * True if this is not our first time we make this request.
    251    */
    252   bool not_first_time;
    253 
    254   /**
    255    * Do soft limits on transactions apply to this merchant for operations
    256    * merchants care about? If so, we should increase our request frequency
    257    * and ask more often to see if they were lifted.
    258    */
    259   bool zero_limited;
    260 
    261   /**
    262    * Did we not run this inquiry due to limits?
    263    */
    264   bool limited;
    265 
    266   /**
    267    * Do we believe this account's KYC is in good shape?
    268    */
    269   bool kyc_ok;
    270 
    271   /**
    272    * True if merchant did perform this account's KYC AUTH transfer and @e access_token is set.
    273    */
    274   bool auth_ok;
    275 
    276   /**
    277    * True if the account is known to be currently under
    278    * investigation by AML staff.
    279    */
    280   bool aml_review;
    281 
    282 };
    283 
    284 
    285 /**
    286  * Head of known exchanges.
    287  */
    288 static struct Exchange *e_head;
    289 
    290 /**
    291  * Tail of known exchanges.
    292  */
    293 static struct Exchange *e_tail;
    294 
    295 /**
    296  * Head of accounts.
    297  */
    298 static struct Account *a_head;
    299 
    300 /**
    301  * Tail of accounts.
    302  */
    303 static struct Account *a_tail;
    304 
    305 /**
    306  * The merchant's configuration.
    307  */
    308 static const struct GNUNET_CONFIGURATION_Handle *cfg;
    309 
    310 /**
    311  * Our database plugin.
    312  */
    313 static struct TALER_MERCHANTDB_Plugin *db_plugin;
    314 
    315 /**
    316  * Handle to the context for interacting with the bank.
    317  */
    318 static struct GNUNET_CURL_Context *ctx;
    319 
    320 /**
    321  * Scheduler context for running the @e ctx.
    322  */
    323 static struct GNUNET_CURL_RescheduleContext *rc;
    324 
    325 /**
    326  * Event handler to learn that there may be new bank
    327  * accounts to check.
    328  */
    329 static struct GNUNET_DB_EventHandler *eh_accounts;
    330 
    331 /**
    332  * Event handler to learn that there may be new exchange
    333  * keys to check.
    334  */
    335 static struct GNUNET_DB_EventHandler *eh_keys;
    336 
    337 /**
    338  * Event handler to learn that there was a KYC
    339  * rule triggered and we need to check the KYC
    340  * status for an account.
    341  */
    342 static struct GNUNET_DB_EventHandler *eh_rule;
    343 
    344 /**
    345  * Event handler to learn that higher-frequency KYC
    346  * checks were forced by an application actively inspecting
    347  * some KYC status values.
    348  */
    349 static struct GNUNET_DB_EventHandler *eh_update_forced;
    350 
    351 /**
    352  * Event handler to learn that we got new /keys
    353  * from an exchange and should reconsider eligibility.
    354  */
    355 static struct GNUNET_DB_EventHandler *keys_rule;
    356 
    357 /**
    358  * Main task to discover (new) accounts.
    359  */
    360 static struct GNUNET_SCHEDULER_Task *account_task;
    361 
    362 /**
    363  * Counter determining how often we have called
    364  * "select_accounts" on the database.
    365  */
    366 static uint64_t database_gen;
    367 
    368 /**
    369  * How many active inquiries do we have right now.
    370  */
    371 static unsigned int active_inquiries;
    372 
    373 /**
    374  * Value to return from main(). 0 on success, non-zero on errors.
    375  */
    376 static int global_ret;
    377 
    378 /**
    379  * #GNUNET_YES if we are in test mode and should exit when idle.
    380  */
    381 static int test_mode;
    382 
    383 /**
    384  * True if the last DB query was limited by the
    385  * #OPEN_INQUIRY_LIMIT and we thus should check again
    386  * as soon as we are substantially below that limit,
    387  * and not only when we get a DB notification.
    388  */
    389 static bool at_limit;
    390 
    391 
    392 /**
    393  * Check about performing a /kyc-check request with the
    394  * exchange for the given inquiry.
    395  *
    396  * @param cls a `struct Inquiry` to process
    397  */
    398 static void
    399 inquiry_work (void *cls);
    400 
    401 
    402 /**
    403  * An inquiry finished, check if we should resume others.
    404  */
    405 static void
    406 end_inquiry (void)
    407 {
    408   GNUNET_assert (active_inquiries > 0);
    409   active_inquiries--;
    410   if ( (active_inquiries < OPEN_INQUIRY_LIMIT / 2) &&
    411        (at_limit) )
    412   {
    413     at_limit = false;
    414     for (struct Account *a = a_head;
    415          NULL != a;
    416          a = a->next)
    417     {
    418       for (struct Inquiry *i = a->i_head;
    419            NULL != i;
    420            i = i->next)
    421       {
    422         if (! i->limited)
    423           continue;
    424         GNUNET_assert (NULL == i->task);
    425         /* done synchronously so that the active_inquiries
    426            is updated immediately */
    427         inquiry_work (i);
    428         if (at_limit)
    429           break;
    430       }
    431       if (at_limit)
    432         break;
    433     }
    434   }
    435   if ( (! at_limit) &&
    436        (0 == active_inquiries) &&
    437        (test_mode) )
    438   {
    439     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    440                 "No more open inquiries and in test mode. Existing.\n");
    441     GNUNET_SCHEDULER_shutdown ();
    442     return;
    443   }
    444 }
    445 
    446 
    447 /**
    448  * Pack the given @a limit into the JSON @a limits array.
    449  *
    450  * @param limit account limit to pack
    451  * @param[in,out] limits JSON array to extend
    452  */
    453 static void
    454 pack_limit (const struct TALER_EXCHANGE_AccountLimit *limit,
    455             json_t *limits)
    456 {
    457   json_t *jl;
    458 
    459   jl = GNUNET_JSON_PACK (
    460     TALER_JSON_pack_kycte ("operation_type",
    461                            limit->operation_type),
    462     GNUNET_JSON_pack_time_rel ("timeframe",
    463                                limit->timeframe),
    464     TALER_JSON_pack_amount ("threshold",
    465                             &limit->threshold),
    466     GNUNET_JSON_pack_bool ("soft_limit",
    467                            limit->soft_limit)
    468     );
    469   GNUNET_assert (0 ==
    470                  json_array_append_new (limits,
    471                                         jl));
    472 }
    473 
    474 
    475 /**
    476  * Update KYC status for @a i based on
    477  * @a account_kyc_status
    478  *
    479  * @param[in,out] i inquiry context, jlimits is updated
    480  * @param account_kyc_status account KYC status details
    481  */
    482 static void
    483 store_kyc_status (
    484   struct Inquiry *i,
    485   const struct TALER_EXCHANGE_AccountKycStatus *account_kyc_status)
    486 {
    487   json_t *jlimits;
    488 
    489   json_decref (i->jlimits);
    490   jlimits = json_array ();
    491   GNUNET_assert (NULL != jlimits);
    492   i->zero_limited = false;
    493   for (unsigned int j = 0; j<account_kyc_status->limits_length; j++)
    494   {
    495     const struct TALER_EXCHANGE_AccountLimit *limit
    496       = &account_kyc_status->limits[j];
    497 
    498     pack_limit (limit,
    499                 jlimits);
    500     if (TALER_amount_is_zero (&limit->threshold) &&
    501         limit->soft_limit &&
    502         ( (TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT == limit->operation_type) ||
    503           (TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE == limit->operation_type) ||
    504           (TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION == limit->operation_type) ) )
    505     {
    506       i->zero_limited = true;
    507     }
    508   }
    509   i->jlimits = jlimits;
    510   GNUNET_break (! GNUNET_is_zero (&account_kyc_status->access_token));
    511   i->access_token = account_kyc_status->access_token;
    512   i->auth_ok = true;
    513   i->aml_review = account_kyc_status->aml_review;
    514   i->kyc_ok = (MHD_HTTP_OK == i->last_http_status);
    515 }
    516 
    517 
    518 /**
    519  * Function called with the result of a KYC check.
    520  *
    521  * @param cls a `struct Inquiry *`
    522  * @param ks the account's KYC status details
    523  */
    524 static void
    525 exchange_check_cb (
    526   void *cls,
    527   const struct TALER_EXCHANGE_GetKycCheckResponse *ks)
    528 {
    529   struct Inquiry *i = cls;
    530   bool progress = false;
    531 
    532   i->kyc = NULL;
    533   if (! i->not_first_time)
    534     progress = true;
    535   if (i->last_http_status != ks->hr.http_status)
    536     progress = true;
    537   i->last_http_status = ks->hr.http_status;
    538   i->last_ec = ks->hr.ec;
    539   i->rule_gen = 0;
    540   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    541               "KYC status of `%s' at `%s' is %u\n",
    542               i->a->merchant_account_uri.full_payto,
    543               i->e->keys->exchange_url,
    544               ks->hr.http_status);
    545   switch (ks->hr.http_status)
    546   {
    547   case MHD_HTTP_OK:
    548     if (! i->kyc_ok)
    549       progress = true;
    550     if (i->rule_gen != ks->details.ok.rule_gen)
    551       progress = true;
    552     i->rule_gen = ks->details.ok.rule_gen;
    553     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    554     /* exchange says KYC is OK, gives status information */
    555     store_kyc_status (i,
    556                       &ks->details.ok);
    557     i->backoff = GNUNET_TIME_UNIT_MINUTES;
    558     if (i->aml_review || i->zero_limited)
    559     {
    560       if (! progress)
    561         i->due = GNUNET_TIME_relative_to_absolute (
    562           GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_freq,
    563                                                            i->backoff)));
    564     }
    565     else
    566     {
    567       /* KYC is OK, only check again if triggered */
    568       if (! progress)
    569         i->due = GNUNET_TIME_relative_to_absolute (
    570           GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_low_freq,
    571                                                            i->backoff)));
    572     }
    573     break;
    574   case MHD_HTTP_ACCEPTED:
    575     progress = ! i->auth_ok;
    576     if (i->rule_gen != ks->details.accepted.rule_gen)
    577       progress = true;
    578     i->rule_gen = ks->details.accepted.rule_gen;
    579     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    580 
    581     /* exchange says KYC is required */
    582     store_kyc_status (i,
    583                       &ks->details.accepted);
    584     i->backoff = GNUNET_TIME_UNIT_MINUTES;
    585     /* Start immediately with long-polling */
    586     if (! progress)
    587       i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time,
    588                                          i->timeout);
    589     break;
    590   case MHD_HTTP_NO_CONTENT:
    591     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    592     i->backoff = GNUNET_TIME_UNIT_MINUTES;
    593     /* exchange claims KYC is off! */
    594     i->kyc_ok = true;
    595     i->aml_review = false;
    596     /* Clear limits, in case exchange had KYC on previously */
    597     json_decref (i->jlimits);
    598     i->jlimits = NULL;
    599     /* KYC is OK, only check again if triggered */
    600     i->due = GNUNET_TIME_relative_to_absolute (
    601       GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_low_freq,
    602                                                        i->backoff)));
    603     break;
    604   case MHD_HTTP_FORBIDDEN: /* bad signature */
    605     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    606     /* Forbidden => KYC auth must be wrong */
    607     i->auth_ok = false;
    608     /* Start with long-polling */
    609     if (! progress)
    610       i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time,
    611                                          i->timeout);
    612     i->backoff = GNUNET_TIME_UNIT_MINUTES;
    613     break;
    614   case MHD_HTTP_NOT_FOUND: /* account unknown */
    615     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    616     /* Account unknown => no KYC auth yet */
    617     i->auth_ok = false;
    618     /* unknown account => wire transfer required! */
    619     i->kyc_ok = false;
    620     /* There should not be any limits yet, but clear them
    621        just in case the exchange has amnesia */
    622     json_decref (i->jlimits);
    623     i->jlimits = NULL;
    624     /* Start immediately with Long-polling */
    625     if (! progress)
    626       i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time,
    627                                          i->timeout);
    628     i->backoff = GNUNET_TIME_UNIT_MINUTES;
    629     break;
    630   case MHD_HTTP_CONFLICT: /* no account_pub known */
    631     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    632     /* Conflict => KYC auth wire transfer missing! */
    633     i->auth_ok = false;
    634     /* Start immediately with Long-polling */
    635     if (! progress)
    636       i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time,
    637                                          i->timeout);
    638     i->backoff = GNUNET_TIME_UNIT_MINUTES;
    639     break;
    640   default:
    641     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    642                 "Exchange responded with HTTP status %u (%d) to /kyc-check request!\n",
    643                 ks->hr.http_status,
    644                 ks->hr.ec);
    645     i->backoff
    646       = GNUNET_TIME_randomized_backoff (i->backoff,
    647                                         EXCHANGE_TIMEOUT);
    648     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    649     i->due = GNUNET_TIME_relative_to_absolute (i->backoff);
    650     i->auth_ok = false;
    651     break;
    652   }
    653 
    654   {
    655     enum GNUNET_DB_QueryStatus qs;
    656 
    657     qs = db_plugin->account_kyc_set_status (
    658       db_plugin->cls,
    659       i->a->instance_id,
    660       &i->a->h_wire,
    661       i->e->keys->exchange_url,
    662       i->last_kyc_check,
    663       i->due,
    664       i->backoff,
    665       i->last_http_status,
    666       i->last_ec,
    667       i->rule_gen,
    668       (i->auth_ok)
    669       ? &i->access_token
    670       : NULL,
    671       i->jlimits,
    672       i->aml_review,
    673       i->kyc_ok);
    674     if (qs < 0)
    675     {
    676       GNUNET_break (0);
    677       global_ret = EXIT_FAILURE;
    678       GNUNET_SCHEDULER_shutdown ();
    679       return;
    680     }
    681     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    682                 "account_kyc_set_status (%s, %u, %s, %s) returned %d\n",
    683                 i->e->keys->exchange_url,
    684                 i->last_http_status,
    685                 i->auth_ok ? "auth OK" : "auth needed",
    686                 NULL == i->jlimits ? "default limits" : "custom limits",
    687                 (int) qs);
    688     i->not_first_time = true;
    689   }
    690   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    691               "Will repeat inquiry in %s\n",
    692               GNUNET_TIME_relative2s (
    693                 GNUNET_TIME_absolute_get_remaining (i->due),
    694                 true));
    695   if (! GNUNET_TIME_absolute_is_never (i->due))
    696     i->task = GNUNET_SCHEDULER_add_at (i->due,
    697                                        &inquiry_work,
    698                                        i);
    699   end_inquiry ();
    700 }
    701 
    702 
    703 static void
    704 inquiry_work (void *cls)
    705 {
    706   struct Inquiry *i = cls;
    707   enum TALER_EXCHANGE_KycLongPollTarget lpt;
    708 
    709   i->task = NULL;
    710   if (! GNUNET_TIME_absolute_is_past (i->due))
    711   {
    712     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    713                 "Will start inquiry on %s for %s in %s\n",
    714                 i->a->merchant_account_uri.full_payto,
    715                 i->e->keys->exchange_url,
    716                 GNUNET_TIME_relative2s (
    717                   GNUNET_TIME_absolute_get_remaining (i->due),
    718                   true));
    719     i->task
    720       = GNUNET_SCHEDULER_add_at (i->due,
    721                                  &inquiry_work,
    722                                  i);
    723     goto finish;
    724   }
    725 
    726   GNUNET_assert (OPEN_INQUIRY_LIMIT >= active_inquiries);
    727   if (OPEN_INQUIRY_LIMIT <= active_inquiries)
    728   {
    729     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    730                 "Not looking for work: at limit\n");
    731     i->limited = true;
    732     at_limit = true;
    733     return;
    734   }
    735   at_limit = false;
    736   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    737               "Starting KYC status of `%s' at `%s'\n",
    738               i->a->merchant_account_uri.full_payto,
    739               i->e->keys->exchange_url);
    740   i->timeout
    741     = GNUNET_TIME_relative_to_absolute (EXCHANGE_TIMEOUT);
    742   lpt = TALER_EXCHANGE_KLPT_NONE;
    743   if (! i->auth_ok)
    744     lpt = TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER;
    745   else if (! i->kyc_ok)
    746     lpt = TALER_EXCHANGE_KLPT_KYC_OK;
    747   else if (i->aml_review)
    748     lpt = TALER_EXCHANGE_KLPT_INVESTIGATION_DONE;
    749   if (! i->not_first_time)
    750     lpt = TALER_EXCHANGE_KLPT_NONE;
    751   i->kyc = TALER_EXCHANGE_get_kyc_check_create (
    752     ctx,
    753     i->e->keys->exchange_url,
    754     &i->a->h_payto,
    755     &i->a->ap);
    756   if (NULL == i->kyc)
    757   {
    758     GNUNET_break (0);
    759     i->due = i->timeout;
    760     i->task
    761       = GNUNET_SCHEDULER_add_at (i->due,
    762                                  &inquiry_work,
    763                                  i);
    764     goto finish;
    765   }
    766   GNUNET_assert (GNUNET_OK ==
    767                  TALER_EXCHANGE_get_kyc_check_set_options (
    768                    i->kyc,
    769                    TALER_EXCHANGE_get_kyc_check_option_known_rule_gen (
    770                      i->rule_gen),
    771                    TALER_EXCHANGE_get_kyc_check_option_lpt (lpt),
    772                    TALER_EXCHANGE_get_kyc_check_option_timeout (
    773                      i->not_first_time && (! test_mode)
    774                      ? EXCHANGE_TIMEOUT
    775                      : GNUNET_TIME_UNIT_ZERO)));
    776   GNUNET_assert (TALER_EC_NONE ==
    777                  TALER_EXCHANGE_get_kyc_check_start (i->kyc,
    778                                                      &exchange_check_cb,
    779                                                      i));
    780   active_inquiries++;
    781 finish:
    782   if ( (0 == active_inquiries) &&
    783        (test_mode) )
    784   {
    785     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    786                 "No more open inquiries and in test mode. Existing.\n");
    787     GNUNET_SCHEDULER_shutdown ();
    788     return;
    789   }
    790 }
    791 
    792 
    793 /**
    794  * Check if the account @a could work with exchange that
    795  * has keys @a keys.
    796  *
    797  * @param keys the keys of an exchange
    798  * @param a an account
    799  */
    800 static bool
    801 is_eligible (const struct TALER_EXCHANGE_Keys *keys,
    802              const struct Account *a)
    803 {
    804   struct TALER_NormalizedPayto np;
    805   bool ret;
    806 
    807   np = TALER_payto_normalize (a->merchant_account_uri);
    808   ret = TALER_EXCHANGE_keys_test_account_allowed (keys,
    809                                                   true,
    810                                                   np);
    811   GNUNET_free (np.normalized_payto);
    812   return ret;
    813 }
    814 
    815 
    816 /**
    817  * Start the KYC checking for account @a at exchange @a e.
    818  *
    819  * @param e an exchange
    820  * @param a an account
    821  */
    822 static void
    823 start_inquiry (struct Exchange *e,
    824                struct Account *a)
    825 {
    826   struct Inquiry *i;
    827   enum GNUNET_DB_QueryStatus qs;
    828 
    829   i = GNUNET_new (struct Inquiry);
    830   i->e = e;
    831   i->a = a;
    832   GNUNET_CONTAINER_DLL_insert (a->i_head,
    833                                a->i_tail,
    834                                i);
    835   qs = db_plugin->get_kyc_status (db_plugin->cls,
    836                                   a->merchant_account_uri,
    837                                   a->instance_id,
    838                                   e->keys->exchange_url,
    839                                   &i->auth_ok,
    840                                   &i->access_token,
    841                                   &i->kyc_ok,
    842                                   &i->last_http_status,
    843                                   &i->last_ec,
    844                                   &i->rule_gen,
    845                                   &i->last_kyc_check,
    846                                   &i->due,
    847                                   &i->backoff,
    848                                   &i->aml_review,
    849                                   &i->jlimits);
    850   if (qs < 0)
    851   {
    852     GNUNET_break (0);
    853     global_ret = EXIT_FAILURE;
    854     GNUNET_SCHEDULER_shutdown ();
    855     return;
    856   }
    857   if (qs > 0)
    858     i->not_first_time = true;
    859   if (GNUNET_YES == test_mode)
    860     i->due = GNUNET_TIME_UNIT_ZERO_ABS; /* immediately */
    861   inquiry_work (i);
    862 }
    863 
    864 
    865 /**
    866  * Stop KYC inquiry @a i.
    867  *
    868  * @param[in] i the inquiry to stop
    869  */
    870 static void
    871 stop_inquiry (struct Inquiry *i)
    872 {
    873   struct Account *a = i->a;
    874 
    875   GNUNET_CONTAINER_DLL_remove (a->i_head,
    876                                a->i_tail,
    877                                i);
    878   if (NULL != i->task)
    879   {
    880     GNUNET_SCHEDULER_cancel (i->task);
    881     i->task = NULL;
    882   }
    883   if (NULL != i->kyc)
    884   {
    885     TALER_EXCHANGE_get_kyc_check_cancel (i->kyc);
    886     i->kyc = NULL;
    887   }
    888   if (NULL != i->jlimits)
    889   {
    890     json_decref (i->jlimits);
    891     i->jlimits = NULL;
    892   }
    893   GNUNET_free (i);
    894 }
    895 
    896 
    897 /**
    898  * Stop KYC inquiry for account @a at exchange @a e.
    899  *
    900  * @param e an exchange
    901  * @param a an account
    902  */
    903 static void
    904 stop_inquiry_at (struct Exchange *e,
    905                  struct Account *a)
    906 {
    907   for (struct Inquiry *i = a->i_head;
    908        NULL != i;
    909        i = i->next)
    910   {
    911     if (e == i->e)
    912     {
    913       stop_inquiry (i);
    914       return;
    915     }
    916   }
    917   /* strange, there should have been a match! */
    918   GNUNET_break (0);
    919 }
    920 
    921 
    922 /**
    923  * Set the account @a h_wire of @a instance_id to be ineligible
    924  * for the exchange at @a exchange_url and thus no need to do KYC checks.
    925  *
    926  * @param instance_id instance that has the account
    927  * @param exchange_url base URL of the exchange
    928  * @param h_wire hash of the merchant bank account that is ineligible
    929  */
    930 static void
    931 flag_ineligible (const char *instance_id,
    932                  const char *exchange_url,
    933                  const struct TALER_MerchantWireHashP *h_wire)
    934 {
    935   enum GNUNET_DB_QueryStatus qs;
    936 
    937   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    938               "Account %s not eligible at exchange %s\n",
    939               TALER_B2S (h_wire),
    940               exchange_url);
    941   qs = db_plugin->account_kyc_set_status (
    942     db_plugin->cls,
    943     instance_id,
    944     h_wire,
    945     exchange_url,
    946     GNUNET_TIME_timestamp_get (),
    947     GNUNET_TIME_UNIT_FOREVER_ABS,
    948     GNUNET_TIME_UNIT_FOREVER_REL,
    949     0,
    950     TALER_EC_MERCHANT_PRIVATE_ACCOUNT_NOT_ELIGIBLE_FOR_EXCHANGE,
    951     0,
    952     NULL,
    953     NULL,
    954     false,
    955     false);
    956   if (qs < 0)
    957   {
    958     GNUNET_break (0);
    959     global_ret = EXIT_FAILURE;
    960     GNUNET_SCHEDULER_shutdown ();
    961     return;
    962   }
    963   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    964               "account_kyc_set_status (%s) returned %d\n",
    965               exchange_url,
    966               (int) qs);
    967 }
    968 
    969 
    970 /**
    971  * Start inquries for all exchanges on account @a a.
    972  *
    973  * @param a an account
    974  */
    975 static void
    976 start_inquiries (struct Account *a)
    977 {
    978   for (struct Exchange *e = e_head;
    979        NULL != e;
    980        e = e->next)
    981   {
    982     if (is_eligible (e->keys,
    983                      a))
    984     {
    985       start_inquiry (e,
    986                      a);
    987     }
    988     else
    989     {
    990       flag_ineligible (a->instance_id,
    991                        e->keys->exchange_url,
    992                        &a->h_wire);
    993     }
    994   }
    995 }
    996 
    997 
    998 /**
    999  * Stop all inquries involving account @a a.
   1000  *
   1001  * @param a an account
   1002  */
   1003 static void
   1004 stop_inquiries (struct Account *a)
   1005 {
   1006   struct Inquiry *i;
   1007 
   1008   while (NULL != (i = a->i_head))
   1009     stop_inquiry (i);
   1010 }
   1011 
   1012 
   1013 /**
   1014  * Callback invoked with information about a bank account.
   1015  *
   1016  * @param cls closure
   1017  * @param merchant_priv private key of the merchant instance
   1018  * @param ad details about the account
   1019  */
   1020 static void
   1021 account_cb (
   1022   void *cls,
   1023   const struct TALER_MerchantPrivateKeyP *merchant_priv,
   1024   const struct TALER_MERCHANTDB_AccountDetails *ad)
   1025 {
   1026   struct TALER_FullPayto payto_uri = ad->payto_uri;
   1027 
   1028   if (! ad->active)
   1029     return;
   1030   if (NULL == merchant_priv)
   1031     return; /* instance was deleted */
   1032   for (struct Account *a = a_head;
   1033        NULL != a;
   1034        a = a->next)
   1035   {
   1036     if (0 ==
   1037         TALER_full_payto_cmp (payto_uri,
   1038                               a->merchant_account_uri))
   1039     {
   1040       a->account_gen = database_gen;
   1041       return;
   1042     }
   1043   }
   1044   {
   1045     struct Account *a = GNUNET_new (struct Account);
   1046 
   1047     a->account_gen = database_gen;
   1048     a->merchant_account_uri.full_payto
   1049       = GNUNET_strdup (ad->payto_uri.full_payto);
   1050     a->instance_id
   1051       = GNUNET_strdup (ad->instance_id);
   1052     a->h_wire
   1053       = ad->h_wire;
   1054     a->ap.merchant_priv
   1055       = *merchant_priv;
   1056     TALER_full_payto_normalize_and_hash (a->merchant_account_uri,
   1057                                          &a->h_payto);
   1058     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1059                 "Found account %s of instance %s with H_PAYTO %s\n",
   1060                 ad->payto_uri.full_payto,
   1061                 ad->instance_id,
   1062                 GNUNET_sh2s (&a->h_payto.hash));
   1063     GNUNET_CONTAINER_DLL_insert (a_head,
   1064                                  a_tail,
   1065                                  a);
   1066     start_inquiries (a);
   1067   }
   1068 }
   1069 
   1070 
   1071 /**
   1072  * The set of bank accounts has changed, update our
   1073  * list of active inquiries.
   1074  *
   1075  * @param cls unused
   1076  */
   1077 static void
   1078 find_accounts (void *cls)
   1079 {
   1080   enum GNUNET_DB_QueryStatus qs;
   1081 
   1082   (void) cls;
   1083   account_task = NULL;
   1084   database_gen++;
   1085   qs = db_plugin->select_accounts (db_plugin->cls,
   1086                                    NULL, /* all instances */
   1087                                    &account_cb,
   1088                                    NULL);
   1089   if (qs < 0)
   1090   {
   1091     GNUNET_break (0);
   1092     global_ret = EXIT_FAILURE;
   1093     GNUNET_SCHEDULER_shutdown ();
   1094     return;
   1095   }
   1096   for (struct Account *a = a_head;
   1097        NULL != a;
   1098        a = a->next)
   1099   {
   1100     if (a->account_gen < database_gen)
   1101       stop_inquiries (a);
   1102   }
   1103   if ( (! at_limit) &&
   1104        (0 == active_inquiries) &&
   1105        (test_mode) )
   1106   {
   1107     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1108                 "No more open inquiries and in test mode. Existing.\n");
   1109     GNUNET_SCHEDULER_shutdown ();
   1110     return;
   1111   }
   1112 }
   1113 
   1114 
   1115 /**
   1116  * Function called when transfers are added to the merchant database.  We look
   1117  * for more work.
   1118  *
   1119  * @param cls closure (NULL)
   1120  * @param extra additional event data provided
   1121  * @param extra_size number of bytes in @a extra
   1122  */
   1123 static void
   1124 account_changed (void *cls,
   1125                  const void *extra,
   1126                  size_t extra_size)
   1127 {
   1128   (void) cls;
   1129   (void) extra;
   1130   (void) extra_size;
   1131   if (NULL != account_task)
   1132     return;
   1133   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1134               "Received account change notification: reloading accounts\n");
   1135   account_task
   1136     = GNUNET_SCHEDULER_add_now (&find_accounts,
   1137                                 NULL);
   1138 }
   1139 
   1140 
   1141 /**
   1142  * Interact with the database to get the current set
   1143  * of exchange keys known to us.
   1144  *
   1145  * @param exchange_url the exchange URL to check
   1146  */
   1147 static void
   1148 find_keys (const char *exchange_url)
   1149 {
   1150   enum GNUNET_DB_QueryStatus qs;
   1151   struct TALER_EXCHANGE_Keys *keys;
   1152   struct Exchange *e;
   1153   struct GNUNET_TIME_Absolute first_retry;
   1154 
   1155   qs = db_plugin->select_exchange_keys (db_plugin->cls,
   1156                                         exchange_url,
   1157                                         &first_retry,
   1158                                         &keys);
   1159   if (qs < 0)
   1160   {
   1161     GNUNET_break (0);
   1162     global_ret = EXIT_FAILURE;
   1163     GNUNET_SCHEDULER_shutdown ();
   1164     return;
   1165   }
   1166   if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) ||
   1167        (NULL == keys) )
   1168   {
   1169     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1170                 "No %s/keys yet!\n",
   1171                 exchange_url);
   1172     return;
   1173   }
   1174   for (e = e_head; NULL != e; e = e->next)
   1175   {
   1176     if (0 == strcmp (e->keys->exchange_url,
   1177                      keys->exchange_url))
   1178     {
   1179       struct TALER_EXCHANGE_Keys *old_keys = e->keys;
   1180 
   1181       e->keys = keys;
   1182       for (struct Account *a = a_head;
   1183            NULL != a;
   1184            a = a->next)
   1185       {
   1186         bool was_eligible = is_eligible (old_keys,
   1187                                          a);
   1188         bool now_eligible = is_eligible (keys,
   1189                                          a);
   1190 
   1191         if (was_eligible == now_eligible)
   1192           continue; /* no change, do nothing */
   1193         if (was_eligible)
   1194           stop_inquiry_at (e,
   1195                            a);
   1196         else /* is_eligible */
   1197           start_inquiry (e,
   1198                          a);
   1199       }
   1200       TALER_EXCHANGE_keys_decref (old_keys);
   1201       return;
   1202     }
   1203   }
   1204   e = GNUNET_new (struct Exchange);
   1205   e->keys = keys;
   1206   GNUNET_CONTAINER_DLL_insert (e_head,
   1207                                e_tail,
   1208                                e);
   1209   for (struct Account *a = a_head;
   1210        NULL != a;
   1211        a = a->next)
   1212   {
   1213     if ( (a->account_gen == database_gen) &&
   1214          (is_eligible (e->keys,
   1215                        a)) )
   1216       start_inquiry (e,
   1217                      a);
   1218   }
   1219 }
   1220 
   1221 
   1222 /**
   1223  * Function called when keys were changed in the
   1224  * merchant database. Updates ours.
   1225  *
   1226  * @param cls closure (NULL)
   1227  * @param extra additional event data provided
   1228  * @param extra_size number of bytes in @a extra
   1229  */
   1230 static void
   1231 keys_changed (void *cls,
   1232               const void *extra,
   1233               size_t extra_size)
   1234 {
   1235   const char *url = extra;
   1236 
   1237   (void) cls;
   1238   if ( (NULL == extra) ||
   1239        (0 == extra_size) )
   1240   {
   1241     GNUNET_break (0);
   1242     global_ret = EXIT_FAILURE;
   1243     GNUNET_SCHEDULER_shutdown ();
   1244     return;
   1245   }
   1246   if ('\0' != url[extra_size - 1])
   1247   {
   1248     GNUNET_break (0);
   1249     global_ret = EXIT_FAILURE;
   1250     GNUNET_SCHEDULER_shutdown ();
   1251     return;
   1252   }
   1253   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1254               "Received keys change notification: reload `%s'\n",
   1255               url);
   1256   find_keys (url);
   1257 }
   1258 
   1259 
   1260 /**
   1261  * Function called when a KYC rule was triggered by
   1262  * a transaction and we need to get the latest KYC
   1263  * status immediately.
   1264  *
   1265  * @param cls closure (NULL)
   1266  * @param extra additional event data provided
   1267  * @param extra_size number of bytes in @a extra
   1268  */
   1269 static void
   1270 rule_triggered (void *cls,
   1271                 const void *extra,
   1272                 size_t extra_size)
   1273 {
   1274   const char *text = extra;
   1275   const char *space;
   1276   struct TALER_MerchantWireHashP h_wire;
   1277   const char *exchange_url;
   1278 
   1279   (void) cls;
   1280   if ( (NULL == extra) ||
   1281        (0 == extra_size) )
   1282   {
   1283     GNUNET_break (0);
   1284     global_ret = EXIT_FAILURE;
   1285     GNUNET_SCHEDULER_shutdown ();
   1286     return;
   1287   }
   1288   if ('\0' != text[extra_size - 1])
   1289   {
   1290     GNUNET_break (0);
   1291     global_ret = EXIT_FAILURE;
   1292     GNUNET_SCHEDULER_shutdown ();
   1293     return;
   1294   }
   1295   space = memchr (extra,
   1296                   ' ',
   1297                   extra_size);
   1298   if (NULL == space)
   1299   {
   1300     GNUNET_break (0);
   1301     global_ret = EXIT_FAILURE;
   1302     GNUNET_SCHEDULER_shutdown ();
   1303     return;
   1304   }
   1305   if (GNUNET_OK !=
   1306       GNUNET_STRINGS_string_to_data (extra,
   1307                                      space - text,
   1308                                      &h_wire,
   1309                                      sizeof (h_wire)))
   1310   {
   1311     GNUNET_break (0);
   1312     global_ret = EXIT_FAILURE;
   1313     GNUNET_SCHEDULER_shutdown ();
   1314     return;
   1315   }
   1316   exchange_url = &space[1];
   1317   if (! TALER_is_web_url (exchange_url))
   1318   {
   1319     GNUNET_break (0);
   1320     global_ret = EXIT_FAILURE;
   1321     GNUNET_SCHEDULER_shutdown ();
   1322     return;
   1323   }
   1324 
   1325   for (struct Account *a = a_head;
   1326        NULL != a;
   1327        a = a->next)
   1328   {
   1329     if (0 !=
   1330         GNUNET_memcmp (&h_wire,
   1331                        &a->h_wire))
   1332       continue;
   1333     for (struct Inquiry *i = a->i_head;
   1334          NULL != i;
   1335          i = i->next)
   1336     {
   1337       if (0 != strcmp (exchange_url,
   1338                        i->e->keys->exchange_url))
   1339         continue;
   1340       i->kyc_ok = false;
   1341       i->due = GNUNET_TIME_UNIT_ZERO_ABS;
   1342       if (NULL != i->task)
   1343       {
   1344         GNUNET_SCHEDULER_cancel (i->task);
   1345         i->task = NULL;
   1346       }
   1347       if (NULL != i->kyc)
   1348       {
   1349         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1350                     "/kyc-check already running for %s\n",
   1351                     text);
   1352         return;
   1353       }
   1354       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1355                   "Starting %skyc-check for `%s' due to KYC rule trigger\n",
   1356                   exchange_url,
   1357                   i->a->merchant_account_uri.full_payto);
   1358       i->task = GNUNET_SCHEDULER_add_at (i->due,
   1359                                          &inquiry_work,
   1360                                          i);
   1361       return;
   1362     }
   1363   }
   1364   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1365               "KYC rule trigger notification `%s' matches none of our accounts\n",
   1366               text);
   1367 }
   1368 
   1369 
   1370 /**
   1371  * Function called on each configuration section. Finds sections
   1372  * about exchanges, parses the entries.
   1373  *
   1374  * @param cls NULL
   1375  * @param section name of the section
   1376  */
   1377 static void
   1378 accept_exchanges (void *cls,
   1379                   const char *section)
   1380 {
   1381   char *url;
   1382 
   1383   (void) cls;
   1384   if (0 !=
   1385       strncasecmp (section,
   1386                    "merchant-exchange-",
   1387                    strlen ("merchant-exchange-")))
   1388     return;
   1389   if (GNUNET_YES ==
   1390       GNUNET_CONFIGURATION_get_value_yesno (cfg,
   1391                                             section,
   1392                                             "DISABLED"))
   1393     return;
   1394   if (GNUNET_OK !=
   1395       GNUNET_CONFIGURATION_get_value_string (cfg,
   1396                                              section,
   1397                                              "EXCHANGE_BASE_URL",
   1398                                              &url))
   1399   {
   1400     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   1401                                section,
   1402                                "EXCHANGE_BASE_URL");
   1403     global_ret = EXIT_NOTCONFIGURED;
   1404     GNUNET_SCHEDULER_shutdown ();
   1405     return;
   1406   }
   1407   find_keys (url);
   1408   GNUNET_free (url);
   1409 }
   1410 
   1411 
   1412 /**
   1413  * We're being aborted with CTRL-C (or SIGTERM). Shut down.
   1414  *
   1415  * @param cls closure (NULL)
   1416  */
   1417 static void
   1418 shutdown_task (void *cls)
   1419 {
   1420   (void) cls;
   1421   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1422               "Running shutdown\n");
   1423   while (NULL != e_head)
   1424   {
   1425     struct Exchange *e = e_head;
   1426 
   1427     if (NULL != e->keys)
   1428     {
   1429       TALER_EXCHANGE_keys_decref (e->keys);
   1430       e->keys = NULL;
   1431     }
   1432     GNUNET_CONTAINER_DLL_remove (e_head,
   1433                                  e_tail,
   1434                                  e);
   1435     GNUNET_free (e);
   1436   }
   1437   while (NULL != a_head)
   1438   {
   1439     struct Account *a = a_head;
   1440 
   1441     stop_inquiries (a);
   1442     GNUNET_CONTAINER_DLL_remove (a_head,
   1443                                  a_tail,
   1444                                  a);
   1445     GNUNET_free (a->merchant_account_uri.full_payto);
   1446     GNUNET_free (a->instance_id);
   1447     GNUNET_free (a);
   1448   }
   1449   if (NULL != eh_accounts)
   1450   {
   1451     db_plugin->event_listen_cancel (eh_accounts);
   1452     eh_accounts = NULL;
   1453   }
   1454   if (NULL != account_task)
   1455   {
   1456     GNUNET_SCHEDULER_cancel (account_task);
   1457     account_task = NULL;
   1458   }
   1459   if (NULL != eh_keys)
   1460   {
   1461     db_plugin->event_listen_cancel (eh_keys);
   1462     eh_keys = NULL;
   1463   }
   1464   if (NULL != eh_rule)
   1465   {
   1466     db_plugin->event_listen_cancel (eh_rule);
   1467     eh_rule = NULL;
   1468   }
   1469   if (NULL != eh_update_forced)
   1470   {
   1471     db_plugin->event_listen_cancel (eh_update_forced);
   1472     eh_update_forced = NULL;
   1473   }
   1474   if (NULL != keys_rule)
   1475   {
   1476     db_plugin->event_listen_cancel (keys_rule);
   1477     keys_rule = NULL;
   1478   }
   1479   TALER_MERCHANTDB_plugin_unload (db_plugin);
   1480   db_plugin = NULL;
   1481   cfg = NULL;
   1482   if (NULL != ctx)
   1483   {
   1484     GNUNET_CURL_fini (ctx);
   1485     ctx = NULL;
   1486   }
   1487   if (NULL != rc)
   1488   {
   1489     GNUNET_CURL_gnunet_rc_destroy (rc);
   1490     rc = NULL;
   1491   }
   1492 }
   1493 
   1494 
   1495 /**
   1496  * Function called when we urgently need to re-check the KYC status
   1497  * of some account. Finds the respective inquiry and re-launches
   1498  * the check, unless we are already doing it.
   1499  *
   1500  * @param cls NULL
   1501  * @param instance_id instance for which to force the check
   1502  * @param exchange_url base URL of the exchange to check
   1503  * @param h_wire hash of the wire account to check KYC status for
   1504  */
   1505 static void
   1506 force_check_now (void *cls,
   1507                  const char *instance_id,
   1508                  const char *exchange_url,
   1509                  const struct TALER_MerchantWireHashP *h_wire)
   1510 {
   1511   for (struct Account *a = a_head;
   1512        NULL != a;
   1513        a = a->next)
   1514   {
   1515     if (0 !=
   1516         strcmp (instance_id,
   1517                 a->instance_id))
   1518       continue;
   1519     if (0 !=
   1520         GNUNET_memcmp (h_wire,
   1521                        &a->h_wire))
   1522       continue;
   1523     for (struct Inquiry *i = a->i_head;
   1524          NULL != i;
   1525          i = i->next)
   1526     {
   1527       if (0 !=
   1528           strcmp (i->e->keys->exchange_url,
   1529                   exchange_url))
   1530         continue;
   1531       /* If we are not actively checking with the exchange, do start
   1532          to check immediately */
   1533       if (NULL != i->kyc)
   1534       {
   1535         i->due = GNUNET_TIME_absolute_get (); /* now! */
   1536         if (NULL != i->task)
   1537           GNUNET_SCHEDULER_cancel (i->task);
   1538         i->task = GNUNET_SCHEDULER_add_at (i->due,
   1539                                            &inquiry_work,
   1540                                            i);
   1541       }
   1542       return;
   1543     }
   1544   }
   1545   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1546               "No inquiry at `%s' for exchange `%s' and h_wire `%s'. Likely the account is not eligible.\n",
   1547               instance_id,
   1548               exchange_url,
   1549               TALER_B2S (h_wire));
   1550   /* In this case, set the due date back to FOREVER */
   1551   flag_ineligible (instance_id,
   1552                    exchange_url,
   1553                    h_wire);
   1554 }
   1555 
   1556 
   1557 /**
   1558  * Function called when a KYC status update was forced by an
   1559  * application checking the KYC status of an account.
   1560  *
   1561  * @param cls closure (NULL)
   1562  * @param extra additional event data provided
   1563  * @param extra_size number of bytes in @a extra
   1564  */
   1565 static void
   1566 update_forced (void *cls,
   1567                const void *extra,
   1568                size_t extra_size)
   1569 {
   1570   enum GNUNET_DB_QueryStatus qs;
   1571 
   1572   (void) cls;
   1573   (void) extra;
   1574   (void) extra_size;
   1575   qs = db_plugin->account_kyc_get_outdated (
   1576     db_plugin->cls,
   1577     &force_check_now,
   1578     NULL);
   1579   if (qs < 0)
   1580   {
   1581     GNUNET_break (0);
   1582     global_ret = EXIT_FAILURE;
   1583     GNUNET_SCHEDULER_shutdown ();
   1584     return;
   1585   }
   1586 }
   1587 
   1588 
   1589 /**
   1590  * First task.
   1591  *
   1592  * @param cls closure, NULL
   1593  * @param args remaining command-line arguments
   1594  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
   1595  * @param c configuration
   1596  */
   1597 static void
   1598 run (void *cls,
   1599      char *const *args,
   1600      const char *cfgfile,
   1601      const struct GNUNET_CONFIGURATION_Handle *c)
   1602 {
   1603   (void) args;
   1604   (void) cfgfile;
   1605 
   1606   cfg = c;
   1607   if (GNUNET_OK !=
   1608       GNUNET_CONFIGURATION_get_value_time (cfg,
   1609                                            "merchant-kyccheck",
   1610                                            "AML_FREQ",
   1611                                            &aml_freq))
   1612   {
   1613     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
   1614                                "merchant-kyccheck",
   1615                                "AML_FREQ");
   1616     /* use default */
   1617     aml_freq = AML_FREQ;
   1618   }
   1619   if (GNUNET_OK !=
   1620       GNUNET_CONFIGURATION_get_value_time (cfg,
   1621                                            "merchant-kyccheck",
   1622                                            "AML_LOW_FREQ",
   1623                                            &aml_low_freq))
   1624   {
   1625     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
   1626                                "merchant-kyccheck",
   1627                                "AML_LOW_FREQ");
   1628     /* use default */
   1629     aml_low_freq = AML_LOW_FREQ;
   1630   }
   1631   if (GNUNET_TIME_relative_cmp (aml_low_freq,
   1632                                 <,
   1633                                 aml_freq))
   1634   {
   1635     aml_low_freq = GNUNET_TIME_relative_multiply (aml_freq,
   1636                                                   10);
   1637     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1638                 "AML_LOW_FREQ was set to less than AML_FREQ. Using %s instead\n",
   1639                 GNUNET_TIME_relative2s (aml_low_freq,
   1640                                         true));
   1641   }
   1642   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
   1643                                  NULL);
   1644   ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
   1645                           &rc);
   1646   rc = GNUNET_CURL_gnunet_rc_create (ctx);
   1647   if (NULL == ctx)
   1648   {
   1649     GNUNET_break (0);
   1650     GNUNET_SCHEDULER_shutdown ();
   1651     global_ret = EXIT_FAILURE;
   1652     return;
   1653   }
   1654   if (NULL ==
   1655       (db_plugin = TALER_MERCHANTDB_plugin_load (cfg)))
   1656   {
   1657     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1658                 "Failed to initialize DB subsystem\n");
   1659     GNUNET_SCHEDULER_shutdown ();
   1660     global_ret = EXIT_NOTCONFIGURED;
   1661     return;
   1662   }
   1663   if (GNUNET_OK !=
   1664       db_plugin->connect (db_plugin->cls))
   1665   {
   1666     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1667                 "Failed to connect to database. Consider running taler-merchant-dbinit.\n");
   1668     GNUNET_SCHEDULER_shutdown ();
   1669     global_ret = EXIT_FAILURE;
   1670     return;
   1671   }
   1672   {
   1673     struct GNUNET_DB_EventHeaderP es = {
   1674       .size = htons (sizeof (es)),
   1675       .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KEYS)
   1676     };
   1677 
   1678     eh_keys
   1679       = db_plugin->event_listen (db_plugin->cls,
   1680                                  &es,
   1681                                  GNUNET_TIME_UNIT_FOREVER_REL,
   1682                                  &keys_changed,
   1683                                  NULL);
   1684   }
   1685   {
   1686     struct GNUNET_DB_EventHeaderP es = {
   1687       .size = htons (sizeof (es)),
   1688       .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_UPDATE_FORCED)
   1689     };
   1690 
   1691     eh_update_forced
   1692       = db_plugin->event_listen (db_plugin->cls,
   1693                                  &es,
   1694                                  GNUNET_TIME_UNIT_FOREVER_REL,
   1695                                  &update_forced,
   1696                                  NULL);
   1697   }
   1698   {
   1699     struct GNUNET_DB_EventHeaderP es = {
   1700       .size = htons (sizeof (es)),
   1701       .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_RULE_TRIGGERED)
   1702     };
   1703 
   1704     eh_rule
   1705       = db_plugin->event_listen (db_plugin->cls,
   1706                                  &es,
   1707                                  GNUNET_TIME_UNIT_FOREVER_REL,
   1708                                  &rule_triggered,
   1709                                  NULL);
   1710   }
   1711   GNUNET_CONFIGURATION_iterate_sections (cfg,
   1712                                          &accept_exchanges,
   1713                                          NULL);
   1714   fprintf (stderr, "NOW\n");
   1715   {
   1716     struct GNUNET_DB_EventHeaderP es = {
   1717       .size = htons (sizeof (es)),
   1718       .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED)
   1719     };
   1720 
   1721     eh_accounts
   1722       = db_plugin->event_listen (db_plugin->cls,
   1723                                  &es,
   1724                                  GNUNET_TIME_UNIT_FOREVER_REL,
   1725                                  &account_changed,
   1726                                  NULL);
   1727   }
   1728   GNUNET_assert (NULL == account_task);
   1729   account_task
   1730     = GNUNET_SCHEDULER_add_now (&find_accounts,
   1731                                 NULL);
   1732 }
   1733 
   1734 
   1735 /**
   1736  * The main function of taler-merchant-kyccheck
   1737  *
   1738  * @param argc number of arguments from the command line
   1739  * @param argv command line arguments
   1740  * @return 0 ok, 1 on error
   1741  */
   1742 int
   1743 main (int argc,
   1744       char *const *argv)
   1745 {
   1746   struct GNUNET_GETOPT_CommandLineOption options[] = {
   1747     GNUNET_GETOPT_option_timetravel ('T',
   1748                                      "timetravel"),
   1749     GNUNET_GETOPT_option_flag ('t',
   1750                                "test",
   1751                                "run in test mode and exit when idle",
   1752                                &test_mode),
   1753     GNUNET_GETOPT_option_version (VERSION "-" VCS_VERSION),
   1754     GNUNET_GETOPT_OPTION_END
   1755   };
   1756   enum GNUNET_GenericReturnValue ret;
   1757 
   1758   ret = GNUNET_PROGRAM_run (
   1759     TALER_MERCHANT_project_data (),
   1760     argc, argv,
   1761     "taler-merchant-kyccheck",
   1762     gettext_noop (
   1763       "background process that checks the KYC state of our bank accounts at various exchanges"),
   1764     options,
   1765     &run, NULL);
   1766   if (GNUNET_SYSERR == ret)
   1767     return EXIT_INVALIDARGUMENT;
   1768   if (GNUNET_NO == ret)
   1769     return EXIT_SUCCESS;
   1770   return global_ret;
   1771 }
   1772 
   1773 
   1774 /* end of taler-merchant-kyccheck.c */