Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2020 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU 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 General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file util/secmod_common.c
18 : * @brief Common functions for the exchange security modules
19 : * @author Florian Dold <dold@taler.net>
20 : */
21 : #include "taler/platform.h"
22 : #include "taler/taler_util.h"
23 : #include "taler/taler_signatures.h"
24 : #include "secmod_common.h"
25 : #include <poll.h>
26 : #ifdef __linux__
27 : #include <sys/eventfd.h>
28 : #endif
29 :
30 :
31 : /**
32 : * Head of DLL of clients connected to us.
33 : */
34 : struct TES_Client *TES_clients_head;
35 :
36 : /**
37 : * Tail of DLL of clients connected to us.
38 : */
39 : struct TES_Client *TES_clients_tail;
40 :
41 : /**
42 : * Lock for the client queue.
43 : */
44 : pthread_mutex_t TES_clients_lock;
45 :
46 : /**
47 : * Private key of this security module. Used to sign denomination key
48 : * announcements.
49 : */
50 : struct TALER_SecurityModulePrivateKeyP TES_smpriv;
51 :
52 : /**
53 : * Public key of this security module.
54 : */
55 : struct TALER_SecurityModulePublicKeyP TES_smpub;
56 :
57 : /**
58 : * Our listen socket.
59 : */
60 : static struct GNUNET_NETWORK_Handle *unix_sock;
61 :
62 : /**
63 : * Path where we are listening.
64 : */
65 : static char *unixpath;
66 :
67 : /**
68 : * Task run to accept new inbound connections.
69 : */
70 : static struct GNUNET_SCHEDULER_Task *listen_task;
71 :
72 : /**
73 : * Set once we are in shutdown and workers should terminate.
74 : */
75 : static volatile bool in_shutdown;
76 :
77 :
78 : enum GNUNET_GenericReturnValue
79 5782 : TES_transmit_raw (int sock,
80 : size_t end,
81 : const void *pos)
82 : {
83 5782 : size_t off = 0;
84 :
85 5782 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
86 : "Sending message of length %u\n",
87 : (unsigned int) end);
88 11554 : while (off < end)
89 : {
90 5766 : ssize_t ret = send (sock,
91 : pos,
92 : end - off,
93 : 0 /* no flags => blocking! */);
94 :
95 5772 : if ( (-1 == ret) &&
96 0 : ( (EAGAIN == errno) ||
97 0 : (EINTR == errno) ) )
98 : {
99 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG,
100 : "send");
101 0 : continue;
102 : }
103 5772 : if (-1 == ret)
104 : {
105 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
106 : "send");
107 0 : return GNUNET_SYSERR;
108 : }
109 5772 : if (0 == ret)
110 : {
111 0 : GNUNET_break (0);
112 0 : return GNUNET_SYSERR;
113 : }
114 5772 : off += ret;
115 5772 : pos += ret;
116 : }
117 5788 : return GNUNET_OK;
118 : }
119 :
120 :
121 : enum GNUNET_GenericReturnValue
122 5718 : TES_transmit (int sock,
123 : const struct GNUNET_MessageHeader *hdr)
124 : {
125 5718 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
126 : "Sending message of type %u and length %u\n",
127 : (unsigned int) ntohs (hdr->type),
128 : (unsigned int) ntohs (hdr->size));
129 11443 : return TES_transmit_raw (sock,
130 5718 : ntohs (hdr->size),
131 : hdr);
132 : }
133 :
134 :
135 : struct GNUNET_NETWORK_Handle *
136 54 : TES_open_socket (const char *my_unixpath)
137 : {
138 : int sock;
139 : mode_t old_umask;
140 54 : struct GNUNET_NETWORK_Handle *ret = NULL;
141 :
142 : /* Change permissions so that group read/writes are allowed.
143 : * We need this for multi-user exchange deployment with privilege
144 : * separation, where taler-exchange-httpd is part of a group
145 : * that allows it to talk to secmod.
146 : */
147 54 : old_umask = umask (S_IROTH | S_IWOTH | S_IXOTH);
148 :
149 54 : sock = socket (PF_UNIX,
150 : SOCK_STREAM,
151 : 0);
152 54 : if (-1 == sock)
153 : {
154 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
155 : "socket");
156 0 : goto cleanup;
157 : }
158 : {
159 : struct sockaddr_un un;
160 :
161 54 : if (GNUNET_OK !=
162 54 : GNUNET_DISK_directory_create_for_file (my_unixpath))
163 : {
164 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
165 : "mkdir(dirname)",
166 : my_unixpath);
167 : }
168 54 : if (0 != unlink (my_unixpath))
169 : {
170 54 : if (ENOENT != errno)
171 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
172 : "unlink",
173 : my_unixpath);
174 : }
175 54 : memset (&un,
176 : 0,
177 : sizeof (un));
178 54 : un.sun_family = AF_UNIX;
179 54 : strncpy (un.sun_path,
180 : my_unixpath,
181 : sizeof (un.sun_path) - 1);
182 54 : if (0 != bind (sock,
183 : (const struct sockaddr *) &un,
184 : sizeof (un)))
185 : {
186 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
187 : "bind",
188 : my_unixpath);
189 0 : GNUNET_break (0 == close (sock));
190 0 : goto cleanup;
191 : }
192 54 : ret = GNUNET_NETWORK_socket_box_native (sock);
193 54 : if (GNUNET_OK !=
194 54 : GNUNET_NETWORK_socket_listen (ret,
195 : 512))
196 : {
197 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
198 : "listen",
199 : my_unixpath);
200 0 : GNUNET_break (GNUNET_OK ==
201 : GNUNET_NETWORK_socket_close (ret));
202 0 : ret = NULL;
203 : }
204 : }
205 54 : cleanup:
206 54 : (void) umask (old_umask);
207 54 : return ret;
208 : }
209 :
210 :
211 : void
212 103 : TES_wake_clients (void)
213 : {
214 103 : uint64_t num = 1;
215 :
216 103 : GNUNET_assert (0 == pthread_mutex_lock (&TES_clients_lock));
217 103 : for (struct TES_Client *client = TES_clients_head;
218 192 : NULL != client;
219 89 : client = client->next)
220 : {
221 : #ifdef __linux__
222 89 : if (-1 == client->esock)
223 30 : continue;
224 59 : GNUNET_assert (sizeof (num) ==
225 : write (client->esock,
226 : &num,
227 : sizeof (num)));
228 : #else
229 : if (-1 == client->esock_in)
230 : continue;
231 : GNUNET_assert (sizeof (num) ==
232 : write (client->esock_in,
233 : &num,
234 : sizeof (num)));
235 : #endif
236 : }
237 103 : GNUNET_assert (0 == pthread_mutex_unlock (&TES_clients_lock));
238 103 : }
239 :
240 :
241 : enum GNUNET_GenericReturnValue
242 3875 : TES_read_work (void *cls,
243 : TES_MessageDispatch dispatch)
244 : {
245 3875 : struct TES_Client *client = cls;
246 3875 : char *buf = client->iobuf;
247 3875 : size_t off = 0;
248 3875 : uint16_t msize = 0;
249 3875 : const struct GNUNET_MessageHeader *hdr = NULL;
250 : enum GNUNET_GenericReturnValue ret;
251 :
252 : do
253 : {
254 : ssize_t recv_size;
255 :
256 3875 : recv_size = recv (client->csock,
257 3875 : &buf[off],
258 : sizeof (client->iobuf) - off,
259 : 0);
260 3877 : if (-1 == recv_size)
261 : {
262 3 : if ( (0 == off) &&
263 1 : (EAGAIN == errno) )
264 0 : return GNUNET_NO;
265 3 : if ( (EINTR == errno) ||
266 1 : (EAGAIN == errno) )
267 : {
268 2 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG,
269 : "recv");
270 0 : continue;
271 : }
272 1 : if (ECONNRESET != errno)
273 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
274 : "recv");
275 1 : return GNUNET_SYSERR;
276 : }
277 3874 : if (0 == recv_size)
278 : {
279 : /* regular disconnect? */
280 32 : GNUNET_break_op (0 == off);
281 32 : return GNUNET_SYSERR;
282 : }
283 3842 : off += recv_size;
284 3842 : more:
285 3842 : if (off < sizeof (struct GNUNET_MessageHeader))
286 0 : continue;
287 3842 : hdr = (const struct GNUNET_MessageHeader *) buf;
288 3842 : msize = ntohs (hdr->size);
289 : #if 0
290 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
291 : "Received message of type %u with %u bytes\n",
292 : (unsigned int) ntohs (hdr->type),
293 : (unsigned int) msize);
294 : #endif
295 3842 : if (msize < sizeof (struct GNUNET_MessageHeader))
296 : {
297 0 : GNUNET_break_op (0);
298 0 : return GNUNET_SYSERR;
299 : }
300 3842 : } while (off < msize);
301 :
302 3842 : ret = dispatch (client,
303 : hdr);
304 3837 : if ( (GNUNET_OK != ret) ||
305 3837 : (off == msize) )
306 3837 : return ret;
307 0 : memmove (buf,
308 0 : &buf[msize],
309 : off - msize);
310 0 : off -= msize;
311 0 : goto more;
312 : }
313 :
314 :
315 : bool
316 3929 : TES_await_ready (struct TES_Client *client)
317 : {
318 : /* wait for reply with 1s timeout */
319 3929 : struct pollfd pfds[] = {
320 : {
321 3929 : .fd = client->csock,
322 : .events = POLLIN
323 : },
324 : {
325 : #ifdef __linux__
326 3929 : .fd = client->esock,
327 : #else
328 : .fd = client->esock_out,
329 : #endif
330 : .events = POLLIN
331 : },
332 : };
333 : int ret;
334 :
335 3929 : ret = poll (pfds,
336 : 2,
337 : -1);
338 3936 : if ( (-1 == ret) &&
339 0 : (EINTR != errno) )
340 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
341 : "poll");
342 11749 : for (int i = 0; i<2; i++)
343 : {
344 7872 : if (
345 : #ifdef __linux__
346 7872 : (pfds[i].fd == client->esock) &&
347 : #else
348 : (pfds[i].fd == client->esock_out) &&
349 : #endif
350 3936 : (POLLIN == pfds[i].revents) )
351 : {
352 : uint64_t num;
353 :
354 : #ifdef __linux__
355 59 : GNUNET_assert (sizeof (num) ==
356 : read (client->esock,
357 : &num,
358 : sizeof (num)));
359 : #else
360 : GNUNET_assert (sizeof (num) ==
361 : read (client->esock_out,
362 : &num,
363 : sizeof (num)));
364 : #endif
365 59 : return true;
366 : }
367 : }
368 3877 : return false;
369 : }
370 :
371 :
372 : /**
373 : * Main function of a worker thread that signs.
374 : *
375 : * @param cls the client we are working on
376 : * @return NULL
377 : */
378 : static void *
379 78 : sign_worker (void *cls)
380 : {
381 78 : struct TES_Client *client = cls;
382 :
383 78 : if (GNUNET_OK !=
384 78 : client->cb.init (client))
385 : {
386 0 : GNUNET_break (0);
387 0 : return NULL;
388 : }
389 3973 : while (! in_shutdown)
390 : {
391 3929 : if (TES_await_ready (client))
392 : {
393 59 : if (GNUNET_OK !=
394 59 : client->cb.updater (client))
395 0 : break;
396 : }
397 : else
398 : {
399 3869 : if (GNUNET_SYSERR ==
400 3877 : TES_read_work (client,
401 : client->cb.dispatch))
402 33 : break;
403 : }
404 : }
405 77 : GNUNET_break (0 == close (client->csock));
406 78 : client->csock = -1;
407 : #ifdef __linux__
408 78 : GNUNET_break (0 == close (client->esock));
409 78 : client->esock = -1;
410 : #else
411 : GNUNET_break (0 == close (client->esock_in));
412 : client->esock_in = -1;
413 : GNUNET_break (0 == close (client->esock_out));
414 : client->esock_out = -1;
415 : #endif
416 78 : return NULL;
417 : }
418 :
419 :
420 : /**
421 : * Task that listens for incoming clients.
422 : *
423 : * @param cls a `struct TES_Callbacks`
424 : */
425 : static void
426 78 : listen_job (void *cls)
427 : {
428 78 : const struct TES_Callbacks *cb = cls;
429 : int s;
430 : #ifdef __linux__
431 : int e;
432 : #else
433 : int e[2];
434 : #endif
435 : struct sockaddr_storage sa;
436 78 : socklen_t sa_len = sizeof (sa);
437 :
438 78 : listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
439 : unix_sock,
440 : &listen_job,
441 : cls);
442 78 : s = accept (GNUNET_NETWORK_get_fd (unix_sock),
443 : (struct sockaddr *) &sa,
444 : &sa_len);
445 78 : if (-1 == s)
446 : {
447 0 : bool st = ( (ENFILE == errno) ||
448 0 : (EMFILE == errno) );
449 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
450 : "accept");
451 0 : if (st)
452 : {
453 0 : GNUNET_SCHEDULER_cancel (listen_task);
454 0 : listen_task = NULL;
455 : }
456 0 : return;
457 : }
458 : #ifdef __linux__
459 78 : e = eventfd (0,
460 : EFD_CLOEXEC);
461 78 : if (-1 == e)
462 : {
463 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
464 : "eventfd");
465 0 : GNUNET_break (0 == close (s));
466 0 : return;
467 : }
468 : #else
469 : if (0 != pipe (e))
470 : {
471 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
472 : "pipe");
473 : GNUNET_break (0 == close (s));
474 : return;
475 : }
476 : #endif
477 : {
478 : struct TES_Client *client;
479 : struct TES_Client *nxt;
480 :
481 78 : client = GNUNET_new (struct TES_Client);
482 78 : client->cb = *cb;
483 78 : client->csock = s;
484 : #ifdef __linux__
485 78 : client->esock = e;
486 : #else
487 : client->esock_in = e[1];
488 : client->esock_out = e[0];
489 : #endif
490 78 : GNUNET_assert (0 == pthread_mutex_lock (&TES_clients_lock));
491 78 : for (struct TES_Client *pos = TES_clients_head;
492 165 : NULL != pos;
493 87 : pos = nxt)
494 : {
495 87 : nxt = pos->next;
496 87 : if (-1 == pos->csock)
497 : {
498 : void *rval;
499 :
500 3 : GNUNET_CONTAINER_DLL_remove (TES_clients_head,
501 : TES_clients_tail,
502 : pos);
503 3 : GNUNET_break (0 ==
504 : pthread_join (pos->worker,
505 : &rval));
506 3 : GNUNET_free (pos);
507 : }
508 : }
509 78 : GNUNET_CONTAINER_DLL_insert (TES_clients_head,
510 : TES_clients_tail,
511 : client);
512 78 : GNUNET_assert (0 == pthread_mutex_unlock (&TES_clients_lock));
513 78 : if (0 !=
514 78 : pthread_create (&client->worker,
515 : NULL,
516 : &sign_worker,
517 : client))
518 : {
519 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
520 : "pthread_create");
521 0 : GNUNET_assert (0 == pthread_mutex_lock (&TES_clients_lock));
522 0 : GNUNET_CONTAINER_DLL_remove (TES_clients_head,
523 : TES_clients_tail,
524 : client);
525 0 : GNUNET_assert (0 == pthread_mutex_unlock (&TES_clients_lock));
526 0 : GNUNET_break (0 == close (client->csock));
527 : #ifdef __linux__
528 0 : GNUNET_break (0 == close (client->esock));
529 : #else
530 : GNUNET_break (0 == close (client->esock_in));
531 : GNUNET_break (0 == close (client->esock_out));
532 : #endif
533 0 : GNUNET_free (client);
534 : }
535 : }
536 : }
537 :
538 :
539 : int
540 54 : TES_listen_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
541 : const char *section,
542 : const struct TES_Callbacks *cb)
543 : {
544 : {
545 : char *pfn;
546 :
547 54 : if (GNUNET_OK !=
548 54 : GNUNET_CONFIGURATION_get_value_filename (cfg,
549 : section,
550 : "SM_PRIV_KEY",
551 : &pfn))
552 : {
553 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
554 : section,
555 : "SM_PRIV_KEY");
556 0 : return EXIT_NOTCONFIGURED;
557 : }
558 54 : if (GNUNET_SYSERR ==
559 54 : GNUNET_CRYPTO_eddsa_key_from_file (pfn,
560 : GNUNET_YES,
561 : &TES_smpriv.eddsa_priv))
562 : {
563 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
564 : section,
565 : "SM_PRIV_KEY",
566 : "Could not use file to persist private key");
567 0 : GNUNET_free (pfn);
568 0 : return EXIT_NOPERMISSION;
569 : }
570 54 : GNUNET_free (pfn);
571 54 : GNUNET_CRYPTO_eddsa_key_get_public (&TES_smpriv.eddsa_priv,
572 : &TES_smpub.eddsa_pub);
573 : }
574 :
575 54 : if (GNUNET_OK !=
576 54 : GNUNET_CONFIGURATION_get_value_filename (cfg,
577 : section,
578 : "UNIXPATH",
579 : &unixpath))
580 : {
581 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
582 : section,
583 : "UNIXPATH");
584 0 : return EXIT_NOTCONFIGURED;
585 : }
586 54 : GNUNET_assert (NULL != unixpath);
587 54 : unix_sock = TES_open_socket (unixpath);
588 54 : if (NULL == unix_sock)
589 : {
590 0 : GNUNET_free (unixpath);
591 0 : GNUNET_break (0);
592 0 : return EXIT_NOPERMISSION;
593 : }
594 : /* start job to accept incoming requests on 'sock' */
595 54 : listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
596 : unix_sock,
597 : &listen_job,
598 : (void *) cb);
599 54 : return 0;
600 : }
601 :
602 :
603 : void
604 54 : TES_listen_stop (void)
605 : {
606 : struct TES_Client *client;
607 :
608 54 : if (NULL != listen_task)
609 : {
610 54 : GNUNET_SCHEDULER_cancel (listen_task);
611 54 : listen_task = NULL;
612 : }
613 54 : if (NULL != unix_sock)
614 : {
615 54 : GNUNET_break (GNUNET_OK ==
616 : GNUNET_NETWORK_socket_close (unix_sock));
617 54 : unix_sock = NULL;
618 : }
619 54 : if (0 != unlink (unixpath))
620 : {
621 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
622 : "unlink",
623 : unixpath);
624 : }
625 54 : GNUNET_free (unixpath);
626 54 : in_shutdown = true;
627 54 : TES_wake_clients ();
628 54 : GNUNET_assert (0 == pthread_mutex_lock (&TES_clients_lock));
629 129 : while (NULL != (client = TES_clients_head))
630 : {
631 : void *rval;
632 :
633 75 : GNUNET_CONTAINER_DLL_remove (TES_clients_head,
634 : TES_clients_tail,
635 : client);
636 75 : GNUNET_break (0 ==
637 : pthread_join (client->worker,
638 : &rval));
639 75 : GNUNET_free (client);
640 : }
641 54 : GNUNET_assert (0 == pthread_mutex_unlock (&TES_clients_lock));
642 54 : }
|