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