taler-merchant-kyccheck.c (40525B)
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 "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_merchant_util.h" 31 #include "taler_merchant_bank_lib.h" 32 #include "taler_merchantdb_lib.h" 33 #include "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_KycCheckHandle *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 * Main task to discover (new) accounts. 346 */ 347 static struct GNUNET_SCHEDULER_Task *account_task; 348 349 /** 350 * Counter determining how often we have called 351 * "select_accounts" on the database. 352 */ 353 static uint64_t database_gen; 354 355 /** 356 * How many active inquiries do we have right now. 357 */ 358 static unsigned int active_inquiries; 359 360 /** 361 * Value to return from main(). 0 on success, non-zero on errors. 362 */ 363 static int global_ret; 364 365 /** 366 * #GNUNET_YES if we are in test mode and should exit when idle. 367 */ 368 static int test_mode; 369 370 /** 371 * True if the last DB query was limited by the 372 * #OPEN_INQUIRY_LIMIT and we thus should check again 373 * as soon as we are substantially below that limit, 374 * and not only when we get a DB notification. 375 */ 376 static bool at_limit; 377 378 379 /** 380 * Check about performing a /kyc-check request with the 381 * exchange for the given inquiry. 382 * 383 * @param cls a `struct Inquiry` to process 384 */ 385 static void 386 inquiry_work (void *cls); 387 388 389 /** 390 * An inquiry finished, check if we should resume others. 391 */ 392 static void 393 end_inquiry (void) 394 { 395 GNUNET_assert (active_inquiries > 0); 396 active_inquiries--; 397 if ( (active_inquiries < OPEN_INQUIRY_LIMIT / 2) && 398 (at_limit) ) 399 { 400 at_limit = false; 401 for (struct Account *a = a_head; 402 NULL != a; 403 a = a->next) 404 { 405 for (struct Inquiry *i = a->i_head; 406 NULL != i; 407 i = i->next) 408 { 409 if (! i->limited) 410 continue; 411 GNUNET_assert (NULL == i->task); 412 /* done synchronously so that the active_inquiries 413 is updated immediately */ 414 inquiry_work (i); 415 if (at_limit) 416 break; 417 } 418 if (at_limit) 419 break; 420 } 421 } 422 if ( (! at_limit) && 423 (0 == active_inquiries) && 424 (test_mode) ) 425 { 426 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 427 "No more open inquiries and in test mode. Existing.\n"); 428 GNUNET_SCHEDULER_shutdown (); 429 return; 430 } 431 } 432 433 434 /** 435 * Pack the given @a limit into the JSON @a limits array. 436 * 437 * @param limit account limit to pack 438 * @param[in,out] limits JSON array to extend 439 */ 440 static void 441 pack_limit (const struct TALER_EXCHANGE_AccountLimit *limit, 442 json_t *limits) 443 { 444 json_t *jl; 445 446 jl = GNUNET_JSON_PACK ( 447 TALER_JSON_pack_kycte ("operation_type", 448 limit->operation_type), 449 GNUNET_JSON_pack_time_rel ("timeframe", 450 limit->timeframe), 451 TALER_JSON_pack_amount ("threshold", 452 &limit->threshold), 453 GNUNET_JSON_pack_bool ("soft_limit", 454 limit->soft_limit) 455 ); 456 GNUNET_assert (0 == 457 json_array_append_new (limits, 458 jl)); 459 } 460 461 462 /** 463 * Update KYC status for @a i based on 464 * @a account_kyc_status 465 * 466 * @param[in,out] i inquiry context, jlimits is updated 467 * @param account_kyc_status account KYC status details 468 */ 469 static void 470 store_kyc_status ( 471 struct Inquiry *i, 472 const struct TALER_EXCHANGE_AccountKycStatus *account_kyc_status) 473 { 474 json_t *jlimits; 475 476 json_decref (i->jlimits); 477 jlimits = json_array (); 478 GNUNET_assert (NULL != jlimits); 479 i->zero_limited = false; 480 for (unsigned int j = 0; j<account_kyc_status->limits_length; j++) 481 { 482 const struct TALER_EXCHANGE_AccountLimit *limit 483 = &account_kyc_status->limits[j]; 484 485 pack_limit (limit, 486 jlimits); 487 if (TALER_amount_is_zero (&limit->threshold) && 488 limit->soft_limit && 489 ( (TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT == limit->operation_type) || 490 (TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE == limit->operation_type) || 491 (TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION == limit->operation_type) ) ) 492 { 493 i->zero_limited = true; 494 } 495 } 496 i->jlimits = jlimits; 497 GNUNET_break (! GNUNET_is_zero (&account_kyc_status->access_token)); 498 i->access_token = account_kyc_status->access_token; 499 i->auth_ok = true; 500 i->aml_review = account_kyc_status->aml_review; 501 i->kyc_ok = (MHD_HTTP_OK == i->last_http_status); 502 } 503 504 505 /** 506 * Function called with the result of a KYC check. 507 * 508 * @param cls a `struct Inquiry *` 509 * @param ks the account's KYC status details 510 */ 511 static void 512 exchange_check_cb ( 513 void *cls, 514 const struct TALER_EXCHANGE_KycStatus *ks) 515 { 516 struct Inquiry *i = cls; 517 bool progress = false; 518 519 if (! i->not_first_time) 520 progress = true; 521 i->kyc = NULL; 522 i->last_http_status = ks->hr.http_status; 523 i->last_ec = ks->hr.ec; 524 i->rule_gen = 0; 525 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 526 "Checking KYC status of `%s' at `%s' is %u\n", 527 i->a->merchant_account_uri.full_payto, 528 i->e->keys->exchange_url, 529 ks->hr.http_status); 530 switch (ks->hr.http_status) 531 { 532 case MHD_HTTP_OK: 533 if (! i->kyc_ok) 534 progress = true; 535 i->rule_gen = ks->details.ok.rule_gen; 536 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 537 /* exchange says KYC is OK, gives status information */ 538 store_kyc_status (i, 539 &ks->details.ok); 540 i->backoff = GNUNET_TIME_UNIT_MINUTES; 541 if (i->aml_review || i->zero_limited) 542 { 543 if (! progress) 544 i->due = GNUNET_TIME_relative_to_absolute ( 545 GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_freq, 546 i->backoff))); 547 } 548 else 549 { 550 /* KYC is OK, only check again if triggered */ 551 i->due = GNUNET_TIME_relative_to_absolute ( 552 GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_low_freq, 553 i->backoff))); 554 } 555 break; 556 case MHD_HTTP_ACCEPTED: 557 progress = ! i->auth_ok; 558 i->rule_gen = ks->details.ok.rule_gen; 559 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 560 561 /* exchange says KYC is required */ 562 store_kyc_status (i, 563 &ks->details.accepted); 564 i->backoff = GNUNET_TIME_UNIT_MINUTES; 565 /* Start immediately with long-polling */ 566 if (! progress) 567 i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time, 568 i->timeout); 569 break; 570 case MHD_HTTP_NO_CONTENT: 571 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 572 i->backoff = GNUNET_TIME_UNIT_MINUTES; 573 /* exchange claims KYC is off! */ 574 i->kyc_ok = true; 575 i->aml_review = false; 576 /* Clear limits, in case exchange had KYC on previously */ 577 json_decref (i->jlimits); 578 i->jlimits = NULL; 579 /* KYC is OK, only check again if triggered */ 580 i->due = GNUNET_TIME_relative_to_absolute ( 581 GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_low_freq, 582 i->backoff))); 583 break; 584 case MHD_HTTP_FORBIDDEN: /* bad signature */ 585 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 586 /* Forbidden => KYC auth must be wrong */ 587 i->auth_ok = false; 588 /* Start with long-polling */ 589 if (! progress) 590 i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time, 591 i->timeout); 592 i->backoff = GNUNET_TIME_UNIT_MINUTES; 593 break; 594 case MHD_HTTP_NOT_FOUND: /* account unknown */ 595 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 596 /* Account unknown => no KYC auth yet */ 597 i->auth_ok = false; 598 /* unknown account => wire transfer required! */ 599 i->kyc_ok = false; 600 /* There should not be any limits yet, but clear them 601 just in case the exchange has amnesia */ 602 json_decref (i->jlimits); 603 i->jlimits = NULL; 604 /* Start immediately with Long-polling */ 605 if (! progress) 606 i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time, 607 i->timeout); 608 i->backoff = GNUNET_TIME_UNIT_MINUTES; 609 break; 610 case MHD_HTTP_CONFLICT: /* no account_pub known */ 611 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 612 /* Conflict => KYC auth wire transfer missing! */ 613 i->auth_ok = false; 614 /* Start immediately with Long-polling */ 615 if (! progress) 616 i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time, 617 i->timeout); 618 i->backoff = GNUNET_TIME_UNIT_MINUTES; 619 break; 620 default: 621 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 622 "Exchange responded with HTTP status %u (%d) to /kyc-check request!\n", 623 ks->hr.http_status, 624 ks->hr.ec); 625 i->backoff 626 = GNUNET_TIME_randomized_backoff (i->backoff, 627 EXCHANGE_TIMEOUT); 628 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 629 i->due = GNUNET_TIME_relative_to_absolute (i->backoff); 630 i->auth_ok = false; 631 break; 632 } 633 634 { 635 enum GNUNET_DB_QueryStatus qs; 636 637 qs = db_plugin->account_kyc_set_status ( 638 db_plugin->cls, 639 i->a->instance_id, 640 &i->a->h_wire, 641 i->e->keys->exchange_url, 642 i->last_kyc_check, 643 i->last_http_status, 644 i->last_ec, 645 i->rule_gen, 646 (i->auth_ok) 647 ? &i->access_token 648 : NULL, 649 i->jlimits, 650 i->aml_review, 651 i->kyc_ok); 652 if (qs < 0) 653 { 654 GNUNET_break (0); 655 global_ret = EXIT_FAILURE; 656 GNUNET_SCHEDULER_shutdown (); 657 return; 658 } 659 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 660 "account_set_kyc_status (%s, %u, %s, %s) returned %d\n", 661 i->e->keys->exchange_url, 662 i->last_http_status, 663 i->auth_ok ? "auth OK" : "auth needed", 664 NULL == i->jlimits ? "default limits" : "custom limits", 665 (int) qs); 666 i->not_first_time = true; 667 } 668 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 669 "Will repeat inquiry in %s\n", 670 GNUNET_TIME_relative2s ( 671 GNUNET_TIME_absolute_get_remaining (i->due), 672 true)); 673 if (! GNUNET_TIME_absolute_is_never (i->due)) 674 i->task = GNUNET_SCHEDULER_add_at (i->due, 675 &inquiry_work, 676 i); 677 end_inquiry (); 678 } 679 680 681 static void 682 inquiry_work (void *cls) 683 { 684 struct Inquiry *i = cls; 685 enum TALER_EXCHANGE_KycLongPollTarget lpt; 686 687 i->task = NULL; 688 if (! GNUNET_TIME_absolute_is_past (i->due)) 689 { 690 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 691 "Will start inquiry on %s for %s in %s\n", 692 i->a->merchant_account_uri.full_payto, 693 i->e->keys->exchange_url, 694 GNUNET_TIME_relative2s ( 695 GNUNET_TIME_absolute_get_remaining (i->due), 696 true)); 697 i->task 698 = GNUNET_SCHEDULER_add_at (i->due, 699 &inquiry_work, 700 i); 701 goto finish; 702 } 703 704 GNUNET_assert (OPEN_INQUIRY_LIMIT >= active_inquiries); 705 if (OPEN_INQUIRY_LIMIT <= active_inquiries) 706 { 707 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 708 "Not looking for work: at limit\n"); 709 i->limited = true; 710 at_limit = true; 711 return; 712 } 713 at_limit = false; 714 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 715 "Checking KYC status of `%s' at `%s'\n", 716 i->a->merchant_account_uri.full_payto, 717 i->e->keys->exchange_url); 718 i->timeout 719 = GNUNET_TIME_relative_to_absolute (EXCHANGE_TIMEOUT); 720 lpt = TALER_EXCHANGE_KLPT_NONE; 721 if (! i->auth_ok) 722 lpt = TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER; 723 else if (! i->kyc_ok) 724 lpt = TALER_EXCHANGE_KLPT_KYC_OK; 725 else if (i->aml_review) 726 lpt = TALER_EXCHANGE_KLPT_INVESTIGATION_DONE; 727 if (! i->not_first_time) 728 lpt = TALER_EXCHANGE_KLPT_NONE; 729 i->kyc = TALER_EXCHANGE_kyc_check ( 730 ctx, 731 i->e->keys->exchange_url, 732 &i->a->h_payto, 733 &i->a->ap, 734 i->rule_gen, 735 lpt, 736 i->not_first_time && (! test_mode) 737 ? EXCHANGE_TIMEOUT 738 : GNUNET_TIME_UNIT_ZERO, 739 &exchange_check_cb, 740 i); 741 if (NULL == i->kyc) 742 { 743 GNUNET_break (0); 744 i->due = i->timeout; 745 i->task 746 = GNUNET_SCHEDULER_add_at (i->due, 747 &inquiry_work, 748 i); 749 goto finish; 750 } 751 active_inquiries++; 752 finish: 753 if ( (0 == active_inquiries) && 754 (test_mode) ) 755 { 756 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 757 "No more open inquiries and in test mode. Existing.\n"); 758 GNUNET_SCHEDULER_shutdown (); 759 return; 760 } 761 } 762 763 764 /** 765 * Check if the account @a could work with exchange that 766 * has keys @a keys. 767 * 768 * @param keys the keys of an exchange 769 * @param a an account 770 */ 771 static bool 772 is_eligible (const struct TALER_EXCHANGE_Keys *keys, 773 const struct Account *a) 774 { 775 struct TALER_NormalizedPayto np; 776 bool ret; 777 778 np = TALER_payto_normalize (a->merchant_account_uri); 779 ret = TALER_EXCHANGE_keys_test_account_allowed (keys, 780 true, 781 np); 782 GNUNET_free (np.normalized_payto); 783 return ret; 784 } 785 786 787 /** 788 * Start the KYC checking for account @a at exchange @a e. 789 * 790 * @param e an exchange 791 * @param a an account 792 */ 793 static void 794 start_inquiry (struct Exchange *e, 795 struct Account *a) 796 { 797 struct Inquiry *i; 798 enum GNUNET_DB_QueryStatus qs; 799 800 i = GNUNET_new (struct Inquiry); 801 i->e = e; 802 i->a = a; 803 GNUNET_CONTAINER_DLL_insert (a->i_head, 804 a->i_tail, 805 i); 806 qs = db_plugin->get_kyc_status (db_plugin->cls, 807 a->merchant_account_uri, 808 a->instance_id, 809 e->keys->exchange_url, 810 &i->auth_ok, 811 &i->access_token, 812 &i->kyc_ok, 813 &i->last_http_status, 814 &i->last_ec, 815 &i->rule_gen, 816 &i->last_kyc_check, 817 &i->aml_review, 818 &i->jlimits); 819 if (qs < 0) 820 { 821 GNUNET_break (0); 822 global_ret = EXIT_FAILURE; 823 GNUNET_SCHEDULER_shutdown (); 824 return; 825 } 826 if (qs > 0) 827 i->not_first_time = true; 828 switch (i->last_http_status) 829 { 830 case MHD_HTTP_OK: 831 /* KYC is OK, but we could have missed some triggers, 832 so let's check, but slowly within the next minute 833 so that we do not overdo it if this process happens 834 to be restarted a lot. */ 835 if (GNUNET_YES != test_mode) 836 { 837 i->due = GNUNET_TIME_relative_to_absolute ( 838 GNUNET_TIME_randomize (GNUNET_TIME_UNIT_MINUTES)); 839 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 840 "Previous KYC status is OK, randomizing inquiry to start at %s\n", 841 GNUNET_TIME_absolute2s (i->due)); 842 } 843 break; 844 case MHD_HTTP_ACCEPTED: 845 /* KYC required, due immediately */ 846 break; 847 case MHD_HTTP_NO_CONTENT: 848 /* KYC is OFF, only check again if triggered */ 849 if (GNUNET_YES != test_mode) 850 { 851 i->due = GNUNET_TIME_relative_to_absolute ( 852 GNUNET_TIME_randomize (aml_low_freq)); 853 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 854 "KYC was disabled, randomizing inquiry to start at %s\n", 855 GNUNET_TIME_absolute2s (i->due)); 856 } 857 break; 858 case MHD_HTTP_FORBIDDEN: /* bad signature */ 859 case MHD_HTTP_NOT_FOUND: /* account unknown */ 860 case MHD_HTTP_CONFLICT: /* no account_pub known */ 861 /* go immediately into long-polling */ 862 break; 863 default: 864 /* start with decent back-off after hard failure */ 865 if (GNUNET_YES != test_mode) 866 { 867 i->backoff 868 = GNUNET_TIME_randomize (GNUNET_TIME_UNIT_MINUTES); 869 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 870 "Last KYC check failed, starting with backoff %s\n", 871 GNUNET_TIME_relative2s (i->backoff, 872 true)); 873 } 874 break; 875 } 876 inquiry_work (i); 877 } 878 879 880 /** 881 * Stop KYC inquiry @a i. 882 * 883 * @param[in] i the inquiry to stop 884 */ 885 static void 886 stop_inquiry (struct Inquiry *i) 887 { 888 struct Account *a = i->a; 889 890 GNUNET_CONTAINER_DLL_remove (a->i_head, 891 a->i_tail, 892 i); 893 if (NULL != i->task) 894 { 895 GNUNET_SCHEDULER_cancel (i->task); 896 i->task = NULL; 897 } 898 if (NULL != i->kyc) 899 { 900 TALER_EXCHANGE_kyc_check_cancel (i->kyc); 901 i->kyc = NULL; 902 } 903 if (NULL != i->jlimits) 904 { 905 json_decref (i->jlimits); 906 i->jlimits = NULL; 907 } 908 GNUNET_free (i); 909 } 910 911 912 /** 913 * Stop KYC inquiry for account @a at exchange @a e. 914 * 915 * @param e an exchange 916 * @param a an account 917 */ 918 static void 919 stop_inquiry_at (struct Exchange *e, 920 struct Account *a) 921 { 922 for (struct Inquiry *i = a->i_head; 923 NULL != i; 924 i = i->next) 925 { 926 if (e == i->e) 927 { 928 stop_inquiry (i); 929 return; 930 } 931 } 932 /* strange, there should have been a match! */ 933 GNUNET_break (0); 934 } 935 936 937 /** 938 * Start inquries for all exchanges on account @a a. 939 * 940 * @param a an account 941 */ 942 static void 943 start_inquiries (struct Account *a) 944 { 945 for (struct Exchange *e = e_head; 946 NULL != e; 947 e = e->next) 948 { 949 if (is_eligible (e->keys, 950 a)) 951 start_inquiry (e, 952 a); 953 else 954 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 955 "Account %s not eligible at exchange %s\n", 956 a->merchant_account_uri.full_payto, 957 e->keys->exchange_url); 958 } 959 } 960 961 962 /** 963 * Stop all inquries involving account @a a. 964 * 965 * @param a an account 966 */ 967 static void 968 stop_inquiries (struct Account *a) 969 { 970 struct Inquiry *i; 971 972 while (NULL != (i = a->i_head)) 973 stop_inquiry (i); 974 } 975 976 977 /** 978 * Callback invoked with information about a bank account. 979 * 980 * @param cls closure 981 * @param merchant_priv private key of the merchant instance 982 * @param ad details about the account 983 */ 984 static void 985 account_cb ( 986 void *cls, 987 const struct TALER_MerchantPrivateKeyP *merchant_priv, 988 const struct TALER_MERCHANTDB_AccountDetails *ad) 989 { 990 struct TALER_FullPayto payto_uri = ad->payto_uri; 991 992 if (! ad->active) 993 return; 994 if (NULL == merchant_priv) 995 return; /* instance was deleted */ 996 for (struct Account *a = a_head; 997 NULL != a; 998 a = a->next) 999 { 1000 if (0 == 1001 TALER_full_payto_cmp (payto_uri, 1002 a->merchant_account_uri)) 1003 { 1004 a->account_gen = database_gen; 1005 return; 1006 } 1007 } 1008 { 1009 struct Account *a = GNUNET_new (struct Account); 1010 1011 a->account_gen = database_gen; 1012 a->merchant_account_uri.full_payto 1013 = GNUNET_strdup (ad->payto_uri.full_payto); 1014 a->instance_id 1015 = GNUNET_strdup (ad->instance_id); 1016 a->h_wire 1017 = ad->h_wire; 1018 a->ap.merchant_priv 1019 = *merchant_priv; 1020 TALER_full_payto_normalize_and_hash (a->merchant_account_uri, 1021 &a->h_payto); 1022 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1023 "Found account %s of instance %s with H_PAYTO %s\n", 1024 ad->payto_uri.full_payto, 1025 ad->instance_id, 1026 GNUNET_sh2s (&a->h_payto.hash)); 1027 GNUNET_CONTAINER_DLL_insert (a_head, 1028 a_tail, 1029 a); 1030 start_inquiries (a); 1031 } 1032 } 1033 1034 1035 /** 1036 * The set of bank accounts has changed, update our 1037 * list of active inquiries. 1038 * 1039 * @param cls unused 1040 */ 1041 static void 1042 find_accounts (void *cls) 1043 { 1044 enum GNUNET_DB_QueryStatus qs; 1045 1046 (void) cls; 1047 account_task = NULL; 1048 database_gen++; 1049 qs = db_plugin->select_accounts (db_plugin->cls, 1050 NULL, /* all instances */ 1051 &account_cb, 1052 NULL); 1053 if (qs < 0) 1054 { 1055 GNUNET_break (0); 1056 return; 1057 } 1058 for (struct Account *a = a_head; 1059 NULL != a; 1060 a = a->next) 1061 { 1062 if (a->account_gen < database_gen) 1063 stop_inquiries (a); 1064 } 1065 } 1066 1067 1068 /** 1069 * Function called when transfers are added to the merchant database. We look 1070 * for more work. 1071 * 1072 * @param cls closure (NULL) 1073 * @param extra additional event data provided 1074 * @param extra_size number of bytes in @a extra 1075 */ 1076 static void 1077 account_changed (void *cls, 1078 const void *extra, 1079 size_t extra_size) 1080 { 1081 (void) cls; 1082 (void) extra; 1083 (void) extra_size; 1084 if (NULL != account_task) 1085 return; 1086 account_task 1087 = GNUNET_SCHEDULER_add_now (&find_accounts, 1088 NULL); 1089 } 1090 1091 1092 /** 1093 * Interact with the database to get the current set 1094 * of exchange keys known to us. 1095 * 1096 * @param exchange_url the exchange URL to check 1097 */ 1098 static void 1099 find_keys (const char *exchange_url) 1100 { 1101 enum GNUNET_DB_QueryStatus qs; 1102 struct TALER_EXCHANGE_Keys *keys; 1103 struct Exchange *e; 1104 struct GNUNET_TIME_Absolute first_retry; 1105 1106 qs = db_plugin->select_exchange_keys (db_plugin->cls, 1107 exchange_url, 1108 &first_retry, 1109 &keys); 1110 if (qs < 0) 1111 { 1112 GNUNET_break (0); 1113 return; 1114 } 1115 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) 1116 { 1117 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1118 "No %s/keys yet!\n", 1119 exchange_url); 1120 return; 1121 } 1122 for (e = e_head; NULL != e; e = e->next) 1123 { 1124 if (0 == strcmp (e->keys->exchange_url, 1125 keys->exchange_url)) 1126 { 1127 struct TALER_EXCHANGE_Keys *old_keys = e->keys; 1128 1129 e->keys = keys; 1130 for (struct Account *a = a_head; 1131 NULL != a; 1132 a = a->next) 1133 { 1134 bool was_eligible = is_eligible (old_keys, 1135 a); 1136 bool now_eligible = is_eligible (keys, 1137 a); 1138 1139 if (was_eligible == now_eligible) 1140 continue; /* no change, do nothing */ 1141 if (was_eligible) 1142 stop_inquiry_at (e, 1143 a); 1144 else /* is_eligible */ 1145 start_inquiry (e, 1146 a); 1147 } 1148 TALER_EXCHANGE_keys_decref (old_keys); 1149 return; 1150 } 1151 } 1152 e = GNUNET_new (struct Exchange); 1153 e->keys = keys; 1154 GNUNET_CONTAINER_DLL_insert (e_head, 1155 e_tail, 1156 e); 1157 for (struct Account *a = a_head; 1158 NULL != a; 1159 a = a->next) 1160 { 1161 if ( (a->account_gen == database_gen) && 1162 (is_eligible (e->keys, 1163 a)) ) 1164 start_inquiry (e, 1165 a); 1166 } 1167 } 1168 1169 1170 /** 1171 * Function called when keys were changed in the 1172 * merchant database. Updates ours. 1173 * 1174 * @param cls closure (NULL) 1175 * @param extra additional event data provided 1176 * @param extra_size number of bytes in @a extra 1177 */ 1178 static void 1179 keys_changed (void *cls, 1180 const void *extra, 1181 size_t extra_size) 1182 { 1183 const char *url = extra; 1184 1185 (void) cls; 1186 if ( (NULL == extra) || 1187 (0 == extra_size) ) 1188 { 1189 GNUNET_break (0); 1190 return; 1191 } 1192 if ('\0' != url[extra_size - 1]) 1193 { 1194 GNUNET_break (0); 1195 return; 1196 } 1197 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1198 "Received keys change notification: reload `%s'\n", 1199 url); 1200 find_keys (url); 1201 } 1202 1203 1204 /** 1205 * Function called when a KYC rule was triggered by 1206 * a transaction and we need to get the latest KYC 1207 * status immediately. 1208 * 1209 * @param cls closure (NULL) 1210 * @param extra additional event data provided 1211 * @param extra_size number of bytes in @a extra 1212 */ 1213 static void 1214 rule_triggered (void *cls, 1215 const void *extra, 1216 size_t extra_size) 1217 { 1218 const char *text = extra; 1219 const char *space; 1220 struct TALER_MerchantWireHashP h_wire; 1221 const char *exchange_url; 1222 1223 (void) cls; 1224 if ( (NULL == extra) || 1225 (0 == extra_size) ) 1226 { 1227 GNUNET_break (0); 1228 return; 1229 } 1230 if ('\0' != text[extra_size - 1]) 1231 { 1232 GNUNET_break (0); 1233 return; 1234 } 1235 space = memchr (extra, 1236 ' ', 1237 extra_size); 1238 if (NULL == space) 1239 { 1240 GNUNET_break (0); 1241 return; 1242 } 1243 if (GNUNET_OK != 1244 GNUNET_STRINGS_string_to_data (extra, 1245 space - text, 1246 &h_wire, 1247 sizeof (h_wire))) 1248 { 1249 GNUNET_break (0); 1250 return; 1251 } 1252 exchange_url = &space[1]; 1253 if (! TALER_is_web_url (exchange_url)) 1254 { 1255 GNUNET_break (0); 1256 return; 1257 } 1258 1259 for (struct Account *a = a_head; 1260 NULL != a; 1261 a = a->next) 1262 { 1263 if (0 != 1264 GNUNET_memcmp (&h_wire, 1265 &a->h_wire)) 1266 continue; 1267 for (struct Inquiry *i = a->i_head; 1268 NULL != i; 1269 i = i->next) 1270 { 1271 if (0 != strcmp (exchange_url, 1272 i->e->keys->exchange_url)) 1273 continue; 1274 i->kyc_ok = false; 1275 i->due = GNUNET_TIME_UNIT_ZERO_ABS; 1276 if (NULL != i->task) 1277 { 1278 GNUNET_SCHEDULER_cancel (i->task); 1279 i->task = NULL; 1280 } 1281 if (NULL != i->kyc) 1282 { 1283 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1284 "/kyc-check already running for %s\n", 1285 text); 1286 return; 1287 } 1288 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1289 "Starting %skyc-check for `%s' due to KYC rule trigger\n", 1290 exchange_url, 1291 i->a->merchant_account_uri.full_payto); 1292 i->task = GNUNET_SCHEDULER_add_at (i->due, 1293 &inquiry_work, 1294 i); 1295 return; 1296 } 1297 } 1298 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1299 "KYC rule trigger notification `%s' matches none of our accounts\n", 1300 text); 1301 } 1302 1303 1304 /** 1305 * Function called on each configuration section. Finds sections 1306 * about exchanges, parses the entries. 1307 * 1308 * @param cls NULL 1309 * @param section name of the section 1310 */ 1311 static void 1312 accept_exchanges (void *cls, 1313 const char *section) 1314 { 1315 char *url; 1316 1317 (void) cls; 1318 if (0 != 1319 strncasecmp (section, 1320 "merchant-exchange-", 1321 strlen ("merchant-exchange-"))) 1322 return; 1323 if (GNUNET_YES == 1324 GNUNET_CONFIGURATION_get_value_yesno (cfg, 1325 section, 1326 "DISABLED")) 1327 return; 1328 if (GNUNET_OK != 1329 GNUNET_CONFIGURATION_get_value_string (cfg, 1330 section, 1331 "EXCHANGE_BASE_URL", 1332 &url)) 1333 { 1334 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1335 section, 1336 "EXCHANGE_BASE_URL"); 1337 global_ret = EXIT_NOTCONFIGURED; 1338 GNUNET_SCHEDULER_shutdown (); 1339 return; 1340 } 1341 find_keys (url); 1342 GNUNET_free (url); 1343 } 1344 1345 1346 /** 1347 * We're being aborted with CTRL-C (or SIGTERM). Shut down. 1348 * 1349 * @param cls closure (NULL) 1350 */ 1351 static void 1352 shutdown_task (void *cls) 1353 { 1354 (void) cls; 1355 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1356 "Running shutdown\n"); 1357 while (NULL != e_head) 1358 { 1359 struct Exchange *e = e_head; 1360 1361 if (NULL != e->keys) 1362 { 1363 TALER_EXCHANGE_keys_decref (e->keys); 1364 e->keys = NULL; 1365 } 1366 GNUNET_CONTAINER_DLL_remove (e_head, 1367 e_tail, 1368 e); 1369 GNUNET_free (e); 1370 } 1371 while (NULL != a_head) 1372 { 1373 struct Account *a = a_head; 1374 1375 stop_inquiries (a); 1376 GNUNET_CONTAINER_DLL_remove (a_head, 1377 a_tail, 1378 a); 1379 GNUNET_free (a->merchant_account_uri.full_payto); 1380 GNUNET_free (a->instance_id); 1381 GNUNET_free (a); 1382 } 1383 if (NULL != eh_accounts) 1384 { 1385 db_plugin->event_listen_cancel (eh_accounts); 1386 eh_accounts = NULL; 1387 } 1388 if (NULL != account_task) 1389 { 1390 GNUNET_SCHEDULER_cancel (account_task); 1391 account_task = NULL; 1392 } 1393 if (NULL != eh_keys) 1394 { 1395 db_plugin->event_listen_cancel (eh_keys); 1396 eh_keys = NULL; 1397 } 1398 if (NULL != eh_rule) 1399 { 1400 db_plugin->event_listen_cancel (eh_rule); 1401 eh_rule = NULL; 1402 } 1403 TALER_MERCHANTDB_plugin_unload (db_plugin); 1404 db_plugin = NULL; 1405 cfg = NULL; 1406 if (NULL != ctx) 1407 { 1408 GNUNET_CURL_fini (ctx); 1409 ctx = NULL; 1410 } 1411 if (NULL != rc) 1412 { 1413 GNUNET_CURL_gnunet_rc_destroy (rc); 1414 rc = NULL; 1415 } 1416 } 1417 1418 1419 /** 1420 * First task. 1421 * 1422 * @param cls closure, NULL 1423 * @param args remaining command-line arguments 1424 * @param cfgfile name of the configuration file used (for saving, can be NULL!) 1425 * @param c configuration 1426 */ 1427 static void 1428 run (void *cls, 1429 char *const *args, 1430 const char *cfgfile, 1431 const struct GNUNET_CONFIGURATION_Handle *c) 1432 { 1433 (void) args; 1434 (void) cfgfile; 1435 1436 cfg = c; 1437 if (GNUNET_OK != 1438 GNUNET_CONFIGURATION_get_value_time (cfg, 1439 "merchant-kyccheck", 1440 "AML_FREQ", 1441 &aml_freq)) 1442 { 1443 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, 1444 "merchant-kyccheck", 1445 "AML_FREQ"); 1446 /* use default */ 1447 aml_freq = AML_FREQ; 1448 } 1449 if (GNUNET_OK != 1450 GNUNET_CONFIGURATION_get_value_time (cfg, 1451 "merchant-kyccheck", 1452 "AML_LOW_FREQ", 1453 &aml_low_freq)) 1454 { 1455 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, 1456 "merchant-kyccheck", 1457 "AML_LOW_FREQ"); 1458 /* use default */ 1459 aml_low_freq = AML_LOW_FREQ; 1460 } 1461 if (GNUNET_TIME_relative_cmp (aml_low_freq, 1462 <, 1463 aml_freq)) 1464 { 1465 aml_low_freq = GNUNET_TIME_relative_multiply (aml_freq, 1466 10); 1467 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1468 "AML_LOW_FREQ was set to less than AML_FREQ. Using %s instead\n", 1469 GNUNET_TIME_relative2s (aml_low_freq, 1470 true)); 1471 } 1472 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1473 NULL); 1474 ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, 1475 &rc); 1476 rc = GNUNET_CURL_gnunet_rc_create (ctx); 1477 if (NULL == ctx) 1478 { 1479 GNUNET_break (0); 1480 GNUNET_SCHEDULER_shutdown (); 1481 global_ret = EXIT_FAILURE; 1482 return; 1483 } 1484 if (NULL == 1485 (db_plugin = TALER_MERCHANTDB_plugin_load (cfg))) 1486 { 1487 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1488 "Failed to initialize DB subsystem\n"); 1489 GNUNET_SCHEDULER_shutdown (); 1490 global_ret = EXIT_NOTCONFIGURED; 1491 return; 1492 } 1493 if (GNUNET_OK != 1494 db_plugin->connect (db_plugin->cls)) 1495 { 1496 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1497 "Failed to connect to database. Consider running taler-merchant-dbinit.\n"); 1498 GNUNET_SCHEDULER_shutdown (); 1499 global_ret = EXIT_FAILURE; 1500 return; 1501 } 1502 { 1503 struct GNUNET_DB_EventHeaderP es = { 1504 .size = htons (sizeof (es)), 1505 .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KEYS) 1506 }; 1507 1508 eh_keys 1509 = db_plugin->event_listen (db_plugin->cls, 1510 &es, 1511 GNUNET_TIME_UNIT_FOREVER_REL, 1512 &keys_changed, 1513 NULL); 1514 } 1515 { 1516 struct GNUNET_DB_EventHeaderP es = { 1517 .size = htons (sizeof (es)), 1518 .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_RULE_TRIGGERED) 1519 }; 1520 1521 eh_rule 1522 = db_plugin->event_listen (db_plugin->cls, 1523 &es, 1524 GNUNET_TIME_UNIT_FOREVER_REL, 1525 &rule_triggered, 1526 NULL); 1527 } 1528 GNUNET_CONFIGURATION_iterate_sections (cfg, 1529 &accept_exchanges, 1530 NULL); 1531 { 1532 struct GNUNET_DB_EventHeaderP es = { 1533 .size = htons (sizeof (es)), 1534 .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED) 1535 }; 1536 1537 eh_accounts 1538 = db_plugin->event_listen (db_plugin->cls, 1539 &es, 1540 GNUNET_TIME_UNIT_FOREVER_REL, 1541 &account_changed, 1542 NULL); 1543 } 1544 GNUNET_assert (NULL == account_task); 1545 account_task 1546 = GNUNET_SCHEDULER_add_now (&find_accounts, 1547 NULL); 1548 } 1549 1550 1551 /** 1552 * The main function of taler-merchant-kyccheck 1553 * 1554 * @param argc number of arguments from the command line 1555 * @param argv command line arguments 1556 * @return 0 ok, 1 on error 1557 */ 1558 int 1559 main (int argc, 1560 char *const *argv) 1561 { 1562 struct GNUNET_GETOPT_CommandLineOption options[] = { 1563 GNUNET_GETOPT_option_timetravel ('T', 1564 "timetravel"), 1565 GNUNET_GETOPT_option_flag ('t', 1566 "test", 1567 "run in test mode and exit when idle", 1568 &test_mode), 1569 GNUNET_GETOPT_option_version (VERSION "-" VCS_VERSION), 1570 GNUNET_GETOPT_OPTION_END 1571 }; 1572 enum GNUNET_GenericReturnValue ret; 1573 1574 ret = GNUNET_PROGRAM_run ( 1575 TALER_MERCHANT_project_data (), 1576 argc, argv, 1577 "taler-merchant-kyccheck", 1578 gettext_noop ( 1579 "background process that checks the KYC state of our bank accounts at various exchanges"), 1580 options, 1581 &run, NULL); 1582 if (GNUNET_SYSERR == ret) 1583 return EXIT_INVALIDARGUMENT; 1584 if (GNUNET_NO == ret) 1585 return EXIT_SUCCESS; 1586 return global_ret; 1587 } 1588 1589 1590 /* end of taler-merchant-kyccheck.c */