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