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