LCOV - code coverage report
Current view: top level - exchange-tools - taler-exchange-offline.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 31.6 % 1616 511
Test Date: 2025-12-22 22:38:17 Functions: 50.0 % 66 33

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

Generated by: LCOV version 2.0-1