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