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