LCOV - code coverage report
Current view: top level - auditor - taler-auditor-httpd.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 52.3 % 214 112
Test Date: 2026-01-18 12:54:31 Functions: 80.0 % 10 8

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2014-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 Affero 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 Affero General Public License for more details.
      12              : 
      13              :   You should have received a copy of the GNU Affero General Public License along with
      14              :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15              : */
      16              : 
      17              : /**
      18              :  * @file taler-auditor-httpd.c
      19              :  * @brief Serve the HTTP interface of the auditor
      20              :  * @defgroup request Request handling routines
      21              :  * @author Florian Dold
      22              :  * @author Benedikt Mueller
      23              :  * @author Christian Grothoff
      24              :  */
      25              : #include "taler/platform.h"
      26              : #include <gnunet/gnunet_util_lib.h>
      27              : #include <jansson.h>
      28              : #include <microhttpd.h>
      29              : #include <pthread.h>
      30              : #include <sys/resource.h>
      31              : #include "taler/taler_mhd_lib.h"
      32              : #include "taler/taler_auditordb_lib.h"
      33              : #include "taler/taler_exchangedb_lib.h"
      34              : #include "taler-auditor-httpd_spa.h"
      35              : #include "taler-auditor-httpd_deposit-confirmation.h"
      36              : #include "taler-auditor-httpd_deposit-confirmation-get.h"
      37              : #include "taler-auditor-httpd_amount-arithmetic-inconsistency-get.h"
      38              : #include "taler-auditor-httpd_coin-inconsistency-get.h"
      39              : #include "taler-auditor-httpd_row-inconsistency-get.h"
      40              : #include "taler-auditor-httpd_emergency-get.h"
      41              : #include "taler-auditor-httpd_emergency-by-count-get.h"
      42              : #include "taler-auditor-httpd_early-aggregation-get.h"
      43              : #include                                                                \
      44              :   "taler-auditor-httpd_denomination-key-validity-withdraw-inconsistency-get.h"
      45              : #include "taler-auditor-httpd_purse-not-closed-inconsistencies-get.h"
      46              : #include "taler-auditor-httpd_reserve-balance-insufficient-inconsistency-get.h"
      47              : #include "taler-auditor-httpd_bad-sig-losses-get.h"
      48              : #include "taler-auditor-httpd_closure-lags-get.h"
      49              : #include "taler-auditor-httpd_mhd.h"
      50              : #include "taler-auditor-httpd.h"
      51              : #include "taler-auditor-httpd_delete_generic.h"
      52              : #include "taler-auditor-httpd_patch_generic_suppressed.h"
      53              : #include "taler-auditor-httpd_reserve-in-inconsistency-get.h"
      54              : #include "taler-auditor-httpd_reserve-not-closed-inconsistency-get.h"
      55              : #include "taler-auditor-httpd_denominations-without-sigs-get.h"
      56              : #include "taler-auditor-httpd_misattribution-in-inconsistency-get.h"
      57              : #include "taler-auditor-httpd_reserves-get.h"
      58              : #include "taler-auditor-httpd_pending-deposits-get.h"
      59              : #include "taler-auditor-httpd_purses-get.h"
      60              : #include "taler-auditor-httpd_historic-denomination-revenue-get.h"
      61              : #include "taler-auditor-httpd_historic-reserve-summary-get.h"
      62              : #include "taler-auditor-httpd_denomination-pending-get.h"
      63              : #include "taler-auditor-httpd_wire-format-inconsistency-get.h"
      64              : #include "taler-auditor-httpd_wire-out-inconsistency-get.h"
      65              : #include "taler-auditor-httpd_reserve-balance-summary-wrong-inconsistency-get.h"
      66              : #include "taler-auditor-httpd_row-minor-inconsistencies-get.h"
      67              : #include "taler-auditor-httpd_fee-time-inconsistency-get.h"
      68              : #include "taler-auditor-httpd_balances-get.h"
      69              : #include "taler-auditor-httpd_progress-get.h"
      70              : 
      71              : 
      72              : /**
      73              :  * Auditor protocol version string.
      74              :  *
      75              :  * Taler protocol version in the format CURRENT:REVISION:AGE
      76              :  * as used by GNU libtool.  See
      77              :  * https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
      78              :  *
      79              :  * Please be very careful when updating and follow
      80              :  * https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
      81              :  * precisely.  Note that this version has NOTHING to do with the
      82              :  * release version, and the format is NOT the same that semantic
      83              :  * versioning uses either.
      84              :  */
      85              : #define AUDITOR_PROTOCOL_VERSION "1:0:1"
      86              : 
      87              : /**
      88              :  * Salt we use when doing the KDF for access.
      89              :  */
      90              : #define KDF_SALT "auditor-standard-auth"
      91              : 
      92              : /**
      93              :  * Backlog for listen operation on unix domain sockets.
      94              :  */
      95              : #define UNIX_BACKLOG 500
      96              : 
      97              : /**
      98              :  * Should we return "Connection: close" in each response?
      99              :  */
     100              : static int auditor_connection_close;
     101              : 
     102              : /**
     103              :  * The auditor's configuration.
     104              :  */
     105              : static const struct GNUNET_CONFIGURATION_Handle *cfg;
     106              : 
     107              : /**
     108              :  * Our DB plugin.
     109              :  */
     110              : struct TALER_AUDITORDB_Plugin *TAH_plugin;
     111              : 
     112              : /**
     113              :  * Our DB plugin to talk to the *exchange* database.
     114              :  */
     115              : struct TALER_EXCHANGEDB_Plugin *TAH_eplugin;
     116              : 
     117              : /**
     118              :  * Public key of this auditor.
     119              :  */
     120              : static struct TALER_AuditorPublicKeyP auditor_pub;
     121              : 
     122              : /**
     123              :  * Exchange master public key (according to the
     124              :  * configuration).  (global)
     125              :  */
     126              : struct TALER_MasterPublicKeyP TAH_master_public_key;
     127              : 
     128              : /**
     129              :  * Default timeout in seconds for HTTP requests.
     130              :  */
     131              : static unsigned int connection_timeout = 30;
     132              : 
     133              : /**
     134              :  * Return value from main()
     135              :  */
     136              : static int global_ret;
     137              : 
     138              : /**
     139              :  * Disables authentication checks.
     140              :  */
     141              : static int disable_auth;
     142              : 
     143              : /**
     144              :  * True if we started any HTTP daemon.
     145              :  */
     146              : static bool have_daemons;
     147              : 
     148              : /**
     149              :  * Our currency.
     150              :  */
     151              : char *TAH_currency;
     152              : 
     153              : /**
     154              :  * Authorization code to use.
     155              :  */
     156              : static struct GNUNET_HashCode TAH_auth;
     157              : 
     158              : /**
     159              :  * Prefix required for the access token.
     160              :  */
     161              : #define RFC_8959_PREFIX "secret-token:"
     162              : 
     163              : 
     164              : /**
     165              :  * Function called whenever MHD is done with a request.  If the
     166              :  * request was a POST, we may have stored a `struct Buffer *` in the
     167              :  * @a con_cls that might still need to be cleaned up.  Call the
     168              :  * respective function to free the memory.
     169              :  *
     170              :  * @param cls client-defined closure
     171              :  * @param connection connection handle
     172              :  * @param con_cls value as set by the last call to
     173              :  *        the #MHD_AccessHandlerCallback
     174              :  * @param toe reason for request termination
     175              :  * @see #MHD_OPTION_NOTIFY_COMPLETED
     176              :  * @ingroup request
     177              :  */
     178              : static void
     179           13 : handle_mhd_completion_callback (void *cls,
     180              :                                 struct MHD_Connection *connection,
     181              :                                 void **con_cls,
     182              :                                 enum MHD_RequestTerminationCode toe)
     183              : {
     184              :   (void) cls;
     185              :   (void) connection;
     186              :   (void) toe;
     187           13 :   if (NULL == *con_cls)
     188           13 :     return;
     189            0 :   TALER_MHD_parse_post_cleanup_callback (*con_cls);
     190            0 :   *con_cls = NULL;
     191              : }
     192              : 
     193              : 
     194              : /**
     195              :  * Handle a "/config" request.
     196              :  *
     197              :  * @param rh context of the handler
     198              :  * @param connection the MHD connection to handle
     199              :  * @param[in,out] connection_cls the connection's closure (can be updated)
     200              :  * @param upload_data upload data
     201              :  * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
     202              :  * @param args NULL-terminated array of remaining parts of the URI broken up at '/'
     203              :  * @return MHD result code
     204              :  */
     205              : static MHD_RESULT
     206            9 : handle_config (struct TAH_RequestHandler *rh,
     207              :                struct MHD_Connection *connection,
     208              :                void **connection_cls,
     209              :                const char *upload_data,
     210              :                size_t *upload_data_size,
     211              :                const char *const args[])
     212              : {
     213              :   static json_t *ver; /* we build the response only once, keep around for next query! */
     214              : 
     215              :   (void) rh;
     216              :   (void) upload_data;
     217              :   (void) upload_data_size;
     218              :   (void) connection_cls;
     219            9 :   if (NULL == ver)
     220              :   {
     221            5 :     ver = GNUNET_JSON_PACK (
     222              :       GNUNET_JSON_pack_string ("name",
     223              :                                "taler-auditor"),
     224              :       GNUNET_JSON_pack_string ("version",
     225              :                                AUDITOR_PROTOCOL_VERSION),
     226              :       GNUNET_JSON_pack_string ("implementation",
     227              :                                "urn:net:taler:specs:taler-auditor:c-reference"),
     228              :       GNUNET_JSON_pack_string ("currency",
     229              :                                TAH_currency),
     230              :       GNUNET_JSON_pack_data_auto ("auditor_public_key",
     231              :                                   &auditor_pub),
     232              :       GNUNET_JSON_pack_data_auto ("exchange_master_public_key",
     233              :                                   &TAH_master_public_key));
     234              :   }
     235            9 :   if (NULL == ver)
     236              :   {
     237            0 :     GNUNET_break (0);
     238            0 :     return MHD_NO;
     239              :   }
     240            9 :   return TALER_MHD_reply_json (connection,
     241              :                                ver,
     242              :                                MHD_HTTP_OK);
     243              : }
     244              : 
     245              : 
     246              : /**
     247              :  * Extract the token from authorization header value @a auth.
     248              :  *
     249              :  * @param auth pointer to authorization header value,
     250              :  *        will be updated to point to the start of the token
     251              :  *        or set to NULL if header value is invalid
     252              :  */
     253              : static void
     254            0 : extract_token (const char **auth)
     255              : {
     256            0 :   const char *bearer = "Bearer ";
     257            0 :   const char *tok = *auth;
     258              : 
     259            0 :   if (0 != strncmp (tok,
     260              :                     bearer,
     261              :                     strlen (bearer)))
     262              :   {
     263            0 :     *auth = NULL;
     264            0 :     return;
     265              :   }
     266            0 :   tok += strlen (bearer);
     267            0 :   while (' ' == *tok)
     268            0 :     tok++;
     269            0 :   if (0 != strncasecmp (tok,
     270              :                         RFC_8959_PREFIX,
     271              :                         strlen (RFC_8959_PREFIX)))
     272              :   {
     273            0 :     *auth = NULL;
     274            0 :     return;
     275              :   }
     276            0 :   *auth = tok;
     277              : }
     278              : 
     279              : 
     280              : static enum GNUNET_GenericReturnValue
     281            0 : check_auth (const char *token)
     282              : {
     283              :   struct GNUNET_HashCode val;
     284              : 
     285            0 :   if (NULL == token)
     286            0 :     return GNUNET_SYSERR;
     287            0 :   token += strlen (RFC_8959_PREFIX);
     288            0 :   GNUNET_assert (GNUNET_YES ==
     289              :                  GNUNET_CRYPTO_kdf (&val,
     290              :                                     sizeof (val),
     291              :                                     KDF_SALT,
     292              :                                     strlen (KDF_SALT),
     293              :                                     token,
     294              :                                     strlen (token),
     295              :                                     NULL,
     296              :                                     0));
     297              :   /* We compare hashes instead of directly comparing
     298              :      tokens to minimize side-channel attacks on token length */
     299              :   return (0 ==
     300            0 :           GNUNET_memcmp_priv (&val,
     301              :                               &TAH_auth))
     302              :            ? GNUNET_OK
     303            0 :            : GNUNET_SYSERR;
     304              : }
     305              : 
     306              : 
     307              : /**
     308              :  * Handle incoming HTTP request.
     309              :  *
     310              :  * @param cls closure for MHD daemon (unused)
     311              :  * @param connection the connection
     312              :  * @param url the requested url
     313              :  * @param method the method (POST, GET, ...)
     314              :  * @param version HTTP version (ignored)
     315              :  * @param upload_data request data
     316              :  * @param upload_data_size size of @a upload_data in bytes
     317              :  * @param con_cls closure for request (a `struct Buffer *`)
     318              :  * @return MHD result code
     319              :  */
     320              : static MHD_RESULT
     321           19 : handle_mhd_request (void *cls,
     322              :                     struct MHD_Connection *connection,
     323              :                     const char *url,
     324              :                     const char *method,
     325              :                     const char *version,
     326              :                     const char *upload_data,
     327              :                     size_t *upload_data_size,
     328              :                     void **con_cls)
     329           19 : {
     330              :   static struct TAH_RequestHandler handlers[] = {
     331              :     /* Our most popular handler (thus first!), used by merchants to
     332              :        probabilistically report us their deposit confirmations. */
     333              :     { .url = "/deposit-confirmation",
     334              :       .method = MHD_HTTP_METHOD_PUT,
     335              :       .mime_type = "application/json",
     336              :       .handler = &TAH_DEPOSIT_CONFIRMATION_handler,
     337              :       .response_code = MHD_HTTP_OK},
     338              :     { .url = "/spa",
     339              :       .method = MHD_HTTP_METHOD_GET,
     340              :       .handler = &TAH_spa_handler},
     341              :     { .url = "/monitoring/deposit-confirmation",
     342              :       .method = MHD_HTTP_METHOD_GET,
     343              :       .mime_type = "application/json",
     344              :       .data = NULL,
     345              :       .data_size = 0,
     346              :       .handler = &TAH_DEPOSIT_CONFIRMATION_handler_get,
     347              :       .response_code = MHD_HTTP_OK,
     348              :       .requires_auth = true },
     349              :     { .url = "/monitoring/pending-deposits",
     350              :       .method = MHD_HTTP_METHOD_GET,
     351              :       .mime_type = "application/json",
     352              :       .data = NULL,
     353              :       .data_size = 0,
     354              :       .handler = &TAH_pending_deposits_handler_get,
     355              :       .response_code = MHD_HTTP_OK,
     356              :       .requires_auth = true },
     357              :     { .url = "/monitoring/early-aggregation",
     358              :       .method = MHD_HTTP_METHOD_GET,
     359              :       .mime_type = "application/json",
     360              :       .data = NULL,
     361              :       .data_size = 0,
     362              :       .handler = &TAH_early_aggregation_handler_get,
     363              :       .response_code = MHD_HTTP_OK,
     364              :       .requires_auth = true },
     365              :     { .url = "/monitoring/deposit-confirmation",
     366              :       .method = MHD_HTTP_METHOD_DELETE,
     367              :       .mime_type = "application/json",
     368              :       .data = NULL,
     369              :       .data_size = 0,
     370              :       .handler = &TAH_delete_handler_generic,
     371              :       .response_code = MHD_HTTP_OK,
     372              :       .requires_auth = true,
     373              :       .table = TALER_AUDITORDB_DEPOSIT_CONFIRMATION },
     374              :     { .url = "/monitoring/amount-arithmetic-inconsistency",
     375              :       .method = MHD_HTTP_METHOD_GET,
     376              :       .mime_type = "application/json",
     377              :       .data = NULL,
     378              :       .data_size = 0,
     379              :       .handler = &TAH_AMOUNT_ARITHMETIC_INCONSISTENCY_handler_get,
     380              :       .response_code = MHD_HTTP_OK,
     381              :       .requires_auth = true },
     382              :     { .url = "/monitoring/amount-arithmetic-inconsistency",
     383              :       .method = MHD_HTTP_METHOD_DELETE,
     384              :       .mime_type = "application/json",
     385              :       .data = NULL,
     386              :       .data_size = 0,
     387              :       .handler = &TAH_delete_handler_generic,
     388              :       .response_code = MHD_HTTP_OK,
     389              :       .requires_auth = true,
     390              :       .table = TALER_AUDITORDB_AMOUNT_ARITHMETIC_INCONSISTENCY },
     391              :     { .url = "/monitoring/amount-arithmetic-inconsistency",
     392              :       .method = MHD_HTTP_METHOD_PATCH,
     393              :       .mime_type = "application/json",
     394              :       .data = NULL,
     395              :       .data_size = 0,
     396              :       .handler = &TAH_patch_handler_generic_suppressed,
     397              :       .response_code = MHD_HTTP_OK,
     398              :       .requires_auth = true,
     399              :       .table = TALER_AUDITORDB_AMOUNT_ARITHMETIC_INCONSISTENCY },
     400              :     { .url = "/monitoring/coin-inconsistency",
     401              :       .method = MHD_HTTP_METHOD_GET,
     402              :       .mime_type = "application/json",
     403              :       .data = NULL,
     404              :       .data_size = 0,
     405              :       .handler = &TAH_COIN_INCONSISTENCY_handler_get,
     406              :       .response_code = MHD_HTTP_OK,
     407              :       .requires_auth = true },
     408              :     { .url = "/monitoring/coin-inconsistency",
     409              :       .method = MHD_HTTP_METHOD_DELETE,
     410              :       .mime_type = "application/json",
     411              :       .data = NULL,
     412              :       .data_size = 0,
     413              :       .handler = &TAH_delete_handler_generic,
     414              :       .response_code = MHD_HTTP_OK,
     415              :       .requires_auth = true,
     416              :       .table = TALER_AUDITORDB_COIN_INCONSISTENCY },
     417              :     { .url = "/monitoring/coin-inconsistency",
     418              :       .method = MHD_HTTP_METHOD_PATCH,
     419              :       .mime_type = "application/json",
     420              :       .data = NULL,
     421              :       .data_size = 0,
     422              :       .handler = &TAH_patch_handler_generic_suppressed,
     423              :       .response_code = MHD_HTTP_OK,
     424              :       .requires_auth = true,
     425              :       .table = TALER_AUDITORDB_COIN_INCONSISTENCY },
     426              :     { .url = "/monitoring/row-inconsistency",
     427              :       .method = MHD_HTTP_METHOD_GET,
     428              :       .mime_type = "application/json",
     429              :       .data = NULL,
     430              :       .data_size = 0,
     431              :       .handler = &TAH_ROW_INCONSISTENCY_handler_get,
     432              :       .response_code = MHD_HTTP_OK,
     433              :       .requires_auth = true },
     434              :     { .url = "/monitoring/row-inconsistency",
     435              :       .method = MHD_HTTP_METHOD_DELETE,
     436              :       .mime_type = "application/json",
     437              :       .data = NULL,
     438              :       .data_size = 0,
     439              :       .handler = &TAH_delete_handler_generic,
     440              :       .response_code = MHD_HTTP_OK,
     441              :       .requires_auth = true,
     442              :       .table = TALER_AUDITORDB_ROW_INCONSISTENCY},
     443              :     { .url = "/monitoring/row-inconsistency",
     444              :       .method = MHD_HTTP_METHOD_PATCH,
     445              :       .mime_type = "application/json",
     446              :       .data = NULL,
     447              :       .data_size = 0,
     448              :       .handler = &TAH_patch_handler_generic_suppressed,
     449              :       .response_code = MHD_HTTP_OK,
     450              :       .requires_auth = true,
     451              :       .table = TALER_AUDITORDB_ROW_INCONSISTENCY },
     452              :     { .url = "/monitoring/bad-sig-losses",
     453              :       .method = MHD_HTTP_METHOD_GET,
     454              :       .mime_type = "application/json",
     455              :       .data = NULL,
     456              :       .data_size = 0,
     457              :       .handler = &TAH_BAD_SIG_LOSSES_handler_get,
     458              :       .response_code = MHD_HTTP_OK,
     459              :       .requires_auth = true },
     460              :     { .url = "/monitoring/bad-sig-losses",
     461              :       .method = MHD_HTTP_METHOD_DELETE,
     462              :       .mime_type = "application/json",
     463              :       .data = NULL,
     464              :       .data_size = 0,
     465              :       .handler = &TAH_delete_handler_generic,
     466              :       .response_code = MHD_HTTP_OK,
     467              :       .requires_auth = true,
     468              :       .table = TALER_AUDITORDB_BAD_SIG_LOSSES},
     469              :     { .url = "/monitoring/bad-sig-losses",
     470              :       .method = MHD_HTTP_METHOD_PATCH,
     471              :       .mime_type = "application/json",
     472              :       .data = NULL,
     473              :       .data_size = 0,
     474              :       .handler = &TAH_patch_handler_generic_suppressed,
     475              :       .response_code = MHD_HTTP_OK,
     476              :       .requires_auth = true,
     477              :       .table = TALER_AUDITORDB_BAD_SIG_LOSSES },
     478              :     { .url = "/monitoring/closure-lags",
     479              :       .method = MHD_HTTP_METHOD_GET,
     480              :       .mime_type = "application/json",
     481              :       .data = NULL,
     482              :       .data_size = 0,
     483              :       .handler = &TAH_CLOSURE_LAGS_handler_get,
     484              :       .response_code = MHD_HTTP_OK,
     485              :       .requires_auth = true },
     486              :     { .url = "/monitoring/closure-lags",
     487              :       .method = MHD_HTTP_METHOD_DELETE,
     488              :       .mime_type = "application/json",
     489              :       .data = NULL,
     490              :       .data_size = 0,
     491              :       .handler = &TAH_delete_handler_generic,
     492              :       .response_code = MHD_HTTP_OK,
     493              :       .requires_auth = true,
     494              :       .table = TALER_AUDITORDB_CLOSURE_LAGS },
     495              :     { .url = "/monitoring/closure-lags",
     496              :       .method = MHD_HTTP_METHOD_PATCH,
     497              :       .mime_type = "application/json",
     498              :       .data = NULL,
     499              :       .data_size = 0,
     500              :       .handler = &TAH_patch_handler_generic_suppressed,
     501              :       .response_code = MHD_HTTP_OK,
     502              :       .requires_auth = true,
     503              :       .table = TALER_AUDITORDB_CLOSURE_LAGS },
     504              :     { .url = "/monitoring/emergency",
     505              :       .method = MHD_HTTP_METHOD_GET,
     506              :       .mime_type = "application/json",
     507              :       .data = NULL,
     508              :       .data_size = 0,
     509              :       .handler = &TAH_EMERGENCY_handler_get,
     510              :       .response_code = MHD_HTTP_OK,
     511              :       .requires_auth = true },
     512              :     { .url = "/monitoring/emergency",
     513              :       .method = MHD_HTTP_METHOD_DELETE,
     514              :       .mime_type = "application/json",
     515              :       .data = NULL,
     516              :       .data_size = 0,
     517              :       .handler = &TAH_delete_handler_generic,
     518              :       .response_code = MHD_HTTP_OK,
     519              :       .requires_auth = true,
     520              :       .table = TALER_AUDITORDB_EMERGENCY },
     521              :     { .url = "/monitoring/emergency",
     522              :       .method = MHD_HTTP_METHOD_PATCH,
     523              :       .mime_type = "application/json",
     524              :       .data = NULL,
     525              :       .data_size = 0,
     526              :       .handler = &TAH_patch_handler_generic_suppressed,
     527              :       .response_code = MHD_HTTP_OK,
     528              :       .requires_auth = true,
     529              :       .table = TALER_AUDITORDB_EMERGENCY  },
     530              :     { .url = "/monitoring/denomination-key-validity-withdraw-inconsistency",
     531              :       .method = MHD_HTTP_METHOD_GET,
     532              :       .mime_type = "application/json",
     533              :       .data = NULL,
     534              :       .data_size = 0,
     535              :       .handler =
     536              :         &TAH_DENOMINATION_KEY_VALIDITY_WITHDRAW_INCONSISTENCY_handler_get,
     537              :       .response_code = MHD_HTTP_OK,
     538              :       .requires_auth = true },
     539              :     { .url = "/monitoring/denomination-key-validity-withdraw-inconsistency",
     540              :       .method = MHD_HTTP_METHOD_DELETE,
     541              :       .mime_type = "application/json",
     542              :       .data = NULL,
     543              :       .data_size = 0,
     544              :       .handler = &TAH_delete_handler_generic,
     545              :       .response_code = MHD_HTTP_OK,
     546              :       .requires_auth = true,
     547              :       .table = TALER_AUDITORDB_DENOMINATION_KEY_VALIDITY_WITHDRAW_INCONSISTENCY}
     548              :     ,
     549              :     { .url = "/monitoring/denomination-key-validity-withdraw-inconsistency",
     550              :       .method = MHD_HTTP_METHOD_PATCH,
     551              :       .mime_type = "application/json",
     552              :       .data = NULL,
     553              :       .data_size = 0,
     554              :       .handler = &TAH_patch_handler_generic_suppressed,
     555              :       .response_code = MHD_HTTP_OK,
     556              :       .requires_auth = true,
     557              :       .table = TALER_AUDITORDB_DENOMINATION_KEY_VALIDITY_WITHDRAW_INCONSISTENCY}
     558              :     ,
     559              :     { .url = "/monitoring/reserve-balance-insufficient-inconsistency",
     560              :       .method = MHD_HTTP_METHOD_GET,
     561              :       .mime_type = "application/json",
     562              :       .data = NULL,
     563              :       .data_size = 0,
     564              :       .handler = &TAH_RESERVE_BALANCE_INSUFFICIENT_INCONSISTENCY_handler_get,
     565              :       .response_code = MHD_HTTP_OK,
     566              :       .requires_auth = true },
     567              :     { .url = "/monitoring/reserve-balance-insufficient-inconsistency",
     568              :       .method = MHD_HTTP_METHOD_DELETE,
     569              :       .mime_type = "application/json",
     570              :       .data = NULL,
     571              :       .data_size = 0,
     572              :       .handler = &TAH_delete_handler_generic,
     573              :       .response_code = MHD_HTTP_OK,
     574              :       .requires_auth = true,
     575              :       .table = TALER_AUDITORDB_RESERVE_BALANCE_INSUFFICIENT_INCONSISTENCY },
     576              :     { .url = "/monitoring/reserve-balance-insufficient-inconsistency",
     577              :       .method = MHD_HTTP_METHOD_PATCH,
     578              :       .mime_type = "application/json",
     579              :       .data = NULL,
     580              :       .data_size = 0,
     581              :       .handler = &TAH_patch_handler_generic_suppressed,
     582              :       .response_code = MHD_HTTP_OK,
     583              :       .requires_auth = true,
     584              :       .table = TALER_AUDITORDB_RESERVE_BALANCE_INSUFFICIENT_INCONSISTENCY },
     585              :     { .url = "/monitoring/purse-not-closed-inconsistencies",
     586              :       .method = MHD_HTTP_METHOD_GET,
     587              :       .mime_type = "application/json",
     588              :       .data = NULL,
     589              :       .data_size = 0,
     590              :       .handler = &TAH_PURSE_NOT_CLOSED_INCONSISTENCIES_handler_get,
     591              :       .response_code = MHD_HTTP_OK,
     592              :       .requires_auth = true },
     593              :     { .url = "/monitoring/purse-not-closed-inconsistencies",
     594              :       .method = MHD_HTTP_METHOD_DELETE,
     595              :       .mime_type = "application/json",
     596              :       .data = NULL,
     597              :       .data_size = 0,
     598              :       .handler = &TAH_delete_handler_generic,
     599              :       .response_code = MHD_HTTP_OK,
     600              :       .requires_auth = true,
     601              :       .table = TALER_AUDITORDB_PURSE_NOT_CLOSED_INCONSISTENCY },
     602              :     { .url = "/monitoring/purse-not-closed-inconsistencies",
     603              :       .method = MHD_HTTP_METHOD_PATCH,
     604              :       .mime_type = "application/json",
     605              :       .data = NULL,
     606              :       .data_size = 0,
     607              :       .handler = &TAH_patch_handler_generic_suppressed,
     608              :       .response_code = MHD_HTTP_OK,
     609              :       .requires_auth = true,
     610              :       .table = TALER_AUDITORDB_PURSE_NOT_CLOSED_INCONSISTENCY  },
     611              :     { .url = "/monitoring/emergency-by-count",
     612              :       .method = MHD_HTTP_METHOD_GET,
     613              :       .mime_type = "application/json",
     614              :       .data = NULL,
     615              :       .data_size = 0,
     616              :       .handler = &TAH_EMERGENCY_BY_COUNT_handler_get,
     617              :       .response_code = MHD_HTTP_OK,
     618              :       .requires_auth = true },
     619              :     { .url = "/monitoring/emergency-by-count",
     620              :       .method = MHD_HTTP_METHOD_DELETE,
     621              :       .mime_type = "application/json",
     622              :       .data = NULL,
     623              :       .data_size = 0,
     624              :       .handler = &TAH_delete_handler_generic,
     625              :       .response_code = MHD_HTTP_OK,
     626              :       .requires_auth = true,
     627              :       .table = TALER_AUDITORDB_EMERGENCY_BY_COUNT },
     628              :     { .url = "/monitoring/emergency-by-count",
     629              :       .method = MHD_HTTP_METHOD_PATCH,
     630              :       .mime_type = "application/json",
     631              :       .data = NULL,
     632              :       .data_size = 0,
     633              :       .handler = &TAH_patch_handler_generic_suppressed,
     634              :       .response_code = MHD_HTTP_OK,
     635              :       .requires_auth = true,
     636              :       .table = TALER_AUDITORDB_EMERGENCY_BY_COUNT },
     637              :     { .url = "/monitoring/reserve-in-inconsistency",
     638              :       .method = MHD_HTTP_METHOD_GET,
     639              :       .mime_type = "application/json",
     640              :       .data = NULL,
     641              :       .data_size = 0,
     642              :       .handler = &TAH_RESERVE_IN_INCONSISTENCY_handler_get,
     643              :       .response_code = MHD_HTTP_OK,
     644              :       .requires_auth = true },
     645              :     { .url = "/monitoring/reserve-in-inconsistency",
     646              :       .method = MHD_HTTP_METHOD_DELETE,
     647              :       .mime_type = "application/json",
     648              :       .data = NULL,
     649              :       .data_size = 0,
     650              :       .handler = &TAH_delete_handler_generic,
     651              :       .response_code = MHD_HTTP_OK,
     652              :       .requires_auth = true,
     653              :       .table = TALER_AUDITORDB_RESERVE_IN_INCONSISTENCY },
     654              :     { .url = "/monitoring/reserve-in-inconsistency",
     655              :       .method = MHD_HTTP_METHOD_PATCH,
     656              :       .mime_type = "application/json",
     657              :       .data = NULL,
     658              :       .data_size = 0,
     659              :       .handler = &TAH_patch_handler_generic_suppressed,
     660              :       .response_code = MHD_HTTP_OK,
     661              :       .requires_auth = true,
     662              :       .table = TALER_AUDITORDB_RESERVE_IN_INCONSISTENCY  },
     663              :     { .url = "/monitoring/reserve-not-closed-inconsistency",
     664              :       .method = MHD_HTTP_METHOD_GET,
     665              :       .mime_type = "application/json",
     666              :       .data = NULL,
     667              :       .data_size = 0,
     668              :       .handler = &TAH_RESERVE_NOT_CLOSED_INCONSISTENCY_handler_get,
     669              :       .response_code = MHD_HTTP_OK,
     670              :       .requires_auth = true },
     671              :     { .url = "/monitoring/reserve-not-closed-inconsistency",
     672              :       .method = MHD_HTTP_METHOD_DELETE,
     673              :       .mime_type = "application/json",
     674              :       .data = NULL,
     675              :       .data_size = 0,
     676              :       .handler = &TAH_delete_handler_generic,
     677              :       .response_code = MHD_HTTP_OK,
     678              :       .requires_auth = true,
     679              :       .table = TALER_AUDITORDB_RESERVE_NOT_CLOSED_INCONSISTENCY },
     680              :     { .url = "/monitoring/reserve-not-closed-inconsistency",
     681              :       .method = MHD_HTTP_METHOD_PATCH,
     682              :       .mime_type = "application/json",
     683              :       .data = NULL,
     684              :       .data_size = 0,
     685              :       .handler = &TAH_patch_handler_generic_suppressed,
     686              :       .response_code = MHD_HTTP_OK,
     687              :       .requires_auth = true,
     688              :       .table = TALER_AUDITORDB_RESERVE_NOT_CLOSED_INCONSISTENCY },
     689              :     { .url = "/monitoring/denominations-without-sigs",
     690              :       .method = MHD_HTTP_METHOD_GET,
     691              :       .mime_type = "application/json",
     692              :       .data = NULL,
     693              :       .data_size = 0,
     694              :       .handler = &TAH_DENOMINATIONS_WITHOUT_SIGS_handler_get,
     695              :       .response_code = MHD_HTTP_OK,
     696              :       .requires_auth = true },
     697              :     { .url = "/monitoring/denominations-without-sigs",
     698              :       .method = MHD_HTTP_METHOD_DELETE,
     699              :       .mime_type = "application/json",
     700              :       .data = NULL,
     701              :       .data_size = 0,
     702              :       .handler = &TAH_delete_handler_generic,
     703              :       .response_code = MHD_HTTP_OK,
     704              :       .requires_auth = true,
     705              :       .table = TALER_AUDITORDB_DENOMINATIONS_WITHOUT_SIG },
     706              :     { .url = "/monitoring/denominations-without-sigs",
     707              :       .method = MHD_HTTP_METHOD_PATCH,
     708              :       .mime_type = "application/json",
     709              :       .data = NULL,
     710              :       .data_size = 0,
     711              :       .handler = &TAH_patch_handler_generic_suppressed,
     712              :       .response_code = MHD_HTTP_OK,
     713              :       .requires_auth = true,
     714              :       .table = TALER_AUDITORDB_DENOMINATIONS_WITHOUT_SIG },
     715              :     { .url = "/monitoring/misattribution-in-inconsistency",
     716              :       .method = MHD_HTTP_METHOD_GET,
     717              :       .mime_type = "application/json",
     718              :       .data = NULL,
     719              :       .data_size = 0,
     720              :       .handler = &TAH_MISATTRIBUTION_IN_INCONSISTENCY_handler_get,
     721              :       .response_code = MHD_HTTP_OK,
     722              :       .requires_auth = true },
     723              :     { .url = "/monitoring/misattribution-in-inconsistency",
     724              :       .method = MHD_HTTP_METHOD_DELETE,
     725              :       .mime_type = "application/json",
     726              :       .data = NULL,
     727              :       .data_size = 0,
     728              :       .handler = &TAH_delete_handler_generic,
     729              :       .response_code = MHD_HTTP_OK,
     730              :       .requires_auth = true,
     731              :       .table = TALER_AUDITORDB_MISATTRIBUTION_IN_INCONSISTENCY },
     732              :     { .url = "/monitoring/misattribution-in-inconsistency",
     733              :       .method = MHD_HTTP_METHOD_PATCH,
     734              :       .mime_type = "application/json",
     735              :       .data = NULL,
     736              :       .data_size = 0,
     737              :       .handler = &TAH_patch_handler_generic_suppressed,
     738              :       .response_code = MHD_HTTP_OK,
     739              :       .requires_auth = true,
     740              :       .table = TALER_AUDITORDB_MISATTRIBUTION_IN_INCONSISTENCY },
     741              :     { .url = "/monitoring/reserves",
     742              :       .method = MHD_HTTP_METHOD_GET,
     743              :       .mime_type = "application/json",
     744              :       .data = NULL,
     745              :       .data_size = 0,
     746              :       .handler = &TAH_RESERVES_handler_get,
     747              :       .response_code = MHD_HTTP_OK,
     748              :       .requires_auth = true },
     749              :     { .url = "/monitoring/purses",
     750              :       .method = MHD_HTTP_METHOD_GET,
     751              :       .mime_type = "application/json",
     752              :       .data = NULL,
     753              :       .data_size = 0,
     754              :       .handler = &TAH_PURSES_handler_get,
     755              :       .response_code = MHD_HTTP_OK,
     756              :       .requires_auth = true },
     757              :     { .url = "/monitoring/historic-denomination-revenue",
     758              :       .method = MHD_HTTP_METHOD_GET,
     759              :       .mime_type = "application/json",
     760              :       .data = NULL,
     761              :       .data_size = 0,
     762              :       .handler = &TAH_HISTORIC_DENOMINATION_REVENUE_handler_get,
     763              :       .response_code = MHD_HTTP_OK,
     764              :       .requires_auth = true },
     765              :     { .url = "/monitoring/denomination-pending",
     766              :       .method = MHD_HTTP_METHOD_GET,
     767              :       .mime_type = "application/json",
     768              :       .data = NULL,
     769              :       .data_size = 0,
     770              :       .handler = &TAH_DENOMINATION_PENDING_handler_get,
     771              :       .response_code = MHD_HTTP_OK,
     772              :       .requires_auth = true },
     773              :     { .url = "/monitoring/denomination-pending",
     774              :       .method = MHD_HTTP_METHOD_DELETE,
     775              :       .mime_type = "application/json",
     776              :       .data = NULL,
     777              :       .data_size = 0,
     778              :       .handler = &TAH_delete_handler_generic,
     779              :       .response_code = MHD_HTTP_OK,
     780              :       .requires_auth = true,
     781              :       .table = TALER_AUDITORDB_DENOMINATION_PENDING },
     782              :     { .url = "/monitoring/historic-reserve-summary",
     783              :       .method = MHD_HTTP_METHOD_GET,
     784              :       .mime_type = "application/json",
     785              :       .data = NULL,
     786              :       .data_size = 0,
     787              :       .handler = &TAH_HISTORIC_RESERVE_SUMMARY_handler_get,
     788              :       .response_code = MHD_HTTP_OK,
     789              :       .requires_auth = true },
     790              :     { .url = "/monitoring/wire-format-inconsistency",
     791              :       .method = MHD_HTTP_METHOD_GET,
     792              :       .mime_type = "application/json",
     793              :       .data = NULL,
     794              :       .data_size = 0,
     795              :       .handler = &TAH_WIRE_FORMAT_INCONSISTENCY_handler_get,
     796              :       .response_code = MHD_HTTP_OK,
     797              :       .requires_auth = true },
     798              :     { .url = "/monitoring/wire-format-inconsistency",
     799              :       .method = MHD_HTTP_METHOD_DELETE,
     800              :       .mime_type = "application/json",
     801              :       .data = NULL,
     802              :       .data_size = 0,
     803              :       .handler = &TAH_delete_handler_generic,
     804              :       .response_code = MHD_HTTP_OK,
     805              :       .requires_auth = true,
     806              :       .table = TALER_AUDITORDB_WIRE_FORMAT_INCONSISTENCY },
     807              :     { .url = "/monitoring/wire-format-inconsistency",
     808              :       .method = MHD_HTTP_METHOD_PATCH,
     809              :       .mime_type = "application/json",
     810              :       .data = NULL,
     811              :       .data_size = 0,
     812              :       .handler = &TAH_patch_handler_generic_suppressed,
     813              :       .response_code = MHD_HTTP_OK,
     814              :       .requires_auth = true,
     815              :       .table = TALER_AUDITORDB_WIRE_FORMAT_INCONSISTENCY },
     816              :     { .url = "/monitoring/wire-out-inconsistency",
     817              :       .method = MHD_HTTP_METHOD_GET,
     818              :       .mime_type = "application/json",
     819              :       .data = NULL,
     820              :       .data_size = 0,
     821              :       .handler = &TAH_WIRE_OUT_INCONSISTENCY_handler_get,
     822              :       .response_code = MHD_HTTP_OK,
     823              :       .requires_auth = true },
     824              :     { .url = "/monitoring/wire-out-inconsistency",
     825              :       .method = MHD_HTTP_METHOD_DELETE,
     826              :       .mime_type = "application/json",
     827              :       .data = NULL,
     828              :       .data_size = 0,
     829              :       .handler = &TAH_delete_handler_generic,
     830              :       .response_code = MHD_HTTP_OK,
     831              :       .requires_auth = true,
     832              :       .table = TALER_AUDITORDB_WIRE_OUT_INCONSISTENCY },
     833              :     { .url = "/monitoring/wire-out-inconsistency",
     834              :       .method = MHD_HTTP_METHOD_PATCH,
     835              :       .mime_type = "application/json",
     836              :       .data = NULL,
     837              :       .data_size = 0,
     838              :       .handler = &TAH_patch_handler_generic_suppressed,
     839              :       .response_code = MHD_HTTP_OK,
     840              :       .requires_auth = true,
     841              :       .table = TALER_AUDITORDB_WIRE_OUT_INCONSISTENCY },
     842              :     { .url = "/monitoring/reserve-balance-summary-wrong-inconsistency",
     843              :       .method = MHD_HTTP_METHOD_GET,
     844              :       .mime_type = "application/json",
     845              :       .data = NULL,
     846              :       .data_size = 0,
     847              :       .handler = &TAH_RESERVE_BALANCE_SUMMARY_WRONG_INCONSISTENCY_handler_get,
     848              :       .response_code = MHD_HTTP_OK,
     849              :       .requires_auth = true },
     850              :     { .url = "/monitoring/reserve-balance-summary-wrong-inconsistency",
     851              :       .method = MHD_HTTP_METHOD_DELETE,
     852              :       .mime_type = "application/json",
     853              :       .data = NULL,
     854              :       .data_size = 0,
     855              :       .handler = &TAH_delete_handler_generic,
     856              :       .response_code = MHD_HTTP_OK,
     857              :       .requires_auth = true,
     858              :       .table = TALER_AUDITORDB_RESERVE_BALANCE_SUMMARY_WRONG_INCONSISTENCY },
     859              :     { .url = "/monitoring/reserve-balance-summary-wrong-inconsistency",
     860              :       .method = MHD_HTTP_METHOD_PATCH,
     861              :       .mime_type = "application/json",
     862              :       .data = NULL,
     863              :       .data_size = 0,
     864              :       .handler = &TAH_patch_handler_generic_suppressed,
     865              :       .response_code = MHD_HTTP_OK,
     866              :       .requires_auth = true,
     867              :       .table = TALER_AUDITORDB_RESERVE_BALANCE_SUMMARY_WRONG_INCONSISTENCY },
     868              :     { .url = "/monitoring/row-minor-inconsistencies",
     869              :       .method = MHD_HTTP_METHOD_GET,
     870              :       .mime_type = "application/json",
     871              :       .data = NULL,
     872              :       .data_size = 0,
     873              :       .handler = &TAH_ROW_MINOR_INCONSISTENCIES_handler_get,
     874              :       .response_code = MHD_HTTP_OK,
     875              :       .requires_auth = true },
     876              :     { .url = "/monitoring/row-minor-inconsistencies",
     877              :       .method = MHD_HTTP_METHOD_DELETE,
     878              :       .mime_type = "application/json",
     879              :       .data = NULL,
     880              :       .data_size = 0,
     881              :       .handler = &TAH_delete_handler_generic,
     882              :       .response_code = MHD_HTTP_OK,
     883              :       .requires_auth = true,
     884              :       .table = TALER_AUDITORDB_ROW_MINOR_INCONSISTENCY },
     885              :     { .url = "/monitoring/row-minor-inconsistencies",
     886              :       .method = MHD_HTTP_METHOD_PATCH,
     887              :       .mime_type = "application/json",
     888              :       .data = NULL,
     889              :       .data_size = 0,
     890              :       .handler = &TAH_patch_handler_generic_suppressed,
     891              :       .response_code = MHD_HTTP_OK,
     892              :       .requires_auth = true,
     893              :       .table = TALER_AUDITORDB_ROW_MINOR_INCONSISTENCY },
     894              :     { .url = "/monitoring/fee-time-inconsistency",
     895              :       .method = MHD_HTTP_METHOD_GET,
     896              :       .mime_type = "application/json",
     897              :       .data = NULL,
     898              :       .data_size = 0,
     899              :       .handler = &TAH_FEE_TIME_INCONSISTENCY_handler_get,
     900              :       .response_code = MHD_HTTP_OK,
     901              :       .requires_auth = true },
     902              :     { .url = "/monitoring/fee-time-inconsistency",
     903              :       .method = MHD_HTTP_METHOD_DELETE,
     904              :       .mime_type = "application/json",
     905              :       .data = NULL,
     906              :       .data_size = 0,
     907              :       .handler = &TAH_delete_handler_generic,
     908              :       .response_code = MHD_HTTP_OK,
     909              :       .requires_auth = true,
     910              :       .table =  TALER_AUDITORDB_FEE_TIME_INCONSISTENCY },
     911              :     { .url = "/monitoring/fee-time-inconsistency",
     912              :       .method = MHD_HTTP_METHOD_PATCH,
     913              :       .mime_type = "application/json",
     914              :       .data = NULL,
     915              :       .data_size = 0,
     916              :       .handler = &TAH_patch_handler_generic_suppressed,
     917              :       .response_code = MHD_HTTP_OK,
     918              :       .requires_auth = true,
     919              :       .table =  TALER_AUDITORDB_FEE_TIME_INCONSISTENCY  },
     920              :     { .url = "/monitoring/balances",
     921              :       .method = MHD_HTTP_METHOD_GET,
     922              :       .mime_type = "application/json",
     923              :       .data = NULL,
     924              :       .data_size = 0,
     925              :       .handler = &TAH_BALANCES_handler_get,
     926              :       .response_code = MHD_HTTP_OK,
     927              :       .requires_auth = true },
     928              :     { .url = "/monitoring/progress",
     929              :       .method = MHD_HTTP_METHOD_GET,
     930              :       .mime_type = "application/json",
     931              :       .data = NULL,
     932              :       .data_size = 0,
     933              :       .handler = &TAH_PROGRESS_handler_get,
     934              :       .response_code = MHD_HTTP_OK,
     935              :       .requires_auth = true },
     936              :     { .url = "/config",
     937              :       .method = MHD_HTTP_METHOD_GET,
     938              :       .mime_type = "application/json",
     939              :       .data = NULL,
     940              :       .data_size = 0,
     941              :       .handler = &handle_config,
     942              :       .response_code = MHD_HTTP_OK,
     943              :       .requires_auth = false },
     944              :     /* /robots.txt: disallow everything */
     945              :     { .url = "/robots.txt",
     946              :       .method = MHD_HTTP_METHOD_GET,
     947              :       .mime_type = "text/plain",
     948              :       .data = "User-agent: *\nDisallow: /\n",
     949              :       .data_size = 0,
     950              :       .handler = &TAH_MHD_handler_static_response,
     951              :       .response_code = MHD_HTTP_OK,
     952              :       .requires_auth = false },
     953              :     /* AGPL licensing page, redirect to source. As per the AGPL-license,
     954              :        every deployment is required to offer the user a download of the
     955              :        source. We make this easy by including a redirect t the source
     956              :        here. */
     957              :     { .url = "/agpl",
     958              :       .method = MHD_HTTP_METHOD_GET,
     959              :       .mime_type = "text/plain",
     960              :       .data = NULL,
     961              :       .data_size = 0,
     962              :       .handler = &TAH_MHD_handler_agpl_redirect,
     963              :       .response_code = MHD_HTTP_FOUND,
     964              :       .requires_auth = false },
     965              :     /* Landing page, for now tells humans to go away
     966              :      * (NOTE: ideally, the reverse proxy will respond with a nicer page) */
     967              :     { .url = "/",
     968              :       .method = MHD_HTTP_METHOD_GET,
     969              :       .mime_type = "text/plain",
     970              :       .data =
     971              :         "Hello, I'm the Taler auditor. This HTTP server is not for humans.\n",
     972              :       .data_size = 0,
     973              :       .handler = &TAH_MHD_handler_static_response,
     974              :       .response_code = MHD_HTTP_OK,
     975              :       .requires_auth = false },
     976              :     { NULL, NULL, NULL, NULL, 0, NULL, 0, 0 }
     977              :   };
     978           19 :   unsigned int args_max = 3;
     979           19 :   const char *args[args_max + 1];
     980           19 :   size_t ulen = strlen (url) + 1;
     981           19 :   char d[ulen];
     982           19 :   /* const */ struct TAH_RequestHandler *match = NULL;
     983           19 :   bool url_match = false;
     984              : 
     985              :   (void) cls;
     986              :   (void) version;
     987           19 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     988              :               "Handling request for URL '%s'\n",
     989              :               url);
     990           19 :   if (0 == strcasecmp (method,
     991              :                        MHD_HTTP_METHOD_HEAD))
     992            0 :     method = MHD_HTTP_METHOD_GET; /* treat HEAD as GET here, MHD will do the rest */
     993           19 :   if (0 == strcasecmp (method,
     994              :                        MHD_HTTP_METHOD_OPTIONS) )
     995            0 :     return TALER_MHD_reply_cors_preflight (connection);
     996              : 
     997           19 :   memset (&args,
     998              :           0,
     999              :           sizeof (args));
    1000           19 :   GNUNET_memcpy (d,
    1001              :                  url,
    1002              :                  ulen);
    1003              :   {
    1004           19 :     unsigned int i = 0;
    1005              : 
    1006           19 :     for (args[i] = strtok (d,
    1007              :                            "/");
    1008           37 :          NULL != args[i];
    1009           18 :          args[i] = strtok (NULL,
    1010              :                            "/"))
    1011              :     {
    1012           18 :       i++;
    1013           18 :       if (i >= args_max)
    1014              :       {
    1015            0 :         GNUNET_break_op (0);
    1016            0 :         goto not_found;
    1017              :       }
    1018              :     }
    1019              :   }
    1020              : 
    1021          732 :   for (unsigned int i = 0; NULL != handlers[i].url; i++)
    1022              :   {
    1023          732 :     /* const */ struct TAH_RequestHandler *rh = &handlers[i];
    1024              : 
    1025          732 :     if ( (0 == strcmp (url,
    1026          713 :                        rh->url)) ||
    1027          713 :          ( (0 == strncmp (url,
    1028              :                           rh->url,
    1029            0 :                           strlen (rh->url))) &&
    1030            0 :            ('/' == url[strlen (rh->url)]) ) )
    1031              :     {
    1032           19 :       url_match = true;
    1033           19 :       if ( (NULL == rh->method) ||
    1034           19 :            (0 == strcasecmp (method,
    1035              :                              rh->method)) )
    1036              :       {
    1037           19 :         match = rh;
    1038           19 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1039              :                     "Matched %s\n",
    1040              :                     rh->url);
    1041           19 :         break;
    1042              :       }
    1043              :     }
    1044              :   }
    1045           19 :   if (NULL == match)
    1046              :   {
    1047            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1048              :                 "Could not find handler for `%s'\n",
    1049              :                 url);
    1050            0 :     goto not_found;
    1051              :   }
    1052           19 :   if (match->requires_auth &&
    1053            0 :       (0 == disable_auth) )
    1054              :   {
    1055              :     const char *auth;
    1056              : 
    1057            0 :     auth = MHD_lookup_connection_value (connection,
    1058              :                                         MHD_HEADER_KIND,
    1059              :                                         MHD_HTTP_HEADER_AUTHORIZATION);
    1060            0 :     if (NULL == auth)
    1061              :     {
    1062            0 :       GNUNET_break_op (0);
    1063            0 :       return TALER_MHD_reply_with_error (
    1064              :         connection,
    1065              :         MHD_HTTP_UNAUTHORIZED,
    1066              :         TALER_EC_AUDITOR_GENERIC_UNAUTHORIZED,
    1067              :         "Check 'Authorization' header");
    1068              :     }
    1069            0 :     extract_token (&auth);
    1070            0 :     if (NULL == auth)
    1071            0 :       return TALER_MHD_reply_with_error (
    1072              :         connection,
    1073              :         MHD_HTTP_UNAUTHORIZED,
    1074              :         TALER_EC_GENERIC_PARAMETER_MALFORMED,
    1075              :         "'" RFC_8959_PREFIX
    1076              :         "' prefix or 'Bearer' missing in 'Authorization' header");
    1077              : 
    1078            0 :     if (GNUNET_OK !=
    1079            0 :         check_auth (auth))
    1080              :     {
    1081            0 :       GNUNET_break_op (0);
    1082            0 :       return TALER_MHD_reply_with_error (
    1083              :         connection,
    1084              :         MHD_HTTP_UNAUTHORIZED,
    1085              :         TALER_EC_AUDITOR_GENERIC_UNAUTHORIZED,
    1086              :         "Check 'Authorization' header");
    1087              :     }
    1088              :   }
    1089              : 
    1090           19 :   return match->handler (match,
    1091              :                          connection,
    1092              :                          con_cls,
    1093              :                          upload_data,
    1094              :                          upload_data_size,
    1095              :                          args);
    1096            0 : not_found:
    1097            0 :   if (url_match)
    1098              :   {
    1099              :     /* FIXME: return list of allowed methods... - #9424 */
    1100            0 :     GNUNET_break (0);
    1101            0 :     return TALER_MHD_reply_with_error (
    1102              :       connection,
    1103              :       MHD_HTTP_METHOD_NOT_ALLOWED,
    1104              :       TALER_EC_AUDITOR_GENERIC_METHOD_NOT_ALLOWED,
    1105              :       "This method is currently disabled.");
    1106              :   }
    1107              : 
    1108              : #define NOT_FOUND \
    1109              :         "<html><title>404: not found</title><body>auditor endpoints have been moved to /monitoring/...</body></html>"
    1110            0 :   return TALER_MHD_reply_static (connection,
    1111              :                                  MHD_HTTP_NOT_FOUND,
    1112              :                                  "text/html",
    1113              :                                  NOT_FOUND,
    1114              :                                  strlen (NOT_FOUND));
    1115              : #undef NOT_FOUND
    1116              : }
    1117              : 
    1118              : 
    1119              : /**
    1120              :  * Load configuration parameters for the auditor
    1121              :  * server into the corresponding global variables.
    1122              :  *
    1123              :  * @return #GNUNET_OK on success
    1124              :  */
    1125              : static enum GNUNET_GenericReturnValue
    1126            5 : auditor_serve_process_config (void)
    1127              : {
    1128            5 :   if (NULL ==
    1129            5 :       (TAH_plugin = TALER_AUDITORDB_plugin_load (cfg,
    1130              :                                                  false)))
    1131              :   {
    1132            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1133              :                 "Failed to initialize DB subsystem to interact with auditor database\n");
    1134            0 :     return GNUNET_SYSERR;
    1135              :   }
    1136            5 :   if (NULL ==
    1137            5 :       (TAH_eplugin = TALER_EXCHANGEDB_plugin_load (cfg,
    1138              :                                                    false)))
    1139              :   {
    1140            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1141              :                 "Failed to initialize DB subsystem to query exchange database\n");
    1142            0 :     return GNUNET_SYSERR;
    1143              :   }
    1144            5 :   if (GNUNET_SYSERR ==
    1145            5 :       TAH_eplugin->preflight (TAH_eplugin->cls))
    1146              :   {
    1147            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1148              :                 "Failed to initialize DB subsystem to query exchange database\n");
    1149            0 :     return GNUNET_SYSERR;
    1150              :   }
    1151            5 :   if (GNUNET_OK !=
    1152            5 :       TALER_config_get_currency (cfg,
    1153              :                                  "exchange",
    1154              :                                  &TAH_currency))
    1155              :   {
    1156            0 :     return GNUNET_SYSERR;
    1157              :   }
    1158              : 
    1159              :   {
    1160              :     char *master_public_key_str;
    1161              : 
    1162            5 :     if (GNUNET_OK !=
    1163            5 :         GNUNET_CONFIGURATION_get_value_string (cfg,
    1164              :                                                "exchange",
    1165              :                                                "MASTER_PUBLIC_KEY",
    1166              :                                                &master_public_key_str))
    1167              :     {
    1168            0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1169              :                                  "exchange",
    1170              :                                  "MASTER_PUBLIC_KEY");
    1171            0 :       return GNUNET_SYSERR;
    1172              :     }
    1173            5 :     if (GNUNET_OK !=
    1174            5 :         GNUNET_CRYPTO_eddsa_public_key_from_string (
    1175              :           master_public_key_str,
    1176              :           strlen (master_public_key_str),
    1177              :           &TAH_master_public_key.eddsa_pub))
    1178              :     {
    1179            0 :       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    1180              :                                  "exchange",
    1181              :                                  "MASTER_PUBLIC_KEY",
    1182              :                                  "invalid base32 encoding for a master public key");
    1183            0 :       GNUNET_free (master_public_key_str);
    1184            0 :       return GNUNET_SYSERR;
    1185              :     }
    1186            5 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1187              :                 "Launching auditor for exchange `%s'...\n",
    1188              :                 master_public_key_str);
    1189            5 :     GNUNET_free (master_public_key_str);
    1190              :   }
    1191              : 
    1192              :   {
    1193              :     char *pub;
    1194              : 
    1195            5 :     if (GNUNET_OK ==
    1196            5 :         GNUNET_CONFIGURATION_get_value_string (cfg,
    1197              :                                                "AUDITOR",
    1198              :                                                "PUBLIC_KEY",
    1199              :                                                &pub))
    1200              :     {
    1201            5 :       if (GNUNET_OK !=
    1202            5 :           GNUNET_CRYPTO_eddsa_public_key_from_string (pub,
    1203              :                                                       strlen (pub),
    1204              :                                                       &auditor_pub.eddsa_pub))
    1205              :       {
    1206            0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1207              :                     "Invalid public key given in auditor configuration.");
    1208            0 :         GNUNET_free (pub);
    1209            5 :         return GNUNET_SYSERR;
    1210              :       }
    1211            5 :       GNUNET_free (pub);
    1212            5 :       return GNUNET_OK;
    1213              :     }
    1214              :   }
    1215              : 
    1216              :   {
    1217              :     /* Fall back to trying to read private key */
    1218              :     char *auditor_key_file;
    1219              :     struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv;
    1220              : 
    1221            0 :     if (GNUNET_OK !=
    1222            0 :         GNUNET_CONFIGURATION_get_value_filename (cfg,
    1223              :                                                  "auditor",
    1224              :                                                  "AUDITOR_PRIV_FILE",
    1225              :                                                  &auditor_key_file))
    1226              :     {
    1227            0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1228              :                                  "AUDITOR",
    1229              :                                  "PUBLIC_KEY");
    1230            0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1231              :                                  "AUDITOR",
    1232              :                                  "AUDITOR_PRIV_FILE");
    1233            0 :       return GNUNET_SYSERR;
    1234              :     }
    1235            0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1236              :                 "Loading auditor private key from %s\n",
    1237              :                 auditor_key_file);
    1238            0 :     if (GNUNET_OK !=
    1239            0 :         GNUNET_CRYPTO_eddsa_key_from_file (auditor_key_file,
    1240              :                                            GNUNET_NO,
    1241              :                                            &eddsa_priv))
    1242              :     {
    1243              :       /* Both failed, complain! */
    1244            0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1245              :                                  "AUDITOR",
    1246              :                                  "PUBLIC_KEY");
    1247            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1248              :                   "Failed to initialize auditor key from file `%s'\n",
    1249              :                   auditor_key_file);
    1250            0 :       GNUNET_free (auditor_key_file);
    1251            0 :       return 1;
    1252              :     }
    1253            0 :     GNUNET_free (auditor_key_file);
    1254            0 :     GNUNET_CRYPTO_eddsa_key_get_public (&eddsa_priv,
    1255              :                                         &auditor_pub.eddsa_pub);
    1256              :   }
    1257            0 :   return GNUNET_OK;
    1258              : }
    1259              : 
    1260              : 
    1261              : /**
    1262              :  * Function run on shutdown.
    1263              :  *
    1264              :  * @param cls NULL
    1265              :  */
    1266              : static void
    1267            5 : do_shutdown (void *cls)
    1268              : {
    1269              :   (void) cls;
    1270            5 :   TALER_MHD_daemons_halt ();
    1271            5 :   TEAH_DEPOSIT_CONFIRMATION_done ();
    1272            5 :   TALER_MHD_daemons_destroy ();
    1273            5 :   if (NULL != TAH_plugin)
    1274              :   {
    1275            5 :     TALER_AUDITORDB_plugin_unload (TAH_plugin);
    1276            5 :     TAH_plugin = NULL;
    1277              :   }
    1278            5 :   if (NULL != TAH_eplugin)
    1279              :   {
    1280            5 :     TALER_EXCHANGEDB_plugin_unload (TAH_eplugin);
    1281            5 :     TAH_eplugin = NULL;
    1282              :   }
    1283            5 : }
    1284              : 
    1285              : 
    1286              : /**
    1287              :  * Callback invoked on every listen socket to start the
    1288              :  * respective MHD HTTP daemon.
    1289              :  *
    1290              :  * @param cls unused
    1291              :  * @param lsock the listen socket
    1292              :  */
    1293              : static void
    1294           10 : start_daemon (void *cls,
    1295              :               int lsock)
    1296              : {
    1297              :   struct MHD_Daemon *mhd;
    1298              : 
    1299              :   (void) cls;
    1300           10 :   GNUNET_assert (-1 != lsock);
    1301           10 :   mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME
    1302              :                           | MHD_USE_PIPE_FOR_SHUTDOWN
    1303              :                           | MHD_USE_DEBUG | MHD_USE_DUAL_STACK
    1304              :                           | MHD_USE_TCP_FASTOPEN,
    1305              :                           0,
    1306              :                           NULL, NULL,
    1307              :                           &handle_mhd_request, NULL,
    1308              :                           MHD_OPTION_LISTEN_SOCKET,
    1309              :                           lsock,
    1310              :                           MHD_OPTION_EXTERNAL_LOGGER,
    1311              :                           &TALER_MHD_handle_logs,
    1312              :                           NULL,
    1313              :                           MHD_OPTION_NOTIFY_COMPLETED,
    1314              :                           &handle_mhd_completion_callback,
    1315              :                           NULL,
    1316              :                           MHD_OPTION_CONNECTION_TIMEOUT,
    1317              :                           connection_timeout,
    1318              :                           MHD_OPTION_END);
    1319           10 :   if (NULL == mhd)
    1320              :   {
    1321            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1322              :                 "Failed to launch HTTP daemon.\n");
    1323            0 :     GNUNET_SCHEDULER_shutdown ();
    1324            0 :     return;
    1325              :   }
    1326           10 :   have_daemons = true;
    1327           10 :   TALER_MHD_daemon_start (mhd);
    1328              : }
    1329              : 
    1330              : 
    1331              : /**
    1332              :  * Main function that will be run by the scheduler.
    1333              :  *
    1334              :  * @param cls closure
    1335              :  * @param args remaining command-line arguments
    1336              :  * @param cfgfile name of the configuration file used (for saving, can be
    1337              :  *        NULL!)
    1338              :  * @param config configuration
    1339              :  */
    1340              : static void
    1341            5 : run (void *cls,
    1342              :      char *const *args,
    1343              :      const char *cfgfile,
    1344              :      const struct GNUNET_CONFIGURATION_Handle *config)
    1345              : {
    1346              :   enum TALER_MHD_GlobalOptions go;
    1347              :   enum GNUNET_GenericReturnValue ret;
    1348              : 
    1349              :   (void) cls;
    1350              :   (void) args;
    1351              :   (void) cfgfile;
    1352            5 :   if (0 == disable_auth)
    1353              :   {
    1354              :     const char *tok;
    1355              : 
    1356            5 :     tok = getenv ("TALER_AUDITOR_ACCESS_TOKEN");
    1357            5 :     if (NULL == tok)
    1358              :     {
    1359            5 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1360              :                   "TALER_AUDITOR_ACCESS_TOKEN environment variable not set. Disabling authentication\n");
    1361            5 :       disable_auth = 1;
    1362              :     }
    1363              :     else
    1364              :     {
    1365            0 :       GNUNET_assert (GNUNET_YES ==
    1366              :                      GNUNET_CRYPTO_kdf (&TAH_auth,
    1367              :                                         sizeof (TAH_auth),
    1368              :                                         KDF_SALT,
    1369              :                                         strlen (KDF_SALT),
    1370              :                                         tok,
    1371              :                                         strlen (tok),
    1372              :                                         NULL,
    1373              :                                         0));
    1374              :     }
    1375              :   }
    1376              : 
    1377            5 :   go = TALER_MHD_GO_NONE;
    1378            5 :   if (auditor_connection_close)
    1379            0 :     go |= TALER_MHD_GO_FORCE_CONNECTION_CLOSE;
    1380            5 :   TALER_MHD_setup (go);
    1381            5 :   cfg = config;
    1382              : 
    1383            5 :   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
    1384              :                                  NULL);
    1385            5 :   if (GNUNET_OK !=
    1386            5 :       auditor_serve_process_config ())
    1387              :   {
    1388            0 :     global_ret = EXIT_NOTCONFIGURED;
    1389            0 :     GNUNET_SCHEDULER_shutdown ();
    1390            0 :     return;
    1391              :   }
    1392            5 :   if (GNUNET_OK !=
    1393            5 :       TAH_spa_init ())
    1394              :   {
    1395            0 :     global_ret = EXIT_NOTCONFIGURED;
    1396            0 :     GNUNET_SCHEDULER_shutdown ();
    1397            0 :     return;
    1398              :   }
    1399            5 :   TEAH_DEPOSIT_CONFIRMATION_init ();
    1400            5 :   ret = TALER_MHD_listen_bind (cfg,
    1401              :                                "auditor",
    1402              :                                &start_daemon,
    1403              :                                NULL);
    1404            5 :   switch (ret)
    1405              :   {
    1406            0 :   case GNUNET_SYSERR:
    1407            0 :     global_ret = EXIT_NOTCONFIGURED;
    1408            0 :     GNUNET_SCHEDULER_shutdown ();
    1409            0 :     return;
    1410            0 :   case GNUNET_NO:
    1411            0 :     if (! have_daemons)
    1412              :     {
    1413            0 :       global_ret = EXIT_NOTCONFIGURED;
    1414            0 :       GNUNET_SCHEDULER_shutdown ();
    1415            0 :       return;
    1416              :     }
    1417            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1418              :                 "Could not open all configured listen sockets\n");
    1419            0 :     break;
    1420            5 :   case GNUNET_OK:
    1421            5 :     break;
    1422              :   }
    1423            5 :   global_ret = EXIT_SUCCESS;
    1424              : }
    1425              : 
    1426              : 
    1427              : /**
    1428              :  * The main function of the taler-auditor-httpd server ("the auditor").
    1429              :  *
    1430              :  * @param argc number of arguments from the command line
    1431              :  * @param argv command line arguments
    1432              :  * @return 0 ok, 1 on error
    1433              :  */
    1434              : int
    1435            5 : main (int argc,
    1436              :       char *const *argv)
    1437              : {
    1438            5 :   const struct GNUNET_GETOPT_CommandLineOption options[] = {
    1439            5 :     GNUNET_GETOPT_option_flag ('C',
    1440              :                                "connection-close",
    1441              :                                "force HTTP connections to be closed after each request",
    1442              :                                &auditor_connection_close),
    1443            5 :     GNUNET_GETOPT_option_flag ('n',
    1444              :                                "no-authentication",
    1445              :                                "disable authentication checks",
    1446              :                                &disable_auth),
    1447            5 :     GNUNET_GETOPT_option_uint ('t',
    1448              :                                "timeout",
    1449              :                                "SECONDS",
    1450              :                                "after how long do connections timeout by default (in seconds)",
    1451              :                                &connection_timeout),
    1452            5 :     GNUNET_GETOPT_option_help (
    1453              :       TALER_AUDITOR_project_data (),
    1454              :       "HTTP server providing a RESTful API to access a Taler auditor"),
    1455            5 :     GNUNET_GETOPT_option_version (VERSION "-" VCS_VERSION),
    1456              :     GNUNET_GETOPT_OPTION_END
    1457              :   };
    1458              :   int ret;
    1459              : 
    1460            5 :   ret = GNUNET_PROGRAM_run (
    1461              :     TALER_AUDITOR_project_data (),
    1462              :     argc, argv,
    1463              :     "taler-auditor-httpd",
    1464              :     "Taler auditor HTTP service",
    1465              :     options,
    1466              :     &run, NULL);
    1467            5 :   if (GNUNET_SYSERR == ret)
    1468            0 :     return EXIT_INVALIDARGUMENT;
    1469            5 :   if (GNUNET_NO == ret)
    1470            0 :     return EXIT_SUCCESS;
    1471            5 :   return global_ret;
    1472              : }
    1473              : 
    1474              : 
    1475              : /* end of taler-auditor-httpd.c */
        

Generated by: LCOV version 2.0-1