exchangedb_aml.c (21443B)
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 exchangedb_aml.c 18 * @brief helper function to handle AML programs 19 * @author Christian Grothoff 20 */ 21 #include "taler/taler_exchangedb_plugin.h" 22 #include "taler/taler_exchangedb_lib.h" 23 #include "taler/taler_kyclogic_lib.h" 24 #include "taler/taler_json_lib.h" 25 #include "taler/taler_dbevents.h" 26 #include <gnunet/gnunet_common.h> 27 28 /** 29 * Maximum recursion depth we allow for AML programs. 30 * Basically, after this number of "skip" processes 31 * we forcefully terminate the recursion and fail hard. 32 */ 33 #define MAX_DEPTH 16 34 35 enum GNUNET_DB_QueryStatus 36 TALER_EXCHANGEDB_persist_aml_program_result ( 37 struct TALER_EXCHANGEDB_Plugin *plugin, 38 uint64_t process_row, 39 const struct TALER_NormalizedPaytoHashP *account_id, 40 const struct TALER_KYCLOGIC_AmlProgramResult *apr, 41 enum TALER_EXCHANGEDB_PersistProgramResultStatus *ret_pprs) 42 { 43 enum GNUNET_DB_QueryStatus qs; 44 json_t *jmeasures = NULL; 45 struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs = NULL; 46 47 GNUNET_assert (NULL != ret_pprs); 48 49 *ret_pprs = TALER_EXCHANGEDB_PPRS_OK; 50 51 if ( (TALER_KYCLOGIC_AMLR_SUCCESS == apr->status) && 52 (NULL != apr->details.success.new_measures) ) 53 { 54 lrs = TALER_KYCLOGIC_rules_parse (apr->details.success.new_rules); 55 if (NULL == lrs) 56 { 57 qs = plugin->insert_aml_program_failure ( 58 plugin->cls, 59 process_row, 60 account_id, 61 "Failed to parse AML program output", 62 TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT); 63 GNUNET_break (qs > 0); 64 return qs; 65 } 66 jmeasures = TALER_KYCLOGIC_get_jmeasures ( 67 lrs, 68 apr->details.success.new_measures); 69 if (NULL == jmeasures) 70 { 71 char *err; 72 73 GNUNET_break (0); 74 GNUNET_asprintf (&err, 75 "Failed to find measures `%s' specified in AML program output", 76 apr->details.success.new_measures); 77 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 78 "AML program specified invalid measures `%s'\n", 79 apr->details.success.new_measures); 80 qs = plugin->insert_aml_program_failure ( 81 plugin->cls, 82 process_row, 83 account_id, 84 err, 85 TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT); 86 *ret_pprs = TALER_EXCHANGEDB_PPRS_BAD_OUTCOME; 87 TALER_KYCLOGIC_rules_free (lrs); 88 GNUNET_free (err); 89 GNUNET_break (qs > 0); 90 return qs; 91 } 92 } 93 94 qs = plugin->clear_aml_lock ( 95 plugin->cls, 96 account_id); 97 switch (apr->status) 98 { 99 case TALER_KYCLOGIC_AMLR_FAILURE: 100 qs = plugin->insert_aml_program_failure ( 101 plugin->cls, 102 process_row, 103 account_id, 104 apr->details.failure.error_message, 105 apr->details.failure.ec); 106 GNUNET_break (qs > 0); 107 goto cleanup; 108 case TALER_KYCLOGIC_AMLR_SUCCESS: 109 { 110 struct TALER_FullPayto null_payto_uri = { 0 }; 111 bool invalid_officer; 112 bool unknown_account; 113 struct GNUNET_TIME_Timestamp last_date; 114 uint64_t legitimization_measure_serial_id; 115 bool is_wallet; 116 117 qs = plugin->insert_aml_decision ( 118 plugin->cls, 119 null_payto_uri, 120 account_id, 121 GNUNET_TIME_timestamp_get (), 122 apr->details.success.expiration_time, 123 apr->details.success.account_properties, 124 apr->details.success.new_rules, 125 apr->details.success.to_investigate, 126 apr->details.success.new_measures, 127 jmeasures, 128 NULL, /* justification */ 129 NULL, /* decider_pub */ 130 NULL, /* decider_sig */ 131 apr->details.success.num_events, 132 apr->details.success.events, 133 NULL, /* form ID */ 134 0, /* enc_attributes_size*/ 135 NULL, /* enc_attributes*/ 136 NULL, /* attributes_hash */ 137 GNUNET_TIME_UNIT_ZERO_TS, /* attributes_expiration_time */ 138 &invalid_officer, 139 &unknown_account, 140 &last_date, 141 &legitimization_measure_serial_id, 142 &is_wallet); 143 GNUNET_break (qs > 0); 144 goto cleanup; 145 } 146 } 147 GNUNET_break (0); 148 qs = GNUNET_DB_STATUS_HARD_ERROR; 149 cleanup: 150 TALER_KYCLOGIC_rules_free (lrs); 151 json_decref (jmeasures); 152 return qs; 153 } 154 155 156 struct TALER_EXCHANGEDB_RuleUpdater 157 { 158 /** 159 * database plugin to use 160 */ 161 struct TALER_EXCHANGEDB_Plugin *plugin; 162 163 /** 164 * key to use to decrypt attributes 165 */ 166 struct TALER_AttributeEncryptionKeyP attribute_key; 167 168 /** 169 * account to get the rule set for 170 */ 171 struct TALER_NormalizedPaytoHashP account; 172 173 /** 174 * function to call with the result 175 */ 176 TALER_EXCHANGEDB_CurrentRulesCallback cb; 177 178 /** 179 * Closure for @e cb. 180 */ 181 void *cb_cls; 182 183 /** 184 * Current rule set we are working on. 185 */ 186 struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs; 187 188 /** 189 * Task for asynchronous continuations. 190 */ 191 struct GNUNET_SCHEDULER_Task *t; 192 193 /** 194 * Handler waiting notification that (previous) AML program 195 * finished. 196 */ 197 struct GNUNET_DB_EventHandler *eh; 198 199 /** 200 * Handle to running AML program. 201 */ 202 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *amlh; 203 204 /** 205 * Name of the AML program we were running asynchronously, 206 * for diagnostics. 207 */ 208 char *aml_program_name; 209 210 /** 211 * Error hint to return with @e ec. 212 */ 213 const char *hint; 214 215 /** 216 * Row the rule set in @a lrs is based on. 217 */ 218 uint64_t legitimization_outcome_last_row; 219 220 /** 221 * Taler error code to return. 222 */ 223 enum TALER_ErrorCode ec; 224 225 /** 226 * Counter used to limit recursion depth. 227 */ 228 unsigned int depth; 229 230 /** 231 * True if @e account is for a wallet. 232 */ 233 bool is_wallet; 234 }; 235 236 237 /** 238 * Function that finally returns the result to the application and cleans 239 * up. Called with an open database transaction on success; on failure, the 240 * transaction will have already been rolled back. 241 * 242 * @param[in,out] ru rule updater to return result for 243 */ 244 static void 245 return_result (struct TALER_EXCHANGEDB_RuleUpdater *ru) 246 { 247 struct TALER_EXCHANGEDB_RuleUpdaterResult rur = { 248 .legitimization_outcome_last_row = ru->legitimization_outcome_last_row, 249 .lrs = ru->lrs, 250 .ec = ru->ec, 251 }; 252 253 ru->cb (ru->cb_cls, 254 &rur); 255 ru->lrs = NULL; 256 TALER_EXCHANGEDB_update_rules_cancel (ru); 257 } 258 259 260 /** 261 * Fail the update with the given @a ec and @a hint. 262 * Called with an open database transaction, which will 263 * be rolled back (!). 264 * 265 * @param[in,out] ru account we are processing 266 * @param ec error code to fail with 267 * @param hint hint to return, can be NULL 268 */ 269 static void 270 fail_update (struct TALER_EXCHANGEDB_RuleUpdater *ru, 271 enum TALER_ErrorCode ec, 272 const char *hint) 273 { 274 GNUNET_assert (NULL == ru->t); 275 ru->plugin->rollback (ru->plugin->cls); 276 ru->ec = ec; 277 ru->hint = hint; 278 return_result (ru); 279 } 280 281 282 /** 283 * Check the rules in @a ru to see if they are current, and 284 * if not begin the updating process. Called with an open 285 * database transaction. 286 * 287 * @param[in] ru rule updater context 288 */ 289 static void 290 check_rules (struct TALER_EXCHANGEDB_RuleUpdater *ru); 291 292 293 /** 294 * Run the measure @a m in the context of the legitimisation rules 295 * of @a ru. Called with an open database transaction. 296 * 297 * @param ru updating context we are using 298 * @param m measure we need to run next 299 */ 300 static void 301 run_measure (struct TALER_EXCHANGEDB_RuleUpdater *ru, 302 const struct TALER_KYCLOGIC_Measure *m); 303 304 305 /** 306 * Function called after AML program was run. Called 307 * without an open database transaction, will start one! 308 * 309 * @param cls the `struct TALER_EXCHANGEDB_RuleUpdater *` 310 * @param apr result of the AML program. 311 */ 312 static void 313 aml_result_callback ( 314 void *cls, 315 const struct TALER_KYCLOGIC_AmlProgramResult *apr) 316 { 317 struct TALER_EXCHANGEDB_RuleUpdater *ru = cls; 318 enum GNUNET_DB_QueryStatus qs; 319 enum GNUNET_GenericReturnValue res; 320 enum TALER_EXCHANGEDB_PersistProgramResultStatus pprs; 321 322 ru->amlh = NULL; 323 res = ru->plugin->start (ru->plugin->cls, 324 "aml-persist-aml-program-result"); 325 if (GNUNET_OK != res) 326 { 327 GNUNET_break (0); 328 fail_update (ru, 329 TALER_EC_GENERIC_DB_START_FAILED, 330 "aml-persist-aml-program-result"); 331 return; 332 } 333 /* Update database update based on result */ 334 qs = TALER_EXCHANGEDB_persist_aml_program_result ( 335 ru->plugin, 336 0LLU, /* 0: no existing legitimization process, creates new row */ 337 &ru->account, 338 apr, 339 &pprs); 340 switch (qs) 341 { 342 case GNUNET_DB_STATUS_HARD_ERROR: 343 GNUNET_break (0); 344 fail_update (ru, 345 TALER_EC_GENERIC_DB_STORE_FAILED, 346 "persist_aml_program_result"); 347 return; 348 case GNUNET_DB_STATUS_SOFT_ERROR: 349 /* Bad, couldn't persist AML result. Try again... */ 350 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 351 "Serialization issue persisting result of AML program. Restarting.\n"); 352 fail_update (ru, 353 TALER_EC_GENERIC_DB_SOFT_FAILURE, 354 "persist_aml_program_result"); 355 return; 356 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 357 /* Strange, but let's just continue */ 358 break; 359 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 360 /* normal case */ 361 break; 362 } 363 switch (pprs) 364 { 365 case TALER_EXCHANGEDB_PPRS_OK: 366 break; 367 case TALER_EXCHANGEDB_PPRS_BAD_OUTCOME: 368 fail_update (ru, 369 TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT, 370 "persist_aml_program_result"); 371 return; 372 } 373 switch (apr->status) 374 { 375 case TALER_KYCLOGIC_AMLR_SUCCESS: 376 TALER_KYCLOGIC_rules_free (ru->lrs); 377 ru->lrs = NULL; 378 ru->lrs = TALER_KYCLOGIC_rules_parse (apr->details.success.new_rules); 379 /* Fall back to default rules on parse error! */ 380 GNUNET_break (NULL != ru->lrs); 381 check_rules (ru); 382 return; 383 case TALER_KYCLOGIC_AMLR_FAILURE: 384 { 385 const char *fmn = apr->details.failure.fallback_measure; 386 const struct TALER_KYCLOGIC_Measure *m; 387 388 m = TALER_KYCLOGIC_get_measure (ru->lrs, 389 fmn); 390 if (NULL == m) 391 { 392 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 393 "Fallback measure `%s' does not exist (anymore?).\n", 394 fmn); 395 TALER_KYCLOGIC_rules_free (ru->lrs); 396 ru->lrs = NULL; 397 return_result (ru); 398 return; 399 } 400 run_measure (ru, 401 m); 402 return; 403 } 404 } 405 /* This should be impossible */ 406 GNUNET_assert (0); 407 } 408 409 410 /** 411 * Entrypoint that fetches the latest rules from the database 412 * and starts processing them. Called without an open database 413 * transaction, will start one. 414 * 415 * @param[in] cls the `struct TALER_EXCHANGEDB_RuleUpdater *` to run 416 */ 417 static void 418 fetch_latest_rules (void *cls); 419 420 421 /** 422 * Notification called when we either timeout on the AML program lock 423 * or when the (previous) AML program finished and we can thus try again. 424 * 425 * @param cls the `struct TALER_EXCHANGEDB_RuleUpdater *` to continue 426 * @param extra additional event data provided (unused) 427 * @param extra_size number of bytes in @a extra (unused) 428 */ 429 static void 430 trigger_fetch_latest_rules (void *cls, 431 const void *extra, 432 size_t extra_size) 433 { 434 struct TALER_EXCHANGEDB_RuleUpdater *ru = cls; 435 436 (void) extra; 437 (void) extra_size; 438 if (NULL != ru->t) 439 return; /* multiple events triggered us, ignore */ 440 ru->t = GNUNET_SCHEDULER_add_now (&fetch_latest_rules, 441 ru); 442 } 443 444 445 static void 446 run_measure (struct TALER_EXCHANGEDB_RuleUpdater *ru, 447 const struct TALER_KYCLOGIC_Measure *m) 448 { 449 if (NULL == m) 450 { 451 /* fall back to default rules */ 452 TALER_KYCLOGIC_rules_free (ru->lrs); 453 ru->lrs = NULL; 454 return_result (ru); 455 return; 456 } 457 ru->depth++; 458 if (ru->depth > MAX_DEPTH) 459 { 460 fail_update (ru, 461 TALER_EC_EXCHANGE_GENERIC_AML_PROGRAM_RECURSION_DETECTED, 462 NULL); 463 return; 464 } 465 if ( (NULL == m->check_name) || 466 (0 == 467 strcasecmp ("SKIP", 468 m->check_name)) ) 469 { 470 struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = { 471 .account = &ru->account, 472 .is_wallet = ru->is_wallet, 473 .db_plugin = ru->plugin, 474 .attribute_key = &ru->attribute_key 475 }; 476 enum GNUNET_DB_QueryStatus qs; 477 struct GNUNET_TIME_Absolute xlock; 478 479 /* Free previous one, in case we are iterating... */ 480 GNUNET_free (ru->aml_program_name); 481 if (NULL != m->prog_name) 482 { 483 ru->aml_program_name = GNUNET_strdup (m->prog_name); 484 } 485 else 486 { 487 /* How do we get to run a measure if the check type 488 is INFO (which is the only case where prog_name 489 is allowed to be NULL?) */ 490 GNUNET_break (0); 491 ru->aml_program_name = NULL; 492 } 493 qs = ru->plugin->set_aml_lock ( 494 ru->plugin->cls, 495 &ru->account, 496 GNUNET_TIME_relative_multiply (ru->plugin->max_aml_program_runtime, 497 2), 498 &xlock); 499 if (GNUNET_TIME_absolute_is_future (xlock)) 500 { 501 struct TALER_KycCompletedEventP eh = { 502 .header.size = htons (sizeof (eh)), 503 .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED), 504 .h_payto = ru->account 505 }; 506 /* Wait for either timeout or notification */ 507 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 508 "AML program already running, waiting for it to finish\n"); 509 ru->plugin->rollback (ru->plugin->cls); 510 ru->eh 511 = ru->plugin->event_listen ( 512 ru->plugin->cls, 513 GNUNET_TIME_absolute_get_remaining (xlock), 514 &eh.header, 515 &trigger_fetch_latest_rules, 516 ru); 517 return; 518 } 519 qs = ru->plugin->commit (ru->plugin->cls); 520 if (qs < 0) 521 { 522 GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); 523 fail_update (ru, 524 GNUNET_DB_STATUS_SOFT_ERROR == qs 525 ? TALER_EC_GENERIC_DB_SOFT_FAILURE 526 : TALER_EC_GENERIC_DB_COMMIT_FAILED, 527 "current-aml-rule-fetch"); 528 return; 529 } 530 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 531 "Check is of type 'SKIP', running AML program %s.\n", 532 m->prog_name); 533 GNUNET_assert (NULL == ru->t); 534 ru->amlh = TALER_KYCLOGIC_run_aml_program3 ( 535 ru->is_wallet, 536 m, 537 &TALER_EXCHANGEDB_current_attributes_builder, 538 &hbc, 539 &TALER_EXCHANGEDB_current_rule_builder, 540 &hbc, 541 &TALER_EXCHANGEDB_aml_history_builder, 542 &hbc, 543 &TALER_EXCHANGEDB_kyc_history_builder, 544 &hbc, 545 ru->plugin->max_aml_program_runtime, 546 &aml_result_callback, 547 ru); 548 return; 549 } 550 551 /* User MUST pass interactive check */ 552 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 553 "Measure %s involves check %s\n", 554 m->measure_name, 555 m->check_name); 556 { 557 /* activate the measure/check */ 558 json_t *succ_jmeasures 559 = TALER_KYCLOGIC_get_jmeasures ( 560 ru->lrs, 561 m->measure_name); 562 bool unknown_account; 563 struct GNUNET_TIME_Timestamp last_date; 564 enum GNUNET_DB_QueryStatus qs; 565 566 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 567 "Inserting LEGI OUTCOME as successor measure\n"); 568 qs = ru->plugin->insert_successor_measure ( 569 ru->plugin->cls, 570 &ru->account, 571 GNUNET_TIME_timestamp_get (), 572 m->measure_name, 573 succ_jmeasures, 574 &unknown_account, 575 &last_date); 576 json_decref (succ_jmeasures); 577 switch (qs) 578 { 579 case GNUNET_DB_STATUS_SOFT_ERROR: 580 GNUNET_log ( 581 GNUNET_ERROR_TYPE_INFO, 582 "Serialization issue!\n"); 583 fail_update (ru, 584 TALER_EC_GENERIC_DB_SOFT_FAILURE, 585 "insert_successor_measure"); 586 return; 587 case GNUNET_DB_STATUS_HARD_ERROR: 588 GNUNET_break (0); 589 fail_update (ru, 590 TALER_EC_GENERIC_DB_STORE_FAILED, 591 "insert_successor_measure"); 592 return; 593 default: 594 break; 595 } 596 597 // FIXME: combine with above transaction... 598 { 599 struct TALER_KycCompletedEventP eh = { 600 .header.size = htons (sizeof (eh)), 601 .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED), 602 .h_payto = ru->account 603 }; 604 605 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 606 "Triggering KYC COMPLETED event\n"); 607 ru->plugin->event_notify (ru->plugin->cls, 608 &eh.header, 609 NULL, 610 0); 611 } 612 613 if (unknown_account) 614 { 615 fail_update (ru, 616 TALER_EC_EXCHANGE_GENERIC_BANK_ACCOUNT_UNKNOWN, 617 NULL); 618 return; 619 } 620 } 621 /* The rules remain these rules until the user passes the check */ 622 return_result (ru); 623 } 624 625 626 /** 627 * Update the expired legitimization rules in @a ru, checking for expiration 628 * first. Called with an open database transaction. 629 * 630 * @param[in,out] ru account we are processing 631 */ 632 static void 633 update_rules (struct TALER_EXCHANGEDB_RuleUpdater *ru) 634 { 635 const struct TALER_KYCLOGIC_Measure *m; 636 637 GNUNET_assert (NULL != ru->lrs); 638 GNUNET_assert (GNUNET_TIME_absolute_is_past ( 639 TALER_KYCLOGIC_rules_get_expiration (ru->lrs).abs_time)); 640 m = TALER_KYCLOGIC_rules_get_successor (ru->lrs); 641 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 642 "Successor measure is %s.\n", 643 (NULL != m) ? m->measure_name : "(null)"); 644 run_measure (ru, 645 m); 646 } 647 648 649 static void 650 check_rules (struct TALER_EXCHANGEDB_RuleUpdater *ru) 651 { 652 ru->depth++; 653 if (ru->depth > MAX_DEPTH) 654 { 655 fail_update (ru, 656 TALER_EC_EXCHANGE_GENERIC_AML_PROGRAM_RECURSION_DETECTED, 657 NULL); 658 return; 659 } 660 if (NULL == ru->lrs) 661 { 662 /* return NULL, aka default rules */ 663 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 664 "Default rules apply\n"); 665 return_result (ru); 666 return; 667 } 668 if (! GNUNET_TIME_absolute_is_past 669 (TALER_KYCLOGIC_rules_get_expiration (ru->lrs).abs_time) ) 670 { 671 /* Rules did not expire, return them! */ 672 return_result (ru); 673 return; 674 } 675 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 676 "Custom rules expired, updating...\n"); 677 update_rules (ru); 678 } 679 680 681 static void 682 fetch_latest_rules (void *cls) 683 { 684 struct TALER_EXCHANGEDB_RuleUpdater *ru = cls; 685 enum GNUNET_DB_QueryStatus qs; 686 json_t *jnew_rules; 687 enum GNUNET_GenericReturnValue res; 688 689 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 690 "Fetching latest rules."); 691 692 ru->t = NULL; 693 if (NULL != ru->eh) 694 { 695 /* cancel event listener, if we have one */ 696 ru->plugin->event_listen_cancel (ru->plugin->cls, 697 ru->eh); 698 ru->eh = NULL; 699 } 700 GNUNET_break (NULL == ru->lrs); 701 res = ru->plugin->start (ru->plugin->cls, 702 "aml-begin-lookup-rules-by-access-token"); 703 if (GNUNET_OK != res) 704 { 705 GNUNET_break (0); 706 fail_update (ru, 707 TALER_EC_GENERIC_DB_START_FAILED, 708 "aml-begin-lookup-rules-by-access-token"); 709 return; 710 } 711 qs = ru->plugin->lookup_rules_by_access_token ( 712 ru->plugin->cls, 713 &ru->account, 714 &jnew_rules, 715 &ru->legitimization_outcome_last_row); 716 if (qs < 0) 717 { 718 GNUNET_break (0); 719 fail_update (ru, 720 TALER_EC_GENERIC_DB_FETCH_FAILED, 721 "lookup_rules_by_access_token"); 722 return; 723 } 724 if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) && 725 (NULL != jnew_rules) ) 726 { 727 ru->lrs = TALER_KYCLOGIC_rules_parse (jnew_rules); 728 GNUNET_break (NULL != ru->lrs); 729 json_decref (jnew_rules); 730 } 731 check_rules (ru); 732 } 733 734 735 struct TALER_EXCHANGEDB_RuleUpdater * 736 TALER_EXCHANGEDB_update_rules ( 737 struct TALER_EXCHANGEDB_Plugin *plugin, 738 const struct TALER_AttributeEncryptionKeyP *attribute_key, 739 const struct TALER_NormalizedPaytoHashP *account, 740 bool is_wallet, 741 TALER_EXCHANGEDB_CurrentRulesCallback cb, 742 void *cb_cls) 743 { 744 struct TALER_EXCHANGEDB_RuleUpdater *ru; 745 746 ru = GNUNET_new (struct TALER_EXCHANGEDB_RuleUpdater); 747 ru->plugin = plugin; 748 ru->attribute_key = *attribute_key; 749 ru->account = *account; 750 ru->is_wallet = is_wallet; 751 ru->cb = cb; 752 ru->cb_cls = cb_cls; 753 ru->t = GNUNET_SCHEDULER_add_now (&fetch_latest_rules, 754 ru); 755 return ru; 756 } 757 758 759 void 760 TALER_EXCHANGEDB_update_rules_cancel ( 761 struct TALER_EXCHANGEDB_RuleUpdater *ru) 762 { 763 if (NULL != ru->t) 764 { 765 GNUNET_SCHEDULER_cancel (ru->t); 766 ru->t = NULL; 767 } 768 if (NULL != ru->amlh) 769 { 770 TALER_KYCLOGIC_run_aml_program_cancel (ru->amlh); 771 ru->amlh = NULL; 772 } 773 if (NULL != ru->lrs) 774 { 775 TALER_KYCLOGIC_rules_free (ru->lrs); 776 ru->lrs = NULL; 777 } 778 if (NULL != ru->eh) 779 { 780 ru->plugin->event_listen_cancel (ru->plugin->cls, 781 ru->eh); 782 ru->eh = NULL; 783 } 784 GNUNET_free (ru->aml_program_name); 785 GNUNET_free (ru); 786 }