taler-merchant-kyccheck.c (61203B)
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 src/backend/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 "platform.h" 22 struct Inquiry; 23 #define TALER_EXCHANGE_GET_KYC_CHECK_RESULT_CLOSURE struct Inquiry 24 #define TALER_EXCHANGE_GET_KYC_INFO_RESULT_CLOSURE struct Inquiry 25 #define TALER_EXCHANGE_POST_KYC_UPLOAD_RESULT_CLOSURE struct Inquiry 26 #include "microhttpd.h" 27 #include <gnunet/gnunet_util_lib.h> 28 #include <jansson.h> 29 #include <pthread.h> 30 #include <regex.h> 31 #include <taler/taler_dbevents.h> 32 #include <taler/taler_json_lib.h> 33 #include <taler/taler_exchange_service.h> 34 #include <taler/exchange/post-kyc-upload-ID.h> 35 #include "taler/taler_merchant_util.h" 36 #include "taler/taler_merchant_bank_lib.h" 37 #include "merchantdb_lib.h" 38 #include "merchantdb_lib.h" 39 #include "merchant-database/account_kyc_get_outdated.h" 40 #include "merchant-database/account_kyc_set_status.h" 41 #include "merchant-database/delete_tos_accepted_early.h" 42 #include "merchant-database/get_kyc_status.h" 43 #include "merchant-database/lookup_tos_accepted_early.h" 44 #include "merchant-database/set_instance.h" 45 #include "merchant-database/select_accounts.h" 46 #include "merchant-database/select_exchange_keys.h" 47 #include "merchant-database/event_listen.h" 48 #include "merchant-database/preflight.h" 49 #include "merchant-database/start.h" 50 51 52 /** 53 * Timeout for the exchange interaction. Rather long as we should do 54 * long-polling and do not want to wake up too often. 55 */ 56 #define EXCHANGE_TIMEOUT GNUNET_TIME_relative_multiply ( \ 57 GNUNET_TIME_UNIT_MINUTES, \ 58 30) 59 60 /** 61 * How long do we wait between requests if all we wait 62 * for is a change in the AML investigation status? 63 * Default value. 64 */ 65 #define AML_FREQ GNUNET_TIME_relative_multiply ( \ 66 GNUNET_TIME_UNIT_HOURS, \ 67 6) 68 69 /** 70 * How long do we wait between requests if all we wait 71 * for is a change in the AML investigation status? 72 */ 73 static struct GNUNET_TIME_Relative aml_freq; 74 75 /** 76 * How frequently do we check for updates to our KYC status 77 * if there is no actual reason to check? Set to a very low 78 * frequency, just to ensure we eventually notice. 79 * Default value. 80 */ 81 #define AML_LOW_FREQ GNUNET_TIME_relative_multiply ( \ 82 GNUNET_TIME_UNIT_DAYS, \ 83 7) 84 85 /** 86 * How frequently do we check for updates to our KYC status 87 * if there is no actual reason to check? Set to a very low 88 * frequency, just to ensure we eventually notice. 89 */ 90 static struct GNUNET_TIME_Relative aml_low_freq; 91 92 93 /** 94 * How many inquiries do we process concurrently at most. 95 */ 96 #define OPEN_INQUIRY_LIMIT 1024 97 98 /** 99 * Name of the KYC form (``FORM_ID``) the exchange uses to affirm 100 * acceptance of the terms of service. Must match the value submitted 101 * by #TALER_EXCHANGE_post_kyc_upload_accept_tos_create(). 102 */ 103 #define ACCEPT_TOS_FORM "accept-tos" 104 105 /** 106 * Minimum delay before we retry after the exchange returned an 107 * internal error to our attempt to automatically accept the terms 108 * of service on behalf of the user. 109 */ 110 #define TOS_ERROR_RETRY_DELAY GNUNET_TIME_UNIT_HOURS 111 112 113 /** 114 * Information about an exchange. 115 */ 116 struct Exchange 117 { 118 /** 119 * Kept in a DLL. 120 */ 121 struct Exchange *next; 122 123 /** 124 * Kept in a DLL. 125 */ 126 struct Exchange *prev; 127 128 /** 129 * The keys of this exchange 130 */ 131 struct TALER_EXCHANGE_Keys *keys; 132 133 }; 134 135 136 /** 137 * Information about an Account. 138 */ 139 struct Account 140 { 141 /** 142 * Kept in a DLL. 143 */ 144 struct Account *next; 145 146 /** 147 * Kept in a DLL. 148 */ 149 struct Account *prev; 150 151 /** 152 * Head of inquiries for this account. 153 */ 154 struct Inquiry *i_head; 155 156 /** 157 * Tail of inquiries for this account. 158 */ 159 struct Inquiry *i_tail; 160 161 /** 162 * Merchant instance this account belongs to. 163 */ 164 char *instance_id; 165 166 /** 167 * The payto-URI of this account. 168 */ 169 struct TALER_FullPayto merchant_account_uri; 170 171 /** 172 * Wire hash of the merchant bank account (with the 173 * respective salt). 174 */ 175 struct TALER_MerchantWireHashP h_wire; 176 177 /** 178 * Private key of the instance. 179 */ 180 union TALER_AccountPrivateKeyP ap; 181 182 /** 183 * Hash of the @e merchant_account_uri. 184 */ 185 struct TALER_NormalizedPaytoHashP h_payto; 186 187 /** 188 * Database generation when this account 189 * was last active. 190 */ 191 uint64_t account_gen; 192 193 }; 194 195 196 /** 197 * Information about an inquiry job. 198 */ 199 struct Inquiry 200 { 201 /** 202 * Kept in a DLL. 203 */ 204 struct Inquiry *next; 205 206 /** 207 * Kept in a DLL. 208 */ 209 struct Inquiry *prev; 210 211 /** 212 * Main task for this inquiry. 213 */ 214 struct GNUNET_SCHEDULER_Task *task; 215 216 /** 217 * Which exchange is this inquiry about. 218 */ 219 struct Exchange *e; 220 221 /** 222 * Which account is this inquiry about. 223 */ 224 struct Account *a; 225 226 /** 227 * AccountLimits that apply to the account, NULL 228 * if unknown. 229 */ 230 json_t *jlimits; 231 232 /** 233 * Handle for the actual HTTP request to the exchange. 234 */ 235 struct TALER_EXCHANGE_GetKycCheckHandle *kyc; 236 237 /** 238 * Handle for fetching /kyc-info to discover the upload ID used to 239 * automatically accept the terms of service, NULL if not active. 240 */ 241 struct TALER_EXCHANGE_GetKycInfoHandle *kyc_info; 242 243 /** 244 * Handle for the /kyc-upload request submitting the automatic 245 * terms-of-service acceptance, NULL if not active. 246 */ 247 struct TALER_EXCHANGE_PostKycUploadHandle *tos_upload; 248 249 /** 250 * If non-NULL, the ``Taler-Terms-Version`` of the terms of service 251 * that the user accepted early (via ``POST /private/accept-tos-early``) 252 * and that we are trying to submit to the exchange on their behalf. 253 * Owned by the inquiry. 254 */ 255 char *tos_etag; 256 257 /** 258 * Access token for the /kyc-info API. 259 */ 260 struct TALER_AccountAccessTokenP access_token; 261 262 /** 263 * Last time we called the /kyc-check endpoint. 264 */ 265 struct GNUNET_TIME_Timestamp last_kyc_check; 266 267 /** 268 * When is the next KYC check due? 269 */ 270 struct GNUNET_TIME_Absolute due; 271 272 /** 273 * When should the current KYC time out? 274 */ 275 struct GNUNET_TIME_Absolute timeout; 276 277 /** 278 * Current exponential backoff. 279 */ 280 struct GNUNET_TIME_Relative backoff; 281 282 /** 283 * Rule generation known to the client, 0 for none. 284 * Corresponds to the decision row in the exchange. 285 */ 286 uint64_t rule_gen; 287 288 /** 289 * Last HTTP status returned by the exchange from 290 * the /kyc-check endpoint. 291 */ 292 unsigned int last_http_status; 293 294 /** 295 * Last Taler error code returned by the exchange from 296 * the /kyc-check endpoint. 297 */ 298 enum TALER_ErrorCode last_ec; 299 300 /** 301 * True if this is not our first time we make this request. 302 */ 303 bool not_first_time; 304 305 /** 306 * Do soft limits on transactions apply to this merchant for operations 307 * merchants care about? If so, we should increase our request frequency 308 * and ask more often to see if they were lifted. 309 */ 310 bool zero_limited; 311 312 /** 313 * Did we not run this inquiry due to limits? 314 */ 315 bool limited; 316 317 /** 318 * Do we believe this account's KYC is in good shape? 319 */ 320 bool kyc_ok; 321 322 /** 323 * True if merchant did perform this account's KYC AUTH transfer and @e access_token is set. 324 */ 325 bool auth_ok; 326 327 /** 328 * True if the account is known to be currently under 329 * investigation by AML staff. 330 */ 331 bool aml_review; 332 333 }; 334 335 336 /** 337 * Head of known exchanges. 338 */ 339 static struct Exchange *e_head; 340 341 /** 342 * Tail of known exchanges. 343 */ 344 static struct Exchange *e_tail; 345 346 /** 347 * Head of accounts. 348 */ 349 static struct Account *a_head; 350 351 /** 352 * Tail of accounts. 353 */ 354 static struct Account *a_tail; 355 356 /** 357 * The merchant's configuration. 358 */ 359 static const struct GNUNET_CONFIGURATION_Handle *cfg; 360 361 /** 362 * Our database connection. 363 */ 364 static struct TALER_MERCHANTDB_PostgresContext *pg; 365 366 /** 367 * Handle to the context for interacting with the bank. 368 */ 369 static struct GNUNET_CURL_Context *ctx; 370 371 /** 372 * Scheduler context for running the @e ctx. 373 */ 374 static struct GNUNET_CURL_RescheduleContext *rc; 375 376 /** 377 * Event handler to learn that there may be new bank 378 * accounts to check. 379 */ 380 static struct GNUNET_DB_EventHandler *eh_accounts; 381 382 /** 383 * Event handler to learn that there may be new exchange 384 * keys to check. 385 */ 386 static struct GNUNET_DB_EventHandler *eh_keys; 387 388 /** 389 * Event handler to learn that there was a KYC 390 * rule triggered and we need to check the KYC 391 * status for an account. 392 */ 393 static struct GNUNET_DB_EventHandler *eh_rule; 394 395 /** 396 * Event handler to learn that higher-frequency KYC 397 * checks were forced by an application actively inspecting 398 * some KYC status values. 399 */ 400 static struct GNUNET_DB_EventHandler *eh_update_forced; 401 402 /** 403 * Event handler to learn that we got new /keys 404 * from an exchange and should reconsider eligibility. 405 */ 406 static struct GNUNET_DB_EventHandler *keys_rule; 407 408 /** 409 * Main task to discover (new) accounts. 410 */ 411 static struct GNUNET_SCHEDULER_Task *account_task; 412 413 /** 414 * Counter determining how often we have called 415 * "select_accounts" on the database. 416 */ 417 static uint64_t database_gen; 418 419 /** 420 * How many active inquiries do we have right now. 421 */ 422 static unsigned int active_inquiries; 423 424 /** 425 * Value to return from main(). 0 on success, non-zero on errors. 426 */ 427 static int global_ret; 428 429 /** 430 * #GNUNET_YES if we are in test mode and should exit when idle. 431 */ 432 static int test_mode; 433 434 /** 435 * True if the last DB query was limited by the 436 * #OPEN_INQUIRY_LIMIT and we thus should check again 437 * as soon as we are substantially below that limit, 438 * and not only when we get a DB notification. 439 */ 440 static bool at_limit; 441 442 443 /** 444 * Check about performing a /kyc-check request with the 445 * exchange for the given inquiry. 446 * 447 * @param cls a `struct Inquiry` to process 448 */ 449 static void 450 inquiry_work (void *cls); 451 452 453 /** 454 * An inquiry finished, check if we should resume others. 455 */ 456 static void 457 end_inquiry (void) 458 { 459 GNUNET_assert (active_inquiries > 0); 460 active_inquiries--; 461 if ( (active_inquiries < OPEN_INQUIRY_LIMIT / 2) && 462 (at_limit) ) 463 { 464 at_limit = false; 465 for (struct Account *a = a_head; 466 NULL != a; 467 a = a->next) 468 { 469 for (struct Inquiry *i = a->i_head; 470 NULL != i; 471 i = i->next) 472 { 473 if (! i->limited) 474 continue; 475 i->limited = false; 476 GNUNET_assert (NULL == i->task); 477 /* done synchronously so that the active_inquiries 478 is updated immediately */ 479 inquiry_work (i); 480 if (at_limit) 481 break; 482 } 483 if (at_limit) 484 break; 485 } 486 } 487 if ( (! at_limit) && 488 (0 == active_inquiries) && 489 (test_mode) ) 490 { 491 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 492 "No more open inquiries and in test mode. Existing.\n"); 493 GNUNET_SCHEDULER_shutdown (); 494 return; 495 } 496 } 497 498 499 /** 500 * Pack the given @a limit into the JSON @a limits array. 501 * 502 * @param limit account limit to pack 503 * @param[in,out] limits JSON array to extend 504 */ 505 static void 506 pack_limit (const struct TALER_EXCHANGE_AccountLimit *limit, 507 json_t *limits) 508 { 509 json_t *jl; 510 511 jl = GNUNET_JSON_PACK ( 512 TALER_JSON_pack_kycte ("operation_type", 513 limit->operation_type), 514 GNUNET_JSON_pack_time_rel ("timeframe", 515 limit->timeframe), 516 TALER_JSON_pack_amount ("threshold", 517 &limit->threshold), 518 GNUNET_JSON_pack_bool ("soft_limit", 519 limit->soft_limit) 520 ); 521 GNUNET_assert (0 == 522 json_array_append_new (limits, 523 jl)); 524 } 525 526 527 /** 528 * Update KYC status for @a i based on 529 * @a account_kyc_status 530 * 531 * @param[in,out] i inquiry context, jlimits is updated 532 * @param account_kyc_status account KYC status details 533 */ 534 static void 535 store_kyc_status ( 536 struct Inquiry *i, 537 const struct TALER_EXCHANGE_AccountKycStatus *account_kyc_status) 538 { 539 json_t *jlimits; 540 541 json_decref (i->jlimits); 542 jlimits = json_array (); 543 GNUNET_assert (NULL != jlimits); 544 i->zero_limited = false; 545 for (unsigned int j = 0; j<account_kyc_status->limits_length; j++) 546 { 547 const struct TALER_EXCHANGE_AccountLimit *limit 548 = &account_kyc_status->limits[j]; 549 550 pack_limit (limit, 551 jlimits); 552 if (TALER_amount_is_zero (&limit->threshold) && 553 limit->soft_limit && 554 ( (TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT == limit->operation_type) || 555 (TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE == limit->operation_type) || 556 (TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION == limit->operation_type) ) ) 557 { 558 i->zero_limited = true; 559 } 560 } 561 i->jlimits = jlimits; 562 GNUNET_break (! GNUNET_is_zero (&account_kyc_status->access_token)); 563 i->access_token = account_kyc_status->access_token; 564 i->aml_review = account_kyc_status->aml_review; 565 i->kyc_ok = (MHD_HTTP_OK == i->last_http_status); 566 } 567 568 569 /** 570 * The current interaction with the exchange for inquiry @a i is 571 * complete (or was aborted). Schedule the next periodic KYC check 572 * at @a i->due and release the active-inquiry slot. 573 * 574 * @param[in,out] i the inquiry to reschedule 575 */ 576 static void 577 finish_inquiry (struct Inquiry *i) 578 { 579 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 580 "Will repeat inquiry in %s\n", 581 GNUNET_TIME_relative2s ( 582 GNUNET_TIME_absolute_get_remaining (i->due), 583 true)); 584 if (! GNUNET_TIME_absolute_is_never (i->due)) 585 i->task = GNUNET_SCHEDULER_add_at (i->due, 586 &inquiry_work, 587 i); 588 end_inquiry (); 589 } 590 591 592 /** 593 * Clear the tos-accepted data from the user, we do not 594 * need the flag anymore, either because we passed it on 595 * to the exchange or because they are too old. 596 * 597 * @param i inquiry this is about 598 */ 599 static void 600 clear_tos (const struct Inquiry *i) 601 { 602 enum GNUNET_DB_QueryStatus qs; 603 604 qs = TALER_MERCHANTDB_set_instance (pg, 605 i->a->instance_id); 606 if (qs < 0) 607 { 608 GNUNET_break (0); 609 global_ret = EXIT_FAILURE; 610 GNUNET_SCHEDULER_shutdown (); 611 return; 612 } 613 qs = TALER_MERCHANTDB_delete_tos_accepted_early ( 614 pg, 615 i->a->instance_id, 616 i->e->keys->exchange_url); 617 GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 618 TALER_MERCHANTDB_set_instance (pg, 619 NULL)); 620 if (qs < 0) 621 { 622 GNUNET_break (0); 623 global_ret = EXIT_FAILURE; 624 GNUNET_SCHEDULER_shutdown (); 625 return; 626 } 627 } 628 629 630 /** 631 * Function called with the result of submitting an automatic 632 * terms-of-service acceptance to the exchange via /kyc-upload. 633 * 634 * @param i the inquiry the acceptance was for 635 * @param pr the exchange's response 636 */ 637 static void 638 tos_upload_cb (struct Inquiry *i, 639 const struct TALER_EXCHANGE_PostKycUploadResponse *pr) 640 { 641 unsigned int http_status = pr->hr.http_status; 642 643 i->tos_upload = NULL; 644 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 645 "Automatic ToS acceptance for `%s' at `%s' returned HTTP %u\n", 646 i->a->merchant_account_uri.full_payto, 647 i->e->keys->exchange_url, 648 http_status); 649 switch (http_status) 650 { 651 case MHD_HTTP_OK: 652 case MHD_HTTP_NO_CONTENT: 653 /* Exchange accepted the terms of service: re-check KYC now. */ 654 i->due = GNUNET_TIME_UNIT_ZERO_ABS; 655 clear_tos (i); 656 break; 657 case 0: /* no answer, like network failure */ 658 case MHD_HTTP_INTERNAL_SERVER_ERROR: 659 case MHD_HTTP_BAD_GATEWAY: 660 case MHD_HTTP_REQUEST_ENTITY_TOO_LARGE: /* Wild error */ 661 /* Internal/transient error at the exchange: do NOT clear the early 662 acceptance, but back off for at least an hour before retrying 663 with a regular periodic KYC check. */ 664 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 665 "Exchange `%s' failed to process automatic ToS acceptance (HTTP %u); retrying later\n", 666 i->e->keys->exchange_url, 667 http_status); 668 i->due = GNUNET_TIME_relative_to_absolute ( 669 GNUNET_TIME_randomize (TOS_ERROR_RETRY_DELAY)); 670 break; 671 case MHD_HTTP_NOT_FOUND: 672 /* Something must have changed exchange-side, try again 673 immediately, but do not clear ToS acceptance */ 674 i->due = GNUNET_TIME_UNIT_ZERO_ABS; 675 clear_tos (i); 676 break; 677 case MHD_HTTP_BAD_REQUEST: 678 /* This should not happen, go back to manual KYC */ 679 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 680 "Exchange `%s' failed to process automatic ToS acceptance (HTTP %u); retrying later\n", 681 i->e->keys->exchange_url, 682 http_status); 683 i->due = GNUNET_TIME_relative_to_absolute ( 684 GNUNET_TIME_randomize (TOS_ERROR_RETRY_DELAY)); 685 break; 686 case MHD_HTTP_CONFLICT: 687 /* Exchange rejected the accepted ToS version (ETag not acceptable 688 or ToS acceptance disappeared): 689 clear the early acceptance so we do not loop, then re-check KYC 690 (the user will have to accept the ToS through the regular flow 691 if it still applies). */ 692 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 693 "Exchange `%s' rejected early ToS acceptance (version `%s', HTTP %u); clearing early acceptance\n", 694 i->e->keys->exchange_url, 695 i->tos_etag, 696 http_status); 697 clear_tos (i); 698 i->due = GNUNET_TIME_UNIT_ZERO_ABS; 699 break; 700 } 701 GNUNET_free (i->tos_etag); 702 finish_inquiry (i); 703 } 704 705 706 /** 707 * Submit an automatic terms-of-service acceptance for inquiry @a i to 708 * the exchange, using the @a id of the corresponding KYC requirement 709 * (obtained from /kyc-info) and the early-accepted version in 710 * @a i->tos_etag. 711 * 712 * @param[in,out] i inquiry to submit the ToS acceptance for 713 * @param id KYC requirement / upload ID for the terms-of-service form 714 */ 715 static void 716 start_tos_upload (struct Inquiry *i, 717 const char *id) 718 { 719 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 720 "Submitting automatic ToS acceptance (version `%s', id `%s') to `%s'\n", 721 i->tos_etag, 722 id, 723 i->e->keys->exchange_url); 724 i->tos_upload = TALER_EXCHANGE_post_kyc_upload_accept_tos_create ( 725 ctx, 726 i->e->keys->exchange_url, 727 id, 728 i->tos_etag); 729 if ( (NULL == i->tos_upload) || 730 (TALER_EC_NONE != 731 TALER_EXCHANGE_post_kyc_upload_start (i->tos_upload, 732 &tos_upload_cb, 733 i)) ) 734 { 735 GNUNET_break (0); 736 if (NULL != i->tos_upload) 737 { 738 TALER_EXCHANGE_post_kyc_upload_cancel (i->tos_upload); 739 i->tos_upload = NULL; 740 } 741 /* Could not even start the upload: treat as transient, keep the 742 early acceptance and retry with a regular periodic check. */ 743 GNUNET_free (i->tos_etag); 744 finish_inquiry (i); 745 } 746 } 747 748 749 /** 750 * Function called with the result of fetching /kyc-info while trying 751 * to automatically accept the terms of service. Finds the ID of the 752 * terms-of-service requirement and submits the acceptance. 753 * 754 * @param i the inquiry the lookup was for 755 * @param ir the exchange's response 756 */ 757 static void 758 tos_info_cb (struct Inquiry *i, 759 const struct TALER_EXCHANGE_GetKycInfoResponse *ir) 760 { 761 i->kyc_info = NULL; 762 if (MHD_HTTP_OK == ir->hr.http_status) 763 { 764 const char *id = NULL; 765 766 for (size_t j = 0; j < ir->details.ok.requirements_length; j++) 767 { 768 const struct TALER_EXCHANGE_RequirementInformation *req 769 = &ir->details.ok.requirements[j]; 770 771 if ( (NULL != req->form) && 772 (NULL != req->id) && 773 (0 == strcmp (req->form, 774 ACCEPT_TOS_FORM)) ) 775 { 776 id = req->id; 777 break; 778 } 779 } 780 if (NULL != id) 781 { 782 start_tos_upload (i, 783 id); 784 return; 785 } 786 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 787 "No `%s' requirement at `%s'; cannot auto-accept ToS, falling back to periodic check\n", 788 ACCEPT_TOS_FORM, 789 i->e->keys->exchange_url); 790 } 791 else 792 { 793 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 794 "GET /kyc-info at `%s' returned HTTP %u; cannot auto-accept ToS now\n", 795 i->e->keys->exchange_url, 796 ir->hr.http_status); 797 } 798 /* Could not determine the upload ID: keep the early acceptance and 799 retry on the next regular periodic KYC check. */ 800 GNUNET_free (i->tos_etag); 801 finish_inquiry (i); 802 } 803 804 805 /** 806 * Start the automatic terms-of-service acceptance for inquiry @a i by 807 * fetching /kyc-info to discover the ID of the terms-of-service 808 * requirement. The early-accepted version is in @a i->tos_etag. 809 * 810 * @param[in,out] i inquiry to auto-accept the terms of service for 811 */ 812 static void 813 start_tos_info (struct Inquiry *i) 814 { 815 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 816 "Fetching /kyc-info from `%s' to auto-accept ToS for `%s'\n", 817 i->e->keys->exchange_url, 818 i->a->merchant_account_uri.full_payto); 819 i->kyc_info = TALER_EXCHANGE_get_kyc_info_create (ctx, 820 i->e->keys->exchange_url, 821 &i->access_token); 822 if ( (NULL == i->kyc_info) || 823 (TALER_EC_NONE != 824 TALER_EXCHANGE_get_kyc_info_start (i->kyc_info, 825 &tos_info_cb, 826 i)) ) 827 { 828 GNUNET_break (0); 829 if (NULL != i->kyc_info) 830 { 831 TALER_EXCHANGE_get_kyc_info_cancel (i->kyc_info); 832 i->kyc_info = NULL; 833 } 834 /* Could not start the lookup: keep the early acceptance and retry 835 with a regular periodic check. */ 836 GNUNET_free (i->tos_etag); 837 finish_inquiry (i); 838 } 839 } 840 841 842 /** 843 * The exchange asked us (via @a tos_required) to accept its terms of 844 * service. Check whether the user already accepted the terms of 845 * service early (via ``POST /private/accept-tos-early``). If so, 846 * remember the accepted version in @a i->tos_etag so that we will try 847 * to submit it to the exchange automatically. 848 * 849 * @param[in,out] i inquiry for which the exchange requires ToS acceptance 850 * @param req required ETag for the accepted ToS 851 */ 852 static void 853 check_early_tos_acceptance (struct Inquiry *i, 854 const char *req) 855 { 856 enum GNUNET_DB_QueryStatus qs; 857 char *tos_version = NULL; 858 859 qs = TALER_MERCHANTDB_set_instance (pg, 860 i->a->instance_id); 861 if (qs < 0) 862 { 863 GNUNET_break (0); 864 global_ret = EXIT_FAILURE; 865 GNUNET_SCHEDULER_shutdown (); 866 return; 867 } 868 qs = TALER_MERCHANTDB_lookup_tos_accepted_early (pg, 869 i->a->instance_id, 870 i->e->keys->exchange_url, 871 &tos_version); 872 GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 873 TALER_MERCHANTDB_set_instance (pg, 874 NULL)); 875 if (qs < 0) 876 { 877 GNUNET_break (0); 878 global_ret = EXIT_FAILURE; 879 GNUNET_SCHEDULER_shutdown (); 880 return; 881 } 882 if (NULL == tos_version) 883 { 884 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 885 "Exchange `%s' supports early ToS acceptance, but user did not accept ToS early\n", 886 i->e->keys->exchange_url); 887 return; 888 } 889 if (0 != strcmp (tos_version, 890 req)) 891 { 892 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 893 "User accepted outdated ToS version `%s' early, but exchange wants `%s'. User will need to accept the ToS again!\n", 894 tos_version, 895 req); 896 GNUNET_free (tos_version); 897 return; 898 } 899 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 900 "User accepted ToS version `%s' early; will submit to `%s'\n", 901 tos_version, 902 i->e->keys->exchange_url); 903 GNUNET_free (i->tos_etag); 904 i->tos_etag = tos_version; 905 } 906 907 908 /** 909 * Function called with the result of a KYC check. 910 * 911 * @param cls a `struct Inquiry *` 912 * @param ks the account's KYC status details 913 */ 914 static void 915 exchange_check_cb ( 916 struct Inquiry *i, 917 const struct TALER_EXCHANGE_GetKycCheckResponse *ks) 918 { 919 bool progress = false; 920 921 i->kyc = NULL; 922 if (! i->not_first_time) 923 progress = true; 924 if ( (i->last_http_status != ks->hr.http_status) && 925 (0 != ks->hr.http_status) ) 926 progress = true; 927 if (0 != ks->hr.http_status) 928 { 929 i->last_http_status = ks->hr.http_status; 930 i->last_ec = ks->hr.ec; 931 } 932 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 933 "KYC status of `%s' / %s at `%s' is %u\n", 934 i->a->merchant_account_uri.full_payto, 935 i->a->instance_id, 936 i->e->keys->exchange_url, 937 ks->hr.http_status); 938 switch (ks->hr.http_status) 939 { 940 case 0: 941 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 942 "Exchange did not responded to /kyc-check request!\n"); 943 i->backoff 944 = GNUNET_TIME_randomized_backoff (i->backoff, 945 EXCHANGE_TIMEOUT); 946 i->due = GNUNET_TIME_relative_to_absolute (i->backoff); 947 break; 948 case MHD_HTTP_OK: 949 if (i->rule_gen != ks->details.ok.rule_gen) 950 progress = true; 951 i->rule_gen = ks->details.ok.rule_gen; 952 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 953 /* exchange says KYC is OK, gives status information */ 954 i->auth_ok = true; 955 store_kyc_status (i, 956 &ks->details.ok); 957 i->backoff = GNUNET_TIME_UNIT_MINUTES; 958 if (i->aml_review || i->zero_limited) 959 { 960 if (! progress) 961 i->due = GNUNET_TIME_relative_to_absolute ( 962 GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_freq, 963 i->backoff))); 964 } 965 else 966 { 967 /* KYC is OK, only check again if triggered */ 968 if (! progress) 969 i->due = GNUNET_TIME_relative_to_absolute ( 970 GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_low_freq, 971 i->backoff))); 972 } 973 break; 974 case MHD_HTTP_ACCEPTED: 975 if (i->rule_gen != ks->details.accepted.rule_gen) 976 progress = true; 977 i->rule_gen = ks->details.accepted.rule_gen; 978 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 979 /* exchange says KYC is required */ 980 i->auth_ok = true; 981 store_kyc_status (i, 982 &ks->details.accepted); 983 i->backoff = GNUNET_TIME_UNIT_MINUTES; 984 /* Start immediately with long-polling */ 985 if (! progress) 986 i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time, 987 i->timeout); 988 if (NULL != ks->details.accepted.tos_required) 989 { 990 /* Exchange wants the user to accept its terms of service. 991 If the user already accepted them early, try to submit that 992 acceptance to the exchange automatically. */ 993 check_early_tos_acceptance (i, 994 ks->details.accepted.tos_required); 995 } 996 break; 997 case MHD_HTTP_NO_CONTENT: 998 i->rule_gen = 0; 999 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 1000 i->backoff = GNUNET_TIME_UNIT_MINUTES; 1001 /* exchange claims KYC is off! */ 1002 i->kyc_ok = true; 1003 i->aml_review = false; 1004 /* Clear limits, in case exchange had KYC on previously */ 1005 json_decref (i->jlimits); 1006 i->jlimits = NULL; 1007 /* KYC is OK, only check again if triggered */ 1008 i->due = GNUNET_TIME_relative_to_absolute ( 1009 GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_low_freq, 1010 i->backoff))); 1011 break; 1012 case MHD_HTTP_FORBIDDEN: /* bad signature */ 1013 i->rule_gen = 0; 1014 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 1015 /* Forbidden => KYC auth must be wrong */ 1016 i->auth_ok = false; 1017 /* Start with long-polling */ 1018 if (! progress) 1019 i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time, 1020 i->timeout); 1021 i->backoff = GNUNET_TIME_UNIT_MINUTES; 1022 break; 1023 case MHD_HTTP_NOT_FOUND: /* account unknown */ 1024 i->rule_gen = 0; 1025 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 1026 /* Account unknown => no KYC auth yet */ 1027 i->auth_ok = false; 1028 /* unknown account => wire transfer required! */ 1029 i->kyc_ok = false; 1030 /* There should not be any limits yet, but clear them 1031 just in case the exchange has amnesia */ 1032 json_decref (i->jlimits); 1033 i->jlimits = NULL; 1034 /* Start immediately with Long-polling */ 1035 if (! progress) 1036 i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time, 1037 i->timeout); 1038 i->backoff = GNUNET_TIME_UNIT_MINUTES; 1039 break; 1040 case MHD_HTTP_CONFLICT: /* no account_pub known */ 1041 i->rule_gen = 0; 1042 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 1043 /* Conflict => KYC auth wire transfer missing! */ 1044 i->auth_ok = false; 1045 /* Start immediately with Long-polling */ 1046 if (! progress) 1047 i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time, 1048 i->timeout); 1049 i->backoff = GNUNET_TIME_UNIT_MINUTES; 1050 break; 1051 default: 1052 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1053 "Exchange responded with HTTP status %u (%d) to /kyc-check request!\n", 1054 ks->hr.http_status, 1055 ks->hr.ec); 1056 i->backoff 1057 = GNUNET_TIME_randomized_backoff (i->backoff, 1058 EXCHANGE_TIMEOUT); 1059 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 1060 i->due = GNUNET_TIME_relative_to_absolute (i->backoff); 1061 i->auth_ok = false; 1062 break; 1063 } 1064 1065 { 1066 enum GNUNET_DB_QueryStatus qs; 1067 1068 qs = TALER_MERCHANTDB_set_instance (pg, 1069 i->a->instance_id); 1070 if (qs < 0) 1071 { 1072 GNUNET_break (0); 1073 global_ret = EXIT_FAILURE; 1074 GNUNET_SCHEDULER_shutdown (); 1075 return; 1076 } 1077 qs = TALER_MERCHANTDB_account_kyc_set_status ( 1078 pg, 1079 i->a->instance_id, 1080 &i->a->h_wire, 1081 i->e->keys->exchange_url, 1082 i->last_kyc_check, 1083 i->due, 1084 i->backoff, 1085 i->last_http_status, 1086 i->last_ec, 1087 i->rule_gen, 1088 (i->auth_ok) 1089 ? &i->access_token 1090 : NULL, 1091 i->jlimits, 1092 i->aml_review, 1093 i->kyc_ok); 1094 GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 1095 TALER_MERCHANTDB_set_instance ( 1096 pg, 1097 NULL)); 1098 if (qs < 0) 1099 { 1100 GNUNET_break (0); 1101 global_ret = EXIT_FAILURE; 1102 GNUNET_SCHEDULER_shutdown (); 1103 return; 1104 } 1105 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1106 "account_kyc_set_status (%s, %s, %u, %s, %s) returned %d\n", 1107 i->a->instance_id, 1108 i->e->keys->exchange_url, 1109 i->last_http_status, 1110 i->auth_ok ? "auth OK" : "auth needed", 1111 NULL == i->jlimits ? "default limits" : "custom limits", 1112 (int) qs); 1113 i->not_first_time = true; 1114 } 1115 if (NULL != i->tos_etag) 1116 { 1117 /* The user accepted the terms of service early and the exchange now 1118 requires acceptance: try to submit it automatically (this keeps 1119 the active-inquiry slot) instead of waiting for the next check. */ 1120 start_tos_info (i); 1121 return; 1122 } 1123 finish_inquiry (i); 1124 } 1125 1126 1127 static void 1128 inquiry_work (void *cls) 1129 { 1130 struct Inquiry *i = cls; 1131 enum TALER_EXCHANGE_KycLongPollTarget lpt; 1132 1133 i->task = NULL; 1134 if (! GNUNET_TIME_absolute_is_past (i->due)) 1135 { 1136 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1137 "Will start inquiry on %s for %s in %s\n", 1138 i->a->merchant_account_uri.full_payto, 1139 i->e->keys->exchange_url, 1140 GNUNET_TIME_relative2s ( 1141 GNUNET_TIME_absolute_get_remaining (i->due), 1142 true)); 1143 i->task 1144 = GNUNET_SCHEDULER_add_at (i->due, 1145 &inquiry_work, 1146 i); 1147 goto finish; 1148 } 1149 1150 GNUNET_assert (OPEN_INQUIRY_LIMIT >= active_inquiries); 1151 if (OPEN_INQUIRY_LIMIT <= active_inquiries) 1152 { 1153 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1154 "Not looking for work: at limit\n"); 1155 i->limited = true; 1156 at_limit = true; 1157 return; 1158 } 1159 at_limit = false; 1160 i->timeout 1161 = GNUNET_TIME_relative_to_absolute (EXCHANGE_TIMEOUT); 1162 lpt = TALER_EXCHANGE_KLPT_NONE; 1163 if (! i->auth_ok) 1164 lpt = TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER; 1165 else if (! i->kyc_ok) 1166 lpt = TALER_EXCHANGE_KLPT_KYC_OK; 1167 else if (i->aml_review) 1168 lpt = TALER_EXCHANGE_KLPT_INVESTIGATION_DONE; 1169 if (! i->not_first_time) 1170 lpt = TALER_EXCHANGE_KLPT_NONE; /* no long polling on 1st call */ 1171 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1172 "Starting KYC status of `%s' for %s at `%s' (%d, %d, %d) using LPT %d\n", 1173 i->a->merchant_account_uri.full_payto, 1174 i->a->instance_id, 1175 i->e->keys->exchange_url, 1176 i->not_first_time, 1177 i->auth_ok, 1178 i->kyc_ok, 1179 lpt); 1180 i->kyc = TALER_EXCHANGE_get_kyc_check_create ( 1181 ctx, 1182 i->e->keys->exchange_url, 1183 &i->a->h_payto, 1184 &i->a->ap); 1185 if (NULL == i->kyc) 1186 { 1187 GNUNET_break (0); 1188 i->due = i->timeout; 1189 i->task 1190 = GNUNET_SCHEDULER_add_at (i->due, 1191 &inquiry_work, 1192 i); 1193 goto finish; 1194 } 1195 GNUNET_assert (GNUNET_OK == 1196 TALER_EXCHANGE_get_kyc_check_set_options ( 1197 i->kyc, 1198 TALER_EXCHANGE_get_kyc_check_option_known_rule_gen ( 1199 i->rule_gen), 1200 TALER_EXCHANGE_get_kyc_check_option_lpt (lpt), 1201 TALER_EXCHANGE_get_kyc_check_option_timeout ( 1202 i->not_first_time && (! test_mode) 1203 ? EXCHANGE_TIMEOUT 1204 : GNUNET_TIME_UNIT_ZERO))); 1205 GNUNET_assert (TALER_EC_NONE == 1206 TALER_EXCHANGE_get_kyc_check_start (i->kyc, 1207 &exchange_check_cb, 1208 i)); 1209 active_inquiries++; 1210 finish: 1211 if ( (0 == active_inquiries) && 1212 (test_mode) ) 1213 { 1214 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1215 "No more open inquiries and in test mode. Existing.\n"); 1216 GNUNET_SCHEDULER_shutdown (); 1217 return; 1218 } 1219 } 1220 1221 1222 /** 1223 * Check if the account @a could work with exchange that 1224 * has keys @a keys. 1225 * 1226 * @param keys the keys of an exchange 1227 * @param a an account 1228 */ 1229 static bool 1230 is_eligible (const struct TALER_EXCHANGE_Keys *keys, 1231 const struct Account *a) 1232 { 1233 struct TALER_NormalizedPayto np; 1234 bool ret; 1235 1236 np = TALER_payto_normalize (a->merchant_account_uri); 1237 ret = TALER_EXCHANGE_keys_test_account_allowed (keys, 1238 true, 1239 np); 1240 GNUNET_free (np.normalized_payto); 1241 return ret; 1242 } 1243 1244 1245 /** 1246 * Start the KYC checking for account @a at exchange @a e. 1247 * 1248 * @param e an exchange 1249 * @param a an account 1250 */ 1251 static void 1252 start_inquiry (struct Exchange *e, 1253 struct Account *a) 1254 { 1255 struct Inquiry *i; 1256 enum GNUNET_DB_QueryStatus qs; 1257 1258 i = GNUNET_new (struct Inquiry); 1259 i->e = e; 1260 i->a = a; 1261 GNUNET_CONTAINER_DLL_insert (a->i_head, 1262 a->i_tail, 1263 i); 1264 qs = TALER_MERCHANTDB_set_instance (pg, 1265 a->instance_id); 1266 if (qs < 0) 1267 { 1268 GNUNET_break (0); 1269 global_ret = EXIT_FAILURE; 1270 GNUNET_SCHEDULER_shutdown (); 1271 return; 1272 } 1273 qs = TALER_MERCHANTDB_get_kyc_status (pg, 1274 a->merchant_account_uri, 1275 a->instance_id, 1276 e->keys->exchange_url, 1277 &i->auth_ok, 1278 &i->access_token, 1279 &i->kyc_ok, 1280 &i->last_http_status, 1281 &i->last_ec, 1282 &i->rule_gen, 1283 &i->last_kyc_check, 1284 &i->due, 1285 &i->backoff, 1286 &i->aml_review, 1287 &i->jlimits); 1288 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1289 "account_kyc_get_status (%s, %s, %s) returned %d (%u, #%llu)\n", 1290 i->a->instance_id, 1291 e->keys->exchange_url, 1292 a->merchant_account_uri.full_payto, 1293 (int) qs, 1294 i->last_http_status, 1295 (unsigned long long) i->rule_gen); 1296 if (qs < 0) 1297 { 1298 GNUNET_break (0); 1299 global_ret = EXIT_FAILURE; 1300 GNUNET_SCHEDULER_shutdown (); 1301 return; 1302 } 1303 if (qs > 0) 1304 i->not_first_time = true; 1305 if (GNUNET_YES == test_mode) 1306 i->due = GNUNET_TIME_UNIT_ZERO_ABS; /* immediately */ 1307 inquiry_work (i); 1308 } 1309 1310 1311 /** 1312 * Stop KYC inquiry @a i. 1313 * 1314 * @param[in] i the inquiry to stop 1315 */ 1316 static void 1317 stop_inquiry (struct Inquiry *i) 1318 { 1319 struct Account *a = i->a; 1320 1321 GNUNET_CONTAINER_DLL_remove (a->i_head, 1322 a->i_tail, 1323 i); 1324 if (NULL != i->task) 1325 { 1326 GNUNET_SCHEDULER_cancel (i->task); 1327 i->task = NULL; 1328 } 1329 if (NULL != i->kyc) 1330 { 1331 TALER_EXCHANGE_get_kyc_check_cancel (i->kyc); 1332 i->kyc = NULL; 1333 } 1334 if (NULL != i->kyc_info) 1335 { 1336 TALER_EXCHANGE_get_kyc_info_cancel (i->kyc_info); 1337 i->kyc_info = NULL; 1338 } 1339 if (NULL != i->tos_upload) 1340 { 1341 TALER_EXCHANGE_post_kyc_upload_cancel (i->tos_upload); 1342 i->tos_upload = NULL; 1343 } 1344 GNUNET_free (i->tos_etag); 1345 if (NULL != i->jlimits) 1346 { 1347 json_decref (i->jlimits); 1348 i->jlimits = NULL; 1349 } 1350 GNUNET_free (i); 1351 } 1352 1353 1354 /** 1355 * Stop KYC inquiry for account @a at exchange @a e. 1356 * 1357 * @param e an exchange 1358 * @param a an account 1359 */ 1360 static void 1361 stop_inquiry_at (struct Exchange *e, 1362 struct Account *a) 1363 { 1364 for (struct Inquiry *i = a->i_head; 1365 NULL != i; 1366 i = i->next) 1367 { 1368 if (e == i->e) 1369 { 1370 stop_inquiry (i); 1371 return; 1372 } 1373 } 1374 /* strange, there should have been a match! */ 1375 GNUNET_break (0); 1376 } 1377 1378 1379 /** 1380 * Set the account @a h_wire of @a instance_id to be ineligible 1381 * for the exchange at @a exchange_url and thus no need to do KYC checks. 1382 * 1383 * @param instance_id instance that has the account 1384 * @param exchange_url base URL of the exchange 1385 * @param h_wire hash of the merchant bank account that is ineligible 1386 */ 1387 static void 1388 flag_ineligible (const char *instance_id, 1389 const char *exchange_url, 1390 const struct TALER_MerchantWireHashP *h_wire) 1391 { 1392 enum GNUNET_DB_QueryStatus qs; 1393 1394 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1395 "Account %s not eligible at exchange %s\n", 1396 TALER_B2S (h_wire), 1397 exchange_url); 1398 qs = TALER_MERCHANTDB_set_instance (pg, 1399 instance_id); 1400 if (qs < 0) 1401 { 1402 GNUNET_break (0); 1403 global_ret = EXIT_FAILURE; 1404 GNUNET_SCHEDULER_shutdown (); 1405 return; 1406 } 1407 qs = TALER_MERCHANTDB_account_kyc_set_status ( 1408 pg, 1409 instance_id, 1410 h_wire, 1411 exchange_url, 1412 GNUNET_TIME_timestamp_get (), 1413 GNUNET_TIME_UNIT_FOREVER_ABS, 1414 GNUNET_TIME_UNIT_FOREVER_REL, 1415 0, 1416 TALER_EC_MERCHANT_PRIVATE_ACCOUNT_NOT_ELIGIBLE_FOR_EXCHANGE, 1417 0, 1418 NULL, 1419 NULL, 1420 false, 1421 false); 1422 GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 1423 TALER_MERCHANTDB_set_instance ( 1424 pg, 1425 NULL)); 1426 if (qs < 0) 1427 { 1428 GNUNET_break (0); 1429 global_ret = EXIT_FAILURE; 1430 GNUNET_SCHEDULER_shutdown (); 1431 return; 1432 } 1433 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1434 "account_kyc_set_status (%s) returned %d\n", 1435 exchange_url, 1436 (int) qs); 1437 } 1438 1439 1440 /** 1441 * Start inquries for all exchanges on account @a a. 1442 * 1443 * @param a an account 1444 */ 1445 static void 1446 start_inquiries (struct Account *a) 1447 { 1448 for (struct Exchange *e = e_head; 1449 NULL != e; 1450 e = e->next) 1451 { 1452 if (is_eligible (e->keys, 1453 a)) 1454 { 1455 start_inquiry (e, 1456 a); 1457 } 1458 else 1459 { 1460 flag_ineligible (a->instance_id, 1461 e->keys->exchange_url, 1462 &a->h_wire); 1463 } 1464 } 1465 } 1466 1467 1468 /** 1469 * Stop all inquries involving account @a a. 1470 * 1471 * @param a an account 1472 */ 1473 static void 1474 stop_inquiries (struct Account *a) 1475 { 1476 struct Inquiry *i; 1477 1478 while (NULL != (i = a->i_head)) 1479 stop_inquiry (i); 1480 } 1481 1482 1483 /** 1484 * Callback invoked with information about a bank account. 1485 * 1486 * @param cls closure 1487 * @param merchant_priv private key of the merchant instance 1488 * @param ad details about the account 1489 */ 1490 static void 1491 account_cb ( 1492 void *cls, 1493 const struct TALER_MerchantPrivateKeyP *merchant_priv, 1494 const struct TALER_MERCHANTDB_AccountDetails *ad) 1495 { 1496 struct TALER_FullPayto payto_uri = ad->payto_uri; 1497 1498 if (! ad->active) 1499 return; 1500 if (NULL == merchant_priv) 1501 return; /* instance was deleted */ 1502 for (struct Account *a = a_head; 1503 NULL != a; 1504 a = a->next) 1505 { 1506 if ( (0 == 1507 TALER_full_payto_cmp (payto_uri, 1508 a->merchant_account_uri)) && 1509 (0 == 1510 GNUNET_memcmp (&a->h_wire, 1511 &ad->h_wire)) && 1512 (0 == 1513 strcmp (ad->instance_id, 1514 a->instance_id)) ) 1515 { 1516 a->account_gen = database_gen; 1517 return; 1518 } 1519 } 1520 { 1521 struct Account *a = GNUNET_new (struct Account); 1522 1523 a->account_gen = database_gen; 1524 a->merchant_account_uri.full_payto 1525 = GNUNET_strdup (ad->payto_uri.full_payto); 1526 a->instance_id 1527 = GNUNET_strdup (ad->instance_id); 1528 a->h_wire 1529 = ad->h_wire; 1530 a->ap.merchant_priv 1531 = *merchant_priv; 1532 TALER_full_payto_normalize_and_hash (a->merchant_account_uri, 1533 &a->h_payto); 1534 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1535 "Found account %s of instance %s with H_PAYTO %s\n", 1536 ad->payto_uri.full_payto, 1537 ad->instance_id, 1538 GNUNET_sh2s (&a->h_payto.hash)); 1539 GNUNET_CONTAINER_DLL_insert (a_head, 1540 a_tail, 1541 a); 1542 start_inquiries (a); 1543 } 1544 } 1545 1546 1547 /** 1548 * The set of bank accounts has changed, update our 1549 * list of active inquiries. 1550 * 1551 * @param cls unused 1552 */ 1553 static void 1554 find_accounts (void *cls) 1555 { 1556 enum GNUNET_DB_QueryStatus qs; 1557 1558 (void) cls; 1559 account_task = NULL; 1560 database_gen++; 1561 qs = TALER_MERCHANTDB_select_accounts (pg, 1562 &account_cb, 1563 NULL); 1564 if (qs < 0) 1565 { 1566 GNUNET_break (0); 1567 global_ret = EXIT_FAILURE; 1568 GNUNET_SCHEDULER_shutdown (); 1569 return; 1570 } 1571 for (struct Account *a = a_head; 1572 NULL != a; 1573 a = a->next) 1574 { 1575 if (a->account_gen < database_gen) 1576 stop_inquiries (a); 1577 } 1578 if ( (! at_limit) && 1579 (0 == active_inquiries) && 1580 (test_mode) ) 1581 { 1582 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1583 "No more open inquiries and in test mode. Existing.\n"); 1584 GNUNET_SCHEDULER_shutdown (); 1585 return; 1586 } 1587 } 1588 1589 1590 /** 1591 * Function called when transfers are added to the merchant database. We look 1592 * for more work. 1593 * 1594 * @param cls closure (NULL) 1595 * @param extra additional event data provided 1596 * @param extra_size number of bytes in @a extra 1597 */ 1598 static void 1599 account_changed (void *cls, 1600 const void *extra, 1601 size_t extra_size) 1602 { 1603 (void) cls; 1604 (void) extra; 1605 (void) extra_size; 1606 if (NULL != account_task) 1607 return; 1608 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1609 "Received account change notification: reloading accounts\n"); 1610 account_task 1611 = GNUNET_SCHEDULER_add_now (&find_accounts, 1612 NULL); 1613 } 1614 1615 1616 /** 1617 * Interact with the database to get the current set 1618 * of exchange keys known to us. 1619 * 1620 * @param exchange_url the exchange URL to check 1621 */ 1622 static void 1623 find_keys (const char *exchange_url) 1624 { 1625 enum GNUNET_DB_QueryStatus qs; 1626 struct TALER_EXCHANGE_Keys *keys; 1627 struct Exchange *e; 1628 struct GNUNET_TIME_Absolute first_retry; 1629 1630 qs = TALER_MERCHANTDB_select_exchange_keys (pg, 1631 exchange_url, 1632 &first_retry, 1633 &keys); 1634 if (qs < 0) 1635 { 1636 GNUNET_break (0); 1637 global_ret = EXIT_FAILURE; 1638 GNUNET_SCHEDULER_shutdown (); 1639 return; 1640 } 1641 if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) || 1642 (NULL == keys) ) 1643 { 1644 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1645 "No %s/keys yet!\n", 1646 exchange_url); 1647 return; 1648 } 1649 for (e = e_head; NULL != e; e = e->next) 1650 { 1651 if (0 == strcmp (e->keys->exchange_url, 1652 keys->exchange_url)) 1653 { 1654 struct TALER_EXCHANGE_Keys *old_keys = e->keys; 1655 1656 e->keys = keys; 1657 for (struct Account *a = a_head; 1658 NULL != a; 1659 a = a->next) 1660 { 1661 bool was_eligible = is_eligible (old_keys, 1662 a); 1663 bool now_eligible = is_eligible (keys, 1664 a); 1665 1666 if (was_eligible == now_eligible) 1667 continue; /* no change, do nothing */ 1668 if (was_eligible) 1669 stop_inquiry_at (e, 1670 a); 1671 else /* is_eligible */ 1672 start_inquiry (e, 1673 a); 1674 } 1675 TALER_EXCHANGE_keys_decref (old_keys); 1676 return; 1677 } 1678 } 1679 e = GNUNET_new (struct Exchange); 1680 e->keys = keys; 1681 GNUNET_CONTAINER_DLL_insert (e_head, 1682 e_tail, 1683 e); 1684 for (struct Account *a = a_head; 1685 NULL != a; 1686 a = a->next) 1687 { 1688 if ( (a->account_gen == database_gen) && 1689 (is_eligible (e->keys, 1690 a)) ) 1691 start_inquiry (e, 1692 a); 1693 } 1694 } 1695 1696 1697 /** 1698 * Function called when keys were changed in the 1699 * merchant database. Updates ours. 1700 * 1701 * @param cls closure (NULL) 1702 * @param extra additional event data provided 1703 * @param extra_size number of bytes in @a extra 1704 */ 1705 static void 1706 keys_changed (void *cls, 1707 const void *extra, 1708 size_t extra_size) 1709 { 1710 const char *url = extra; 1711 1712 (void) cls; 1713 if ( (NULL == extra) || 1714 (0 == extra_size) ) 1715 { 1716 GNUNET_break (0); 1717 global_ret = EXIT_FAILURE; 1718 GNUNET_SCHEDULER_shutdown (); 1719 return; 1720 } 1721 if ('\0' != url[extra_size - 1]) 1722 { 1723 GNUNET_break (0); 1724 global_ret = EXIT_FAILURE; 1725 GNUNET_SCHEDULER_shutdown (); 1726 return; 1727 } 1728 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1729 "Received keys change notification: reload `%s'\n", 1730 url); 1731 find_keys (url); 1732 } 1733 1734 1735 /** 1736 * Function called when a KYC rule was triggered by 1737 * a transaction and we need to get the latest KYC 1738 * status immediately. 1739 * 1740 * @param cls closure (NULL) 1741 * @param extra additional event data provided 1742 * @param extra_size number of bytes in @a extra 1743 */ 1744 static void 1745 rule_triggered (void *cls, 1746 const void *extra, 1747 size_t extra_size) 1748 { 1749 const char *text = extra; 1750 const char *space; 1751 struct TALER_MerchantWireHashP h_wire; 1752 const char *exchange_url; 1753 1754 (void) cls; 1755 if ( (NULL == extra) || 1756 (0 == extra_size) ) 1757 { 1758 GNUNET_break (0); 1759 global_ret = EXIT_FAILURE; 1760 GNUNET_SCHEDULER_shutdown (); 1761 return; 1762 } 1763 if ('\0' != text[extra_size - 1]) 1764 { 1765 GNUNET_break (0); 1766 global_ret = EXIT_FAILURE; 1767 GNUNET_SCHEDULER_shutdown (); 1768 return; 1769 } 1770 space = memchr (extra, 1771 ' ', 1772 extra_size); 1773 if (NULL == space) 1774 { 1775 GNUNET_break (0); 1776 global_ret = EXIT_FAILURE; 1777 GNUNET_SCHEDULER_shutdown (); 1778 return; 1779 } 1780 if (GNUNET_OK != 1781 GNUNET_STRINGS_string_to_data (extra, 1782 space - text, 1783 &h_wire, 1784 sizeof (h_wire))) 1785 { 1786 GNUNET_break (0); 1787 global_ret = EXIT_FAILURE; 1788 GNUNET_SCHEDULER_shutdown (); 1789 return; 1790 } 1791 exchange_url = &space[1]; 1792 if (! TALER_is_web_url (exchange_url)) 1793 { 1794 GNUNET_break (0); 1795 global_ret = EXIT_FAILURE; 1796 GNUNET_SCHEDULER_shutdown (); 1797 return; 1798 } 1799 1800 for (struct Account *a = a_head; 1801 NULL != a; 1802 a = a->next) 1803 { 1804 if (0 != 1805 GNUNET_memcmp (&h_wire, 1806 &a->h_wire)) 1807 continue; 1808 for (struct Inquiry *i = a->i_head; 1809 NULL != i; 1810 i = i->next) 1811 { 1812 if (0 != strcmp (exchange_url, 1813 i->e->keys->exchange_url)) 1814 continue; 1815 i->kyc_ok = false; 1816 i->due = GNUNET_TIME_UNIT_ZERO_ABS; 1817 if (NULL != i->task) 1818 { 1819 GNUNET_SCHEDULER_cancel (i->task); 1820 i->task = NULL; 1821 } 1822 if (NULL != i->kyc) 1823 { 1824 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1825 "/kyc-check already running for %s\n", 1826 text); 1827 return; 1828 } 1829 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1830 "Starting %skyc-check for `%s' due to KYC rule trigger\n", 1831 exchange_url, 1832 i->a->merchant_account_uri.full_payto); 1833 i->task = GNUNET_SCHEDULER_add_at (i->due, 1834 &inquiry_work, 1835 i); 1836 return; 1837 } 1838 } 1839 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1840 "KYC rule trigger notification `%s' matches none of our accounts\n", 1841 text); 1842 } 1843 1844 1845 /** 1846 * Function called on each configuration section. Finds sections 1847 * about exchanges, parses the entries. 1848 * 1849 * @param cls NULL 1850 * @param section name of the section 1851 */ 1852 static void 1853 accept_exchanges (void *cls, 1854 const char *section) 1855 { 1856 char *url; 1857 1858 (void) cls; 1859 if (0 != 1860 strncasecmp (section, 1861 "merchant-exchange-", 1862 strlen ("merchant-exchange-"))) 1863 return; 1864 if (GNUNET_YES == 1865 GNUNET_CONFIGURATION_get_value_yesno (cfg, 1866 section, 1867 "DISABLED")) 1868 return; 1869 if (GNUNET_OK != 1870 GNUNET_CONFIGURATION_get_value_string (cfg, 1871 section, 1872 "EXCHANGE_BASE_URL", 1873 &url)) 1874 { 1875 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1876 section, 1877 "EXCHANGE_BASE_URL"); 1878 global_ret = EXIT_NOTCONFIGURED; 1879 GNUNET_SCHEDULER_shutdown (); 1880 return; 1881 } 1882 find_keys (url); 1883 GNUNET_free (url); 1884 } 1885 1886 1887 /** 1888 * We're being aborted with CTRL-C (or SIGTERM). Shut down. 1889 * 1890 * @param cls closure (NULL) 1891 */ 1892 static void 1893 shutdown_task (void *cls) 1894 { 1895 (void) cls; 1896 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1897 "Running shutdown\n"); 1898 while (NULL != e_head) 1899 { 1900 struct Exchange *e = e_head; 1901 1902 if (NULL != e->keys) 1903 { 1904 TALER_EXCHANGE_keys_decref (e->keys); 1905 e->keys = NULL; 1906 } 1907 GNUNET_CONTAINER_DLL_remove (e_head, 1908 e_tail, 1909 e); 1910 GNUNET_free (e); 1911 } 1912 while (NULL != a_head) 1913 { 1914 struct Account *a = a_head; 1915 1916 stop_inquiries (a); 1917 GNUNET_CONTAINER_DLL_remove (a_head, 1918 a_tail, 1919 a); 1920 GNUNET_free (a->merchant_account_uri.full_payto); 1921 GNUNET_free (a->instance_id); 1922 GNUNET_free (a); 1923 } 1924 if (NULL != eh_accounts) 1925 { 1926 TALER_MERCHANTDB_event_listen_cancel (eh_accounts); 1927 eh_accounts = NULL; 1928 } 1929 if (NULL != account_task) 1930 { 1931 GNUNET_SCHEDULER_cancel (account_task); 1932 account_task = NULL; 1933 } 1934 if (NULL != eh_keys) 1935 { 1936 TALER_MERCHANTDB_event_listen_cancel (eh_keys); 1937 eh_keys = NULL; 1938 } 1939 if (NULL != eh_rule) 1940 { 1941 TALER_MERCHANTDB_event_listen_cancel (eh_rule); 1942 eh_rule = NULL; 1943 } 1944 if (NULL != eh_update_forced) 1945 { 1946 TALER_MERCHANTDB_event_listen_cancel (eh_update_forced); 1947 eh_update_forced = NULL; 1948 } 1949 if (NULL != keys_rule) 1950 { 1951 TALER_MERCHANTDB_event_listen_cancel (keys_rule); 1952 keys_rule = NULL; 1953 } 1954 if (NULL != pg) 1955 { 1956 TALER_MERCHANTDB_disconnect (pg); 1957 pg = NULL; 1958 } 1959 cfg = NULL; 1960 if (NULL != ctx) 1961 { 1962 GNUNET_CURL_fini (ctx); 1963 ctx = NULL; 1964 } 1965 if (NULL != rc) 1966 { 1967 GNUNET_CURL_gnunet_rc_destroy (rc); 1968 rc = NULL; 1969 } 1970 } 1971 1972 1973 /** 1974 * Function called when we urgently need to re-check the KYC status 1975 * of some account. Finds the respective inquiry and re-launches 1976 * the check, unless we are already doing it. 1977 * 1978 * @param cls NULL 1979 * @param instance_id instance for which to force the check 1980 * @param exchange_url base URL of the exchange to check 1981 * @param h_wire hash of the wire account to check KYC status for 1982 */ 1983 static void 1984 force_check_now (void *cls, 1985 const char *instance_id, 1986 const char *exchange_url, 1987 const struct TALER_MerchantWireHashP *h_wire) 1988 { 1989 for (struct Account *a = a_head; 1990 NULL != a; 1991 a = a->next) 1992 { 1993 if (0 != 1994 strcmp (instance_id, 1995 a->instance_id)) 1996 continue; 1997 if (0 != 1998 GNUNET_memcmp (h_wire, 1999 &a->h_wire)) 2000 continue; 2001 for (struct Inquiry *i = a->i_head; 2002 NULL != i; 2003 i = i->next) 2004 { 2005 if (0 != 2006 strcmp (i->e->keys->exchange_url, 2007 exchange_url)) 2008 continue; 2009 /* If we are not actively checking with the exchange, do start 2010 to check immediately */ 2011 if (NULL != i->kyc) 2012 { 2013 i->due = GNUNET_TIME_absolute_get (); /* now! */ 2014 if (NULL != i->task) 2015 GNUNET_SCHEDULER_cancel (i->task); 2016 i->task = GNUNET_SCHEDULER_add_at (i->due, 2017 &inquiry_work, 2018 i); 2019 } 2020 return; 2021 } 2022 } 2023 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2024 "No inquiry at `%s' for exchange `%s' and h_wire `%s'. Likely the account is not eligible.\n", 2025 instance_id, 2026 exchange_url, 2027 TALER_B2S (h_wire)); 2028 /* In this case, set the due date back to FOREVER */ 2029 flag_ineligible (instance_id, 2030 exchange_url, 2031 h_wire); 2032 } 2033 2034 2035 /** 2036 * Function called when a KYC status update was forced by an 2037 * application checking the KYC status of an account. 2038 * 2039 * @param cls closure (NULL) 2040 * @param extra additional event data provided 2041 * @param extra_size number of bytes in @a extra 2042 */ 2043 static void 2044 update_forced (void *cls, 2045 const void *extra, 2046 size_t extra_size) 2047 { 2048 enum GNUNET_DB_QueryStatus qs; 2049 2050 (void) cls; 2051 (void) extra; 2052 (void) extra_size; 2053 qs = TALER_MERCHANTDB_account_kyc_get_outdated ( 2054 pg, 2055 &force_check_now, 2056 NULL); 2057 if (qs < 0) 2058 { 2059 GNUNET_break (0); 2060 global_ret = EXIT_FAILURE; 2061 GNUNET_SCHEDULER_shutdown (); 2062 return; 2063 } 2064 } 2065 2066 2067 /** 2068 * First task. 2069 * 2070 * @param cls closure, NULL 2071 * @param args remaining command-line arguments 2072 * @param cfgfile name of the configuration file used (for saving, can be NULL!) 2073 * @param c configuration 2074 */ 2075 static void 2076 run (void *cls, 2077 char *const *args, 2078 const char *cfgfile, 2079 const struct GNUNET_CONFIGURATION_Handle *c) 2080 { 2081 (void) args; 2082 (void) cfgfile; 2083 2084 cfg = c; 2085 if (GNUNET_OK != 2086 GNUNET_CONFIGURATION_get_value_time (cfg, 2087 "merchant-kyccheck", 2088 "AML_FREQ", 2089 &aml_freq)) 2090 { 2091 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, 2092 "merchant-kyccheck", 2093 "AML_FREQ"); 2094 /* use default */ 2095 aml_freq = AML_FREQ; 2096 } 2097 if (GNUNET_OK != 2098 GNUNET_CONFIGURATION_get_value_time (cfg, 2099 "merchant-kyccheck", 2100 "AML_LOW_FREQ", 2101 &aml_low_freq)) 2102 { 2103 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, 2104 "merchant-kyccheck", 2105 "AML_LOW_FREQ"); 2106 /* use default */ 2107 aml_low_freq = AML_LOW_FREQ; 2108 } 2109 if (GNUNET_TIME_relative_cmp (aml_low_freq, 2110 <, 2111 aml_freq)) 2112 { 2113 aml_low_freq = GNUNET_TIME_relative_multiply (aml_freq, 2114 10); 2115 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2116 "AML_LOW_FREQ was set to less than AML_FREQ. Using %s instead\n", 2117 GNUNET_TIME_relative2s (aml_low_freq, 2118 true)); 2119 } 2120 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 2121 NULL); 2122 ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, 2123 &rc); 2124 rc = GNUNET_CURL_gnunet_rc_create (ctx); 2125 if (NULL == ctx) 2126 { 2127 GNUNET_break (0); 2128 GNUNET_SCHEDULER_shutdown (); 2129 global_ret = EXIT_FAILURE; 2130 return; 2131 } 2132 if (NULL == 2133 (pg = TALER_MERCHANTDB_connect (cfg))) 2134 { 2135 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2136 "Failed to initialize DB subsystem. Consider running taler-merchant-dbconfig.\n"); 2137 GNUNET_SCHEDULER_shutdown (); 2138 global_ret = EXIT_FAILURE; 2139 return; 2140 } 2141 { 2142 struct GNUNET_DB_EventHeaderP es = { 2143 .size = htons (sizeof (es)), 2144 .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KEYS) 2145 }; 2146 2147 eh_keys 2148 = TALER_MERCHANTDB_event_listen (pg, 2149 &es, 2150 GNUNET_TIME_UNIT_FOREVER_REL, 2151 &keys_changed, 2152 NULL); 2153 } 2154 { 2155 struct GNUNET_DB_EventHeaderP es = { 2156 .size = htons (sizeof (es)), 2157 .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_UPDATE_FORCED) 2158 }; 2159 2160 eh_update_forced 2161 = TALER_MERCHANTDB_event_listen (pg, 2162 &es, 2163 GNUNET_TIME_UNIT_FOREVER_REL, 2164 &update_forced, 2165 NULL); 2166 } 2167 { 2168 struct GNUNET_DB_EventHeaderP es = { 2169 .size = htons (sizeof (es)), 2170 .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_RULE_TRIGGERED) 2171 }; 2172 2173 eh_rule 2174 = TALER_MERCHANTDB_event_listen (pg, 2175 &es, 2176 GNUNET_TIME_UNIT_FOREVER_REL, 2177 &rule_triggered, 2178 NULL); 2179 } 2180 GNUNET_CONFIGURATION_iterate_sections (cfg, 2181 &accept_exchanges, 2182 NULL); 2183 { 2184 struct GNUNET_DB_EventHeaderP es = { 2185 .size = htons (sizeof (es)), 2186 .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED) 2187 }; 2188 2189 eh_accounts 2190 = TALER_MERCHANTDB_event_listen (pg, 2191 &es, 2192 GNUNET_TIME_UNIT_FOREVER_REL, 2193 &account_changed, 2194 NULL); 2195 } 2196 GNUNET_assert (NULL == account_task); 2197 account_task 2198 = GNUNET_SCHEDULER_add_now (&find_accounts, 2199 NULL); 2200 } 2201 2202 2203 /** 2204 * The main function of taler-merchant-kyccheck 2205 * 2206 * @param argc number of arguments from the command line 2207 * @param argv command line arguments 2208 * @return 0 ok, 1 on error 2209 */ 2210 int 2211 main (int argc, 2212 char *const *argv) 2213 { 2214 struct GNUNET_GETOPT_CommandLineOption options[] = { 2215 GNUNET_GETOPT_option_timetravel ('T', 2216 "timetravel"), 2217 GNUNET_GETOPT_option_flag ('t', 2218 "test", 2219 "run in test mode and exit when idle", 2220 &test_mode), 2221 GNUNET_GETOPT_option_version (VERSION), 2222 GNUNET_GETOPT_OPTION_END 2223 }; 2224 enum GNUNET_GenericReturnValue ret; 2225 2226 ret = GNUNET_PROGRAM_run ( 2227 TALER_MERCHANT_project_data (), 2228 argc, argv, 2229 "taler-merchant-kyccheck", 2230 gettext_noop ( 2231 "background process that checks the KYC state of our bank accounts at various exchanges"), 2232 options, 2233 &run, NULL); 2234 if (GNUNET_SYSERR == ret) 2235 return EXIT_INVALIDARGUMENT; 2236 if (GNUNET_NO == ret) 2237 return EXIT_SUCCESS; 2238 return global_ret; 2239 } 2240 2241 2242 /* end of taler-merchant-kyccheck.c */