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