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