kyclogic_api.c (142577B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2022-2025 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 kyclogic_api.c 18 * @brief server-side KYC API 19 * @author Christian Grothoff 20 */ 21 #include "taler/platform.h" 22 #include "taler/taler_json_lib.h" 23 #include "taler/taler_kyclogic_lib.h" 24 25 /** 26 * Log verbosely, including possibly privacy-sensitive data. 27 */ 28 #define DEBUG 1 29 30 /** 31 * Name of the KYC measure that may never be passed. Useful if some 32 * operations/amounts are categorically forbidden. 33 */ 34 #define KYC_MEASURE_IMPOSSIBLE "verboten" 35 36 /** 37 * Information about a KYC provider. 38 */ 39 struct TALER_KYCLOGIC_KycProvider 40 { 41 42 /** 43 * Name of the provider. 44 */ 45 char *provider_name; 46 47 /** 48 * Logic to run for this provider. 49 */ 50 struct TALER_KYCLOGIC_Plugin *logic; 51 52 /** 53 * Provider-specific details to pass to the @e logic functions. 54 */ 55 struct TALER_KYCLOGIC_ProviderDetails *pd; 56 57 }; 58 59 60 /** 61 * Rule that triggers some measure(s). 62 */ 63 struct TALER_KYCLOGIC_KycRule 64 { 65 66 /** 67 * Name of the rule (configuration section name). 68 * NULL if not from the configuration. 69 */ 70 char *rule_name; 71 72 /** 73 * Rule set with custom measures that this KYC rule 74 * is part of. 75 */ 76 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs; 77 78 /** 79 * Timeframe to consider for computing the amount 80 * to compare against the @e limit. Zero for the 81 * wallet balance trigger (as not applicable). 82 */ 83 struct GNUNET_TIME_Relative timeframe; 84 85 /** 86 * Maximum amount that can be transacted until 87 * the rule triggers. 88 */ 89 struct TALER_Amount threshold; 90 91 /** 92 * Array of names of measures to apply on this trigger. 93 */ 94 char **next_measures; 95 96 /** 97 * Length of the @e next_measures array. 98 */ 99 unsigned int num_measures; 100 101 /** 102 * Display priority for this rule. 103 */ 104 uint32_t display_priority; 105 106 /** 107 * What operation type is this rule for? 108 */ 109 enum TALER_KYCLOGIC_KycTriggerEvent trigger; 110 111 /** 112 * True if all @e next_measures will eventually need to 113 * be satisfied, False if the user has a choice between them. 114 */ 115 bool is_and_combinator; 116 117 /** 118 * True if this rule and the general nature of the next measures 119 * should be exposed to the client. 120 */ 121 bool exposed; 122 123 /** 124 * True if any of the measures is 'verboten' and 125 * thus this rule cannot ever be satisfied. 126 */ 127 bool verboten; 128 129 }; 130 131 132 /** 133 * Set of rules that applies to an account. 134 */ 135 struct TALER_KYCLOGIC_LegitimizationRuleSet 136 { 137 138 /** 139 * When does this rule set expire? 140 */ 141 struct GNUNET_TIME_Timestamp expiration_time; 142 143 /** 144 * Name of the successor measure after expiration. 145 * NULL to revert to default rules. 146 */ 147 char *successor_measure; 148 149 /** 150 * Array of the rules. 151 */ 152 struct TALER_KYCLOGIC_KycRule *kyc_rules; 153 154 /** 155 * Array of custom measures the @e kyc_rules may refer 156 * to. 157 */ 158 struct TALER_KYCLOGIC_Measure *custom_measures; 159 160 /** 161 * Length of the @e kyc_rules array. 162 */ 163 unsigned int num_kyc_rules; 164 165 /** 166 * Length of the @e custom_measures array. 167 */ 168 unsigned int num_custom_measures; 169 170 }; 171 172 173 /** 174 * AML program inputs as per "-i" option of the AML program. 175 * This is a bitmask. 176 */ 177 enum AmlProgramInputs 178 { 179 /** 180 * No inputs are needed. 181 */ 182 API_NONE = 0, 183 184 /** 185 * Context is needed. 186 */ 187 API_CONTEXT = 1, 188 189 /** 190 * Current (just submitted) attributes needed. 191 */ 192 API_ATTRIBUTES = 2, 193 194 /** 195 * Current AML rules are needed. 196 */ 197 API_CURRENT_RULES = 4, 198 199 /** 200 * Default AML rules (that apply to fresh accounts) are needed. 201 */ 202 API_DEFAULT_RULES = 8, 203 204 /** 205 * Account AML history is needed, possibly length-limited, 206 * see ``aml_history_length_limit``. 207 */ 208 API_AML_HISTORY = 16, 209 210 /** 211 * Account KYC history is needed, possibly length-limited, 212 * see ``kyc_history_length_limit`` 213 */ 214 API_KYC_HISTORY = 32, 215 216 }; 217 218 219 /** 220 * AML programs. 221 */ 222 struct TALER_KYCLOGIC_AmlProgram 223 { 224 225 /** 226 * Name of the AML program configuration section. 227 */ 228 char *program_name; 229 230 /** 231 * Name of the AML program (binary) to run. 232 */ 233 char *command; 234 235 /** 236 * Human-readable description of what this AML helper 237 * program will do. 238 */ 239 char *description; 240 241 /** 242 * Name of an original measure to take in case the 243 * @e command fails, NULL to fallback to default rules. 244 */ 245 char *fallback; 246 247 /** 248 * Output of @e command "-r". 249 */ 250 char **required_contexts; 251 252 /** 253 * Length of the @e required_contexts array. 254 */ 255 unsigned int num_required_contexts; 256 257 /** 258 * Output of @e command "-a". 259 */ 260 char **required_attributes; 261 262 /** 263 * Length of the @e required_attributes array. 264 */ 265 unsigned int num_required_attributes; 266 267 /** 268 * Bitmask of inputs this AML program would like (based on '-i'). 269 */ 270 enum AmlProgramInputs input_mask; 271 272 /** 273 * How many entries of the AML history are requested; 274 * negative number if we want the latest entries only. 275 */ 276 long long aml_history_length_limit; 277 278 /** 279 * How many entries of the KYC history are requested; 280 * negative number if we want the latest entries only. 281 */ 282 long long kyc_history_length_limit; 283 284 }; 285 286 287 /** 288 * Array of @e num_kyc_logics KYC logic plugins we have loaded. 289 */ 290 static struct TALER_KYCLOGIC_Plugin **kyc_logics; 291 292 /** 293 * Length of the #kyc_logics array. 294 */ 295 static unsigned int num_kyc_logics; 296 297 /** 298 * Array of configured providers. 299 */ 300 static struct TALER_KYCLOGIC_KycProvider **kyc_providers; 301 302 /** 303 * Length of the #kyc_providers array. 304 */ 305 static unsigned int num_kyc_providers; 306 307 /** 308 * Array of @e num_kyc_checks known types of 309 * KYC checks. 310 */ 311 static struct TALER_KYCLOGIC_KycCheck **kyc_checks; 312 313 /** 314 * Length of the #kyc_checks array. 315 */ 316 static unsigned int num_kyc_checks; 317 318 /** 319 * Rules that apply if we do not have an AMLA record. 320 */ 321 static struct TALER_KYCLOGIC_LegitimizationRuleSet default_rules; 322 323 /** 324 * Array of available AML programs. 325 */ 326 static struct TALER_KYCLOGIC_AmlProgram **aml_programs; 327 328 /** 329 * Length of the #aml_programs array. 330 */ 331 static unsigned int num_aml_programs; 332 333 /** 334 * Name of our configuration file. 335 */ 336 static char *cfg_filename; 337 338 /** 339 * Currency we expect to see in all rules. 340 */ 341 static char *my_currency; 342 343 /** 344 * Default LegitimizationRuleSet for wallets. Excludes *default* measures 345 * even if these are the default rules. 346 */ 347 static json_t *wallet_default_lrs; 348 349 /** 350 * Default LegitimizationRuleSet for bank accounts. Excludes *default* measures 351 * even if these are the default rules. 352 */ 353 static json_t *bankaccount_default_lrs; 354 355 356 struct GNUNET_TIME_Timestamp 357 TALER_KYCLOGIC_rules_get_expiration ( 358 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs) 359 { 360 if (NULL == lrs) 361 return GNUNET_TIME_UNIT_FOREVER_TS; 362 return lrs->expiration_time; 363 } 364 365 366 const struct TALER_KYCLOGIC_Measure * 367 TALER_KYCLOGIC_rules_get_successor ( 368 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs) 369 { 370 const char *successor_measure_name = lrs->successor_measure; 371 372 if (NULL == successor_measure_name) 373 { 374 return NULL; 375 } 376 return TALER_KYCLOGIC_get_measure ( 377 lrs, 378 successor_measure_name); 379 } 380 381 382 /** 383 * Check if @a trigger applies to our context. 384 * 385 * @param trigger the trigger to evaluate 386 * @param is_wallet #GNUNET_YES if this is for a wallet, 387 * #GNUNET_NO for account, 388 * #GNUNET_SYSERR for unknown (returns all rules) 389 * @return true if @a trigger applies in this context 390 */ 391 static bool 392 trigger_applies (enum TALER_KYCLOGIC_KycTriggerEvent trigger, 393 enum GNUNET_GenericReturnValue is_wallet) 394 { 395 switch (trigger) 396 { 397 case TALER_KYCLOGIC_KYC_TRIGGER_NONE: 398 GNUNET_break (0); 399 break; 400 case TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW: 401 return GNUNET_YES != is_wallet; 402 case TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT: 403 return GNUNET_YES != is_wallet; 404 case TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE: 405 return GNUNET_NO != is_wallet; 406 case TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE: 407 return GNUNET_NO != is_wallet; 408 case TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE: 409 return GNUNET_YES != is_wallet; 410 case TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE: 411 return GNUNET_YES != is_wallet; 412 case TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION: 413 return true; 414 case TALER_KYCLOGIC_KYC_TRIGGER_REFUND: 415 return true; 416 } 417 GNUNET_break (0); 418 return true; 419 } 420 421 422 /** 423 * Lookup a KYC check by @a check_name 424 * 425 * @param check_name name to search for 426 * @return NULL if not found 427 */ 428 static struct TALER_KYCLOGIC_KycCheck * 429 find_check (const char *check_name) 430 { 431 for (unsigned int i = 0; i<num_kyc_checks; i++) 432 { 433 struct TALER_KYCLOGIC_KycCheck *kyc_check 434 = kyc_checks[i]; 435 436 if (0 == strcasecmp (check_name, 437 kyc_check->check_name)) 438 return kyc_check; 439 } 440 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 441 "Check `%s' unknown\n", 442 check_name); 443 return NULL; 444 } 445 446 447 /** 448 * Lookup AML program by @a program_name 449 * 450 * @param program_name name to search for 451 * @return NULL if not found 452 */ 453 static struct TALER_KYCLOGIC_AmlProgram * 454 find_program (const char *program_name) 455 { 456 if (NULL == program_name) 457 { 458 GNUNET_break (0); 459 return NULL; 460 } 461 for (unsigned int i = 0; i<num_aml_programs; i++) 462 { 463 struct TALER_KYCLOGIC_AmlProgram *program 464 = aml_programs[i]; 465 466 if (0 == strcasecmp (program_name, 467 program->program_name)) 468 return program; 469 } 470 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 471 "AML program `%s' unknown\n", 472 program_name); 473 return NULL; 474 } 475 476 477 /** 478 * Lookup KYC provider by @a provider_name 479 * 480 * @param provider_name name to search for 481 * @return NULL if not found 482 */ 483 static struct TALER_KYCLOGIC_KycProvider * 484 find_provider (const char *provider_name) 485 { 486 for (unsigned int i = 0; i<num_kyc_providers; i++) 487 { 488 struct TALER_KYCLOGIC_KycProvider *provider 489 = kyc_providers[i]; 490 491 if (0 == strcasecmp (provider_name, 492 provider->provider_name)) 493 return provider; 494 } 495 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 496 "KYC provider `%s' unknown\n", 497 provider_name); 498 return NULL; 499 } 500 501 502 /** 503 * Check that @a measure is well-formed and internally 504 * consistent. 505 * 506 * @param measure measure to check 507 * @return true if measure is well-formed 508 */ 509 static bool 510 check_measure (const struct TALER_KYCLOGIC_Measure *measure) 511 { 512 const struct TALER_KYCLOGIC_KycCheck *check; 513 514 check = find_check (measure->check_name); 515 if ( (NULL == check) && 516 (0 != strcasecmp (measure->check_name, 517 "SKIP")) ) 518 { 519 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 520 "Unknown check `%s' used in measure `%s'\n", 521 measure->check_name, 522 measure->measure_name); 523 return false; 524 } 525 if ( (NULL == check) || 526 (TALER_KYCLOGIC_CT_INFO != check->type) ) 527 { 528 const struct TALER_KYCLOGIC_AmlProgram *program; 529 530 program = find_program (measure->prog_name); 531 if (NULL == program) 532 { 533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 534 "Unknown program `%s' used in measure `%s'\n", 535 measure->prog_name, 536 measure->measure_name); 537 return false; 538 } 539 for (unsigned int j = 0; j<program->num_required_contexts; j++) 540 { 541 const char *required_context = program->required_contexts[j]; 542 543 if (NULL == 544 json_object_get (measure->context, 545 required_context)) 546 { 547 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 548 "Measure `%s' lacks required context `%s' for AML program `%s'\n", 549 measure->measure_name, 550 required_context, 551 program->program_name); 552 return false; 553 } 554 } 555 if (0 == strcasecmp (measure->check_name, 556 "SKIP")) 557 { 558 if (0 != program->num_required_attributes) 559 { 560 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 561 "AML program `%s' of measure `%s' has required attributes, but check is of type `SKIP' and thus cannot provide any!\n", 562 program->program_name, 563 measure->measure_name); 564 return false; 565 } 566 return true; 567 } 568 for (unsigned int j = 0; j<program->num_required_attributes; j++) 569 { 570 const char *required_attribute = program->required_attributes[j]; 571 bool found = false; 572 573 if (NULL != check) 574 { 575 for (unsigned int i = 0; i<check->num_outputs; i++) 576 { 577 if (0 == strcasecmp (required_attribute, 578 check->outputs[i])) 579 { 580 found = true; 581 break; 582 } 583 } 584 } 585 if (! found) 586 { 587 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 588 "Check `%s' of measure `%s' does not provide required output `%s' for AML program `%s'\n", 589 measure->check_name, 590 measure->measure_name, 591 required_attribute, 592 program->program_name); 593 return false; 594 } 595 } 596 } 597 else 598 { 599 /* Check is of type "INFO" */ 600 if (NULL != measure->prog_name) 601 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 602 "Program `%s' used in INFO measure `%s' will never be used.\n", 603 measure->prog_name, 604 measure->measure_name); 605 if (0 == strcasecmp (measure->check_name, 606 "SKIP")) 607 { 608 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 609 "INFO check of measure `%s' should not be called 'SKIP'.\n", 610 measure->measure_name); 611 return false; 612 } 613 } 614 if (NULL != check) 615 { 616 for (unsigned int j = 0; j<check->num_requires; j++) 617 { 618 const char *required_input = check->requires[j]; 619 620 if (NULL == 621 json_object_get (measure->context, 622 required_input)) 623 { 624 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 625 "Measure `%s' lacks required context `%s' for check `%s'\n", 626 measure->measure_name, 627 required_input, 628 measure->check_name); 629 return false; 630 } 631 } 632 } 633 return true; 634 } 635 636 637 /** 638 * Find measure @a measure_name in @a lrs. 639 * If measure is not found in @a lrs, fall back to 640 * default measures. 641 * 642 * @param lrs rule set to search, can be NULL to only search default measures 643 * @param measure_name name of measure to find 644 * @return NULL if not found, otherwise the measure 645 */ 646 static const struct TALER_KYCLOGIC_Measure * 647 find_measure ( 648 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs, 649 const char *measure_name) 650 { 651 if (NULL != lrs) 652 { 653 for (unsigned int i = 0; i<lrs->num_custom_measures; i++) 654 { 655 const struct TALER_KYCLOGIC_Measure *cm 656 = &lrs->custom_measures[i]; 657 658 if (0 == strcasecmp (measure_name, 659 cm->measure_name)) 660 return cm; 661 } 662 } 663 if (lrs != &default_rules) 664 { 665 /* Try measures from default rules */ 666 for (unsigned int i = 0; i<default_rules.num_custom_measures; i++) 667 { 668 const struct TALER_KYCLOGIC_Measure *cm 669 = &default_rules.custom_measures[i]; 670 671 if (0 == strcasecmp (measure_name, 672 cm->measure_name)) 673 return cm; 674 } 675 } 676 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 677 "Measure `%s' not found\n", 678 measure_name); 679 return NULL; 680 } 681 682 683 struct TALER_KYCLOGIC_LegitimizationRuleSet * 684 TALER_KYCLOGIC_rules_parse (const json_t *jlrs) 685 { 686 struct GNUNET_TIME_Timestamp expiration_time; 687 const char *successor_measure = NULL; 688 const json_t *jrules; 689 const json_t *jcustom_measures; 690 struct GNUNET_JSON_Specification spec[] = { 691 GNUNET_JSON_spec_timestamp ( 692 "expiration_time", 693 &expiration_time), 694 GNUNET_JSON_spec_mark_optional ( 695 GNUNET_JSON_spec_string ( 696 "successor_measure", 697 &successor_measure), 698 NULL), 699 GNUNET_JSON_spec_array_const ("rules", 700 &jrules), 701 GNUNET_JSON_spec_object_const ("custom_measures", 702 &jcustom_measures), 703 GNUNET_JSON_spec_end () 704 }; 705 struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs; 706 const char *err; 707 unsigned int line; 708 709 if (NULL == jlrs) 710 { 711 GNUNET_break_op (0); 712 return NULL; 713 } 714 if (GNUNET_OK != 715 GNUNET_JSON_parse (jlrs, 716 spec, 717 &err, 718 &line)) 719 { 720 GNUNET_break_op (0); 721 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 722 "Legitimization rules have incorrect input field `%s'\n", 723 err); 724 json_dumpf (jlrs, 725 stderr, 726 JSON_INDENT (2)); 727 return NULL; 728 } 729 lrs = GNUNET_new (struct TALER_KYCLOGIC_LegitimizationRuleSet); 730 lrs->expiration_time = expiration_time; 731 lrs->successor_measure 732 = (NULL == successor_measure) 733 ? NULL 734 : GNUNET_strdup (successor_measure); 735 lrs->num_custom_measures 736 = (unsigned int) json_object_size (jcustom_measures); 737 if (((size_t) lrs->num_custom_measures) != 738 json_object_size (jcustom_measures)) 739 { 740 GNUNET_break (0); 741 goto cleanup; 742 } 743 744 if (0 != lrs->num_custom_measures) 745 { 746 lrs->custom_measures 747 = GNUNET_new_array (lrs->num_custom_measures, 748 struct TALER_KYCLOGIC_Measure); 749 750 { 751 const json_t *jmeasure; 752 const char *measure_name; 753 unsigned int off = 0; 754 755 json_object_foreach ((json_t *) jcustom_measures, 756 measure_name, 757 jmeasure) 758 { 759 const char *check_name; 760 const char *prog_name = NULL; 761 const json_t *context = NULL; 762 bool voluntary = false; 763 struct TALER_KYCLOGIC_Measure *measure 764 = &lrs->custom_measures[off++]; 765 struct GNUNET_JSON_Specification ispec[] = { 766 GNUNET_JSON_spec_string ("check_name", 767 &check_name), 768 GNUNET_JSON_spec_mark_optional ( 769 GNUNET_JSON_spec_string ("prog_name", 770 &prog_name), 771 NULL), 772 GNUNET_JSON_spec_mark_optional ( 773 GNUNET_JSON_spec_object_const ("context", 774 &context), 775 NULL), 776 GNUNET_JSON_spec_mark_optional ( 777 GNUNET_JSON_spec_bool ("voluntary", 778 &voluntary), 779 NULL), 780 GNUNET_JSON_spec_end () 781 }; 782 783 if (GNUNET_OK != 784 GNUNET_JSON_parse (jmeasure, 785 ispec, 786 NULL, NULL)) 787 { 788 GNUNET_break_op (0); 789 goto cleanup; 790 } 791 measure->measure_name 792 = GNUNET_strdup (measure_name); 793 measure->check_name 794 = GNUNET_strdup (check_name); 795 if (NULL != prog_name) 796 measure->prog_name 797 = GNUNET_strdup (prog_name); 798 measure->voluntary 799 = voluntary; 800 if (NULL != context) 801 measure->context 802 = json_incref ((json_t*) context); 803 if (! check_measure (measure)) 804 { 805 GNUNET_break_op (0); 806 goto cleanup; 807 } 808 } 809 } 810 } 811 812 lrs->num_kyc_rules 813 = (unsigned int) json_array_size (jrules); 814 if (((size_t) lrs->num_kyc_rules) != 815 json_array_size (jrules)) 816 { 817 GNUNET_break (0); 818 goto cleanup; 819 } 820 lrs->kyc_rules 821 = GNUNET_new_array (lrs->num_kyc_rules, 822 struct TALER_KYCLOGIC_KycRule); 823 { 824 const json_t *jrule; 825 size_t off; 826 827 json_array_foreach ((json_t *) jrules, 828 off, 829 jrule) 830 { 831 struct TALER_KYCLOGIC_KycRule *rule 832 = &lrs->kyc_rules[off]; 833 const json_t *jmeasures; 834 const char *rn = NULL; 835 struct GNUNET_JSON_Specification ispec[] = { 836 TALER_JSON_spec_kycte ("operation_type", 837 &rule->trigger), 838 TALER_JSON_spec_amount ("threshold", 839 my_currency, 840 &rule->threshold), 841 GNUNET_JSON_spec_relative_time ("timeframe", 842 &rule->timeframe), 843 GNUNET_JSON_spec_array_const ("measures", 844 &jmeasures), 845 GNUNET_JSON_spec_uint32 ("display_priority", 846 &rule->display_priority), 847 GNUNET_JSON_spec_mark_optional ( 848 GNUNET_JSON_spec_bool ("exposed", 849 &rule->exposed), 850 NULL), 851 GNUNET_JSON_spec_mark_optional ( 852 GNUNET_JSON_spec_string ("rule_name", 853 &rn), 854 NULL), 855 GNUNET_JSON_spec_mark_optional ( 856 GNUNET_JSON_spec_bool ("is_and_combinator", 857 &rule->is_and_combinator), 858 NULL), 859 GNUNET_JSON_spec_end () 860 }; 861 862 if (GNUNET_OK != 863 GNUNET_JSON_parse (jrule, 864 ispec, 865 NULL, NULL)) 866 { 867 GNUNET_break_op (0); 868 goto cleanup; 869 } 870 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 871 "Parsed KYC rule %u for %d with threshold %s\n", 872 (unsigned int) off, 873 (int) rule->trigger, 874 TALER_amount2s (&rule->threshold)); 875 rule->lrs = lrs; 876 if (NULL != rn) 877 rule->rule_name = GNUNET_strdup (rn); 878 rule->num_measures = json_array_size (jmeasures); 879 rule->next_measures 880 = GNUNET_new_array (rule->num_measures, 881 char *); 882 if (((size_t) rule->num_measures) != 883 json_array_size (jmeasures)) 884 { 885 GNUNET_break (0); 886 goto cleanup; 887 } 888 { 889 size_t j; 890 json_t *jmeasure; 891 892 json_array_foreach (jmeasures, 893 j, 894 jmeasure) 895 { 896 const char *str; 897 898 str = json_string_value (jmeasure); 899 if (NULL == str) 900 { 901 GNUNET_break (0); 902 goto cleanup; 903 } 904 if (0 == strcasecmp (str, 905 KYC_MEASURE_IMPOSSIBLE)) 906 { 907 rule->verboten = true; 908 continue; 909 } 910 else if (NULL == 911 find_measure (lrs, 912 str)) 913 { 914 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 915 "Measure `%s' specified in rule set unknown\n", 916 str); 917 GNUNET_break_op (0); 918 goto cleanup; 919 } 920 rule->next_measures[j] 921 = GNUNET_strdup (str); 922 } 923 } 924 } 925 } 926 return lrs; 927 cleanup: 928 TALER_KYCLOGIC_rules_free (lrs); 929 return NULL; 930 } 931 932 933 void 934 TALER_KYCLOGIC_rules_free (struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs) 935 { 936 if (NULL == lrs) 937 return; 938 for (unsigned int i = 0; i<lrs->num_kyc_rules; i++) 939 { 940 struct TALER_KYCLOGIC_KycRule *rule 941 = &lrs->kyc_rules[i]; 942 943 for (unsigned int j = 0; j<rule->num_measures; j++) 944 GNUNET_free (rule->next_measures[j]); 945 GNUNET_free (rule->next_measures); 946 GNUNET_free (rule->rule_name); 947 } 948 for (unsigned int i = 0; i<lrs->num_custom_measures; i++) 949 { 950 struct TALER_KYCLOGIC_Measure *measure 951 = &lrs->custom_measures[i]; 952 953 GNUNET_free (measure->measure_name); 954 GNUNET_free (measure->check_name); 955 GNUNET_free (measure->prog_name); 956 json_decref (measure->context); 957 } 958 GNUNET_free (lrs->kyc_rules); 959 GNUNET_free (lrs->custom_measures); 960 GNUNET_free (lrs->successor_measure); 961 GNUNET_free (lrs); 962 } 963 964 965 const char * 966 TALER_KYCLOGIC_rule2s ( 967 const struct TALER_KYCLOGIC_KycRule *r) 968 { 969 return r->rule_name; 970 } 971 972 973 const char * 974 TALER_KYCLOGIC_status2s (enum TALER_KYCLOGIC_KycStatus status) 975 { 976 switch (status) 977 { 978 case TALER_KYCLOGIC_STATUS_SUCCESS: 979 return "success"; 980 case TALER_KYCLOGIC_STATUS_USER: 981 return "user"; 982 case TALER_KYCLOGIC_STATUS_PROVIDER: 983 return "provider"; 984 case TALER_KYCLOGIC_STATUS_FAILED: 985 return "failed"; 986 case TALER_KYCLOGIC_STATUS_PENDING: 987 return "pending"; 988 case TALER_KYCLOGIC_STATUS_ABORTED: 989 return "aborted"; 990 case TALER_KYCLOGIC_STATUS_USER_PENDING: 991 return "pending with user"; 992 case TALER_KYCLOGIC_STATUS_PROVIDER_PENDING: 993 return "pending at provider"; 994 case TALER_KYCLOGIC_STATUS_USER_ABORTED: 995 return "aborted by user"; 996 case TALER_KYCLOGIC_STATUS_PROVIDER_FAILED: 997 return "failed by provider"; 998 case TALER_KYCLOGIC_STATUS_KEEP: 999 return "keep"; 1000 case TALER_KYCLOGIC_STATUS_INTERNAL_ERROR: 1001 return "internal error"; 1002 } 1003 return "unknown status"; 1004 } 1005 1006 1007 json_t * 1008 TALER_KYCLOGIC_rules_to_limits (const json_t *jrules, 1009 enum GNUNET_GenericReturnValue is_wallet) 1010 { 1011 if (NULL == jrules) 1012 { 1013 /* default limits apply */ 1014 const struct TALER_KYCLOGIC_KycRule *rules 1015 = default_rules.kyc_rules; 1016 unsigned int num_rules 1017 = default_rules.num_kyc_rules; 1018 json_t *jlimits; 1019 1020 jlimits = json_array (); 1021 GNUNET_assert (NULL != jlimits); 1022 for (unsigned int i = 0; i<num_rules; i++) 1023 { 1024 const struct TALER_KYCLOGIC_KycRule *rule = &rules[i]; 1025 json_t *limit; 1026 1027 if (! rule->exposed) 1028 continue; 1029 if (! trigger_applies (rule->trigger, 1030 is_wallet)) 1031 continue; 1032 limit = GNUNET_JSON_PACK ( 1033 GNUNET_JSON_pack_allow_null ( 1034 GNUNET_JSON_pack_string ("rule_name", 1035 rule->rule_name)), 1036 GNUNET_JSON_pack_bool ("soft_limit", 1037 ! rule->verboten), 1038 TALER_JSON_pack_kycte ("operation_type", 1039 rule->trigger), 1040 GNUNET_JSON_pack_time_rel ("timeframe", 1041 rule->timeframe), 1042 TALER_JSON_pack_amount ("threshold", 1043 &rule->threshold) 1044 ); 1045 GNUNET_assert (0 == 1046 json_array_append_new (jlimits, 1047 limit)); 1048 } 1049 return jlimits; 1050 } 1051 1052 { 1053 const json_t *rules; 1054 json_t *limits; 1055 json_t *limit; 1056 json_t *rule; 1057 size_t idx; 1058 1059 rules = json_object_get (jrules, 1060 "rules"); 1061 limits = json_array (); 1062 GNUNET_assert (NULL != limits); 1063 json_array_foreach ((json_t *) rules, idx, rule) 1064 { 1065 struct GNUNET_TIME_Relative timeframe; 1066 struct TALER_Amount threshold; 1067 bool exposed = false; 1068 const json_t *jmeasures; 1069 const char *rule_name; 1070 enum TALER_KYCLOGIC_KycTriggerEvent operation_type; 1071 struct GNUNET_JSON_Specification spec[] = { 1072 TALER_JSON_spec_kycte ("operation_type", 1073 &operation_type), 1074 GNUNET_JSON_spec_relative_time ("timeframe", 1075 &timeframe), 1076 TALER_JSON_spec_amount ("threshold", 1077 my_currency, 1078 &threshold), 1079 GNUNET_JSON_spec_array_const ("measures", 1080 &jmeasures), 1081 GNUNET_JSON_spec_mark_optional ( 1082 GNUNET_JSON_spec_bool ("exposed", 1083 &exposed), 1084 NULL), 1085 GNUNET_JSON_spec_mark_optional ( 1086 GNUNET_JSON_spec_string ("rule_name", 1087 &rule_name), 1088 NULL), 1089 GNUNET_JSON_spec_end () 1090 }; 1091 bool forbidden = false; 1092 size_t i; 1093 json_t *jmeasure; 1094 1095 if (GNUNET_OK != 1096 GNUNET_JSON_parse (rule, 1097 spec, 1098 NULL, NULL)) 1099 { 1100 GNUNET_break_op (0); 1101 json_decref (limits); 1102 return NULL; 1103 } 1104 if (! exposed) 1105 continue; 1106 if (! trigger_applies (operation_type, 1107 is_wallet)) 1108 { 1109 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1110 "Skipping rule #%u that does not apply to %s\n", 1111 (unsigned int) idx, 1112 is_wallet ? "wallets" : "accounts"); 1113 json_dumpf (rule, 1114 stderr, 1115 JSON_INDENT (2)); 1116 continue; 1117 } 1118 json_array_foreach (jmeasures, i, jmeasure) 1119 { 1120 const char *val; 1121 1122 val = json_string_value (jmeasure); 1123 if (NULL == val) 1124 { 1125 GNUNET_break_op (0); 1126 json_decref (limits); 1127 return NULL; 1128 } 1129 if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE, 1130 val)) 1131 forbidden = true; 1132 } 1133 1134 limit = GNUNET_JSON_PACK ( 1135 GNUNET_JSON_pack_allow_null ( 1136 GNUNET_JSON_pack_string ("rule_name", 1137 rule_name)), 1138 TALER_JSON_pack_kycte ( 1139 "operation_type", 1140 operation_type), 1141 GNUNET_JSON_pack_time_rel ( 1142 "timeframe", 1143 timeframe), 1144 TALER_JSON_pack_amount ( 1145 "threshold", 1146 &threshold), 1147 /* optional since v21, defaults to 'false' */ 1148 GNUNET_JSON_pack_bool ( 1149 "soft_limit", 1150 ! forbidden)); 1151 GNUNET_assert (0 == 1152 json_array_append_new (limits, 1153 limit)); 1154 } 1155 return limits; 1156 } 1157 } 1158 1159 1160 const struct TALER_KYCLOGIC_Measure * 1161 TALER_KYCLOGIC_rule_get_instant_measure ( 1162 const struct TALER_KYCLOGIC_KycRule *r) 1163 { 1164 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs 1165 = r->lrs; 1166 1167 if (r->verboten) 1168 return NULL; 1169 for (unsigned int i = 0; i<r->num_measures; i++) 1170 { 1171 const char *measure_name = r->next_measures[i]; 1172 const struct TALER_KYCLOGIC_Measure *ms; 1173 1174 if (0 == strcasecmp (measure_name, 1175 KYC_MEASURE_IMPOSSIBLE)) 1176 { 1177 /* If any of the measures if verboten, we do not even 1178 consider execution of the instant measure. */ 1179 return NULL; 1180 } 1181 1182 ms = find_measure (lrs, 1183 measure_name); 1184 if (NULL == ms) 1185 { 1186 GNUNET_break (0); 1187 return NULL; 1188 } 1189 if (0 == strcasecmp (ms->check_name, 1190 "SKIP")) 1191 return ms; 1192 } 1193 return NULL; 1194 } 1195 1196 1197 json_t * 1198 TALER_KYCLOGIC_rule_to_measures ( 1199 const struct TALER_KYCLOGIC_KycRule *r) 1200 { 1201 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs 1202 = r->lrs; 1203 json_t *jmeasures; 1204 1205 jmeasures = json_array (); 1206 GNUNET_assert (NULL != jmeasures); 1207 if (! r->verboten) 1208 { 1209 for (unsigned int i = 0; i<r->num_measures; i++) 1210 { 1211 const char *measure_name = r->next_measures[i]; 1212 const struct TALER_KYCLOGIC_Measure *ms; 1213 json_t *mi; 1214 1215 if (0 == 1216 strcasecmp (measure_name, 1217 KYC_MEASURE_IMPOSSIBLE)) 1218 { 1219 /* This case should be covered via the 'verboten' flag! */ 1220 GNUNET_break (0); 1221 continue; 1222 } 1223 ms = find_measure (lrs, 1224 measure_name); 1225 if (NULL == ms) 1226 { 1227 GNUNET_break (0); 1228 json_decref (jmeasures); 1229 return NULL; 1230 } 1231 mi = GNUNET_JSON_PACK ( 1232 GNUNET_JSON_pack_string ("check_name", 1233 ms->check_name), 1234 GNUNET_JSON_pack_allow_null ( 1235 GNUNET_JSON_pack_string ("prog_name", 1236 ms->prog_name)), 1237 GNUNET_JSON_pack_allow_null ( 1238 GNUNET_JSON_pack_object_incref ("context", 1239 ms->context))); 1240 GNUNET_assert (0 == 1241 json_array_append_new (jmeasures, 1242 mi)); 1243 } 1244 } 1245 1246 return GNUNET_JSON_PACK ( 1247 GNUNET_JSON_pack_array_steal ("measures", 1248 jmeasures), 1249 GNUNET_JSON_pack_bool ("is_and_combinator", 1250 r->is_and_combinator), 1251 GNUNET_JSON_pack_bool ("verboten", 1252 r->verboten)); 1253 } 1254 1255 1256 json_t * 1257 TALER_KYCLOGIC_zero_measures ( 1258 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs, 1259 enum GNUNET_GenericReturnValue is_wallet) 1260 { 1261 json_t *zero_measures; 1262 const struct TALER_KYCLOGIC_KycRule *rules; 1263 unsigned int num_zero_measures = 0; 1264 1265 if (NULL == lrs) 1266 lrs = &default_rules; 1267 rules = lrs->kyc_rules; 1268 zero_measures = json_array (); 1269 GNUNET_assert (NULL != zero_measures); 1270 for (unsigned int i = 0; i<lrs->num_kyc_rules; i++) 1271 { 1272 const struct TALER_KYCLOGIC_KycRule *rule = &rules[i]; 1273 1274 if (! rule->exposed) 1275 continue; 1276 if (rule->verboten) 1277 continue; /* see: hard_limits */ 1278 if (! trigger_applies (rule->trigger, 1279 is_wallet)) 1280 continue; 1281 if (! TALER_amount_is_zero (&rule->threshold)) 1282 continue; 1283 for (unsigned int j = 0; j<rule->num_measures; j++) 1284 { 1285 const struct TALER_KYCLOGIC_Measure *ms; 1286 json_t *mi; 1287 1288 ms = find_measure (lrs, 1289 rule->next_measures[j]); 1290 if (NULL == ms) 1291 { 1292 /* Error in the configuration, should've been 1293 * caught before. We simply ignore the bad measure. */ 1294 GNUNET_break (0); 1295 continue; 1296 } 1297 if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE, 1298 ms->check_name)) 1299 continue; /* not a measure to be selected */ 1300 mi = GNUNET_JSON_PACK ( 1301 GNUNET_JSON_pack_allow_null ( 1302 GNUNET_JSON_pack_string ("rule_name", 1303 rule->rule_name)), 1304 TALER_JSON_pack_kycte ("operation_type", 1305 rule->trigger), 1306 GNUNET_JSON_pack_string ("check_name", 1307 ms->check_name), 1308 GNUNET_JSON_pack_allow_null ( 1309 GNUNET_JSON_pack_string ("prog_name", 1310 ms->prog_name)), 1311 GNUNET_JSON_pack_allow_null ( 1312 GNUNET_JSON_pack_object_incref ("context", 1313 ms->context))); 1314 GNUNET_assert (0 == 1315 json_array_append_new (zero_measures, 1316 mi)); 1317 num_zero_measures++; 1318 } 1319 } 1320 if (0 == num_zero_measures) 1321 { 1322 json_decref (zero_measures); 1323 return NULL; 1324 } 1325 return GNUNET_JSON_PACK ( 1326 GNUNET_JSON_pack_array_steal ("measures", 1327 zero_measures), 1328 /* Zero-measures are always OR */ 1329 GNUNET_JSON_pack_bool ("is_and_combinator", 1330 false), 1331 /* OR means verboten measures do not matter */ 1332 GNUNET_JSON_pack_bool ("verboten", 1333 false)); 1334 } 1335 1336 1337 /** 1338 * Check if @a ms is a voluntary measure, and if so 1339 * convert to JSON and append to @a voluntary_measures. 1340 * 1341 * @param[in,out] voluntary_measures JSON array of MeasureInformation 1342 * @param ms a measure to possibly append 1343 */ 1344 static void 1345 append_voluntary_measure ( 1346 json_t *voluntary_measures, 1347 const struct TALER_KYCLOGIC_Measure *ms) 1348 { 1349 #if 0 1350 json_t *mj; 1351 #endif 1352 1353 if (! ms->voluntary) 1354 return; 1355 if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE, 1356 ms->check_name)) 1357 return; /* very strange configuration */ 1358 #if 0 1359 /* FIXME: support vATTEST-#9048 (this API in kyclogic!) */ 1360 // NOTE: need to convert ms to "KycRequirementInformation" 1361 // *and* in particular generate "id" values that 1362 // are then understood to refer to the voluntary measures 1363 // by the rest of the API (which is the hard part!) 1364 // => need to change the API to encode the 1365 // legitimization_outcomes row ID of the lrs from 1366 // which the voluntary 'ms' originated, and 1367 // then update the kyc-upload/kyc-start endpoints 1368 // to recognize the new ID format! 1369 mj = GNUNET_JSON_PACK ( 1370 GNUNET_JSON_pack_string ("check_name", 1371 ms->check_name), 1372 GNUNET_JSON_pack_allow_null ( 1373 GNUNET_JSON_pack_string ("prog_name", 1374 ms->prog_name)), 1375 GNUNET_JSON_pack_allow_null ( 1376 GNUNET_JSON_pack_object_incref ("context", 1377 ms->context))); 1378 GNUNET_assert (0 == 1379 json_array_append_new (voluntary_measures, 1380 mj)); 1381 #endif 1382 } 1383 1384 1385 json_t * 1386 TALER_KYCLOGIC_voluntary_measures ( 1387 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs) 1388 { 1389 json_t *voluntary_measures; 1390 1391 voluntary_measures = json_array (); 1392 GNUNET_assert (NULL != voluntary_measures); 1393 if (NULL != lrs) 1394 { 1395 for (unsigned int i = 0; i<lrs->num_custom_measures; i++) 1396 { 1397 const struct TALER_KYCLOGIC_Measure *ms 1398 = &lrs->custom_measures[i]; 1399 1400 append_voluntary_measure (voluntary_measures, 1401 ms); 1402 } 1403 } 1404 for (unsigned int i = 0; i<default_rules.num_custom_measures; i++) 1405 { 1406 const struct TALER_KYCLOGIC_Measure *ms 1407 = &default_rules.custom_measures[i]; 1408 1409 append_voluntary_measure (voluntary_measures, 1410 ms); 1411 } 1412 return voluntary_measures; 1413 } 1414 1415 1416 const struct TALER_KYCLOGIC_Measure * 1417 TALER_KYCLOGIC_get_instant_measure ( 1418 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs, 1419 const char *measures_spec) 1420 { 1421 char *nm; 1422 const struct TALER_KYCLOGIC_Measure *ret = NULL; 1423 1424 GNUNET_assert (NULL != measures_spec); 1425 1426 if ('+' == measures_spec[0]) 1427 { 1428 nm = GNUNET_strdup (&measures_spec[1]); 1429 } 1430 else 1431 { 1432 nm = GNUNET_strdup (measures_spec); 1433 } 1434 for (const char *tok = strtok (nm, " "); 1435 NULL != tok; 1436 tok = strtok (NULL, " ")) 1437 { 1438 const struct TALER_KYCLOGIC_Measure *ms; 1439 1440 if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE, 1441 tok)) 1442 { 1443 continue; 1444 } 1445 ms = find_measure (lrs, 1446 tok); 1447 if (NULL == ms) 1448 { 1449 GNUNET_break (0); 1450 continue; 1451 } 1452 if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE, 1453 ms->check_name)) 1454 { 1455 continue; 1456 } 1457 if (0 == strcasecmp ("SKIP", 1458 ms->check_name)) 1459 { 1460 ret = ms; 1461 goto done; 1462 } 1463 } 1464 done: 1465 GNUNET_free (nm); 1466 return ret; 1467 } 1468 1469 1470 const struct TALER_KYCLOGIC_Measure * 1471 TALER_KYCLOGIC_get_measure ( 1472 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs, 1473 const char *measure_name) 1474 { 1475 return find_measure (lrs, 1476 measure_name); 1477 } 1478 1479 1480 json_t * 1481 TALER_KYCLOGIC_get_jmeasures ( 1482 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs, 1483 const char *measures_spec) 1484 { 1485 json_t *jmeasures; 1486 char *nm; 1487 bool verboten = false; 1488 bool is_and = false; 1489 1490 if ('+' == measures_spec[0]) 1491 { 1492 nm = GNUNET_strdup (&measures_spec[1]); 1493 is_and = true; 1494 } 1495 else 1496 { 1497 nm = GNUNET_strdup (measures_spec); 1498 } 1499 jmeasures = json_array (); 1500 GNUNET_assert (NULL != jmeasures); 1501 for (const char *tok = strtok (nm, " "); 1502 NULL != tok; 1503 tok = strtok (NULL, " ")) 1504 { 1505 const struct TALER_KYCLOGIC_Measure *ms; 1506 json_t *mi; 1507 1508 if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE, 1509 tok)) 1510 { 1511 verboten = true; 1512 continue; 1513 } 1514 ms = find_measure (lrs, 1515 tok); 1516 if (NULL == ms) 1517 { 1518 GNUNET_break (0); 1519 GNUNET_free (nm); 1520 json_decref (jmeasures); 1521 return NULL; 1522 } 1523 mi = GNUNET_JSON_PACK ( 1524 GNUNET_JSON_pack_string ("check_name", 1525 ms->check_name), 1526 GNUNET_JSON_pack_allow_null ( 1527 GNUNET_JSON_pack_string ("prog_name", 1528 ms->prog_name)), 1529 GNUNET_JSON_pack_allow_null ( 1530 GNUNET_JSON_pack_object_incref ("context", 1531 ms->context))); 1532 GNUNET_assert (0 == 1533 json_array_append_new (jmeasures, 1534 mi)); 1535 } 1536 GNUNET_free (nm); 1537 return GNUNET_JSON_PACK ( 1538 GNUNET_JSON_pack_array_steal ("measures", 1539 jmeasures), 1540 GNUNET_JSON_pack_bool ("is_and_combinator", 1541 is_and), 1542 GNUNET_JSON_pack_bool ("verboten", 1543 verboten)); 1544 } 1545 1546 1547 json_t * 1548 TALER_KYCLOGIC_check_to_jmeasures ( 1549 const struct TALER_KYCLOGIC_KycCheckContext *kcc) 1550 { 1551 const struct TALER_KYCLOGIC_KycCheck *check 1552 = kcc->check; 1553 json_t *jmeasures; 1554 json_t *mi; 1555 1556 mi = GNUNET_JSON_PACK ( 1557 GNUNET_JSON_pack_string ("check_name", 1558 NULL == check 1559 ? "SKIP" 1560 : check->check_name), 1561 GNUNET_JSON_pack_allow_null ( 1562 GNUNET_JSON_pack_string ("prog_name", 1563 kcc->prog_name)), 1564 GNUNET_JSON_pack_allow_null ( 1565 GNUNET_JSON_pack_object_incref ("context", 1566 (json_t *) kcc->context))); 1567 jmeasures = json_array (); 1568 GNUNET_assert (NULL != jmeasures); 1569 GNUNET_assert (0 == 1570 json_array_append_new (jmeasures, 1571 mi)); 1572 return GNUNET_JSON_PACK ( 1573 GNUNET_JSON_pack_array_steal ("measures", 1574 jmeasures), 1575 GNUNET_JSON_pack_bool ("is_and_combinator", 1576 true), 1577 GNUNET_JSON_pack_bool ("verboten", 1578 false)); 1579 } 1580 1581 1582 json_t * 1583 TALER_KYCLOGIC_measure_to_jmeasures ( 1584 const struct TALER_KYCLOGIC_Measure *m) 1585 { 1586 json_t *jmeasures; 1587 json_t *mi; 1588 1589 mi = GNUNET_JSON_PACK ( 1590 GNUNET_JSON_pack_string ("check_name", 1591 m->check_name), 1592 GNUNET_JSON_pack_allow_null ( 1593 GNUNET_JSON_pack_string ("prog_name", 1594 m->prog_name)), 1595 GNUNET_JSON_pack_allow_null ( 1596 GNUNET_JSON_pack_object_incref ("context", 1597 (json_t *) m->context))); 1598 jmeasures = json_array (); 1599 GNUNET_assert (NULL != jmeasures); 1600 GNUNET_assert (0 == 1601 json_array_append_new (jmeasures, 1602 mi)); 1603 return GNUNET_JSON_PACK ( 1604 GNUNET_JSON_pack_array_steal ("measures", 1605 jmeasures), 1606 GNUNET_JSON_pack_bool ("is_and_combinator", 1607 false), 1608 GNUNET_JSON_pack_bool ("verboten", 1609 false)); 1610 } 1611 1612 1613 uint32_t 1614 TALER_KYCLOGIC_rule2priority ( 1615 const struct TALER_KYCLOGIC_KycRule *r) 1616 { 1617 return r->display_priority; 1618 } 1619 1620 1621 /** 1622 * Perform very primitive word splitting of a command. 1623 * 1624 * @param command command to split 1625 * @param extra_args extra arguments to append after the word 1626 * @returns NULL-terminated array of words 1627 */ 1628 static char ** 1629 split_words (const char *command, 1630 const char **extra_args) 1631 { 1632 unsigned int i = 0; 1633 unsigned int j = 0; 1634 unsigned int n = 0; 1635 char **res = NULL; 1636 1637 /* Result is always NULL-terminated */ 1638 GNUNET_array_append (res, n, NULL); 1639 1640 /* Split command into words */ 1641 while (1) 1642 { 1643 char *c; 1644 1645 /* Skip initial whitespace before word */ 1646 while (' ' == command[i]) 1647 i++; 1648 1649 /* Start of new word */ 1650 j = i; 1651 1652 /* Scan to end of word */ 1653 while ( (0 != command[j]) && (' ' != command[j]) ) 1654 j++; 1655 1656 /* No new word found */ 1657 if (i == j) 1658 break; 1659 1660 /* Append word to result */ 1661 c = GNUNET_malloc (j - i + 1); 1662 memcpy (c, &command[i], j - i); 1663 c[j - i] = 0; 1664 res[n - 1] = c; 1665 GNUNET_array_append (res, n, NULL); 1666 1667 /* Continue at end of word */ 1668 i = j; 1669 } 1670 1671 /* Append extra args */ 1672 if (NULL != extra_args) 1673 { 1674 for (const char **m = extra_args; *m; m++) 1675 { 1676 res[n - 1] = GNUNET_strdup (*m); 1677 GNUNET_array_append (res, n, NULL); 1678 } 1679 } 1680 1681 return res; 1682 } 1683 1684 1685 /** 1686 * Free arguments allocated with split_words. 1687 * 1688 * @param args NULL-terminated array of strings to free. 1689 */ 1690 static void 1691 destroy_words (char **args) 1692 { 1693 if (NULL == args) 1694 return; 1695 for (char **m = args; *m; m++) 1696 { 1697 GNUNET_free (*m); 1698 *m = NULL; 1699 } 1700 GNUNET_free (args); 1701 } 1702 1703 1704 /** 1705 * Run @a command with @a argument and return the 1706 * respective output from stdout. 1707 * 1708 * @param command binary to run 1709 * @param argument command-line argument to pass 1710 * @return NULL if @a command failed 1711 */ 1712 static char * 1713 command_output (const char *command, 1714 const char *argument) 1715 { 1716 char *rval; 1717 unsigned int sval; 1718 size_t soff; 1719 ssize_t ret; 1720 int sout[2]; 1721 pid_t chld; 1722 const char *extra_args[] = { 1723 argument, 1724 "-c", 1725 cfg_filename, 1726 NULL, 1727 }; 1728 1729 if (0 != pipe (sout)) 1730 { 1731 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, 1732 "pipe"); 1733 return NULL; 1734 } 1735 chld = fork (); 1736 if (-1 == chld) 1737 { 1738 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, 1739 "fork"); 1740 return NULL; 1741 } 1742 if (0 == chld) 1743 { 1744 char **argv; 1745 1746 argv = split_words (command, 1747 extra_args); 1748 1749 GNUNET_break (0 == 1750 close (sout[0])); 1751 GNUNET_break (0 == 1752 close (STDOUT_FILENO)); 1753 GNUNET_assert (STDOUT_FILENO == 1754 dup2 (sout[1], 1755 STDOUT_FILENO)); 1756 GNUNET_break (0 == 1757 close (sout[1])); 1758 execvp (argv[0], 1759 argv); 1760 destroy_words (argv); 1761 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 1762 "exec", 1763 command); 1764 exit (EXIT_FAILURE); 1765 } 1766 GNUNET_break (0 == 1767 close (sout[1])); 1768 sval = 1024; 1769 rval = GNUNET_malloc (sval); 1770 soff = 0; 1771 while (0 < (ret = read (sout[0], 1772 rval + soff, 1773 sval - soff)) ) 1774 { 1775 soff += ret; 1776 if (soff == sval) 1777 { 1778 GNUNET_array_grow (rval, 1779 sval, 1780 sval * 2); 1781 } 1782 } 1783 GNUNET_break (0 == close (sout[0])); 1784 { 1785 int wstatus; 1786 1787 GNUNET_break (chld == 1788 waitpid (chld, 1789 &wstatus, 1790 0)); 1791 if ( (! WIFEXITED (wstatus)) || 1792 (0 != WEXITSTATUS (wstatus)) ) 1793 { 1794 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1795 "Command `%s' %s failed with status %d\n", 1796 command, 1797 argument, 1798 wstatus); 1799 GNUNET_array_grow (rval, 1800 sval, 1801 0); 1802 return NULL; 1803 } 1804 } 1805 GNUNET_array_grow (rval, 1806 sval, 1807 soff + 1); 1808 rval[soff] = '\0'; 1809 return rval; 1810 } 1811 1812 1813 /** 1814 * Convert check type @a ctype_s into @a ctype. 1815 * 1816 * @param ctype_s check type as a string 1817 * @param[out] ctype set to check type as enum 1818 * @return #GNUNET_OK on success 1819 */ 1820 static enum GNUNET_GenericReturnValue 1821 check_type_from_string ( 1822 const char *ctype_s, 1823 enum TALER_KYCLOGIC_CheckType *ctype) 1824 { 1825 struct 1826 { 1827 const char *in; 1828 enum TALER_KYCLOGIC_CheckType out; 1829 } map [] = { 1830 { "INFO", TALER_KYCLOGIC_CT_INFO }, 1831 { "LINK", TALER_KYCLOGIC_CT_LINK }, 1832 { "FORM", TALER_KYCLOGIC_CT_FORM }, 1833 { NULL, 0 } 1834 }; 1835 1836 for (unsigned int i = 0; NULL != map[i].in; i++) 1837 if (0 == strcasecmp (map[i].in, 1838 ctype_s)) 1839 { 1840 *ctype = map[i].out; 1841 return GNUNET_OK; 1842 } 1843 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1844 "Invalid check type `%s'\n", 1845 ctype_s); 1846 return GNUNET_SYSERR; 1847 } 1848 1849 1850 enum GNUNET_GenericReturnValue 1851 TALER_KYCLOGIC_kyc_trigger_from_string ( 1852 const char *trigger_s, 1853 enum TALER_KYCLOGIC_KycTriggerEvent *trigger) 1854 { 1855 /* NOTE: if you change this, also change 1856 the code in src/json/json_helper.c! */ 1857 struct 1858 { 1859 const char *in; 1860 enum TALER_KYCLOGIC_KycTriggerEvent out; 1861 } map [] = { 1862 { "WITHDRAW", TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW }, 1863 { "DEPOSIT", TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT }, 1864 { "MERGE", TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE }, 1865 { "BALANCE", TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE }, 1866 { "CLOSE", TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE }, 1867 { "AGGREGATE", TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE }, 1868 { "TRANSACTION", TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION }, 1869 { "REFUND", TALER_KYCLOGIC_KYC_TRIGGER_REFUND }, 1870 { NULL, 0 } 1871 }; 1872 1873 for (unsigned int i = 0; NULL != map[i].in; i++) 1874 if (0 == strcasecmp (map[i].in, 1875 trigger_s)) 1876 { 1877 *trigger = map[i].out; 1878 return GNUNET_OK; 1879 } 1880 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1881 "Invalid KYC trigger `%s'\n", 1882 trigger_s); 1883 return GNUNET_SYSERR; 1884 } 1885 1886 1887 json_t * 1888 TALER_KYCLOGIC_get_wallet_thresholds (void) 1889 { 1890 json_t *ret; 1891 1892 ret = json_array (); 1893 GNUNET_assert (NULL != ret); 1894 for (unsigned int i = 0; i<default_rules.num_kyc_rules; i++) 1895 { 1896 struct TALER_KYCLOGIC_KycRule *rule 1897 = &default_rules.kyc_rules[i]; 1898 1899 if (TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE != rule->trigger) 1900 continue; 1901 GNUNET_assert ( 1902 0 == 1903 json_array_append_new ( 1904 ret, 1905 TALER_JSON_from_amount ( 1906 &rule->threshold))); 1907 } 1908 return ret; 1909 } 1910 1911 1912 /** 1913 * Load KYC logic plugin. 1914 * 1915 * @param cfg configuration to use 1916 * @param name name of the plugin 1917 * @return NULL on error 1918 */ 1919 static struct TALER_KYCLOGIC_Plugin * 1920 load_logic (const struct GNUNET_CONFIGURATION_Handle *cfg, 1921 const char *name) 1922 { 1923 char *lib_name; 1924 struct TALER_KYCLOGIC_Plugin *plugin; 1925 1926 1927 GNUNET_asprintf (&lib_name, 1928 "libtaler_plugin_kyclogic_%s", 1929 name); 1930 for (unsigned int i = 0; i<num_kyc_logics; i++) 1931 if (0 == strcasecmp (lib_name, 1932 kyc_logics[i]->library_name)) 1933 { 1934 GNUNET_free (lib_name); 1935 return kyc_logics[i]; 1936 } 1937 plugin = GNUNET_PLUGIN_load (TALER_EXCHANGE_project_data (), 1938 lib_name, 1939 (void *) cfg); 1940 if (NULL == plugin) 1941 { 1942 GNUNET_free (lib_name); 1943 return NULL; 1944 } 1945 plugin->library_name = lib_name; 1946 plugin->name = GNUNET_strdup (name); 1947 GNUNET_array_append (kyc_logics, 1948 num_kyc_logics, 1949 plugin); 1950 return plugin; 1951 } 1952 1953 1954 /** 1955 * Parse configuration of a KYC provider. 1956 * 1957 * @param cfg configuration to parse 1958 * @param section name of the section to analyze 1959 * @return #GNUNET_OK on success 1960 */ 1961 static enum GNUNET_GenericReturnValue 1962 add_provider (const struct GNUNET_CONFIGURATION_Handle *cfg, 1963 const char *section) 1964 { 1965 char *logic; 1966 struct TALER_KYCLOGIC_Plugin *lp; 1967 struct TALER_KYCLOGIC_ProviderDetails *pd; 1968 1969 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1970 "Parsing KYC provider %s\n", 1971 section); 1972 if (GNUNET_OK != 1973 GNUNET_CONFIGURATION_get_value_string (cfg, 1974 section, 1975 "LOGIC", 1976 &logic)) 1977 { 1978 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1979 section, 1980 "LOGIC"); 1981 return GNUNET_SYSERR; 1982 } 1983 lp = load_logic (cfg, 1984 logic); 1985 if (NULL == lp) 1986 { 1987 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 1988 section, 1989 "LOGIC", 1990 "logic plugin could not be loaded"); 1991 GNUNET_free (logic); 1992 return GNUNET_SYSERR; 1993 } 1994 GNUNET_free (logic); 1995 pd = lp->load_configuration (lp->cls, 1996 section); 1997 if (NULL == pd) 1998 return GNUNET_SYSERR; 1999 2000 { 2001 struct TALER_KYCLOGIC_KycProvider *kp; 2002 2003 kp = GNUNET_new (struct TALER_KYCLOGIC_KycProvider); 2004 kp->provider_name 2005 = GNUNET_strdup (§ion[strlen ("kyc-provider-")]); 2006 kp->logic = lp; 2007 kp->pd = pd; 2008 GNUNET_array_append (kyc_providers, 2009 num_kyc_providers, 2010 kp); 2011 } 2012 return GNUNET_OK; 2013 } 2014 2015 2016 /** 2017 * Tokenize @a input along @a token 2018 * and build an array of the tokens. 2019 * 2020 * @param[in,out] input the input to tokenize; clobbered 2021 * @param sep separator between tokens to separate @a input on 2022 * @param[out] p_strs where to put array of tokens 2023 * @param[out] num_strs set to length of @a p_strs array 2024 */ 2025 static void 2026 add_tokens (char *input, 2027 const char *sep, 2028 char ***p_strs, 2029 unsigned int *num_strs) 2030 { 2031 char *sptr; 2032 char **rstr = NULL; 2033 unsigned int num_rstr = 0; 2034 2035 for (char *tok = strtok_r (input, sep, &sptr); 2036 NULL != tok; 2037 tok = strtok_r (NULL, sep, &sptr)) 2038 { 2039 GNUNET_array_append (rstr, 2040 num_rstr, 2041 GNUNET_strdup (tok)); 2042 } 2043 *p_strs = rstr; 2044 *num_strs = num_rstr; 2045 } 2046 2047 2048 /** 2049 * Closure for the handle_XXX_section functions 2050 * that parse configuration sections matching certain 2051 * prefixes. 2052 */ 2053 struct SectionContext 2054 { 2055 /** 2056 * Configuration to handle. 2057 */ 2058 const struct GNUNET_CONFIGURATION_Handle *cfg; 2059 2060 /** 2061 * Result to return, set to false on failures. 2062 */ 2063 bool result; 2064 }; 2065 2066 2067 /** 2068 * Function to iterate over configuration sections. 2069 * 2070 * @param cls a `struct SectionContext *` 2071 * @param section name of the section 2072 */ 2073 static void 2074 handle_provider_section (void *cls, 2075 const char *section) 2076 { 2077 struct SectionContext *sc = cls; 2078 2079 if (! sc->result) 2080 return; 2081 if (0 == strncasecmp (section, 2082 "kyc-provider-", 2083 strlen ("kyc-provider-"))) 2084 { 2085 if (GNUNET_OK != 2086 add_provider (sc->cfg, 2087 section)) 2088 { 2089 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2090 "Setup failed in configuration section `%s'\n", 2091 section); 2092 sc->result = false; 2093 } 2094 return; 2095 } 2096 } 2097 2098 2099 /** 2100 * Parse configuration @a cfg in section @a section for 2101 * the specification of a KYC check. 2102 * 2103 * @param cfg configuration to parse 2104 * @param section configuration section to parse 2105 * @return #GNUNET_OK on success 2106 */ 2107 static enum GNUNET_GenericReturnValue 2108 add_check (const struct GNUNET_CONFIGURATION_Handle *cfg, 2109 const char *section) 2110 { 2111 enum TALER_KYCLOGIC_CheckType ct; 2112 char *description = NULL; 2113 json_t *description_i18n = NULL; 2114 char *requires = NULL; 2115 char *outputs = NULL; 2116 char *fallback = NULL; 2117 2118 if (0 == strcasecmp (§ion[strlen ("kyc-check-")], 2119 "SKIP")) 2120 { 2121 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2122 "The kyc-check-skip section must not exist, 'skip' is reserved name for a built-in check\n"); 2123 return GNUNET_SYSERR; 2124 } 2125 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2126 "Parsing KYC check %s\n", 2127 section); 2128 { 2129 char *type_s; 2130 2131 if (GNUNET_OK != 2132 GNUNET_CONFIGURATION_get_value_string (cfg, 2133 section, 2134 "TYPE", 2135 &type_s)) 2136 { 2137 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2138 section, 2139 "TYPE"); 2140 return GNUNET_SYSERR; 2141 } 2142 if (GNUNET_OK != 2143 check_type_from_string (type_s, 2144 &ct)) 2145 { 2146 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2147 section, 2148 "TYPE", 2149 "valid check type required"); 2150 GNUNET_free (type_s); 2151 return GNUNET_SYSERR; 2152 } 2153 GNUNET_free (type_s); 2154 } 2155 2156 if (GNUNET_OK != 2157 GNUNET_CONFIGURATION_get_value_string (cfg, 2158 section, 2159 "DESCRIPTION", 2160 &description)) 2161 { 2162 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2163 section, 2164 "DESCRIPTION"); 2165 goto fail; 2166 } 2167 2168 { 2169 char *tmp; 2170 2171 if (GNUNET_OK == 2172 GNUNET_CONFIGURATION_get_value_string (cfg, 2173 section, 2174 "DESCRIPTION_I18N", 2175 &tmp)) 2176 { 2177 json_error_t err; 2178 2179 description_i18n = json_loads (tmp, 2180 JSON_REJECT_DUPLICATES, 2181 &err); 2182 GNUNET_free (tmp); 2183 if (NULL == description_i18n) 2184 { 2185 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2186 section, 2187 "DESCRIPTION_I18N", 2188 err.text); 2189 goto fail; 2190 } 2191 if (! TALER_JSON_check_i18n (description_i18n) ) 2192 { 2193 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2194 section, 2195 "DESCRIPTION_I18N", 2196 "JSON with internationalization map required"); 2197 goto fail; 2198 } 2199 } 2200 } 2201 2202 if (GNUNET_OK != 2203 GNUNET_CONFIGURATION_get_value_string (cfg, 2204 section, 2205 "REQUIRES", 2206 &requires)) 2207 { 2208 /* no requirements is OK */ 2209 requires = GNUNET_strdup (""); 2210 } 2211 2212 if (GNUNET_OK != 2213 GNUNET_CONFIGURATION_get_value_string (cfg, 2214 section, 2215 "OUTPUTS", 2216 &outputs)) 2217 { 2218 /* no outputs is OK */ 2219 outputs = GNUNET_strdup (""); 2220 } 2221 2222 if (GNUNET_OK != 2223 GNUNET_CONFIGURATION_get_value_string (cfg, 2224 section, 2225 "FALLBACK", 2226 &fallback)) 2227 { 2228 /* We do *not* allow NULL to fall back to default rules because fallbacks 2229 are used when there is actually a serious error and thus some action 2230 (usually an investigation) is always in order, and that's basically 2231 never the default. And as fallbacks should be rare, we really insist on 2232 them at least being explicitly configured. Otherwise these errors may 2233 go undetected simply because someone forgot to configure a fallback and 2234 then nothing happens. */ 2235 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2236 section, 2237 "FALLBACK"); 2238 goto fail; 2239 } 2240 2241 { 2242 struct TALER_KYCLOGIC_KycCheck *kc; 2243 2244 kc = GNUNET_new (struct TALER_KYCLOGIC_KycCheck); 2245 switch (ct) 2246 { 2247 case TALER_KYCLOGIC_CT_INFO: 2248 /* nothing to do */ 2249 break; 2250 case TALER_KYCLOGIC_CT_FORM: 2251 { 2252 char *form_name; 2253 2254 if (GNUNET_OK != 2255 GNUNET_CONFIGURATION_get_value_string (cfg, 2256 section, 2257 "FORM_NAME", 2258 &form_name)) 2259 { 2260 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2261 section, 2262 "FORM_NAME"); 2263 GNUNET_free (requires); 2264 GNUNET_free (outputs); 2265 GNUNET_free (kc); 2266 return GNUNET_SYSERR; 2267 } 2268 kc->details.form.name = form_name; 2269 } 2270 break; 2271 case TALER_KYCLOGIC_CT_LINK: 2272 { 2273 char *provider_id; 2274 2275 if (GNUNET_OK != 2276 GNUNET_CONFIGURATION_get_value_string (cfg, 2277 section, 2278 "PROVIDER_ID", 2279 &provider_id)) 2280 { 2281 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2282 section, 2283 "PROVIDER_ID"); 2284 GNUNET_free (requires); 2285 GNUNET_free (outputs); 2286 GNUNET_free (kc); 2287 return GNUNET_SYSERR; 2288 } 2289 kc->details.link.provider = find_provider (provider_id); 2290 if (NULL == kc->details.link.provider) 2291 { 2292 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2293 "Unknown KYC provider `%s' used in check `%s'\n", 2294 provider_id, 2295 §ion[strlen ("kyc-check-")]); 2296 GNUNET_free (provider_id); 2297 GNUNET_free (requires); 2298 GNUNET_free (outputs); 2299 GNUNET_free (kc); 2300 return GNUNET_SYSERR; 2301 } 2302 GNUNET_free (provider_id); 2303 } 2304 break; 2305 } 2306 kc->check_name = GNUNET_strdup (§ion[strlen ("kyc-check-")]); 2307 kc->description = description; 2308 kc->description_i18n = description_i18n; 2309 kc->fallback = fallback; 2310 kc->type = ct; 2311 add_tokens (requires, 2312 "; \n\t", 2313 &kc->requires, 2314 &kc->num_requires); 2315 GNUNET_free (requires); 2316 add_tokens (outputs, 2317 "; \n\t", 2318 &kc->outputs, 2319 &kc->num_outputs); 2320 GNUNET_free (outputs); 2321 GNUNET_array_append (kyc_checks, 2322 num_kyc_checks, 2323 kc); 2324 } 2325 2326 return GNUNET_OK; 2327 fail: 2328 GNUNET_free (description); 2329 json_decref (description_i18n); 2330 GNUNET_free (requires); 2331 GNUNET_free (outputs); 2332 GNUNET_free (fallback); 2333 return GNUNET_SYSERR; 2334 } 2335 2336 2337 /** 2338 * Function to iterate over configuration sections. 2339 * 2340 * @param cls a `struct SectionContext *` 2341 * @param section name of the section 2342 */ 2343 static void 2344 handle_check_section (void *cls, 2345 const char *section) 2346 { 2347 struct SectionContext *sc = cls; 2348 2349 if (! sc->result) 2350 return; 2351 if (0 == strncasecmp (section, 2352 "kyc-check-", 2353 strlen ("kyc-check-"))) 2354 { 2355 if (GNUNET_OK != 2356 add_check (sc->cfg, 2357 section)) 2358 sc->result = false; 2359 } 2360 } 2361 2362 2363 /** 2364 * Parse configuration @a cfg in section @a section for 2365 * the specification of a KYC rule. 2366 * 2367 * @param cfg configuration to parse 2368 * @param section configuration section to parse 2369 * @return #GNUNET_OK on success 2370 */ 2371 static enum GNUNET_GenericReturnValue 2372 add_rule (const struct GNUNET_CONFIGURATION_Handle *cfg, 2373 const char *section) 2374 { 2375 struct TALER_Amount threshold; 2376 struct GNUNET_TIME_Relative timeframe; 2377 enum TALER_KYCLOGIC_KycTriggerEvent ot; 2378 char *measures; 2379 bool exposed; 2380 bool is_and; 2381 2382 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2383 "Parsing KYC rule from %s\n", 2384 section); 2385 if (GNUNET_YES != 2386 GNUNET_CONFIGURATION_get_value_yesno (cfg, 2387 section, 2388 "ENABLED")) 2389 return GNUNET_OK; 2390 if (GNUNET_OK != 2391 TALER_config_get_amount (cfg, 2392 section, 2393 "THRESHOLD", 2394 &threshold)) 2395 { 2396 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2397 section, 2398 "THRESHOLD", 2399 "amount required"); 2400 return GNUNET_SYSERR; 2401 } 2402 exposed = (GNUNET_YES == 2403 GNUNET_CONFIGURATION_get_value_yesno (cfg, 2404 section, 2405 "EXPOSED")); 2406 { 2407 enum GNUNET_GenericReturnValue r; 2408 2409 r = GNUNET_CONFIGURATION_get_value_yesno (cfg, 2410 section, 2411 "IS_AND_COMBINATOR"); 2412 if (GNUNET_SYSERR == r) 2413 { 2414 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2415 section, 2416 "IS_AND_COMBINATOR", 2417 "YES or NO required"); 2418 return GNUNET_SYSERR; 2419 } 2420 is_and = (GNUNET_YES == r); 2421 } 2422 2423 { 2424 char *ot_s; 2425 2426 if (GNUNET_OK != 2427 GNUNET_CONFIGURATION_get_value_string (cfg, 2428 section, 2429 "OPERATION_TYPE", 2430 &ot_s)) 2431 { 2432 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2433 section, 2434 "OPERATION_TYPE"); 2435 return GNUNET_SYSERR; 2436 } 2437 if (GNUNET_OK != 2438 TALER_KYCLOGIC_kyc_trigger_from_string (ot_s, 2439 &ot)) 2440 { 2441 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2442 section, 2443 "OPERATION_TYPE", 2444 "valid trigger type required"); 2445 GNUNET_free (ot_s); 2446 return GNUNET_SYSERR; 2447 } 2448 GNUNET_free (ot_s); 2449 } 2450 2451 if (GNUNET_OK != 2452 GNUNET_CONFIGURATION_get_value_time (cfg, 2453 section, 2454 "TIMEFRAME", 2455 &timeframe)) 2456 { 2457 if (TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE == ot) 2458 { 2459 timeframe = GNUNET_TIME_UNIT_ZERO; 2460 } 2461 else 2462 { 2463 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2464 section, 2465 "TIMEFRAME", 2466 "duration required"); 2467 return GNUNET_SYSERR; 2468 } 2469 } 2470 if (GNUNET_OK != 2471 GNUNET_CONFIGURATION_get_value_string (cfg, 2472 section, 2473 "NEXT_MEASURES", 2474 &measures)) 2475 { 2476 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2477 section, 2478 "NEXT_MEASURES"); 2479 return GNUNET_SYSERR; 2480 } 2481 2482 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2483 "Adding KYC rule %s for trigger %d with threshold %s\n", 2484 section, 2485 (int) ot, 2486 TALER_amount2s (&threshold)); 2487 { 2488 struct TALER_KYCLOGIC_KycRule kt = { 2489 .lrs = &default_rules, 2490 .rule_name = GNUNET_strdup (§ion[strlen ("kyc-rule-")]), 2491 .timeframe = timeframe, 2492 .threshold = threshold, 2493 .trigger = ot, 2494 .is_and_combinator = is_and, 2495 .exposed = exposed, 2496 .display_priority = 0, 2497 .verboten = false 2498 }; 2499 2500 add_tokens (measures, 2501 "; \n\t", 2502 &kt.next_measures, 2503 &kt.num_measures); 2504 for (unsigned int i=0; i<kt.num_measures; i++) 2505 if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE, 2506 kt.next_measures[i])) 2507 kt.verboten = true; 2508 GNUNET_free (measures); 2509 GNUNET_array_append (default_rules.kyc_rules, 2510 default_rules.num_kyc_rules, 2511 kt); 2512 } 2513 return GNUNET_OK; 2514 } 2515 2516 2517 /** 2518 * Function to iterate over configuration sections. 2519 * 2520 * @param cls a `struct SectionContext *` 2521 * @param section name of the section 2522 */ 2523 static void 2524 handle_rule_section (void *cls, 2525 const char *section) 2526 { 2527 struct SectionContext *sc = cls; 2528 2529 if (! sc->result) 2530 return; 2531 if (0 == strncasecmp (section, 2532 "kyc-rule-", 2533 strlen ("kyc-rule-"))) 2534 { 2535 if (GNUNET_OK != 2536 add_rule (sc->cfg, 2537 section)) 2538 sc->result = false; 2539 } 2540 } 2541 2542 2543 /** 2544 * Parse array dimension argument of @a tok (if present) 2545 * and store result in @a dimp. Does nothing if 2546 * @a tok does not contain '['. Otherwise does some input 2547 * validation. 2548 * 2549 * @param section name of configuration section for logging 2550 * @param tok input to parse, of form "text[$DIM]" 2551 * @param[out] dimp set to value of $DIM 2552 * @return true on success 2553 */ 2554 static bool 2555 parse_dim (const char *section, 2556 const char *tok, 2557 long long *dimp) 2558 { 2559 const char *dim = strchr (tok, 2560 '['); 2561 char dummy; 2562 2563 if (NULL == dim) 2564 return true; 2565 if (1 != 2566 sscanf (dim, 2567 "[%lld]%c", 2568 dimp, 2569 &dummy)) 2570 { 2571 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2572 section, 2573 "COMMAND", 2574 "output for -i invalid (bad dimension given)"); 2575 return false; 2576 } 2577 return true; 2578 } 2579 2580 2581 /** 2582 * Parse configuration @a cfg in section @a section for 2583 * the specification of an AML program. 2584 * 2585 * @param cfg configuration to parse 2586 * @param section configuration section to parse 2587 * @return #GNUNET_OK on success 2588 */ 2589 static enum GNUNET_GenericReturnValue 2590 add_program (const struct GNUNET_CONFIGURATION_Handle *cfg, 2591 const char *section) 2592 { 2593 char *command = NULL; 2594 char *description = NULL; 2595 char *fallback = NULL; 2596 char *required_contexts = NULL; 2597 char *required_attributes = NULL; 2598 char *required_inputs = NULL; 2599 enum AmlProgramInputs input_mask = API_NONE; 2600 long long aml_history_length_limit = INT64_MAX; 2601 long long kyc_history_length_limit = INT64_MAX; 2602 2603 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2604 "Parsing KYC program %s\n", 2605 section); 2606 if (GNUNET_OK != 2607 GNUNET_CONFIGURATION_get_value_string (cfg, 2608 section, 2609 "COMMAND", 2610 &command)) 2611 { 2612 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2613 section, 2614 "COMMAND", 2615 "command required"); 2616 goto fail; 2617 } 2618 if (GNUNET_OK != 2619 GNUNET_CONFIGURATION_get_value_string (cfg, 2620 section, 2621 "DESCRIPTION", 2622 &description)) 2623 { 2624 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2625 section, 2626 "DESCRIPTION", 2627 "description required"); 2628 goto fail; 2629 } 2630 if (GNUNET_OK != 2631 GNUNET_CONFIGURATION_get_value_string (cfg, 2632 section, 2633 "FALLBACK", 2634 &fallback)) 2635 { 2636 /* We do *not* allow NULL to fall back to default rules because fallbacks 2637 are used when there is actually a serious error and thus some action 2638 (usually an investigation) is always in order, and that's basically 2639 never the default. And as fallbacks should be rare, we really insist on 2640 them at least being explicitly configured. Otherwise these errors may 2641 go undetected simply because someone forgot to configure a fallback and 2642 then nothing happens. */ 2643 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2644 section, 2645 "FALLBACK", 2646 "fallback measure name required"); 2647 goto fail; 2648 } 2649 2650 required_contexts = command_output (command, 2651 "-r"); 2652 if (NULL == required_contexts) 2653 { 2654 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2655 section, 2656 "COMMAND", 2657 "output for -r invalid"); 2658 goto fail; 2659 } 2660 required_attributes = command_output (command, 2661 "-a"); 2662 if (NULL == required_attributes) 2663 { 2664 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2665 section, 2666 "COMMAND", 2667 "output for -a invalid"); 2668 goto fail; 2669 } 2670 2671 required_inputs = command_output (command, 2672 "-i"); 2673 if (NULL == required_inputs) 2674 { 2675 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2676 section, 2677 "COMMAND", 2678 "output for -i invalid"); 2679 goto fail; 2680 } 2681 { 2682 char *sptr; 2683 2684 for (char *tok = strtok_r (required_inputs, 2685 ";\n \t", 2686 &sptr); 2687 NULL != tok; 2688 tok = strtok_r (NULL, 2689 ";\n \t", 2690 &sptr) ) 2691 { 2692 if (0 == strcasecmp (tok, 2693 "context")) 2694 input_mask |= API_CONTEXT; 2695 else if (0 == strcasecmp (tok, 2696 "attributes")) 2697 input_mask |= API_ATTRIBUTES; 2698 else if (0 == strcasecmp (tok, 2699 "current_rules")) 2700 input_mask |= API_CURRENT_RULES; 2701 else if (0 == strcasecmp (tok, 2702 "default_rules")) 2703 input_mask |= API_DEFAULT_RULES; 2704 else if (0 == strncasecmp (tok, 2705 "aml_history", 2706 strlen ("aml_history"))) 2707 { 2708 input_mask |= API_AML_HISTORY; 2709 if (! parse_dim (section, 2710 tok, 2711 &aml_history_length_limit)) 2712 goto fail; 2713 } 2714 else if (0 == strncasecmp (tok, 2715 "kyc_history", 2716 strlen ("kyc_history"))) 2717 { 2718 input_mask |= API_KYC_HISTORY; 2719 if (! parse_dim (section, 2720 tok, 2721 &kyc_history_length_limit)) 2722 goto fail; 2723 } 2724 else 2725 { 2726 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2727 section, 2728 "COMMAND", 2729 "output for -i invalid (unsupported input)"); 2730 goto fail; 2731 } 2732 } 2733 } 2734 GNUNET_free (required_inputs); 2735 2736 { 2737 struct TALER_KYCLOGIC_AmlProgram *ap; 2738 2739 ap = GNUNET_new (struct TALER_KYCLOGIC_AmlProgram); 2740 ap->program_name = GNUNET_strdup (§ion[strlen ("aml-program-")]); 2741 ap->command = command; 2742 ap->description = description; 2743 ap->fallback = fallback; 2744 ap->input_mask = input_mask; 2745 ap->aml_history_length_limit = aml_history_length_limit; 2746 ap->kyc_history_length_limit = kyc_history_length_limit; 2747 add_tokens (required_contexts, 2748 "; \n\t", 2749 &ap->required_contexts, 2750 &ap->num_required_contexts); 2751 GNUNET_free (required_contexts); 2752 add_tokens (required_attributes, 2753 "; \n\t", 2754 &ap->required_attributes, 2755 &ap->num_required_attributes); 2756 GNUNET_free (required_attributes); 2757 GNUNET_array_append (aml_programs, 2758 num_aml_programs, 2759 ap); 2760 } 2761 return GNUNET_OK; 2762 fail: 2763 GNUNET_free (command); 2764 GNUNET_free (description); 2765 GNUNET_free (required_inputs); 2766 GNUNET_free (required_contexts); 2767 GNUNET_free (required_attributes); 2768 GNUNET_free (fallback); 2769 return GNUNET_SYSERR; 2770 } 2771 2772 2773 /** 2774 * Function to iterate over configuration sections. 2775 * 2776 * @param cls a `struct SectionContext *` 2777 * @param section name of the section 2778 */ 2779 static void 2780 handle_program_section (void *cls, 2781 const char *section) 2782 { 2783 struct SectionContext *sc = cls; 2784 2785 if (! sc->result) 2786 return; 2787 if (0 == strncasecmp (section, 2788 "aml-program-", 2789 strlen ("aml-program-"))) 2790 { 2791 if (GNUNET_OK != 2792 add_program (sc->cfg, 2793 section)) 2794 sc->result = false; 2795 } 2796 } 2797 2798 2799 /** 2800 * Parse configuration @a cfg in section @a section for 2801 * the specification of a KYC measure. 2802 * 2803 * @param cfg configuration to parse 2804 * @param section configuration section to parse 2805 * @return #GNUNET_OK on success 2806 */ 2807 static enum GNUNET_GenericReturnValue 2808 add_measure (const struct GNUNET_CONFIGURATION_Handle *cfg, 2809 const char *section) 2810 { 2811 bool voluntary; 2812 char *check_name = NULL; 2813 struct TALER_KYCLOGIC_KycCheck *kc = NULL; 2814 char *context_str = NULL; 2815 char *program = NULL; 2816 json_t *context; 2817 json_error_t err; 2818 2819 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2820 "Parsing KYC measure %s\n", 2821 section); 2822 if (GNUNET_OK != 2823 GNUNET_CONFIGURATION_get_value_string (cfg, 2824 section, 2825 "CHECK_NAME", 2826 &check_name)) 2827 { 2828 check_name = GNUNET_strdup ("SKIP"); 2829 } 2830 if (0 != strcasecmp (check_name, 2831 "SKIP")) 2832 { 2833 kc = find_check (check_name); 2834 if (NULL == kc) 2835 { 2836 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2837 section, 2838 "CHECK_NAME", 2839 "check unknown"); 2840 goto fail; 2841 } 2842 } 2843 if (GNUNET_OK != 2844 GNUNET_CONFIGURATION_get_value_string (cfg, 2845 section, 2846 "PROGRAM", 2847 &program)) 2848 { 2849 if ( (NULL == kc) || 2850 (TALER_KYCLOGIC_CT_INFO != kc->type) ) 2851 { 2852 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2853 section, 2854 "PROGRAM"); 2855 goto fail; 2856 } 2857 } 2858 else 2859 { 2860 /* AML program given, but do we want one? */ 2861 if ( (NULL != kc) && 2862 (TALER_KYCLOGIC_CT_INFO == kc->type) ) 2863 { 2864 GNUNET_log_config_invalid ( 2865 GNUNET_ERROR_TYPE_WARNING, 2866 section, 2867 "PROGRAM", 2868 "AML program specified for a check of type INFO (ignored)"); 2869 GNUNET_free (program); 2870 } 2871 } 2872 voluntary = (GNUNET_YES == 2873 GNUNET_CONFIGURATION_get_value_yesno (cfg, 2874 section, 2875 "VOLUNTARY")); 2876 if (GNUNET_OK != 2877 GNUNET_CONFIGURATION_get_value_string (cfg, 2878 section, 2879 "CONTEXT", 2880 &context_str)) 2881 { 2882 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2883 section, 2884 "CONTEXT"); 2885 goto fail; 2886 } 2887 context = json_loads (context_str, 2888 JSON_REJECT_DUPLICATES, 2889 &err); 2890 GNUNET_free (context_str); 2891 if (NULL == context) 2892 { 2893 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2894 section, 2895 "CONTEXT", 2896 err.text); 2897 goto fail; 2898 } 2899 2900 { 2901 struct TALER_KYCLOGIC_Measure m; 2902 2903 m.measure_name = GNUNET_strdup (§ion[strlen ("kyc-measure-")]); 2904 m.check_name = check_name; 2905 m.prog_name = program; 2906 m.context = context; 2907 m.voluntary = voluntary; 2908 GNUNET_array_append (default_rules.custom_measures, 2909 default_rules.num_custom_measures, 2910 m); 2911 } 2912 return GNUNET_OK; 2913 fail: 2914 GNUNET_free (check_name); 2915 GNUNET_free (program); 2916 GNUNET_free (context_str); 2917 return GNUNET_SYSERR; 2918 } 2919 2920 2921 /** 2922 * Function to iterate over configuration sections. 2923 * 2924 * @param cls a `struct SectionContext *` 2925 * @param section name of the section 2926 */ 2927 static void 2928 handle_measure_section (void *cls, 2929 const char *section) 2930 { 2931 struct SectionContext *sc = cls; 2932 2933 if (! sc->result) 2934 return; 2935 if (0 == strncasecmp (section, 2936 "kyc-measure-", 2937 strlen ("kyc-measure-"))) 2938 { 2939 if (GNUNET_OK != 2940 add_measure (sc->cfg, 2941 section)) 2942 sc->result = false; 2943 } 2944 } 2945 2946 2947 /** 2948 * Comparator for qsort. Compares two rules 2949 * by timeframe to sort rules by time. 2950 * 2951 * @param p1 first trigger to compare 2952 * @param p2 second trigger to compare 2953 * @return -1 if p1 < p2, 0 if p1==p2, 1 if p1 > p2. 2954 */ 2955 static int 2956 sort_by_timeframe (const void *p1, 2957 const void *p2) 2958 { 2959 struct TALER_KYCLOGIC_KycRule *r1 2960 = (struct TALER_KYCLOGIC_KycRule *) p1; 2961 struct TALER_KYCLOGIC_KycRule *r2 2962 = (struct TALER_KYCLOGIC_KycRule *) p2; 2963 2964 if (GNUNET_TIME_relative_cmp (r1->timeframe, 2965 <, 2966 r2->timeframe)) 2967 return -1; 2968 if (GNUNET_TIME_relative_cmp (r1->timeframe, 2969 >, 2970 r2->timeframe)) 2971 return 1; 2972 return 0; 2973 } 2974 2975 2976 enum GNUNET_GenericReturnValue 2977 TALER_KYCLOGIC_kyc_init ( 2978 const struct GNUNET_CONFIGURATION_Handle *cfg, 2979 const char *cfg_fn) 2980 { 2981 struct SectionContext sc = { 2982 .cfg = cfg, 2983 .result = true 2984 }; 2985 json_t *jkyc_rules_w; 2986 json_t *jkyc_rules_a; 2987 2988 if (NULL != cfg_fn) 2989 cfg_filename = GNUNET_strdup (cfg_fn); 2990 GNUNET_assert (GNUNET_OK == 2991 TALER_config_get_currency (cfg, 2992 "exchange", 2993 &my_currency)); 2994 GNUNET_CONFIGURATION_iterate_sections (cfg, 2995 &handle_provider_section, 2996 &sc); 2997 if (! sc.result) 2998 { 2999 TALER_KYCLOGIC_kyc_done (); 3000 return GNUNET_SYSERR; 3001 } 3002 GNUNET_CONFIGURATION_iterate_sections (cfg, 3003 &handle_check_section, 3004 &sc); 3005 if (! sc.result) 3006 { 3007 TALER_KYCLOGIC_kyc_done (); 3008 return GNUNET_SYSERR; 3009 } 3010 GNUNET_CONFIGURATION_iterate_sections (cfg, 3011 &handle_rule_section, 3012 &sc); 3013 if (! sc.result) 3014 { 3015 TALER_KYCLOGIC_kyc_done (); 3016 return GNUNET_SYSERR; 3017 } 3018 GNUNET_CONFIGURATION_iterate_sections (cfg, 3019 &handle_program_section, 3020 &sc); 3021 if (! sc.result) 3022 { 3023 TALER_KYCLOGIC_kyc_done (); 3024 return GNUNET_SYSERR; 3025 } 3026 GNUNET_CONFIGURATION_iterate_sections (cfg, 3027 &handle_measure_section, 3028 &sc); 3029 if (! sc.result) 3030 { 3031 TALER_KYCLOGIC_kyc_done (); 3032 return GNUNET_SYSERR; 3033 } 3034 3035 if (0 != default_rules.num_kyc_rules) 3036 qsort (default_rules.kyc_rules, 3037 default_rules.num_kyc_rules, 3038 sizeof (struct TALER_KYCLOGIC_KycRule), 3039 &sort_by_timeframe); 3040 jkyc_rules_w = json_array (); 3041 GNUNET_assert (NULL != jkyc_rules_w); 3042 jkyc_rules_a = json_array (); 3043 GNUNET_assert (NULL != jkyc_rules_a); 3044 3045 for (unsigned int i=0; i<default_rules.num_kyc_rules; i++) 3046 { 3047 const struct TALER_KYCLOGIC_KycRule *rule 3048 = &default_rules.kyc_rules[i]; 3049 json_t *jrule; 3050 json_t *jmeasures; 3051 3052 jmeasures = json_array (); 3053 GNUNET_assert (NULL != jmeasures); 3054 for (unsigned int j=0; j<rule->num_measures; j++) 3055 { 3056 const char *measure_name = rule->next_measures[j]; 3057 const struct TALER_KYCLOGIC_Measure *m; 3058 3059 if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE, 3060 measure_name)) 3061 { 3062 GNUNET_assert ( 3063 0 == 3064 json_array_append_new (jmeasures, 3065 json_string (KYC_MEASURE_IMPOSSIBLE))); 3066 continue; 3067 } 3068 m = find_measure (&default_rules, 3069 measure_name); 3070 if (NULL == m) 3071 { 3072 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3073 "Unknown measure `%s' used in rule `%s'\n", 3074 measure_name, 3075 rule->rule_name); 3076 return GNUNET_SYSERR; 3077 } 3078 GNUNET_assert (0 == 3079 json_array_append_new (jmeasures, 3080 json_string (measure_name))); 3081 } 3082 jrule = GNUNET_JSON_PACK ( 3083 GNUNET_JSON_pack_allow_null ( 3084 GNUNET_JSON_pack_string ("rule_name", 3085 rule->rule_name)), 3086 TALER_JSON_pack_kycte ("operation_type", 3087 rule->trigger), 3088 TALER_JSON_pack_amount ("threshold", 3089 &rule->threshold), 3090 GNUNET_JSON_pack_time_rel ("timeframe", 3091 rule->timeframe), 3092 GNUNET_JSON_pack_array_steal ("measures", 3093 jmeasures), 3094 GNUNET_JSON_pack_uint64 ("display_priority", 3095 rule->display_priority), 3096 GNUNET_JSON_pack_bool ("exposed", 3097 rule->exposed), 3098 GNUNET_JSON_pack_bool ("is_and_combinator", 3099 rule->is_and_combinator) 3100 ); 3101 switch (rule->trigger) 3102 { 3103 case TALER_KYCLOGIC_KYC_TRIGGER_NONE: 3104 GNUNET_break (0); 3105 break; 3106 case TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW: 3107 GNUNET_assert (0 == 3108 json_array_append (jkyc_rules_a, 3109 jrule)); 3110 break; 3111 case TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT: 3112 GNUNET_assert (0 == 3113 json_array_append (jkyc_rules_a, 3114 jrule)); 3115 break; 3116 case TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE: 3117 GNUNET_assert (0 == 3118 json_array_append (jkyc_rules_w, 3119 jrule)); 3120 break; 3121 case TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE: 3122 GNUNET_assert (0 == 3123 json_array_append (jkyc_rules_w, 3124 jrule)); 3125 break; 3126 case TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE: 3127 GNUNET_assert (0 == 3128 json_array_append (jkyc_rules_a, 3129 jrule)); 3130 break; 3131 case TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE: 3132 GNUNET_assert (0 == 3133 json_array_append (jkyc_rules_a, 3134 jrule)); 3135 break; 3136 case TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION: 3137 GNUNET_assert (0 == 3138 json_array_append (jkyc_rules_a, 3139 jrule)); 3140 GNUNET_assert (0 == 3141 json_array_append (jkyc_rules_w, 3142 jrule)); 3143 break; 3144 case TALER_KYCLOGIC_KYC_TRIGGER_REFUND: 3145 GNUNET_assert (0 == 3146 json_array_append (jkyc_rules_a, 3147 jrule)); 3148 GNUNET_assert (0 == 3149 json_array_append (jkyc_rules_w, 3150 jrule)); 3151 break; 3152 } 3153 json_decref (jrule); 3154 } 3155 { 3156 json_t *empty = json_object (); 3157 3158 GNUNET_assert (NULL != empty); 3159 wallet_default_lrs 3160 = GNUNET_JSON_PACK ( 3161 GNUNET_JSON_pack_timestamp ("expiration_time", 3162 GNUNET_TIME_UNIT_FOREVER_TS), 3163 GNUNET_JSON_pack_array_steal ("rules", 3164 jkyc_rules_w), 3165 GNUNET_JSON_pack_object_incref ("custom_measures", 3166 empty) 3167 ); 3168 bankaccount_default_lrs 3169 = GNUNET_JSON_PACK ( 3170 GNUNET_JSON_pack_timestamp ("expiration_time", 3171 GNUNET_TIME_UNIT_FOREVER_TS), 3172 GNUNET_JSON_pack_array_steal ("rules", 3173 jkyc_rules_a), 3174 GNUNET_JSON_pack_object_incref ("custom_measures", 3175 empty) 3176 ); 3177 json_decref (empty); 3178 } 3179 for (unsigned int i=0; i<default_rules.num_custom_measures; i++) 3180 { 3181 const struct TALER_KYCLOGIC_Measure *measure 3182 = &default_rules.custom_measures[i]; 3183 3184 if (! check_measure (measure)) 3185 { 3186 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3187 "Configuration of AML measures incorrect. Exiting.\n"); 3188 return GNUNET_SYSERR; 3189 } 3190 } 3191 3192 for (unsigned int i=0; i<num_aml_programs; i++) 3193 { 3194 const struct TALER_KYCLOGIC_AmlProgram *program 3195 = aml_programs[i]; 3196 const struct TALER_KYCLOGIC_Measure *m; 3197 3198 m = find_measure (&default_rules, 3199 program->fallback); 3200 if (NULL == m) 3201 { 3202 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3203 "Unknown fallback measure `%s' used in program `%s'\n", 3204 program->fallback, 3205 program->program_name); 3206 return GNUNET_SYSERR; 3207 } 3208 if (0 != strcasecmp (m->check_name, 3209 "SKIP")) 3210 { 3211 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3212 "Fallback measure `%s' used in AML program `%s' has a check `%s' but fallbacks must have a check of type 'SKIP'\n", 3213 program->fallback, 3214 program->program_name, 3215 m->check_name); 3216 return GNUNET_SYSERR; 3217 } 3218 if (NULL != m->prog_name) 3219 { 3220 const struct TALER_KYCLOGIC_AmlProgram *fprogram; 3221 3222 fprogram = find_program (m->prog_name); 3223 GNUNET_assert (NULL != fprogram); 3224 if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES))) 3225 { 3226 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3227 "Fallback program %s of fallback measure `%s' used in AML program `%s' has required inputs, but fallback measures must not require any inputs\n", 3228 m->prog_name, 3229 program->program_name, 3230 m->check_name); 3231 return GNUNET_SYSERR; 3232 } 3233 } 3234 } 3235 3236 for (unsigned int i = 0; i<num_kyc_checks; i++) 3237 { 3238 struct TALER_KYCLOGIC_KycCheck *kyc_check 3239 = kyc_checks[i]; 3240 const struct TALER_KYCLOGIC_Measure *measure; 3241 3242 measure = find_measure (&default_rules, 3243 kyc_check->fallback); 3244 if (NULL == measure) 3245 { 3246 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3247 "Unknown fallback measure `%s' used in check `%s'\n", 3248 kyc_check->fallback, 3249 kyc_check->check_name); 3250 return GNUNET_SYSERR; 3251 } 3252 if (0 != strcasecmp (measure->check_name, 3253 "SKIP")) 3254 { 3255 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3256 "Fallback measure `%s' used in KYC check `%s' has a check `%s' but fallbacks must have a check of type 'SKIP'\n", 3257 kyc_check->fallback, 3258 kyc_check->check_name, 3259 measure->check_name); 3260 return GNUNET_SYSERR; 3261 } 3262 if (NULL != measure->prog_name) 3263 { 3264 const struct TALER_KYCLOGIC_AmlProgram *fprogram; 3265 3266 fprogram = find_program (measure->prog_name); 3267 GNUNET_assert (NULL != fprogram); 3268 if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES))) 3269 { 3270 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3271 "AML program `%s' used fallback measure `%s' of KYC check `%s' has required inputs, but fallback measures must not require any inputs\n", 3272 measure->prog_name, 3273 kyc_check->fallback, 3274 kyc_check->check_name); 3275 return GNUNET_SYSERR; 3276 } 3277 } 3278 } 3279 3280 return GNUNET_OK; 3281 } 3282 3283 3284 void 3285 TALER_KYCLOGIC_kyc_done (void) 3286 { 3287 for (unsigned int i = 0; i<default_rules.num_kyc_rules; i++) 3288 { 3289 struct TALER_KYCLOGIC_KycRule *kt 3290 = &default_rules.kyc_rules[i]; 3291 3292 for (unsigned int j = 0; j<kt->num_measures; j++) 3293 GNUNET_free (kt->next_measures[j]); 3294 GNUNET_array_grow (kt->next_measures, 3295 kt->num_measures, 3296 0); 3297 GNUNET_free (kt->rule_name); 3298 } 3299 GNUNET_array_grow (default_rules.kyc_rules, 3300 default_rules.num_kyc_rules, 3301 0); 3302 for (unsigned int i = 0; i<num_kyc_providers; i++) 3303 { 3304 struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i]; 3305 3306 kp->logic->unload_configuration (kp->pd); 3307 GNUNET_free (kp->provider_name); 3308 GNUNET_free (kp); 3309 } 3310 GNUNET_array_grow (kyc_providers, 3311 num_kyc_providers, 3312 0); 3313 for (unsigned int i = 0; i<num_kyc_logics; i++) 3314 { 3315 struct TALER_KYCLOGIC_Plugin *lp = kyc_logics[i]; 3316 char *lib_name = lp->library_name; 3317 3318 GNUNET_free (lp->name); 3319 GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name, 3320 lp)); 3321 GNUNET_free (lib_name); 3322 } 3323 GNUNET_array_grow (kyc_logics, 3324 num_kyc_logics, 3325 0); 3326 for (unsigned int i = 0; i<num_kyc_checks; i++) 3327 { 3328 struct TALER_KYCLOGIC_KycCheck *kc = kyc_checks[i]; 3329 3330 GNUNET_free (kc->check_name); 3331 GNUNET_free (kc->description); 3332 json_decref (kc->description_i18n); 3333 for (unsigned int j = 0; j<kc->num_requires; j++) 3334 GNUNET_free (kc->requires[j]); 3335 GNUNET_array_grow (kc->requires, 3336 kc->num_requires, 3337 0); 3338 GNUNET_free (kc->fallback); 3339 for (unsigned int j = 0; j<kc->num_outputs; j++) 3340 GNUNET_free (kc->outputs[j]); 3341 GNUNET_array_grow (kc->outputs, 3342 kc->num_outputs, 3343 0); 3344 switch (kc->type) 3345 { 3346 case TALER_KYCLOGIC_CT_INFO: 3347 break; 3348 case TALER_KYCLOGIC_CT_FORM: 3349 GNUNET_free (kc->details.form.name); 3350 break; 3351 case TALER_KYCLOGIC_CT_LINK: 3352 break; 3353 } 3354 GNUNET_free (kc); 3355 } 3356 GNUNET_array_grow (kyc_checks, 3357 num_kyc_checks, 3358 0); 3359 for (unsigned int i = 0; i<num_aml_programs; i++) 3360 { 3361 struct TALER_KYCLOGIC_AmlProgram *ap = aml_programs[i]; 3362 3363 GNUNET_free (ap->program_name); 3364 GNUNET_free (ap->command); 3365 GNUNET_free (ap->description); 3366 GNUNET_free (ap->fallback); 3367 for (unsigned int j = 0; j<ap->num_required_contexts; j++) 3368 GNUNET_free (ap->required_contexts[j]); 3369 GNUNET_array_grow (ap->required_contexts, 3370 ap->num_required_contexts, 3371 0); 3372 for (unsigned int j = 0; j<ap->num_required_attributes; j++) 3373 GNUNET_free (ap->required_attributes[j]); 3374 GNUNET_array_grow (ap->required_attributes, 3375 ap->num_required_attributes, 3376 0); 3377 GNUNET_free (ap); 3378 } 3379 GNUNET_array_grow (aml_programs, 3380 num_aml_programs, 3381 0); 3382 GNUNET_free (cfg_filename); 3383 } 3384 3385 3386 void 3387 TALER_KYCLOGIC_provider_to_logic ( 3388 const struct TALER_KYCLOGIC_KycProvider *provider, 3389 struct TALER_KYCLOGIC_Plugin **plugin, 3390 struct TALER_KYCLOGIC_ProviderDetails **pd, 3391 const char **provider_name) 3392 { 3393 *plugin = provider->logic; 3394 *pd = provider->pd; 3395 *provider_name = provider->provider_name; 3396 } 3397 3398 3399 enum GNUNET_GenericReturnValue 3400 TALER_KYCLOGIC_get_original_measure ( 3401 const char *measure_name, 3402 struct TALER_KYCLOGIC_KycCheckContext *kcc) 3403 { 3404 const struct TALER_KYCLOGIC_Measure *measure; 3405 3406 measure = find_measure (&default_rules, 3407 measure_name); 3408 if (NULL == measure) 3409 { 3410 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3411 "Default measure `%s' unknown\n", 3412 measure_name); 3413 return GNUNET_SYSERR; 3414 } 3415 if (0 == strcasecmp (measure->check_name, 3416 "SKIP")) 3417 { 3418 kcc->check = NULL; 3419 kcc->prog_name = measure->prog_name; 3420 kcc->context = measure->context; 3421 return GNUNET_OK; 3422 } 3423 3424 for (unsigned int i = 0; i<num_kyc_checks; i++) 3425 if (0 == strcasecmp (measure->check_name, 3426 kyc_checks[i]->check_name)) 3427 { 3428 kcc->check = kyc_checks[i]; 3429 kcc->prog_name = measure->prog_name; 3430 kcc->context = measure->context; 3431 return GNUNET_OK; 3432 } 3433 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3434 "Check `%s' unknown (but required by measure %s)\n", 3435 measure->check_name, 3436 measure_name); 3437 return GNUNET_SYSERR; 3438 } 3439 3440 3441 enum GNUNET_GenericReturnValue 3442 TALER_KYCLOGIC_requirements_to_check ( 3443 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs, 3444 const struct TALER_KYCLOGIC_KycRule *kyc_rule, 3445 const char *measure_name, 3446 struct TALER_KYCLOGIC_KycCheckContext *kcc) 3447 { 3448 bool found = false; 3449 const struct TALER_KYCLOGIC_Measure *measure = NULL; 3450 3451 if (NULL == lrs) 3452 lrs = &default_rules; 3453 if (NULL == measure_name) 3454 { 3455 GNUNET_break (0); 3456 return GNUNET_SYSERR; 3457 } 3458 if (NULL != kyc_rule) 3459 { 3460 for (unsigned int i = 0; i<kyc_rule->num_measures; i++) 3461 { 3462 if (0 != strcasecmp (measure_name, 3463 kyc_rule->next_measures[i])) 3464 continue; 3465 found = true; 3466 break; 3467 } 3468 if (! found) 3469 { 3470 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3471 "Measure `%s' not allowed for rule `%s'\n", 3472 measure_name, 3473 kyc_rule->rule_name); 3474 return GNUNET_SYSERR; 3475 } 3476 if (kyc_rule->verboten) 3477 { 3478 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3479 "Rule says operation is categorically is verboten, cannot take measures\n"); 3480 return GNUNET_SYSERR; 3481 } 3482 } 3483 measure = find_measure (lrs, 3484 measure_name); 3485 if (NULL == measure) 3486 { 3487 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3488 "Measure `%s' unknown (but allowed by rule `%s')\n", 3489 measure_name, 3490 NULL != kyc_rule 3491 ? kyc_rule->rule_name 3492 : "<NONE>"); 3493 return GNUNET_SYSERR; 3494 } 3495 3496 if (0 == strcasecmp (measure->check_name, 3497 "SKIP")) 3498 { 3499 kcc->check = NULL; 3500 kcc->prog_name = measure->prog_name; 3501 kcc->context = measure->context; 3502 return GNUNET_OK; 3503 } 3504 3505 for (unsigned int i = 0; i<num_kyc_checks; i++) 3506 if (0 == strcasecmp (measure->check_name, 3507 kyc_checks[i]->check_name)) 3508 { 3509 kcc->check = kyc_checks[i]; 3510 kcc->prog_name = measure->prog_name; 3511 kcc->context = measure->context; 3512 return GNUNET_OK; 3513 } 3514 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3515 "Check `%s' unknown (but required by measure %s)\n", 3516 measure->check_name, 3517 measure_name); 3518 return GNUNET_SYSERR; 3519 } 3520 3521 3522 enum GNUNET_GenericReturnValue 3523 TALER_KYCLOGIC_lookup_logic ( 3524 const char *name, 3525 struct TALER_KYCLOGIC_Plugin **plugin, 3526 struct TALER_KYCLOGIC_ProviderDetails **pd, 3527 const char **provider_name) 3528 { 3529 for (unsigned int i = 0; i<num_kyc_providers; i++) 3530 { 3531 struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i]; 3532 3533 if (0 != 3534 strcasecmp (name, 3535 kp->provider_name)) 3536 continue; 3537 *plugin = kp->logic; 3538 *pd = kp->pd; 3539 *provider_name = kp->provider_name; 3540 return GNUNET_OK; 3541 } 3542 for (unsigned int i = 0; i<num_kyc_logics; i++) 3543 { 3544 struct TALER_KYCLOGIC_Plugin *logic = kyc_logics[i]; 3545 3546 if (0 != 3547 strcasecmp (logic->name, 3548 name)) 3549 continue; 3550 *plugin = logic; 3551 *pd = NULL; 3552 *provider_name = NULL; 3553 return GNUNET_OK; 3554 } 3555 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3556 "Provider `%s' unknown\n", 3557 name); 3558 return GNUNET_SYSERR; 3559 } 3560 3561 3562 void 3563 TALER_KYCLOGIC_kyc_get_details ( 3564 const char *logic_name, 3565 TALER_KYCLOGIC_DetailsCallback cb, 3566 void *cb_cls) 3567 { 3568 for (unsigned int i = 0; i<num_kyc_providers; i++) 3569 { 3570 struct TALER_KYCLOGIC_KycProvider *kp 3571 = kyc_providers[i]; 3572 3573 if (0 != 3574 strcasecmp (kp->logic->name, 3575 logic_name)) 3576 continue; 3577 if (GNUNET_OK != 3578 cb (cb_cls, 3579 kp->pd, 3580 kp->logic->cls)) 3581 return; 3582 } 3583 } 3584 3585 3586 /** 3587 * Closure for check_amount(). 3588 */ 3589 struct KycTestContext 3590 { 3591 /** 3592 * Rule set we apply. 3593 */ 3594 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs; 3595 3596 /** 3597 * Events we care about. 3598 */ 3599 enum TALER_KYCLOGIC_KycTriggerEvent event; 3600 3601 /** 3602 * Total amount encountered so far, invalid if zero. 3603 */ 3604 struct TALER_Amount sum; 3605 3606 /** 3607 * Set to the triggered rule. 3608 */ 3609 const struct TALER_KYCLOGIC_KycRule *triggered_rule; 3610 3611 }; 3612 3613 3614 /** 3615 * Function called on each @a amount that was found to 3616 * be relevant for a KYC check. Evaluates the given 3617 * @a amount and @a date against all the applicable 3618 * rules in the legitimization rule set. 3619 * 3620 * @param cls our `struct KycTestContext *` 3621 * @param amount encountered transaction amount 3622 * @param date when was the amount encountered 3623 * @return #GNUNET_OK to continue to iterate, 3624 * #GNUNET_NO to abort iteration, 3625 * #GNUNET_SYSERR on internal error (also abort itaration) 3626 */ 3627 static enum GNUNET_GenericReturnValue 3628 check_amount ( 3629 void *cls, 3630 const struct TALER_Amount *amount, 3631 struct GNUNET_TIME_Absolute date) 3632 { 3633 struct KycTestContext *ktc = cls; 3634 struct GNUNET_TIME_Relative dur; 3635 3636 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3637 "KYC checking transaction amount %s from %s against %u rules\n", 3638 TALER_amount2s (amount), 3639 GNUNET_TIME_absolute2s (date), 3640 ktc->lrs->num_kyc_rules); 3641 dur = GNUNET_TIME_absolute_get_duration (date); 3642 if (GNUNET_OK != 3643 TALER_amount_is_valid (&ktc->sum)) 3644 ktc->sum = *amount; 3645 else 3646 GNUNET_assert (0 <= 3647 TALER_amount_add (&ktc->sum, 3648 &ktc->sum, 3649 amount)); 3650 for (unsigned int i=0; i<ktc->lrs->num_kyc_rules; i++) 3651 { 3652 const struct TALER_KYCLOGIC_KycRule *rule 3653 = &ktc->lrs->kyc_rules[i]; 3654 3655 if (ktc->event != rule->trigger) 3656 { 3657 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3658 "Wrong event type (%d) for rule %u (%d)\n", 3659 (int) ktc->event, 3660 i, 3661 (int) rule->trigger); 3662 continue; /* wrong trigger event type */ 3663 } 3664 if (GNUNET_TIME_relative_cmp (dur, 3665 >, 3666 rule->timeframe)) 3667 { 3668 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3669 "Out of time range for rule %u\n", 3670 i); 3671 continue; /* out of time range for rule */ 3672 } 3673 if (-1 == TALER_amount_cmp (&ktc->sum, 3674 &rule->threshold)) 3675 { 3676 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3677 "Below threshold of %s for rule %u\n", 3678 TALER_amount2s (&rule->threshold), 3679 i); 3680 continue; /* sum < threshold */ 3681 } 3682 if ( (NULL != ktc->triggered_rule) && 3683 (1 == TALER_amount_cmp (&ktc->triggered_rule->threshold, 3684 &rule->threshold)) ) 3685 { 3686 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3687 "Higher than threshold of already triggered rule\n"); 3688 continue; /* threshold of triggered_rule > rule */ 3689 } 3690 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3691 "Remembering rule %s as triggered\n", 3692 rule->rule_name); 3693 ktc->triggered_rule = rule; 3694 } 3695 return GNUNET_OK; 3696 } 3697 3698 3699 enum GNUNET_DB_QueryStatus 3700 TALER_KYCLOGIC_kyc_test_required ( 3701 enum TALER_KYCLOGIC_KycTriggerEvent event, 3702 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs, 3703 TALER_KYCLOGIC_KycAmountIterator ai, 3704 void *ai_cls, 3705 const struct TALER_KYCLOGIC_KycRule **triggered_rule, 3706 struct TALER_Amount *next_threshold) 3707 { 3708 struct GNUNET_TIME_Relative range 3709 = GNUNET_TIME_UNIT_ZERO; 3710 enum GNUNET_DB_QueryStatus qs; 3711 bool have_threshold = false; 3712 3713 memset (next_threshold, 3714 0, 3715 sizeof (struct TALER_Amount)); 3716 if (NULL == lrs) 3717 lrs = &default_rules; 3718 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3719 "Testing %u KYC rules for trigger %d\n", 3720 lrs->num_kyc_rules, 3721 event); 3722 for (unsigned int i=0; i<lrs->num_kyc_rules; i++) 3723 { 3724 const struct TALER_KYCLOGIC_KycRule *rule 3725 = &lrs->kyc_rules[i]; 3726 3727 if (event != rule->trigger) 3728 { 3729 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3730 "Rule %u is for a different trigger (%d/%d)\n", 3731 i, 3732 (int) event, 3733 (int) rule->trigger); 3734 continue; 3735 } 3736 if (have_threshold) 3737 { 3738 GNUNET_assert (GNUNET_OK == 3739 TALER_amount_min (next_threshold, 3740 next_threshold, 3741 &rule->threshold)); 3742 } 3743 else 3744 { 3745 *next_threshold = rule->threshold; 3746 have_threshold = true; 3747 } 3748 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3749 "Matched rule %u with timeframe %s and threshold %s\n", 3750 i, 3751 GNUNET_TIME_relative2s (rule->timeframe, 3752 true), 3753 TALER_amount2s (&rule->threshold)); 3754 range = GNUNET_TIME_relative_max (range, 3755 rule->timeframe); 3756 } 3757 3758 if (! have_threshold) 3759 { 3760 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3761 "No rules apply\n"); 3762 *triggered_rule = NULL; 3763 return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; 3764 } 3765 3766 { 3767 struct GNUNET_TIME_Absolute now 3768 = GNUNET_TIME_absolute_get (); 3769 struct KycTestContext ktc = { 3770 .lrs = lrs, 3771 .event = event 3772 }; 3773 3774 qs = ai (ai_cls, 3775 GNUNET_TIME_absolute_subtract (now, 3776 range), 3777 &check_amount, 3778 &ktc); 3779 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3780 "Triggered rule is %s\n", 3781 (NULL == ktc.triggered_rule) 3782 ? "NONE" 3783 : ktc.triggered_rule->rule_name); 3784 *triggered_rule = ktc.triggered_rule; 3785 } 3786 return qs; 3787 } 3788 3789 3790 json_t * 3791 TALER_KYCLOGIC_measure_to_requirement ( 3792 const char *check_name, 3793 const json_t *context, 3794 const struct TALER_AccountAccessTokenP *access_token, 3795 size_t offset, 3796 uint64_t legitimization_measure_row_id) 3797 { 3798 struct TALER_KYCLOGIC_KycCheck *kc; 3799 json_t *kri; 3800 struct TALER_KycMeasureAuthorizationHashP shv; 3801 char *ids; 3802 char *xids; 3803 3804 kc = find_check (check_name); 3805 if (NULL == kc) 3806 { 3807 GNUNET_break (0); 3808 return NULL; 3809 } 3810 GNUNET_assert (offset <= UINT32_MAX); 3811 TALER_kyc_measure_authorization_hash (access_token, 3812 legitimization_measure_row_id, 3813 (uint32_t) offset, 3814 &shv); 3815 switch (kc->type) 3816 { 3817 case TALER_KYCLOGIC_CT_INFO: 3818 return GNUNET_JSON_PACK ( 3819 GNUNET_JSON_pack_string ("form", 3820 "INFO"), 3821 GNUNET_JSON_pack_string ("description", 3822 kc->description), 3823 GNUNET_JSON_pack_allow_null ( 3824 GNUNET_JSON_pack_object_incref ("description_i18n", 3825 (json_t *) kc->description_i18n))); 3826 case TALER_KYCLOGIC_CT_FORM: 3827 GNUNET_assert (offset <= UINT_MAX); 3828 ids = GNUNET_STRINGS_data_to_string_alloc (&shv, 3829 sizeof (shv)); 3830 GNUNET_asprintf (&xids, 3831 "%s-%u-%llu", 3832 ids, 3833 (unsigned int) offset, 3834 (unsigned long long) legitimization_measure_row_id); 3835 GNUNET_free (ids); 3836 kri = GNUNET_JSON_PACK ( 3837 GNUNET_JSON_pack_string ("form", 3838 kc->details.form.name), 3839 GNUNET_JSON_pack_string ("id", 3840 xids), 3841 GNUNET_JSON_pack_allow_null ( 3842 GNUNET_JSON_pack_object_incref ("context", 3843 (json_t *) context)), 3844 GNUNET_JSON_pack_string ("description", 3845 kc->description), 3846 GNUNET_JSON_pack_allow_null ( 3847 GNUNET_JSON_pack_object_incref ("description_i18n", 3848 (json_t *) kc->description_i18n))); 3849 GNUNET_free (xids); 3850 return kri; 3851 case TALER_KYCLOGIC_CT_LINK: 3852 GNUNET_assert (offset <= UINT_MAX); 3853 ids = GNUNET_STRINGS_data_to_string_alloc (&shv, 3854 sizeof (shv)); 3855 GNUNET_asprintf (&xids, 3856 "%s-%u-%llu", 3857 ids, 3858 (unsigned int) offset, 3859 (unsigned long long) legitimization_measure_row_id); 3860 GNUNET_free (ids); 3861 kri = GNUNET_JSON_PACK ( 3862 GNUNET_JSON_pack_string ("form", 3863 "LINK"), 3864 GNUNET_JSON_pack_string ("id", 3865 xids), 3866 GNUNET_JSON_pack_string ("description", 3867 kc->description), 3868 GNUNET_JSON_pack_allow_null ( 3869 GNUNET_JSON_pack_object_incref ("description_i18n", 3870 (json_t *) kc->description_i18n))); 3871 GNUNET_free (xids); 3872 return kri; 3873 } 3874 GNUNET_break (0); /* invalid type */ 3875 return NULL; 3876 } 3877 3878 3879 void 3880 TALER_KYCLOGIC_get_measure_configuration ( 3881 json_t **proots, 3882 json_t **pprograms, 3883 json_t **pchecks, 3884 json_t **pdefault_rules) 3885 { 3886 json_t *roots; 3887 json_t *programs; 3888 json_t *checks; 3889 json_t *drules; 3890 3891 roots = json_object (); 3892 GNUNET_assert (NULL != roots); 3893 for (unsigned int i = 0; i<default_rules.num_custom_measures; i++) 3894 { 3895 const struct TALER_KYCLOGIC_Measure *m 3896 = &default_rules.custom_measures[i]; 3897 json_t *jm; 3898 3899 jm = GNUNET_JSON_PACK ( 3900 GNUNET_JSON_pack_string ("check_name", 3901 m->check_name), 3902 GNUNET_JSON_pack_allow_null ( 3903 GNUNET_JSON_pack_string ("prog_name", 3904 m->prog_name)), 3905 GNUNET_JSON_pack_allow_null ( 3906 GNUNET_JSON_pack_object_incref ("context", 3907 m->context))); 3908 GNUNET_assert (0 == 3909 json_object_set_new (roots, 3910 m->measure_name, 3911 jm)); 3912 } 3913 3914 programs = json_object (); 3915 GNUNET_assert (NULL != programs); 3916 for (unsigned int i = 0; i<num_aml_programs; i++) 3917 { 3918 const struct TALER_KYCLOGIC_AmlProgram *ap 3919 = aml_programs[i]; 3920 json_t *jp; 3921 json_t *ctx; 3922 json_t *inp; 3923 3924 ctx = json_array (); 3925 GNUNET_assert (NULL != ctx); 3926 for (unsigned int j = 0; j<ap->num_required_contexts; j++) 3927 { 3928 const char *rc = ap->required_contexts[j]; 3929 3930 GNUNET_assert (0 == 3931 json_array_append_new (ctx, 3932 json_string (rc))); 3933 } 3934 inp = json_array (); 3935 GNUNET_assert (NULL != inp); 3936 for (unsigned int j = 0; j<ap->num_required_attributes; j++) 3937 { 3938 const char *ra = ap->required_attributes[j]; 3939 3940 GNUNET_assert (0 == 3941 json_array_append_new (inp, 3942 json_string (ra))); 3943 } 3944 3945 jp = GNUNET_JSON_PACK ( 3946 GNUNET_JSON_pack_string ("description", 3947 ap->description), 3948 GNUNET_JSON_pack_array_steal ("context", 3949 ctx), 3950 GNUNET_JSON_pack_array_steal ("inputs", 3951 inp)); 3952 GNUNET_assert (0 == 3953 json_object_set_new (programs, 3954 ap->program_name, 3955 jp)); 3956 } 3957 3958 checks = json_object (); 3959 GNUNET_assert (NULL != checks); 3960 for (unsigned int i = 0; i<num_kyc_checks; i++) 3961 { 3962 const struct TALER_KYCLOGIC_KycCheck *ck 3963 = kyc_checks[i]; 3964 json_t *jc; 3965 json_t *requires; 3966 json_t *outputs; 3967 3968 requires = json_array (); 3969 GNUNET_assert (NULL != requires); 3970 for (unsigned int j = 0; j<ck->num_requires; j++) 3971 { 3972 const char *ra = ck->requires[j]; 3973 3974 GNUNET_assert (0 == 3975 json_array_append_new (requires, 3976 json_string (ra))); 3977 } 3978 outputs = json_array (); 3979 GNUNET_assert (NULL != outputs); 3980 for (unsigned int j = 0; j<ck->num_outputs; j++) 3981 { 3982 const char *out = ck->outputs[j]; 3983 3984 GNUNET_assert (0 == 3985 json_array_append_new (outputs, 3986 json_string (out))); 3987 } 3988 3989 jc = GNUNET_JSON_PACK ( 3990 GNUNET_JSON_pack_string ("description", 3991 ck->description), 3992 GNUNET_JSON_pack_allow_null ( 3993 GNUNET_JSON_pack_object_incref ("description_i18n", 3994 ck->description_i18n)), 3995 GNUNET_JSON_pack_array_steal ("requires", 3996 requires), 3997 GNUNET_JSON_pack_array_steal ("outputs", 3998 outputs), 3999 GNUNET_JSON_pack_string ("fallback", 4000 ck->fallback)); 4001 GNUNET_assert (0 == 4002 json_object_set_new (checks, 4003 ck->check_name, 4004 jc)); 4005 } 4006 drules = json_array (); 4007 GNUNET_assert (NULL != drules); 4008 { 4009 const struct TALER_KYCLOGIC_KycRule *rules 4010 = default_rules.kyc_rules; 4011 unsigned int num_rules 4012 = default_rules.num_kyc_rules; 4013 4014 for (unsigned int i = 0; i<num_rules; i++) 4015 { 4016 const struct TALER_KYCLOGIC_KycRule *rule = &rules[i]; 4017 json_t *measures; 4018 json_t *limit; 4019 4020 measures = json_array (); 4021 GNUNET_assert (NULL != measures); 4022 for (unsigned int j = 0; j<rule->num_measures; j++) 4023 GNUNET_assert ( 4024 0 == 4025 json_array_append_new (measures, 4026 json_string ( 4027 rule->next_measures[j]))); 4028 limit = GNUNET_JSON_PACK ( 4029 GNUNET_JSON_pack_allow_null ( 4030 GNUNET_JSON_pack_string ("rule_name", 4031 rule->rule_name)), 4032 TALER_JSON_pack_kycte ("operation_type", 4033 rule->trigger), 4034 TALER_JSON_pack_amount ("threshold", 4035 &rule->threshold), 4036 GNUNET_JSON_pack_time_rel ("timeframe", 4037 rule->timeframe), 4038 GNUNET_JSON_pack_array_steal ("measures", 4039 measures), 4040 GNUNET_JSON_pack_uint64 ("display_priority", 4041 rule->display_priority), 4042 GNUNET_JSON_pack_bool ("soft_limit", 4043 ! rule->verboten), 4044 GNUNET_JSON_pack_bool ("exposed", 4045 rule->exposed), 4046 GNUNET_JSON_pack_bool ("is_and_combinator", 4047 rule->is_and_combinator) 4048 ); 4049 GNUNET_assert (0 == 4050 json_array_append_new (drules, 4051 limit)); 4052 } 4053 } 4054 4055 *proots = roots; 4056 *pprograms = programs; 4057 *pchecks = checks; 4058 *pdefault_rules = drules; 4059 } 4060 4061 4062 enum TALER_ErrorCode 4063 TALER_KYCLOGIC_select_measure ( 4064 const json_t *jmeasures, 4065 size_t measure_index, 4066 const char **check_name, 4067 const char **prog_name, 4068 const json_t **context) 4069 { 4070 const json_t *jmeasure_arr; 4071 struct GNUNET_JSON_Specification spec[] = { 4072 GNUNET_JSON_spec_array_const ("measures", 4073 &jmeasure_arr), 4074 GNUNET_JSON_spec_end () 4075 }; 4076 const json_t *jmeasure; 4077 struct GNUNET_JSON_Specification ispec[] = { 4078 GNUNET_JSON_spec_string ("check_name", 4079 check_name), 4080 GNUNET_JSON_spec_mark_optional ( 4081 GNUNET_JSON_spec_string ("prog_name", 4082 prog_name), 4083 NULL), 4084 GNUNET_JSON_spec_mark_optional ( 4085 GNUNET_JSON_spec_object_const ("context", 4086 context), 4087 NULL), 4088 GNUNET_JSON_spec_end () 4089 }; 4090 4091 *check_name = NULL; 4092 *prog_name = NULL; 4093 *context = NULL; 4094 if (GNUNET_OK != 4095 GNUNET_JSON_parse (jmeasures, 4096 spec, 4097 NULL, NULL)) 4098 { 4099 GNUNET_break (0); 4100 return TALER_EC_EXCHANGE_KYC_MEASURES_MALFORMED; 4101 } 4102 if (measure_index >= json_array_size (jmeasure_arr)) 4103 { 4104 GNUNET_break_op (0); 4105 return TALER_EC_EXCHANGE_KYC_MEASURE_INDEX_INVALID; 4106 } 4107 jmeasure = json_array_get (jmeasure_arr, 4108 measure_index); 4109 if (GNUNET_OK != 4110 GNUNET_JSON_parse (jmeasure, 4111 ispec, 4112 NULL, NULL)) 4113 { 4114 GNUNET_break (0); 4115 return TALER_EC_EXCHANGE_KYC_MEASURES_MALFORMED; 4116 } 4117 return TALER_EC_NONE; 4118 } 4119 4120 4121 enum TALER_ErrorCode 4122 TALER_KYCLOGIC_check_form ( 4123 const json_t *jmeasures, 4124 size_t measure_index, 4125 const json_t *form_data, 4126 char **form_name, 4127 const char **error_message) 4128 { 4129 const char *check_name; 4130 const char *prog_name; 4131 const json_t *context; 4132 struct TALER_KYCLOGIC_KycCheck *kc; 4133 struct TALER_KYCLOGIC_AmlProgram *prog; 4134 4135 *error_message = NULL; 4136 *form_name = NULL; 4137 if (TALER_EC_NONE != 4138 TALER_KYCLOGIC_select_measure (jmeasures, 4139 measure_index, 4140 &check_name, 4141 &prog_name, 4142 &context)) 4143 { 4144 GNUNET_break_op (0); 4145 return TALER_EC_EXCHANGE_KYC_MEASURE_INDEX_INVALID; 4146 } 4147 kc = find_check (check_name); 4148 if (NULL == kc) 4149 { 4150 GNUNET_break (0); 4151 *error_message = check_name; 4152 return TALER_EC_EXCHANGE_KYC_GENERIC_CHECK_GONE; 4153 } 4154 if (TALER_KYCLOGIC_CT_FORM != kc->type) 4155 { 4156 GNUNET_break_op (0); 4157 return TALER_EC_EXCHANGE_KYC_NOT_A_FORM; 4158 } 4159 if (NULL == prog_name) 4160 { 4161 /* non-INFO checks must have an AML program */ 4162 GNUNET_break (0); 4163 return TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_BUG; 4164 } 4165 for (unsigned int i = 0; i<kc->num_outputs; i++) 4166 { 4167 const char *rattr = kc->outputs[i]; 4168 4169 if (NULL == json_object_get (form_data, 4170 rattr)) 4171 { 4172 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4173 "Form data lacks required attribute `%s' for KYC check `%s'\n", 4174 rattr, 4175 check_name); 4176 *error_message = rattr; 4177 return TALER_EC_EXCHANGE_KYC_AML_FORM_INCOMPLETE; 4178 } 4179 } 4180 prog = find_program (prog_name); 4181 if (NULL == prog) 4182 { 4183 GNUNET_break (0); 4184 *error_message = prog_name; 4185 return TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_GONE; 4186 } 4187 for (unsigned int i = 0; i<prog->num_required_attributes; i++) 4188 { 4189 const char *rattr = prog->required_attributes[i]; 4190 4191 if (NULL == json_object_get (form_data, 4192 rattr)) 4193 { 4194 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4195 "Form data lacks required attribute `%s' for AML program %s\n", 4196 rattr, 4197 prog_name); 4198 *error_message = rattr; 4199 return TALER_EC_EXCHANGE_KYC_AML_FORM_INCOMPLETE; 4200 } 4201 } 4202 *form_name = GNUNET_strdup (kc->details.form.name); 4203 return TALER_EC_NONE; 4204 } 4205 4206 4207 const char * 4208 TALER_KYCLOGIC_get_aml_program_fallback (const char *prog_name) 4209 { 4210 struct TALER_KYCLOGIC_AmlProgram *prog; 4211 4212 prog = find_program (prog_name); 4213 if (NULL == prog) 4214 { 4215 GNUNET_break (0); 4216 return NULL; 4217 } 4218 return prog->fallback; 4219 } 4220 4221 4222 const struct TALER_KYCLOGIC_KycProvider * 4223 TALER_KYCLOGIC_check_to_provider (const char *check_name) 4224 { 4225 struct TALER_KYCLOGIC_KycCheck *kc; 4226 4227 if (NULL == check_name) 4228 return NULL; 4229 if (0 == strcasecmp (check_name, 4230 "SKIP")) 4231 return NULL; 4232 kc = find_check (check_name); 4233 if (NULL == kc) 4234 { 4235 GNUNET_break (0); 4236 return NULL; 4237 } 4238 switch (kc->type) 4239 { 4240 case TALER_KYCLOGIC_CT_FORM: 4241 case TALER_KYCLOGIC_CT_INFO: 4242 return NULL; 4243 case TALER_KYCLOGIC_CT_LINK: 4244 break; 4245 } 4246 return kc->details.link.provider; 4247 } 4248 4249 4250 struct TALER_KYCLOGIC_AmlProgramRunnerHandle 4251 { 4252 /** 4253 * Function to call back with the result. 4254 */ 4255 TALER_KYCLOGIC_AmlProgramResultCallback aprc; 4256 4257 /** 4258 * Closure for @e aprc. 4259 */ 4260 void *aprc_cls; 4261 4262 /** 4263 * Handle to an external process. 4264 */ 4265 struct TALER_JSON_ExternalConversion *proc; 4266 4267 /** 4268 * AML program to turn. 4269 */ 4270 const struct TALER_KYCLOGIC_AmlProgram *program; 4271 4272 /** 4273 * Task to return @e apr result asynchronously. 4274 */ 4275 struct GNUNET_SCHEDULER_Task *async_cb; 4276 4277 /** 4278 * Result returned to the client. 4279 */ 4280 struct TALER_KYCLOGIC_AmlProgramResult apr; 4281 4282 /** 4283 * How long do we allow the AML program to run? 4284 */ 4285 struct GNUNET_TIME_Relative timeout; 4286 4287 }; 4288 4289 4290 /** 4291 * Function that that receives a JSON @a result from 4292 * the AML program. 4293 * 4294 * @param cls closure of type `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` 4295 * @param status_type how did the process die 4296 * @param code termination status code from the process, 4297 * non-zero if AML checks are required next 4298 * @param result some JSON result, NULL if we failed to get an JSON output 4299 */ 4300 static void 4301 handle_aml_output ( 4302 void *cls, 4303 enum GNUNET_OS_ProcessStatusType status_type, 4304 unsigned long code, 4305 const json_t *result) 4306 { 4307 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls; 4308 const char *fallback_measure = aprh->program->fallback; 4309 struct TALER_KYCLOGIC_AmlProgramResult *apr = &aprh->apr; 4310 const char **evs = NULL; 4311 4312 aprh->proc = NULL; 4313 if (NULL != aprh->async_cb) 4314 { 4315 GNUNET_SCHEDULER_cancel (aprh->async_cb); 4316 aprh->async_cb = NULL; 4317 } 4318 #if DEBUG 4319 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4320 "AML program %s output is:\n", 4321 aprh->program->program_name); 4322 json_dumpf (result, 4323 stderr, 4324 JSON_INDENT (2)); 4325 #endif 4326 memset (apr, 4327 0, 4328 sizeof (*apr)); 4329 if ( (GNUNET_OS_PROCESS_EXITED != status_type) || 4330 (0 != code) ) 4331 { 4332 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 4333 "AML program %s returned non-zero status %d/%d\n", 4334 aprh->program->program_name, 4335 (int) status_type, 4336 (int) code); 4337 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4338 apr->details.failure.fallback_measure 4339 = fallback_measure; 4340 apr->details.failure.error_message 4341 = "AML program returned non-zero exit code"; 4342 apr->details.failure.ec 4343 = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_FAILURE; 4344 goto ready; 4345 } 4346 4347 { 4348 const json_t *jevents = NULL; 4349 struct GNUNET_JSON_Specification spec[] = { 4350 GNUNET_JSON_spec_mark_optional ( 4351 GNUNET_JSON_spec_bool ( 4352 "to_investigate", 4353 &apr->details.success.to_investigate), 4354 NULL), 4355 GNUNET_JSON_spec_mark_optional ( 4356 GNUNET_JSON_spec_object_const ( 4357 "properties", 4358 &apr->details.success.account_properties), 4359 NULL), 4360 GNUNET_JSON_spec_mark_optional ( 4361 GNUNET_JSON_spec_array_const ( 4362 "events", 4363 &jevents), 4364 NULL), 4365 GNUNET_JSON_spec_object_const ( 4366 "new_rules", 4367 &apr->details.success.new_rules), 4368 GNUNET_JSON_spec_mark_optional ( 4369 GNUNET_JSON_spec_string ( 4370 "new_measures", 4371 &apr->details.success.new_measures), 4372 NULL), 4373 GNUNET_JSON_spec_end () 4374 }; 4375 const char *err; 4376 unsigned int line; 4377 4378 if (GNUNET_OK != 4379 GNUNET_JSON_parse (result, 4380 spec, 4381 &err, 4382 &line)) 4383 { 4384 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4385 "AML program output is malformed at `%s'\n", 4386 err); 4387 json_dumpf (result, 4388 stderr, 4389 JSON_INDENT (2)); 4390 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4391 apr->details.failure.fallback_measure 4392 = fallback_measure; 4393 apr->details.failure.error_message 4394 = err; 4395 apr->details.failure.ec 4396 = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT; 4397 goto ready; 4398 } 4399 apr->details.success.num_events 4400 = json_array_size (jevents); 4401 4402 GNUNET_assert (((size_t) apr->details.success.num_events) == 4403 json_array_size (jevents)); 4404 evs = GNUNET_new_array ( 4405 apr->details.success.num_events, 4406 const char *); 4407 for (unsigned int i = 0; i<apr->details.success.num_events; i++) 4408 { 4409 evs[i] = json_string_value ( 4410 json_array_get (jevents, 4411 i)); 4412 if (NULL == evs[i]) 4413 { 4414 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4415 apr->details.failure.fallback_measure 4416 = fallback_measure; 4417 apr->details.failure.error_message 4418 = "events"; 4419 apr->details.failure.ec 4420 = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT; 4421 goto ready; 4422 } 4423 } 4424 apr->status = TALER_KYCLOGIC_AMLR_SUCCESS; 4425 apr->details.success.events = evs; 4426 { 4427 /* check new_rules */ 4428 struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs; 4429 4430 lrs = TALER_KYCLOGIC_rules_parse ( 4431 apr->details.success.new_rules); 4432 if (NULL == lrs) 4433 { 4434 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4435 "AML program output is malformed at `%s'\n", 4436 "new_rules"); 4437 4438 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4439 apr->details.failure.fallback_measure 4440 = fallback_measure; 4441 apr->details.failure.error_message 4442 = "new_rules"; 4443 apr->details.failure.ec 4444 = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT; 4445 goto ready; 4446 } 4447 apr->details.success.expiration_time 4448 = lrs->expiration_time; 4449 TALER_KYCLOGIC_rules_free (lrs); 4450 } 4451 } 4452 ready: 4453 aprh->aprc (aprh->aprc_cls, 4454 &aprh->apr); 4455 GNUNET_free (evs); 4456 TALER_KYCLOGIC_run_aml_program_cancel (aprh); 4457 } 4458 4459 4460 /** 4461 * Helper function to asynchronously return the result. 4462 * 4463 * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return results for 4464 */ 4465 static void 4466 async_return_task (void *cls) 4467 { 4468 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls; 4469 4470 aprh->async_cb = NULL; 4471 aprh->aprc (aprh->aprc_cls, 4472 &aprh->apr); 4473 TALER_KYCLOGIC_run_aml_program_cancel (aprh); 4474 } 4475 4476 4477 /** 4478 * Helper function called on timeout on the fallback measure. 4479 * 4480 * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return results for 4481 */ 4482 static void 4483 handle_aml_timeout2 (void *cls) 4484 { 4485 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls; 4486 struct TALER_KYCLOGIC_AmlProgramResult *apr = &aprh->apr; 4487 const char *fallback_measure = aprh->program->fallback; 4488 4489 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4490 "Fallback measure %s ran into timeout (!)\n", 4491 aprh->program->program_name); 4492 if (NULL != aprh->proc) 4493 { 4494 TALER_JSON_external_conversion_stop (aprh->proc); 4495 aprh->proc = NULL; 4496 } 4497 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4498 apr->details.failure.fallback_measure 4499 = fallback_measure; 4500 apr->details.failure.error_message 4501 = aprh->program->program_name; 4502 apr->details.failure.ec 4503 = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT; 4504 async_return_task (aprh); 4505 } 4506 4507 4508 /** 4509 * Helper function called on timeout of an AML program. 4510 * Runs the fallback measure. 4511 * 4512 * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return results for 4513 */ 4514 static void 4515 handle_aml_timeout (void *cls) 4516 { 4517 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls; 4518 struct TALER_KYCLOGIC_AmlProgramResult *apr = &aprh->apr; 4519 const char *fallback_measure = aprh->program->fallback; 4520 const struct TALER_KYCLOGIC_Measure *m; 4521 const struct TALER_KYCLOGIC_AmlProgram *fprogram; 4522 4523 aprh->async_cb = NULL; 4524 GNUNET_assert (NULL != fallback_measure); 4525 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 4526 "AML program %s ran into timeout\n", 4527 aprh->program->program_name); 4528 if (NULL != aprh->proc) 4529 { 4530 TALER_JSON_external_conversion_stop (aprh->proc); 4531 aprh->proc = NULL; 4532 } 4533 4534 m = TALER_KYCLOGIC_get_measure (&default_rules, 4535 fallback_measure); 4536 /* Fallback program could have "disappeared" due to configuration change, 4537 as we do not check all rule sets in the database when our configuration 4538 is updated... */ 4539 if (NULL == m) 4540 { 4541 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4542 "Fallback measure `%s' does not exist (anymore?).\n", 4543 fallback_measure); 4544 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4545 apr->details.failure.fallback_measure 4546 = fallback_measure; 4547 apr->details.failure.error_message 4548 = aprh->program->program_name; 4549 apr->details.failure.ec 4550 = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT; 4551 async_return_task (aprh); 4552 return; 4553 } 4554 /* We require fallback measures to have a 'SKIP' check */ 4555 GNUNET_break (0 == 4556 strcasecmp (m->check_name, 4557 "SKIP")); 4558 fprogram = find_program (m->prog_name); 4559 /* Program associated with an original measure must exist */ 4560 GNUNET_assert (NULL != fprogram); 4561 if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES))) 4562 { 4563 /* We might not have recognized the fallback measure as such 4564 because it was not used as such in the plain configuration, 4565 and legitimization rule sets might have referred to an older 4566 configuration. So this should be super-rare but possible. */ 4567 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4568 "Program `%s' used in fallback measure `%s' requires inputs and is thus unsuitable as a fallback measure!\n", 4569 m->prog_name, 4570 fallback_measure); 4571 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4572 apr->details.failure.fallback_measure 4573 = fallback_measure; 4574 apr->details.failure.error_message 4575 = aprh->program->program_name; 4576 apr->details.failure.ec 4577 = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT; 4578 async_return_task (aprh); 4579 return; 4580 } 4581 { 4582 /* Run fallback AML program */ 4583 json_t *input = json_object (); 4584 const char *extra_args[] = { 4585 "-c", 4586 cfg_filename, 4587 NULL, 4588 }; 4589 char **args; 4590 4591 args = split_words (fprogram->command, 4592 extra_args); 4593 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4594 "Running fallback measure `%s' (%s)\n", 4595 fallback_measure, 4596 fprogram->command); 4597 aprh->proc = TALER_JSON_external_conversion_start ( 4598 input, 4599 &handle_aml_output, 4600 aprh, 4601 args[0], 4602 (const char **) args); 4603 destroy_words (args); 4604 json_decref (input); 4605 } 4606 aprh->async_cb = GNUNET_SCHEDULER_add_delayed (aprh->timeout, 4607 &handle_aml_timeout2, 4608 aprh); 4609 } 4610 4611 4612 struct TALER_KYCLOGIC_AmlProgramRunnerHandle * 4613 TALER_KYCLOGIC_run_aml_program ( 4614 const json_t *jmeasures, 4615 bool is_wallet, 4616 unsigned int measure_index, 4617 TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb, 4618 void *current_attributes_cb_cls, 4619 TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb, 4620 void *current_rules_cb_cls, 4621 TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb, 4622 void *aml_history_cb_cls, 4623 TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb, 4624 void *kyc_history_cb_cls, 4625 struct GNUNET_TIME_Relative timeout, 4626 TALER_KYCLOGIC_AmlProgramResultCallback aprc, 4627 void *aprc_cls) 4628 { 4629 const json_t *context; 4630 const char *check_name; 4631 const char *prog_name; 4632 4633 { 4634 enum TALER_ErrorCode ec; 4635 4636 ec = TALER_KYCLOGIC_select_measure (jmeasures, 4637 measure_index, 4638 &check_name, 4639 &prog_name, 4640 &context); 4641 if (TALER_EC_NONE != ec) 4642 { 4643 GNUNET_break (0); 4644 return NULL; 4645 } 4646 } 4647 if (NULL == prog_name) 4648 { 4649 /* Trying to run AML program on a measure that does not 4650 have one, and that should thus be an INFO check which 4651 should never lead here. Very strange. */ 4652 GNUNET_break (0); 4653 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4654 "Measure %u with check `%s' does not have an AML program!\n", 4655 measure_index, 4656 check_name); 4657 json_dumpf (jmeasures, 4658 stderr, 4659 JSON_INDENT (2)); 4660 return NULL; 4661 } 4662 return TALER_KYCLOGIC_run_aml_program2 (prog_name, 4663 context, 4664 is_wallet, 4665 current_attributes_cb, 4666 current_attributes_cb_cls, 4667 current_rules_cb, 4668 current_rules_cb_cls, 4669 aml_history_cb, 4670 aml_history_cb_cls, 4671 kyc_history_cb, 4672 kyc_history_cb_cls, 4673 timeout, 4674 aprc, 4675 aprc_cls); 4676 } 4677 4678 4679 struct TALER_KYCLOGIC_AmlProgramRunnerHandle * 4680 TALER_KYCLOGIC_run_aml_program2 ( 4681 const char *prog_name, 4682 const json_t *context, 4683 bool is_wallet, 4684 TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb, 4685 void *current_attributes_cb_cls, 4686 TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb, 4687 void *current_rules_cb_cls, 4688 TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb, 4689 void *aml_history_cb_cls, 4690 TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb, 4691 void *kyc_history_cb_cls, 4692 struct GNUNET_TIME_Relative timeout, 4693 TALER_KYCLOGIC_AmlProgramResultCallback aprc, 4694 void *aprc_cls) 4695 { 4696 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh; 4697 struct TALER_KYCLOGIC_AmlProgram *prog; 4698 const json_t *jdefault_rules; 4699 json_t *current_rules; 4700 json_t *aml_history; 4701 json_t *kyc_history; 4702 json_t *attributes; 4703 4704 prog = find_program (prog_name); 4705 if (NULL == prog) 4706 { 4707 GNUNET_break (0); 4708 return NULL; 4709 } 4710 aprh = GNUNET_new (struct TALER_KYCLOGIC_AmlProgramRunnerHandle); 4711 aprh->aprc = aprc; 4712 aprh->aprc_cls = aprc_cls; 4713 aprh->program = prog; 4714 if (0 != (API_ATTRIBUTES & prog->input_mask)) 4715 { 4716 attributes = current_attributes_cb (current_attributes_cb_cls); 4717 #if DEBUG 4718 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4719 "KYC attributes for AML program %s are:\n", 4720 prog_name); 4721 json_dumpf (attributes, 4722 stderr, 4723 JSON_INDENT (2)); 4724 fprintf (stderr, 4725 "\n"); 4726 #endif 4727 for (unsigned int i = 0; i<prog->num_required_attributes; i++) 4728 { 4729 const char *rattr = prog->required_attributes[i]; 4730 4731 if (NULL == json_object_get (attributes, 4732 rattr)) 4733 { 4734 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4735 "KYC attributes lack required attribute `%s' for AML program %s\n", 4736 rattr, 4737 prog->program_name); 4738 #if DEBUG 4739 json_dumpf (attributes, 4740 stderr, 4741 JSON_INDENT (2)); 4742 #endif 4743 aprh->apr.status = TALER_KYCLOGIC_AMLR_FAILURE; 4744 aprh->apr.details.failure.fallback_measure 4745 = prog->fallback; 4746 aprh->apr.details.failure.error_message 4747 = rattr; 4748 aprh->apr.details.failure.ec 4749 = TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_INCOMPLETE_REPLY; 4750 aprh->async_cb 4751 = GNUNET_SCHEDULER_add_now (&async_return_task, 4752 aprh); 4753 json_decref (attributes); 4754 return aprh; 4755 } 4756 } 4757 } 4758 else 4759 { 4760 attributes = NULL; 4761 } 4762 if (0 != (API_CONTEXT & prog->input_mask)) 4763 { 4764 for (unsigned int i = 0; i<prog->num_required_contexts; i++) 4765 { 4766 const char *rctx = prog->required_contexts[i]; 4767 4768 if (NULL == json_object_get (context, 4769 rctx)) 4770 { 4771 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4772 "Context lacks required field `%s' for AML program %s\n", 4773 rctx, 4774 prog->program_name); 4775 #if DEBUG 4776 json_dumpf (context, 4777 stderr, 4778 JSON_INDENT (2)); 4779 #endif 4780 aprh->apr.status = TALER_KYCLOGIC_AMLR_FAILURE; 4781 aprh->apr.details.failure.fallback_measure 4782 = prog->fallback; 4783 aprh->apr.details.failure.error_message 4784 = rctx; 4785 aprh->apr.details.failure.ec 4786 = TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_INCOMPLETE_CONTEXT; 4787 aprh->async_cb 4788 = GNUNET_SCHEDULER_add_now (&async_return_task, 4789 aprh); 4790 json_decref (attributes); 4791 return aprh; 4792 } 4793 } 4794 } 4795 else 4796 { 4797 context = NULL; 4798 } 4799 if (0 == (API_AML_HISTORY & prog->input_mask)) 4800 aml_history = NULL; 4801 else 4802 aml_history = aml_history_cb (aml_history_cb_cls); 4803 if (0 == (API_KYC_HISTORY & prog->input_mask)) 4804 kyc_history = NULL; 4805 else 4806 kyc_history = kyc_history_cb (kyc_history_cb_cls); 4807 if (0 == (API_CURRENT_RULES & prog->input_mask)) 4808 current_rules = NULL; 4809 else 4810 current_rules = current_rules_cb (current_rules_cb_cls); 4811 if (0 != (API_DEFAULT_RULES & prog->input_mask)) 4812 jdefault_rules = 4813 (is_wallet 4814 ? wallet_default_lrs 4815 : bankaccount_default_lrs); 4816 else 4817 jdefault_rules = NULL; 4818 { 4819 json_t *input; 4820 const char *extra_args[] = { 4821 "-c", 4822 cfg_filename, 4823 NULL, 4824 }; 4825 char **args; 4826 4827 input = GNUNET_JSON_PACK ( 4828 GNUNET_JSON_pack_allow_null ( 4829 GNUNET_JSON_pack_object_steal ("current_rules", 4830 current_rules)), 4831 GNUNET_JSON_pack_allow_null ( 4832 GNUNET_JSON_pack_object_incref ("default_rules", 4833 (json_t *) jdefault_rules)), 4834 GNUNET_JSON_pack_allow_null ( 4835 GNUNET_JSON_pack_object_incref ("context", 4836 (json_t *) context)), 4837 GNUNET_JSON_pack_allow_null ( 4838 GNUNET_JSON_pack_object_steal ("attributes", 4839 attributes)), 4840 GNUNET_JSON_pack_allow_null ( 4841 GNUNET_JSON_pack_array_steal ("aml_history", 4842 aml_history)), 4843 GNUNET_JSON_pack_allow_null ( 4844 GNUNET_JSON_pack_array_steal ("kyc_history", 4845 kyc_history)) 4846 ); 4847 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4848 "Running AML program %s\n", 4849 prog->command); 4850 args = split_words (prog->command, 4851 extra_args); 4852 GNUNET_assert (NULL != args); 4853 GNUNET_assert (NULL != args[0]); 4854 #if DEBUG 4855 json_dumpf (input, 4856 stderr, 4857 JSON_INDENT (2)); 4858 #endif 4859 aprh->proc = TALER_JSON_external_conversion_start ( 4860 input, 4861 &handle_aml_output, 4862 aprh, 4863 args[0], 4864 (const char **) args); 4865 destroy_words (args); 4866 json_decref (input); 4867 } 4868 aprh->timeout = timeout; 4869 aprh->async_cb = GNUNET_SCHEDULER_add_delayed (timeout, 4870 &handle_aml_timeout, 4871 aprh); 4872 return aprh; 4873 } 4874 4875 4876 struct TALER_KYCLOGIC_AmlProgramRunnerHandle * 4877 TALER_KYCLOGIC_run_aml_program3 ( 4878 bool is_wallet, 4879 const struct TALER_KYCLOGIC_Measure *measure, 4880 TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb, 4881 void *current_attributes_cb_cls, 4882 TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb, 4883 void *current_rules_cb_cls, 4884 TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb, 4885 void *aml_history_cb_cls, 4886 TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb, 4887 void *kyc_history_cb_cls, 4888 struct GNUNET_TIME_Relative timeout, 4889 TALER_KYCLOGIC_AmlProgramResultCallback aprc, 4890 void *aprc_cls) 4891 { 4892 return TALER_KYCLOGIC_run_aml_program2 ( 4893 measure->prog_name, 4894 measure->context, 4895 is_wallet, 4896 current_attributes_cb, 4897 current_attributes_cb_cls, 4898 current_rules_cb, 4899 current_rules_cb_cls, 4900 aml_history_cb, 4901 aml_history_cb_cls, 4902 kyc_history_cb, 4903 kyc_history_cb_cls, 4904 timeout, 4905 aprc, 4906 aprc_cls); 4907 } 4908 4909 4910 const char * 4911 TALER_KYCLOGIC_run_aml_program_get_name ( 4912 const struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh) 4913 { 4914 return aprh->program->program_name; 4915 } 4916 4917 4918 void 4919 TALER_KYCLOGIC_run_aml_program_cancel ( 4920 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh) 4921 { 4922 if (NULL != aprh->proc) 4923 { 4924 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 4925 "Killing AML program\n"); 4926 TALER_JSON_external_conversion_stop (aprh->proc); 4927 aprh->proc = NULL; 4928 } 4929 if (NULL != aprh->async_cb) 4930 { 4931 GNUNET_SCHEDULER_cancel (aprh->async_cb); 4932 aprh->async_cb = NULL; 4933 } 4934 GNUNET_free (aprh); 4935 } 4936 4937 4938 json_t * 4939 TALER_KYCLOGIC_get_hard_limits () 4940 { 4941 const struct TALER_KYCLOGIC_KycRule *rules 4942 = default_rules.kyc_rules; 4943 unsigned int num_rules 4944 = default_rules.num_kyc_rules; 4945 json_t *hard_limits; 4946 4947 hard_limits = json_array (); 4948 GNUNET_assert (NULL != hard_limits); 4949 for (unsigned int i = 0; i<num_rules; i++) 4950 { 4951 const struct TALER_KYCLOGIC_KycRule *rule = &rules[i]; 4952 json_t *hard_limit; 4953 4954 if (! rule->verboten) 4955 continue; 4956 if (! rule->exposed) 4957 continue; 4958 hard_limit = GNUNET_JSON_PACK ( 4959 GNUNET_JSON_pack_allow_null ( 4960 GNUNET_JSON_pack_string ("rule_name", 4961 rule->rule_name)), 4962 TALER_JSON_pack_kycte ("operation_type", 4963 rule->trigger), 4964 GNUNET_JSON_pack_time_rel ("timeframe", 4965 rule->timeframe), 4966 TALER_JSON_pack_amount ("threshold", 4967 &rule->threshold) 4968 ); 4969 GNUNET_assert (0 == 4970 json_array_append_new (hard_limits, 4971 hard_limit)); 4972 } 4973 return hard_limits; 4974 } 4975 4976 4977 json_t * 4978 TALER_KYCLOGIC_get_zero_limits () 4979 { 4980 const struct TALER_KYCLOGIC_KycRule *rules 4981 = default_rules.kyc_rules; 4982 unsigned int num_rules 4983 = default_rules.num_kyc_rules; 4984 json_t *zero_limits; 4985 4986 zero_limits = json_array (); 4987 GNUNET_assert (NULL != zero_limits); 4988 for (unsigned int i = 0; i<num_rules; i++) 4989 { 4990 const struct TALER_KYCLOGIC_KycRule *rule = &rules[i]; 4991 json_t *zero_limit; 4992 4993 if (! rule->exposed) 4994 continue; 4995 if (rule->verboten) 4996 continue; /* see: hard_limits */ 4997 if (! TALER_amount_is_zero (&rule->threshold)) 4998 continue; 4999 zero_limit = GNUNET_JSON_PACK ( 5000 GNUNET_JSON_pack_allow_null ( 5001 GNUNET_JSON_pack_string ("rule_name", 5002 rule->rule_name)), 5003 TALER_JSON_pack_kycte ("operation_type", 5004 rule->trigger)); 5005 GNUNET_assert (0 == 5006 json_array_append_new (zero_limits, 5007 zero_limit)); 5008 } 5009 return zero_limits; 5010 } 5011 5012 5013 json_t * 5014 TALER_KYCLOGIC_get_default_legi_rules (bool for_wallet) 5015 { 5016 const json_t *r; 5017 5018 r = (for_wallet 5019 ? wallet_default_lrs 5020 : bankaccount_default_lrs); 5021 return json_incref ((json_t *) r); 5022 } 5023 5024 5025 /* end of kyclogic_api.c */