taler-auditor-httpd.c (53418B)
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 /* more than @e args_max segments in the URL */ 1080 GNUNET_break_op (0); 1081 goto not_found; 1082 } 1083 } 1084 } 1085 1086 for (unsigned int i = 0; NULL != handlers[i].url; i++) 1087 { 1088 /* const */ struct TAH_RequestHandler *rh = &handlers[i]; 1089 1090 if ( (0 == strcmp (url, 1091 rh->url)) || 1092 ( (0 == strncmp (url, 1093 rh->url, 1094 strlen (rh->url))) && 1095 ('/' == url[strlen (rh->url)]) ) ) 1096 { 1097 url_match = true; 1098 if ( (NULL == rh->method) || 1099 (0 == strcasecmp (method, 1100 rh->method)) ) 1101 { 1102 match = rh; 1103 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1104 "Matched %s\n", 1105 rh->url); 1106 break; 1107 } 1108 } 1109 } 1110 if (NULL == match) 1111 { 1112 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1113 "Could not find handler for `%s'\n", 1114 url); 1115 goto not_found; 1116 } 1117 if (match->requires_auth && 1118 (0 == disable_auth) ) 1119 { 1120 const char *auth; 1121 1122 auth = MHD_lookup_connection_value (connection, 1123 MHD_HEADER_KIND, 1124 MHD_HTTP_HEADER_AUTHORIZATION); 1125 if (NULL == auth) 1126 { 1127 GNUNET_break_op (0); 1128 return TALER_MHD_reply_with_error ( 1129 connection, 1130 MHD_HTTP_UNAUTHORIZED, 1131 TALER_EC_AUDITOR_GENERIC_UNAUTHORIZED, 1132 "Check 'Authorization' header"); 1133 } 1134 extract_token (&auth); 1135 if (NULL == auth) 1136 return TALER_MHD_reply_with_error ( 1137 connection, 1138 MHD_HTTP_BAD_REQUEST, 1139 TALER_EC_GENERIC_PARAMETER_MALFORMED, 1140 "'" RFC_8959_PREFIX 1141 "' prefix or 'Bearer' missing in 'Authorization' header"); 1142 1143 if (GNUNET_OK != 1144 check_auth (auth)) 1145 { 1146 GNUNET_break_op (0); 1147 return TALER_MHD_reply_with_error ( 1148 connection, 1149 MHD_HTTP_UNAUTHORIZED, 1150 TALER_EC_AUDITOR_GENERIC_UNAUTHORIZED, 1151 "Check 'Authorization' header"); 1152 } 1153 } 1154 1155 return match->handler (match, 1156 connection, 1157 con_cls, 1158 upload_data, 1159 upload_data_size, 1160 args); 1161 not_found: 1162 if (url_match) 1163 { 1164 /* The URL exists, but not for the requested HTTP method: respond with 1165 405 Method Not Allowed and an 'Allow' header listing the methods that 1166 are supported for this URL (#9424). */ 1167 char allow[128] = "OPTIONS"; 1168 size_t aoff = strlen ("OPTIONS"); 1169 struct MHD_Response *resp; 1170 enum MHD_Result ret; 1171 1172 GNUNET_break_op (0); 1173 /* OPTIONS is always supported (handled above); additionally list every 1174 method registered for this URL. */ 1175 for (unsigned int i = 0; NULL != handlers[i].url; i++) 1176 { 1177 const struct TAH_RequestHandler *rh = &handlers[i]; 1178 1179 if (NULL == rh->method) 1180 continue; 1181 if ( (0 != strcmp (url, 1182 rh->url)) && 1183 ! ( (0 == strncmp (url, 1184 rh->url, 1185 strlen (rh->url))) && 1186 ('/' == url[strlen (rh->url)]) ) ) 1187 continue; 1188 GNUNET_assert (aoff + strlen (rh->method) + 3 < sizeof (allow)); 1189 memcpy (&allow[aoff], 1190 ", ", 1191 2); 1192 aoff += 2; 1193 memcpy (&allow[aoff], 1194 rh->method, 1195 strlen (rh->method)); 1196 aoff += strlen (rh->method); 1197 allow[aoff] = '\0'; 1198 } 1199 resp = MHD_create_response_from_buffer (0, 1200 NULL, 1201 MHD_RESPMEM_PERSISTENT); 1202 TALER_MHD_add_global_headers (resp, 1203 false); 1204 GNUNET_break (MHD_YES == 1205 MHD_add_response_header (resp, 1206 MHD_HTTP_HEADER_ALLOW, 1207 allow)); 1208 ret = MHD_queue_response (connection, 1209 MHD_HTTP_METHOD_NOT_ALLOWED, 1210 resp); 1211 MHD_destroy_response (resp); 1212 return ret; 1213 } 1214 1215 #define NOT_FOUND \ 1216 "<html><title>404: not found</title><body>auditor endpoints have been moved to /monitoring/...</body></html>" 1217 return TALER_MHD_reply_static (connection, 1218 MHD_HTTP_NOT_FOUND, 1219 "text/html", 1220 NOT_FOUND, 1221 strlen (NOT_FOUND)); 1222 #undef NOT_FOUND 1223 } 1224 1225 1226 /** 1227 * Load configuration parameters for the auditor 1228 * server into the corresponding global variables. 1229 * 1230 * @return #GNUNET_OK on success 1231 */ 1232 static enum GNUNET_GenericReturnValue 1233 auditor_serve_process_config (void) 1234 { 1235 if (NULL == 1236 (TAH_apg = TALER_AUDITORDB_connect (cfg))) 1237 { 1238 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1239 "Failed to initialize DB subsystem to interact with auditor database\n"); 1240 return GNUNET_SYSERR; 1241 } 1242 if (NULL == 1243 (TAH_epg = TALER_EXCHANGEDB_connect (cfg))) 1244 { 1245 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1246 "Failed to initialize DB subsystem to query exchange database\n"); 1247 return GNUNET_SYSERR; 1248 } 1249 if (GNUNET_SYSERR == 1250 TALER_EXCHANGEDB_preflight (TAH_epg)) 1251 { 1252 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1253 "Failed to initialize DB subsystem to query exchange database\n"); 1254 return GNUNET_SYSERR; 1255 } 1256 if (GNUNET_OK != 1257 TALER_config_get_currency (cfg, 1258 "exchange", 1259 &TAH_currency)) 1260 { 1261 return GNUNET_SYSERR; 1262 } 1263 1264 { 1265 char *master_public_key_str; 1266 1267 if (GNUNET_OK != 1268 GNUNET_CONFIGURATION_get_value_string (cfg, 1269 "exchange", 1270 "MASTER_PUBLIC_KEY", 1271 &master_public_key_str)) 1272 { 1273 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1274 "exchange", 1275 "MASTER_PUBLIC_KEY"); 1276 return GNUNET_SYSERR; 1277 } 1278 if (GNUNET_OK != 1279 GNUNET_CRYPTO_eddsa_public_key_from_string ( 1280 master_public_key_str, 1281 strlen (master_public_key_str), 1282 &TAH_master_public_key.eddsa_pub)) 1283 { 1284 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 1285 "exchange", 1286 "MASTER_PUBLIC_KEY", 1287 "invalid base32 encoding for a master public key"); 1288 GNUNET_free (master_public_key_str); 1289 return GNUNET_SYSERR; 1290 } 1291 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1292 "Launching auditor for exchange `%s'...\n", 1293 master_public_key_str); 1294 GNUNET_free (master_public_key_str); 1295 } 1296 1297 { 1298 char *pub; 1299 1300 if (GNUNET_OK == 1301 GNUNET_CONFIGURATION_get_value_string (cfg, 1302 "AUDITOR", 1303 "PUBLIC_KEY", 1304 &pub)) 1305 { 1306 if (GNUNET_OK != 1307 GNUNET_CRYPTO_eddsa_public_key_from_string (pub, 1308 strlen (pub), 1309 &auditor_pub.eddsa_pub)) 1310 { 1311 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1312 "Invalid public key given in auditor configuration."); 1313 GNUNET_free (pub); 1314 return GNUNET_SYSERR; 1315 } 1316 GNUNET_free (pub); 1317 return GNUNET_OK; 1318 } 1319 } 1320 1321 { 1322 /* Fall back to trying to read private key */ 1323 char *auditor_key_file; 1324 struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv; 1325 1326 if (GNUNET_OK != 1327 GNUNET_CONFIGURATION_get_value_filename (cfg, 1328 "auditor", 1329 "AUDITOR_PRIV_FILE", 1330 &auditor_key_file)) 1331 { 1332 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1333 "AUDITOR", 1334 "PUBLIC_KEY"); 1335 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1336 "AUDITOR", 1337 "AUDITOR_PRIV_FILE"); 1338 return GNUNET_SYSERR; 1339 } 1340 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1341 "Loading auditor private key from %s\n", 1342 auditor_key_file); 1343 if (GNUNET_OK != 1344 GNUNET_CRYPTO_eddsa_key_from_file (auditor_key_file, 1345 GNUNET_NO, 1346 &eddsa_priv)) 1347 { 1348 /* Both failed, complain! */ 1349 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1350 "AUDITOR", 1351 "PUBLIC_KEY"); 1352 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1353 "Failed to initialize auditor key from file `%s'\n", 1354 auditor_key_file); 1355 GNUNET_free (auditor_key_file); 1356 return 1; 1357 } 1358 GNUNET_free (auditor_key_file); 1359 GNUNET_CRYPTO_eddsa_key_get_public (&eddsa_priv, 1360 &auditor_pub.eddsa_pub); 1361 } 1362 if (GNUNET_OK == 1363 GNUNET_CONFIGURATION_get_value_filename (cfg, 1364 "auditor", 1365 "SPA_DIR", 1366 &TAH_spa_dir)) 1367 { 1368 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1369 "Loading auditor SPA from %s\n", 1370 TAH_spa_dir); 1371 } 1372 else 1373 { 1374 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1375 "Loading exchange AML SPA from default location\n"); 1376 } 1377 return GNUNET_OK; 1378 } 1379 1380 1381 /** 1382 * Function run on shutdown. 1383 * 1384 * @param cls NULL 1385 */ 1386 static void 1387 do_shutdown (void *cls) 1388 { 1389 (void) cls; 1390 TALER_MHD_daemons_halt (); 1391 TEAH_put_deposit_confirmation_done (); 1392 TALER_MHD_daemons_destroy (); 1393 if (NULL != TAH_apg) 1394 { 1395 TALER_AUDITORDB_disconnect (TAH_apg); 1396 TAH_apg = NULL; 1397 } 1398 if (NULL != TAH_epg) 1399 { 1400 TALER_EXCHANGEDB_disconnect (TAH_epg); 1401 TAH_epg = NULL; 1402 } 1403 } 1404 1405 1406 /** 1407 * Callback invoked on every listen socket to start the 1408 * respective MHD HTTP daemon. 1409 * 1410 * @param cls unused 1411 * @param lsock the listen socket 1412 */ 1413 static void 1414 start_daemon (void *cls, 1415 int lsock) 1416 { 1417 struct MHD_Daemon *mhd; 1418 1419 (void) cls; 1420 GNUNET_assert (-1 != lsock); 1421 mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME 1422 | MHD_USE_PIPE_FOR_SHUTDOWN 1423 | MHD_USE_DEBUG | MHD_USE_DUAL_STACK 1424 | MHD_USE_TCP_FASTOPEN, 1425 0, 1426 NULL, NULL, 1427 &handle_mhd_request, NULL, 1428 MHD_OPTION_LISTEN_SOCKET, 1429 lsock, 1430 MHD_OPTION_EXTERNAL_LOGGER, 1431 &TALER_MHD_handle_logs, 1432 NULL, 1433 MHD_OPTION_NOTIFY_COMPLETED, 1434 &handle_mhd_completion_callback, 1435 NULL, 1436 MHD_OPTION_CONNECTION_TIMEOUT, 1437 connection_timeout, 1438 MHD_OPTION_END); 1439 if (NULL == mhd) 1440 { 1441 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1442 "Failed to launch HTTP daemon.\n"); 1443 GNUNET_SCHEDULER_shutdown (); 1444 return; 1445 } 1446 have_daemons = true; 1447 TALER_MHD_daemon_start (mhd); 1448 } 1449 1450 1451 /** 1452 * Main function that will be run by the scheduler. 1453 * 1454 * @param cls closure 1455 * @param args remaining command-line arguments 1456 * @param cfgfile name of the configuration file used (for saving, can be 1457 * NULL!) 1458 * @param config configuration 1459 */ 1460 static void 1461 run (void *cls, 1462 char *const *args, 1463 const char *cfgfile, 1464 const struct GNUNET_CONFIGURATION_Handle *config) 1465 { 1466 enum TALER_MHD_GlobalOptions go; 1467 enum GNUNET_GenericReturnValue ret; 1468 1469 (void) cls; 1470 (void) args; 1471 (void) cfgfile; 1472 if (0 == disable_auth) 1473 { 1474 const char *tok; 1475 1476 tok = getenv ("TALER_AUDITOR_ACCESS_TOKEN"); 1477 if (NULL == tok) 1478 { 1479 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1480 "TALER_AUDITOR_ACCESS_TOKEN environment variable not set. Disabling authentication\n"); 1481 disable_auth = 1; 1482 } 1483 else 1484 { 1485 GNUNET_assert (GNUNET_YES == 1486 GNUNET_CRYPTO_hkdf_gnunet ( 1487 &TAH_auth, 1488 sizeof (TAH_auth), 1489 KDF_SALT, 1490 strlen (KDF_SALT), 1491 tok, 1492 strlen (tok))); 1493 } 1494 } 1495 1496 go = TALER_MHD_GO_NONE; 1497 if (auditor_connection_close) 1498 go |= TALER_MHD_GO_FORCE_CONNECTION_CLOSE; 1499 TALER_MHD_setup (go); 1500 cfg = config; 1501 1502 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, 1503 NULL); 1504 if (GNUNET_OK != 1505 auditor_serve_process_config ()) 1506 { 1507 global_ret = EXIT_NOTCONFIGURED; 1508 GNUNET_SCHEDULER_shutdown (); 1509 return; 1510 } 1511 if (GNUNET_OK != 1512 TAH_spa_init ()) 1513 { 1514 global_ret = EXIT_NOTCONFIGURED; 1515 GNUNET_SCHEDULER_shutdown (); 1516 return; 1517 } 1518 TEAH_put_deposit_confirmation_init (); 1519 ret = TALER_MHD_listen_bind (cfg, 1520 "auditor", 1521 &start_daemon, 1522 NULL); 1523 switch (ret) 1524 { 1525 case GNUNET_SYSERR: 1526 global_ret = EXIT_NOTCONFIGURED; 1527 GNUNET_SCHEDULER_shutdown (); 1528 return; 1529 case GNUNET_NO: 1530 if (! have_daemons) 1531 { 1532 global_ret = EXIT_NOTCONFIGURED; 1533 GNUNET_SCHEDULER_shutdown (); 1534 return; 1535 } 1536 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1537 "Could not open all configured listen sockets\n"); 1538 break; 1539 case GNUNET_OK: 1540 break; 1541 } 1542 global_ret = EXIT_SUCCESS; 1543 } 1544 1545 1546 /** 1547 * The main function of the taler-auditor-httpd server ("the auditor"). 1548 * 1549 * @param argc number of arguments from the command line 1550 * @param argv command line arguments 1551 * @return 0 ok, 1 on error 1552 */ 1553 int 1554 main (int argc, 1555 char *const *argv) 1556 { 1557 const struct GNUNET_GETOPT_CommandLineOption options[] = { 1558 GNUNET_GETOPT_option_flag ('C', 1559 "connection-close", 1560 "force HTTP connections to be closed after each request", 1561 &auditor_connection_close), 1562 GNUNET_GETOPT_option_flag ('n', 1563 "no-authentication", 1564 "disable authentication checks", 1565 &disable_auth), 1566 GNUNET_GETOPT_option_uint ('t', 1567 "timeout", 1568 "SECONDS", 1569 "after how long do connections timeout by default (in seconds)", 1570 &connection_timeout), 1571 GNUNET_GETOPT_option_help ( 1572 TALER_AUDITOR_project_data (), 1573 "HTTP server providing a RESTful API to access a Taler auditor"), 1574 GNUNET_GETOPT_option_version (VERSION), 1575 GNUNET_GETOPT_OPTION_END 1576 }; 1577 int ret; 1578 1579 ret = GNUNET_PROGRAM_run ( 1580 TALER_AUDITOR_project_data (), 1581 argc, argv, 1582 "taler-auditor-httpd", 1583 "Taler auditor HTTP service", 1584 options, 1585 &run, NULL); 1586 if (GNUNET_SYSERR == ret) 1587 return EXIT_INVALIDARGUMENT; 1588 if (GNUNET_NO == ret) 1589 return EXIT_SUCCESS; 1590 return global_ret; 1591 } 1592 1593 1594 /* end of taler-auditor-httpd.c */