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