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