taler-exchange-httpd_common_kyc.c (47138B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2023, 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-exchange-httpd_common_kyc.c 18 * @brief shared logic for finishing a KYC process 19 * @author Christian Grothoff 20 */ 21 #include "taler-exchange-httpd.h" 22 #include "exchange-database/do_trigger_kyc_rule_for_account.h" 23 #include "taler-exchange-httpd_common_kyc.h" 24 #include "taler/taler_attributes.h" 25 #include "taler/taler_error_codes.h" 26 #include "taler/taler_kyclogic_lib.h" 27 #include "exchangedb_lib.h" 28 #include <gnunet/gnunet_common.h> 29 #include "exchange-database/commit.h" 30 #include "exchange-database/get_kyc_rules.h" 31 #include "exchange-database/insert_aml_decision.h" 32 #include "exchange-database/insert_kyc_failure.h" 33 #include "exchange-database/insert_legitimization_process.h" 34 #include "exchange-database/get_active_legitimization.h" 35 #include "exchange-database/do_insert_kyc_attributes.h" 36 #include "exchange-database/preflight.h" 37 #include "exchange-database/rollback.h" 38 #include "exchange-database/start.h" 39 struct TEH_LegitimizationCheckHandle; 40 #define TALER_EXCHANGEDB_CURRENT_RULES_RESULT_CLOSURE \ 41 struct TEH_LegitimizationCheckHandle 42 #include "exchange-database/begin_rule_update.h" 43 #include "exchange-database/account_history.h" 44 #include "exchange-database/do_persist_aml_program_result.h" 45 46 47 /** 48 * How often do we allow a legitimization rule to 49 * automatically trigger the next rule before bailing 50 * out? 51 */ 52 #define MAX_LEGI_LOOPS 5 53 54 /** 55 * Enable additional sanity-checks for debugging? 56 */ 57 #define EXTRA_CHECK 0 58 59 /** 60 * Enable extra logging that may include sensitive data? 61 */ 62 #define DEBUG 1 63 64 65 struct TEH_KycMeasureRunContext 66 { 67 68 /** 69 * Our logging scope. 70 */ 71 struct GNUNET_AsyncScopeId scope; 72 73 /** 74 * account the operation is about 75 */ 76 struct TALER_NormalizedPaytoHashP account_id; 77 78 /** 79 * legitimization process the KYC data is about 80 */ 81 uint64_t process_row; 82 83 /** 84 * function to call with the result 85 */ 86 TEH_KycMeasureRunContextCallback cb; 87 88 /** 89 * closure for @e cb 90 */ 91 void *cb_cls; 92 93 /** 94 * Handle to fallback processing. 95 */ 96 struct TEH_KycAmlFallback *fb; 97 98 /** 99 * Name of the fallback @e fb is running (or NULL). 100 */ 101 char *fallback_name; 102 103 /** 104 * Measures this KYC process is responding to. 105 */ 106 json_t *jmeasures; 107 108 /** 109 * Handle to an external process that evaluates the 110 * need to run AML on the account. 111 */ 112 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *kyc_aml; 113 114 /** 115 * Task scheduled to return a result asynchronously. 116 */ 117 struct GNUNET_SCHEDULER_Task *async_task; 118 119 /** 120 * KYC measure the client is (trying to) satisfy. 121 */ 122 uint32_t measure_index; 123 124 /** 125 * True if @e account_id is for a wallet. 126 */ 127 bool is_wallet; 128 }; 129 130 131 /** 132 * Function called with the result of activating a 133 * fallback measure. 134 * 135 * @param cls a `struct TEH_KycMeasureRunContext *` 136 * @param fallback_ok true if the fallback was activated 137 * successfully 138 * @param requirement_row row of 139 * new KYC requirement that was created, 0 for none 140 */ 141 static void 142 fallback_result_cb (void *cls, 143 bool fallback_ok, 144 uint64_t requirement_row) 145 { 146 struct TEH_KycMeasureRunContext *kat = cls; 147 struct GNUNET_AsyncScopeSave old_scope; 148 149 kat->fb = NULL; 150 (void) requirement_row; 151 GNUNET_async_scope_enter (&kat->scope, 152 &old_scope); 153 if (fallback_ok) 154 { 155 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 156 "Fallback completed (row %llu)\n", 157 (unsigned long long) requirement_row); 158 /* For the HTTP client, us running the fallback 159 should not become a visible failure, after all 160 the fallback should put the account back into 161 a "correct" state (even if that is a deny-all 162 or manual review). Hence we do not return an 163 error here. */ 164 kat->cb (kat->cb_cls, 165 TALER_EC_NONE, 166 NULL); 167 } 168 else 169 { 170 GNUNET_break (0); 171 kat->cb (kat->cb_cls, 172 TALER_EC_EXCHANGE_GENERIC_KYC_FALLBACK_FAILED, 173 kat->fallback_name); 174 } 175 TEH_kyc_run_measure_cancel (kat); 176 GNUNET_async_scope_restore (&old_scope); 177 } 178 179 180 /** 181 * Handle the AML program result @a apr for the KYC measure in @a cls. 182 * 183 * @param cls closure of type `struct TEH_KycMeasureRunContext *` 184 * @param apr AML program result 185 */ 186 static void 187 kyc_aml_finished ( 188 void *cls, 189 const struct TALER_KYCLOGIC_AmlProgramResult *apr) 190 { 191 struct TEH_KycMeasureRunContext *kat = cls; 192 enum GNUNET_DB_QueryStatus qs; 193 struct GNUNET_AsyncScopeSave old_scope; 194 enum TALER_EXCHANGEDB_PersistProgramResultStatus pprs; 195 196 kat->kyc_aml = NULL; 197 if (NULL != kat->async_task) 198 { 199 GNUNET_SCHEDULER_cancel (kat->async_task); 200 kat->async_task = NULL; 201 } 202 GNUNET_async_scope_enter (&kat->scope, 203 &old_scope); 204 GNUNET_break (GNUNET_OK == 205 TALER_EXCHANGEDB_preflight (TEH_pg)); 206 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 207 "AML program finished with status %d\n", 208 (int) apr->status); 209 qs = TALER_EXCHANGEDB_do_persist_aml_program_result ( 210 TEH_pg, 211 kat->process_row, 212 &kat->account_id, 213 apr, 214 &pprs); 215 switch (qs) 216 { 217 case GNUNET_DB_STATUS_HARD_ERROR: 218 case GNUNET_DB_STATUS_SOFT_ERROR: 219 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 220 GNUNET_break (0); 221 kat->cb (kat->cb_cls, 222 TALER_EC_GENERIC_DB_STORE_FAILED, 223 "persist_aml_program_result"); 224 TEH_kyc_run_measure_cancel (kat); 225 GNUNET_async_scope_restore (&old_scope); 226 return; 227 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 228 break; 229 } 230 switch (pprs) 231 { 232 case TALER_EXCHANGEDB_PPRS_OK: 233 break; 234 case TALER_EXCHANGEDB_PPRS_BAD_OUTCOME: 235 GNUNET_break (0); 236 kat->cb (kat->cb_cls, 237 TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT, 238 "persist_aml_program_result"); 239 TEH_kyc_run_measure_cancel (kat); 240 GNUNET_async_scope_restore (&old_scope); 241 return; 242 } 243 switch (apr->status) 244 { 245 case TALER_KYCLOGIC_AMLR_FAILURE: 246 if (NULL == apr->details.failure.fallback_measure) 247 { 248 /* Not sure this can happen (fallback required?), 249 but report AML program failure to client */ 250 GNUNET_break (0); 251 kat->cb (kat->cb_cls, 252 TALER_EC_EXCHANGE_KYC_AML_PROGRAM_FAILURE, 253 NULL); 254 break; 255 } 256 kat->fallback_name 257 = GNUNET_strdup ( 258 apr->details.failure.fallback_measure); 259 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 260 "AML program failed, running fallback %s\n", 261 kat->fallback_name); 262 kat->fb 263 = TEH_kyc_fallback ( 264 &kat->scope, 265 &kat->account_id, 266 kat->is_wallet, 267 kat->process_row, 268 kat->fallback_name, 269 &fallback_result_cb, 270 kat); 271 if (NULL == kat->fb) 272 { 273 GNUNET_break (0); 274 kat->cb (kat->cb_cls, 275 TALER_EC_EXCHANGE_GENERIC_KYC_FALLBACK_UNKNOWN, 276 kat->fallback_name); 277 break; 278 } 279 /* continued in fallback_result_cb */ 280 GNUNET_async_scope_restore (&old_scope); 281 return; 282 case TALER_KYCLOGIC_AMLR_SUCCESS: 283 /* Finally, return result to main handler */ 284 kat->cb (kat->cb_cls, 285 TALER_EC_NONE, 286 0); 287 break; 288 } 289 TEH_kyc_run_measure_cancel (kat); 290 GNUNET_async_scope_restore (&old_scope); 291 } 292 293 294 void 295 TEH_kyc_run_measure_cancel (struct TEH_KycMeasureRunContext *kat) 296 { 297 if (NULL != kat->kyc_aml) 298 { 299 TALER_KYCLOGIC_run_aml_program_cancel (kat->kyc_aml); 300 kat->kyc_aml = NULL; 301 } 302 if (NULL != kat->fb) 303 { 304 TEH_kyc_fallback_cancel (kat->fb); 305 kat->fb = NULL; 306 } 307 if (NULL != kat->async_task) 308 { 309 GNUNET_SCHEDULER_cancel (kat->async_task); 310 kat->async_task = NULL; 311 } 312 GNUNET_free (kat->fallback_name); 313 json_decref (kat->jmeasures); 314 GNUNET_free (kat); 315 } 316 317 318 enum GNUNET_DB_QueryStatus 319 TEH_kyc_store_attributes ( 320 uint64_t process_row, 321 const struct TALER_NormalizedPaytoHashP *account_id, 322 const char *provider_name, 323 const char *provider_user_id, 324 const char *provider_legitimization_id, 325 struct GNUNET_TIME_Absolute expiration, 326 const json_t *new_attributes) 327 { 328 enum GNUNET_DB_QueryStatus qs; 329 unsigned int birthday = 0; 330 size_t eas = 0; 331 void *ea = NULL; 332 const char *form_id = NULL; 333 334 if (TEH_age_restriction_enabled) 335 { 336 const char *birthdate; 337 338 birthdate = json_string_value ( 339 json_object_get (new_attributes, 340 TALER_ATTRIBUTE_BIRTHDATE)); 341 if (NULL != birthdate) 342 { 343 enum GNUNET_GenericReturnValue ret; 344 345 ret = TALER_parse_coarse_date (birthdate, 346 &TEH_age_restriction_mask, 347 &birthday); 348 349 if (GNUNET_OK != ret) 350 { 351 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 352 "Failed to parse birthdate `%s' from KYC attributes of %s\n", 353 birthdate, 354 provider_name); 355 } 356 } 357 } 358 359 if (NULL != new_attributes) 360 { 361 form_id = json_string_value (json_object_get (new_attributes, 362 "FORM_ID")); 363 if (NULL == form_id) 364 { 365 /* invalid input, FORM_ID is mandatory, caller is bad */ 366 GNUNET_break (0); 367 return GNUNET_DB_STATUS_HARD_ERROR; 368 } 369 TALER_CRYPTO_kyc_attributes_encrypt (&TEH_attribute_key, 370 new_attributes, 371 &ea, 372 &eas); 373 } 374 qs = TALER_EXCHANGEDB_do_insert_kyc_attributes ( 375 TEH_pg, 376 process_row, 377 account_id, 378 provider_name, 379 provider_user_id, 380 provider_legitimization_id, 381 birthday, 382 expiration, 383 form_id, 384 eas, 385 ea); 386 GNUNET_free (ea); 387 switch (qs) 388 { 389 case GNUNET_DB_STATUS_HARD_ERROR: 390 GNUNET_break (0); 391 break; 392 case GNUNET_DB_STATUS_SOFT_ERROR: 393 GNUNET_break (0); 394 break; 395 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 396 GNUNET_break (0); 397 break; 398 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 399 break; 400 } 401 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 402 "Stored encrypted KYC process #%llu attributes: %d\n", 403 (unsigned long long) process_row, 404 qs); 405 return qs; 406 } 407 408 409 struct TEH_KycMeasureRunContext * 410 TEH_kyc_run_measure_for_attributes ( 411 const struct GNUNET_AsyncScopeId *scope, 412 uint64_t process_row, 413 const struct TALER_NormalizedPaytoHashP *account_id, 414 bool is_wallet, 415 TEH_KycMeasureRunContextCallback cb, 416 void *cb_cls) 417 { 418 struct TEH_KycMeasureRunContext *kat; 419 enum GNUNET_DB_QueryStatus qs; 420 421 kat = GNUNET_new (struct TEH_KycMeasureRunContext); 422 kat->scope = *scope; 423 kat->process_row = process_row; 424 kat->account_id = *account_id; 425 kat->is_wallet = is_wallet; 426 kat->cb = cb; 427 kat->cb_cls = cb_cls; 428 qs = TALER_EXCHANGEDB_get_active_legitimization ( 429 TEH_pg, 430 process_row, 431 &kat->measure_index, 432 &kat->jmeasures); 433 switch (qs) 434 { 435 case GNUNET_DB_STATUS_HARD_ERROR: 436 case GNUNET_DB_STATUS_SOFT_ERROR: 437 GNUNET_break (0); 438 TEH_kyc_run_measure_cancel (kat); 439 return NULL; 440 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 441 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 442 "No active legitimization for %llu\n", 443 (unsigned long long) process_row); 444 TEH_kyc_run_measure_cancel (kat); 445 return NULL; 446 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 447 break; 448 } 449 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 450 "Running AML program on for current measures\n"); 451 #if DEBUG 452 json_dumpf (kat->jmeasures, 453 stderr, 454 JSON_INDENT (2)); 455 fprintf (stderr, 456 "\n"); 457 #endif 458 { 459 struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = { 460 .account = &kat->account_id, 461 .is_wallet = kat->is_wallet, 462 .pg = TEH_pg, 463 .attribute_key = &TEH_attribute_key 464 }; 465 466 kat->kyc_aml 467 = TALER_KYCLOGIC_run_aml_program ( 468 kat->jmeasures, 469 kat->is_wallet, 470 kat->measure_index, 471 &TALER_EXCHANGEDB_current_attributes_builder, 472 &hbc, 473 &TALER_EXCHANGEDB_current_rule_builder, 474 &hbc, 475 &TALER_EXCHANGEDB_aml_history_builder, 476 &hbc, 477 &TALER_EXCHANGEDB_kyc_history_builder, 478 &hbc, 479 TEH_aml_program_timeout, 480 &kyc_aml_finished, 481 kat); 482 } 483 if (NULL == kat->kyc_aml) 484 { 485 GNUNET_break (0); 486 TEH_kyc_run_measure_cancel (kat); 487 return NULL; 488 } 489 return kat; 490 } 491 492 493 /** 494 * Helper task that asynchronously calls the result 495 * callback and then cleans up. 496 * 497 * @param[in] cls a `struct TEH_KycMeasureRunContext *` 498 */ 499 static void 500 async_return_measure_result (void *cls) 501 { 502 struct TEH_KycMeasureRunContext *kat = cls; 503 504 kat->async_task = NULL; 505 kat->cb (kat->cb_cls, 506 TALER_EC_NONE, 507 NULL); 508 TEH_kyc_run_measure_cancel (kat); 509 } 510 511 512 struct TEH_KycMeasureRunContext * 513 TEH_kyc_run_measure_directly ( 514 const struct GNUNET_AsyncScopeId *scope, 515 const struct TALER_KYCLOGIC_Measure *instant_ms, 516 const struct TALER_NormalizedPaytoHashP *account_id, 517 bool is_wallet, 518 TEH_KycMeasureRunContextCallback cb, 519 void *cb_cls) 520 { 521 struct TEH_KycMeasureRunContext *kat; 522 uint64_t legi_measure_serial_id; 523 bool bad_kyc_auth; 524 enum GNUNET_DB_QueryStatus qs; 525 struct TALER_FullPayto null_account = { 526 .full_payto = NULL 527 }; 528 529 kat = GNUNET_new (struct TEH_KycMeasureRunContext); 530 kat->jmeasures = TALER_KYCLOGIC_measure_to_jmeasures (instant_ms); 531 kat->measure_index = 0; 532 kat->scope = *scope; 533 kat->account_id = *account_id; 534 kat->is_wallet = is_wallet; 535 kat->cb = cb; 536 kat->cb_cls = cb_cls; 537 538 GNUNET_assert (NULL != kat->jmeasures); 539 540 qs = TALER_EXCHANGEDB_do_trigger_kyc_rule_for_account ( 541 TEH_pg, 542 null_account, 543 account_id, 544 NULL, 545 NULL, 546 kat->jmeasures, 547 0, /* no particular priority */ 548 &legi_measure_serial_id, 549 &bad_kyc_auth); 550 switch (qs) 551 { 552 case GNUNET_DB_STATUS_HARD_ERROR: 553 case GNUNET_DB_STATUS_SOFT_ERROR: 554 GNUNET_break (0); 555 TEH_kyc_run_measure_cancel (kat); 556 return NULL; 557 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 558 GNUNET_break (0); 559 TEH_kyc_run_measure_cancel (kat); 560 return NULL; 561 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 562 break; 563 } 564 565 if (0 != 566 strcasecmp (instant_ms->check_name, 567 "SKIP")) 568 { 569 /* Not an instant measure, it's enough to trigger it. 570 The AMP will be run later. */ 571 kat->async_task 572 = GNUNET_SCHEDULER_add_now ( 573 &async_return_measure_result, 574 kat); 575 return kat; 576 } 577 578 qs = TALER_EXCHANGEDB_insert_legitimization_process ( 579 TEH_pg, 580 account_id, 581 0, /* measure index */ 582 legi_measure_serial_id, 583 "SKIP", 584 NULL, /* provider_account_id */ 585 NULL, /* provider_legitimziation_id */ 586 &kat->process_row); 587 if (qs < 0) 588 { 589 GNUNET_break (0); 590 TEH_kyc_run_measure_cancel (kat); 591 return NULL; 592 } 593 { 594 struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = { 595 .account = &kat->account_id, 596 .is_wallet = kat->is_wallet, 597 .pg = TEH_pg, 598 .attribute_key = &TEH_attribute_key 599 }; 600 601 kat->kyc_aml 602 = TALER_KYCLOGIC_run_aml_program3 ( 603 kat->is_wallet, 604 instant_ms, 605 &TALER_EXCHANGEDB_current_attributes_builder, 606 &hbc, 607 &TALER_EXCHANGEDB_current_rule_builder, 608 &hbc, 609 &TALER_EXCHANGEDB_aml_history_builder, 610 &hbc, 611 &TALER_EXCHANGEDB_kyc_history_builder, 612 &hbc, 613 TEH_aml_program_timeout, 614 &kyc_aml_finished, 615 kat); 616 } 617 if (NULL == kat->kyc_aml) 618 { 619 GNUNET_break (0); 620 TEH_kyc_run_measure_cancel (kat); 621 return NULL; 622 } 623 return kat; 624 } 625 626 627 struct TEH_KycAmlFallback 628 { 629 630 /** 631 * Our logging scope. 632 */ 633 struct GNUNET_AsyncScopeId scope; 634 635 /** 636 * Account this is for. 637 */ 638 struct TALER_NormalizedPaytoHashP account_id; 639 640 /** 641 * Function to call when done. 642 */ 643 TEH_KycAmlFallbackCallback cb; 644 645 /** 646 * Closure for @e cb. 647 */ 648 void *cb_cls; 649 650 /** 651 * Handle for asynchronously running AML program. 652 */ 653 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh; 654 655 /** 656 * Task for asynchronously returning of the result. 657 */ 658 struct GNUNET_SCHEDULER_Task *task; 659 660 /** 661 * New requirement row we created, 0 if none. 662 */ 663 uint64_t requirement_row; 664 665 /** 666 * Original requirement row the fallback is for. 667 */ 668 uint64_t orig_requirement_row; 669 670 /** 671 * True if we failed. 672 */ 673 bool failure; 674 675 }; 676 677 678 /** 679 * Handle result from AML fallback program. 680 * 681 * @param cls a `struct TEH_KycAmlFallback` 682 * @param apr AML program result to handle 683 */ 684 static void 685 handle_aml_fallback_result ( 686 void *cls, 687 const struct TALER_KYCLOGIC_AmlProgramResult *apr) 688 { 689 struct TEH_KycAmlFallback *fb = cls; 690 enum GNUNET_DB_QueryStatus qs; 691 struct GNUNET_AsyncScopeSave old_scope; 692 json_t *jmeasures = NULL; 693 struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs = NULL; 694 695 fb->aprh = NULL; 696 GNUNET_async_scope_enter (&fb->scope, 697 &old_scope); 698 if (TALER_KYCLOGIC_AMLR_SUCCESS != apr->status) 699 { 700 if (! TEH_kyc_failed ( 701 fb->orig_requirement_row, 702 &fb->account_id, 703 "FALLBACK", 704 NULL, 705 NULL, 706 apr->details.failure.error_message, 707 apr->details.failure.ec)) 708 { 709 /* triple-bad: error during error handling of fallback */ 710 GNUNET_break (0); 711 fb->cb (fb->cb_cls, 712 false, 713 0); 714 goto cleanup; 715 } 716 /* Fallback not allowed on fallback */ 717 GNUNET_break (0); 718 fb->cb (fb->cb_cls, 719 false, 720 0); 721 goto cleanup; 722 } 723 724 if (NULL != apr->details.success.new_measures) 725 { 726 lrs = TALER_KYCLOGIC_rules_parse (apr->details.success.new_rules); 727 GNUNET_assert (NULL != lrs); 728 jmeasures = TALER_KYCLOGIC_get_jmeasures ( 729 lrs, 730 apr->details.success.new_measures); 731 GNUNET_assert (NULL != jmeasures); 732 } 733 734 { 735 struct TALER_FullPayto null_payto_uri = { 0 }; 736 bool invalid_officer; 737 bool unknown_account; 738 struct GNUNET_TIME_Timestamp last_date; 739 uint64_t legitimization_measure_serial_id; 740 bool is_wallet; 741 742 qs = TALER_EXCHANGEDB_insert_aml_decision ( 743 TEH_pg, 744 null_payto_uri, 745 &fb->account_id, 746 GNUNET_TIME_timestamp_get (), 747 apr->details.success.expiration_time, 748 apr->details.success.account_properties, 749 apr->details.success.new_rules, 750 apr->details.success.to_investigate, 751 apr->details.success.new_measures, 752 jmeasures, 753 NULL, /* justification */ 754 NULL, /* decider_pub */ 755 NULL, /* decider_sig */ 756 apr->details.success.num_events, 757 apr->details.success.events, 758 NULL, /* form_id */ 759 0, /* enc_attributes_size*/ 760 NULL, /* enc_attributes*/ 761 NULL, /* attributes_hash */ 762 GNUNET_TIME_UNIT_ZERO_TS, /* attributes_expiration_time */ 763 &invalid_officer, 764 &unknown_account, 765 &last_date, 766 &legitimization_measure_serial_id, 767 &is_wallet); 768 } 769 770 if (qs < 0) 771 { 772 GNUNET_break (0); 773 fb->cb (fb->cb_cls, 774 false, 775 0); 776 goto cleanup; 777 } 778 /* Finally, return result to main handler */ 779 fb->cb (fb->cb_cls, 780 true, 781 0); 782 cleanup: 783 TEH_kyc_fallback_cancel (fb); 784 GNUNET_async_scope_restore (&old_scope); 785 TALER_KYCLOGIC_rules_free (lrs); 786 json_decref (jmeasures); 787 } 788 789 790 /** 791 * Helper task function to asynchronously return 792 * the result of the operation. 793 * 794 * @param cls a `struct TEH_KycAmlFallback`. 795 */ 796 static void 797 return_fallback_result (void *cls) 798 { 799 struct TEH_KycAmlFallback *fb = cls; 800 struct GNUNET_AsyncScopeSave old_scope; 801 802 fb->task = NULL; 803 GNUNET_async_scope_enter (&fb->scope, 804 &old_scope); 805 fb->cb (fb->cb_cls, 806 ! fb->failure, 807 fb->requirement_row); 808 TEH_kyc_fallback_cancel (fb); 809 GNUNET_async_scope_restore (&old_scope); 810 } 811 812 813 struct TEH_KycAmlFallback* 814 TEH_kyc_fallback ( 815 const struct GNUNET_AsyncScopeId *scope, 816 const struct TALER_NormalizedPaytoHashP *account_id, 817 bool is_wallet, 818 uint64_t orig_requirement_row, 819 const char *fallback_measure, 820 TEH_KycAmlFallbackCallback cb, 821 void *cb_cls) 822 { 823 struct TEH_KycAmlFallback *fb; 824 struct TALER_KYCLOGIC_KycCheckContext kcc; 825 826 if (GNUNET_OK != 827 TALER_KYCLOGIC_get_original_measure ( 828 fallback_measure, 829 &kcc)) 830 { 831 /* very bad, could not find fallback measure!? */ 832 GNUNET_break (0); 833 return NULL; 834 } 835 fb = GNUNET_new (struct TEH_KycAmlFallback); 836 fb->scope = *scope; 837 fb->account_id = *account_id; 838 fb->orig_requirement_row = orig_requirement_row; 839 fb->cb = cb; 840 fb->cb_cls = cb_cls; 841 if (NULL == kcc.check) 842 { 843 struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = { 844 .account = &fb->account_id, 845 .is_wallet = is_wallet, 846 .pg = TEH_pg, 847 .attribute_key = &TEH_attribute_key 848 }; 849 850 /* check was set to 'SKIP', run program immediately */ 851 fb->aprh 852 = TALER_KYCLOGIC_run_aml_program2 ( 853 kcc.prog_name, 854 kcc.context, 855 is_wallet, 856 &TALER_EXCHANGEDB_current_attributes_builder, 857 &hbc, 858 &TALER_EXCHANGEDB_current_rule_builder, 859 &hbc, 860 &TALER_EXCHANGEDB_aml_history_builder, 861 &hbc, 862 &TALER_EXCHANGEDB_kyc_history_builder, 863 &hbc, 864 TEH_aml_program_timeout, 865 &handle_aml_fallback_result, 866 fb); 867 if (NULL == fb->aprh) 868 { 869 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 870 "Fallback AML program `%s' unknown\n", 871 kcc.prog_name); 872 TEH_kyc_fallback_cancel (fb); 873 return NULL; 874 } 875 return fb; 876 } 877 /* activate given check */ 878 { 879 json_t *jmeasures; 880 enum GNUNET_DB_QueryStatus qs; 881 bool bad_kyc_auth; 882 struct TALER_FullPayto null_account = { 883 .full_payto = NULL 884 }; 885 886 jmeasures = TALER_KYCLOGIC_check_to_jmeasures (&kcc); 887 qs = TALER_EXCHANGEDB_do_trigger_kyc_rule_for_account ( 888 TEH_pg, 889 null_account, /* account_id is already in wire targets */ 890 account_id, 891 NULL, /* account_pub */ 892 NULL, /* merchant_pub */ 893 jmeasures, 894 65536, /* high priority (does it matter?) */ 895 &fb->requirement_row, 896 &bad_kyc_auth); 897 json_decref (jmeasures); 898 fb->failure = (qs <= 0); 899 fb->task = GNUNET_SCHEDULER_add_now (&return_fallback_result, 900 fb); 901 } 902 return fb; 903 } 904 905 906 void 907 TEH_kyc_fallback_cancel ( 908 struct TEH_KycAmlFallback *fb) 909 { 910 if (NULL != fb->task) 911 { 912 GNUNET_SCHEDULER_cancel (fb->task); 913 fb->task = NULL; 914 } 915 if (NULL != fb->aprh) 916 { 917 TALER_KYCLOGIC_run_aml_program_cancel (fb->aprh); 918 fb->aprh = NULL; 919 } 920 GNUNET_free (fb); 921 } 922 923 924 bool 925 TEH_kyc_failed ( 926 uint64_t process_row, 927 const struct TALER_NormalizedPaytoHashP *account_id, 928 const char *provider_name, 929 const char *provider_user_id, 930 const char *provider_legitimization_id, 931 const char *error_message, 932 enum TALER_ErrorCode ec) 933 { 934 enum GNUNET_DB_QueryStatus qs; 935 936 qs = TALER_EXCHANGEDB_insert_kyc_failure ( 937 TEH_pg, 938 process_row, 939 account_id, 940 provider_name, 941 provider_user_id, 942 provider_legitimization_id, 943 error_message, 944 ec); 945 if (qs <= 0) 946 { 947 GNUNET_break (0); 948 return false; 949 } 950 return true; 951 } 952 953 954 struct TEH_LegitimizationCheckHandle 955 { 956 /** 957 * Function to call with the result. 958 */ 959 TEH_LegitimizationCheckCallback result_cb; 960 961 /** 962 * Closure for @e result_cb. 963 */ 964 void *result_cb_cls; 965 966 /** 967 * Task scheduled to return a result asynchronously. 968 */ 969 struct GNUNET_SCHEDULER_Task *async_task; 970 971 /** 972 * Handle to asynchronously running instant measure. 973 */ 974 struct TEH_KycMeasureRunContext *kat; 975 976 /** 977 * Handle for the task that gets us the latest 978 * applicable rules. 979 */ 980 struct TALER_EXCHANGEDB_RuleUpdater *ru; 981 982 /** 983 * Payto-URI of the account. 984 */ 985 struct TALER_FullPayto payto_uri; 986 987 /** 988 * Amount iterator to call to check for amounts. 989 */ 990 TALER_KYCLOGIC_KycAmountIterator ai; 991 992 /** 993 * Closure for @e ai. 994 */ 995 void *ai_cls; 996 997 /** 998 * Hash of @e payto_uri. 999 */ 1000 struct TALER_NormalizedPaytoHashP h_payto; 1001 1002 /** 1003 * Public key of the account. We should associate this public 1004 * key with the account if @e have_account_pub is true. Do not 1005 * confuse with @e lcr.kyc.have_account_pub which refers to us 1006 * already having an @e lcr.kyc.account_pub in the database for 1007 * the given @e h_payto. 1008 */ 1009 union TALER_AccountPublicKeyP account_pub; 1010 1011 /** 1012 * Public key of the merchant. Checks that the KYC 1013 * data was actually provided for this merchant if 1014 * @e have_merchant_pub is true, and if not rejects 1015 * the operation. 1016 */ 1017 struct TALER_MerchantPublicKeyP merchant_pub; 1018 1019 /** 1020 * Our request scope for logging. 1021 */ 1022 struct GNUNET_AsyncScopeId scope; 1023 1024 /** 1025 * Legitimization result we have been building and 1026 * should return. 1027 */ 1028 struct TEH_LegitimizationCheckResult lcr; 1029 1030 /** 1031 * Event we were triggered for. 1032 */ 1033 enum TALER_KYCLOGIC_KycTriggerEvent et; 1034 1035 /** 1036 * Number of instant rule triggers we have experienced 1037 * in this check already. 1038 */ 1039 unsigned int rerun; 1040 1041 /** 1042 * Do we have @e account_pub? 1043 */ 1044 bool have_account_pub; 1045 1046 /** 1047 * Do we have @e merchant_pub? 1048 */ 1049 bool have_merchant_pub; 1050 1051 /** 1052 * Is our @e h_payto for a wallet? 1053 */ 1054 bool is_wallet; 1055 1056 /** 1057 * Set to true if the merchant public key does not 1058 * match the public key we have on file for this 1059 * target account *and* a rule actually triggered 1060 * for this operation (and thus a new KYC AUTH is 1061 * required). 1062 */ 1063 bool bad_kyc_auth; 1064 1065 }; 1066 1067 1068 /** 1069 * Helper task that asynchronously calls the result 1070 * callback and then cleans up. 1071 * 1072 * @param[in] cls a `struct TEH_LegitimizationCheckHandle *` 1073 */ 1074 static void 1075 async_return_legi_result (void *cls) 1076 { 1077 struct TEH_LegitimizationCheckHandle *lch = cls; 1078 struct GNUNET_AsyncScopeSave old_scope; 1079 1080 lch->async_task = NULL; 1081 GNUNET_async_scope_enter (&lch->scope, 1082 &old_scope); 1083 lch->result_cb (lch->result_cb_cls, 1084 &lch->lcr); 1085 lch->lcr.response = NULL; 1086 TEH_legitimization_check_cancel (lch); 1087 GNUNET_async_scope_restore (&old_scope); 1088 } 1089 1090 1091 /** 1092 * The legitimization process failed, return an error 1093 * response. 1094 * 1095 * @param[in,out] lch legitimization check that failed 1096 * @param ec error code to return 1097 * @param details error details to return (can be NULL) 1098 */ 1099 static void 1100 legi_fail (struct TEH_LegitimizationCheckHandle *lch, 1101 enum TALER_ErrorCode ec, 1102 const char *details) 1103 { 1104 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1105 "Legitimziation process failed: %s (%s)\n", 1106 TALER_ErrorCode_get_hint (ec), 1107 details); 1108 lch->lcr.http_status 1109 = TALER_ErrorCode_get_http_status (ec); 1110 lch->lcr.response 1111 = TALER_MHD_make_error ( 1112 ec, 1113 details); 1114 lch->async_task 1115 = GNUNET_SCHEDULER_add_now ( 1116 &async_return_legi_result, 1117 lch); 1118 } 1119 1120 1121 /** 1122 * Actually (re)-run the legitimization check @a lch. 1123 * 1124 * @param[in,out] lch legitimization check to run 1125 */ 1126 static void 1127 legitimization_check_run ( 1128 struct TEH_LegitimizationCheckHandle *lch); 1129 1130 1131 /** 1132 * Function called after the KYC-AML trigger is done. 1133 * 1134 * @param cls must be a `struct TEH_LegitimizationCheckHandle *` 1135 * @param ec error code or 0 on success 1136 * @param detail error message or NULL on success / no info 1137 */ 1138 static void 1139 legi_check_aml_trigger_cb ( 1140 void *cls, 1141 enum TALER_ErrorCode ec, 1142 const char *detail) 1143 { 1144 struct TEH_LegitimizationCheckHandle *lch = cls; 1145 1146 lch->kat = NULL; 1147 if (TALER_EC_NONE != ec) 1148 { 1149 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1150 "AML program failed: %s (%s, %d)\n", 1151 TALER_ErrorCode_get_hint (ec), 1152 detail, 1153 (int) ec); 1154 lch->lcr.http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; 1155 lch->lcr.response = TALER_MHD_make_error ( 1156 ec, 1157 detail); 1158 lch->async_task 1159 = GNUNET_SCHEDULER_add_now ( 1160 &async_return_legi_result, 1161 lch); 1162 return; 1163 } 1164 /* re-run the check, we got new rules! */ 1165 if (lch->rerun > MAX_LEGI_LOOPS) 1166 { 1167 /* deep recursion not allowed, abort! */ 1168 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1169 "Deep recursion (> %u) detected in AML programs, aborting\n", 1170 (unsigned int) MAX_LEGI_LOOPS); 1171 legi_fail (lch, 1172 TALER_EC_EXCHANGE_KYC_RECURSIVE_RULE_DETECTED, 1173 NULL); 1174 return; 1175 } 1176 lch->rerun++; 1177 legitimization_check_run (lch); 1178 } 1179 1180 1181 /** 1182 * Setup legitimization check. 1183 * 1184 * @param scope scope for logging 1185 * @param et type of event we are checking 1186 * @param payto_uri account we are checking for 1187 * @param h_payto hash of @a payto_uri 1188 * @param account_pub public key to enable for the 1189 * KYC authorization, NULL if not known 1190 * @param ai callback to get amounts involved historically 1191 * @param ai_cls closure for @a ai 1192 * @param result_cb function to call with the result 1193 * @param result_cb_cls closure for @a result_cb 1194 * @return handle for the operation 1195 */ 1196 static struct TEH_LegitimizationCheckHandle * 1197 setup_legitimization_check ( 1198 const struct GNUNET_AsyncScopeId *scope, 1199 enum TALER_KYCLOGIC_KycTriggerEvent et, 1200 const struct TALER_FullPayto payto_uri, 1201 const struct TALER_NormalizedPaytoHashP *h_payto, 1202 const union TALER_AccountPublicKeyP *account_pub, 1203 TALER_KYCLOGIC_KycAmountIterator ai, 1204 void *ai_cls, 1205 TEH_LegitimizationCheckCallback result_cb, 1206 void *result_cb_cls) 1207 { 1208 struct TEH_LegitimizationCheckHandle *lch; 1209 1210 #if EXTRA_CHECK 1211 { 1212 struct TALER_NormalizedPaytoHashP npt; 1213 1214 TALER_full_payto_normalize_and_hash (payto_uri, 1215 &npt); 1216 GNUNET_assert (0 == 1217 GNUNET_memcmp (&npt, 1218 h_payto)); 1219 } 1220 #endif 1221 lch = GNUNET_new (struct TEH_LegitimizationCheckHandle); 1222 lch->scope = *scope; 1223 lch->et = et; 1224 lch->payto_uri.full_payto 1225 = GNUNET_strdup (payto_uri.full_payto); 1226 lch->is_wallet 1227 = TALER_payto_is_wallet (payto_uri.full_payto); 1228 lch->h_payto = *h_payto; 1229 if (NULL != account_pub) 1230 { 1231 lch->account_pub = *account_pub; 1232 lch->have_account_pub = true; 1233 } 1234 lch->ai = ai; 1235 lch->ai_cls = ai_cls; 1236 lch->result_cb = result_cb; 1237 lch->result_cb_cls = result_cb_cls; 1238 return lch; 1239 } 1240 1241 1242 struct TEH_LegitimizationCheckHandle * 1243 TEH_legitimization_check ( 1244 const struct GNUNET_AsyncScopeId *scope, 1245 enum TALER_KYCLOGIC_KycTriggerEvent et, 1246 const struct TALER_FullPayto payto_uri, 1247 const struct TALER_NormalizedPaytoHashP *h_payto, 1248 const union TALER_AccountPublicKeyP *account_pub, 1249 TALER_KYCLOGIC_KycAmountIterator ai, 1250 void *ai_cls, 1251 TEH_LegitimizationCheckCallback result_cb, 1252 void *result_cb_cls) 1253 { 1254 struct TEH_LegitimizationCheckHandle *lch; 1255 1256 lch = setup_legitimization_check (scope, 1257 et, 1258 payto_uri, 1259 h_payto, 1260 account_pub, 1261 ai, 1262 ai_cls, 1263 result_cb, 1264 result_cb_cls); 1265 legitimization_check_run (lch); 1266 return lch; 1267 } 1268 1269 1270 struct TEH_LegitimizationCheckHandle * 1271 TEH_legitimization_check2 ( 1272 const struct GNUNET_AsyncScopeId *scope, 1273 enum TALER_KYCLOGIC_KycTriggerEvent et, 1274 const struct TALER_FullPayto payto_uri, 1275 const struct TALER_NormalizedPaytoHashP *h_payto, 1276 const struct TALER_MerchantPublicKeyP *merchant_pub, 1277 TALER_KYCLOGIC_KycAmountIterator ai, 1278 void *ai_cls, 1279 TEH_LegitimizationCheckCallback result_cb, 1280 void *result_cb_cls) 1281 { 1282 struct TEH_LegitimizationCheckHandle *lch; 1283 1284 lch = setup_legitimization_check (scope, 1285 et, 1286 payto_uri, 1287 h_payto, 1288 NULL, 1289 ai, 1290 ai_cls, 1291 result_cb, 1292 result_cb_cls); 1293 lch->merchant_pub = *merchant_pub; 1294 lch->have_merchant_pub = true; 1295 legitimization_check_run (lch); 1296 return lch; 1297 } 1298 1299 1300 /** 1301 * The KYC check failed because KYC auth is required 1302 * to match and it does not. 1303 * 1304 * @param[in,out] lch legitimization check to fail 1305 */ 1306 static void 1307 fail_kyc_auth (struct TEH_LegitimizationCheckHandle *lch) 1308 { 1309 lch->lcr.kyc.requirement_row = 0; 1310 lch->lcr.kyc.ok = false; 1311 lch->lcr.bad_kyc_auth = true; 1312 lch->lcr.expiration_date 1313 = GNUNET_TIME_UNIT_FOREVER_TS; 1314 memset (&lch->lcr.next_threshold, 1315 0, 1316 sizeof (struct TALER_Amount)); 1317 lch->lcr.http_status = 0; 1318 lch->lcr.response = NULL; 1319 lch->async_task 1320 = GNUNET_SCHEDULER_add_now ( 1321 &async_return_legi_result, 1322 lch); 1323 } 1324 1325 1326 /** 1327 * Function called to iterate over KYC-relevant 1328 * transaction amounts for a particular time range. 1329 * Called within a database transaction, so must 1330 * not start a new one. 1331 * 1332 * Given that there *is* a KYC requirement, we also 1333 * check if the kyc_auth_bad is set and react 1334 * accordingly. 1335 * 1336 * @param cls closure, a `struct TEH_LegitimizationCheckHandle *` 1337 * @param limit maximum time-range for which events 1338 * should be fetched (timestamp in the past) 1339 * @param cb function to call on each event found, 1340 * events must be returned in reverse chronological 1341 * order 1342 * @param cb_cls closure for @a cb 1343 * @return transaction status 1344 */ 1345 static enum GNUNET_DB_QueryStatus 1346 amount_iterator_wrapper_cb ( 1347 void *cls, 1348 struct GNUNET_TIME_Absolute limit, 1349 TALER_KYCLOGIC_KycAmountCallback cb, 1350 void *cb_cls) 1351 { 1352 struct TEH_LegitimizationCheckHandle *lch = cls; 1353 1354 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1355 "KYC: Checking amounts until %s\n", 1356 GNUNET_TIME_absolute2s (limit)); 1357 if (lch->lcr.bad_kyc_auth) 1358 { 1359 /* We *do* have applicable KYC rules *and* the 1360 target_pub does not match the merchant_pub, 1361 so we indeed have a problem! */ 1362 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1363 "KYC: Mismatch between merchant_pub and target_pub is relevant!\n"); 1364 lch->bad_kyc_auth = true; 1365 } 1366 return lch->ai (lch->ai_cls, 1367 limit, 1368 cb, 1369 cb_cls); 1370 } 1371 1372 1373 /** 1374 * Function called with the current rule set. Called with an open 1375 * database transaction. 1376 * 1377 * @param lch a `struct TEH_LegitimizationCheckHandle *` 1378 * @param rur includes legitimziation rule set that applies to the account 1379 * (owned by callee, callee must free the lrs!) 1380 */ 1381 static void 1382 current_rules_cb ( 1383 struct TEH_LegitimizationCheckHandle *lch, 1384 struct TALER_EXCHANGEDB_RuleUpdaterResult *rur) 1385 { 1386 struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs = rur->lrs; 1387 struct GNUNET_AsyncScopeSave old_scope; 1388 enum GNUNET_DB_QueryStatus qs; 1389 const struct TALER_KYCLOGIC_KycRule *requirement; 1390 const struct TALER_KYCLOGIC_Measure *instant_ms; 1391 1392 GNUNET_async_scope_enter (&lch->scope, 1393 &old_scope); 1394 if (TALER_EC_NONE != rur->ec) 1395 { 1396 /* rollback should not be needed, but better be safe */ 1397 TALER_EXCHANGEDB_rollback (TEH_pg); 1398 legi_fail (lch, 1399 rur->ec, 1400 rur->hint); 1401 goto cleanup; 1402 } 1403 1404 qs = TALER_KYCLOGIC_kyc_test_required ( 1405 lch->et, 1406 lrs, 1407 &amount_iterator_wrapper_cb, 1408 lch, 1409 &requirement, 1410 &lch->lcr.next_threshold); 1411 if (qs < 0) 1412 { 1413 GNUNET_break (0); 1414 TALER_EXCHANGEDB_rollback (TEH_pg); 1415 legi_fail (lch, 1416 TALER_EC_GENERIC_DB_FETCH_FAILED, 1417 "kyc_test_required"); 1418 goto cleanup; 1419 } 1420 if (lch->bad_kyc_auth) 1421 { 1422 qs = TALER_EXCHANGEDB_commit (TEH_pg); 1423 if (0 > qs) 1424 { 1425 legi_fail (lch, 1426 TALER_EC_GENERIC_DB_COMMIT_FAILED, 1427 "kyc_test_required"); 1428 goto cleanup; 1429 } 1430 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1431 "KYC auth required\n"); 1432 fail_kyc_auth (lch); 1433 goto cleanup; 1434 } 1435 1436 if (NULL == requirement) 1437 { 1438 qs = TALER_EXCHANGEDB_commit (TEH_pg); 1439 if (0 > qs) 1440 { 1441 legi_fail (lch, 1442 TALER_EC_GENERIC_DB_COMMIT_FAILED, 1443 "kyc_test_required"); 1444 goto cleanup; 1445 } 1446 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1447 "KYC check passed\n"); 1448 lch->lcr.kyc.ok = true; 1449 lch->lcr.expiration_date 1450 = TALER_KYCLOGIC_rules_get_expiration (lrs); 1451 /* return success! */ 1452 lch->async_task 1453 = GNUNET_SCHEDULER_add_now ( 1454 &async_return_legi_result, 1455 lch); 1456 goto cleanup; 1457 } 1458 1459 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1460 "KYC requirement is %s\n", 1461 TALER_KYCLOGIC_rule2s (requirement)); 1462 instant_ms 1463 = TALER_KYCLOGIC_rule_get_instant_measure ( 1464 requirement); 1465 if (NULL != instant_ms) 1466 { 1467 /* We have an 'instant' measure which means we must run the 1468 AML program immediately instead of waiting for the account owner 1469 to select some measure and contribute their KYC data. */ 1470 1471 lch->kat = TEH_kyc_run_measure_directly ( 1472 &lch->scope, 1473 instant_ms, 1474 &lch->h_payto, 1475 lch->is_wallet, 1476 &legi_check_aml_trigger_cb, 1477 lch); 1478 if (NULL == lch->kat) 1479 { 1480 GNUNET_break (0); 1481 TALER_EXCHANGEDB_rollback (TEH_pg); 1482 legi_fail (lch, 1483 TALER_EC_EXCHANGE_KYC_AML_PROGRAM_FAILURE, 1484 NULL); 1485 goto cleanup; 1486 } 1487 qs = TALER_EXCHANGEDB_commit (TEH_pg); 1488 if (0 > qs) 1489 { 1490 legi_fail (lch, 1491 TALER_EC_GENERIC_DB_COMMIT_FAILED, 1492 "kyc_test_required"); 1493 goto cleanup; 1494 } 1495 goto cleanup; 1496 } 1497 1498 /* No instant measure, store all measures in the database and 1499 wait for the user to select one (via /kyc-info) and to then 1500 provide the data. */ 1501 lch->lcr.kyc.ok = false; 1502 { 1503 json_t *jmeasures; 1504 1505 jmeasures = TALER_KYCLOGIC_rule_to_measures (requirement); 1506 qs = TALER_EXCHANGEDB_do_trigger_kyc_rule_for_account ( 1507 TEH_pg, 1508 lch->payto_uri, 1509 &lch->h_payto, 1510 lch->have_account_pub ? &lch->account_pub : NULL, 1511 lch->have_merchant_pub ? &lch->merchant_pub : NULL, 1512 jmeasures, 1513 TALER_KYCLOGIC_rule2priority (requirement), 1514 &lch->lcr.kyc.requirement_row, 1515 &lch->lcr.bad_kyc_auth); 1516 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1517 "trigger_kyc_rule_for_account-1 on %d/%d returned %d/%llu/%d\n", 1518 lch->have_account_pub, 1519 lch->have_merchant_pub, 1520 (int) qs, 1521 (unsigned long long) lch->lcr.kyc.requirement_row, 1522 lch->lcr.bad_kyc_auth); 1523 json_decref (jmeasures); 1524 } 1525 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) 1526 { 1527 GNUNET_break (0); 1528 TALER_EXCHANGEDB_rollback (TEH_pg); 1529 legi_fail (lch, 1530 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 1531 "trigger_kyc_rule_for_account"); 1532 goto cleanup; 1533 } 1534 if (GNUNET_DB_STATUS_HARD_ERROR == qs) 1535 { 1536 GNUNET_break (0); 1537 TALER_EXCHANGEDB_rollback (TEH_pg); 1538 legi_fail (lch, 1539 TALER_EC_GENERIC_DB_STORE_FAILED, 1540 "trigger_kyc_rule_for_account"); 1541 goto cleanup; 1542 } 1543 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 1544 { 1545 /* Serialization failure or a lost connection. This used to fall 1546 through to the commit below, which PostgreSQL happily accepted on the 1547 already-aborted transaction, so the client was told its legitimization 1548 measure had been registered when nothing had been written. There is 1549 no retry loop in this file (the transaction is hand-rolled rather than 1550 run through TEH_DB_run_transaction), so all we can do here is fail 1551 visibly and let the client repeat the request. */ 1552 TALER_EXCHANGEDB_rollback (TEH_pg); 1553 legi_fail (lch, 1554 TALER_EC_GENERIC_DB_SOFT_FAILURE, 1555 "trigger_kyc_rule_for_account"); 1556 goto cleanup; 1557 } 1558 qs = TALER_EXCHANGEDB_commit (TEH_pg); 1559 if (0 > qs) 1560 { 1561 legi_fail (lch, 1562 TALER_EC_GENERIC_DB_COMMIT_FAILED, 1563 "kyc_test_required"); 1564 goto cleanup; 1565 } 1566 /* return success! */ 1567 GNUNET_break (GNUNET_OK == 1568 TALER_EXCHANGEDB_preflight (TEH_pg)); 1569 lch->async_task 1570 = GNUNET_SCHEDULER_add_now ( 1571 &async_return_legi_result, 1572 lch); 1573 cleanup: 1574 TALER_KYCLOGIC_rules_free (lrs); 1575 GNUNET_async_scope_restore (&old_scope); 1576 } 1577 1578 1579 static void 1580 legitimization_check_run ( 1581 struct TEH_LegitimizationCheckHandle *lch) 1582 { 1583 struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs = NULL; 1584 enum GNUNET_DB_QueryStatus qs; 1585 struct GNUNET_AsyncScopeSave old_scope; 1586 enum GNUNET_GenericReturnValue res; 1587 1588 if (! TEH_enable_kyc) 1589 { 1590 /* AML/KYC disabled, just immediately return success! */ 1591 lch->lcr.kyc.requirement_row = 0; 1592 lch->lcr.kyc.ok = true; 1593 lch->lcr.bad_kyc_auth = false; 1594 lch->lcr.expiration_date 1595 = GNUNET_TIME_UNIT_FOREVER_TS; 1596 memset (&lch->lcr.next_threshold, 1597 0, 1598 sizeof (struct TALER_Amount)); 1599 lch->lcr.http_status = 0; 1600 lch->lcr.response = NULL; 1601 lch->async_task 1602 = GNUNET_SCHEDULER_add_now ( 1603 &async_return_legi_result, 1604 lch); 1605 return; 1606 } 1607 GNUNET_async_scope_enter (&lch->scope, 1608 &old_scope); 1609 res = TALER_EXCHANGEDB_start (TEH_pg, 1610 "legi-check-run-start-precheck"); 1611 if (GNUNET_OK != res) 1612 { 1613 GNUNET_break (0); 1614 legi_fail (lch, 1615 TALER_EC_GENERIC_DB_START_FAILED, 1616 "legi-check-run-start-precheck"); 1617 GNUNET_async_scope_restore (&old_scope); 1618 return; 1619 } 1620 { 1621 json_t *jrules; 1622 bool no_account_pub; 1623 bool no_reserve_pub; 1624 1625 qs = TALER_EXCHANGEDB_get_kyc_rules_with_account ( 1626 TEH_pg, 1627 &lch->h_payto, 1628 lch->have_merchant_pub 1629 ? &lch->merchant_pub 1630 : NULL, 1631 &no_account_pub, 1632 &lch->lcr.kyc.account_pub, 1633 &no_reserve_pub, 1634 &lch->lcr.reserve_pub.reserve_pub, 1635 &jrules); 1636 switch (qs) 1637 { 1638 case GNUNET_DB_STATUS_HARD_ERROR: 1639 case GNUNET_DB_STATUS_SOFT_ERROR: 1640 GNUNET_break (0); 1641 TALER_EXCHANGEDB_rollback (TEH_pg); 1642 legi_fail (lch, 1643 TALER_EC_GENERIC_DB_FETCH_FAILED, 1644 "get_kyc_rules_with_account"); 1645 GNUNET_async_scope_restore (&old_scope); 1646 return; 1647 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 1648 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 1649 break; 1650 } 1651 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1652 "get_kyc_rules returned %d/%d/%d/%d(%d)\n", 1653 (int) qs, 1654 ! no_account_pub, 1655 ! no_reserve_pub, 1656 NULL != jrules, 1657 (int) lch->have_merchant_pub); 1658 1659 lch->lcr.kyc.have_account_pub 1660 = ! no_account_pub; 1661 lch->lcr.have_reserve_pub 1662 = ! no_reserve_pub; 1663 if ( (lch->have_merchant_pub) && 1664 ( (! lch->lcr.kyc.have_account_pub) || 1665 (0 != 1666 GNUNET_memcmp (&lch->merchant_pub, 1667 &lch->lcr.kyc.account_pub.merchant_pub)) ) && 1668 ( (! lch->lcr.have_reserve_pub) || 1669 (0 != 1670 GNUNET_memcmp (&lch->merchant_pub, 1671 &lch->lcr.reserve_pub.merchant_pub)) ) ) 1672 { 1673 if (NULL == jrules) 1674 { 1675 /* We do not have custom rules, defer enforcing merchant_pub 1676 match until we actually have deposit constraints */ 1677 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1678 "KYC: merchant_pub given but no known target_pub(%d)/reserve_pub(%d) match (%d)!\n", 1679 lch->lcr.kyc.have_account_pub, 1680 lch->lcr.have_reserve_pub, 1681 (int) qs); 1682 lch->lcr.bad_kyc_auth = true; 1683 } 1684 else 1685 { 1686 /* We have custom rules, but the target_pub for 1687 those custom rules does not match the 1688 merchant_pub. Fail the KYC process! */ 1689 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1690 "KYC: merchant_pub does not match target_pub of custom rules!\n"); 1691 TALER_EXCHANGEDB_rollback (TEH_pg); 1692 json_decref (jrules); 1693 fail_kyc_auth (lch); 1694 goto cleanup; 1695 } 1696 } 1697 1698 /* parse and free jrules (if we had any) */ 1699 if (NULL != jrules) 1700 { 1701 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1702 "KYC: have custom KYC rules for this account!\n"); 1703 lrs = TALER_KYCLOGIC_rules_parse (jrules); 1704 GNUNET_break (NULL != lrs); 1705 /* Fall back to default rules on parse error! */ 1706 json_decref (jrules); 1707 } 1708 else 1709 { 1710 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1711 "KYC: default KYC rules apply to this account!\n"); 1712 } 1713 } 1714 1715 /* NOTE-CG: I don't recall why we need to make this distinction 1716 and re-fetch the rules this way. The main difference is that 1717 we fetch the "legitimization_outcome_last_row" on the true 1718 path, but we could presumably fetch it above as well. Not 1719 doing another transaction would seem more efficient. So why 1720 exactly do we do this here? */ 1721 if (NULL != lrs) 1722 { 1723 /* Stop the current transaction and start a new 1724 asynchronous task with a new transaction to 1725 fetch the rules for the account. */ 1726 TALER_EXCHANGEDB_rollback (TEH_pg); 1727 TALER_KYCLOGIC_rules_free (lrs); 1728 lch->ru = TALER_EXCHANGEDB_begin_rule_update (TEH_pg, 1729 &TEH_attribute_key, 1730 &lch->h_payto, 1731 lch->is_wallet, 1732 ¤t_rules_cb, 1733 lch); 1734 } 1735 else 1736 { 1737 struct TALER_EXCHANGEDB_RuleUpdaterResult rur = { 0 }; 1738 1739 /* Simplified case, just default rules apply, we can 1740 continue in this transaction */ 1741 current_rules_cb (lch, 1742 &rur); 1743 } 1744 cleanup: 1745 GNUNET_async_scope_restore (&old_scope); 1746 } 1747 1748 1749 void 1750 TEH_legitimization_check_cancel ( 1751 struct TEH_LegitimizationCheckHandle *lch) 1752 { 1753 if (NULL != lch->async_task) 1754 { 1755 GNUNET_SCHEDULER_cancel (lch->async_task); 1756 lch->async_task = NULL; 1757 } 1758 if (NULL != lch->kat) 1759 { 1760 TEH_kyc_run_measure_cancel (lch->kat); 1761 lch->kat = NULL; 1762 } 1763 if (NULL != lch->lcr.response) 1764 { 1765 MHD_destroy_response (lch->lcr.response); 1766 lch->lcr.response = NULL; 1767 } 1768 GNUNET_free (lch->payto_uri.full_payto); 1769 GNUNET_free (lch); 1770 }