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