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