LCOV - code coverage report
Current view: top level - exchange-tools - taler-exchange-offline.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 33.3 % 1569 522
Test Date: 2026-06-14 14:19:22 Functions: 54.1 % 61 33

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

Generated by: LCOV version 2.0-1