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

Generated by: LCOV version 1.16