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