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