LCOV - code coverage report
Current view: top level - exchange-tools - taler-exchange-offline.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 31.3 % 1660 520
Test Date: 2026-04-14 15:39:31 Functions: 50.0 % 66 33

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

Generated by: LCOV version 2.0-1