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