Line data Source code
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 13 : 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 13 : if (NULL == *con_cls)
188 13 : return;
189 0 : TALER_MHD_parse_post_cleanup_callback (*con_cls);
190 0 : *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 9 : 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 9 : if (NULL == ver)
220 : {
221 5 : 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 9 : if (NULL == ver)
236 : {
237 0 : GNUNET_break (0);
238 0 : return MHD_NO;
239 : }
240 9 : 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 0 : extract_token (const char **auth)
255 : {
256 0 : const char *bearer = "Bearer ";
257 0 : const char *tok = *auth;
258 :
259 0 : if (0 != strncmp (tok,
260 : bearer,
261 : strlen (bearer)))
262 : {
263 0 : *auth = NULL;
264 0 : return;
265 : }
266 0 : tok += strlen (bearer);
267 0 : while (' ' == *tok)
268 0 : tok++;
269 0 : if (0 != strncasecmp (tok,
270 : RFC_8959_PREFIX,
271 : strlen (RFC_8959_PREFIX)))
272 : {
273 0 : *auth = NULL;
274 0 : return;
275 : }
276 0 : *auth = tok;
277 : }
278 :
279 :
280 : static enum GNUNET_GenericReturnValue
281 0 : check_auth (const char *token)
282 : {
283 : struct GNUNET_HashCode val;
284 :
285 0 : if (NULL == token)
286 0 : return GNUNET_SYSERR;
287 0 : token += strlen (RFC_8959_PREFIX);
288 0 : 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 0 : GNUNET_memcmp_priv (&val,
301 : &TAH_auth))
302 : ? GNUNET_OK
303 0 : : 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 19 : 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 19 : {
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 19 : unsigned int args_max = 3;
979 19 : const char *args[args_max + 1];
980 19 : size_t ulen = strlen (url) + 1;
981 19 : char d[ulen];
982 19 : /* const */ struct TAH_RequestHandler *match = NULL;
983 19 : bool url_match = false;
984 :
985 : (void) cls;
986 : (void) version;
987 19 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
988 : "Handling request for URL '%s'\n",
989 : url);
990 19 : if (0 == strcasecmp (method,
991 : MHD_HTTP_METHOD_HEAD))
992 0 : method = MHD_HTTP_METHOD_GET; /* treat HEAD as GET here, MHD will do the rest */
993 19 : if (0 == strcasecmp (method,
994 : MHD_HTTP_METHOD_OPTIONS) )
995 0 : return TALER_MHD_reply_cors_preflight (connection);
996 :
997 19 : memset (&args,
998 : 0,
999 : sizeof (args));
1000 19 : GNUNET_memcpy (d,
1001 : url,
1002 : ulen);
1003 : {
1004 19 : unsigned int i = 0;
1005 :
1006 19 : for (args[i] = strtok (d,
1007 : "/");
1008 37 : NULL != args[i];
1009 18 : args[i] = strtok (NULL,
1010 : "/"))
1011 : {
1012 18 : i++;
1013 18 : if (i >= args_max)
1014 : {
1015 0 : GNUNET_break_op (0);
1016 0 : goto not_found;
1017 : }
1018 : }
1019 : }
1020 :
1021 732 : for (unsigned int i = 0; NULL != handlers[i].url; i++)
1022 : {
1023 732 : /* const */ struct TAH_RequestHandler *rh = &handlers[i];
1024 :
1025 732 : if ( (0 == strcmp (url,
1026 713 : rh->url)) ||
1027 713 : ( (0 == strncmp (url,
1028 : rh->url,
1029 0 : strlen (rh->url))) &&
1030 0 : ('/' == url[strlen (rh->url)]) ) )
1031 : {
1032 19 : url_match = true;
1033 19 : if ( (NULL == rh->method) ||
1034 19 : (0 == strcasecmp (method,
1035 : rh->method)) )
1036 : {
1037 19 : match = rh;
1038 19 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1039 : "Matched %s\n",
1040 : rh->url);
1041 19 : break;
1042 : }
1043 : }
1044 : }
1045 19 : if (NULL == match)
1046 : {
1047 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1048 : "Could not find handler for `%s'\n",
1049 : url);
1050 0 : goto not_found;
1051 : }
1052 19 : if (match->requires_auth &&
1053 0 : (0 == disable_auth) )
1054 : {
1055 : const char *auth;
1056 :
1057 0 : auth = MHD_lookup_connection_value (connection,
1058 : MHD_HEADER_KIND,
1059 : MHD_HTTP_HEADER_AUTHORIZATION);
1060 0 : if (NULL == auth)
1061 : {
1062 0 : GNUNET_break_op (0);
1063 0 : return TALER_MHD_reply_with_error (
1064 : connection,
1065 : MHD_HTTP_UNAUTHORIZED,
1066 : TALER_EC_AUDITOR_GENERIC_UNAUTHORIZED,
1067 : "Check 'Authorization' header");
1068 : }
1069 0 : extract_token (&auth);
1070 0 : if (NULL == auth)
1071 0 : 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 0 : if (GNUNET_OK !=
1079 0 : check_auth (auth))
1080 : {
1081 0 : GNUNET_break_op (0);
1082 0 : 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 19 : return match->handler (match,
1091 : connection,
1092 : con_cls,
1093 : upload_data,
1094 : upload_data_size,
1095 : args);
1096 0 : not_found:
1097 0 : if (url_match)
1098 : {
1099 : /* FIXME: return list of allowed methods... - #9424 */
1100 0 : GNUNET_break (0);
1101 0 : 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 0 : 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 5 : auditor_serve_process_config (void)
1127 : {
1128 5 : if (NULL ==
1129 5 : (TAH_plugin = TALER_AUDITORDB_plugin_load (cfg,
1130 : false)))
1131 : {
1132 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1133 : "Failed to initialize DB subsystem to interact with auditor database\n");
1134 0 : return GNUNET_SYSERR;
1135 : }
1136 5 : if (NULL ==
1137 5 : (TAH_eplugin = TALER_EXCHANGEDB_plugin_load (cfg,
1138 : false)))
1139 : {
1140 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1141 : "Failed to initialize DB subsystem to query exchange database\n");
1142 0 : return GNUNET_SYSERR;
1143 : }
1144 5 : if (GNUNET_SYSERR ==
1145 5 : TAH_eplugin->preflight (TAH_eplugin->cls))
1146 : {
1147 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1148 : "Failed to initialize DB subsystem to query exchange database\n");
1149 0 : return GNUNET_SYSERR;
1150 : }
1151 5 : if (GNUNET_OK !=
1152 5 : TALER_config_get_currency (cfg,
1153 : "exchange",
1154 : &TAH_currency))
1155 : {
1156 0 : return GNUNET_SYSERR;
1157 : }
1158 :
1159 : {
1160 : char *master_public_key_str;
1161 :
1162 5 : if (GNUNET_OK !=
1163 5 : GNUNET_CONFIGURATION_get_value_string (cfg,
1164 : "exchange",
1165 : "MASTER_PUBLIC_KEY",
1166 : &master_public_key_str))
1167 : {
1168 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1169 : "exchange",
1170 : "MASTER_PUBLIC_KEY");
1171 0 : return GNUNET_SYSERR;
1172 : }
1173 5 : if (GNUNET_OK !=
1174 5 : 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 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1180 : "exchange",
1181 : "MASTER_PUBLIC_KEY",
1182 : "invalid base32 encoding for a master public key");
1183 0 : GNUNET_free (master_public_key_str);
1184 0 : return GNUNET_SYSERR;
1185 : }
1186 5 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1187 : "Launching auditor for exchange `%s'...\n",
1188 : master_public_key_str);
1189 5 : GNUNET_free (master_public_key_str);
1190 : }
1191 :
1192 : {
1193 : char *pub;
1194 :
1195 5 : if (GNUNET_OK ==
1196 5 : GNUNET_CONFIGURATION_get_value_string (cfg,
1197 : "AUDITOR",
1198 : "PUBLIC_KEY",
1199 : &pub))
1200 : {
1201 5 : if (GNUNET_OK !=
1202 5 : GNUNET_CRYPTO_eddsa_public_key_from_string (pub,
1203 : strlen (pub),
1204 : &auditor_pub.eddsa_pub))
1205 : {
1206 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1207 : "Invalid public key given in auditor configuration.");
1208 0 : GNUNET_free (pub);
1209 5 : return GNUNET_SYSERR;
1210 : }
1211 5 : GNUNET_free (pub);
1212 5 : 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 0 : if (GNUNET_OK !=
1222 0 : GNUNET_CONFIGURATION_get_value_filename (cfg,
1223 : "auditor",
1224 : "AUDITOR_PRIV_FILE",
1225 : &auditor_key_file))
1226 : {
1227 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1228 : "AUDITOR",
1229 : "PUBLIC_KEY");
1230 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1231 : "AUDITOR",
1232 : "AUDITOR_PRIV_FILE");
1233 0 : return GNUNET_SYSERR;
1234 : }
1235 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1236 : "Loading auditor private key from %s\n",
1237 : auditor_key_file);
1238 0 : if (GNUNET_OK !=
1239 0 : GNUNET_CRYPTO_eddsa_key_from_file (auditor_key_file,
1240 : GNUNET_NO,
1241 : &eddsa_priv))
1242 : {
1243 : /* Both failed, complain! */
1244 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1245 : "AUDITOR",
1246 : "PUBLIC_KEY");
1247 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1248 : "Failed to initialize auditor key from file `%s'\n",
1249 : auditor_key_file);
1250 0 : GNUNET_free (auditor_key_file);
1251 0 : return 1;
1252 : }
1253 0 : GNUNET_free (auditor_key_file);
1254 0 : GNUNET_CRYPTO_eddsa_key_get_public (&eddsa_priv,
1255 : &auditor_pub.eddsa_pub);
1256 : }
1257 0 : return GNUNET_OK;
1258 : }
1259 :
1260 :
1261 : /**
1262 : * Function run on shutdown.
1263 : *
1264 : * @param cls NULL
1265 : */
1266 : static void
1267 5 : do_shutdown (void *cls)
1268 : {
1269 : (void) cls;
1270 5 : TALER_MHD_daemons_halt ();
1271 5 : TEAH_DEPOSIT_CONFIRMATION_done ();
1272 5 : TALER_MHD_daemons_destroy ();
1273 5 : if (NULL != TAH_plugin)
1274 : {
1275 5 : TALER_AUDITORDB_plugin_unload (TAH_plugin);
1276 5 : TAH_plugin = NULL;
1277 : }
1278 5 : if (NULL != TAH_eplugin)
1279 : {
1280 5 : TALER_EXCHANGEDB_plugin_unload (TAH_eplugin);
1281 5 : TAH_eplugin = NULL;
1282 : }
1283 5 : }
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 10 : start_daemon (void *cls,
1295 : int lsock)
1296 : {
1297 : struct MHD_Daemon *mhd;
1298 :
1299 : (void) cls;
1300 10 : GNUNET_assert (-1 != lsock);
1301 10 : 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 10 : if (NULL == mhd)
1320 : {
1321 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1322 : "Failed to launch HTTP daemon.\n");
1323 0 : GNUNET_SCHEDULER_shutdown ();
1324 0 : return;
1325 : }
1326 10 : have_daemons = true;
1327 10 : 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 5 : 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 5 : if (0 == disable_auth)
1353 : {
1354 : const char *tok;
1355 :
1356 5 : tok = getenv ("TALER_AUDITOR_ACCESS_TOKEN");
1357 5 : if (NULL == tok)
1358 : {
1359 5 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1360 : "TALER_AUDITOR_ACCESS_TOKEN environment variable not set. Disabling authentication\n");
1361 5 : disable_auth = 1;
1362 : }
1363 : else
1364 : {
1365 0 : 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 5 : go = TALER_MHD_GO_NONE;
1378 5 : if (auditor_connection_close)
1379 0 : go |= TALER_MHD_GO_FORCE_CONNECTION_CLOSE;
1380 5 : TALER_MHD_setup (go);
1381 5 : cfg = config;
1382 :
1383 5 : GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1384 : NULL);
1385 5 : if (GNUNET_OK !=
1386 5 : auditor_serve_process_config ())
1387 : {
1388 0 : global_ret = EXIT_NOTCONFIGURED;
1389 0 : GNUNET_SCHEDULER_shutdown ();
1390 0 : return;
1391 : }
1392 5 : if (GNUNET_OK !=
1393 5 : TAH_spa_init ())
1394 : {
1395 0 : global_ret = EXIT_NOTCONFIGURED;
1396 0 : GNUNET_SCHEDULER_shutdown ();
1397 0 : return;
1398 : }
1399 5 : TEAH_DEPOSIT_CONFIRMATION_init ();
1400 5 : ret = TALER_MHD_listen_bind (cfg,
1401 : "auditor",
1402 : &start_daemon,
1403 : NULL);
1404 5 : switch (ret)
1405 : {
1406 0 : case GNUNET_SYSERR:
1407 0 : global_ret = EXIT_NOTCONFIGURED;
1408 0 : GNUNET_SCHEDULER_shutdown ();
1409 0 : return;
1410 0 : case GNUNET_NO:
1411 0 : if (! have_daemons)
1412 : {
1413 0 : global_ret = EXIT_NOTCONFIGURED;
1414 0 : GNUNET_SCHEDULER_shutdown ();
1415 0 : return;
1416 : }
1417 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1418 : "Could not open all configured listen sockets\n");
1419 0 : break;
1420 5 : case GNUNET_OK:
1421 5 : break;
1422 : }
1423 5 : 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 5 : main (int argc,
1436 : char *const *argv)
1437 : {
1438 5 : const struct GNUNET_GETOPT_CommandLineOption options[] = {
1439 5 : GNUNET_GETOPT_option_flag ('C',
1440 : "connection-close",
1441 : "force HTTP connections to be closed after each request",
1442 : &auditor_connection_close),
1443 5 : GNUNET_GETOPT_option_flag ('n',
1444 : "no-authentication",
1445 : "disable authentication checks",
1446 : &disable_auth),
1447 5 : GNUNET_GETOPT_option_uint ('t',
1448 : "timeout",
1449 : "SECONDS",
1450 : "after how long do connections timeout by default (in seconds)",
1451 : &connection_timeout),
1452 5 : GNUNET_GETOPT_option_help (
1453 : TALER_AUDITOR_project_data (),
1454 : "HTTP server providing a RESTful API to access a Taler auditor"),
1455 5 : GNUNET_GETOPT_option_version (VERSION "-" VCS_VERSION),
1456 : GNUNET_GETOPT_OPTION_END
1457 : };
1458 : int ret;
1459 :
1460 5 : 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 5 : if (GNUNET_SYSERR == ret)
1468 0 : return EXIT_INVALIDARGUMENT;
1469 5 : if (GNUNET_NO == ret)
1470 0 : return EXIT_SUCCESS;
1471 5 : return global_ret;
1472 : }
1473 :
1474 :
1475 : /* end of taler-auditor-httpd.c */
|