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