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