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