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