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