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