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