kyclogic_api.c (148756B)
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 { 2566 enum GNUNET_GenericReturnValue r; 2567 2568 r = GNUNET_CONFIGURATION_get_value_yesno (cfg, 2569 section, 2570 "ENABLED"); 2571 if ( (GNUNET_SYSERR == r) && 2572 (GNUNET_YES == 2573 GNUNET_CONFIGURATION_have_value (cfg, 2574 section, 2575 "ENABLED")) ) 2576 { 2577 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2578 section, 2579 "ENABLED", 2580 "YES or NO required"); 2581 return GNUNET_SYSERR; 2582 } 2583 if (GNUNET_YES != r) 2584 return GNUNET_OK; 2585 } 2586 if (GNUNET_OK != 2587 TALER_config_get_amount (cfg, 2588 section, 2589 "THRESHOLD", 2590 &threshold)) 2591 { 2592 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2593 section, 2594 "THRESHOLD", 2595 "amount required"); 2596 return GNUNET_SYSERR; 2597 } 2598 if (0 != 2599 strcasecmp (threshold.currency, 2600 my_currency)) 2601 { 2602 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2603 section, 2604 "THRESHOLD", 2605 "currency mismatch"); 2606 return GNUNET_SYSERR; 2607 } 2608 { 2609 enum GNUNET_GenericReturnValue r; 2610 2611 r = GNUNET_CONFIGURATION_get_value_yesno (cfg, 2612 section, 2613 "EXPOSED"); 2614 if ( (GNUNET_SYSERR == r) && 2615 (GNUNET_YES == 2616 GNUNET_CONFIGURATION_have_value (cfg, 2617 section, 2618 "EXPOSED")) ) 2619 { 2620 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2621 section, 2622 "EXPOSED", 2623 "YES or NO required"); 2624 return GNUNET_SYSERR; 2625 } 2626 exposed = (GNUNET_YES == r); 2627 } 2628 { 2629 enum GNUNET_GenericReturnValue r; 2630 2631 r = GNUNET_CONFIGURATION_get_value_yesno (cfg, 2632 section, 2633 "IS_AND_COMBINATOR"); 2634 if (GNUNET_SYSERR == r) 2635 { 2636 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2637 section, 2638 "IS_AND_COMBINATOR", 2639 "YES or NO required"); 2640 return GNUNET_SYSERR; 2641 } 2642 is_and = (GNUNET_YES == r); 2643 } 2644 2645 { 2646 char *ot_s; 2647 2648 if (GNUNET_OK != 2649 GNUNET_CONFIGURATION_get_value_string (cfg, 2650 section, 2651 "OPERATION_TYPE", 2652 &ot_s)) 2653 { 2654 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2655 section, 2656 "OPERATION_TYPE"); 2657 return GNUNET_SYSERR; 2658 } 2659 if (GNUNET_OK != 2660 TALER_KYCLOGIC_kyc_trigger_from_string (ot_s, 2661 &ot)) 2662 { 2663 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2664 section, 2665 "OPERATION_TYPE", 2666 "valid trigger type required"); 2667 GNUNET_free (ot_s); 2668 return GNUNET_SYSERR; 2669 } 2670 GNUNET_free (ot_s); 2671 } 2672 2673 if (GNUNET_OK != 2674 GNUNET_CONFIGURATION_get_value_time (cfg, 2675 section, 2676 "TIMEFRAME", 2677 &timeframe)) 2678 { 2679 if (TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE == ot) 2680 { 2681 timeframe = GNUNET_TIME_UNIT_ZERO; 2682 } 2683 else 2684 { 2685 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2686 section, 2687 "TIMEFRAME", 2688 "duration required"); 2689 return GNUNET_SYSERR; 2690 } 2691 } 2692 if (GNUNET_OK != 2693 GNUNET_CONFIGURATION_get_value_string (cfg, 2694 section, 2695 "NEXT_MEASURES", 2696 &measures)) 2697 { 2698 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2699 section, 2700 "NEXT_MEASURES"); 2701 return GNUNET_SYSERR; 2702 } 2703 if (! token_list_lower (measures)) 2704 { 2705 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2706 section, 2707 "NEXT_MEASURES", 2708 "Only [a-zA-Z0-9 _-] are allowed"); 2709 GNUNET_free (measures); 2710 return GNUNET_SYSERR; 2711 } 2712 2713 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2714 "Adding KYC rule %s for trigger %d with threshold %s\n", 2715 section, 2716 (int) ot, 2717 TALER_amount2s (&threshold)); 2718 { 2719 struct TALER_KYCLOGIC_KycRule kt = { 2720 .lrs = &default_rules, 2721 .rule_name = GNUNET_strdup (§ion[strlen ("kyc-rule-")]), 2722 .timeframe = timeframe, 2723 .threshold = threshold, 2724 .trigger = ot, 2725 .is_and_combinator = is_and, 2726 .exposed = exposed, 2727 .display_priority = 0, 2728 .verboten = false 2729 }; 2730 2731 add_tokens (measures, 2732 "; \n\t", 2733 &kt.next_measures, 2734 &kt.num_measures); 2735 for (unsigned int i=0; i<kt.num_measures; i++) 2736 if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE, 2737 kt.next_measures[i])) 2738 kt.verboten = true; 2739 GNUNET_free (measures); 2740 GNUNET_array_append (default_rules.kyc_rules, 2741 default_rules.num_kyc_rules, 2742 kt); 2743 } 2744 return GNUNET_OK; 2745 } 2746 2747 2748 /** 2749 * Function to iterate over configuration sections. 2750 * 2751 * @param cls a `struct SectionContext *` 2752 * @param section name of the section 2753 */ 2754 static void 2755 handle_rule_section (void *cls, 2756 const char *section) 2757 { 2758 struct SectionContext *sc = cls; 2759 char *s; 2760 2761 if (! sc->result) 2762 return; 2763 s = normalize_section_with_prefix ("kyc-rule-", 2764 section); 2765 if (NULL == s) 2766 return; 2767 if (GNUNET_OK != 2768 add_rule (sc->cfg, 2769 s)) 2770 sc->result = false; 2771 GNUNET_free (s); 2772 } 2773 2774 2775 /** 2776 * Parse array dimension argument of @a tok (if present) 2777 * and store result in @a dimp. Does nothing if 2778 * @a tok does not contain '['. Otherwise does some input 2779 * validation. 2780 * 2781 * @param section name of configuration section for logging 2782 * @param tok input to parse, of form "text[$DIM]" 2783 * @param[out] dimp set to value of $DIM 2784 * @return true on success 2785 */ 2786 static bool 2787 parse_dim (const char *section, 2788 const char *tok, 2789 long long *dimp) 2790 { 2791 const char *dim = strchr (tok, 2792 '['); 2793 char dummy; 2794 2795 if (NULL == dim) 2796 return true; 2797 if (1 != 2798 sscanf (dim, 2799 "[%lld]%c", 2800 dimp, 2801 &dummy)) 2802 { 2803 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2804 section, 2805 "COMMAND", 2806 "output for -i invalid (bad dimension given)"); 2807 return false; 2808 } 2809 return true; 2810 } 2811 2812 2813 /** 2814 * Parse configuration @a cfg in section @a section for 2815 * the specification of an AML program. 2816 * 2817 * @param cfg configuration to parse 2818 * @param section configuration section to parse 2819 * @return #GNUNET_OK on success 2820 */ 2821 static enum GNUNET_GenericReturnValue 2822 add_program (const struct GNUNET_CONFIGURATION_Handle *cfg, 2823 const char *section) 2824 { 2825 char *command = NULL; 2826 char *description = NULL; 2827 char *fallback = NULL; 2828 char *required_contexts = NULL; 2829 char *required_attributes = NULL; 2830 char *required_inputs = NULL; 2831 enum AmlProgramInputs input_mask = API_NONE; 2832 long long aml_history_length_limit = INT64_MAX; 2833 long long kyc_history_length_limit = INT64_MAX; 2834 2835 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2836 "Parsing KYC program %s\n", 2837 section); 2838 if (GNUNET_OK != 2839 GNUNET_CONFIGURATION_get_value_string (cfg, 2840 section, 2841 "COMMAND", 2842 &command)) 2843 { 2844 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2845 section, 2846 "COMMAND", 2847 "command required"); 2848 goto fail; 2849 } 2850 if (GNUNET_OK != 2851 GNUNET_CONFIGURATION_get_value_string (cfg, 2852 section, 2853 "DESCRIPTION", 2854 &description)) 2855 { 2856 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2857 section, 2858 "DESCRIPTION", 2859 "description required"); 2860 goto fail; 2861 } 2862 if (GNUNET_OK != 2863 GNUNET_CONFIGURATION_get_value_string (cfg, 2864 section, 2865 "FALLBACK", 2866 &fallback)) 2867 { 2868 /* We do *not* allow NULL to fall back to default rules because fallbacks 2869 are used when there is actually a serious error and thus some action 2870 (usually an investigation) is always in order, and that's basically 2871 never the default. And as fallbacks should be rare, we really insist on 2872 them at least being explicitly configured. Otherwise these errors may 2873 go undetected simply because someone forgot to configure a fallback and 2874 then nothing happens. */ 2875 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2876 section, 2877 "FALLBACK", 2878 "fallback measure name required"); 2879 goto fail; 2880 } 2881 2882 required_contexts = command_output (command, 2883 "-r"); 2884 if (NULL == required_contexts) 2885 { 2886 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2887 section, 2888 "COMMAND", 2889 "output for -r invalid"); 2890 goto fail; 2891 } 2892 2893 required_attributes = command_output (command, 2894 "-a"); 2895 if (NULL == required_attributes) 2896 { 2897 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2898 section, 2899 "COMMAND", 2900 "output for -a invalid"); 2901 goto fail; 2902 } 2903 2904 required_inputs = command_output (command, 2905 "-i"); 2906 if (NULL == required_inputs) 2907 { 2908 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2909 section, 2910 "COMMAND", 2911 "output for -i invalid"); 2912 goto fail; 2913 } 2914 2915 { 2916 char *sptr; 2917 2918 for (char *tok = strtok_r (required_inputs, 2919 ";\n \t", 2920 &sptr); 2921 NULL != tok; 2922 tok = strtok_r (NULL, 2923 ";\n \t", 2924 &sptr) ) 2925 { 2926 if (0 == strcasecmp (tok, 2927 "context")) 2928 input_mask |= API_CONTEXT; 2929 else if (0 == strcasecmp (tok, 2930 "attributes")) 2931 input_mask |= API_ATTRIBUTES; 2932 else if (0 == strcasecmp (tok, 2933 "current_rules")) 2934 input_mask |= API_CURRENT_RULES; 2935 else if (0 == strcasecmp (tok, 2936 "default_rules")) 2937 input_mask |= API_DEFAULT_RULES; 2938 else if (0 == strncasecmp (tok, 2939 "aml_history", 2940 strlen ("aml_history"))) 2941 { 2942 input_mask |= API_AML_HISTORY; 2943 if (! parse_dim (section, 2944 tok, 2945 &aml_history_length_limit)) 2946 goto fail; 2947 } 2948 else if (0 == strncasecmp (tok, 2949 "kyc_history", 2950 strlen ("kyc_history"))) 2951 { 2952 input_mask |= API_KYC_HISTORY; 2953 if (! parse_dim (section, 2954 tok, 2955 &kyc_history_length_limit)) 2956 goto fail; 2957 } 2958 else 2959 { 2960 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2961 section, 2962 "COMMAND", 2963 "output for -i invalid (unsupported input)"); 2964 goto fail; 2965 } 2966 } 2967 } 2968 GNUNET_free (required_inputs); 2969 2970 { 2971 struct TALER_KYCLOGIC_AmlProgram *ap; 2972 2973 ap = GNUNET_new (struct TALER_KYCLOGIC_AmlProgram); 2974 ap->program_name = GNUNET_strdup (§ion[strlen ("aml-program-")]); 2975 ap->command = command; 2976 ap->description = description; 2977 ap->fallback = fallback; 2978 ap->input_mask = input_mask; 2979 ap->aml_history_length_limit = aml_history_length_limit; 2980 ap->kyc_history_length_limit = kyc_history_length_limit; 2981 add_tokens (required_contexts, 2982 "; \n\t", 2983 &ap->required_contexts, 2984 &ap->num_required_contexts); 2985 GNUNET_free (required_contexts); 2986 add_tokens (required_attributes, 2987 "; \n\t", 2988 &ap->required_attributes, 2989 &ap->num_required_attributes); 2990 GNUNET_free (required_attributes); 2991 GNUNET_array_append (aml_programs, 2992 num_aml_programs, 2993 ap); 2994 } 2995 return GNUNET_OK; 2996 fail: 2997 GNUNET_free (command); 2998 GNUNET_free (description); 2999 GNUNET_free (required_inputs); 3000 GNUNET_free (required_contexts); 3001 GNUNET_free (required_attributes); 3002 GNUNET_free (fallback); 3003 return GNUNET_SYSERR; 3004 } 3005 3006 3007 /** 3008 * Function to iterate over configuration sections. 3009 * 3010 * @param cls a `struct SectionContext *` 3011 * @param section name of the section 3012 */ 3013 static void 3014 handle_program_section (void *cls, 3015 const char *section) 3016 { 3017 struct SectionContext *sc = cls; 3018 char *s; 3019 3020 if (! sc->result) 3021 return; 3022 s = normalize_section_with_prefix ("aml-program-", 3023 section); 3024 if (NULL == s) 3025 return; 3026 if (GNUNET_OK != 3027 add_program (sc->cfg, 3028 s)) 3029 sc->result = false; 3030 GNUNET_free (s); 3031 } 3032 3033 3034 /** 3035 * Parse configuration @a cfg in section @a section for 3036 * the specification of a KYC measure. 3037 * 3038 * @param cfg configuration to parse 3039 * @param section configuration section to parse 3040 * @return #GNUNET_OK on success 3041 */ 3042 static enum GNUNET_GenericReturnValue 3043 add_measure (const struct GNUNET_CONFIGURATION_Handle *cfg, 3044 const char *section) 3045 { 3046 bool voluntary; 3047 char *check_name = NULL; 3048 struct TALER_KYCLOGIC_KycCheck *kc = NULL; 3049 char *context_str = NULL; 3050 char *program = NULL; 3051 json_t *context; 3052 json_error_t err; 3053 3054 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3055 "Parsing KYC measure %s\n", 3056 section); 3057 if (GNUNET_OK != 3058 GNUNET_CONFIGURATION_get_value_string (cfg, 3059 section, 3060 "CHECK_NAME", 3061 &check_name)) 3062 { 3063 check_name = GNUNET_strdup ("skip"); 3064 } 3065 if (0 != strcasecmp (check_name, 3066 "skip")) 3067 { 3068 kc = find_check (check_name); 3069 if (NULL == kc) 3070 { 3071 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 3072 section, 3073 "CHECK_NAME", 3074 "check unknown"); 3075 goto fail; 3076 } 3077 } 3078 if (GNUNET_OK != 3079 GNUNET_CONFIGURATION_get_value_string (cfg, 3080 section, 3081 "PROGRAM", 3082 &program)) 3083 { 3084 if ( (NULL == kc) || 3085 (TALER_KYCLOGIC_CT_INFO != kc->type) ) 3086 { 3087 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 3088 section, 3089 "PROGRAM"); 3090 goto fail; 3091 } 3092 } 3093 else 3094 { 3095 /* AML program given, but do we want one? */ 3096 if ( (NULL != kc) && 3097 (TALER_KYCLOGIC_CT_INFO == kc->type) ) 3098 { 3099 GNUNET_log_config_invalid ( 3100 GNUNET_ERROR_TYPE_WARNING, 3101 section, 3102 "PROGRAM", 3103 "AML program specified for a check of type INFO (ignored)"); 3104 GNUNET_free (program); 3105 } 3106 } 3107 voluntary = (GNUNET_YES == 3108 GNUNET_CONFIGURATION_get_value_yesno (cfg, 3109 section, 3110 "VOLUNTARY")); 3111 if (GNUNET_OK != 3112 GNUNET_CONFIGURATION_get_value_string (cfg, 3113 section, 3114 "CONTEXT", 3115 &context_str)) 3116 { 3117 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 3118 section, 3119 "CONTEXT"); 3120 goto fail; 3121 } 3122 context = json_loads (context_str, 3123 JSON_REJECT_DUPLICATES, 3124 &err); 3125 GNUNET_free (context_str); 3126 if (NULL == context) 3127 { 3128 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 3129 section, 3130 "CONTEXT", 3131 err.text); 3132 goto fail; 3133 } 3134 3135 { 3136 struct TALER_KYCLOGIC_Measure m; 3137 3138 m.measure_name = GNUNET_strdup (§ion[strlen ("kyc-measure-")]); 3139 m.check_name = check_name; 3140 m.prog_name = program; 3141 m.context = context; 3142 m.voluntary = voluntary; 3143 GNUNET_array_append (default_rules.custom_measures, 3144 default_rules.num_custom_measures, 3145 m); 3146 } 3147 return GNUNET_OK; 3148 fail: 3149 GNUNET_free (check_name); 3150 GNUNET_free (program); 3151 GNUNET_free (context_str); 3152 return GNUNET_SYSERR; 3153 } 3154 3155 3156 /** 3157 * Function to iterate over configuration sections. 3158 * 3159 * @param cls a `struct SectionContext *` 3160 * @param section name of the section 3161 */ 3162 static void 3163 handle_measure_section (void *cls, 3164 const char *section) 3165 { 3166 struct SectionContext *sc = cls; 3167 char *s; 3168 3169 if (! sc->result) 3170 return; 3171 s = normalize_section_with_prefix ("kyc-measure-", 3172 section); 3173 if (NULL == s) 3174 return; 3175 if (GNUNET_OK != 3176 add_measure (sc->cfg, 3177 s)) 3178 sc->result = false; 3179 GNUNET_free (s); 3180 } 3181 3182 3183 /** 3184 * Comparator for qsort. Compares two rules 3185 * by timeframe to sort rules by time. 3186 * 3187 * @param p1 first trigger to compare 3188 * @param p2 second trigger to compare 3189 * @return -1 if p1 < p2, 0 if p1==p2, 1 if p1 > p2. 3190 */ 3191 static int 3192 sort_by_timeframe (const void *p1, 3193 const void *p2) 3194 { 3195 struct TALER_KYCLOGIC_KycRule *r1 3196 = (struct TALER_KYCLOGIC_KycRule *) p1; 3197 struct TALER_KYCLOGIC_KycRule *r2 3198 = (struct TALER_KYCLOGIC_KycRule *) p2; 3199 3200 if (GNUNET_TIME_relative_cmp (r1->timeframe, 3201 <, 3202 r2->timeframe)) 3203 return -1; 3204 if (GNUNET_TIME_relative_cmp (r1->timeframe, 3205 >, 3206 r2->timeframe)) 3207 return 1; 3208 return 0; 3209 } 3210 3211 3212 enum GNUNET_GenericReturnValue 3213 TALER_KYCLOGIC_kyc_init ( 3214 const struct GNUNET_CONFIGURATION_Handle *cfg, 3215 const char *cfg_fn) 3216 { 3217 struct SectionContext sc = { 3218 .cfg = cfg, 3219 .result = true 3220 }; 3221 json_t *jkyc_rules_w; 3222 json_t *jkyc_rules_a; 3223 3224 if (NULL != cfg_fn) 3225 cfg_filename = GNUNET_strdup (cfg_fn); 3226 GNUNET_assert (GNUNET_OK == 3227 TALER_config_get_currency (cfg, 3228 "exchange", 3229 &my_currency)); 3230 GNUNET_CONFIGURATION_iterate_sections (cfg, 3231 &handle_provider_section, 3232 &sc); 3233 if (! sc.result) 3234 { 3235 TALER_KYCLOGIC_kyc_done (); 3236 return GNUNET_SYSERR; 3237 } 3238 GNUNET_CONFIGURATION_iterate_sections (cfg, 3239 &handle_check_section, 3240 &sc); 3241 if (! sc.result) 3242 { 3243 TALER_KYCLOGIC_kyc_done (); 3244 return GNUNET_SYSERR; 3245 } 3246 GNUNET_CONFIGURATION_iterate_sections (cfg, 3247 &handle_rule_section, 3248 &sc); 3249 if (! sc.result) 3250 { 3251 TALER_KYCLOGIC_kyc_done (); 3252 return GNUNET_SYSERR; 3253 } 3254 GNUNET_CONFIGURATION_iterate_sections (cfg, 3255 &handle_program_section, 3256 &sc); 3257 if (! sc.result) 3258 { 3259 TALER_KYCLOGIC_kyc_done (); 3260 return GNUNET_SYSERR; 3261 } 3262 GNUNET_CONFIGURATION_iterate_sections (cfg, 3263 &handle_measure_section, 3264 &sc); 3265 if (! sc.result) 3266 { 3267 TALER_KYCLOGIC_kyc_done (); 3268 return GNUNET_SYSERR; 3269 } 3270 3271 if (0 != default_rules.num_kyc_rules) 3272 qsort (default_rules.kyc_rules, 3273 default_rules.num_kyc_rules, 3274 sizeof (struct TALER_KYCLOGIC_KycRule), 3275 &sort_by_timeframe); 3276 jkyc_rules_w = json_array (); 3277 GNUNET_assert (NULL != jkyc_rules_w); 3278 jkyc_rules_a = json_array (); 3279 GNUNET_assert (NULL != jkyc_rules_a); 3280 3281 for (unsigned int i=0; i<default_rules.num_kyc_rules; i++) 3282 { 3283 const struct TALER_KYCLOGIC_KycRule *rule 3284 = &default_rules.kyc_rules[i]; 3285 json_t *jrule; 3286 json_t *jmeasures; 3287 3288 jmeasures = json_array (); 3289 GNUNET_assert (NULL != jmeasures); 3290 for (unsigned int j=0; j<rule->num_measures; j++) 3291 { 3292 const char *measure_name = rule->next_measures[j]; 3293 const struct TALER_KYCLOGIC_Measure *m; 3294 3295 if (0 == strcasecmp (KYC_MEASURE_IMPOSSIBLE, 3296 measure_name)) 3297 { 3298 GNUNET_assert ( 3299 0 == 3300 json_array_append_new (jmeasures, 3301 json_string (KYC_MEASURE_IMPOSSIBLE))); 3302 continue; 3303 } 3304 m = find_measure (&default_rules, 3305 measure_name); 3306 if (NULL == m) 3307 { 3308 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3309 "Unknown measure `%s' used in rule `%s'\n", 3310 measure_name, 3311 rule->rule_name); 3312 return GNUNET_SYSERR; 3313 } 3314 GNUNET_assert (0 == 3315 json_array_append_new (jmeasures, 3316 json_string (measure_name))); 3317 } 3318 jrule = GNUNET_JSON_PACK ( 3319 GNUNET_JSON_pack_allow_null ( 3320 GNUNET_JSON_pack_string ("rule_name", 3321 rule->rule_name)), 3322 TALER_JSON_pack_kycte ("operation_type", 3323 rule->trigger), 3324 TALER_JSON_pack_amount ("threshold", 3325 &rule->threshold), 3326 GNUNET_JSON_pack_time_rel ("timeframe", 3327 rule->timeframe), 3328 GNUNET_JSON_pack_array_steal ("measures", 3329 jmeasures), 3330 GNUNET_JSON_pack_uint64 ("display_priority", 3331 rule->display_priority), 3332 GNUNET_JSON_pack_bool ("exposed", 3333 rule->exposed), 3334 GNUNET_JSON_pack_bool ("is_and_combinator", 3335 rule->is_and_combinator) 3336 ); 3337 switch (rule->trigger) 3338 { 3339 case TALER_KYCLOGIC_KYC_TRIGGER_NONE: 3340 GNUNET_break (0); 3341 break; 3342 case TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW: 3343 GNUNET_assert (0 == 3344 json_array_append (jkyc_rules_a, 3345 jrule)); 3346 break; 3347 case TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT: 3348 GNUNET_assert (0 == 3349 json_array_append (jkyc_rules_a, 3350 jrule)); 3351 break; 3352 case TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE: 3353 GNUNET_assert (0 == 3354 json_array_append (jkyc_rules_w, 3355 jrule)); 3356 break; 3357 case TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE: 3358 GNUNET_assert (0 == 3359 json_array_append (jkyc_rules_w, 3360 jrule)); 3361 break; 3362 case TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE: 3363 GNUNET_assert (0 == 3364 json_array_append (jkyc_rules_a, 3365 jrule)); 3366 break; 3367 case TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE: 3368 GNUNET_assert (0 == 3369 json_array_append (jkyc_rules_a, 3370 jrule)); 3371 break; 3372 case TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION: 3373 GNUNET_assert (0 == 3374 json_array_append (jkyc_rules_a, 3375 jrule)); 3376 GNUNET_assert (0 == 3377 json_array_append (jkyc_rules_w, 3378 jrule)); 3379 break; 3380 case TALER_KYCLOGIC_KYC_TRIGGER_REFUND: 3381 GNUNET_assert (0 == 3382 json_array_append (jkyc_rules_a, 3383 jrule)); 3384 GNUNET_assert (0 == 3385 json_array_append (jkyc_rules_w, 3386 jrule)); 3387 break; 3388 } 3389 json_decref (jrule); 3390 } 3391 { 3392 json_t *empty = json_object (); 3393 3394 GNUNET_assert (NULL != empty); 3395 wallet_default_lrs 3396 = GNUNET_JSON_PACK ( 3397 GNUNET_JSON_pack_timestamp ("expiration_time", 3398 GNUNET_TIME_UNIT_FOREVER_TS), 3399 GNUNET_JSON_pack_array_steal ("rules", 3400 jkyc_rules_w), 3401 GNUNET_JSON_pack_object_incref ("custom_measures", 3402 empty) 3403 ); 3404 bankaccount_default_lrs 3405 = GNUNET_JSON_PACK ( 3406 GNUNET_JSON_pack_timestamp ("expiration_time", 3407 GNUNET_TIME_UNIT_FOREVER_TS), 3408 GNUNET_JSON_pack_array_steal ("rules", 3409 jkyc_rules_a), 3410 GNUNET_JSON_pack_object_incref ("custom_measures", 3411 empty) 3412 ); 3413 json_decref (empty); 3414 } 3415 for (unsigned int i=0; i<default_rules.num_custom_measures; i++) 3416 { 3417 const struct TALER_KYCLOGIC_Measure *measure 3418 = &default_rules.custom_measures[i]; 3419 3420 if (! check_measure (measure)) 3421 { 3422 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3423 "Configuration of AML measures incorrect. Exiting.\n"); 3424 return GNUNET_SYSERR; 3425 } 3426 } 3427 3428 for (unsigned int i=0; i<num_aml_programs; i++) 3429 { 3430 const struct TALER_KYCLOGIC_AmlProgram *program 3431 = aml_programs[i]; 3432 const struct TALER_KYCLOGIC_Measure *m; 3433 3434 m = find_measure (&default_rules, 3435 program->fallback); 3436 if (NULL == m) 3437 { 3438 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3439 "Unknown fallback measure `%s' used in program `%s'\n", 3440 program->fallback, 3441 program->program_name); 3442 return GNUNET_SYSERR; 3443 } 3444 if (0 != strcasecmp (m->check_name, 3445 "skip")) 3446 { 3447 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3448 "Fallback measure `%s' used in AML program `%s' has a check `%s' but fallbacks must have a check of type 'skip'\n", 3449 program->fallback, 3450 program->program_name, 3451 m->check_name); 3452 return GNUNET_SYSERR; 3453 } 3454 if (NULL != m->prog_name) 3455 { 3456 const struct TALER_KYCLOGIC_AmlProgram *fprogram; 3457 3458 fprogram = find_program (m->prog_name); 3459 GNUNET_assert (NULL != fprogram); 3460 if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES))) 3461 { 3462 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3463 "Fallback program %s of fallback measure `%s' used in AML program `%s' has required inputs, but fallback measures must not require any inputs\n", 3464 m->prog_name, 3465 program->program_name, 3466 m->check_name); 3467 return GNUNET_SYSERR; 3468 } 3469 } 3470 } 3471 3472 for (unsigned int i = 0; i<num_kyc_checks; i++) 3473 { 3474 struct TALER_KYCLOGIC_KycCheck *kyc_check 3475 = kyc_checks[i]; 3476 const struct TALER_KYCLOGIC_Measure *measure; 3477 3478 measure = find_measure (&default_rules, 3479 kyc_check->fallback); 3480 if (NULL == measure) 3481 { 3482 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3483 "Unknown fallback measure `%s' used in check `%s'\n", 3484 kyc_check->fallback, 3485 kyc_check->check_name); 3486 return GNUNET_SYSERR; 3487 } 3488 if (0 != strcasecmp (measure->check_name, 3489 "skip")) 3490 { 3491 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3492 "Fallback measure `%s' used in KYC check `%s' has a check `%s' but fallbacks must have a check of type 'skip'\n", 3493 kyc_check->fallback, 3494 kyc_check->check_name, 3495 measure->check_name); 3496 return GNUNET_SYSERR; 3497 } 3498 if (NULL != measure->prog_name) 3499 { 3500 const struct TALER_KYCLOGIC_AmlProgram *fprogram; 3501 3502 fprogram = find_program (measure->prog_name); 3503 GNUNET_assert (NULL != fprogram); 3504 if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES))) 3505 { 3506 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3507 "AML program `%s' used fallback measure `%s' of KYC check `%s' has required inputs, but fallback measures must not require any inputs\n", 3508 measure->prog_name, 3509 kyc_check->fallback, 3510 kyc_check->check_name); 3511 return GNUNET_SYSERR; 3512 } 3513 } 3514 } 3515 3516 return GNUNET_OK; 3517 } 3518 3519 3520 void 3521 TALER_KYCLOGIC_kyc_done (void) 3522 { 3523 free_rules (&default_rules); 3524 memset (&default_rules, 3525 0, 3526 sizeof (default_rules)); 3527 for (unsigned int i = 0; i<num_kyc_providers; i++) 3528 { 3529 struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i]; 3530 3531 kp->logic->unload_configuration (kp->pd); 3532 GNUNET_free (kp->provider_name); 3533 GNUNET_free (kp); 3534 } 3535 GNUNET_array_grow (kyc_providers, 3536 num_kyc_providers, 3537 0); 3538 for (unsigned int i = 0; i<num_kyc_logics; i++) 3539 { 3540 struct TALER_KYCLOGIC_Plugin *lp = kyc_logics[i]; 3541 char *lib_name = lp->library_name; 3542 3543 GNUNET_free (lp->name); 3544 GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name, 3545 lp)); 3546 GNUNET_free (lib_name); 3547 } 3548 GNUNET_array_grow (kyc_logics, 3549 num_kyc_logics, 3550 0); 3551 for (unsigned int i = 0; i<num_kyc_checks; i++) 3552 { 3553 struct TALER_KYCLOGIC_KycCheck *kc = kyc_checks[i]; 3554 3555 GNUNET_free (kc->check_name); 3556 GNUNET_free (kc->description); 3557 json_decref (kc->description_i18n); 3558 for (unsigned int j = 0; j<kc->num_requires; j++) 3559 GNUNET_free (kc->requires[j]); 3560 GNUNET_array_grow (kc->requires, 3561 kc->num_requires, 3562 0); 3563 GNUNET_free (kc->fallback); 3564 for (unsigned int j = 0; j<kc->num_outputs; j++) 3565 GNUNET_free (kc->outputs[j]); 3566 GNUNET_array_grow (kc->outputs, 3567 kc->num_outputs, 3568 0); 3569 switch (kc->type) 3570 { 3571 case TALER_KYCLOGIC_CT_INFO: 3572 break; 3573 case TALER_KYCLOGIC_CT_FORM: 3574 GNUNET_free (kc->details.form.name); 3575 break; 3576 case TALER_KYCLOGIC_CT_LINK: 3577 break; 3578 } 3579 GNUNET_free (kc); 3580 } 3581 GNUNET_array_grow (kyc_checks, 3582 num_kyc_checks, 3583 0); 3584 for (unsigned int i = 0; i<num_aml_programs; i++) 3585 { 3586 struct TALER_KYCLOGIC_AmlProgram *ap = aml_programs[i]; 3587 3588 GNUNET_free (ap->program_name); 3589 GNUNET_free (ap->command); 3590 GNUNET_free (ap->description); 3591 GNUNET_free (ap->fallback); 3592 for (unsigned int j = 0; j<ap->num_required_contexts; j++) 3593 GNUNET_free (ap->required_contexts[j]); 3594 GNUNET_array_grow (ap->required_contexts, 3595 ap->num_required_contexts, 3596 0); 3597 for (unsigned int j = 0; j<ap->num_required_attributes; j++) 3598 GNUNET_free (ap->required_attributes[j]); 3599 GNUNET_array_grow (ap->required_attributes, 3600 ap->num_required_attributes, 3601 0); 3602 GNUNET_free (ap); 3603 } 3604 GNUNET_array_grow (aml_programs, 3605 num_aml_programs, 3606 0); 3607 GNUNET_free (cfg_filename); 3608 } 3609 3610 3611 void 3612 TALER_KYCLOGIC_provider_to_logic ( 3613 const struct TALER_KYCLOGIC_KycProvider *provider, 3614 struct TALER_KYCLOGIC_Plugin **plugin, 3615 struct TALER_KYCLOGIC_ProviderDetails **pd, 3616 const char **provider_name) 3617 { 3618 *plugin = provider->logic; 3619 *pd = provider->pd; 3620 *provider_name = provider->provider_name; 3621 } 3622 3623 3624 enum GNUNET_GenericReturnValue 3625 TALER_KYCLOGIC_get_original_measure ( 3626 const char *measure_name, 3627 struct TALER_KYCLOGIC_KycCheckContext *kcc) 3628 { 3629 const struct TALER_KYCLOGIC_Measure *measure; 3630 3631 measure = find_measure (&default_rules, 3632 measure_name); 3633 if (NULL == measure) 3634 { 3635 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3636 "Default measure `%s' unknown\n", 3637 measure_name); 3638 return GNUNET_SYSERR; 3639 } 3640 if (0 == strcasecmp (measure->check_name, 3641 "skip")) 3642 { 3643 kcc->check = NULL; 3644 kcc->prog_name = measure->prog_name; 3645 kcc->context = measure->context; 3646 return GNUNET_OK; 3647 } 3648 3649 for (unsigned int i = 0; i<num_kyc_checks; i++) 3650 if (0 == strcasecmp (measure->check_name, 3651 kyc_checks[i]->check_name)) 3652 { 3653 kcc->check = kyc_checks[i]; 3654 kcc->prog_name = measure->prog_name; 3655 kcc->context = measure->context; 3656 return GNUNET_OK; 3657 } 3658 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3659 "Check `%s' unknown (but required by measure `%s')\n", 3660 measure->check_name, 3661 measure_name); 3662 return GNUNET_SYSERR; 3663 } 3664 3665 3666 enum GNUNET_GenericReturnValue 3667 TALER_KYCLOGIC_requirements_to_check ( 3668 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs, 3669 const struct TALER_KYCLOGIC_KycRule *kyc_rule, 3670 const char *measure_name, 3671 struct TALER_KYCLOGIC_KycCheckContext *kcc) 3672 { 3673 bool found = false; 3674 const struct TALER_KYCLOGIC_Measure *measure = NULL; 3675 3676 if (NULL == lrs) 3677 lrs = &default_rules; 3678 if (NULL == measure_name) 3679 { 3680 GNUNET_break (0); 3681 return GNUNET_SYSERR; 3682 } 3683 if (NULL != kyc_rule) 3684 { 3685 if (kyc_rule->verboten) 3686 { 3687 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3688 "Rule says operation is categorically is verboten, cannot take measures\n"); 3689 return GNUNET_SYSERR; 3690 } 3691 for (unsigned int i = 0; i<kyc_rule->num_measures; i++) 3692 { 3693 if (0 != strcasecmp (measure_name, 3694 kyc_rule->next_measures[i])) 3695 continue; 3696 found = true; 3697 break; 3698 } 3699 if (! found) 3700 { 3701 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3702 "Measure `%s' not allowed for rule `%s'\n", 3703 measure_name, 3704 kyc_rule->rule_name); 3705 return GNUNET_SYSERR; 3706 } 3707 } 3708 measure = find_measure (lrs, 3709 measure_name); 3710 if (NULL == measure) 3711 { 3712 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3713 "Measure `%s' unknown (but allowed by rule `%s')\n", 3714 measure_name, 3715 NULL != kyc_rule 3716 ? kyc_rule->rule_name 3717 : "<NONE>"); 3718 return GNUNET_SYSERR; 3719 } 3720 3721 if (0 == strcasecmp (measure->check_name, 3722 "skip")) 3723 { 3724 kcc->check = NULL; 3725 kcc->prog_name = measure->prog_name; 3726 kcc->context = measure->context; 3727 return GNUNET_OK; 3728 } 3729 3730 for (unsigned int i = 0; i<num_kyc_checks; i++) 3731 if (0 == strcasecmp (measure->check_name, 3732 kyc_checks[i]->check_name)) 3733 { 3734 kcc->check = kyc_checks[i]; 3735 kcc->prog_name = measure->prog_name; 3736 kcc->context = measure->context; 3737 return GNUNET_OK; 3738 } 3739 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3740 "Check `%s' unknown (but required by measure `%s')\n", 3741 measure->check_name, 3742 measure_name); 3743 return GNUNET_SYSERR; 3744 } 3745 3746 3747 enum GNUNET_GenericReturnValue 3748 TALER_KYCLOGIC_lookup_logic ( 3749 const char *name, 3750 struct TALER_KYCLOGIC_Plugin **plugin, 3751 struct TALER_KYCLOGIC_ProviderDetails **pd, 3752 const char **provider_name) 3753 { 3754 for (unsigned int i = 0; i<num_kyc_providers; i++) 3755 { 3756 struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i]; 3757 3758 if (0 != 3759 strcasecmp (name, 3760 kp->provider_name)) 3761 continue; 3762 *plugin = kp->logic; 3763 *pd = kp->pd; 3764 *provider_name = kp->provider_name; 3765 return GNUNET_OK; 3766 } 3767 for (unsigned int i = 0; i<num_kyc_logics; i++) 3768 { 3769 struct TALER_KYCLOGIC_Plugin *logic = kyc_logics[i]; 3770 3771 if (0 != 3772 strcasecmp (logic->name, 3773 name)) 3774 continue; 3775 *plugin = logic; 3776 *pd = NULL; 3777 *provider_name = NULL; 3778 return GNUNET_OK; 3779 } 3780 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3781 "Provider `%s' unknown\n", 3782 name); 3783 return GNUNET_SYSERR; 3784 } 3785 3786 3787 void 3788 TALER_KYCLOGIC_kyc_get_details ( 3789 const char *logic_name, 3790 TALER_KYCLOGIC_DetailsCallback cb, 3791 void *cb_cls) 3792 { 3793 for (unsigned int i = 0; i<num_kyc_providers; i++) 3794 { 3795 struct TALER_KYCLOGIC_KycProvider *kp 3796 = kyc_providers[i]; 3797 3798 if (0 != 3799 strcasecmp (kp->logic->name, 3800 logic_name)) 3801 continue; 3802 if (GNUNET_OK != 3803 cb (cb_cls, 3804 kp->pd, 3805 kp->logic->cls)) 3806 return; 3807 } 3808 } 3809 3810 3811 /** 3812 * Closure for check_amount(). 3813 */ 3814 struct KycTestContext 3815 { 3816 /** 3817 * Rule set we apply. 3818 */ 3819 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs; 3820 3821 /** 3822 * Events we care about. 3823 */ 3824 enum TALER_KYCLOGIC_KycTriggerEvent event; 3825 3826 /** 3827 * Total amount encountered so far, invalid if zero. 3828 */ 3829 struct TALER_Amount sum; 3830 3831 /** 3832 * Set to the triggered rule. 3833 */ 3834 const struct TALER_KYCLOGIC_KycRule *triggered_rule; 3835 3836 }; 3837 3838 3839 /** 3840 * Function called on each @a amount that was found to 3841 * be relevant for a KYC check. Evaluates the given 3842 * @a amount and @a date against all the applicable 3843 * rules in the legitimization rule set. 3844 * 3845 * @param cls our `struct KycTestContext *` 3846 * @param amount encountered transaction amount 3847 * @param date when was the amount encountered 3848 * @return #GNUNET_OK to continue to iterate, 3849 * #GNUNET_NO to abort iteration, 3850 * #GNUNET_SYSERR on internal error (also abort itaration) 3851 */ 3852 static enum GNUNET_GenericReturnValue 3853 check_amount ( 3854 void *cls, 3855 const struct TALER_Amount *amount, 3856 struct GNUNET_TIME_Absolute date) 3857 { 3858 struct KycTestContext *ktc = cls; 3859 struct GNUNET_TIME_Relative dur; 3860 3861 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3862 "KYC checking transaction amount %s from %s against %u rules\n", 3863 TALER_amount2s (amount), 3864 GNUNET_TIME_absolute2s (date), 3865 ktc->lrs->num_kyc_rules); 3866 dur = GNUNET_TIME_absolute_get_duration (date); 3867 if (GNUNET_OK != 3868 TALER_amount_is_valid (&ktc->sum)) 3869 ktc->sum = *amount; 3870 else 3871 GNUNET_assert (0 <= 3872 TALER_amount_add (&ktc->sum, 3873 &ktc->sum, 3874 amount)); 3875 for (unsigned int i=0; i<ktc->lrs->num_kyc_rules; i++) 3876 { 3877 const struct TALER_KYCLOGIC_KycRule *rule 3878 = &ktc->lrs->kyc_rules[i]; 3879 3880 if (ktc->event != rule->trigger) 3881 { 3882 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3883 "Wrong event type (%d) for rule %u (%d)\n", 3884 (int) ktc->event, 3885 i, 3886 (int) rule->trigger); 3887 continue; /* wrong trigger event type */ 3888 } 3889 if (GNUNET_TIME_relative_cmp (dur, 3890 >, 3891 rule->timeframe)) 3892 { 3893 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3894 "Out of time range for rule %u\n", 3895 i); 3896 continue; /* out of time range for rule */ 3897 } 3898 if (-1 == TALER_amount_cmp (&ktc->sum, 3899 &rule->threshold)) 3900 { 3901 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3902 "Below threshold of %s for rule %u\n", 3903 TALER_amount2s (&rule->threshold), 3904 i); 3905 continue; /* sum < threshold */ 3906 } 3907 if ( (NULL != ktc->triggered_rule) && 3908 (1 == TALER_amount_cmp (&ktc->triggered_rule->threshold, 3909 &rule->threshold)) ) 3910 { 3911 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3912 "Higher than threshold of already triggered rule\n"); 3913 continue; /* threshold of triggered_rule > rule */ 3914 } 3915 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3916 "Remembering rule %s as triggered\n", 3917 rule->rule_name); 3918 ktc->triggered_rule = rule; 3919 } 3920 return GNUNET_OK; 3921 } 3922 3923 3924 enum GNUNET_DB_QueryStatus 3925 TALER_KYCLOGIC_kyc_test_required ( 3926 enum TALER_KYCLOGIC_KycTriggerEvent event, 3927 const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs, 3928 TALER_KYCLOGIC_KycAmountIterator ai, 3929 void *ai_cls, 3930 const struct TALER_KYCLOGIC_KycRule **triggered_rule, 3931 struct TALER_Amount *next_threshold) 3932 { 3933 struct GNUNET_TIME_Relative range 3934 = GNUNET_TIME_UNIT_ZERO; 3935 enum GNUNET_DB_QueryStatus qs; 3936 bool have_threshold = false; 3937 3938 memset (next_threshold, 3939 0, 3940 sizeof (struct TALER_Amount)); 3941 if (NULL == lrs) 3942 lrs = &default_rules; 3943 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3944 "Testing %u KYC rules for trigger %d\n", 3945 lrs->num_kyc_rules, 3946 event); 3947 for (unsigned int i=0; i<lrs->num_kyc_rules; i++) 3948 { 3949 const struct TALER_KYCLOGIC_KycRule *rule 3950 = &lrs->kyc_rules[i]; 3951 3952 if (event != rule->trigger) 3953 { 3954 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3955 "Rule %u is for a different trigger (%d/%d)\n", 3956 i, 3957 (int) event, 3958 (int) rule->trigger); 3959 continue; 3960 } 3961 if (have_threshold) 3962 { 3963 GNUNET_assert (GNUNET_OK == 3964 TALER_amount_min (next_threshold, 3965 next_threshold, 3966 &rule->threshold)); 3967 } 3968 else 3969 { 3970 *next_threshold = rule->threshold; 3971 have_threshold = true; 3972 } 3973 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3974 "Matched rule %u with timeframe %s and threshold %s\n", 3975 i, 3976 GNUNET_TIME_relative2s (rule->timeframe, 3977 true), 3978 TALER_amount2s (&rule->threshold)); 3979 range = GNUNET_TIME_relative_max (range, 3980 rule->timeframe); 3981 } 3982 3983 if (! have_threshold) 3984 { 3985 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3986 "No rules apply\n"); 3987 *triggered_rule = NULL; 3988 return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; 3989 } 3990 3991 { 3992 struct GNUNET_TIME_Absolute now 3993 = GNUNET_TIME_absolute_get (); 3994 struct KycTestContext ktc = { 3995 .lrs = lrs, 3996 .event = event 3997 }; 3998 3999 qs = ai (ai_cls, 4000 GNUNET_TIME_absolute_subtract (now, 4001 range), 4002 &check_amount, 4003 &ktc); 4004 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4005 "Triggered rule is %s\n", 4006 (NULL == ktc.triggered_rule) 4007 ? "NONE" 4008 : ktc.triggered_rule->rule_name); 4009 *triggered_rule = ktc.triggered_rule; 4010 } 4011 return qs; 4012 } 4013 4014 4015 json_t * 4016 TALER_KYCLOGIC_measure_to_requirement ( 4017 const char *check_name, 4018 const json_t *context, 4019 const struct TALER_AccountAccessTokenP *access_token, 4020 size_t offset, 4021 uint64_t legitimization_measure_row_id) 4022 { 4023 struct TALER_KYCLOGIC_KycCheck *kc; 4024 json_t *kri; 4025 struct TALER_KycMeasureAuthorizationHashP shv; 4026 char *ids; 4027 char *xids; 4028 4029 kc = find_check (check_name); 4030 if (NULL == kc) 4031 { 4032 GNUNET_break (0); 4033 return NULL; 4034 } 4035 GNUNET_assert (offset <= UINT32_MAX); 4036 TALER_kyc_measure_authorization_hash (access_token, 4037 legitimization_measure_row_id, 4038 (uint32_t) offset, 4039 &shv); 4040 switch (kc->type) 4041 { 4042 case TALER_KYCLOGIC_CT_INFO: 4043 return GNUNET_JSON_PACK ( 4044 GNUNET_JSON_pack_string ("form", 4045 "INFO"), 4046 GNUNET_JSON_pack_string ("description", 4047 kc->description), 4048 GNUNET_JSON_pack_allow_null ( 4049 GNUNET_JSON_pack_object_incref ("description_i18n", 4050 (json_t *) kc->description_i18n))); 4051 case TALER_KYCLOGIC_CT_FORM: 4052 GNUNET_assert (offset <= UINT_MAX); 4053 ids = GNUNET_STRINGS_data_to_string_alloc (&shv, 4054 sizeof (shv)); 4055 GNUNET_asprintf (&xids, 4056 "%s-%u-%llu", 4057 ids, 4058 (unsigned int) offset, 4059 (unsigned long long) legitimization_measure_row_id); 4060 GNUNET_free (ids); 4061 kri = GNUNET_JSON_PACK ( 4062 GNUNET_JSON_pack_string ("form", 4063 kc->details.form.name), 4064 GNUNET_JSON_pack_string ("id", 4065 xids), 4066 GNUNET_JSON_pack_allow_null ( 4067 GNUNET_JSON_pack_object_incref ("context", 4068 (json_t *) context)), 4069 GNUNET_JSON_pack_string ("description", 4070 kc->description), 4071 GNUNET_JSON_pack_allow_null ( 4072 GNUNET_JSON_pack_object_incref ("description_i18n", 4073 (json_t *) kc->description_i18n))); 4074 GNUNET_free (xids); 4075 return kri; 4076 case TALER_KYCLOGIC_CT_LINK: 4077 GNUNET_assert (offset <= UINT_MAX); 4078 ids = GNUNET_STRINGS_data_to_string_alloc (&shv, 4079 sizeof (shv)); 4080 GNUNET_asprintf (&xids, 4081 "%s-%u-%llu", 4082 ids, 4083 (unsigned int) offset, 4084 (unsigned long long) legitimization_measure_row_id); 4085 GNUNET_free (ids); 4086 kri = GNUNET_JSON_PACK ( 4087 GNUNET_JSON_pack_string ("form", 4088 "LINK"), 4089 GNUNET_JSON_pack_string ("id", 4090 xids), 4091 GNUNET_JSON_pack_string ("description", 4092 kc->description), 4093 GNUNET_JSON_pack_allow_null ( 4094 GNUNET_JSON_pack_object_incref ("description_i18n", 4095 (json_t *) kc->description_i18n))); 4096 GNUNET_free (xids); 4097 return kri; 4098 } 4099 GNUNET_break (0); /* invalid type */ 4100 return NULL; 4101 } 4102 4103 4104 void 4105 TALER_KYCLOGIC_get_measure_configuration ( 4106 json_t **proots, 4107 json_t **pprograms, 4108 json_t **pchecks, 4109 json_t **pdefault_rules) 4110 { 4111 json_t *roots; 4112 json_t *programs; 4113 json_t *checks; 4114 json_t *drules; 4115 4116 roots = json_object (); 4117 GNUNET_assert (NULL != roots); 4118 for (unsigned int i = 0; i<default_rules.num_custom_measures; i++) 4119 { 4120 const struct TALER_KYCLOGIC_Measure *m 4121 = &default_rules.custom_measures[i]; 4122 json_t *jm; 4123 4124 jm = GNUNET_JSON_PACK ( 4125 GNUNET_JSON_pack_string ("check_name", 4126 m->check_name), 4127 GNUNET_JSON_pack_allow_null ( 4128 GNUNET_JSON_pack_string ("prog_name", 4129 m->prog_name)), 4130 GNUNET_JSON_pack_allow_null ( 4131 GNUNET_JSON_pack_object_incref ("context", 4132 m->context))); 4133 GNUNET_assert (0 == 4134 json_object_set_new (roots, 4135 m->measure_name, 4136 jm)); 4137 } 4138 4139 programs = json_object (); 4140 GNUNET_assert (NULL != programs); 4141 for (unsigned int i = 0; i<num_aml_programs; i++) 4142 { 4143 const struct TALER_KYCLOGIC_AmlProgram *ap 4144 = aml_programs[i]; 4145 json_t *jp; 4146 json_t *ctx; 4147 json_t *inp; 4148 4149 ctx = json_array (); 4150 GNUNET_assert (NULL != ctx); 4151 for (unsigned int j = 0; j<ap->num_required_contexts; j++) 4152 { 4153 const char *rc = ap->required_contexts[j]; 4154 4155 GNUNET_assert (0 == 4156 json_array_append_new (ctx, 4157 json_string (rc))); 4158 } 4159 inp = json_array (); 4160 GNUNET_assert (NULL != inp); 4161 for (unsigned int j = 0; j<ap->num_required_attributes; j++) 4162 { 4163 const char *ra = ap->required_attributes[j]; 4164 4165 GNUNET_assert (0 == 4166 json_array_append_new (inp, 4167 json_string (ra))); 4168 } 4169 4170 jp = GNUNET_JSON_PACK ( 4171 GNUNET_JSON_pack_string ("description", 4172 ap->description), 4173 GNUNET_JSON_pack_array_steal ("context", 4174 ctx), 4175 GNUNET_JSON_pack_array_steal ("inputs", 4176 inp)); 4177 GNUNET_assert (0 == 4178 json_object_set_new (programs, 4179 ap->program_name, 4180 jp)); 4181 } 4182 4183 checks = json_object (); 4184 GNUNET_assert (NULL != checks); 4185 for (unsigned int i = 0; i<num_kyc_checks; i++) 4186 { 4187 const struct TALER_KYCLOGIC_KycCheck *ck 4188 = kyc_checks[i]; 4189 json_t *jc; 4190 json_t *requires; 4191 json_t *outputs; 4192 4193 requires = json_array (); 4194 GNUNET_assert (NULL != requires); 4195 for (unsigned int j = 0; j<ck->num_requires; j++) 4196 { 4197 const char *ra = ck->requires[j]; 4198 4199 GNUNET_assert (0 == 4200 json_array_append_new (requires, 4201 json_string (ra))); 4202 } 4203 outputs = json_array (); 4204 GNUNET_assert (NULL != outputs); 4205 for (unsigned int j = 0; j<ck->num_outputs; j++) 4206 { 4207 const char *out = ck->outputs[j]; 4208 4209 GNUNET_assert (0 == 4210 json_array_append_new (outputs, 4211 json_string (out))); 4212 } 4213 4214 jc = GNUNET_JSON_PACK ( 4215 GNUNET_JSON_pack_string ("description", 4216 ck->description), 4217 GNUNET_JSON_pack_allow_null ( 4218 GNUNET_JSON_pack_object_incref ("description_i18n", 4219 ck->description_i18n)), 4220 GNUNET_JSON_pack_array_steal ("requires", 4221 requires), 4222 GNUNET_JSON_pack_array_steal ("outputs", 4223 outputs), 4224 GNUNET_JSON_pack_string ("fallback", 4225 ck->fallback)); 4226 GNUNET_assert (0 == 4227 json_object_set_new (checks, 4228 ck->check_name, 4229 jc)); 4230 } 4231 drules = json_array (); 4232 GNUNET_assert (NULL != drules); 4233 { 4234 const struct TALER_KYCLOGIC_KycRule *rules 4235 = default_rules.kyc_rules; 4236 unsigned int num_rules 4237 = default_rules.num_kyc_rules; 4238 4239 for (unsigned int i = 0; i<num_rules; i++) 4240 { 4241 const struct TALER_KYCLOGIC_KycRule *rule = &rules[i]; 4242 json_t *measures; 4243 json_t *limit; 4244 4245 measures = json_array (); 4246 GNUNET_assert (NULL != measures); 4247 for (unsigned int j = 0; j<rule->num_measures; j++) 4248 GNUNET_assert ( 4249 0 == 4250 json_array_append_new (measures, 4251 json_string ( 4252 rule->next_measures[j]))); 4253 limit = GNUNET_JSON_PACK ( 4254 GNUNET_JSON_pack_allow_null ( 4255 GNUNET_JSON_pack_string ("rule_name", 4256 rule->rule_name)), 4257 TALER_JSON_pack_kycte ("operation_type", 4258 rule->trigger), 4259 TALER_JSON_pack_amount ("threshold", 4260 &rule->threshold), 4261 GNUNET_JSON_pack_time_rel ("timeframe", 4262 rule->timeframe), 4263 GNUNET_JSON_pack_array_steal ("measures", 4264 measures), 4265 GNUNET_JSON_pack_uint64 ("display_priority", 4266 rule->display_priority), 4267 GNUNET_JSON_pack_bool ("soft_limit", 4268 ! rule->verboten), 4269 GNUNET_JSON_pack_bool ("exposed", 4270 rule->exposed), 4271 GNUNET_JSON_pack_bool ("is_and_combinator", 4272 rule->is_and_combinator) 4273 ); 4274 GNUNET_assert (0 == 4275 json_array_append_new (drules, 4276 limit)); 4277 } 4278 } 4279 4280 *proots = roots; 4281 *pprograms = programs; 4282 *pchecks = checks; 4283 *pdefault_rules = drules; 4284 } 4285 4286 4287 enum TALER_ErrorCode 4288 TALER_KYCLOGIC_select_measure ( 4289 const json_t *jmeasures, 4290 size_t measure_index, 4291 const char **check_name, 4292 const char **prog_name, 4293 const json_t **context) 4294 { 4295 const json_t *jmeasure_arr; 4296 struct GNUNET_JSON_Specification spec[] = { 4297 GNUNET_JSON_spec_array_const ("measures", 4298 &jmeasure_arr), 4299 GNUNET_JSON_spec_end () 4300 }; 4301 const json_t *jmeasure; 4302 struct GNUNET_JSON_Specification ispec[] = { 4303 GNUNET_JSON_spec_string ("check_name", 4304 check_name), 4305 GNUNET_JSON_spec_mark_optional ( 4306 GNUNET_JSON_spec_string ("prog_name", 4307 prog_name), 4308 NULL), 4309 GNUNET_JSON_spec_mark_optional ( 4310 GNUNET_JSON_spec_object_const ("context", 4311 context), 4312 NULL), 4313 GNUNET_JSON_spec_end () 4314 }; 4315 4316 *check_name = NULL; 4317 *prog_name = NULL; 4318 *context = NULL; 4319 if (GNUNET_OK != 4320 GNUNET_JSON_parse (jmeasures, 4321 spec, 4322 NULL, NULL)) 4323 { 4324 GNUNET_break (0); 4325 return TALER_EC_EXCHANGE_KYC_MEASURES_MALFORMED; 4326 } 4327 if (measure_index >= json_array_size (jmeasure_arr)) 4328 { 4329 GNUNET_break_op (0); 4330 return TALER_EC_EXCHANGE_KYC_MEASURE_INDEX_INVALID; 4331 } 4332 jmeasure = json_array_get (jmeasure_arr, 4333 measure_index); 4334 if (GNUNET_OK != 4335 GNUNET_JSON_parse (jmeasure, 4336 ispec, 4337 NULL, NULL)) 4338 { 4339 GNUNET_break (0); 4340 return TALER_EC_EXCHANGE_KYC_MEASURES_MALFORMED; 4341 } 4342 return TALER_EC_NONE; 4343 } 4344 4345 4346 enum TALER_ErrorCode 4347 TALER_KYCLOGIC_check_form ( 4348 const json_t *jmeasures, 4349 size_t measure_index, 4350 const json_t *form_data, 4351 char **form_name, 4352 const char **error_message) 4353 { 4354 const char *check_name; 4355 const char *prog_name; 4356 const json_t *context; 4357 struct TALER_KYCLOGIC_KycCheck *kc; 4358 struct TALER_KYCLOGIC_AmlProgram *prog; 4359 4360 *error_message = NULL; 4361 *form_name = NULL; 4362 if (TALER_EC_NONE != 4363 TALER_KYCLOGIC_select_measure (jmeasures, 4364 measure_index, 4365 &check_name, 4366 &prog_name, 4367 &context)) 4368 { 4369 GNUNET_break_op (0); 4370 return TALER_EC_EXCHANGE_KYC_MEASURE_INDEX_INVALID; 4371 } 4372 kc = find_check (check_name); 4373 if (NULL == kc) 4374 { 4375 GNUNET_break (0); 4376 *error_message = check_name; 4377 return TALER_EC_EXCHANGE_KYC_GENERIC_CHECK_GONE; 4378 } 4379 if (TALER_KYCLOGIC_CT_FORM != kc->type) 4380 { 4381 GNUNET_break_op (0); 4382 return TALER_EC_EXCHANGE_KYC_NOT_A_FORM; 4383 } 4384 if (NULL == prog_name) 4385 { 4386 /* non-INFO checks must have an AML program */ 4387 GNUNET_break (0); 4388 return TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_BUG; 4389 } 4390 for (unsigned int i = 0; i<kc->num_outputs; i++) 4391 { 4392 const char *rattr = kc->outputs[i]; 4393 4394 if (NULL == json_object_get (form_data, 4395 rattr)) 4396 { 4397 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4398 "Form data lacks required attribute `%s' for KYC check `%s'\n", 4399 rattr, 4400 check_name); 4401 *error_message = rattr; 4402 return TALER_EC_EXCHANGE_KYC_AML_FORM_INCOMPLETE; 4403 } 4404 } 4405 prog = find_program (prog_name); 4406 if (NULL == prog) 4407 { 4408 GNUNET_break (0); 4409 *error_message = prog_name; 4410 return TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_GONE; 4411 } 4412 for (unsigned int i = 0; i<prog->num_required_attributes; i++) 4413 { 4414 const char *rattr = prog->required_attributes[i]; 4415 4416 if (NULL == json_object_get (form_data, 4417 rattr)) 4418 { 4419 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4420 "Form data lacks required attribute `%s' for AML program %s\n", 4421 rattr, 4422 prog_name); 4423 *error_message = rattr; 4424 return TALER_EC_EXCHANGE_KYC_AML_FORM_INCOMPLETE; 4425 } 4426 } 4427 *form_name = GNUNET_strdup (kc->details.form.name); 4428 return TALER_EC_NONE; 4429 } 4430 4431 4432 const char * 4433 TALER_KYCLOGIC_get_aml_program_fallback (const char *prog_name) 4434 { 4435 struct TALER_KYCLOGIC_AmlProgram *prog; 4436 4437 prog = find_program (prog_name); 4438 if (NULL == prog) 4439 { 4440 GNUNET_break (0); 4441 return NULL; 4442 } 4443 return prog->fallback; 4444 } 4445 4446 4447 const struct TALER_KYCLOGIC_KycProvider * 4448 TALER_KYCLOGIC_check_to_provider (const char *check_name) 4449 { 4450 struct TALER_KYCLOGIC_KycCheck *kc; 4451 4452 if (NULL == check_name) 4453 return NULL; 4454 if (0 == strcasecmp (check_name, 4455 "skip")) 4456 return NULL; 4457 kc = find_check (check_name); 4458 if (NULL == kc) 4459 { 4460 GNUNET_break (0); 4461 return NULL; 4462 } 4463 switch (kc->type) 4464 { 4465 case TALER_KYCLOGIC_CT_FORM: 4466 case TALER_KYCLOGIC_CT_INFO: 4467 return NULL; 4468 case TALER_KYCLOGIC_CT_LINK: 4469 break; 4470 } 4471 return kc->details.link.provider; 4472 } 4473 4474 4475 struct TALER_KYCLOGIC_AmlProgramRunnerHandle 4476 { 4477 /** 4478 * Function to call back with the result. 4479 */ 4480 TALER_KYCLOGIC_AmlProgramResultCallback aprc; 4481 4482 /** 4483 * Closure for @e aprc. 4484 */ 4485 void *aprc_cls; 4486 4487 /** 4488 * Handle to an external process. 4489 */ 4490 struct TALER_JSON_ExternalConversion *proc; 4491 4492 /** 4493 * AML program to turn. 4494 */ 4495 const struct TALER_KYCLOGIC_AmlProgram *program; 4496 4497 /** 4498 * Task to return @e apr result asynchronously. 4499 */ 4500 struct GNUNET_SCHEDULER_Task *async_cb; 4501 4502 /** 4503 * Result returned to the client. 4504 */ 4505 struct TALER_KYCLOGIC_AmlProgramResult apr; 4506 4507 /** 4508 * How long do we allow the AML program to run? 4509 */ 4510 struct GNUNET_TIME_Relative timeout; 4511 4512 }; 4513 4514 4515 /** 4516 * Function that that receives a JSON @a result from 4517 * the AML program. 4518 * 4519 * @param cls closure of type `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` 4520 * @param status_type how did the process die 4521 * @param code termination status code from the process, 4522 * non-zero if AML checks are required next 4523 * @param result some JSON result, NULL if we failed to get an JSON output 4524 */ 4525 static void 4526 handle_aml_output ( 4527 void *cls, 4528 enum GNUNET_OS_ProcessStatusType status_type, 4529 unsigned long code, 4530 const json_t *result) 4531 { 4532 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls; 4533 const char *fallback_measure = aprh->program->fallback; 4534 struct TALER_KYCLOGIC_AmlProgramResult *apr = &aprh->apr; 4535 const char **evs = NULL; 4536 4537 aprh->proc = NULL; 4538 if (NULL != aprh->async_cb) 4539 { 4540 GNUNET_SCHEDULER_cancel (aprh->async_cb); 4541 aprh->async_cb = NULL; 4542 } 4543 #if DEBUG 4544 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4545 "AML program %s output is:\n", 4546 aprh->program->program_name); 4547 json_dumpf (result, 4548 stderr, 4549 JSON_INDENT (2)); 4550 #endif 4551 memset (apr, 4552 0, 4553 sizeof (*apr)); 4554 if ( (GNUNET_OS_PROCESS_EXITED != status_type) || 4555 (0 != code) ) 4556 { 4557 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 4558 "AML program %s returned non-zero status %d/%d\n", 4559 aprh->program->program_name, 4560 (int) status_type, 4561 (int) code); 4562 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4563 apr->details.failure.fallback_measure 4564 = fallback_measure; 4565 apr->details.failure.error_message 4566 = "AML program returned non-zero exit code"; 4567 apr->details.failure.ec 4568 = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_FAILURE; 4569 goto ready; 4570 } 4571 4572 { 4573 const json_t *jevents = NULL; 4574 struct GNUNET_JSON_Specification spec[] = { 4575 GNUNET_JSON_spec_mark_optional ( 4576 GNUNET_JSON_spec_bool ( 4577 "to_investigate", 4578 &apr->details.success.to_investigate), 4579 NULL), 4580 GNUNET_JSON_spec_mark_optional ( 4581 GNUNET_JSON_spec_object_const ( 4582 "properties", 4583 &apr->details.success.account_properties), 4584 NULL), 4585 GNUNET_JSON_spec_mark_optional ( 4586 GNUNET_JSON_spec_array_const ( 4587 "events", 4588 &jevents), 4589 NULL), 4590 GNUNET_JSON_spec_object_const ( 4591 "new_rules", 4592 &apr->details.success.new_rules), 4593 GNUNET_JSON_spec_mark_optional ( 4594 GNUNET_JSON_spec_string ( 4595 "new_measures", 4596 &apr->details.success.new_measures), 4597 NULL), 4598 GNUNET_JSON_spec_end () 4599 }; 4600 const char *err; 4601 unsigned int line; 4602 4603 if (GNUNET_OK != 4604 GNUNET_JSON_parse (result, 4605 spec, 4606 &err, 4607 &line)) 4608 { 4609 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4610 "AML program output is malformed at `%s'\n", 4611 err); 4612 json_dumpf (result, 4613 stderr, 4614 JSON_INDENT (2)); 4615 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4616 apr->details.failure.fallback_measure 4617 = fallback_measure; 4618 apr->details.failure.error_message 4619 = err; 4620 apr->details.failure.ec 4621 = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT; 4622 goto ready; 4623 } 4624 apr->details.success.num_events 4625 = json_array_size (jevents); 4626 4627 GNUNET_assert (((size_t) apr->details.success.num_events) == 4628 json_array_size (jevents)); 4629 evs = GNUNET_new_array ( 4630 apr->details.success.num_events, 4631 const char *); 4632 for (unsigned int i = 0; i<apr->details.success.num_events; i++) 4633 { 4634 evs[i] = json_string_value ( 4635 json_array_get (jevents, 4636 i)); 4637 if (NULL == evs[i]) 4638 { 4639 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4640 apr->details.failure.fallback_measure 4641 = fallback_measure; 4642 apr->details.failure.error_message 4643 = "events"; 4644 apr->details.failure.ec 4645 = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT; 4646 goto ready; 4647 } 4648 } 4649 apr->status = TALER_KYCLOGIC_AMLR_SUCCESS; 4650 apr->details.success.events = evs; 4651 { 4652 /* check new_rules */ 4653 struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs; 4654 4655 lrs = TALER_KYCLOGIC_rules_parse ( 4656 apr->details.success.new_rules); 4657 if (NULL == lrs) 4658 { 4659 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4660 "AML program output is malformed at `%s'\n", 4661 "new_rules"); 4662 4663 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4664 apr->details.failure.fallback_measure 4665 = fallback_measure; 4666 apr->details.failure.error_message 4667 = "new_rules"; 4668 apr->details.failure.ec 4669 = TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT; 4670 goto ready; 4671 } 4672 apr->details.success.expiration_time 4673 = lrs->expiration_time; 4674 TALER_KYCLOGIC_rules_free (lrs); 4675 } 4676 } 4677 ready: 4678 aprh->aprc (aprh->aprc_cls, 4679 &aprh->apr); 4680 GNUNET_free (evs); 4681 TALER_KYCLOGIC_run_aml_program_cancel (aprh); 4682 } 4683 4684 4685 /** 4686 * Helper function to asynchronously return the result. 4687 * 4688 * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return results for 4689 */ 4690 static void 4691 async_return_task (void *cls) 4692 { 4693 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls; 4694 4695 aprh->async_cb = NULL; 4696 aprh->aprc (aprh->aprc_cls, 4697 &aprh->apr); 4698 TALER_KYCLOGIC_run_aml_program_cancel (aprh); 4699 } 4700 4701 4702 /** 4703 * Helper function called on timeout on the fallback measure. 4704 * 4705 * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return results for 4706 */ 4707 static void 4708 handle_aml_timeout2 (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 4714 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4715 "Fallback measure %s ran into timeout (!)\n", 4716 aprh->program->program_name); 4717 if (NULL != aprh->proc) 4718 { 4719 TALER_JSON_external_conversion_stop (aprh->proc); 4720 aprh->proc = NULL; 4721 } 4722 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4723 apr->details.failure.fallback_measure 4724 = fallback_measure; 4725 apr->details.failure.error_message 4726 = aprh->program->program_name; 4727 apr->details.failure.ec 4728 = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT; 4729 async_return_task (aprh); 4730 } 4731 4732 4733 /** 4734 * Helper function called on timeout of an AML program. 4735 * Runs the fallback measure. 4736 * 4737 * @param[in] cls a `struct TALER_KYCLOGIC_AmlProgramRunnerHandle` to return results for 4738 */ 4739 static void 4740 handle_aml_timeout (void *cls) 4741 { 4742 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh = cls; 4743 struct TALER_KYCLOGIC_AmlProgramResult *apr = &aprh->apr; 4744 const char *fallback_measure = aprh->program->fallback; 4745 const struct TALER_KYCLOGIC_Measure *m; 4746 const struct TALER_KYCLOGIC_AmlProgram *fprogram; 4747 4748 aprh->async_cb = NULL; 4749 GNUNET_assert (NULL != fallback_measure); 4750 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 4751 "AML program %s ran into timeout\n", 4752 aprh->program->program_name); 4753 if (NULL != aprh->proc) 4754 { 4755 TALER_JSON_external_conversion_stop (aprh->proc); 4756 aprh->proc = NULL; 4757 } 4758 4759 m = TALER_KYCLOGIC_get_measure (&default_rules, 4760 fallback_measure); 4761 /* Fallback program could have "disappeared" due to configuration change, 4762 as we do not check all rule sets in the database when our configuration 4763 is updated... */ 4764 if (NULL == m) 4765 { 4766 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4767 "Fallback measure `%s' does not exist (anymore?).\n", 4768 fallback_measure); 4769 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4770 apr->details.failure.fallback_measure 4771 = fallback_measure; 4772 apr->details.failure.error_message 4773 = aprh->program->program_name; 4774 apr->details.failure.ec 4775 = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT; 4776 async_return_task (aprh); 4777 return; 4778 } 4779 /* We require fallback measures to have a 'skip' check */ 4780 GNUNET_break (0 == 4781 strcasecmp (m->check_name, 4782 "skip")); 4783 fprogram = find_program (m->prog_name); 4784 /* Program associated with an original measure must exist */ 4785 GNUNET_assert (NULL != fprogram); 4786 if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES))) 4787 { 4788 /* We might not have recognized the fallback measure as such 4789 because it was not used as such in the plain configuration, 4790 and legitimization rule sets might have referred to an older 4791 configuration. So this should be super-rare but possible. */ 4792 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4793 "Program `%s' used in fallback measure `%s' requires inputs and is thus unsuitable as a fallback measure!\n", 4794 m->prog_name, 4795 fallback_measure); 4796 apr->status = TALER_KYCLOGIC_AMLR_FAILURE; 4797 apr->details.failure.fallback_measure 4798 = fallback_measure; 4799 apr->details.failure.error_message 4800 = aprh->program->program_name; 4801 apr->details.failure.ec 4802 = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT; 4803 async_return_task (aprh); 4804 return; 4805 } 4806 { 4807 /* Run fallback AML program */ 4808 json_t *input = json_object (); 4809 const char *extra_args[] = { 4810 "-c", 4811 cfg_filename, 4812 NULL, 4813 }; 4814 char **args; 4815 4816 args = TALER_words_split (fprogram->command, 4817 extra_args); 4818 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4819 "Running fallback measure `%s' (%s)\n", 4820 fallback_measure, 4821 fprogram->command); 4822 aprh->proc = TALER_JSON_external_conversion_start ( 4823 input, 4824 &handle_aml_output, 4825 aprh, 4826 args[0], 4827 (const char **) args); 4828 TALER_words_destroy (args); 4829 json_decref (input); 4830 } 4831 aprh->async_cb = GNUNET_SCHEDULER_add_delayed (aprh->timeout, 4832 &handle_aml_timeout2, 4833 aprh); 4834 } 4835 4836 4837 struct TALER_KYCLOGIC_AmlProgramRunnerHandle * 4838 TALER_KYCLOGIC_run_aml_program ( 4839 const json_t *jmeasures, 4840 bool is_wallet, 4841 unsigned int measure_index, 4842 TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb, 4843 void *current_attributes_cb_cls, 4844 TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb, 4845 void *current_rules_cb_cls, 4846 TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb, 4847 void *aml_history_cb_cls, 4848 TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb, 4849 void *kyc_history_cb_cls, 4850 struct GNUNET_TIME_Relative timeout, 4851 TALER_KYCLOGIC_AmlProgramResultCallback aprc, 4852 void *aprc_cls) 4853 { 4854 const json_t *context; 4855 const char *check_name; 4856 const char *prog_name; 4857 4858 { 4859 enum TALER_ErrorCode ec; 4860 4861 ec = TALER_KYCLOGIC_select_measure (jmeasures, 4862 measure_index, 4863 &check_name, 4864 &prog_name, 4865 &context); 4866 if (TALER_EC_NONE != ec) 4867 { 4868 GNUNET_break (0); 4869 return NULL; 4870 } 4871 } 4872 if (NULL == prog_name) 4873 { 4874 /* Trying to run AML program on a measure that does not 4875 have one, and that should thus be an INFO check which 4876 should never lead here. Very strange. */ 4877 GNUNET_break (0); 4878 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4879 "Measure %u with check `%s' does not have an AML program!\n", 4880 measure_index, 4881 check_name); 4882 json_dumpf (jmeasures, 4883 stderr, 4884 JSON_INDENT (2)); 4885 return NULL; 4886 } 4887 return TALER_KYCLOGIC_run_aml_program2 (prog_name, 4888 context, 4889 is_wallet, 4890 current_attributes_cb, 4891 current_attributes_cb_cls, 4892 current_rules_cb, 4893 current_rules_cb_cls, 4894 aml_history_cb, 4895 aml_history_cb_cls, 4896 kyc_history_cb, 4897 kyc_history_cb_cls, 4898 timeout, 4899 aprc, 4900 aprc_cls); 4901 } 4902 4903 4904 struct TALER_KYCLOGIC_AmlProgramRunnerHandle * 4905 TALER_KYCLOGIC_run_aml_program2 ( 4906 const char *prog_name, 4907 const json_t *context, 4908 bool is_wallet, 4909 TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb, 4910 void *current_attributes_cb_cls, 4911 TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb, 4912 void *current_rules_cb_cls, 4913 TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb, 4914 void *aml_history_cb_cls, 4915 TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb, 4916 void *kyc_history_cb_cls, 4917 struct GNUNET_TIME_Relative timeout, 4918 TALER_KYCLOGIC_AmlProgramResultCallback aprc, 4919 void *aprc_cls) 4920 { 4921 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh; 4922 struct TALER_KYCLOGIC_AmlProgram *prog; 4923 const json_t *jdefault_rules; 4924 json_t *current_rules; 4925 json_t *aml_history; 4926 json_t *kyc_history; 4927 json_t *attributes; 4928 4929 prog = find_program (prog_name); 4930 if (NULL == prog) 4931 { 4932 GNUNET_break (0); 4933 return NULL; 4934 } 4935 aprh = GNUNET_new (struct TALER_KYCLOGIC_AmlProgramRunnerHandle); 4936 aprh->aprc = aprc; 4937 aprh->aprc_cls = aprc_cls; 4938 aprh->program = prog; 4939 if (0 != (API_ATTRIBUTES & prog->input_mask)) 4940 { 4941 attributes = current_attributes_cb (current_attributes_cb_cls); 4942 #if DEBUG 4943 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4944 "KYC attributes for AML program %s are:\n", 4945 prog_name); 4946 json_dumpf (attributes, 4947 stderr, 4948 JSON_INDENT (2)); 4949 fprintf (stderr, 4950 "\n"); 4951 #endif 4952 for (unsigned int i = 0; i<prog->num_required_attributes; i++) 4953 { 4954 const char *rattr = prog->required_attributes[i]; 4955 4956 if (NULL == json_object_get (attributes, 4957 rattr)) 4958 { 4959 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4960 "KYC attributes lack required attribute `%s' for AML program %s\n", 4961 rattr, 4962 prog->program_name); 4963 #if DEBUG 4964 json_dumpf (attributes, 4965 stderr, 4966 JSON_INDENT (2)); 4967 #endif 4968 aprh->apr.status = TALER_KYCLOGIC_AMLR_FAILURE; 4969 aprh->apr.details.failure.fallback_measure 4970 = prog->fallback; 4971 aprh->apr.details.failure.error_message 4972 = rattr; 4973 aprh->apr.details.failure.ec 4974 = TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_INCOMPLETE_REPLY; 4975 aprh->async_cb 4976 = GNUNET_SCHEDULER_add_now (&async_return_task, 4977 aprh); 4978 json_decref (attributes); 4979 return aprh; 4980 } 4981 } 4982 } 4983 else 4984 { 4985 attributes = NULL; 4986 } 4987 if (0 != (API_CONTEXT & prog->input_mask)) 4988 { 4989 for (unsigned int i = 0; i<prog->num_required_contexts; i++) 4990 { 4991 const char *rctx = prog->required_contexts[i]; 4992 4993 if (NULL == json_object_get (context, 4994 rctx)) 4995 { 4996 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4997 "Context lacks required field `%s' for AML program %s\n", 4998 rctx, 4999 prog->program_name); 5000 #if DEBUG 5001 json_dumpf (context, 5002 stderr, 5003 JSON_INDENT (2)); 5004 #endif 5005 aprh->apr.status = TALER_KYCLOGIC_AMLR_FAILURE; 5006 aprh->apr.details.failure.fallback_measure 5007 = prog->fallback; 5008 aprh->apr.details.failure.error_message 5009 = rctx; 5010 aprh->apr.details.failure.ec 5011 = TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_INCOMPLETE_CONTEXT; 5012 aprh->async_cb 5013 = GNUNET_SCHEDULER_add_now (&async_return_task, 5014 aprh); 5015 json_decref (attributes); 5016 return aprh; 5017 } 5018 } 5019 } 5020 else 5021 { 5022 context = NULL; 5023 } 5024 if (0 == (API_AML_HISTORY & prog->input_mask)) 5025 aml_history = NULL; 5026 else 5027 aml_history = aml_history_cb (aml_history_cb_cls); 5028 if (0 == (API_KYC_HISTORY & prog->input_mask)) 5029 kyc_history = NULL; 5030 else 5031 kyc_history = kyc_history_cb (kyc_history_cb_cls); 5032 if (0 == (API_CURRENT_RULES & prog->input_mask)) 5033 current_rules = NULL; 5034 else 5035 current_rules = current_rules_cb (current_rules_cb_cls); 5036 if (0 != (API_DEFAULT_RULES & prog->input_mask)) 5037 jdefault_rules = 5038 (is_wallet 5039 ? wallet_default_lrs 5040 : bankaccount_default_lrs); 5041 else 5042 jdefault_rules = NULL; 5043 { 5044 json_t *input; 5045 const char *extra_args[] = { 5046 "-c", 5047 cfg_filename, 5048 NULL, 5049 }; 5050 char **args; 5051 5052 input = GNUNET_JSON_PACK ( 5053 GNUNET_JSON_pack_allow_null ( 5054 GNUNET_JSON_pack_object_steal ("current_rules", 5055 current_rules)), 5056 GNUNET_JSON_pack_allow_null ( 5057 GNUNET_JSON_pack_object_incref ("default_rules", 5058 (json_t *) jdefault_rules)), 5059 GNUNET_JSON_pack_allow_null ( 5060 GNUNET_JSON_pack_object_incref ("context", 5061 (json_t *) context)), 5062 GNUNET_JSON_pack_allow_null ( 5063 GNUNET_JSON_pack_object_steal ("attributes", 5064 attributes)), 5065 GNUNET_JSON_pack_allow_null ( 5066 GNUNET_JSON_pack_array_steal ("aml_history", 5067 aml_history)), 5068 GNUNET_JSON_pack_allow_null ( 5069 GNUNET_JSON_pack_array_steal ("kyc_history", 5070 kyc_history)) 5071 ); 5072 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 5073 "Running AML program %s\n", 5074 prog->command); 5075 args = TALER_words_split (prog->command, 5076 extra_args); 5077 GNUNET_assert (NULL != args); 5078 GNUNET_assert (NULL != args[0]); 5079 #if DEBUG 5080 json_dumpf (input, 5081 stderr, 5082 JSON_INDENT (2)); 5083 #endif 5084 aprh->proc = TALER_JSON_external_conversion_start ( 5085 input, 5086 &handle_aml_output, 5087 aprh, 5088 args[0], 5089 (const char **) args); 5090 TALER_words_destroy (args); 5091 json_decref (input); 5092 } 5093 aprh->timeout = timeout; 5094 aprh->async_cb = GNUNET_SCHEDULER_add_delayed (timeout, 5095 &handle_aml_timeout, 5096 aprh); 5097 return aprh; 5098 } 5099 5100 5101 struct TALER_KYCLOGIC_AmlProgramRunnerHandle * 5102 TALER_KYCLOGIC_run_aml_program3 ( 5103 bool is_wallet, 5104 const struct TALER_KYCLOGIC_Measure *measure, 5105 TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb, 5106 void *current_attributes_cb_cls, 5107 TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb, 5108 void *current_rules_cb_cls, 5109 TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb, 5110 void *aml_history_cb_cls, 5111 TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb, 5112 void *kyc_history_cb_cls, 5113 struct GNUNET_TIME_Relative timeout, 5114 TALER_KYCLOGIC_AmlProgramResultCallback aprc, 5115 void *aprc_cls) 5116 { 5117 return TALER_KYCLOGIC_run_aml_program2 ( 5118 measure->prog_name, 5119 measure->context, 5120 is_wallet, 5121 current_attributes_cb, 5122 current_attributes_cb_cls, 5123 current_rules_cb, 5124 current_rules_cb_cls, 5125 aml_history_cb, 5126 aml_history_cb_cls, 5127 kyc_history_cb, 5128 kyc_history_cb_cls, 5129 timeout, 5130 aprc, 5131 aprc_cls); 5132 } 5133 5134 5135 const char * 5136 TALER_KYCLOGIC_run_aml_program_get_name ( 5137 const struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh) 5138 { 5139 return aprh->program->program_name; 5140 } 5141 5142 5143 void 5144 TALER_KYCLOGIC_run_aml_program_cancel ( 5145 struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh) 5146 { 5147 if (NULL != aprh->proc) 5148 { 5149 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 5150 "Killing AML program\n"); 5151 TALER_JSON_external_conversion_stop (aprh->proc); 5152 aprh->proc = NULL; 5153 } 5154 if (NULL != aprh->async_cb) 5155 { 5156 GNUNET_SCHEDULER_cancel (aprh->async_cb); 5157 aprh->async_cb = NULL; 5158 } 5159 GNUNET_free (aprh); 5160 } 5161 5162 5163 json_t * 5164 TALER_KYCLOGIC_get_hard_limits () 5165 { 5166 const struct TALER_KYCLOGIC_KycRule *rules 5167 = default_rules.kyc_rules; 5168 unsigned int num_rules 5169 = default_rules.num_kyc_rules; 5170 json_t *hard_limits; 5171 5172 hard_limits = json_array (); 5173 GNUNET_assert (NULL != hard_limits); 5174 for (unsigned int i = 0; i<num_rules; i++) 5175 { 5176 const struct TALER_KYCLOGIC_KycRule *rule = &rules[i]; 5177 json_t *hard_limit; 5178 5179 if (! rule->verboten) 5180 continue; 5181 if (! rule->exposed) 5182 continue; 5183 hard_limit = GNUNET_JSON_PACK ( 5184 GNUNET_JSON_pack_allow_null ( 5185 GNUNET_JSON_pack_string ("rule_name", 5186 rule->rule_name)), 5187 TALER_JSON_pack_kycte ("operation_type", 5188 rule->trigger), 5189 GNUNET_JSON_pack_time_rel ("timeframe", 5190 rule->timeframe), 5191 TALER_JSON_pack_amount ("threshold", 5192 &rule->threshold) 5193 ); 5194 GNUNET_assert (0 == 5195 json_array_append_new (hard_limits, 5196 hard_limit)); 5197 } 5198 return hard_limits; 5199 } 5200 5201 5202 json_t * 5203 TALER_KYCLOGIC_get_zero_limits () 5204 { 5205 const struct TALER_KYCLOGIC_KycRule *rules 5206 = default_rules.kyc_rules; 5207 unsigned int num_rules 5208 = default_rules.num_kyc_rules; 5209 json_t *zero_limits; 5210 5211 zero_limits = json_array (); 5212 GNUNET_assert (NULL != zero_limits); 5213 for (unsigned int i = 0; i<num_rules; i++) 5214 { 5215 const struct TALER_KYCLOGIC_KycRule *rule = &rules[i]; 5216 json_t *zero_limit; 5217 5218 if (! rule->exposed) 5219 continue; 5220 if (rule->verboten) 5221 continue; /* see: hard_limits */ 5222 if (! TALER_amount_is_zero (&rule->threshold)) 5223 continue; 5224 zero_limit = GNUNET_JSON_PACK ( 5225 GNUNET_JSON_pack_allow_null ( 5226 GNUNET_JSON_pack_string ("rule_name", 5227 rule->rule_name)), 5228 TALER_JSON_pack_kycte ("operation_type", 5229 rule->trigger)); 5230 GNUNET_assert (0 == 5231 json_array_append_new (zero_limits, 5232 zero_limit)); 5233 } 5234 return zero_limits; 5235 } 5236 5237 5238 json_t * 5239 TALER_KYCLOGIC_get_default_legi_rules (bool for_wallet) 5240 { 5241 const json_t *r; 5242 5243 r = (for_wallet 5244 ? wallet_default_lrs 5245 : bankaccount_default_lrs); 5246 return json_incref ((json_t *) r); 5247 } 5248 5249 5250 /* end of kyclogic_api.c */