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