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