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