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