LCOV - code coverage report
Current view: top level - exchange-tools - taler-exchange-offline.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 35.1 % 1568 551
Test Date: 2026-10-17 15:46:49 Functions: 59.0 % 61 36

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

Generated by: LCOV version 2.0-1