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