Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2020-2026 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU 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 General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file taler-exchange-offline.c
18 : * @brief Support for operations involving the exchange's offline master key.
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <gnunet/gnunet_json_lib.h>
23 : #include <gnunet/gnunet_util_lib.h>
24 : #include "taler/taler_json_lib.h"
25 :
26 : struct AmlStaffRequest;
27 : #define TALER_EXCHANGE_POST_MANAGEMENT_AML_OFFICERS_RESULT_CLOSURE \
28 : struct AmlStaffRequest
29 : #include "taler/exchange/post-management-aml-officers.h"
30 :
31 : struct DenomRevocationRequest;
32 : #define TALER_EXCHANGE_POST_MANAGEMENT_DENOMINATIONS_REVOKE_RESULT_CLOSURE \
33 : struct DenomRevocationRequest
34 : #include \
35 : "taler/exchange/post-management-denominations-H_DENOM_PUB-revoke.h"
36 :
37 : struct SignkeyRevocationRequest;
38 : #define TALER_EXCHANGE_POST_MANAGEMENT_SIGNKEYS_REVOKE_RESULT_CLOSURE \
39 : struct SignkeyRevocationRequest
40 : #include \
41 : "taler/exchange/post-management-signkeys-EXCHANGE_PUB-revoke.h"
42 :
43 : struct AuditorAddRequest;
44 : #define TALER_EXCHANGE_POST_MANAGEMENT_AUDITORS_RESULT_CLOSURE \
45 : struct AuditorAddRequest
46 : #include "taler/exchange/post-management-auditors.h"
47 :
48 : struct AuditorDelRequest;
49 : #define TALER_EXCHANGE_POST_MANAGEMENT_AUDITORS_DISABLE_RESULT_CLOSURE \
50 : struct AuditorDelRequest
51 : #include "taler/exchange/post-management-auditors-AUDITOR_PUB-disable.h"
52 :
53 : struct WireAddRequest;
54 : #define TALER_EXCHANGE_POST_MANAGEMENT_WIRE_RESULT_CLOSURE \
55 : struct WireAddRequest
56 : #include "taler/exchange/post-management-wire.h"
57 :
58 : struct WireDelRequest;
59 : #define TALER_EXCHANGE_POST_MANAGEMENT_WIRE_DISABLE_RESULT_CLOSURE \
60 : struct WireDelRequest
61 : #include "taler/exchange/post-management-wire-disable.h"
62 :
63 : struct WireFeeRequest;
64 : #define TALER_EXCHANGE_POST_MANAGEMENT_WIRE_FEES_RESULT_CLOSURE \
65 : struct WireFeeRequest
66 : #include "taler/exchange/post-management-wire-fee.h"
67 :
68 : struct GlobalFeeRequest;
69 : #define TALER_EXCHANGE_POST_MANAGEMENT_GLOBAL_FEES_RESULT_CLOSURE \
70 : struct GlobalFeeRequest
71 : #include "taler/exchange/post-management-global-fees.h"
72 :
73 : struct DrainProfitsRequest;
74 : #define TALER_EXCHANGE_POST_MANAGEMENT_DRAIN_RESULT_CLOSURE \
75 : struct DrainProfitsRequest
76 : #include "taler/exchange/post-management-drain.h"
77 :
78 : struct UploadKeysRequest;
79 : #define TALER_EXCHANGE_POST_MANAGEMENT_KEYS_RESULT_CLOSURE \
80 : struct UploadKeysRequest
81 : #include "taler/exchange/post-management-keys.h"
82 :
83 : struct PartnerAddRequest;
84 : #define TALER_EXCHANGE_POST_MANAGEMENT_PARTNERS_RESULT_CLOSURE \
85 : struct PartnerAddRequest
86 : #include "taler/exchange/post-management-partners.h"
87 :
88 : #define TALER_EXCHANGE_GET_MANAGEMENT_KEYS_RESULT_CLOSURE \
89 : char *const
90 : #include "taler/exchange/get-management-keys.h"
91 :
92 : #include <microhttpd.h>
93 : #include <regex.h>
94 :
95 :
96 : /**
97 : * Name of the input for the 'sign' and 'show' operation.
98 : * The last component --by convention-- identifies the protocol version
99 : * and should be incremented whenever the JSON format of the 'argument' changes.
100 : */
101 : #define OP_INPUT_KEYS "exchange-input-keys-0"
102 :
103 : /**
104 : * Name of the operation to 'disable auditor'
105 : * The last component --by convention-- identifies the protocol version
106 : * and should be incremented whenever the JSON format of the 'argument' changes.
107 : */
108 : #define OP_DISABLE_AUDITOR "exchange-disable-auditor-0"
109 :
110 : /**
111 : * Name of the operation to 'enable auditor'
112 : * The last component --by convention-- identifies the protocol version
113 : * and should be incremented whenever the JSON format of the 'argument' changes.
114 : */
115 : #define OP_ENABLE_AUDITOR "exchange-enable-auditor-0"
116 :
117 : /**
118 : * Name of the operation to 'enable wire'
119 : * The last component --by convention-- identifies the protocol version
120 : * and should be incremented whenever the JSON format of the 'argument' changes.
121 : */
122 : #define OP_ENABLE_WIRE "exchange-enable-wire-0"
123 :
124 : /**
125 : * Name of the operation to 'disable wire'
126 : * The last component --by convention-- identifies the protocol version
127 : * and should be incremented whenever the JSON format of the 'argument' changes.
128 : */
129 : #define OP_DISABLE_WIRE "exchange-disable-wire-0"
130 :
131 : /**
132 : * Name of the operation to set a 'wire-fee'
133 : * The last component --by convention-- identifies the protocol version
134 : * and should be incremented whenever the JSON format of the 'argument' changes.
135 : */
136 : #define OP_SET_WIRE_FEE "exchange-set-wire-fee-0"
137 :
138 : /**
139 : * Name of the operation to set a 'global-fee'
140 : * The last component --by convention-- identifies the protocol version
141 : * and should be incremented whenever the JSON format of the 'argument' changes.
142 : */
143 : #define OP_SET_GLOBAL_FEE "exchange-set-global-fee-0"
144 :
145 : /**
146 : * Name of the operation to 'upload' key signatures
147 : * The last component --by convention-- identifies the protocol version
148 : * and should be incremented whenever the JSON format of the 'argument' changes.
149 : */
150 : #define OP_UPLOAD_SIGS "exchange-upload-sigs-0"
151 :
152 : /**
153 : * Name of the operation to 'revoke-denomination' key
154 : * The last component --by convention-- identifies the protocol version
155 : * and should be incremented whenever the JSON format of the 'argument' changes.
156 : */
157 : #define OP_REVOKE_DENOMINATION "exchange-revoke-denomination-0"
158 :
159 : /**
160 : * Name of the operation to 'revoke-signkey'
161 : * The last component --by convention-- identifies the protocol version
162 : * and should be incremented whenever the JSON format of the 'argument' changes.
163 : */
164 : #define OP_REVOKE_SIGNKEY "exchange-revoke-signkey-0"
165 :
166 : /**
167 : * Show the offline signing key.
168 : * The last component --by convention-- identifies the protocol version
169 : * and should be incremented whenever the JSON format of the 'argument' changes.
170 : */
171 : #define OP_SETUP "exchange-setup-0"
172 :
173 : /**
174 : * Generate message to drain profits.
175 : */
176 : #define OP_DRAIN_PROFITS "exchange-drain-profits-0"
177 :
178 : /**
179 : * Setup AML staff.
180 : */
181 : #define OP_UPDATE_AML_STAFF "exchange-add-aml-staff-0"
182 :
183 : /**
184 : * Setup partner exchange for wad transfers.
185 : */
186 : #define OP_ADD_PARTNER "exchange-add-partner-0"
187 :
188 : /**
189 : * Our private key, initialized in #load_offline_key().
190 : */
191 : static struct TALER_MasterPrivateKeyP master_priv;
192 :
193 : /**
194 : * Our public key, initialized in #load_offline_key().
195 : */
196 : static struct TALER_MasterPublicKeyP master_pub;
197 :
198 : /**
199 : * Our context for making HTTP requests.
200 : */
201 : static struct GNUNET_CURL_Context *ctx;
202 :
203 : /**
204 : * Reschedule context for #ctx.
205 : */
206 : static struct GNUNET_CURL_RescheduleContext *rc;
207 :
208 : /**
209 : * Handle to the exchange's configuration
210 : */
211 : static const struct GNUNET_CONFIGURATION_Handle *kcfg;
212 :
213 : /**
214 : * Return value from main().
215 : */
216 : static int global_ret;
217 :
218 : /**
219 : * Input to consume.
220 : */
221 : static json_t *in;
222 :
223 : /**
224 : * Array of actions to perform.
225 : */
226 : static json_t *out;
227 :
228 : /**
229 : * Currency we have configured.
230 : */
231 : static char *currency;
232 :
233 : /**
234 : * URL of the exchange we are interacting with
235 : * as per our configuration.
236 : */
237 : static char *CFG_exchange_url;
238 :
239 : /**
240 : * A subcommand supported by this program.
241 : */
242 : struct SubCommand
243 : {
244 : /**
245 : * Name of the command.
246 : */
247 : const char *name;
248 :
249 : /**
250 : * Help text for the command.
251 : */
252 : const char *help;
253 :
254 : /**
255 : * Function implementing the command.
256 : *
257 : * @param args subsequent command line arguments (char **)
258 : */
259 : void (*cb)(char *const *args);
260 : };
261 :
262 :
263 : /**
264 : * Data structure for denomination revocation requests.
265 : */
266 : struct DenomRevocationRequest
267 : {
268 :
269 : /**
270 : * Kept in a DLL.
271 : */
272 : struct DenomRevocationRequest *next;
273 :
274 : /**
275 : * Kept in a DLL.
276 : */
277 : struct DenomRevocationRequest *prev;
278 :
279 : /**
280 : * Operation handle.
281 : */
282 : struct TALER_EXCHANGE_PostManagementDenominationsRevokeHandle *h;
283 :
284 : /**
285 : * Array index of the associated command.
286 : */
287 : size_t idx;
288 : };
289 :
290 :
291 : /**
292 : * Data structure for signkey revocation requests.
293 : */
294 : struct SignkeyRevocationRequest
295 : {
296 :
297 : /**
298 : * Kept in a DLL.
299 : */
300 : struct SignkeyRevocationRequest *next;
301 :
302 : /**
303 : * Kept in a DLL.
304 : */
305 : struct SignkeyRevocationRequest *prev;
306 :
307 : /**
308 : * Operation handle.
309 : */
310 : struct TALER_EXCHANGE_PostManagementSignkeysRevokeHandle *h;
311 :
312 : /**
313 : * Array index of the associated command.
314 : */
315 : size_t idx;
316 : };
317 :
318 :
319 : /**
320 : * Data structure for auditor add requests.
321 : */
322 : struct AuditorAddRequest
323 : {
324 :
325 : /**
326 : * Kept in a DLL.
327 : */
328 : struct AuditorAddRequest *next;
329 :
330 : /**
331 : * Kept in a DLL.
332 : */
333 : struct AuditorAddRequest *prev;
334 :
335 : /**
336 : * Operation handle.
337 : */
338 : struct TALER_EXCHANGE_PostManagementAuditorsHandle *h;
339 :
340 : /**
341 : * Array index of the associated command.
342 : */
343 : size_t idx;
344 : };
345 :
346 :
347 : /**
348 : * Data structure for auditor del requests.
349 : */
350 : struct AuditorDelRequest
351 : {
352 :
353 : /**
354 : * Kept in a DLL.
355 : */
356 : struct AuditorDelRequest *next;
357 :
358 : /**
359 : * Kept in a DLL.
360 : */
361 : struct AuditorDelRequest *prev;
362 :
363 : /**
364 : * Operation handle.
365 : */
366 : struct TALER_EXCHANGE_PostManagementAuditorsDisableHandle *h;
367 :
368 : /**
369 : * Array index of the associated command.
370 : */
371 : size_t idx;
372 : };
373 :
374 :
375 : /**
376 : * Data structure for wire add requests.
377 : */
378 : struct WireAddRequest
379 : {
380 :
381 : /**
382 : * Kept in a DLL.
383 : */
384 : struct WireAddRequest *next;
385 :
386 : /**
387 : * Kept in a DLL.
388 : */
389 : struct WireAddRequest *prev;
390 :
391 : /**
392 : * Operation handle.
393 : */
394 : struct TALER_EXCHANGE_PostManagementWireHandle *h;
395 :
396 : /**
397 : * Array index of the associated command.
398 : */
399 : size_t idx;
400 : };
401 :
402 :
403 : /**
404 : * Data structure for wire del requests.
405 : */
406 : struct WireDelRequest
407 : {
408 :
409 : /**
410 : * Kept in a DLL.
411 : */
412 : struct WireDelRequest *next;
413 :
414 : /**
415 : * Kept in a DLL.
416 : */
417 : struct WireDelRequest *prev;
418 :
419 : /**
420 : * Operation handle.
421 : */
422 : struct TALER_EXCHANGE_PostManagementWireDisableHandle *h;
423 :
424 : /**
425 : * Array index of the associated command.
426 : */
427 : size_t idx;
428 : };
429 :
430 :
431 : /**
432 : * Data structure for announcing wire fees.
433 : */
434 : struct WireFeeRequest
435 : {
436 :
437 : /**
438 : * Kept in a DLL.
439 : */
440 : struct WireFeeRequest *next;
441 :
442 : /**
443 : * Kept in a DLL.
444 : */
445 : struct WireFeeRequest *prev;
446 :
447 : /**
448 : * Operation handle.
449 : */
450 : struct TALER_EXCHANGE_PostManagementWireFeesHandle *h;
451 :
452 : /**
453 : * Array index of the associated command.
454 : */
455 : size_t idx;
456 : };
457 :
458 :
459 : /**
460 : * Data structure for draining profits.
461 : */
462 : struct DrainProfitsRequest
463 : {
464 :
465 : /**
466 : * Kept in a DLL.
467 : */
468 : struct DrainProfitsRequest *next;
469 :
470 : /**
471 : * Kept in a DLL.
472 : */
473 : struct DrainProfitsRequest *prev;
474 :
475 : /**
476 : * Operation handle.
477 : */
478 : struct TALER_EXCHANGE_PostManagementDrainHandle *h;
479 :
480 : /**
481 : * Array index of the associated command.
482 : */
483 : size_t idx;
484 : };
485 :
486 :
487 : /**
488 : * Data structure for announcing global fees.
489 : */
490 : struct GlobalFeeRequest
491 : {
492 :
493 : /**
494 : * Kept in a DLL.
495 : */
496 : struct GlobalFeeRequest *next;
497 :
498 : /**
499 : * Kept in a DLL.
500 : */
501 : struct GlobalFeeRequest *prev;
502 :
503 : /**
504 : * Operation handle.
505 : */
506 : struct TALER_EXCHANGE_PostManagementGlobalFeesHandle *h;
507 :
508 : /**
509 : * Array index of the associated command.
510 : */
511 : size_t idx;
512 : };
513 :
514 :
515 : /**
516 : * Ongoing /keys request.
517 : */
518 : struct UploadKeysRequest
519 : {
520 : /**
521 : * Kept in a DLL.
522 : */
523 : struct UploadKeysRequest *next;
524 :
525 : /**
526 : * Kept in a DLL.
527 : */
528 : struct UploadKeysRequest *prev;
529 :
530 : /**
531 : * Operation handle.
532 : */
533 : struct TALER_EXCHANGE_PostManagementKeysHandle *h;
534 :
535 : /**
536 : * Operation index.
537 : */
538 : size_t idx;
539 : };
540 :
541 :
542 : /**
543 : * Data structure for AML staff requests.
544 : */
545 : struct AmlStaffRequest
546 : {
547 :
548 : /**
549 : * Kept in a DLL.
550 : */
551 : struct AmlStaffRequest *next;
552 :
553 : /**
554 : * Kept in a DLL.
555 : */
556 : struct AmlStaffRequest *prev;
557 :
558 : /**
559 : * Operation handle.
560 : */
561 : struct TALER_EXCHANGE_PostManagementAmlOfficersHandle *h;
562 :
563 : /**
564 : * Array index of the associated command.
565 : */
566 : size_t idx;
567 : };
568 :
569 :
570 : /**
571 : * Data structure for partner add requests.
572 : */
573 : struct PartnerAddRequest
574 : {
575 :
576 : /**
577 : * Kept in a DLL.
578 : */
579 : struct PartnerAddRequest *next;
580 :
581 : /**
582 : * Kept in a DLL.
583 : */
584 : struct PartnerAddRequest *prev;
585 :
586 : /**
587 : * Operation handle.
588 : */
589 : struct TALER_EXCHANGE_PostManagementPartnersHandle *h;
590 :
591 : /**
592 : * Array index of the associated command.
593 : */
594 : size_t idx;
595 : };
596 :
597 :
598 : /**
599 : * Next work item to perform.
600 : */
601 : static struct GNUNET_SCHEDULER_Task *nxt;
602 :
603 : /**
604 : * Handle for #do_download.
605 : */
606 : static struct TALER_EXCHANGE_GetManagementKeysHandle *mgkh;
607 :
608 : /**
609 : * Active AML staff change requests.
610 : */
611 : static struct AmlStaffRequest *asr_head;
612 :
613 : /**
614 : * Active AML staff change requests.
615 : */
616 : static struct AmlStaffRequest *asr_tail;
617 :
618 : /**
619 : * Active partner add requests.
620 : */
621 : static struct PartnerAddRequest *par_head;
622 :
623 : /**
624 : * Active partner add requests.
625 : */
626 : static struct PartnerAddRequest *par_tail;
627 :
628 : /**
629 : * Active denomiantion revocation requests.
630 : */
631 : static struct DenomRevocationRequest *drr_head;
632 :
633 : /**
634 : * Active denomiantion revocation requests.
635 : */
636 : static struct DenomRevocationRequest *drr_tail;
637 :
638 : /**
639 : * Active signkey revocation requests.
640 : */
641 : static struct SignkeyRevocationRequest *srr_head;
642 :
643 : /**
644 : * Active signkey revocation requests.
645 : */
646 : static struct SignkeyRevocationRequest *srr_tail;
647 :
648 : /**
649 : * Active auditor add requests.
650 : */
651 : static struct AuditorAddRequest *aar_head;
652 :
653 : /**
654 : * Active auditor add requests.
655 : */
656 : static struct AuditorAddRequest *aar_tail;
657 :
658 : /**
659 : * Active auditor del requests.
660 : */
661 : static struct AuditorDelRequest *adr_head;
662 :
663 : /**
664 : * Active auditor del requests.
665 : */
666 : static struct AuditorDelRequest *adr_tail;
667 :
668 : /**
669 : * Active wire add requests.
670 : */
671 : static struct WireAddRequest *war_head;
672 :
673 : /**
674 : * Active wire add requests.
675 : */
676 : static struct WireAddRequest *war_tail;
677 :
678 : /**
679 : * Active wire del requests.
680 : */
681 : static struct WireDelRequest *wdr_head;
682 :
683 : /**
684 : * Active wire del requests.
685 : */
686 : static struct WireDelRequest *wdr_tail;
687 :
688 : /**
689 : * Active wire fee requests.
690 : */
691 : static struct WireFeeRequest *wfr_head;
692 :
693 : /**
694 : * Active wire fee requests.
695 : */
696 : static struct WireFeeRequest *wfr_tail;
697 :
698 : /**
699 : * Active global fee requests.
700 : */
701 : static struct GlobalFeeRequest *gfr_head;
702 :
703 : /**
704 : * Active global fee requests.
705 : */
706 : static struct GlobalFeeRequest *gfr_tail;
707 :
708 : /**
709 : * Active keys upload requests.
710 : */
711 : static struct UploadKeysRequest *ukr_head;
712 :
713 : /**
714 : * Active keys upload requests.
715 : */
716 : static struct UploadKeysRequest *ukr_tail;
717 :
718 : /**
719 : * Active drain profits requests.
720 : */
721 : struct DrainProfitsRequest *dpr_head;
722 :
723 : /**
724 : * Active drain profits requests.
725 : */
726 : static struct DrainProfitsRequest *dpr_tail;
727 :
728 :
729 : /**
730 : * Shutdown task. Invoked when the application is being terminated.
731 : *
732 : * @param cls NULL
733 : */
734 : static void
735 40 : do_shutdown (void *cls)
736 : {
737 : (void) cls;
738 :
739 : {
740 : struct AmlStaffRequest *asr;
741 :
742 40 : while (NULL != (asr = asr_head))
743 : {
744 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
745 : "Aborting incomplete AML staff update #%u\n",
746 : (unsigned int) asr->idx);
747 0 : TALER_EXCHANGE_post_management_aml_officers_cancel (asr->h);
748 0 : GNUNET_CONTAINER_DLL_remove (asr_head,
749 : asr_tail,
750 : asr);
751 0 : GNUNET_free (asr);
752 : }
753 : }
754 : {
755 : struct PartnerAddRequest *par;
756 :
757 40 : while (NULL != (par = par_head))
758 : {
759 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
760 : "Aborting incomplete partner add request #%u\n",
761 : (unsigned int) par->idx);
762 0 : TALER_EXCHANGE_post_management_partners_cancel (par->h);
763 0 : GNUNET_CONTAINER_DLL_remove (par_head,
764 : par_tail,
765 : par);
766 0 : GNUNET_free (par);
767 : }
768 : }
769 : {
770 : struct DenomRevocationRequest *drr;
771 :
772 40 : while (NULL != (drr = drr_head))
773 : {
774 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
775 : "Aborting incomplete denomination revocation #%u\n",
776 : (unsigned int) drr->idx);
777 0 : TALER_EXCHANGE_post_management_denominations_revoke_cancel (drr->h);
778 0 : GNUNET_CONTAINER_DLL_remove (drr_head,
779 : drr_tail,
780 : drr);
781 0 : GNUNET_free (drr);
782 : }
783 : }
784 : {
785 : struct SignkeyRevocationRequest *srr;
786 :
787 40 : while (NULL != (srr = srr_head))
788 : {
789 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
790 : "Aborting incomplete signkey revocation #%u\n",
791 : (unsigned int) srr->idx);
792 0 : TALER_EXCHANGE_post_management_signkeys_revoke_cancel (srr->h);
793 0 : GNUNET_CONTAINER_DLL_remove (srr_head,
794 : srr_tail,
795 : srr);
796 0 : GNUNET_free (srr);
797 : }
798 : }
799 :
800 : {
801 : struct AuditorAddRequest *aar;
802 :
803 40 : while (NULL != (aar = aar_head))
804 : {
805 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
806 : "Aborting incomplete auditor add #%u\n",
807 : (unsigned int) aar->idx);
808 0 : TALER_EXCHANGE_post_management_auditors_cancel (aar->h);
809 0 : GNUNET_CONTAINER_DLL_remove (aar_head,
810 : aar_tail,
811 : aar);
812 0 : GNUNET_free (aar);
813 : }
814 : }
815 : {
816 : struct AuditorDelRequest *adr;
817 :
818 40 : while (NULL != (adr = adr_head))
819 : {
820 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
821 : "Aborting incomplete auditor del #%u\n",
822 : (unsigned int) adr->idx);
823 0 : TALER_EXCHANGE_post_management_auditors_disable_cancel (adr->h);
824 0 : GNUNET_CONTAINER_DLL_remove (adr_head,
825 : adr_tail,
826 : adr);
827 0 : GNUNET_free (adr);
828 : }
829 : }
830 : {
831 : struct WireAddRequest *war;
832 :
833 40 : while (NULL != (war = war_head))
834 : {
835 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
836 : "Aborting incomplete wire add #%u\n",
837 : (unsigned int) war->idx);
838 0 : TALER_EXCHANGE_post_management_wire_cancel (war->h);
839 0 : GNUNET_CONTAINER_DLL_remove (war_head,
840 : war_tail,
841 : war);
842 0 : GNUNET_free (war);
843 : }
844 : }
845 : {
846 : struct WireDelRequest *wdr;
847 :
848 40 : while (NULL != (wdr = wdr_head))
849 : {
850 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
851 : "Aborting incomplete wire del #%u\n",
852 : (unsigned int) wdr->idx);
853 0 : TALER_EXCHANGE_post_management_wire_disable_cancel (wdr->h);
854 0 : GNUNET_CONTAINER_DLL_remove (wdr_head,
855 : wdr_tail,
856 : wdr);
857 0 : GNUNET_free (wdr);
858 : }
859 : }
860 : {
861 : struct WireFeeRequest *wfr;
862 :
863 40 : while (NULL != (wfr = wfr_head))
864 : {
865 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
866 : "Aborting incomplete wire fee #%u\n",
867 : (unsigned int) wfr->idx);
868 0 : TALER_EXCHANGE_post_management_wire_fees_cancel (wfr->h);
869 0 : GNUNET_CONTAINER_DLL_remove (wfr_head,
870 : wfr_tail,
871 : wfr);
872 0 : GNUNET_free (wfr);
873 : }
874 : }
875 : {
876 : struct GlobalFeeRequest *gfr;
877 :
878 40 : while (NULL != (gfr = gfr_head))
879 : {
880 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
881 : "Aborting incomplete global fee #%u\n",
882 : (unsigned int) gfr->idx);
883 0 : TALER_EXCHANGE_post_management_global_fees_cancel (gfr->h);
884 0 : GNUNET_CONTAINER_DLL_remove (gfr_head,
885 : gfr_tail,
886 : gfr);
887 0 : GNUNET_free (gfr);
888 : }
889 : }
890 : {
891 : struct UploadKeysRequest *ukr;
892 :
893 40 : while (NULL != (ukr = ukr_head))
894 : {
895 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
896 : "Aborting incomplete key signature upload #%u\n",
897 : (unsigned int) ukr->idx);
898 0 : TALER_EXCHANGE_post_management_keys_cancel (ukr->h);
899 0 : GNUNET_CONTAINER_DLL_remove (ukr_head,
900 : ukr_tail,
901 : ukr);
902 0 : GNUNET_free (ukr);
903 : }
904 : }
905 :
906 : {
907 : struct DrainProfitsRequest *dpr;
908 :
909 40 : while (NULL != (dpr = dpr_head))
910 : {
911 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
912 : "Aborting incomplete drain profits request #%u\n",
913 : (unsigned int) dpr->idx);
914 0 : TALER_EXCHANGE_post_management_drain_cancel (dpr->h);
915 0 : GNUNET_CONTAINER_DLL_remove (dpr_head,
916 : dpr_tail,
917 : dpr);
918 0 : GNUNET_free (dpr);
919 : }
920 : }
921 :
922 40 : if (NULL != out)
923 : {
924 0 : if (EXIT_SUCCESS == global_ret)
925 0 : json_dumpf (out,
926 : stdout,
927 : JSON_INDENT (2));
928 0 : json_decref (out);
929 0 : out = NULL;
930 : }
931 40 : if (NULL != in)
932 : {
933 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
934 : "Input not consumed!\n");
935 0 : json_decref (in);
936 0 : in = NULL;
937 : }
938 40 : if (NULL != nxt)
939 : {
940 0 : GNUNET_SCHEDULER_cancel (nxt);
941 0 : nxt = NULL;
942 : }
943 40 : if (NULL != mgkh)
944 : {
945 0 : TALER_EXCHANGE_get_management_keys_cancel (mgkh);
946 0 : mgkh = NULL;
947 : }
948 40 : if (NULL != ctx)
949 : {
950 40 : GNUNET_CURL_fini (ctx);
951 40 : ctx = NULL;
952 : }
953 40 : if (NULL != rc)
954 : {
955 40 : GNUNET_CURL_gnunet_rc_destroy (rc);
956 40 : rc = NULL;
957 : }
958 40 : }
959 :
960 :
961 : /**
962 : * Test if we should shut down because all tasks are done.
963 : */
964 : static void
965 108 : test_shutdown (void)
966 : {
967 108 : if ( (NULL == drr_head) &&
968 108 : (NULL == par_head) &&
969 108 : (NULL == asr_head) &&
970 108 : (NULL == srr_head) &&
971 108 : (NULL == aar_head) &&
972 108 : (NULL == adr_head) &&
973 108 : (NULL == war_head) &&
974 108 : (NULL == wdr_head) &&
975 108 : (NULL == wfr_head) &&
976 74 : (NULL == gfr_head) &&
977 40 : (NULL == ukr_head) &&
978 40 : (NULL == dpr_head) &&
979 40 : (NULL == mgkh) &&
980 40 : (NULL == nxt) )
981 40 : GNUNET_SCHEDULER_shutdown ();
982 108 : }
983 :
984 :
985 : /**
986 : * Function to continue processing the next command.
987 : *
988 : * @param cls must be a `char *const*` with the array of
989 : * command-line arguments to process next
990 : */
991 : static void
992 : work (void *cls);
993 :
994 :
995 : /**
996 : * Function to schedule job to process the next command.
997 : *
998 : * @param args the array of command-line arguments to process next
999 : */
1000 : static void
1001 167 : next (char *const *args)
1002 : {
1003 167 : GNUNET_assert (NULL == nxt);
1004 167 : if (NULL == args[0])
1005 : {
1006 0 : test_shutdown ();
1007 0 : return;
1008 : }
1009 167 : nxt = GNUNET_SCHEDULER_add_now (&work,
1010 : (void *) args);
1011 : }
1012 :
1013 :
1014 : /**
1015 : * Add an operation to the #out JSON array for processing later.
1016 : *
1017 : * @param op_name name of the operation
1018 : * @param op_value values for the operation (consumed)
1019 : */
1020 : static void
1021 108 : output_operation (const char *op_name,
1022 : json_t *op_value)
1023 : {
1024 : json_t *action;
1025 :
1026 108 : GNUNET_break (NULL != op_value);
1027 108 : if (NULL == out)
1028 : {
1029 40 : out = json_array ();
1030 40 : GNUNET_assert (NULL != out);
1031 : }
1032 108 : action = GNUNET_JSON_PACK (
1033 : GNUNET_JSON_pack_string ("operation",
1034 : op_name),
1035 : GNUNET_JSON_pack_object_steal ("arguments",
1036 : op_value));
1037 108 : GNUNET_assert (0 ==
1038 : json_array_append_new (out,
1039 : action));
1040 108 : }
1041 :
1042 :
1043 : /**
1044 : * Information about a subroutine for an upload.
1045 : */
1046 : struct UploadHandler
1047 : {
1048 : /**
1049 : * Key to trigger this subroutine.
1050 : */
1051 : const char *key;
1052 :
1053 : /**
1054 : * Function implementing an upload.
1055 : *
1056 : * @param exchange_url URL of the exchange
1057 : * @param idx index of the operation we are performing
1058 : * @param value arguments to drive the upload.
1059 : */
1060 : void (*cb)(const char *exchange_url,
1061 : size_t idx,
1062 : const json_t *value);
1063 :
1064 : };
1065 :
1066 :
1067 : /**
1068 : * Load the offline key (if not yet done). Triggers shutdown on failure.
1069 : *
1070 : * @param do_create #GNUNET_YES if the key may be created
1071 : * @return #GNUNET_OK on success
1072 : */
1073 : static enum GNUNET_GenericReturnValue
1074 108 : load_offline_key (int do_create)
1075 : {
1076 : static bool done;
1077 : int ret;
1078 : char *fn;
1079 :
1080 108 : if (done)
1081 68 : return GNUNET_OK;
1082 40 : if (GNUNET_OK !=
1083 40 : GNUNET_CONFIGURATION_get_value_filename (kcfg,
1084 : "exchange-offline",
1085 : "MASTER_PRIV_FILE",
1086 : &fn))
1087 : {
1088 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1089 : "exchange-offline",
1090 : "MASTER_PRIV_FILE");
1091 0 : test_shutdown ();
1092 0 : return GNUNET_SYSERR;
1093 : }
1094 40 : if (GNUNET_YES !=
1095 40 : GNUNET_DISK_file_test (fn))
1096 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1097 : "Exchange master private key `%s' does not exist yet, creating it!\n",
1098 : fn);
1099 40 : ret = GNUNET_CRYPTO_eddsa_key_from_file (fn,
1100 : do_create,
1101 : &master_priv.eddsa_priv);
1102 40 : if (GNUNET_SYSERR == ret)
1103 : {
1104 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1105 : "Failed to initialize master key from file `%s': %s\n",
1106 : fn,
1107 : "could not create file");
1108 0 : GNUNET_free (fn);
1109 0 : test_shutdown ();
1110 0 : return GNUNET_SYSERR;
1111 : }
1112 40 : GNUNET_free (fn);
1113 40 : GNUNET_CRYPTO_eddsa_key_get_public (&master_priv.eddsa_priv,
1114 : &master_pub.eddsa_pub);
1115 40 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1116 : "Using master public key %s\n",
1117 : TALER_B2S (&master_pub));
1118 40 : done = true;
1119 40 : return GNUNET_OK;
1120 : }
1121 :
1122 :
1123 : /**
1124 : * Function called with information about the post revocation operation result.
1125 : *
1126 : * @param drr the revocation request
1127 : * @param dr response data
1128 : */
1129 : static void
1130 0 : denom_revocation_cb (
1131 : struct DenomRevocationRequest *drr,
1132 : const struct TALER_EXCHANGE_PostManagementDenominationsRevokeResponse *dr)
1133 : {
1134 0 : const struct TALER_EXCHANGE_HttpResponse *hr = &dr->hr;
1135 :
1136 0 : if (MHD_HTTP_NO_CONTENT != hr->http_status)
1137 : {
1138 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1139 : "Upload failed for command %u with status %u: %s (%s)\n",
1140 : (unsigned int) drr->idx,
1141 : hr->http_status,
1142 : hr->hint,
1143 : TALER_JSON_get_error_hint (hr->reply));
1144 0 : global_ret = EXIT_FAILURE;
1145 : }
1146 0 : GNUNET_CONTAINER_DLL_remove (drr_head,
1147 : drr_tail,
1148 : drr);
1149 0 : GNUNET_free (drr);
1150 0 : test_shutdown ();
1151 0 : }
1152 :
1153 :
1154 : /**
1155 : * Upload denomination revocation request data.
1156 : *
1157 : * @param exchange_url base URL of the exchange
1158 : * @param idx index of the operation we are performing (for logging)
1159 : * @param value arguments for denomination revocation
1160 : */
1161 : static void
1162 0 : upload_denom_revocation (const char *exchange_url,
1163 : size_t idx,
1164 : const json_t *value)
1165 : {
1166 : struct TALER_MasterSignatureP master_sig;
1167 : struct TALER_DenominationHashP h_denom_pub;
1168 : struct DenomRevocationRequest *drr;
1169 : const char *err_name;
1170 : unsigned int err_line;
1171 : struct GNUNET_JSON_Specification spec[] = {
1172 0 : GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
1173 : &h_denom_pub),
1174 0 : GNUNET_JSON_spec_fixed_auto ("master_sig",
1175 : &master_sig),
1176 0 : GNUNET_JSON_spec_end ()
1177 : };
1178 :
1179 0 : if (GNUNET_OK !=
1180 0 : GNUNET_JSON_parse (value,
1181 : spec,
1182 : &err_name,
1183 : &err_line))
1184 : {
1185 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1186 : "Invalid input for denomination revocation: %s#%u at %u (skipping)\n",
1187 : err_name,
1188 : err_line,
1189 : (unsigned int) idx);
1190 0 : json_dumpf (value,
1191 : stderr,
1192 : JSON_INDENT (2));
1193 0 : global_ret = EXIT_FAILURE;
1194 0 : GNUNET_SCHEDULER_shutdown ();
1195 0 : return;
1196 : }
1197 0 : drr = GNUNET_new (struct DenomRevocationRequest);
1198 0 : drr->idx = idx;
1199 0 : drr->h =
1200 0 : TALER_EXCHANGE_post_management_denominations_revoke_create (ctx,
1201 : exchange_url,
1202 : &h_denom_pub,
1203 : &master_sig);
1204 0 : TALER_EXCHANGE_post_management_denominations_revoke_start (drr->h,
1205 : &
1206 : denom_revocation_cb,
1207 : drr);
1208 0 : GNUNET_CONTAINER_DLL_insert (drr_head,
1209 : drr_tail,
1210 : drr);
1211 : }
1212 :
1213 :
1214 : /**
1215 : * Function called with information about the post revocation operation result.
1216 : *
1217 : * @param srr the revocation request
1218 : * @param sr response data
1219 : */
1220 : static void
1221 0 : signkey_revocation_cb (
1222 : struct SignkeyRevocationRequest *srr,
1223 : const struct TALER_EXCHANGE_PostManagementSignkeysRevokeResponse *sr)
1224 : {
1225 0 : const struct TALER_EXCHANGE_HttpResponse *hr = &sr->hr;
1226 :
1227 0 : if (MHD_HTTP_NO_CONTENT != hr->http_status)
1228 : {
1229 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1230 : "Upload failed for command %u with status %u: %s (%s)\n",
1231 : (unsigned int) srr->idx,
1232 : hr->http_status,
1233 : hr->hint,
1234 : TALER_JSON_get_error_hint (hr->reply));
1235 0 : global_ret = EXIT_FAILURE;
1236 : }
1237 0 : GNUNET_CONTAINER_DLL_remove (srr_head,
1238 : srr_tail,
1239 : srr);
1240 0 : GNUNET_free (srr);
1241 0 : test_shutdown ();
1242 0 : }
1243 :
1244 :
1245 : /**
1246 : * Upload signkey revocation request data.
1247 : *
1248 : * @param exchange_url base URL of the exchange
1249 : * @param idx index of the operation we are performing (for logging)
1250 : * @param value arguments for denomination revocation
1251 : */
1252 : static void
1253 0 : upload_signkey_revocation (const char *exchange_url,
1254 : size_t idx,
1255 : const json_t *value)
1256 : {
1257 : struct TALER_MasterSignatureP master_sig;
1258 : struct TALER_ExchangePublicKeyP exchange_pub;
1259 : struct SignkeyRevocationRequest *srr;
1260 : const char *err_name;
1261 : unsigned int err_line;
1262 : struct GNUNET_JSON_Specification spec[] = {
1263 0 : GNUNET_JSON_spec_fixed_auto ("exchange_pub",
1264 : &exchange_pub),
1265 0 : GNUNET_JSON_spec_fixed_auto ("master_sig",
1266 : &master_sig),
1267 0 : GNUNET_JSON_spec_end ()
1268 : };
1269 :
1270 0 : if (GNUNET_OK !=
1271 0 : GNUNET_JSON_parse (value,
1272 : spec,
1273 : &err_name,
1274 : &err_line))
1275 : {
1276 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1277 : "Invalid input for signkey revocation: %s#%u at %u (skipping)\n",
1278 : err_name,
1279 : err_line,
1280 : (unsigned int) idx);
1281 0 : json_dumpf (value,
1282 : stderr,
1283 : JSON_INDENT (2));
1284 0 : global_ret = EXIT_FAILURE;
1285 0 : GNUNET_SCHEDULER_shutdown ();
1286 0 : return;
1287 : }
1288 0 : srr = GNUNET_new (struct SignkeyRevocationRequest);
1289 0 : srr->idx = idx;
1290 0 : srr->h =
1291 0 : TALER_EXCHANGE_post_management_signkeys_revoke_create (ctx,
1292 : exchange_url,
1293 : &exchange_pub,
1294 : &master_sig);
1295 0 : TALER_EXCHANGE_post_management_signkeys_revoke_start (srr->h,
1296 : &signkey_revocation_cb,
1297 : srr);
1298 0 : GNUNET_CONTAINER_DLL_insert (srr_head,
1299 : srr_tail,
1300 : srr);
1301 : }
1302 :
1303 :
1304 : /**
1305 : * Function called with information about the post auditor add operation result.
1306 : *
1307 : * @param aar the auditor add request
1308 : * @param mer response data
1309 : */
1310 : static void
1311 4 : auditor_add_cb (
1312 : struct AuditorAddRequest *aar,
1313 : const struct TALER_EXCHANGE_PostManagementAuditorsResponse *mer)
1314 : {
1315 4 : const struct TALER_EXCHANGE_HttpResponse *hr = &mer->hr;
1316 :
1317 4 : if (MHD_HTTP_NO_CONTENT != hr->http_status)
1318 : {
1319 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1320 : "Upload failed for command %u with status %u: %s (%s)\n",
1321 : (unsigned int) aar->idx,
1322 : hr->http_status,
1323 : TALER_ErrorCode_get_hint (hr->ec),
1324 : hr->hint);
1325 0 : global_ret = EXIT_FAILURE;
1326 : }
1327 4 : GNUNET_CONTAINER_DLL_remove (aar_head,
1328 : aar_tail,
1329 : aar);
1330 4 : GNUNET_free (aar);
1331 4 : test_shutdown ();
1332 4 : }
1333 :
1334 :
1335 : /**
1336 : * Upload auditor add data.
1337 : *
1338 : * @param exchange_url base URL of the exchange
1339 : * @param idx index of the operation we are performing (for logging)
1340 : * @param value arguments for denomination revocation
1341 : */
1342 : static void
1343 4 : upload_auditor_add (const char *exchange_url,
1344 : size_t idx,
1345 : const json_t *value)
1346 : {
1347 : struct TALER_MasterSignatureP master_sig;
1348 : const char *auditor_url;
1349 : const char *auditor_name;
1350 : struct GNUNET_TIME_Timestamp start_time;
1351 : struct TALER_AuditorPublicKeyP auditor_pub;
1352 : struct AuditorAddRequest *aar;
1353 : const char *err_name;
1354 : unsigned int err_line;
1355 : struct GNUNET_JSON_Specification spec[] = {
1356 4 : TALER_JSON_spec_web_url ("auditor_url",
1357 : &auditor_url),
1358 4 : GNUNET_JSON_spec_string ("auditor_name",
1359 : &auditor_name),
1360 4 : GNUNET_JSON_spec_timestamp ("validity_start",
1361 : &start_time),
1362 4 : GNUNET_JSON_spec_fixed_auto ("auditor_pub",
1363 : &auditor_pub),
1364 4 : GNUNET_JSON_spec_fixed_auto ("master_sig",
1365 : &master_sig),
1366 4 : GNUNET_JSON_spec_end ()
1367 : };
1368 :
1369 4 : if (GNUNET_OK !=
1370 4 : GNUNET_JSON_parse (value,
1371 : spec,
1372 : &err_name,
1373 : &err_line))
1374 : {
1375 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1376 : "Invalid input for adding auditor: %s#%u at %u (skipping)\n",
1377 : err_name,
1378 : err_line,
1379 : (unsigned int) idx);
1380 0 : json_dumpf (value,
1381 : stderr,
1382 : JSON_INDENT (2));
1383 0 : global_ret = EXIT_FAILURE;
1384 0 : GNUNET_SCHEDULER_shutdown ();
1385 0 : return;
1386 : }
1387 4 : aar = GNUNET_new (struct AuditorAddRequest);
1388 4 : aar->idx = idx;
1389 4 : aar->h =
1390 4 : TALER_EXCHANGE_post_management_auditors_create (ctx,
1391 : exchange_url,
1392 : &auditor_pub,
1393 : auditor_url,
1394 : auditor_name,
1395 : start_time,
1396 : &master_sig);
1397 4 : TALER_EXCHANGE_post_management_auditors_start (aar->h,
1398 : &auditor_add_cb,
1399 : aar);
1400 4 : GNUNET_CONTAINER_DLL_insert (aar_head,
1401 : aar_tail,
1402 : aar);
1403 : }
1404 :
1405 :
1406 : /**
1407 : * Function called with information about the post auditor del operation result.
1408 : *
1409 : * @param adr auditor delete request
1410 : * @param mdr response data
1411 : */
1412 : static void
1413 0 : auditor_del_cb (
1414 : struct AuditorDelRequest *adr,
1415 : const struct TALER_EXCHANGE_PostManagementAuditorsDisableResponse *mdr)
1416 : {
1417 0 : const struct TALER_EXCHANGE_HttpResponse *hr = &mdr->hr;
1418 :
1419 0 : if (MHD_HTTP_NO_CONTENT != hr->http_status)
1420 : {
1421 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1422 : "Upload failed for command %u with status %u: %s (%s)\n",
1423 : (unsigned int) adr->idx,
1424 : hr->http_status,
1425 : TALER_ErrorCode_get_hint (hr->ec),
1426 : hr->hint);
1427 0 : global_ret = EXIT_FAILURE;
1428 : }
1429 0 : GNUNET_CONTAINER_DLL_remove (adr_head,
1430 : adr_tail,
1431 : adr);
1432 0 : GNUNET_free (adr);
1433 0 : test_shutdown ();
1434 0 : }
1435 :
1436 :
1437 : /**
1438 : * Upload auditor del data.
1439 : *
1440 : * @param exchange_url base URL of the exchange
1441 : * @param idx index of the operation we are performing (for logging)
1442 : * @param value arguments for denomination revocation
1443 : */
1444 : static void
1445 0 : upload_auditor_del (const char *exchange_url,
1446 : size_t idx,
1447 : const json_t *value)
1448 : {
1449 : struct TALER_AuditorPublicKeyP auditor_pub;
1450 : struct TALER_MasterSignatureP master_sig;
1451 : struct GNUNET_TIME_Timestamp end_time;
1452 : struct AuditorDelRequest *adr;
1453 : const char *err_name;
1454 : unsigned int err_line;
1455 : struct GNUNET_JSON_Specification spec[] = {
1456 0 : GNUNET_JSON_spec_fixed_auto ("auditor_pub",
1457 : &auditor_pub),
1458 0 : GNUNET_JSON_spec_timestamp ("validity_end",
1459 : &end_time),
1460 0 : GNUNET_JSON_spec_fixed_auto ("master_sig",
1461 : &master_sig),
1462 0 : GNUNET_JSON_spec_end ()
1463 : };
1464 :
1465 0 : if (GNUNET_OK !=
1466 0 : GNUNET_JSON_parse (value,
1467 : spec,
1468 : &err_name,
1469 : &err_line))
1470 : {
1471 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1472 : "Invalid input to disable auditor: %s#%u at %u (skipping)\n",
1473 : err_name,
1474 : err_line,
1475 : (unsigned int) idx);
1476 0 : json_dumpf (value,
1477 : stderr,
1478 : JSON_INDENT (2));
1479 0 : global_ret = EXIT_FAILURE;
1480 0 : GNUNET_SCHEDULER_shutdown ();
1481 0 : return;
1482 : }
1483 0 : adr = GNUNET_new (struct AuditorDelRequest);
1484 0 : adr->idx = idx;
1485 0 : adr->h =
1486 0 : TALER_EXCHANGE_post_management_auditors_disable_create (ctx,
1487 : exchange_url,
1488 : &auditor_pub,
1489 : end_time,
1490 : &master_sig);
1491 0 : TALER_EXCHANGE_post_management_auditors_disable_start (adr->h,
1492 : &auditor_del_cb,
1493 : adr);
1494 0 : GNUNET_CONTAINER_DLL_insert (adr_head,
1495 : adr_tail,
1496 : adr);
1497 : }
1498 :
1499 :
1500 : /**
1501 : * Function called with information about the post wire add operation result.
1502 : *
1503 : * @param war the wire add request
1504 : * @param wer response data
1505 : */
1506 : static void
1507 17 : wire_add_cb (
1508 : struct WireAddRequest *war,
1509 : const struct TALER_EXCHANGE_PostManagementWireResponse *wer)
1510 : {
1511 17 : const struct TALER_EXCHANGE_HttpResponse *hr = &wer->hr;
1512 :
1513 17 : if (MHD_HTTP_NO_CONTENT != hr->http_status)
1514 : {
1515 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1516 : "Upload failed for command %u with status %u: %s (%s)\n",
1517 : (unsigned int) war->idx,
1518 : hr->http_status,
1519 : TALER_ErrorCode_get_hint (hr->ec),
1520 : hr->hint);
1521 0 : global_ret = EXIT_FAILURE;
1522 : }
1523 17 : GNUNET_CONTAINER_DLL_remove (war_head,
1524 : war_tail,
1525 : war);
1526 17 : GNUNET_free (war);
1527 17 : test_shutdown ();
1528 17 : }
1529 :
1530 :
1531 : /**
1532 : * Upload wire add data.
1533 : *
1534 : * @param exchange_url base URL of the exchange
1535 : * @param idx index of the operation we are performing (for logging)
1536 : * @param value arguments for denomination revocation
1537 : */
1538 : static void
1539 17 : upload_wire_add (const char *exchange_url,
1540 : size_t idx,
1541 : const json_t *value)
1542 : {
1543 : struct TALER_MasterSignatureP master_sig_add;
1544 : struct TALER_MasterSignatureP master_sig_wire;
1545 : struct TALER_FullPayto payto_uri;
1546 : struct GNUNET_TIME_Timestamp start_time;
1547 : struct WireAddRequest *war;
1548 : const char *err_name;
1549 17 : const char *conversion_url = NULL;
1550 17 : const char *open_banking_gateway = NULL;
1551 17 : const char *prepared_transfer_url = NULL;
1552 17 : const char *bank_label = NULL;
1553 17 : int64_t priority = 0;
1554 : const json_t *debit_restrictions;
1555 : const json_t *credit_restrictions;
1556 : unsigned int err_line;
1557 : struct GNUNET_JSON_Specification spec[] = {
1558 17 : TALER_JSON_spec_full_payto_uri ("payto_uri",
1559 : &payto_uri),
1560 17 : GNUNET_JSON_spec_mark_optional (
1561 : TALER_JSON_spec_web_url ("conversion_url",
1562 : &conversion_url),
1563 : NULL),
1564 17 : GNUNET_JSON_spec_mark_optional (
1565 : TALER_JSON_spec_web_url ("open_banking_gateway",
1566 : &open_banking_gateway),
1567 : NULL),
1568 17 : GNUNET_JSON_spec_mark_optional (
1569 : TALER_JSON_spec_web_url ("prepared_transfer_url",
1570 : &prepared_transfer_url),
1571 : NULL),
1572 17 : GNUNET_JSON_spec_mark_optional (
1573 : GNUNET_JSON_spec_string ("bank_label",
1574 : &bank_label),
1575 : NULL),
1576 17 : GNUNET_JSON_spec_int64 ("priority",
1577 : &priority),
1578 17 : GNUNET_JSON_spec_array_const ("debit_restrictions",
1579 : &debit_restrictions),
1580 17 : GNUNET_JSON_spec_array_const ("credit_restrictions",
1581 : &credit_restrictions),
1582 17 : GNUNET_JSON_spec_timestamp ("validity_start",
1583 : &start_time),
1584 17 : GNUNET_JSON_spec_fixed_auto ("master_sig_add",
1585 : &master_sig_add),
1586 17 : GNUNET_JSON_spec_fixed_auto ("master_sig_wire",
1587 : &master_sig_wire),
1588 17 : GNUNET_JSON_spec_end ()
1589 : };
1590 :
1591 17 : if (GNUNET_OK !=
1592 17 : GNUNET_JSON_parse (value,
1593 : spec,
1594 : &err_name,
1595 : &err_line))
1596 : {
1597 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1598 : "Invalid input for adding wire account: %s#%u at %u (skipping)\n",
1599 : err_name,
1600 : err_line,
1601 : (unsigned int) idx);
1602 0 : json_dumpf (value,
1603 : stderr,
1604 : JSON_INDENT (2));
1605 0 : global_ret = EXIT_FAILURE;
1606 0 : GNUNET_SCHEDULER_shutdown ();
1607 0 : return;
1608 : }
1609 : {
1610 : char *wire_method;
1611 :
1612 17 : wire_method = TALER_payto_get_method (payto_uri.full_payto);
1613 17 : if (NULL == wire_method)
1614 : {
1615 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1616 : "payto:// URI `%s' is malformed\n",
1617 : payto_uri.full_payto);
1618 0 : global_ret = EXIT_FAILURE;
1619 0 : GNUNET_SCHEDULER_shutdown ();
1620 0 : return;
1621 : }
1622 17 : GNUNET_free (wire_method);
1623 : }
1624 : {
1625 17 : char *msg = TALER_payto_validate (payto_uri);
1626 :
1627 17 : if (NULL != msg)
1628 : {
1629 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1630 : "payto URI is malformed: %s\n",
1631 : msg);
1632 0 : GNUNET_free (msg);
1633 0 : GNUNET_SCHEDULER_shutdown ();
1634 0 : global_ret = EXIT_INVALIDARGUMENT;
1635 0 : return;
1636 : }
1637 : }
1638 17 : war = GNUNET_new (struct WireAddRequest);
1639 17 : war->idx = idx;
1640 17 : war->h =
1641 17 : TALER_EXCHANGE_post_management_wire_create (ctx,
1642 : exchange_url,
1643 : payto_uri,
1644 : start_time,
1645 : &master_sig_add,
1646 : &master_sig_wire);
1647 17 : TALER_EXCHANGE_post_management_wire_set_options (
1648 : war->h,
1649 : TALER_EXCHANGE_post_management_wire_option_bank_label (bank_label),
1650 : TALER_EXCHANGE_post_management_wire_option_conversion_url (conversion_url),
1651 : TALER_EXCHANGE_post_management_wire_option_open_banking_gateway (
1652 : open_banking_gateway),
1653 : TALER_EXCHANGE_post_management_wire_option_prepared_transfer_url (
1654 : prepared_transfer_url),
1655 : TALER_EXCHANGE_post_management_wire_option_debit_restrictions (
1656 : debit_restrictions),
1657 : TALER_EXCHANGE_post_management_wire_option_credit_restrictions (
1658 : credit_restrictions),
1659 : TALER_EXCHANGE_post_management_wire_option_priority (priority));
1660 17 : TALER_EXCHANGE_post_management_wire_start (war->h,
1661 : &wire_add_cb,
1662 : war);
1663 17 : GNUNET_CONTAINER_DLL_insert (war_head,
1664 : war_tail,
1665 : war);
1666 : }
1667 :
1668 :
1669 : /**
1670 : * Function called with information about the post wire del operation result.
1671 : *
1672 : * @param wdr request to delete wire account
1673 : * @param wdres response data
1674 : */
1675 : static void
1676 0 : wire_del_cb (
1677 : struct WireDelRequest *wdr,
1678 : const struct TALER_EXCHANGE_PostManagementWireDisableResponse *wdres)
1679 : {
1680 0 : const struct TALER_EXCHANGE_HttpResponse *hr = &wdres->hr;
1681 :
1682 0 : if (MHD_HTTP_NO_CONTENT != hr->http_status)
1683 : {
1684 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1685 : "Upload failed for command %u with status %u: %s (%s)\n",
1686 : (unsigned int) wdr->idx,
1687 : hr->http_status,
1688 : TALER_ErrorCode_get_hint (hr->ec),
1689 : hr->hint);
1690 0 : global_ret = EXIT_FAILURE;
1691 : }
1692 0 : GNUNET_CONTAINER_DLL_remove (wdr_head,
1693 : wdr_tail,
1694 : wdr);
1695 0 : GNUNET_free (wdr);
1696 0 : test_shutdown ();
1697 0 : }
1698 :
1699 :
1700 : /**
1701 : * Upload wire del data.
1702 : *
1703 : * @param exchange_url base URL of the exchange
1704 : * @param idx index of the operation we are performing (for logging)
1705 : * @param value arguments for denomination revocation
1706 : */
1707 : static void
1708 0 : upload_wire_del (const char *exchange_url,
1709 : size_t idx,
1710 : const json_t *value)
1711 : {
1712 : struct TALER_MasterSignatureP master_sig;
1713 : struct TALER_FullPayto payto_uri;
1714 : struct GNUNET_TIME_Timestamp end_time;
1715 : struct WireDelRequest *wdr;
1716 : const char *err_name;
1717 : unsigned int err_line;
1718 : struct GNUNET_JSON_Specification spec[] = {
1719 0 : TALER_JSON_spec_full_payto_uri ("payto_uri",
1720 : &payto_uri),
1721 0 : GNUNET_JSON_spec_timestamp ("validity_end",
1722 : &end_time),
1723 0 : GNUNET_JSON_spec_fixed_auto ("master_sig",
1724 : &master_sig),
1725 0 : GNUNET_JSON_spec_end ()
1726 : };
1727 :
1728 0 : if (GNUNET_OK !=
1729 0 : GNUNET_JSON_parse (value,
1730 : spec,
1731 : &err_name,
1732 : &err_line))
1733 : {
1734 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1735 : "Invalid input to disable wire account: %s#%u at %u (skipping)\n",
1736 : err_name,
1737 : err_line,
1738 : (unsigned int) idx);
1739 0 : json_dumpf (value,
1740 : stderr,
1741 : JSON_INDENT (2));
1742 0 : global_ret = EXIT_FAILURE;
1743 0 : GNUNET_SCHEDULER_shutdown ();
1744 0 : return;
1745 : }
1746 0 : wdr = GNUNET_new (struct WireDelRequest);
1747 0 : wdr->idx = idx;
1748 0 : wdr->h =
1749 0 : TALER_EXCHANGE_post_management_wire_disable_create (ctx,
1750 : exchange_url,
1751 : payto_uri,
1752 : end_time,
1753 : &master_sig);
1754 0 : TALER_EXCHANGE_post_management_wire_disable_start (wdr->h,
1755 : &wire_del_cb,
1756 : wdr);
1757 0 : GNUNET_CONTAINER_DLL_insert (wdr_head,
1758 : wdr_tail,
1759 : wdr);
1760 : }
1761 :
1762 :
1763 : /**
1764 : * Function called with information about the post wire fee operation result.
1765 : *
1766 : * @param wfr the wire fee request
1767 : * @param swr response data
1768 : */
1769 : static void
1770 34 : wire_fee_cb (
1771 : struct WireFeeRequest *wfr,
1772 : const struct TALER_EXCHANGE_PostManagementWireFeesResponse *swr)
1773 : {
1774 34 : const struct TALER_EXCHANGE_HttpResponse *hr = &swr->hr;
1775 :
1776 34 : if (MHD_HTTP_NO_CONTENT != hr->http_status)
1777 : {
1778 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1779 : "Upload failed for command %u with status %u: %s (%s)\n",
1780 : (unsigned int) wfr->idx,
1781 : hr->http_status,
1782 : TALER_ErrorCode_get_hint (hr->ec),
1783 : hr->hint);
1784 0 : global_ret = EXIT_FAILURE;
1785 : }
1786 34 : GNUNET_CONTAINER_DLL_remove (wfr_head,
1787 : wfr_tail,
1788 : wfr);
1789 34 : GNUNET_free (wfr);
1790 34 : test_shutdown ();
1791 34 : }
1792 :
1793 :
1794 : /**
1795 : * Upload wire fee.
1796 : *
1797 : * @param exchange_url base URL of the exchange
1798 : * @param idx index of the operation we are performing (for logging)
1799 : * @param value arguments for denomination revocation
1800 : */
1801 : static void
1802 34 : upload_wire_fee (const char *exchange_url,
1803 : size_t idx,
1804 : const json_t *value)
1805 : {
1806 : struct TALER_MasterSignatureP master_sig;
1807 : const char *wire_method;
1808 : struct WireFeeRequest *wfr;
1809 : const char *err_name;
1810 : unsigned int err_line;
1811 : struct TALER_WireFeeSet fees;
1812 : struct GNUNET_TIME_Timestamp start_time;
1813 : struct GNUNET_TIME_Timestamp end_time;
1814 : struct GNUNET_JSON_Specification spec[] = {
1815 34 : GNUNET_JSON_spec_string ("wire_method",
1816 : &wire_method),
1817 34 : TALER_JSON_spec_amount ("wire_fee",
1818 : currency,
1819 : &fees.wire),
1820 34 : TALER_JSON_spec_amount ("closing_fee",
1821 : currency,
1822 : &fees.closing),
1823 34 : GNUNET_JSON_spec_timestamp ("start_time",
1824 : &start_time),
1825 34 : GNUNET_JSON_spec_timestamp ("end_time",
1826 : &end_time),
1827 34 : GNUNET_JSON_spec_fixed_auto ("master_sig",
1828 : &master_sig),
1829 34 : GNUNET_JSON_spec_end ()
1830 : };
1831 :
1832 34 : if (GNUNET_OK !=
1833 34 : GNUNET_JSON_parse (value,
1834 : spec,
1835 : &err_name,
1836 : &err_line))
1837 : {
1838 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1839 : "Invalid input to set wire fee: %s#%u at %u (skipping)\n",
1840 : err_name,
1841 : err_line,
1842 : (unsigned int) idx);
1843 0 : json_dumpf (value,
1844 : stderr,
1845 : JSON_INDENT (2));
1846 0 : global_ret = EXIT_FAILURE;
1847 0 : GNUNET_SCHEDULER_shutdown ();
1848 0 : return;
1849 : }
1850 34 : wfr = GNUNET_new (struct WireFeeRequest);
1851 34 : wfr->idx = idx;
1852 34 : wfr->h =
1853 34 : TALER_EXCHANGE_post_management_wire_fees_create (ctx,
1854 : exchange_url,
1855 : wire_method,
1856 : start_time,
1857 : end_time,
1858 : &fees,
1859 : &master_sig);
1860 34 : TALER_EXCHANGE_post_management_wire_fees_start (wfr->h,
1861 : &wire_fee_cb,
1862 : wfr);
1863 34 : GNUNET_CONTAINER_DLL_insert (wfr_head,
1864 : wfr_tail,
1865 : wfr);
1866 : }
1867 :
1868 :
1869 : /**
1870 : * Function called with information about the post global fee operation result.
1871 : *
1872 : * @param gfr the global fee request
1873 : * @param gr response data
1874 : */
1875 : static void
1876 34 : global_fee_cb (
1877 : struct GlobalFeeRequest *gfr,
1878 : const struct TALER_EXCHANGE_PostManagementGlobalFeesResponse *gr)
1879 : {
1880 34 : const struct TALER_EXCHANGE_HttpResponse *hr = &gr->hr;
1881 :
1882 34 : if (MHD_HTTP_NO_CONTENT != hr->http_status)
1883 : {
1884 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1885 : "Upload failed for command %u with status %u: %s (%s)\n",
1886 : (unsigned int) gfr->idx,
1887 : hr->http_status,
1888 : TALER_ErrorCode_get_hint (hr->ec),
1889 : hr->hint);
1890 0 : global_ret = EXIT_FAILURE;
1891 : }
1892 34 : GNUNET_CONTAINER_DLL_remove (gfr_head,
1893 : gfr_tail,
1894 : gfr);
1895 34 : GNUNET_free (gfr);
1896 34 : test_shutdown ();
1897 34 : }
1898 :
1899 :
1900 : /**
1901 : * Upload global fee.
1902 : *
1903 : * @param exchange_url base URL of the exchange
1904 : * @param idx index of the operation we are performing (for logging)
1905 : * @param value arguments for denomination revocation
1906 : */
1907 : static void
1908 34 : upload_global_fee (const char *exchange_url,
1909 : size_t idx,
1910 : const json_t *value)
1911 : {
1912 : struct TALER_MasterSignatureP master_sig;
1913 : struct GlobalFeeRequest *gfr;
1914 : const char *err_name;
1915 : unsigned int err_line;
1916 : struct TALER_GlobalFeeSet fees;
1917 : struct GNUNET_TIME_Timestamp start_time;
1918 : struct GNUNET_TIME_Timestamp end_time;
1919 : struct GNUNET_TIME_Relative purse_timeout;
1920 : struct GNUNET_TIME_Relative history_expiration;
1921 : uint32_t purse_account_limit;
1922 : struct GNUNET_JSON_Specification spec[] = {
1923 34 : TALER_JSON_spec_amount ("history_fee",
1924 : currency,
1925 : &fees.history),
1926 34 : TALER_JSON_spec_amount ("account_fee",
1927 : currency,
1928 : &fees.account),
1929 34 : TALER_JSON_spec_amount ("purse_fee",
1930 : currency,
1931 : &fees.purse),
1932 34 : GNUNET_JSON_spec_relative_time ("purse_timeout",
1933 : &purse_timeout),
1934 34 : GNUNET_JSON_spec_relative_time ("history_expiration",
1935 : &history_expiration),
1936 34 : GNUNET_JSON_spec_uint32 ("purse_account_limit",
1937 : &purse_account_limit),
1938 34 : GNUNET_JSON_spec_timestamp ("start_time",
1939 : &start_time),
1940 34 : GNUNET_JSON_spec_timestamp ("end_time",
1941 : &end_time),
1942 34 : GNUNET_JSON_spec_fixed_auto ("master_sig",
1943 : &master_sig),
1944 34 : GNUNET_JSON_spec_end ()
1945 : };
1946 :
1947 34 : if (GNUNET_OK !=
1948 34 : GNUNET_JSON_parse (value,
1949 : spec,
1950 : &err_name,
1951 : &err_line))
1952 : {
1953 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1954 : "Invalid input to set wire fee: %s#%u at %u (skipping)\n",
1955 : err_name,
1956 : err_line,
1957 : (unsigned int) idx);
1958 0 : json_dumpf (value,
1959 : stderr,
1960 : JSON_INDENT (2));
1961 0 : global_ret = EXIT_FAILURE;
1962 0 : GNUNET_SCHEDULER_shutdown ();
1963 0 : return;
1964 : }
1965 34 : gfr = GNUNET_new (struct GlobalFeeRequest);
1966 34 : gfr->idx = idx;
1967 34 : gfr->h =
1968 34 : TALER_EXCHANGE_post_management_global_fees_create (ctx,
1969 : exchange_url,
1970 : start_time,
1971 : end_time,
1972 : &fees,
1973 : purse_timeout,
1974 : history_expiration,
1975 : purse_account_limit,
1976 : &master_sig);
1977 34 : TALER_EXCHANGE_post_management_global_fees_start (gfr->h,
1978 : &global_fee_cb,
1979 : gfr);
1980 34 : GNUNET_CONTAINER_DLL_insert (gfr_head,
1981 : gfr_tail,
1982 : gfr);
1983 : }
1984 :
1985 :
1986 : /**
1987 : * Function called with information about the drain profits operation.
1988 : *
1989 : * @param dpr the drain profits request
1990 : * @param mdr response data
1991 : */
1992 : static void
1993 0 : drain_profits_cb (
1994 : struct DrainProfitsRequest *dpr,
1995 : const struct TALER_EXCHANGE_PostManagementDrainResponse *mdr)
1996 : {
1997 0 : const struct TALER_EXCHANGE_HttpResponse *hr = &mdr->hr;
1998 :
1999 0 : if (MHD_HTTP_NO_CONTENT != hr->http_status)
2000 : {
2001 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2002 : "Upload failed for command %u with status %u: %s (%s)\n",
2003 : (unsigned int) dpr->idx,
2004 : hr->http_status,
2005 : TALER_ErrorCode_get_hint (hr->ec),
2006 : hr->hint);
2007 0 : global_ret = EXIT_FAILURE;
2008 : }
2009 0 : GNUNET_CONTAINER_DLL_remove (dpr_head,
2010 : dpr_tail,
2011 : dpr);
2012 0 : GNUNET_free (dpr);
2013 0 : test_shutdown ();
2014 0 : }
2015 :
2016 :
2017 : /**
2018 : * Upload drain profit action.
2019 : *
2020 : * @param exchange_url base URL of the exchange
2021 : * @param idx index of the operation we are performing (for logging)
2022 : * @param value arguments for drain profits
2023 : */
2024 : static void
2025 0 : upload_drain (const char *exchange_url,
2026 : size_t idx,
2027 : const json_t *value)
2028 : {
2029 : struct TALER_WireTransferIdentifierRawP wtid;
2030 : struct TALER_MasterSignatureP master_sig;
2031 : const char *err_name;
2032 : unsigned int err_line;
2033 : struct TALER_Amount amount;
2034 : struct GNUNET_TIME_Timestamp date;
2035 : struct TALER_FullPayto payto_uri;
2036 : const char *account_section;
2037 : struct DrainProfitsRequest *dpr;
2038 : struct GNUNET_JSON_Specification spec[] = {
2039 0 : GNUNET_JSON_spec_fixed_auto ("wtid",
2040 : &wtid),
2041 0 : TALER_JSON_spec_amount ("amount",
2042 : currency,
2043 : &amount),
2044 0 : GNUNET_JSON_spec_timestamp ("date",
2045 : &date),
2046 0 : GNUNET_JSON_spec_string ("account_section",
2047 : &account_section),
2048 0 : TALER_JSON_spec_full_payto_uri ("payto_uri",
2049 : &payto_uri),
2050 0 : GNUNET_JSON_spec_fixed_auto ("master_sig",
2051 : &master_sig),
2052 0 : GNUNET_JSON_spec_end ()
2053 : };
2054 :
2055 0 : if (GNUNET_OK !=
2056 0 : GNUNET_JSON_parse (value,
2057 : spec,
2058 : &err_name,
2059 : &err_line))
2060 : {
2061 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2062 : "Invalid input to drain profits: %s#%u at %u (skipping)\n",
2063 : err_name,
2064 : err_line,
2065 : (unsigned int) idx);
2066 0 : json_dumpf (value,
2067 : stderr,
2068 : JSON_INDENT (2));
2069 0 : global_ret = EXIT_FAILURE;
2070 0 : GNUNET_SCHEDULER_shutdown ();
2071 0 : return;
2072 : }
2073 0 : dpr = GNUNET_new (struct DrainProfitsRequest);
2074 0 : dpr->idx = idx;
2075 0 : dpr->h =
2076 0 : TALER_EXCHANGE_post_management_drain_create (ctx,
2077 : exchange_url,
2078 : &wtid,
2079 : &amount,
2080 : date,
2081 : account_section,
2082 : payto_uri,
2083 : &master_sig);
2084 0 : TALER_EXCHANGE_post_management_drain_start (dpr->h,
2085 : &drain_profits_cb,
2086 : dpr);
2087 0 : GNUNET_CONTAINER_DLL_insert (dpr_head,
2088 : dpr_tail,
2089 : dpr);
2090 : }
2091 :
2092 :
2093 : /**
2094 : * Function called with information about the post upload keys operation result.
2095 : *
2096 : * @param ukr the upload keys request
2097 : * @param mr response data
2098 : */
2099 : static void
2100 19 : keys_cb (
2101 : struct UploadKeysRequest *ukr,
2102 : const struct TALER_EXCHANGE_PostManagementKeysResponse *mr)
2103 : {
2104 19 : const struct TALER_EXCHANGE_HttpResponse *hr = &mr->hr;
2105 :
2106 19 : if (MHD_HTTP_NO_CONTENT != hr->http_status)
2107 : {
2108 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2109 : "Upload failed for command %u with status %u: %s (%s)\n",
2110 : (unsigned int) ukr->idx,
2111 : hr->http_status,
2112 : TALER_ErrorCode_get_hint (hr->ec),
2113 : hr->hint);
2114 0 : global_ret = EXIT_FAILURE;
2115 : }
2116 19 : GNUNET_CONTAINER_DLL_remove (ukr_head,
2117 : ukr_tail,
2118 : ukr);
2119 19 : GNUNET_free (ukr);
2120 19 : test_shutdown ();
2121 19 : }
2122 :
2123 :
2124 : /**
2125 : * Upload (denomination and signing) key master signatures.
2126 : *
2127 : * @param exchange_url base URL of the exchange
2128 : * @param idx index of the operation we are performing (for logging)
2129 : * @param value arguments for POSTing keys
2130 : */
2131 : static void
2132 19 : upload_keys (const char *exchange_url,
2133 : size_t idx,
2134 : const json_t *value)
2135 : {
2136 : struct TALER_EXCHANGE_ManagementPostKeysData pkd;
2137 : struct UploadKeysRequest *ukr;
2138 : const char *err_name;
2139 : unsigned int err_line;
2140 : const json_t *denom_sigs;
2141 : const json_t *signkey_sigs;
2142 : struct GNUNET_JSON_Specification spec[] = {
2143 19 : GNUNET_JSON_spec_array_const ("denom_sigs",
2144 : &denom_sigs),
2145 19 : GNUNET_JSON_spec_array_const ("signkey_sigs",
2146 : &signkey_sigs),
2147 19 : GNUNET_JSON_spec_end ()
2148 : };
2149 19 : bool ok = true;
2150 :
2151 19 : if (GNUNET_OK !=
2152 19 : GNUNET_JSON_parse (value,
2153 : spec,
2154 : &err_name,
2155 : &err_line))
2156 : {
2157 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2158 : "Invalid input to 'upload': %s#%u (skipping)\n",
2159 : err_name,
2160 : err_line);
2161 0 : json_dumpf (value,
2162 : stderr,
2163 : JSON_INDENT (2));
2164 0 : global_ret = EXIT_FAILURE;
2165 0 : GNUNET_SCHEDULER_shutdown ();
2166 0 : return;
2167 : }
2168 19 : pkd.num_sign_sigs = json_array_size (signkey_sigs);
2169 19 : pkd.num_denom_sigs = json_array_size (denom_sigs);
2170 19 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2171 : "Uploading %u denomination and %u signing key signatures\n",
2172 : pkd.num_denom_sigs,
2173 : pkd.num_sign_sigs);
2174 19 : pkd.sign_sigs = GNUNET_new_array (
2175 : pkd.num_sign_sigs,
2176 : struct TALER_EXCHANGE_SigningKeySignature);
2177 19 : pkd.denom_sigs = GNUNET_new_array (
2178 : pkd.num_denom_sigs,
2179 : struct TALER_EXCHANGE_DenominationKeySignature);
2180 40 : for (unsigned int i = 0; i<pkd.num_sign_sigs; i++)
2181 : {
2182 21 : struct TALER_EXCHANGE_SigningKeySignature *ss = &pkd.sign_sigs[i];
2183 21 : json_t *val = json_array_get (signkey_sigs,
2184 : i);
2185 : struct GNUNET_JSON_Specification ispec[] = {
2186 21 : GNUNET_JSON_spec_fixed_auto ("exchange_pub",
2187 : &ss->exchange_pub),
2188 21 : GNUNET_JSON_spec_fixed_auto ("master_sig",
2189 : &ss->master_sig),
2190 21 : GNUNET_JSON_spec_end ()
2191 : };
2192 :
2193 21 : if (GNUNET_OK !=
2194 21 : GNUNET_JSON_parse (val,
2195 : ispec,
2196 : &err_name,
2197 : &err_line))
2198 : {
2199 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2200 : "Invalid input for signkey validity: %s#%u at %u (aborting)\n",
2201 : err_name,
2202 : err_line,
2203 : i);
2204 0 : json_dumpf (val,
2205 : stderr,
2206 : JSON_INDENT (2));
2207 0 : ok = false;
2208 : }
2209 : }
2210 374 : for (unsigned int i = 0; i<pkd.num_denom_sigs; i++)
2211 : {
2212 355 : struct TALER_EXCHANGE_DenominationKeySignature *ds = &pkd.denom_sigs[i];
2213 355 : json_t *val = json_array_get (denom_sigs,
2214 : i);
2215 : struct GNUNET_JSON_Specification ispec[] = {
2216 355 : GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
2217 : &ds->h_denom_pub),
2218 355 : GNUNET_JSON_spec_fixed_auto ("master_sig",
2219 : &ds->master_sig),
2220 355 : GNUNET_JSON_spec_end ()
2221 : };
2222 :
2223 355 : if (GNUNET_OK !=
2224 355 : GNUNET_JSON_parse (val,
2225 : ispec,
2226 : &err_name,
2227 : &err_line))
2228 : {
2229 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2230 : "Invalid input for denomination validity: %s#%u at %u (aborting)\n",
2231 : err_name,
2232 : err_line,
2233 : i);
2234 0 : json_dumpf (val,
2235 : stderr,
2236 : JSON_INDENT (2));
2237 0 : ok = false;
2238 : }
2239 : }
2240 :
2241 19 : if (ok)
2242 : {
2243 19 : ukr = GNUNET_new (struct UploadKeysRequest);
2244 19 : ukr->idx = idx;
2245 19 : ukr->h =
2246 19 : TALER_EXCHANGE_post_management_keys_create (ctx,
2247 : exchange_url,
2248 : &pkd);
2249 19 : TALER_EXCHANGE_post_management_keys_start (ukr->h,
2250 : &keys_cb,
2251 : ukr);
2252 19 : GNUNET_CONTAINER_DLL_insert (ukr_head,
2253 : ukr_tail,
2254 : ukr);
2255 : }
2256 : else
2257 : {
2258 0 : global_ret = EXIT_FAILURE;
2259 0 : GNUNET_SCHEDULER_shutdown ();
2260 : }
2261 19 : GNUNET_free (pkd.sign_sigs);
2262 19 : GNUNET_free (pkd.denom_sigs);
2263 : }
2264 :
2265 :
2266 :
2267 : /**
2268 : * Function called with information about the add partner operation.
2269 : *
2270 : * @param par the request
2271 : * @param apr response data
2272 : */
2273 : static void
2274 0 : add_partner_cb (
2275 : struct PartnerAddRequest *par,
2276 : const struct TALER_EXCHANGE_PostManagementPartnersResponse *apr)
2277 : {
2278 0 : const struct TALER_EXCHANGE_HttpResponse *hr = &apr->hr;
2279 :
2280 0 : if (MHD_HTTP_NO_CONTENT != hr->http_status)
2281 : {
2282 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2283 : "Upload failed for command %u with status %u: %s (%s)\n",
2284 : (unsigned int) par->idx,
2285 : hr->http_status,
2286 : TALER_ErrorCode_get_hint (hr->ec),
2287 : hr->hint);
2288 0 : global_ret = EXIT_FAILURE;
2289 : }
2290 0 : GNUNET_CONTAINER_DLL_remove (par_head,
2291 : par_tail,
2292 : par);
2293 0 : GNUNET_free (par);
2294 0 : test_shutdown ();
2295 0 : }
2296 :
2297 :
2298 : /**
2299 : * Add partner action.
2300 : *
2301 : * @param exchange_url base URL of the exchange
2302 : * @param idx index of the operation we are performing (for logging)
2303 : * @param value arguments for add partner
2304 : */
2305 : static void
2306 0 : add_partner (const char *exchange_url,
2307 : size_t idx,
2308 : const json_t *value)
2309 : {
2310 : struct TALER_MasterPublicKeyP partner_pub;
2311 : struct GNUNET_TIME_Timestamp start_date;
2312 : struct GNUNET_TIME_Timestamp end_date;
2313 : struct GNUNET_TIME_Relative wad_frequency;
2314 : struct TALER_Amount wad_fee;
2315 : const char *partner_base_url;
2316 : struct TALER_MasterSignatureP master_sig;
2317 : struct PartnerAddRequest *par;
2318 : struct GNUNET_JSON_Specification spec[] = {
2319 0 : GNUNET_JSON_spec_fixed_auto ("partner_pub",
2320 : &partner_pub),
2321 0 : TALER_JSON_spec_amount ("wad_fee",
2322 : currency,
2323 : &wad_fee),
2324 0 : GNUNET_JSON_spec_relative_time ("wad_frequency",
2325 : &wad_frequency),
2326 0 : GNUNET_JSON_spec_timestamp ("start_date",
2327 : &start_date),
2328 0 : GNUNET_JSON_spec_timestamp ("end_date",
2329 : &end_date),
2330 0 : TALER_JSON_spec_web_url ("partner_base_url",
2331 : &partner_base_url),
2332 0 : GNUNET_JSON_spec_fixed_auto ("master_sig",
2333 : &master_sig),
2334 0 : GNUNET_JSON_spec_end ()
2335 : };
2336 : const char *err_name;
2337 : unsigned int err_line;
2338 :
2339 0 : if (GNUNET_OK !=
2340 0 : GNUNET_JSON_parse (value,
2341 : spec,
2342 : &err_name,
2343 : &err_line))
2344 : {
2345 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2346 : "Invalid input to add partner: %s#%u at %u (skipping)\n",
2347 : err_name,
2348 : err_line,
2349 : (unsigned int) idx);
2350 0 : json_dumpf (value,
2351 : stderr,
2352 : JSON_INDENT (2));
2353 0 : global_ret = EXIT_FAILURE;
2354 0 : GNUNET_SCHEDULER_shutdown ();
2355 0 : return;
2356 : }
2357 0 : par = GNUNET_new (struct PartnerAddRequest);
2358 0 : par->idx = idx;
2359 0 : par->h =
2360 0 : TALER_EXCHANGE_post_management_partners_create (ctx,
2361 : exchange_url,
2362 : &partner_pub,
2363 : start_date,
2364 : end_date,
2365 : wad_frequency,
2366 : &wad_fee,
2367 : partner_base_url,
2368 : &master_sig);
2369 0 : TALER_EXCHANGE_post_management_partners_start (par->h,
2370 : &add_partner_cb,
2371 : par);
2372 0 : GNUNET_CONTAINER_DLL_insert (par_head,
2373 : par_tail,
2374 : par);
2375 : }
2376 :
2377 :
2378 : /**
2379 : * Function called with information about the AML officer update operation.
2380 : *
2381 : * @param asr the request
2382 : * @param ar response data
2383 : */
2384 : static void
2385 0 : update_aml_officer_cb (
2386 : TALER_EXCHANGE_POST_MANAGEMENT_AML_OFFICERS_RESULT_CLOSURE *asr,
2387 : const struct TALER_EXCHANGE_PostManagementAmlOfficersResponse *ar)
2388 : {
2389 0 : const struct TALER_EXCHANGE_HttpResponse *hr = &ar->hr;
2390 :
2391 0 : if (MHD_HTTP_NO_CONTENT != hr->http_status)
2392 : {
2393 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2394 : "Upload failed for command %u with status %u: %s (%s)\n",
2395 : (unsigned int) asr->idx,
2396 : hr->http_status,
2397 : TALER_ErrorCode_get_hint (hr->ec),
2398 : hr->hint);
2399 0 : global_ret = EXIT_FAILURE;
2400 : }
2401 0 : GNUNET_CONTAINER_DLL_remove (asr_head,
2402 : asr_tail,
2403 : asr);
2404 0 : GNUNET_free (asr);
2405 0 : test_shutdown ();
2406 0 : }
2407 :
2408 :
2409 : /**
2410 : * Upload AML staff action.
2411 : *
2412 : * @param exchange_url base URL of the exchange
2413 : * @param idx index of the operation we are performing (for logging)
2414 : * @param value arguments for AML staff change
2415 : */
2416 : static void
2417 0 : update_aml_staff (const char *exchange_url,
2418 : size_t idx,
2419 : const json_t *value)
2420 : {
2421 : struct TALER_AmlOfficerPublicKeyP officer_pub;
2422 : const char *officer_name;
2423 : struct GNUNET_TIME_Timestamp change_date;
2424 : bool is_active;
2425 : bool read_only;
2426 : struct TALER_MasterSignatureP master_sig;
2427 : struct AmlStaffRequest *asr;
2428 : struct GNUNET_JSON_Specification spec[] = {
2429 0 : GNUNET_JSON_spec_fixed_auto ("officer_pub",
2430 : &officer_pub),
2431 0 : GNUNET_JSON_spec_timestamp ("change_date",
2432 : &change_date),
2433 0 : GNUNET_JSON_spec_bool ("is_active",
2434 : &is_active),
2435 0 : GNUNET_JSON_spec_bool ("read_only",
2436 : &read_only),
2437 0 : GNUNET_JSON_spec_string ("officer_name",
2438 : &officer_name),
2439 0 : GNUNET_JSON_spec_fixed_auto ("master_sig",
2440 : &master_sig),
2441 0 : GNUNET_JSON_spec_end ()
2442 : };
2443 : const char *err_name;
2444 : unsigned int err_line;
2445 :
2446 0 : if (GNUNET_OK !=
2447 0 : GNUNET_JSON_parse (value,
2448 : spec,
2449 : &err_name,
2450 : &err_line))
2451 : {
2452 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2453 : "Invalid input to AML staff update: %s#%u at %u (skipping)\n",
2454 : err_name,
2455 : err_line,
2456 : (unsigned int) idx);
2457 0 : json_dumpf (value,
2458 : stderr,
2459 : JSON_INDENT (2));
2460 0 : global_ret = EXIT_FAILURE;
2461 0 : GNUNET_SCHEDULER_shutdown ();
2462 0 : return;
2463 : }
2464 0 : asr = GNUNET_new (struct AmlStaffRequest);
2465 0 : asr->idx = idx;
2466 0 : asr->h = TALER_EXCHANGE_post_management_aml_officers_create (
2467 : ctx,
2468 : exchange_url,
2469 : &officer_pub,
2470 : officer_name,
2471 : change_date,
2472 : is_active,
2473 : read_only,
2474 : &master_sig);
2475 0 : GNUNET_CONTAINER_DLL_insert (asr_head,
2476 : asr_tail,
2477 : asr);
2478 0 : GNUNET_assert (TALER_EC_NONE ==
2479 : TALER_EXCHANGE_post_management_aml_officers_start (
2480 : asr->h,
2481 : &update_aml_officer_cb,
2482 : asr));
2483 : }
2484 :
2485 :
2486 : /**
2487 : * Perform uploads based on the JSON in #out.
2488 : *
2489 : * @param exchange_url base URL of the exchange to use
2490 : */
2491 : static void
2492 40 : trigger_upload (const char *exchange_url)
2493 : {
2494 40 : struct UploadHandler uhs[] = {
2495 : {
2496 : .key = OP_REVOKE_DENOMINATION,
2497 : .cb = &upload_denom_revocation
2498 : },
2499 : {
2500 : .key = OP_REVOKE_SIGNKEY,
2501 : .cb = &upload_signkey_revocation
2502 : },
2503 : {
2504 : .key = OP_ENABLE_AUDITOR,
2505 : .cb = &upload_auditor_add
2506 : },
2507 : {
2508 : .key = OP_DISABLE_AUDITOR,
2509 : .cb = &upload_auditor_del
2510 : },
2511 : {
2512 : .key = OP_ENABLE_WIRE,
2513 : .cb = &upload_wire_add
2514 : },
2515 : {
2516 : .key = OP_DISABLE_WIRE,
2517 : .cb = &upload_wire_del
2518 : },
2519 : {
2520 : .key = OP_SET_WIRE_FEE,
2521 : .cb = &upload_wire_fee
2522 : },
2523 : {
2524 : .key = OP_SET_GLOBAL_FEE,
2525 : .cb = &upload_global_fee
2526 : },
2527 : {
2528 : .key = OP_UPLOAD_SIGS,
2529 : .cb = &upload_keys
2530 : },
2531 : {
2532 : .key = OP_DRAIN_PROFITS,
2533 : .cb = &upload_drain
2534 : },
2535 : {
2536 : .key = OP_UPDATE_AML_STAFF,
2537 : .cb = &update_aml_staff
2538 : },
2539 : {
2540 : .key = OP_ADD_PARTNER,
2541 : .cb = &add_partner
2542 : },
2543 : /* array termination */
2544 : {
2545 : .key = NULL
2546 : }
2547 : };
2548 : size_t index;
2549 : json_t *obj;
2550 :
2551 148 : json_array_foreach (out, index, obj) {
2552 108 : bool found = false;
2553 : const char *key;
2554 : const json_t *value;
2555 :
2556 108 : key = json_string_value (json_object_get (obj, "operation"));
2557 108 : value = json_object_get (obj, "arguments");
2558 108 : if (NULL == key)
2559 : {
2560 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2561 : "Malformed JSON input\n");
2562 0 : global_ret = EXIT_FAILURE;
2563 0 : GNUNET_SCHEDULER_shutdown ();
2564 0 : return;
2565 : }
2566 : /* block of code that uses key and value */
2567 778 : for (unsigned int i = 0; NULL != uhs[i].key; i++)
2568 : {
2569 778 : if (0 == strcasecmp (key,
2570 : uhs[i].key))
2571 : {
2572 :
2573 108 : found = true;
2574 108 : uhs[i].cb (exchange_url,
2575 : index,
2576 : value);
2577 108 : break;
2578 : }
2579 : }
2580 108 : if (! found)
2581 : {
2582 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2583 : "Upload does not know how to handle `%s'\n",
2584 : key);
2585 0 : global_ret = EXIT_FAILURE;
2586 0 : GNUNET_SCHEDULER_shutdown ();
2587 0 : return;
2588 : }
2589 : }
2590 : }
2591 :
2592 :
2593 : /**
2594 : * Upload operation result (signatures) to exchange.
2595 : *
2596 : * @param args the array of command-line arguments to process next
2597 : */
2598 : static void
2599 40 : do_upload (char *const *args)
2600 : {
2601 : (void) args;
2602 40 : if (NULL != in)
2603 : {
2604 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2605 : "Downloaded data was not consumed, refusing upload\n");
2606 0 : GNUNET_SCHEDULER_shutdown ();
2607 0 : global_ret = EXIT_FAILURE;
2608 0 : return;
2609 : }
2610 40 : if (NULL == out)
2611 : {
2612 : json_error_t err;
2613 :
2614 0 : out = json_loadf (stdin,
2615 : JSON_REJECT_DUPLICATES,
2616 : &err);
2617 0 : if (NULL == out)
2618 : {
2619 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2620 : "Failed to read JSON input: %s at %d:%s (offset: %d)\n",
2621 : err.text,
2622 : err.line,
2623 : err.source,
2624 : err.position);
2625 0 : GNUNET_SCHEDULER_shutdown ();
2626 0 : global_ret = EXIT_FAILURE;
2627 0 : return;
2628 : }
2629 : }
2630 40 : if (! json_is_array (out))
2631 : {
2632 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2633 : "Error: expected JSON array for `upload` command\n");
2634 0 : GNUNET_SCHEDULER_shutdown ();
2635 0 : global_ret = EXIT_FAILURE;
2636 0 : return;
2637 : }
2638 61 : if ( (NULL == CFG_exchange_url) &&
2639 : (GNUNET_OK !=
2640 21 : GNUNET_CONFIGURATION_get_value_string (kcfg,
2641 : "exchange",
2642 : "BASE_URL",
2643 : &CFG_exchange_url)) )
2644 : {
2645 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2646 : "exchange",
2647 : "BASE_URL");
2648 0 : global_ret = EXIT_NOTCONFIGURED;
2649 0 : GNUNET_SCHEDULER_shutdown ();
2650 0 : return;
2651 : }
2652 40 : trigger_upload (CFG_exchange_url);
2653 40 : json_decref (out);
2654 40 : out = NULL;
2655 : }
2656 :
2657 :
2658 : /**
2659 : * Revoke denomination key.
2660 : *
2661 : * @param args the array of command-line arguments to process next;
2662 : * args[0] must be the hash of the denomination key to revoke
2663 : */
2664 : static void
2665 0 : do_revoke_denomination_key (char *const *args)
2666 : {
2667 : struct TALER_DenominationHashP h_denom_pub;
2668 : struct TALER_MasterSignatureP master_sig;
2669 :
2670 0 : if (NULL != in)
2671 : {
2672 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2673 : "Downloaded data was not consumed, refusing revocation\n");
2674 0 : GNUNET_SCHEDULER_shutdown ();
2675 0 : global_ret = EXIT_FAILURE;
2676 0 : return;
2677 : }
2678 0 : if ( (NULL == args[0]) ||
2679 : (GNUNET_OK !=
2680 0 : GNUNET_STRINGS_string_to_data (args[0],
2681 : strlen (args[0]),
2682 : &h_denom_pub,
2683 : sizeof (h_denom_pub))) )
2684 : {
2685 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2686 : "You must specify a denomination key with this subcommand\n");
2687 0 : GNUNET_SCHEDULER_shutdown ();
2688 0 : global_ret = EXIT_INVALIDARGUMENT;
2689 0 : return;
2690 : }
2691 0 : if (GNUNET_OK !=
2692 0 : load_offline_key (GNUNET_NO))
2693 0 : return;
2694 0 : TALER_exchange_offline_denomination_revoke_sign (&h_denom_pub,
2695 : &master_priv,
2696 : &master_sig);
2697 0 : output_operation (OP_REVOKE_DENOMINATION,
2698 0 : GNUNET_JSON_PACK (
2699 : GNUNET_JSON_pack_data_auto ("h_denom_pub",
2700 : &h_denom_pub),
2701 : GNUNET_JSON_pack_data_auto ("master_sig",
2702 : &master_sig)));
2703 0 : next (args + 1);
2704 : }
2705 :
2706 :
2707 : /**
2708 : * Revoke signkey.
2709 : *
2710 : * @param args the array of command-line arguments to process next;
2711 : * args[0] must be the hash of the denomination key to revoke
2712 : */
2713 : static void
2714 0 : do_revoke_signkey (char *const *args)
2715 : {
2716 : struct TALER_ExchangePublicKeyP exchange_pub;
2717 : struct TALER_MasterSignatureP master_sig;
2718 :
2719 0 : if (NULL != in)
2720 : {
2721 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2722 : "Downloaded data was not consumed, refusing revocation\n");
2723 0 : GNUNET_SCHEDULER_shutdown ();
2724 0 : global_ret = EXIT_FAILURE;
2725 0 : return;
2726 : }
2727 0 : if ( (NULL == args[0]) ||
2728 : (GNUNET_OK !=
2729 0 : GNUNET_STRINGS_string_to_data (args[0],
2730 : strlen (args[0]),
2731 : &exchange_pub,
2732 : sizeof (exchange_pub))) )
2733 : {
2734 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2735 : "You must specify an exchange signing key with this subcommand\n");
2736 0 : GNUNET_SCHEDULER_shutdown ();
2737 0 : global_ret = EXIT_INVALIDARGUMENT;
2738 0 : return;
2739 : }
2740 0 : if (GNUNET_OK !=
2741 0 : load_offline_key (GNUNET_NO))
2742 0 : return;
2743 0 : TALER_exchange_offline_signkey_revoke_sign (&exchange_pub,
2744 : &master_priv,
2745 : &master_sig);
2746 0 : output_operation (OP_REVOKE_SIGNKEY,
2747 0 : GNUNET_JSON_PACK (
2748 : GNUNET_JSON_pack_data_auto ("exchange_pub",
2749 : &exchange_pub),
2750 : GNUNET_JSON_pack_data_auto ("master_sig",
2751 : &master_sig)));
2752 0 : next (args + 1);
2753 : }
2754 :
2755 :
2756 : /**
2757 : * Add auditor.
2758 : *
2759 : * @param args the array of command-line arguments to process next;
2760 : * args[0] must be the auditor's public key, args[1] the auditor's
2761 : * API base URL, and args[2] the auditor's name.
2762 : */
2763 : static void
2764 4 : do_add_auditor (char *const *args)
2765 : {
2766 : struct TALER_MasterSignatureP master_sig;
2767 : struct TALER_AuditorPublicKeyP auditor_pub;
2768 : struct GNUNET_TIME_Timestamp now;
2769 :
2770 4 : if (NULL != in)
2771 : {
2772 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2773 : "Downloaded data was not consumed, not adding auditor\n");
2774 0 : GNUNET_SCHEDULER_shutdown ();
2775 0 : global_ret = EXIT_FAILURE;
2776 0 : return;
2777 : }
2778 8 : if ( (NULL == args[0]) ||
2779 : (GNUNET_OK !=
2780 4 : GNUNET_STRINGS_string_to_data (args[0],
2781 : strlen (args[0]),
2782 : &auditor_pub,
2783 : sizeof (auditor_pub))) )
2784 : {
2785 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2786 : "You must specify an auditor public key as first argument for this subcommand\n");
2787 0 : GNUNET_SCHEDULER_shutdown ();
2788 0 : global_ret = EXIT_INVALIDARGUMENT;
2789 0 : return;
2790 : }
2791 :
2792 4 : if ( (NULL == args[1]) ||
2793 4 : (0 != strncmp ("http",
2794 4 : args[1],
2795 4 : strlen ("http"))) ||
2796 4 : (NULL == args[2]) )
2797 : {
2798 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2799 : "You must specify an auditor URI and auditor name as 2nd and 3rd arguments to this subcommand\n");
2800 0 : GNUNET_SCHEDULER_shutdown ();
2801 0 : global_ret = EXIT_INVALIDARGUMENT;
2802 0 : return;
2803 : }
2804 4 : if (GNUNET_OK !=
2805 4 : load_offline_key (GNUNET_NO))
2806 0 : return;
2807 4 : now = GNUNET_TIME_timestamp_get ();
2808 4 : TALER_exchange_offline_auditor_add_sign (&auditor_pub,
2809 4 : args[1],
2810 : now,
2811 : &master_priv,
2812 : &master_sig);
2813 4 : output_operation (OP_ENABLE_AUDITOR,
2814 4 : GNUNET_JSON_PACK (
2815 : GNUNET_JSON_pack_string ("auditor_url",
2816 : args[1]),
2817 : GNUNET_JSON_pack_string ("auditor_name",
2818 : args[2]),
2819 : GNUNET_JSON_pack_timestamp ("validity_start",
2820 : now),
2821 : GNUNET_JSON_pack_data_auto ("auditor_pub",
2822 : &auditor_pub),
2823 : GNUNET_JSON_pack_data_auto ("master_sig",
2824 : &master_sig)));
2825 4 : next (args + 3);
2826 : }
2827 :
2828 :
2829 : /**
2830 : * Disable auditor account.
2831 : *
2832 : * @param args the array of command-line arguments to process next;
2833 : * args[0] must be the hash of the denomination key to revoke
2834 : */
2835 : static void
2836 0 : do_del_auditor (char *const *args)
2837 : {
2838 : struct TALER_MasterSignatureP master_sig;
2839 : struct TALER_AuditorPublicKeyP auditor_pub;
2840 : struct GNUNET_TIME_Timestamp now;
2841 :
2842 0 : if (NULL != in)
2843 : {
2844 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2845 : "Downloaded data was not consumed, not deleting auditor account\n");
2846 0 : GNUNET_SCHEDULER_shutdown ();
2847 0 : global_ret = EXIT_FAILURE;
2848 0 : return;
2849 : }
2850 0 : if ( (NULL == args[0]) ||
2851 : (GNUNET_OK !=
2852 0 : GNUNET_STRINGS_string_to_data (args[0],
2853 : strlen (args[0]),
2854 : &auditor_pub,
2855 : sizeof (auditor_pub))) )
2856 : {
2857 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2858 : "You must specify an auditor public key as first argument for this subcommand\n");
2859 0 : GNUNET_SCHEDULER_shutdown ();
2860 0 : global_ret = EXIT_INVALIDARGUMENT;
2861 0 : return;
2862 : }
2863 0 : if (GNUNET_OK !=
2864 0 : load_offline_key (GNUNET_NO))
2865 0 : return;
2866 0 : now = GNUNET_TIME_timestamp_get ();
2867 0 : TALER_exchange_offline_auditor_del_sign (&auditor_pub,
2868 : now,
2869 : &master_priv,
2870 : &master_sig);
2871 0 : output_operation (OP_DISABLE_AUDITOR,
2872 0 : GNUNET_JSON_PACK (
2873 : GNUNET_JSON_pack_data_auto ("auditor_pub",
2874 : &auditor_pub),
2875 : GNUNET_JSON_pack_timestamp ("validity_end",
2876 : now),
2877 : GNUNET_JSON_pack_data_auto ("master_sig",
2878 : &master_sig)));
2879 0 : next (args + 1);
2880 : }
2881 :
2882 :
2883 : /**
2884 : * Parse account restriction.
2885 : *
2886 : * @param args the array of command-line arguments to process next
2887 : * @param[in,out] restrictions JSON array to update
2888 : * @return -1 on error, otherwise number of arguments from @a args that were used
2889 : */
2890 : static int
2891 0 : parse_restriction (char *const *args,
2892 : json_t *restrictions)
2893 : {
2894 0 : if (NULL == args[0])
2895 : {
2896 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2897 : "Restriction TYPE argument missing\n");
2898 0 : return -1;
2899 : }
2900 0 : if (0 == strcmp (args[0],
2901 : "deny"))
2902 : {
2903 0 : GNUNET_assert (0 ==
2904 : json_array_append_new (
2905 : restrictions,
2906 : GNUNET_JSON_PACK (
2907 : GNUNET_JSON_pack_string ("type",
2908 : "deny"))));
2909 0 : return 1;
2910 : }
2911 0 : if (0 == strcmp (args[0],
2912 : "regex"))
2913 : {
2914 : json_t *i18n;
2915 : json_error_t err;
2916 :
2917 0 : if ( (NULL == args[1]) ||
2918 0 : (NULL == args[2]) ||
2919 0 : (NULL == args[3]) )
2920 : {
2921 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2922 : "Mandatory arguments for restriction of type `regex' missing (REGEX, HINT, HINT-I18 required)\n");
2923 0 : return -1;
2924 : }
2925 : {
2926 : regex_t ex;
2927 :
2928 0 : if (0 != regcomp (&ex,
2929 0 : args[1],
2930 : REG_NOSUB | REG_EXTENDED))
2931 : {
2932 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2933 : "Invalid regular expression `%s'\n",
2934 : args[1]);
2935 0 : return -1;
2936 : }
2937 0 : regfree (&ex);
2938 : }
2939 :
2940 0 : i18n = json_loads (args[3],
2941 : JSON_REJECT_DUPLICATES,
2942 : &err);
2943 0 : if (NULL == i18n)
2944 : {
2945 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2946 : "Invalid JSON for restriction of type `regex': `%s` at %d\n",
2947 : args[3],
2948 : err.position);
2949 0 : return -1;
2950 : }
2951 0 : GNUNET_assert (0 ==
2952 : json_array_append_new (
2953 : restrictions,
2954 : GNUNET_JSON_PACK (
2955 : GNUNET_JSON_pack_string ("type",
2956 : "regex"),
2957 : GNUNET_JSON_pack_string ("payto_regex",
2958 : args[1]),
2959 : GNUNET_JSON_pack_string ("human_hint",
2960 : args[2]),
2961 : GNUNET_JSON_pack_object_steal ("human_hint_i18n",
2962 : i18n)
2963 : )));
2964 0 : return 4;
2965 : }
2966 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2967 : "Restriction TYPE `%s' unsupported\n",
2968 : args[0]);
2969 0 : return -1;
2970 : }
2971 :
2972 :
2973 : /**
2974 : * Add wire account.
2975 : *
2976 : * @param args the array of command-line arguments to process next;
2977 : * args[0] must be the hash of the denomination key to revoke
2978 : */
2979 : static void
2980 17 : do_add_wire (char *const *args)
2981 : {
2982 : struct TALER_MasterSignatureP master_sig_add;
2983 : struct TALER_MasterSignatureP master_sig_wire;
2984 : struct GNUNET_TIME_Timestamp now;
2985 17 : const char *conversion_url = NULL;
2986 17 : const char *open_banking_gateway = NULL;
2987 17 : const char *prepared_transfer_url = NULL;
2988 17 : const char *bank_label = NULL;
2989 17 : int64_t priority = 0;
2990 : json_t *debit_restrictions;
2991 : json_t *credit_restrictions;
2992 17 : unsigned int num_args = 1;
2993 17 : struct TALER_FullPayto payto_uri = {
2994 17 : .full_payto = args[0]
2995 : };
2996 :
2997 17 : if (NULL != in)
2998 : {
2999 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3000 : "Downloaded data was not consumed, not adding wire account\n");
3001 0 : GNUNET_SCHEDULER_shutdown ();
3002 0 : global_ret = EXIT_FAILURE;
3003 0 : return;
3004 : }
3005 17 : if (NULL == args[0])
3006 : {
3007 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3008 : "You must specify a payto://-URI with this subcommand\n");
3009 0 : GNUNET_SCHEDULER_shutdown ();
3010 0 : global_ret = EXIT_INVALIDARGUMENT;
3011 0 : return;
3012 : }
3013 17 : if (GNUNET_OK !=
3014 17 : load_offline_key (GNUNET_NO))
3015 0 : return;
3016 : {
3017 17 : char *msg = TALER_payto_validate (payto_uri);
3018 :
3019 17 : if (NULL != msg)
3020 : {
3021 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3022 : "payto URI `%s' is malformed: %s\n",
3023 : payto_uri.full_payto,
3024 : msg);
3025 0 : GNUNET_free (msg);
3026 0 : GNUNET_SCHEDULER_shutdown ();
3027 0 : global_ret = EXIT_INVALIDARGUMENT;
3028 0 : return;
3029 : }
3030 : }
3031 17 : now = GNUNET_TIME_timestamp_get ();
3032 : {
3033 : char *wire_method;
3034 :
3035 17 : wire_method = TALER_payto_get_method (payto_uri.full_payto);
3036 17 : if (NULL == wire_method)
3037 : {
3038 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3039 : "payto:// URI `%s' is malformed\n",
3040 : payto_uri.full_payto);
3041 0 : global_ret = EXIT_INVALIDARGUMENT;
3042 0 : GNUNET_SCHEDULER_shutdown ();
3043 0 : return;
3044 : }
3045 17 : GNUNET_free (wire_method);
3046 : }
3047 17 : debit_restrictions = json_array ();
3048 17 : GNUNET_assert (NULL != debit_restrictions);
3049 17 : credit_restrictions = json_array ();
3050 17 : GNUNET_assert (NULL != credit_restrictions);
3051 17 : while (NULL != args[num_args])
3052 : {
3053 17 : if (0 == strcmp (args[num_args],
3054 : "conversion-url"))
3055 : {
3056 0 : num_args++;
3057 0 : conversion_url = args[num_args];
3058 0 : if (NULL == conversion_url)
3059 : {
3060 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3061 : "'conversion-url' requires an argument\n");
3062 0 : global_ret = EXIT_INVALIDARGUMENT;
3063 0 : GNUNET_SCHEDULER_shutdown ();
3064 0 : json_decref (debit_restrictions);
3065 0 : json_decref (credit_restrictions);
3066 0 : return;
3067 : }
3068 0 : if (! TALER_is_web_url (conversion_url))
3069 : {
3070 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3071 : "'conversion-url' must refer to HTTP(S) endpoint, `%s' is invalid\n",
3072 : conversion_url);
3073 0 : global_ret = EXIT_INVALIDARGUMENT;
3074 0 : GNUNET_SCHEDULER_shutdown ();
3075 0 : json_decref (debit_restrictions);
3076 0 : json_decref (credit_restrictions);
3077 0 : return;
3078 : }
3079 0 : num_args++;
3080 0 : continue;
3081 : }
3082 :
3083 17 : if (0 == strcmp (args[num_args],
3084 : "open-banking-gateway"))
3085 : {
3086 0 : num_args++;
3087 0 : open_banking_gateway = args[num_args];
3088 0 : if (NULL == open_banking_gateway)
3089 : {
3090 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3091 : "'open-banking-gateway' requires an argument\n");
3092 0 : global_ret = EXIT_INVALIDARGUMENT;
3093 0 : GNUNET_SCHEDULER_shutdown ();
3094 0 : json_decref (debit_restrictions);
3095 0 : json_decref (credit_restrictions);
3096 0 : return;
3097 : }
3098 0 : if (! TALER_is_web_url (open_banking_gateway))
3099 : {
3100 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3101 : "'open-banking-gateway' must refer to HTTP(S) endpoint, `%s' is invalid\n",
3102 : open_banking_gateway);
3103 0 : global_ret = EXIT_INVALIDARGUMENT;
3104 0 : GNUNET_SCHEDULER_shutdown ();
3105 0 : json_decref (debit_restrictions);
3106 0 : json_decref (credit_restrictions);
3107 0 : return;
3108 : }
3109 0 : num_args++;
3110 0 : continue;
3111 : }
3112 :
3113 17 : if (0 == strcmp (args[num_args],
3114 : "prepared-transfer-url"))
3115 : {
3116 0 : num_args++;
3117 0 : prepared_transfer_url = args[num_args];
3118 0 : if (NULL == prepared_transfer_url)
3119 : {
3120 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3121 : "'prepared-transfer-url' requires an argument\n");
3122 0 : global_ret = EXIT_INVALIDARGUMENT;
3123 0 : GNUNET_SCHEDULER_shutdown ();
3124 0 : json_decref (debit_restrictions);
3125 0 : json_decref (credit_restrictions);
3126 0 : return;
3127 : }
3128 0 : if (! TALER_is_web_url (prepared_transfer_url))
3129 : {
3130 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3131 : "'prepared-transfer-url' must refer to HTTP(S) endpoint, `%s' is invalid\n",
3132 : prepared_transfer_url);
3133 0 : global_ret = EXIT_INVALIDARGUMENT;
3134 0 : GNUNET_SCHEDULER_shutdown ();
3135 0 : json_decref (debit_restrictions);
3136 0 : json_decref (credit_restrictions);
3137 0 : return;
3138 : }
3139 0 : num_args++;
3140 0 : continue;
3141 : }
3142 :
3143 17 : if (0 == strcmp (args[num_args],
3144 : "credit-restriction"))
3145 0 : {
3146 : int iret;
3147 :
3148 0 : num_args++;
3149 0 : iret = parse_restriction (&args[num_args],
3150 : credit_restrictions);
3151 0 : if (iret <= 0)
3152 : {
3153 0 : global_ret = EXIT_INVALIDARGUMENT;
3154 0 : GNUNET_SCHEDULER_shutdown ();
3155 0 : json_decref (debit_restrictions);
3156 0 : json_decref (credit_restrictions);
3157 0 : return;
3158 : }
3159 0 : num_args += iret;
3160 0 : continue;
3161 : }
3162 17 : if (0 == strcmp (args[num_args],
3163 : "debit-restriction"))
3164 0 : {
3165 : int iret;
3166 :
3167 0 : num_args++;
3168 0 : iret = parse_restriction (&args[num_args],
3169 : debit_restrictions);
3170 0 : if (iret <= 0)
3171 : {
3172 0 : global_ret = EXIT_INVALIDARGUMENT;
3173 0 : GNUNET_SCHEDULER_shutdown ();
3174 0 : json_decref (debit_restrictions);
3175 0 : json_decref (credit_restrictions);
3176 0 : return;
3177 : }
3178 0 : num_args += iret;
3179 0 : continue;
3180 : }
3181 17 : if (0 == strcmp (args[num_args],
3182 : "display-hint"))
3183 0 : {
3184 : long long p;
3185 : char dummy;
3186 :
3187 0 : num_args++;
3188 0 : if ( (NULL == args[num_args]) ||
3189 0 : (NULL == args[num_args + 1]) )
3190 : {
3191 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3192 : "'display-hint' requires at least two arguments (priority and label)\n");
3193 0 : global_ret = EXIT_INVALIDARGUMENT;
3194 0 : GNUNET_SCHEDULER_shutdown ();
3195 0 : json_decref (debit_restrictions);
3196 0 : json_decref (credit_restrictions);
3197 0 : return;
3198 : }
3199 0 : if (1 != sscanf (args[num_args],
3200 : "%lld%c",
3201 : &p,
3202 : &dummy))
3203 : {
3204 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3205 : "Priority argument `%s' is not a number\n",
3206 : args[num_args]);
3207 0 : global_ret = EXIT_INVALIDARGUMENT;
3208 0 : GNUNET_SCHEDULER_shutdown ();
3209 0 : json_decref (debit_restrictions);
3210 0 : json_decref (credit_restrictions);
3211 0 : return;
3212 : }
3213 0 : priority = (int64_t) p;
3214 0 : num_args++;
3215 0 : bank_label = args[num_args];
3216 0 : num_args++;
3217 0 : continue;
3218 : }
3219 17 : break;
3220 : }
3221 17 : TALER_exchange_offline_wire_add_sign (payto_uri,
3222 : conversion_url,
3223 : open_banking_gateway,
3224 : prepared_transfer_url,
3225 : debit_restrictions,
3226 : credit_restrictions,
3227 : now,
3228 : &master_priv,
3229 : &master_sig_add);
3230 17 : TALER_exchange_wire_signature_make (payto_uri,
3231 : conversion_url,
3232 : open_banking_gateway,
3233 : prepared_transfer_url,
3234 : debit_restrictions,
3235 : credit_restrictions,
3236 : &master_priv,
3237 : &master_sig_wire);
3238 17 : output_operation (OP_ENABLE_WIRE,
3239 17 : GNUNET_JSON_PACK (
3240 : TALER_JSON_pack_full_payto ("payto_uri",
3241 : payto_uri),
3242 : GNUNET_JSON_pack_array_steal ("debit_restrictions",
3243 : debit_restrictions),
3244 : GNUNET_JSON_pack_array_steal ("credit_restrictions",
3245 : credit_restrictions),
3246 : GNUNET_JSON_pack_allow_null (
3247 : GNUNET_JSON_pack_string ("conversion_url",
3248 : conversion_url)),
3249 : GNUNET_JSON_pack_allow_null (
3250 : GNUNET_JSON_pack_string ("open_banking_gateway",
3251 : open_banking_gateway)),
3252 : GNUNET_JSON_pack_allow_null (
3253 : GNUNET_JSON_pack_string ("prepared_transfer_url",
3254 : prepared_transfer_url)),
3255 : GNUNET_JSON_pack_allow_null (
3256 : GNUNET_JSON_pack_string ("bank_label",
3257 : bank_label)),
3258 : GNUNET_JSON_pack_int64 ("priority",
3259 : priority),
3260 : GNUNET_JSON_pack_timestamp ("validity_start",
3261 : now),
3262 : GNUNET_JSON_pack_data_auto ("master_sig_add",
3263 : &master_sig_add),
3264 : GNUNET_JSON_pack_data_auto ("master_sig_wire",
3265 : &master_sig_wire)));
3266 17 : next (args + num_args);
3267 : }
3268 :
3269 :
3270 : /**
3271 : * Disable wire account.
3272 : *
3273 : * @param args the array of command-line arguments to process next;
3274 : * args[0] must be the payto URI of the account to disable
3275 : */
3276 : static void
3277 0 : do_del_wire (char *const *args)
3278 : {
3279 : struct TALER_MasterSignatureP master_sig;
3280 : struct GNUNET_TIME_Timestamp now;
3281 0 : struct TALER_FullPayto payto_uri = {
3282 0 : .full_payto = args[0]
3283 : };
3284 :
3285 0 : if (NULL != in)
3286 : {
3287 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3288 : "Downloaded data was not consumed, not deleting wire account\n")
3289 : ;
3290 0 : GNUNET_SCHEDULER_shutdown ();
3291 0 : global_ret = EXIT_FAILURE;
3292 0 : return;
3293 : }
3294 0 : if (NULL == args[0])
3295 : {
3296 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3297 : "You must specify a payto://-URI with this subcommand\n");
3298 0 : GNUNET_SCHEDULER_shutdown ();
3299 0 : global_ret = EXIT_INVALIDARGUMENT;
3300 0 : return;
3301 : }
3302 0 : if (GNUNET_OK !=
3303 0 : load_offline_key (GNUNET_NO))
3304 0 : return;
3305 0 : now = GNUNET_TIME_timestamp_get ();
3306 0 : TALER_exchange_offline_wire_del_sign (payto_uri,
3307 : now,
3308 : &master_priv,
3309 : &master_sig);
3310 0 : output_operation (OP_DISABLE_WIRE,
3311 0 : GNUNET_JSON_PACK (
3312 : TALER_JSON_pack_full_payto ("payto_uri",
3313 : payto_uri),
3314 : GNUNET_JSON_pack_timestamp ("validity_end",
3315 : now),
3316 : GNUNET_JSON_pack_data_auto ("master_sig",
3317 : &master_sig)));
3318 0 : next (args + 1);
3319 : }
3320 :
3321 :
3322 : /**
3323 : * Set wire fees for the given year.
3324 : *
3325 : * @param args the array of command-line arguments to process next;
3326 : * args[0] must be the year, args[1] the wire method, args[2] the wire fee and args[3]
3327 : * the closing fee.
3328 : */
3329 : static void
3330 34 : do_set_wire_fee (char *const *args)
3331 : {
3332 : struct TALER_MasterSignatureP master_sig;
3333 : char dummy;
3334 : unsigned int year;
3335 : struct TALER_WireFeeSet fees;
3336 : struct GNUNET_TIME_Timestamp start_time;
3337 : struct GNUNET_TIME_Timestamp end_time;
3338 :
3339 34 : if (NULL != in)
3340 : {
3341 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3342 : "Downloaded data was not consumed, not setting wire fee\n");
3343 0 : GNUNET_SCHEDULER_shutdown ();
3344 0 : global_ret = EXIT_FAILURE;
3345 0 : return;
3346 : }
3347 34 : if ( (NULL == args[0]) ||
3348 34 : (NULL == args[1]) ||
3349 34 : (NULL == args[2]) ||
3350 34 : (NULL == args[3]) ||
3351 34 : ( (1 != sscanf (args[0],
3352 : "%u%c",
3353 : &year,
3354 17 : &dummy)) &&
3355 17 : (0 != strcasecmp ("now",
3356 34 : args[0])) ) ||
3357 : (GNUNET_OK !=
3358 34 : TALER_string_to_amount (args[2],
3359 34 : &fees.wire)) ||
3360 : (GNUNET_OK !=
3361 34 : TALER_string_to_amount (args[3],
3362 : &fees.closing)) )
3363 : {
3364 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3365 : "You must use YEAR, METHOD, WIRE-FEE, and CLOSING-FEE as arguments for this subcommand\n");
3366 0 : GNUNET_SCHEDULER_shutdown ();
3367 0 : global_ret = EXIT_INVALIDARGUMENT;
3368 0 : return;
3369 : }
3370 34 : if (0 == strcasecmp ("now",
3371 : args[0]))
3372 17 : year = GNUNET_TIME_get_current_year ();
3373 34 : if (GNUNET_OK !=
3374 34 : load_offline_key (GNUNET_NO))
3375 0 : return;
3376 34 : start_time = GNUNET_TIME_absolute_to_timestamp (
3377 : GNUNET_TIME_year_to_time (year));
3378 34 : end_time = GNUNET_TIME_absolute_to_timestamp (
3379 : GNUNET_TIME_year_to_time (year + 1));
3380 :
3381 34 : TALER_exchange_offline_wire_fee_sign (args[1],
3382 : start_time,
3383 : end_time,
3384 : &fees,
3385 : &master_priv,
3386 : &master_sig);
3387 34 : output_operation (OP_SET_WIRE_FEE,
3388 34 : GNUNET_JSON_PACK (
3389 : GNUNET_JSON_pack_string ("wire_method",
3390 : args[1]),
3391 : GNUNET_JSON_pack_timestamp ("start_time",
3392 : start_time),
3393 : GNUNET_JSON_pack_timestamp ("end_time",
3394 : end_time),
3395 : TALER_JSON_pack_amount ("wire_fee",
3396 : &fees.wire),
3397 : TALER_JSON_pack_amount ("closing_fee",
3398 : &fees.closing),
3399 : GNUNET_JSON_pack_data_auto ("master_sig",
3400 : &master_sig)));
3401 34 : next (args + 4);
3402 : }
3403 :
3404 :
3405 : /**
3406 : * Set global fees for the given year.
3407 : *
3408 : * @param args the array of command-line arguments to process next;
3409 : * args[0] must be the year, args[1] the history fee, args[2]
3410 : * the account fee and args[3] the purse fee. These are followed by args[4] purse timeout,
3411 : * args[5] history expiration. Last is args[6] the (free) purse account limit.
3412 : */
3413 : static void
3414 34 : do_set_global_fee (char *const *args)
3415 : {
3416 : struct TALER_MasterSignatureP master_sig;
3417 : char dummy;
3418 : unsigned int year;
3419 : struct TALER_GlobalFeeSet fees;
3420 : struct GNUNET_TIME_Relative purse_timeout;
3421 : struct GNUNET_TIME_Relative history_expiration;
3422 : unsigned int purse_account_limit;
3423 : struct GNUNET_TIME_Timestamp start_time;
3424 : struct GNUNET_TIME_Timestamp end_time;
3425 :
3426 34 : if (NULL != in)
3427 : {
3428 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3429 : "Downloaded data was not consumed, not setting global fee\n");
3430 0 : GNUNET_SCHEDULER_shutdown ();
3431 0 : global_ret = EXIT_FAILURE;
3432 0 : return;
3433 : }
3434 34 : if ( (NULL == args[0]) ||
3435 34 : (NULL == args[1]) ||
3436 34 : (NULL == args[2]) ||
3437 34 : (NULL == args[3]) ||
3438 34 : (NULL == args[4]) ||
3439 34 : (NULL == args[5]) ||
3440 34 : (NULL == args[6]) )
3441 : {
3442 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3443 : "You must use YEAR, HISTORY-FEE, ACCOUNT-FEE, PURSE-FEE, PURSE-TIMEOUT, HISTORY-EXPIRATION and PURSE-ACCOUNT-LIMIT as arguments for this subcommand\n");
3444 0 : GNUNET_SCHEDULER_shutdown ();
3445 0 : global_ret = EXIT_INVALIDARGUMENT;
3446 0 : return;
3447 : }
3448 34 : if ( (1 != sscanf (args[0],
3449 : "%u%c",
3450 : &year,
3451 17 : &dummy)) &&
3452 17 : (0 != strcasecmp ("now",
3453 : args[0])) )
3454 : {
3455 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3456 : "Invalid YEAR given for 'global-fee' subcommand\n");
3457 0 : GNUNET_SCHEDULER_shutdown ();
3458 0 : global_ret = EXIT_INVALIDARGUMENT;
3459 0 : return;
3460 : }
3461 34 : if ( (GNUNET_OK !=
3462 34 : TALER_string_to_amount (args[1],
3463 34 : &fees.history)) ||
3464 : (GNUNET_OK !=
3465 34 : TALER_string_to_amount (args[2],
3466 34 : &fees.account)) ||
3467 : (GNUNET_OK !=
3468 34 : TALER_string_to_amount (args[3],
3469 : &fees.purse)) )
3470 : {
3471 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3472 : "Invalid amount given for 'global-fee' subcommand\n");
3473 0 : GNUNET_SCHEDULER_shutdown ();
3474 0 : global_ret = EXIT_INVALIDARGUMENT;
3475 0 : return;
3476 : }
3477 34 : if (GNUNET_OK !=
3478 34 : GNUNET_STRINGS_fancy_time_to_relative (args[4],
3479 : &purse_timeout))
3480 : {
3481 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3482 : "Invalid purse timeout `%s' given for 'global-fee' subcommand\n",
3483 : args[4]);
3484 0 : GNUNET_SCHEDULER_shutdown ();
3485 0 : global_ret = EXIT_INVALIDARGUMENT;
3486 0 : return;
3487 : }
3488 34 : if (GNUNET_OK !=
3489 34 : GNUNET_STRINGS_fancy_time_to_relative (args[5],
3490 : &history_expiration))
3491 : {
3492 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3493 : "Invalid history expiratoin `%s' given for 'global-fee' subcommand\n",
3494 : args[5]);
3495 0 : GNUNET_SCHEDULER_shutdown ();
3496 0 : global_ret = EXIT_INVALIDARGUMENT;
3497 0 : return;
3498 : }
3499 34 : if (1 != sscanf (args[6],
3500 : "%u%c",
3501 : &purse_account_limit,
3502 : &dummy))
3503 : {
3504 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3505 : "Invalid purse account limit given for 'global-fee' subcommand\n");
3506 0 : GNUNET_SCHEDULER_shutdown ();
3507 0 : global_ret = EXIT_INVALIDARGUMENT;
3508 0 : return;
3509 : }
3510 34 : if (0 == strcasecmp ("now",
3511 : args[0]))
3512 17 : year = GNUNET_TIME_get_current_year ();
3513 34 : if (GNUNET_OK !=
3514 34 : load_offline_key (GNUNET_NO))
3515 0 : return;
3516 34 : start_time = GNUNET_TIME_absolute_to_timestamp (
3517 : GNUNET_TIME_year_to_time (year));
3518 34 : end_time = GNUNET_TIME_absolute_to_timestamp (
3519 : GNUNET_TIME_year_to_time (year + 1));
3520 :
3521 34 : TALER_exchange_offline_global_fee_sign (start_time,
3522 : end_time,
3523 : &fees,
3524 : purse_timeout,
3525 : history_expiration,
3526 : (uint32_t) purse_account_limit,
3527 : &master_priv,
3528 : &master_sig);
3529 34 : output_operation (OP_SET_GLOBAL_FEE,
3530 34 : GNUNET_JSON_PACK (
3531 : GNUNET_JSON_pack_timestamp ("start_time",
3532 : start_time),
3533 : GNUNET_JSON_pack_timestamp ("end_time",
3534 : end_time),
3535 : TALER_JSON_pack_amount ("history_fee",
3536 : &fees.history),
3537 : TALER_JSON_pack_amount ("account_fee",
3538 : &fees.account),
3539 : TALER_JSON_pack_amount ("purse_fee",
3540 : &fees.purse),
3541 : GNUNET_JSON_pack_time_rel ("purse_timeout",
3542 : purse_timeout),
3543 : GNUNET_JSON_pack_time_rel ("history_expiration",
3544 : history_expiration),
3545 : GNUNET_JSON_pack_uint64 ("purse_account_limit",
3546 : (uint32_t) purse_account_limit),
3547 : GNUNET_JSON_pack_data_auto ("master_sig",
3548 : &master_sig)));
3549 34 : next (args + 7);
3550 : }
3551 :
3552 :
3553 : /**
3554 : * Drain profits from exchange's escrow account to
3555 : * regular exchange account.
3556 : *
3557 : * @param args the array of command-line arguments to process next;
3558 : * args[0] must be the amount,
3559 : * args[1] must be the section of the escrow account to drain
3560 : * args[2] must be the payto://-URI of the target account
3561 : */
3562 : static void
3563 0 : do_drain (char *const *args)
3564 : {
3565 : struct TALER_WireTransferIdentifierRawP wtid;
3566 : struct GNUNET_TIME_Timestamp date;
3567 : struct TALER_Amount amount;
3568 : const char *account_section;
3569 : struct TALER_FullPayto payto_uri;
3570 : struct TALER_MasterSignatureP master_sig;
3571 : char *err;
3572 :
3573 0 : if (NULL != in)
3574 : {
3575 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3576 : "Downloaded data was not consumed, refusing drain\n");
3577 0 : GNUNET_SCHEDULER_shutdown ();
3578 0 : global_ret = EXIT_FAILURE;
3579 0 : return;
3580 : }
3581 0 : if ( (NULL == args[0]) ||
3582 0 : (NULL == args[1]) ||
3583 0 : (NULL == args[2]) ||
3584 : (GNUNET_OK !=
3585 0 : TALER_string_to_amount (args[0],
3586 : &amount)) )
3587 : {
3588 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3589 : "Drain requires an amount, section name and target payto://-URI as arguments\n");
3590 0 : GNUNET_SCHEDULER_shutdown ();
3591 0 : global_ret = EXIT_INVALIDARGUMENT;
3592 0 : return;
3593 : }
3594 0 : if ( (NULL == args[0]) ||
3595 0 : (NULL == args[1]) ||
3596 0 : (NULL == args[2]) )
3597 : {
3598 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3599 : "Drain requires an amount, section name and target payto://-URI as arguments\n");
3600 0 : GNUNET_SCHEDULER_shutdown ();
3601 0 : global_ret = EXIT_INVALIDARGUMENT;
3602 0 : return;
3603 : }
3604 0 : if (GNUNET_OK !=
3605 0 : TALER_string_to_amount (args[0],
3606 : &amount))
3607 : {
3608 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3609 : "Invalid amount `%s' specified for drain\n",
3610 : args[0]);
3611 0 : GNUNET_SCHEDULER_shutdown ();
3612 0 : global_ret = EXIT_INVALIDARGUMENT;
3613 0 : return;
3614 : }
3615 0 : account_section = args[1];
3616 0 : payto_uri.full_payto = args[2];
3617 0 : err = TALER_payto_validate (payto_uri);
3618 0 : if (NULL != err)
3619 : {
3620 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3621 : "Invalid payto://-URI `%s' specified for drain: %s\n",
3622 : payto_uri.full_payto,
3623 : err);
3624 0 : GNUNET_free (err);
3625 0 : GNUNET_SCHEDULER_shutdown ();
3626 0 : global_ret = EXIT_INVALIDARGUMENT;
3627 0 : return;
3628 : }
3629 0 : if (GNUNET_OK !=
3630 0 : load_offline_key (GNUNET_NO))
3631 0 : return;
3632 0 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
3633 : &wtid,
3634 : sizeof (wtid));
3635 0 : date = GNUNET_TIME_timestamp_get ();
3636 0 : TALER_exchange_offline_profit_drain_sign (&wtid,
3637 : date,
3638 : &amount,
3639 : account_section,
3640 : payto_uri,
3641 : &master_priv,
3642 : &master_sig);
3643 0 : output_operation (OP_DRAIN_PROFITS,
3644 0 : GNUNET_JSON_PACK (
3645 : GNUNET_JSON_pack_data_auto ("wtid",
3646 : &wtid),
3647 : GNUNET_JSON_pack_string ("account_section",
3648 : account_section),
3649 : TALER_JSON_pack_full_payto ("payto_uri",
3650 : payto_uri),
3651 : TALER_JSON_pack_amount ("amount",
3652 : &amount),
3653 : GNUNET_JSON_pack_timestamp ("date",
3654 : date),
3655 : GNUNET_JSON_pack_data_auto ("master_sig",
3656 : &master_sig)));
3657 0 : next (args + 3);
3658 : }
3659 :
3660 :
3661 : /**
3662 : * Add partner.
3663 : *
3664 : * @param args the array of command-line arguments to process next;
3665 : * args[0] must be the partner's master public key, args[1] the partner's
3666 : * API base URL, args[2] the wad fee, args[3] the wad frequency, and
3667 : * args[4] the year (including possibly 'now')
3668 : */
3669 : static void
3670 0 : do_add_partner (char *const *args)
3671 : {
3672 : struct TALER_MasterPublicKeyP partner_pub;
3673 : struct GNUNET_TIME_Timestamp start_date;
3674 : struct GNUNET_TIME_Timestamp end_date;
3675 : struct GNUNET_TIME_Relative wad_frequency;
3676 : struct TALER_Amount wad_fee;
3677 : const char *partner_base_url;
3678 : struct TALER_MasterSignatureP master_sig;
3679 : char dummy;
3680 : unsigned int year;
3681 :
3682 0 : if (NULL != in)
3683 : {
3684 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3685 : "Downloaded data was not consumed, not adding partner\n");
3686 0 : GNUNET_SCHEDULER_shutdown ();
3687 0 : global_ret = EXIT_FAILURE;
3688 0 : return;
3689 : }
3690 0 : if ( (NULL == args[0]) ||
3691 : (GNUNET_OK !=
3692 0 : GNUNET_STRINGS_string_to_data (args[0],
3693 : strlen (args[0]),
3694 : &partner_pub,
3695 : sizeof (partner_pub))) )
3696 : {
3697 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3698 : "You must specify the partner master public key as first argument for this subcommand\n");
3699 0 : GNUNET_SCHEDULER_shutdown ();
3700 0 : global_ret = EXIT_INVALIDARGUMENT;
3701 0 : return;
3702 : }
3703 0 : if ( (NULL == args[1]) ||
3704 0 : (0 != strncmp ("http",
3705 0 : args[1],
3706 : strlen ("http"))) )
3707 : {
3708 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3709 : "You must specify the partner's base URL as the 2nd argument to this subcommand\n");
3710 0 : GNUNET_SCHEDULER_shutdown ();
3711 0 : global_ret = EXIT_INVALIDARGUMENT;
3712 0 : return;
3713 : }
3714 0 : partner_base_url = args[1];
3715 0 : if ( (NULL == args[2]) ||
3716 : (GNUNET_OK !=
3717 0 : TALER_string_to_amount (args[2],
3718 : &wad_fee)) )
3719 : {
3720 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3721 : "Invalid amount `%s' specified for wad fee of partner\n",
3722 : args[2]);
3723 0 : GNUNET_SCHEDULER_shutdown ();
3724 0 : global_ret = EXIT_INVALIDARGUMENT;
3725 0 : return;
3726 : }
3727 0 : if ( (NULL == args[3]) ||
3728 : (GNUNET_OK !=
3729 0 : GNUNET_STRINGS_fancy_time_to_relative (args[3],
3730 : &wad_frequency)) )
3731 : {
3732 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3733 : "Invalid wad frequency `%s' specified for add partner\n",
3734 : args[3]);
3735 0 : GNUNET_SCHEDULER_shutdown ();
3736 0 : global_ret = EXIT_INVALIDARGUMENT;
3737 0 : return;
3738 : }
3739 0 : if ( (NULL == args[4]) ||
3740 0 : ( (1 != sscanf (args[4],
3741 : "%u%c",
3742 : &year,
3743 0 : &dummy)) &&
3744 0 : (0 != strcasecmp ("now",
3745 0 : args[4])) ) )
3746 : {
3747 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3748 : "Invalid year `%s' specified for add partner\n",
3749 : args[4]);
3750 0 : GNUNET_SCHEDULER_shutdown ();
3751 0 : global_ret = EXIT_INVALIDARGUMENT;
3752 0 : return;
3753 : }
3754 0 : if (0 == strcasecmp ("now",
3755 0 : args[4]))
3756 0 : year = GNUNET_TIME_get_current_year ();
3757 0 : start_date = GNUNET_TIME_absolute_to_timestamp (
3758 : GNUNET_TIME_year_to_time (year));
3759 0 : end_date = GNUNET_TIME_absolute_to_timestamp (
3760 : GNUNET_TIME_year_to_time (year + 1));
3761 :
3762 0 : if (GNUNET_OK !=
3763 0 : load_offline_key (GNUNET_NO))
3764 0 : return;
3765 0 : TALER_exchange_offline_partner_details_sign (&partner_pub,
3766 : start_date,
3767 : end_date,
3768 : wad_frequency,
3769 : &wad_fee,
3770 : partner_base_url,
3771 : &master_priv,
3772 : &master_sig);
3773 0 : output_operation (OP_ADD_PARTNER,
3774 0 : GNUNET_JSON_PACK (
3775 : GNUNET_JSON_pack_string ("partner_base_url",
3776 : partner_base_url),
3777 : GNUNET_JSON_pack_time_rel ("wad_frequency",
3778 : wad_frequency),
3779 : GNUNET_JSON_pack_timestamp ("start_date",
3780 : start_date),
3781 : GNUNET_JSON_pack_timestamp ("end_date",
3782 : end_date),
3783 : GNUNET_JSON_pack_data_auto ("partner_pub",
3784 : &partner_pub),
3785 : GNUNET_JSON_pack_data_auto ("master_sig",
3786 : &master_sig)));
3787 0 : next (args + 5);
3788 : }
3789 :
3790 :
3791 : /**
3792 : * Enable or disable AML staff.
3793 : *
3794 : * @param is_active true to enable, false to disable
3795 : * @param args the array of command-line arguments to process next; args[0] must be the AML staff's public key, args[1] the AML staff's legal name, and if @a is_active then args[2] rw (read write) or ro (read only)
3796 : */
3797 : static void
3798 0 : do_set_aml_staff (bool is_active,
3799 : char *const *args)
3800 : {
3801 : struct TALER_AmlOfficerPublicKeyP officer_pub;
3802 : const char *officer_name;
3803 : bool read_only;
3804 : struct TALER_MasterSignatureP master_sig;
3805 : struct GNUNET_TIME_Timestamp now
3806 0 : = GNUNET_TIME_timestamp_get ();
3807 :
3808 0 : if (NULL != in)
3809 : {
3810 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3811 : "Downloaded data was not consumed, not updating AML staff status\n");
3812 0 : GNUNET_SCHEDULER_shutdown ();
3813 0 : global_ret = EXIT_FAILURE;
3814 0 : return;
3815 : }
3816 0 : if ( (NULL == args[0]) ||
3817 : (GNUNET_OK !=
3818 0 : GNUNET_STRINGS_string_to_data (args[0],
3819 : strlen (args[0]),
3820 : &officer_pub,
3821 : sizeof (officer_pub))) )
3822 : {
3823 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3824 : "You must specify the AML officer's public key as first argument for this subcommand\n");
3825 0 : GNUNET_SCHEDULER_shutdown ();
3826 0 : global_ret = EXIT_INVALIDARGUMENT;
3827 0 : return;
3828 : }
3829 0 : if (NULL == args[1])
3830 : {
3831 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3832 : "You must specify the officer's legal name as the 2nd argument to this subcommand\n");
3833 0 : GNUNET_SCHEDULER_shutdown ();
3834 0 : global_ret = EXIT_INVALIDARGUMENT;
3835 0 : return;
3836 : }
3837 0 : officer_name = args[1];
3838 0 : if (is_active)
3839 : {
3840 0 : if ( (NULL == args[2]) ||
3841 0 : ( (0 != strcmp (args[2],
3842 0 : "ro")) &&
3843 0 : (0 != strcmp (args[2],
3844 : "rw")) ) )
3845 : {
3846 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3847 : "You must specify 'ro' or 'rw' (and not `%s') for the access level\n",
3848 : args[2]);
3849 0 : GNUNET_SCHEDULER_shutdown ();
3850 0 : global_ret = EXIT_INVALIDARGUMENT;
3851 0 : return;
3852 : }
3853 0 : read_only = (0 == strcmp (args[2],
3854 : "ro"));
3855 : }
3856 : else
3857 : {
3858 0 : read_only = true;
3859 : }
3860 0 : if (GNUNET_OK !=
3861 0 : load_offline_key (GNUNET_NO))
3862 0 : return;
3863 0 : TALER_exchange_offline_aml_officer_status_sign (&officer_pub,
3864 : officer_name,
3865 : now,
3866 : is_active,
3867 : read_only,
3868 : &master_priv,
3869 : &master_sig);
3870 0 : output_operation (OP_UPDATE_AML_STAFF,
3871 0 : GNUNET_JSON_PACK (
3872 : GNUNET_JSON_pack_string ("officer_name",
3873 : officer_name),
3874 : GNUNET_JSON_pack_timestamp ("change_date",
3875 : now),
3876 : GNUNET_JSON_pack_bool ("is_active",
3877 : is_active),
3878 : GNUNET_JSON_pack_bool ("read_only",
3879 : read_only),
3880 : GNUNET_JSON_pack_data_auto ("officer_pub",
3881 : &officer_pub),
3882 : GNUNET_JSON_pack_data_auto ("master_sig",
3883 : &master_sig)));
3884 0 : next (args + (is_active ? 3 : 2));
3885 : }
3886 :
3887 :
3888 : /**
3889 : * Disable AML staff.
3890 : *
3891 : * @param args the array of command-line arguments to process next;
3892 : * args[0] must be the AML staff's public key, args[1] the AML staff's legal name, args[2] rw (read write) or ro (read only)
3893 : */
3894 : static void
3895 0 : disable_aml_staff (char *const *args)
3896 : {
3897 0 : do_set_aml_staff (false,
3898 : args);
3899 0 : }
3900 :
3901 :
3902 : /**
3903 : * Enable AML staff.
3904 : *
3905 : * @param args the array of command-line arguments to process next;
3906 : * args[0] must be the AML staff's public key, args[1] the AML staff's legal name, args[2] rw (read write) or ro (read only)
3907 : */
3908 : static void
3909 0 : enable_aml_staff (char *const *args)
3910 : {
3911 0 : do_set_aml_staff (true,
3912 : args);
3913 0 : }
3914 :
3915 :
3916 : /**
3917 : * Function called with information about future keys. Dumps the JSON output
3918 : * (on success), either into an internal buffer or to stdout (depending on
3919 : * whether there are subsequent commands).
3920 : *
3921 : * @param args the remaining args
3922 : * @param mgr response data
3923 : */
3924 : static void
3925 19 : download_cb (char *const *args,
3926 : const struct TALER_EXCHANGE_GetManagementKeysResponse *mgr)
3927 : {
3928 19 : const struct TALER_EXCHANGE_HttpResponse *hr = &mgr->hr;
3929 :
3930 19 : mgkh = NULL;
3931 19 : switch (hr->http_status)
3932 : {
3933 19 : case MHD_HTTP_OK:
3934 19 : break;
3935 0 : default:
3936 0 : if (0 != hr->http_status)
3937 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3938 : "Failed to download keys from `%s': %s (HTTP status: %u/%u)\n",
3939 : CFG_exchange_url,
3940 : hr->hint,
3941 : hr->http_status,
3942 : (unsigned int) hr->ec);
3943 : else
3944 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3945 : "Failed to download keys from `%s' (no HTTP response)\n",
3946 : CFG_exchange_url);
3947 0 : GNUNET_SCHEDULER_shutdown ();
3948 0 : global_ret = EXIT_FAILURE;
3949 0 : return;
3950 : }
3951 19 : in = GNUNET_JSON_PACK (
3952 : GNUNET_JSON_pack_string ("operation",
3953 : OP_INPUT_KEYS),
3954 : GNUNET_JSON_pack_object_incref ("arguments",
3955 : (json_t *) hr->reply));
3956 19 : if (NULL == args[0])
3957 : {
3958 0 : json_dumpf (in,
3959 : stdout,
3960 : JSON_INDENT (2));
3961 0 : json_decref (in);
3962 0 : in = NULL;
3963 : }
3964 19 : next (args);
3965 : }
3966 :
3967 :
3968 : /**
3969 : * Download future keys.
3970 : *
3971 : * @param args the array of command-line arguments to process next
3972 : */
3973 : static void
3974 19 : do_download (char *const *args)
3975 : {
3976 38 : if ( (NULL == CFG_exchange_url) &&
3977 : (GNUNET_OK !=
3978 19 : GNUNET_CONFIGURATION_get_value_string (kcfg,
3979 : "exchange",
3980 : "BASE_URL",
3981 : &CFG_exchange_url)) )
3982 : {
3983 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3984 : "exchange",
3985 : "BASE_URL");
3986 0 : GNUNET_SCHEDULER_shutdown ();
3987 0 : global_ret = EXIT_NOTCONFIGURED;
3988 0 : return;
3989 : }
3990 19 : mgkh = TALER_EXCHANGE_get_management_keys_create (ctx,
3991 : CFG_exchange_url);
3992 19 : TALER_EXCHANGE_get_management_keys_start (mgkh,
3993 : &download_cb,
3994 : (void *) args);
3995 : }
3996 :
3997 :
3998 : /**
3999 : * Check that the security module keys are the same as before. If we had no
4000 : * keys in store before, remember them (Trust On First Use).
4001 : *
4002 : * @param secmset security module keys
4003 : * @return #GNUNET_OK if keys match with what we have in store
4004 : * #GNUNET_NO if we had nothing in store but now do
4005 : * #GNUNET_SYSERR if keys changed from what we remember or other error
4006 : */
4007 : static enum GNUNET_GenericReturnValue
4008 19 : tofu_check (const struct TALER_SecurityModulePublicKeySetP *secmset)
4009 : {
4010 : char *fn;
4011 : struct TALER_SecurityModulePublicKeySetP oldset;
4012 : ssize_t ret;
4013 :
4014 19 : if (GNUNET_OK !=
4015 19 : GNUNET_CONFIGURATION_get_value_filename (kcfg,
4016 : "exchange-offline",
4017 : "SECM_TOFU_FILE",
4018 : &fn))
4019 : {
4020 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
4021 : "exchange-offline",
4022 : "SECM_TOFU_FILE");
4023 0 : return GNUNET_SYSERR;
4024 : }
4025 19 : if (GNUNET_OK ==
4026 19 : GNUNET_DISK_file_test (fn))
4027 : {
4028 2 : ret = GNUNET_DISK_fn_read (fn,
4029 : &oldset,
4030 : sizeof (oldset));
4031 2 : if (GNUNET_SYSERR != ret)
4032 : {
4033 2 : if (ret != sizeof (oldset))
4034 : {
4035 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4036 : "File `%s' corrupt\n",
4037 : fn);
4038 0 : GNUNET_free (fn);
4039 0 : return GNUNET_SYSERR;
4040 : }
4041 : /* TOFU check */
4042 2 : if (0 != memcmp (&oldset,
4043 : secmset,
4044 : sizeof (*secmset)))
4045 : {
4046 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4047 : "Fatal: security module keys changed (file `%s')!\n",
4048 : fn);
4049 0 : GNUNET_free (fn);
4050 0 : return GNUNET_SYSERR;
4051 : }
4052 2 : GNUNET_free (fn);
4053 2 : return GNUNET_OK;
4054 : }
4055 : }
4056 :
4057 : {
4058 : char *key;
4059 :
4060 : /* check against SECMOD-keys pinned in configuration */
4061 17 : if (GNUNET_OK ==
4062 17 : GNUNET_CONFIGURATION_get_value_string (kcfg,
4063 : "exchange-offline",
4064 : "SECM_ESIGN_PUBKEY",
4065 : &key))
4066 : {
4067 : struct TALER_SecurityModulePublicKeyP k;
4068 :
4069 0 : if (GNUNET_OK !=
4070 0 : GNUNET_STRINGS_string_to_data (key,
4071 : strlen (key),
4072 : &k,
4073 : sizeof (k)))
4074 : {
4075 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
4076 : "exchange-offline",
4077 : "SECM_ESIGN_PUBKEY",
4078 : "key malformed");
4079 0 : GNUNET_free (key);
4080 0 : GNUNET_free (fn);
4081 0 : return GNUNET_SYSERR;
4082 : }
4083 0 : GNUNET_free (key);
4084 0 : if (0 !=
4085 0 : GNUNET_memcmp (&k,
4086 : &secmset->eddsa))
4087 : {
4088 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4089 : "ESIGN security module key does not match SECM_ESIGN_PUBKEY in configuration\n");
4090 0 : GNUNET_free (fn);
4091 0 : return GNUNET_SYSERR;
4092 : }
4093 : }
4094 17 : if (GNUNET_OK ==
4095 17 : GNUNET_CONFIGURATION_get_value_string (kcfg,
4096 : "exchange-offline",
4097 : "SECM_DENOM_PUBKEY",
4098 : &key))
4099 : {
4100 : struct TALER_SecurityModulePublicKeyP k;
4101 :
4102 0 : if (GNUNET_OK !=
4103 0 : GNUNET_STRINGS_string_to_data (key,
4104 : strlen (key),
4105 : &k,
4106 : sizeof (k)))
4107 : {
4108 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
4109 : "exchange-offline",
4110 : "SECM_DENOM_PUBKEY",
4111 : "key malformed");
4112 0 : GNUNET_free (key);
4113 0 : GNUNET_free (fn);
4114 0 : return GNUNET_SYSERR;
4115 : }
4116 0 : GNUNET_free (key);
4117 0 : if (0 !=
4118 0 : GNUNET_memcmp (&k,
4119 : &secmset->rsa))
4120 : {
4121 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4122 : "DENOM security module key does not match SECM_DENOM_PUBKEY in configuration\n");
4123 0 : GNUNET_free (fn);
4124 0 : return GNUNET_SYSERR;
4125 : }
4126 : }
4127 17 : if (GNUNET_OK ==
4128 17 : GNUNET_CONFIGURATION_get_value_string (kcfg,
4129 : "exchange-offline",
4130 : "SECM_DENOM_CS_PUBKEY",
4131 : &key))
4132 : {
4133 : struct TALER_SecurityModulePublicKeyP k;
4134 :
4135 0 : if (GNUNET_OK !=
4136 0 : GNUNET_STRINGS_string_to_data (key,
4137 : strlen (key),
4138 : &k,
4139 : sizeof (k)))
4140 : {
4141 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
4142 : "exchange-offline",
4143 : "SECM_DENOM_CS_PUBKEY",
4144 : "key malformed");
4145 0 : GNUNET_free (key);
4146 0 : GNUNET_free (fn);
4147 0 : return GNUNET_SYSERR;
4148 : }
4149 0 : GNUNET_free (key);
4150 0 : if (0 !=
4151 0 : GNUNET_memcmp (&k,
4152 : &secmset->cs))
4153 : {
4154 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4155 : "DENOM security module key does not match SECM_DENOM_CS_PUBKEY in configuration\n");
4156 0 : GNUNET_free (fn);
4157 0 : return GNUNET_SYSERR;
4158 : }
4159 : }
4160 : }
4161 17 : if (GNUNET_OK !=
4162 17 : GNUNET_DISK_directory_create_for_file (fn))
4163 : {
4164 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4165 : "Failed create directory to store key material in file `%s'\n",
4166 : fn);
4167 0 : GNUNET_free (fn);
4168 0 : return GNUNET_SYSERR;
4169 : }
4170 : /* persist keys for future runs */
4171 17 : if (GNUNET_OK !=
4172 17 : GNUNET_DISK_fn_write (fn,
4173 : secmset,
4174 : sizeof (oldset),
4175 : GNUNET_DISK_PERM_USER_READ))
4176 : {
4177 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4178 : "Failed to store key material in file `%s'\n",
4179 : fn);
4180 0 : GNUNET_free (fn);
4181 0 : return GNUNET_SYSERR;
4182 : }
4183 17 : GNUNET_free (fn);
4184 17 : return GNUNET_NO;
4185 : }
4186 :
4187 :
4188 : /**
4189 : * Output @a signkeys for human consumption.
4190 : *
4191 : * @param secm_pub security module public key used to sign the denominations
4192 : * @param signkeys keys to output
4193 : * @return #GNUNET_OK on success
4194 : */
4195 : static enum GNUNET_GenericReturnValue
4196 0 : show_signkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
4197 : const json_t *signkeys)
4198 : {
4199 : size_t index;
4200 : json_t *value;
4201 :
4202 0 : json_array_foreach (signkeys, index, value) {
4203 : const char *err_name;
4204 : unsigned int err_line;
4205 : struct TALER_ExchangePublicKeyP exchange_pub;
4206 : struct TALER_SecurityModuleSignatureP secm_sig;
4207 : struct GNUNET_TIME_Timestamp start_time;
4208 : struct GNUNET_TIME_Timestamp sign_end;
4209 : struct GNUNET_TIME_Timestamp legal_end;
4210 : struct GNUNET_TIME_Relative duration;
4211 : struct GNUNET_JSON_Specification spec[] = {
4212 0 : GNUNET_JSON_spec_timestamp ("stamp_start",
4213 : &start_time),
4214 0 : GNUNET_JSON_spec_timestamp ("stamp_expire",
4215 : &sign_end),
4216 0 : GNUNET_JSON_spec_timestamp ("stamp_end",
4217 : &legal_end),
4218 0 : GNUNET_JSON_spec_fixed_auto ("key",
4219 : &exchange_pub),
4220 0 : GNUNET_JSON_spec_fixed_auto ("signkey_secmod_sig",
4221 : &secm_sig),
4222 0 : GNUNET_JSON_spec_end ()
4223 : };
4224 :
4225 0 : if (GNUNET_OK !=
4226 0 : GNUNET_JSON_parse (value,
4227 : spec,
4228 : &err_name,
4229 : &err_line))
4230 : {
4231 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4232 : "Invalid input for signing key to 'show': %s#%u at %u (skipping)\n",
4233 : err_name,
4234 : err_line,
4235 : (unsigned int) index);
4236 0 : json_dumpf (value,
4237 : stderr,
4238 : JSON_INDENT (2));
4239 0 : global_ret = EXIT_FAILURE;
4240 0 : GNUNET_SCHEDULER_shutdown ();
4241 0 : return GNUNET_SYSERR;
4242 : }
4243 0 : duration = GNUNET_TIME_absolute_get_difference (start_time.abs_time,
4244 : sign_end.abs_time);
4245 0 : if (GNUNET_OK !=
4246 0 : TALER_exchange_secmod_eddsa_verify (&exchange_pub,
4247 : start_time,
4248 : duration,
4249 : secm_pub,
4250 : &secm_sig))
4251 : {
4252 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4253 : "Invalid security module signature for signing key %s (aborting)\n",
4254 : TALER_B2S (&exchange_pub));
4255 0 : global_ret = EXIT_FAILURE;
4256 0 : GNUNET_SCHEDULER_shutdown ();
4257 0 : return GNUNET_SYSERR;
4258 : }
4259 : {
4260 : char *legal_end_s;
4261 :
4262 0 : legal_end_s = GNUNET_strdup (
4263 : GNUNET_TIME_timestamp2s (legal_end));
4264 0 : printf ("EXCHANGE-KEY %s starting at %s (used for: %s, legal end: %s)\n",
4265 : TALER_B2S (&exchange_pub),
4266 : GNUNET_TIME_timestamp2s (start_time),
4267 : GNUNET_TIME_relative2s (duration,
4268 : false),
4269 : legal_end_s);
4270 0 : GNUNET_free (legal_end_s);
4271 : }
4272 : }
4273 0 : return GNUNET_OK;
4274 : }
4275 :
4276 :
4277 : /**
4278 : * Output @a denomkeys for human consumption.
4279 : *
4280 : * @param secm_pub_rsa security module public key used to sign the RSA denominations
4281 : * @param secm_pub_cs security module public key used to sign the CS denominations
4282 : * @param denomkeys keys to output
4283 : * @return #GNUNET_OK on success
4284 : */
4285 : static enum GNUNET_GenericReturnValue
4286 0 : show_denomkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub_rsa,
4287 : const struct TALER_SecurityModulePublicKeyP *secm_pub_cs,
4288 : const json_t *denomkeys)
4289 : {
4290 : size_t index;
4291 : json_t *value;
4292 :
4293 0 : json_array_foreach (denomkeys, index, value) {
4294 : const char *err_name;
4295 : unsigned int err_line;
4296 : const char *section_name;
4297 : struct TALER_DenominationPublicKey denom_pub;
4298 : struct GNUNET_TIME_Timestamp stamp_start;
4299 : struct GNUNET_TIME_Timestamp stamp_expire_withdraw;
4300 : struct GNUNET_TIME_Timestamp stamp_expire_deposit;
4301 : struct GNUNET_TIME_Timestamp stamp_expire_legal;
4302 : struct TALER_Amount coin_value;
4303 : struct TALER_DenomFeeSet fees;
4304 : struct TALER_SecurityModuleSignatureP secm_sig;
4305 : struct GNUNET_JSON_Specification spec[] = {
4306 0 : GNUNET_JSON_spec_string ("section_name",
4307 : §ion_name),
4308 0 : TALER_JSON_spec_denom_pub ("denom_pub",
4309 : &denom_pub),
4310 0 : TALER_JSON_spec_amount ("value",
4311 : currency,
4312 : &coin_value),
4313 0 : TALER_JSON_SPEC_DENOM_FEES ("fee",
4314 : currency,
4315 : &fees),
4316 0 : GNUNET_JSON_spec_timestamp ("stamp_start",
4317 : &stamp_start),
4318 0 : GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
4319 : &stamp_expire_withdraw),
4320 0 : GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
4321 : &stamp_expire_deposit),
4322 0 : GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
4323 : &stamp_expire_legal),
4324 0 : GNUNET_JSON_spec_fixed_auto ("denom_secmod_sig",
4325 : &secm_sig),
4326 0 : GNUNET_JSON_spec_end ()
4327 : };
4328 : struct GNUNET_TIME_Relative duration;
4329 : struct TALER_DenominationHashP h_denom_pub;
4330 : enum GNUNET_GenericReturnValue ok;
4331 :
4332 0 : if (GNUNET_OK !=
4333 0 : GNUNET_JSON_parse (value,
4334 : spec,
4335 : &err_name,
4336 : &err_line))
4337 : {
4338 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4339 : "Invalid input for denomination key to 'show': %s#%u at %u (skipping)\n",
4340 : err_name,
4341 : err_line,
4342 : (unsigned int) index);
4343 0 : json_dumpf (value,
4344 : stderr,
4345 : JSON_INDENT (2));
4346 0 : GNUNET_JSON_parse_free (spec);
4347 0 : global_ret = EXIT_FAILURE;
4348 0 : GNUNET_SCHEDULER_shutdown ();
4349 0 : return GNUNET_SYSERR;
4350 : }
4351 0 : duration = GNUNET_TIME_absolute_get_difference (
4352 : stamp_start.abs_time,
4353 : stamp_expire_withdraw.abs_time);
4354 0 : TALER_denom_pub_hash (&denom_pub,
4355 : &h_denom_pub);
4356 0 : switch (denom_pub.bsign_pub_key->cipher)
4357 : {
4358 0 : case GNUNET_CRYPTO_BSA_RSA:
4359 : {
4360 : struct TALER_RsaPubHashP h_rsa;
4361 :
4362 0 : TALER_rsa_pub_hash (denom_pub.bsign_pub_key->details.rsa_public_key,
4363 : &h_rsa);
4364 0 : ok = TALER_exchange_secmod_rsa_verify (&h_rsa,
4365 : section_name,
4366 : stamp_start,
4367 : duration,
4368 : secm_pub_rsa,
4369 : &secm_sig);
4370 : }
4371 0 : break;
4372 0 : case GNUNET_CRYPTO_BSA_CS:
4373 : {
4374 : struct TALER_CsPubHashP h_cs;
4375 :
4376 0 : TALER_cs_pub_hash (&denom_pub.bsign_pub_key->details.cs_public_key,
4377 : &h_cs);
4378 0 : ok = TALER_exchange_secmod_cs_verify (&h_cs,
4379 : section_name,
4380 : stamp_start,
4381 : duration,
4382 : secm_pub_cs,
4383 : &secm_sig);
4384 : }
4385 0 : break;
4386 0 : default:
4387 0 : GNUNET_break (0);
4388 0 : ok = GNUNET_SYSERR;
4389 0 : break;
4390 : }
4391 0 : if (GNUNET_OK != ok)
4392 : {
4393 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4394 : "Invalid security module signature for denomination key %s (aborting)\n",
4395 : GNUNET_h2s (&h_denom_pub.hash));
4396 0 : global_ret = EXIT_FAILURE;
4397 0 : GNUNET_SCHEDULER_shutdown ();
4398 0 : return GNUNET_SYSERR;
4399 : }
4400 :
4401 : {
4402 : char *withdraw_fee_s;
4403 : char *deposit_fee_s;
4404 : char *refresh_fee_s;
4405 : char *refund_fee_s;
4406 : char *deposit_s;
4407 : char *legal_s;
4408 :
4409 0 : withdraw_fee_s = TALER_amount_to_string (&fees.withdraw);
4410 0 : deposit_fee_s = TALER_amount_to_string (&fees.deposit);
4411 0 : refresh_fee_s = TALER_amount_to_string (&fees.refresh);
4412 0 : refund_fee_s = TALER_amount_to_string (&fees.refund);
4413 0 : deposit_s = GNUNET_strdup (
4414 : GNUNET_TIME_timestamp2s (stamp_expire_deposit));
4415 0 : legal_s = GNUNET_strdup (
4416 : GNUNET_TIME_timestamp2s (stamp_expire_legal));
4417 :
4418 0 : printf (
4419 : "DENOMINATION-KEY(%s) %s of value %s starting at %s "
4420 : "(used for: %s, deposit until: %s legal end: %s) with fees %s/%s/%s/%s\n",
4421 : section_name,
4422 : TALER_B2S (&h_denom_pub),
4423 : TALER_amount2s (&coin_value),
4424 : GNUNET_TIME_timestamp2s (stamp_start),
4425 : GNUNET_TIME_relative2s (duration,
4426 : false),
4427 : deposit_s,
4428 : legal_s,
4429 : withdraw_fee_s,
4430 : deposit_fee_s,
4431 : refresh_fee_s,
4432 : refund_fee_s);
4433 0 : GNUNET_free (withdraw_fee_s);
4434 0 : GNUNET_free (deposit_fee_s);
4435 0 : GNUNET_free (refresh_fee_s);
4436 0 : GNUNET_free (refund_fee_s);
4437 0 : GNUNET_free (deposit_s);
4438 0 : GNUNET_free (legal_s);
4439 : }
4440 :
4441 0 : GNUNET_JSON_parse_free (spec);
4442 : }
4443 0 : return GNUNET_OK;
4444 : }
4445 :
4446 :
4447 : /**
4448 : * Parse the input of exchange keys for the 'show' and 'sign' commands.
4449 : *
4450 : * @param command_name name of the command, for logging
4451 : * @return NULL on error, otherwise the keys details to be free'd by caller
4452 : */
4453 : static json_t *
4454 19 : parse_keys_input (const char *command_name)
4455 : {
4456 : const char *op_str;
4457 : json_t *keys;
4458 : struct GNUNET_JSON_Specification spec[] = {
4459 19 : GNUNET_JSON_spec_json ("arguments",
4460 : &keys),
4461 19 : GNUNET_JSON_spec_string ("operation",
4462 : &op_str),
4463 19 : GNUNET_JSON_spec_end ()
4464 : };
4465 : const char *err_name;
4466 : unsigned int err_line;
4467 :
4468 19 : if (NULL == in)
4469 : {
4470 : json_error_t err;
4471 :
4472 0 : in = json_loadf (stdin,
4473 : JSON_REJECT_DUPLICATES,
4474 : &err);
4475 0 : if (NULL == in)
4476 : {
4477 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4478 : "Failed to read JSON input: %s at %d:%s (offset: %d)\n",
4479 : err.text,
4480 : err.line,
4481 : err.source,
4482 : err.position);
4483 0 : global_ret = EXIT_FAILURE;
4484 0 : GNUNET_SCHEDULER_shutdown ();
4485 0 : return NULL;
4486 : }
4487 : }
4488 19 : if (GNUNET_OK !=
4489 19 : GNUNET_JSON_parse (in,
4490 : spec,
4491 : &err_name,
4492 : &err_line))
4493 : {
4494 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4495 : "Invalid input to '%s': %s#%u (skipping)\n",
4496 : command_name,
4497 : err_name,
4498 : err_line);
4499 0 : json_dumpf (in,
4500 : stderr,
4501 : JSON_INDENT (2));
4502 0 : global_ret = EXIT_FAILURE;
4503 0 : GNUNET_SCHEDULER_shutdown ();
4504 0 : return NULL;
4505 : }
4506 19 : if (0 != strcmp (op_str,
4507 : OP_INPUT_KEYS))
4508 : {
4509 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4510 : "Invalid input to '%s' : operation is `%s', expected `%s'\n",
4511 : command_name,
4512 : op_str,
4513 : OP_INPUT_KEYS);
4514 0 : GNUNET_JSON_parse_free (spec);
4515 0 : return NULL;
4516 : }
4517 19 : json_decref (in);
4518 19 : in = NULL;
4519 19 : return keys;
4520 : }
4521 :
4522 :
4523 : /**
4524 : * Show future keys.
4525 : *
4526 : * @param args the array of command-line arguments to process next
4527 : */
4528 : static void
4529 0 : do_show (char *const *args)
4530 : {
4531 : json_t *keys;
4532 : const char *err_name;
4533 : unsigned int err_line;
4534 : const json_t *denomkeys;
4535 : const json_t *signkeys;
4536 : struct TALER_MasterPublicKeyP mpub;
4537 : struct TALER_SecurityModulePublicKeySetP secmset;
4538 : struct GNUNET_JSON_Specification spec[] = {
4539 0 : GNUNET_JSON_spec_array_const ("future_denoms",
4540 : &denomkeys),
4541 0 : GNUNET_JSON_spec_array_const ("future_signkeys",
4542 : &signkeys),
4543 0 : GNUNET_JSON_spec_fixed_auto ("master_pub",
4544 : &mpub),
4545 0 : GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
4546 : &secmset.rsa),
4547 0 : GNUNET_JSON_spec_fixed_auto ("denom_secmod_cs_public_key",
4548 : &secmset.cs),
4549 0 : GNUNET_JSON_spec_fixed_auto ("signkey_secmod_public_key",
4550 : &secmset.eddsa),
4551 0 : GNUNET_JSON_spec_end ()
4552 : };
4553 :
4554 0 : keys = parse_keys_input ("show");
4555 0 : if (NULL == keys)
4556 0 : return;
4557 :
4558 0 : if (GNUNET_OK !=
4559 0 : load_offline_key (GNUNET_NO))
4560 0 : return;
4561 0 : if (GNUNET_OK !=
4562 0 : GNUNET_JSON_parse (keys,
4563 : spec,
4564 : &err_name,
4565 : &err_line))
4566 : {
4567 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4568 : "Invalid input to 'show': %s #%u (skipping)\n",
4569 : err_name,
4570 : err_line);
4571 0 : json_dumpf (in,
4572 : stderr,
4573 : JSON_INDENT (2));
4574 0 : global_ret = EXIT_FAILURE;
4575 0 : GNUNET_SCHEDULER_shutdown ();
4576 0 : json_decref (keys);
4577 0 : return;
4578 : }
4579 0 : if (0 !=
4580 0 : GNUNET_memcmp (&master_pub,
4581 : &mpub))
4582 : {
4583 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4584 : "Fatal: exchange uses different master key!\n");
4585 0 : global_ret = EXIT_FAILURE;
4586 0 : GNUNET_SCHEDULER_shutdown ();
4587 0 : json_decref (keys);
4588 0 : return;
4589 : }
4590 0 : if (GNUNET_SYSERR ==
4591 0 : tofu_check (&secmset))
4592 : {
4593 0 : global_ret = EXIT_FAILURE;
4594 0 : GNUNET_SCHEDULER_shutdown ();
4595 0 : json_decref (keys);
4596 0 : return;
4597 : }
4598 0 : if ( (GNUNET_OK !=
4599 0 : show_signkeys (&secmset.eddsa,
4600 0 : signkeys)) ||
4601 : (GNUNET_OK !=
4602 0 : show_denomkeys (&secmset.rsa,
4603 : &secmset.cs,
4604 : denomkeys)) )
4605 : {
4606 0 : global_ret = EXIT_FAILURE;
4607 0 : GNUNET_SCHEDULER_shutdown ();
4608 0 : json_decref (keys);
4609 0 : return;
4610 : }
4611 0 : json_decref (keys);
4612 0 : next (args);
4613 : }
4614 :
4615 :
4616 : /**
4617 : * Sign @a signkeys with offline key.
4618 : *
4619 : * @param secm_pub security module public key used to sign the denominations
4620 : * @param signkeys keys to output
4621 : * @param[in,out] result array where to output the signatures
4622 : * @return #GNUNET_OK on success
4623 : */
4624 : static enum GNUNET_GenericReturnValue
4625 19 : sign_signkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
4626 : const json_t *signkeys,
4627 : json_t *result)
4628 : {
4629 : size_t index;
4630 : json_t *value;
4631 :
4632 40 : json_array_foreach (signkeys, index, value) {
4633 : const char *err_name;
4634 : unsigned int err_line;
4635 : struct TALER_ExchangePublicKeyP exchange_pub;
4636 : struct TALER_SecurityModuleSignatureP secm_sig;
4637 : struct GNUNET_TIME_Timestamp start_time;
4638 : struct GNUNET_TIME_Timestamp sign_end;
4639 : struct GNUNET_TIME_Timestamp legal_end;
4640 : struct GNUNET_TIME_Relative duration;
4641 : struct GNUNET_JSON_Specification spec[] = {
4642 21 : GNUNET_JSON_spec_timestamp ("stamp_start",
4643 : &start_time),
4644 21 : GNUNET_JSON_spec_timestamp ("stamp_expire",
4645 : &sign_end),
4646 21 : GNUNET_JSON_spec_timestamp ("stamp_end",
4647 : &legal_end),
4648 21 : GNUNET_JSON_spec_fixed_auto ("key",
4649 : &exchange_pub),
4650 21 : GNUNET_JSON_spec_fixed_auto ("signkey_secmod_sig",
4651 : &secm_sig),
4652 21 : GNUNET_JSON_spec_end ()
4653 : };
4654 :
4655 21 : if (GNUNET_OK !=
4656 21 : GNUNET_JSON_parse (value,
4657 : spec,
4658 : &err_name,
4659 : &err_line))
4660 : {
4661 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4662 : "Invalid input for signing key to 'show': %s #%u at %u (skipping)\n",
4663 : err_name,
4664 : err_line,
4665 : (unsigned int) index);
4666 0 : json_dumpf (value,
4667 : stderr,
4668 : JSON_INDENT (2));
4669 0 : global_ret = EXIT_FAILURE;
4670 0 : GNUNET_SCHEDULER_shutdown ();
4671 0 : return GNUNET_SYSERR;
4672 : }
4673 :
4674 21 : duration = GNUNET_TIME_absolute_get_difference (start_time.abs_time,
4675 : sign_end.abs_time);
4676 21 : if (GNUNET_OK !=
4677 21 : TALER_exchange_secmod_eddsa_verify (&exchange_pub,
4678 : start_time,
4679 : duration,
4680 : secm_pub,
4681 : &secm_sig))
4682 : {
4683 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4684 : "Invalid security module signature for signing key %s (aborting)\n",
4685 : TALER_B2S (&exchange_pub));
4686 0 : global_ret = EXIT_FAILURE;
4687 0 : GNUNET_SCHEDULER_shutdown ();
4688 0 : GNUNET_JSON_parse_free (spec);
4689 0 : return GNUNET_SYSERR;
4690 : }
4691 : {
4692 : struct TALER_MasterSignatureP master_sig;
4693 :
4694 21 : TALER_exchange_offline_signkey_validity_sign (&exchange_pub,
4695 : start_time,
4696 : sign_end,
4697 : legal_end,
4698 : &master_priv,
4699 : &master_sig);
4700 21 : GNUNET_assert (0 ==
4701 : json_array_append_new (
4702 : result,
4703 : GNUNET_JSON_PACK (
4704 : GNUNET_JSON_pack_data_auto ("exchange_pub",
4705 : &exchange_pub),
4706 : GNUNET_JSON_pack_data_auto ("master_sig",
4707 : &master_sig))));
4708 : }
4709 21 : GNUNET_JSON_parse_free (spec);
4710 : }
4711 19 : return GNUNET_OK;
4712 : }
4713 :
4714 :
4715 : /**
4716 : * Looks up the AGE_RESTRICTED setting for a denomination in the config and
4717 : * returns the age restriction (mask) accordingly.
4718 : *
4719 : * @param section_name Section in the configuration for the particular
4720 : * denomination.
4721 : */
4722 : static struct TALER_AgeMask
4723 355 : load_age_mask (const char*section_name)
4724 : {
4725 : static const struct TALER_AgeMask null_mask = {0};
4726 : enum GNUNET_GenericReturnValue ret;
4727 :
4728 355 : if (GNUNET_YES !=
4729 355 : GNUNET_CONFIGURATION_get_value_yesno (kcfg,
4730 : "exchange",
4731 : "AGE_RESTRICTION_ENABLED"))
4732 25 : return null_mask;
4733 :
4734 330 : if (GNUNET_OK != (GNUNET_CONFIGURATION_have_value (
4735 : kcfg,
4736 : section_name,
4737 : "AGE_RESTRICTED")))
4738 165 : return null_mask;
4739 :
4740 165 : ret = GNUNET_CONFIGURATION_get_value_yesno (kcfg,
4741 : section_name,
4742 : "AGE_RESTRICTED");
4743 165 : if (GNUNET_SYSERR == ret)
4744 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
4745 : section_name,
4746 : "AGE_RESTRICTED",
4747 : "Value must be YES or NO\n");
4748 165 : if (GNUNET_YES == ret)
4749 : {
4750 165 : char *groups = NULL;
4751 165 : struct TALER_AgeMask mask = {0};
4752 :
4753 165 : if (GNUNET_OK !=
4754 165 : GNUNET_CONFIGURATION_get_value_string (kcfg,
4755 : "exchange",
4756 : "AGE_GROUPS",
4757 : &groups))
4758 165 : groups = GNUNET_strdup ("8:10:12:14:16:18:21");
4759 165 : if (GNUNET_OK ==
4760 165 : TALER_parse_age_group_string (groups, &mask))
4761 : {
4762 165 : GNUNET_free (groups);
4763 165 : return mask;
4764 : }
4765 0 : GNUNET_free (groups);
4766 : }
4767 :
4768 0 : return null_mask;
4769 : }
4770 :
4771 :
4772 : /**
4773 : * Sign @a denomkeys with offline key.
4774 : *
4775 : * @param secm_pub_rsa security module public key used to sign the RSA denominations
4776 : * @param secm_pub_cs security module public key used to sign the CS denominations
4777 : * @param denomkeys keys to output
4778 : * @param[in,out] result array where to output the signatures
4779 : * @return #GNUNET_OK on success
4780 : */
4781 : static enum GNUNET_GenericReturnValue
4782 19 : sign_denomkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub_rsa,
4783 : const struct TALER_SecurityModulePublicKeyP *secm_pub_cs,
4784 : const json_t *denomkeys,
4785 : json_t *result)
4786 : {
4787 : size_t index;
4788 : json_t *value;
4789 :
4790 374 : json_array_foreach (denomkeys, index, value) {
4791 : const char *err_name;
4792 : unsigned int err_line;
4793 : const char *section_name;
4794 : struct TALER_DenominationPublicKey denom_pub;
4795 : struct GNUNET_TIME_Timestamp stamp_start;
4796 : struct GNUNET_TIME_Timestamp stamp_expire_withdraw;
4797 : struct GNUNET_TIME_Timestamp stamp_expire_deposit;
4798 : struct GNUNET_TIME_Timestamp stamp_expire_legal;
4799 : struct TALER_Amount coin_value;
4800 : struct TALER_DenomFeeSet fees;
4801 : struct TALER_SecurityModuleSignatureP secm_sig;
4802 : struct GNUNET_JSON_Specification spec[] = {
4803 355 : GNUNET_JSON_spec_string ("section_name",
4804 : §ion_name),
4805 355 : TALER_JSON_spec_denom_pub ("denom_pub",
4806 : &denom_pub),
4807 355 : TALER_JSON_spec_amount ("value",
4808 : currency,
4809 : &coin_value),
4810 355 : TALER_JSON_SPEC_DENOM_FEES ("fee",
4811 : currency,
4812 : &fees),
4813 355 : GNUNET_JSON_spec_timestamp ("stamp_start",
4814 : &stamp_start),
4815 355 : GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
4816 : &stamp_expire_withdraw),
4817 355 : GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
4818 : &stamp_expire_deposit),
4819 355 : GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
4820 : &stamp_expire_legal),
4821 355 : GNUNET_JSON_spec_fixed_auto ("denom_secmod_sig",
4822 : &secm_sig),
4823 355 : GNUNET_JSON_spec_end ()
4824 : };
4825 : struct GNUNET_TIME_Relative duration;
4826 : struct TALER_DenominationHashP h_denom_pub;
4827 :
4828 355 : if (GNUNET_OK !=
4829 355 : GNUNET_JSON_parse (value,
4830 : spec,
4831 : &err_name,
4832 : &err_line))
4833 : {
4834 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4835 : "Invalid input for denomination key to 'sign': %s #%u at %u (skipping)\n",
4836 : err_name,
4837 : err_line,
4838 : (unsigned int) index);
4839 0 : json_dumpf (value,
4840 : stderr,
4841 : JSON_INDENT (2));
4842 0 : GNUNET_JSON_parse_free (spec);
4843 0 : global_ret = EXIT_FAILURE;
4844 0 : GNUNET_SCHEDULER_shutdown ();
4845 0 : return GNUNET_SYSERR;
4846 : }
4847 355 : duration = GNUNET_TIME_absolute_get_difference (
4848 : stamp_start.abs_time,
4849 : stamp_expire_withdraw.abs_time);
4850 :
4851 : /* Load the age mask, if applicable to this denomination */
4852 355 : denom_pub.age_mask = load_age_mask (section_name);
4853 :
4854 355 : TALER_denom_pub_hash (&denom_pub,
4855 : &h_denom_pub);
4856 :
4857 355 : switch (denom_pub.bsign_pub_key->cipher)
4858 : {
4859 196 : case GNUNET_CRYPTO_BSA_RSA:
4860 : {
4861 : struct TALER_RsaPubHashP h_rsa;
4862 :
4863 196 : TALER_rsa_pub_hash (denom_pub.bsign_pub_key->details.rsa_public_key,
4864 : &h_rsa);
4865 196 : if (GNUNET_OK !=
4866 196 : TALER_exchange_secmod_rsa_verify (&h_rsa,
4867 : section_name,
4868 : stamp_start,
4869 : duration,
4870 : secm_pub_rsa,
4871 : &secm_sig))
4872 : {
4873 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4874 : "Invalid security module signature for denomination key %s (aborting)\n",
4875 : GNUNET_h2s (&h_denom_pub.hash));
4876 0 : global_ret = EXIT_FAILURE;
4877 0 : GNUNET_SCHEDULER_shutdown ();
4878 0 : GNUNET_JSON_parse_free (spec);
4879 0 : return GNUNET_SYSERR;
4880 : }
4881 : }
4882 196 : break;
4883 159 : case GNUNET_CRYPTO_BSA_CS:
4884 : {
4885 : struct TALER_CsPubHashP h_cs;
4886 :
4887 159 : TALER_cs_pub_hash (&denom_pub.bsign_pub_key->details.cs_public_key,
4888 : &h_cs);
4889 159 : if (GNUNET_OK !=
4890 159 : TALER_exchange_secmod_cs_verify (&h_cs,
4891 : section_name,
4892 : stamp_start,
4893 : duration,
4894 : secm_pub_cs,
4895 : &secm_sig))
4896 : {
4897 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4898 : "Invalid security module signature for denomination key %s (aborting)\n",
4899 : GNUNET_h2s (&h_denom_pub.hash));
4900 0 : global_ret = EXIT_FAILURE;
4901 0 : GNUNET_SCHEDULER_shutdown ();
4902 0 : GNUNET_JSON_parse_free (spec);
4903 0 : return GNUNET_SYSERR;
4904 : }
4905 : }
4906 159 : break;
4907 0 : default:
4908 0 : global_ret = EXIT_FAILURE;
4909 0 : GNUNET_SCHEDULER_shutdown ();
4910 0 : GNUNET_JSON_parse_free (spec);
4911 0 : return GNUNET_SYSERR;
4912 : }
4913 :
4914 : {
4915 : struct TALER_MasterSignatureP master_sig;
4916 :
4917 355 : TALER_exchange_offline_denom_validity_sign (&h_denom_pub,
4918 : stamp_start,
4919 : stamp_expire_withdraw,
4920 : stamp_expire_deposit,
4921 : stamp_expire_legal,
4922 : &coin_value,
4923 : &fees,
4924 : &master_priv,
4925 : &master_sig);
4926 355 : GNUNET_assert (0 ==
4927 : json_array_append_new (
4928 : result,
4929 : GNUNET_JSON_PACK (
4930 : GNUNET_JSON_pack_data_auto ("h_denom_pub",
4931 : &h_denom_pub),
4932 : GNUNET_JSON_pack_data_auto ("master_sig",
4933 : &master_sig))));
4934 : }
4935 355 : GNUNET_JSON_parse_free (spec);
4936 : }
4937 19 : return GNUNET_OK;
4938 : }
4939 :
4940 :
4941 : /**
4942 : * Sign future keys.
4943 : *
4944 : * @param args the array of command-line arguments to process next
4945 : */
4946 : static void
4947 19 : do_sign (char *const *args)
4948 : {
4949 : json_t *keys;
4950 : const char *err_name;
4951 : unsigned int err_line;
4952 : const json_t *denomkeys;
4953 : const json_t *signkeys;
4954 : struct TALER_MasterPublicKeyP mpub;
4955 : struct TALER_SecurityModulePublicKeySetP secmset;
4956 : struct GNUNET_JSON_Specification spec[] = {
4957 19 : GNUNET_JSON_spec_array_const ("future_denoms",
4958 : &denomkeys),
4959 19 : GNUNET_JSON_spec_array_const ("future_signkeys",
4960 : &signkeys),
4961 19 : GNUNET_JSON_spec_fixed_auto ("master_pub",
4962 : &mpub),
4963 19 : GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
4964 : &secmset.rsa),
4965 19 : GNUNET_JSON_spec_fixed_auto ("denom_secmod_cs_public_key",
4966 : &secmset.cs),
4967 19 : GNUNET_JSON_spec_fixed_auto ("signkey_secmod_public_key",
4968 : &secmset.eddsa),
4969 19 : GNUNET_JSON_spec_end ()
4970 : };
4971 :
4972 19 : keys = parse_keys_input ("sign");
4973 19 : if (NULL == keys)
4974 0 : return;
4975 19 : if (GNUNET_OK !=
4976 19 : load_offline_key (GNUNET_NO))
4977 : {
4978 0 : json_decref (keys);
4979 0 : return;
4980 : }
4981 19 : if (GNUNET_OK !=
4982 19 : GNUNET_JSON_parse (keys,
4983 : spec,
4984 : &err_name,
4985 : &err_line))
4986 : {
4987 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4988 : "Invalid input to 'sign' : %s #%u (skipping)\n",
4989 : err_name,
4990 : err_line);
4991 0 : json_dumpf (in,
4992 : stderr,
4993 : JSON_INDENT (2));
4994 0 : global_ret = EXIT_FAILURE;
4995 0 : GNUNET_SCHEDULER_shutdown ();
4996 0 : json_decref (keys);
4997 0 : return;
4998 : }
4999 19 : if (0 !=
5000 19 : GNUNET_memcmp (&master_pub,
5001 : &mpub))
5002 : {
5003 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5004 : "Fatal: exchange uses different master key!\n");
5005 0 : global_ret = EXIT_FAILURE;
5006 0 : GNUNET_SCHEDULER_shutdown ();
5007 0 : json_decref (keys);
5008 0 : return;
5009 : }
5010 19 : if (GNUNET_SYSERR ==
5011 19 : tofu_check (&secmset))
5012 : {
5013 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5014 : "Fatal: security module keys changed!\n");
5015 0 : global_ret = EXIT_FAILURE;
5016 0 : GNUNET_SCHEDULER_shutdown ();
5017 0 : json_decref (keys);
5018 0 : return;
5019 : }
5020 : {
5021 19 : json_t *signkey_sig_array = json_array ();
5022 19 : json_t *denomkey_sig_array = json_array ();
5023 :
5024 19 : GNUNET_assert (NULL != signkey_sig_array);
5025 19 : GNUNET_assert (NULL != denomkey_sig_array);
5026 19 : if ( (GNUNET_OK !=
5027 19 : sign_signkeys (&secmset.eddsa,
5028 : signkeys,
5029 19 : signkey_sig_array)) ||
5030 : (GNUNET_OK !=
5031 19 : sign_denomkeys (&secmset.rsa,
5032 : &secmset.cs,
5033 : denomkeys,
5034 : denomkey_sig_array)) )
5035 : {
5036 0 : global_ret = EXIT_FAILURE;
5037 0 : GNUNET_SCHEDULER_shutdown ();
5038 0 : json_decref (signkey_sig_array);
5039 0 : json_decref (denomkey_sig_array);
5040 0 : json_decref (keys);
5041 0 : return;
5042 : }
5043 :
5044 19 : output_operation (OP_UPLOAD_SIGS,
5045 19 : GNUNET_JSON_PACK (
5046 : GNUNET_JSON_pack_array_steal ("denom_sigs",
5047 : denomkey_sig_array),
5048 : GNUNET_JSON_pack_array_steal ("signkey_sigs",
5049 : signkey_sig_array)));
5050 : }
5051 19 : json_decref (keys);
5052 19 : next (args);
5053 : }
5054 :
5055 :
5056 : /**
5057 : * Setup and output offline signing key.
5058 : *
5059 : * @param args the array of command-line arguments to process next
5060 : */
5061 : static void
5062 0 : do_setup (char *const *args)
5063 : {
5064 0 : if (GNUNET_OK !=
5065 0 : load_offline_key (GNUNET_YES))
5066 : {
5067 0 : global_ret = EXIT_NOPERMISSION;
5068 0 : return;
5069 : }
5070 0 : if (NULL != *args)
5071 : {
5072 0 : output_operation (OP_SETUP,
5073 0 : GNUNET_JSON_PACK (
5074 : GNUNET_JSON_pack_data_auto ("exchange_offline_pub",
5075 : &master_pub)));
5076 : }
5077 :
5078 : else
5079 : {
5080 : char *pub_s;
5081 :
5082 0 : pub_s = GNUNET_STRINGS_data_to_string_alloc (&master_pub,
5083 : sizeof (master_pub));
5084 0 : fprintf (stdout,
5085 : "%s\n",
5086 : pub_s);
5087 0 : GNUNET_free (pub_s);
5088 : }
5089 0 : if ( (NULL != *args) &&
5090 0 : (0 == strcmp (*args,
5091 : "-")) )
5092 0 : args++;
5093 0 : next (args);
5094 : }
5095 :
5096 :
5097 :
5098 : /**
5099 : * Dispatch @a args in the @a cmds array.
5100 : *
5101 : * @param args arguments with subcommand to dispatch
5102 : * @param cmds array of possible subcommands to call
5103 : */
5104 : static void
5105 167 : cmd_handler (char *const *args,
5106 : const struct SubCommand *cmds)
5107 : {
5108 167 : nxt = NULL;
5109 1757 : for (unsigned int i = 0; NULL != cmds[i].name; i++)
5110 : {
5111 1757 : if (0 == strcasecmp (cmds[i].name,
5112 : args[0]))
5113 : {
5114 167 : cmds[i].cb (&args[1]);
5115 167 : return;
5116 : }
5117 : }
5118 :
5119 0 : if (0 != strcasecmp ("help",
5120 : args[0]))
5121 : {
5122 0 : GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
5123 : "Unexpected command `%s'\n",
5124 : args[0]);
5125 0 : global_ret = EXIT_INVALIDARGUMENT;
5126 : }
5127 :
5128 0 : GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
5129 : "Supported subcommands:\n");
5130 0 : for (unsigned int i = 0; NULL != cmds[i].name; i++)
5131 : {
5132 0 : GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
5133 : "- %s: %s\n",
5134 : cmds[i].name,
5135 : cmds[i].help);
5136 : }
5137 0 : json_decref (out);
5138 0 : out = NULL;
5139 0 : GNUNET_SCHEDULER_shutdown ();
5140 : }
5141 :
5142 :
5143 :
5144 : static void
5145 167 : work (void *cls)
5146 : {
5147 167 : char *const *args = cls;
5148 167 : struct SubCommand cmds[] = {
5149 : {
5150 : .name = "setup",
5151 : .help =
5152 : "initialize offline key signing material and display public offline key",
5153 : .cb = &do_setup
5154 : },
5155 : {
5156 : .name = "download",
5157 : .help =
5158 : "obtain future public keys from exchange (to be performed online!)",
5159 : .cb = &do_download
5160 : },
5161 : {
5162 : .name = "show",
5163 : .help =
5164 : "display future public keys from exchange for human review (pass '-' as argument to disable consuming input)",
5165 : .cb = &do_show
5166 : },
5167 : {
5168 : .name = "sign",
5169 : .help = "sign all future public keys from the input",
5170 : .cb = &do_sign
5171 : },
5172 : {
5173 : .name = "revoke-denomination",
5174 : .help =
5175 : "revoke denomination key (hash of public key must be given as argument)",
5176 : .cb = &do_revoke_denomination_key
5177 : },
5178 : {
5179 : .name = "revoke-signkey",
5180 : .help =
5181 : "revoke exchange online signing key (public key must be given as argument)",
5182 : .cb = &do_revoke_signkey
5183 : },
5184 : {
5185 : .name = "enable-auditor",
5186 : .help =
5187 : "enable auditor for the exchange (auditor-public key, auditor-URI and auditor-name must be given as arguments)",
5188 : .cb = &do_add_auditor
5189 : },
5190 : {
5191 : .name = "disable-auditor",
5192 : .help =
5193 : "disable auditor at the exchange (auditor-public key must be given as argument)",
5194 : .cb = &do_del_auditor
5195 : },
5196 : {
5197 : .name = "enable-account",
5198 : .help =
5199 : "enable wire account of the exchange (payto-URI must be given as argument; for optional arguments see man page)",
5200 : .cb = &do_add_wire
5201 : },
5202 : {
5203 : .name = "disable-account",
5204 : .help =
5205 : "disable wire account of the exchange (payto-URI must be given as argument)",
5206 : .cb = &do_del_wire
5207 : },
5208 : {
5209 : .name = "wire-fee",
5210 : .help =
5211 : "sign wire fees for the given year (year, wire method, wire fee, and closing fee must be given as arguments)",
5212 : .cb = &do_set_wire_fee
5213 : },
5214 : {
5215 : .name = "global-fee",
5216 : .help =
5217 : "sign global fees for the given year (year, history fee, account fee, purse fee, purse timeout, history expiration and the maximum number of free purses per account must be given as arguments)",
5218 : .cb = &do_set_global_fee
5219 : },
5220 : {
5221 : .name = "drain",
5222 : .help =
5223 : "drain profits from exchange escrow account to regular exchange operator account (amount, debit account configuration section and credit account payto://-URI must be given as arguments)",
5224 : .cb = &do_drain
5225 : },
5226 : {
5227 : .name = "add-partner",
5228 : .help =
5229 : "add partner exchange for P2P wad transfers (partner master public key, partner base URL, wad fee, wad frequency and validity year must be given as arguments)",
5230 : .cb = &do_add_partner
5231 : },
5232 : {
5233 : .name = "aml-enable",
5234 : .help =
5235 : "enable AML staff member (staff member public key, legal name and rw (read write) or ro (read only) must be given as arguments)",
5236 : .cb = &enable_aml_staff
5237 : },
5238 : {
5239 : .name = "aml-disable",
5240 : .help =
5241 : "disable AML staff member (staff member public key and legal name must be given as arguments)",
5242 : .cb = &disable_aml_staff
5243 : },
5244 : {
5245 : .name = "upload",
5246 : .help =
5247 : "upload operation result to exchange (to be performed online!)",
5248 : .cb = &do_upload
5249 : },
5250 : /* list terminator */
5251 : {
5252 : .name = NULL,
5253 : }
5254 : };
5255 : (void) cls;
5256 :
5257 167 : cmd_handler (args, cmds);
5258 167 : }
5259 :
5260 :
5261 : /**
5262 : * Main function that will be run.
5263 : *
5264 : * @param cls closure
5265 : * @param args remaining command-line arguments
5266 : * @param cfgfile name of the configuration file used (for saving, can be NULL!)
5267 : * @param cfg configuration
5268 : */
5269 : static void
5270 40 : run (void *cls,
5271 : char *const *args,
5272 : const char *cfgfile,
5273 : const struct GNUNET_CONFIGURATION_Handle *cfg)
5274 : {
5275 : (void) cls;
5276 : (void) cfgfile;
5277 40 : kcfg = cfg;
5278 :
5279 : /* age restriction is read per-denomination in load_age_mask() from [exchange] */
5280 :
5281 :
5282 40 : if (GNUNET_OK !=
5283 40 : TALER_config_get_currency (kcfg,
5284 : "exchange",
5285 : ¤cy))
5286 : {
5287 0 : global_ret = EXIT_NOTCONFIGURED;
5288 0 : return;
5289 : }
5290 :
5291 40 : ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
5292 : &rc);
5293 40 : rc = GNUNET_CURL_gnunet_rc_create (ctx);
5294 40 : GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
5295 : NULL);
5296 40 : next (args);
5297 : }
5298 :
5299 :
5300 : /**
5301 : * The main function of the taler-exchange-offline tool. This tool is used to
5302 : * create the signing and denomination keys for the exchange. It uses the
5303 : * long-term offline private key and generates signatures with it. It also
5304 : * supports online operations with the exchange to download its input data and
5305 : * to upload its results. Those online operations should be performed on
5306 : * another machine in production!
5307 : *
5308 : * @param argc number of arguments from the command line
5309 : * @param argv command line arguments
5310 : * @return 0 ok, 1 on error
5311 : */
5312 : int
5313 40 : main (int argc,
5314 : char *const *argv)
5315 : {
5316 40 : struct GNUNET_GETOPT_CommandLineOption options[] = {
5317 : GNUNET_GETOPT_OPTION_END
5318 : };
5319 : enum GNUNET_GenericReturnValue ret;
5320 :
5321 40 : ret = GNUNET_PROGRAM_run (
5322 : TALER_EXCHANGE_project_data (),
5323 : argc, argv,
5324 : "taler-exchange-offline",
5325 : gettext_noop ("Operations for offline signing for a Taler exchange"),
5326 : options,
5327 : &run, NULL);
5328 40 : if (GNUNET_SYSERR == ret)
5329 0 : return EXIT_INVALIDARGUMENT;
5330 40 : if (GNUNET_NO == ret)
5331 0 : return EXIT_SUCCESS;
5332 40 : return global_ret;
5333 : }
5334 :
5335 :
5336 : /* end of taler-exchange-offline.c */
|