secmod_common.c (24444B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2020, 2026 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 "platform.h" 22 #include "taler/taler_util.h" 23 #include "secmod_common.h" 24 #include <poll.h> 25 #ifdef __linux__ 26 #include <sys/eventfd.h> 27 #endif 28 29 30 char * 31 TES_normalize_section (const char *section) 32 { 33 char *result = GNUNET_strdup (section); 34 35 for (char *p = result; '\0' != *p; p++) 36 *p = (char) tolower ((unsigned char) *p); 37 return result; 38 } 39 40 41 /** 42 * A denomination directory to rename after checking for conflicts. 43 */ 44 struct KeyDirectory 45 { 46 char *old_name; 47 char *new_name; 48 }; 49 50 51 /** 52 * Closure for #check_section_name and #collect_key_directory. 53 */ 54 struct KeyDirectoryContext 55 { 56 const char *cprefix; 57 struct KeyDirectory *dirs; 58 unsigned int num_dirs; 59 bool invalid_section_name; 60 }; 61 62 63 /** 64 * Reject section names that would use nested key directories. 65 * 66 * @param cls a `struct KeyDirectoryContext` 67 * @param section configuration section name to check 68 */ 69 static void 70 check_section_name (void *cls, 71 const char *section) 72 { 73 struct KeyDirectoryContext *ctx = cls; 74 size_t prefix_len = strlen (ctx->cprefix); 75 76 if ( (0 != strncasecmp (section, 77 ctx->cprefix, 78 prefix_len)) || 79 (NULL == strchr (section + prefix_len, '/')) ) 80 return; 81 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 82 "Invalid denomination section `%s': suffix must not contain '/'\n", 83 section); 84 ctx->invalid_section_name = true; 85 } 86 87 88 /** 89 * Collect directories requiring migration without modifying the directory 90 * being scanned. Reject symlinks and check all destinations before starting 91 * the migration. 92 * 93 * @param cls a `struct KeyDirectoryContext` 94 * @param filename directory entry to inspect 95 * @return #GNUNET_OK to continue, #GNUNET_SYSERR on a symlink, conflict or I/O error 96 */ 97 static enum GNUNET_GenericReturnValue 98 collect_key_directory (void *cls, 99 const char *filename) 100 { 101 struct KeyDirectoryContext *ctx = cls; 102 const char *base = strrchr (filename, '/') + 1; 103 struct KeyDirectory dir; 104 struct stat sb; 105 struct stat target; 106 char *normalized; 107 108 if (0 != lstat (filename, &sb)) 109 { 110 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 111 "lstat", 112 filename); 113 return GNUNET_SYSERR; 114 } 115 if (S_ISLNK (sb.st_mode)) 116 { 117 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 118 "Invalid key directory entry `%s': symbolic links are not allowed\n", 119 filename); 120 return GNUNET_SYSERR; 121 } 122 if (0 != strncasecmp (base, 123 ctx->cprefix, 124 strlen (ctx->cprefix))) 125 return GNUNET_OK; 126 if (! S_ISDIR (sb.st_mode)) 127 return GNUNET_OK; 128 normalized = TES_normalize_section (base); 129 if (0 == strcmp (base, normalized)) 130 { 131 GNUNET_free (normalized); 132 return GNUNET_OK; 133 } 134 GNUNET_asprintf (&dir.new_name, 135 "%.*s%s", 136 (int) (base - filename), 137 filename, 138 normalized); 139 GNUNET_free (normalized); 140 for (unsigned int i = 0; i < ctx->num_dirs; i++) 141 { 142 if (0 != strcmp (dir.new_name, ctx->dirs[i].new_name)) 143 continue; 144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 145 "Conflicting denomination key directories `%s' and `%s'; resolve their capitalization before restarting\n", 146 filename, 147 ctx->dirs[i].old_name); 148 GNUNET_free (dir.new_name); 149 return GNUNET_SYSERR; 150 } 151 if (0 == lstat (dir.new_name, &target)) 152 { 153 /* On a case-insensitive filesystem both spellings may already refer to 154 the same directory. Still rename it to update the stored spelling. */ 155 if ( (sb.st_dev != target.st_dev) || 156 (sb.st_ino != target.st_ino) ) 157 { 158 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 159 "Cannot rename denomination key directory `%s' to `%s': destination exists; resolve the conflict before restarting\n", 160 filename, 161 dir.new_name); 162 GNUNET_free (dir.new_name); 163 return GNUNET_SYSERR; 164 } 165 } 166 else if (ENOENT != errno) 167 { 168 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 169 "lstat", 170 dir.new_name); 171 GNUNET_free (dir.new_name); 172 return GNUNET_SYSERR; 173 } 174 dir.old_name = GNUNET_strdup (filename); 175 GNUNET_array_append (ctx->dirs, ctx->num_dirs, dir); 176 return GNUNET_OK; 177 } 178 179 180 enum GNUNET_GenericReturnValue 181 TES_normalize_key_directory (const struct GNUNET_CONFIGURATION_Handle *cfg, 182 const char *keydir, 183 const char *cprefix) 184 { 185 struct KeyDirectoryContext ctx = { 186 .cprefix = cprefix 187 }; 188 enum GNUNET_GenericReturnValue ret = GNUNET_OK; 189 190 GNUNET_CONFIGURATION_iterate_sections (cfg, 191 &check_section_name, 192 &ctx); 193 if (ctx.invalid_section_name) 194 return GNUNET_SYSERR; 195 if (GNUNET_OK != GNUNET_DISK_directory_create (keydir)) 196 return GNUNET_SYSERR; 197 if (0 > GNUNET_DISK_directory_scan (keydir, 198 &collect_key_directory, 199 &ctx)) 200 ret = GNUNET_SYSERR; 201 for (unsigned int i = 0; i < ctx.num_dirs; i++) 202 { 203 struct KeyDirectory *dir = &ctx.dirs[i]; 204 205 if (GNUNET_OK == ret) 206 { 207 if (0 != rename (dir->old_name, dir->new_name)) 208 { 209 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 210 "rename", 211 dir->old_name); 212 ret = GNUNET_SYSERR; 213 } 214 else 215 { 216 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 217 "Renamed denomination key directory `%s' to `%s'\n", 218 dir->old_name, 219 dir->new_name); 220 } 221 } 222 GNUNET_free (dir->old_name); 223 GNUNET_free (dir->new_name); 224 } 225 GNUNET_free (ctx.dirs); 226 return ret; 227 } 228 229 230 int 231 TES_open_key_file (const char *filename, 232 struct stat *sbuf) 233 { 234 int fd; 235 236 /* O_NOFOLLOW refuses symbolic links without a separate lstat(), and 237 O_NONBLOCK keeps us from hanging on a FIFO, which fstat() refuses. */ 238 fd = open (filename, 239 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK); 240 if (-1 == fd) 241 { 242 /* Linux reports a symbolic link with ELOOP, some BSDs with EMLINK */ 243 if ( (ELOOP == errno) || 244 (EMLINK == errno) ) 245 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 246 "File `%s' is a symbolic link, which is not allowed for private keys; refusing to use it\n", 247 filename); 248 else 249 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 250 "open", 251 filename); 252 return -1; 253 } 254 if (0 != fstat (fd, 255 sbuf)) 256 { 257 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 258 "fstat", 259 filename); 260 GNUNET_break (0 == close (fd)); 261 return -1; 262 } 263 if (! S_ISREG (sbuf->st_mode)) 264 { 265 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 266 "File `%s' is not a regular file, which is not allowed for private keys; refusing to use it\n", 267 filename); 268 GNUNET_break (0 == close (fd)); 269 return -1; 270 } 271 if (geteuid () != sbuf->st_uid) 272 { 273 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 274 "Private key file `%s' is owned by uid %u, not by our uid %u; refusing to use it\n", 275 filename, 276 (unsigned int) sbuf->st_uid, 277 (unsigned int) geteuid ()); 278 GNUNET_break (0 == close (fd)); 279 return -1; 280 } 281 if (1 != sbuf->st_nlink) 282 { 283 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 284 "Private key file `%s' has %llu hard links instead of one; refusing to use it\n", 285 filename, 286 (unsigned long long) sbuf->st_nlink); 287 GNUNET_break (0 == close (fd)); 288 return -1; 289 } 290 if (0 != (sbuf->st_mode & (S_IRWXG | S_IRWXO))) 291 { 292 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 293 "Private key file `%s' is accessible by group or others (mode %04o); refusing to use it, restrict it to its owner (chmod 400)\n", 294 filename, 295 (unsigned int) (sbuf->st_mode & 07777)); 296 GNUNET_break (0 == close (fd)); 297 return -1; 298 } 299 return fd; 300 } 301 302 303 /** 304 * Head of DLL of clients connected to us. 305 */ 306 struct TES_Client *TES_clients_head; 307 308 /** 309 * Tail of DLL of clients connected to us. 310 */ 311 struct TES_Client *TES_clients_tail; 312 313 /** 314 * Lock for the client queue. 315 */ 316 pthread_mutex_t TES_clients_lock = PTHREAD_MUTEX_INITIALIZER; 317 318 /** 319 * Private key of this security module. Used to sign denomination key 320 * announcements. 321 */ 322 struct TALER_SecurityModulePrivateKeyP TES_smpriv; 323 324 /** 325 * Public key of this security module. 326 */ 327 struct TALER_SecurityModulePublicKeyP TES_smpub; 328 329 /** 330 * Our listen socket. 331 */ 332 static struct GNUNET_NETWORK_Handle *unix_sock; 333 334 /** 335 * Path where we are listening. 336 */ 337 static char *unixpath; 338 339 /** 340 * Task run to accept new inbound connections. 341 */ 342 static struct GNUNET_SCHEDULER_Task *listen_task; 343 344 /** 345 * Set once we are in shutdown and workers should terminate. 346 */ 347 static volatile bool in_shutdown; 348 349 350 enum GNUNET_GenericReturnValue 351 TES_transmit_raw (int sock, 352 size_t end, 353 const void *pos) 354 { 355 size_t off = 0; 356 357 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 358 "Sending message of length %u\n", 359 (unsigned int) end); 360 while (off < end) 361 { 362 ssize_t ret = send (sock, 363 pos, 364 end - off, 365 0 /* no flags => blocking! */); 366 367 if ( (-1 == ret) && 368 ( (EAGAIN == errno) || 369 (EINTR == errno) ) ) 370 { 371 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, 372 "send"); 373 continue; 374 } 375 if (-1 == ret) 376 { 377 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 378 "send"); 379 return GNUNET_SYSERR; 380 } 381 if (0 == ret) 382 { 383 GNUNET_break (0); 384 return GNUNET_SYSERR; 385 } 386 off += ret; 387 pos += ret; 388 } 389 return GNUNET_OK; 390 } 391 392 393 enum GNUNET_GenericReturnValue 394 TES_transmit (int sock, 395 const struct GNUNET_MessageHeader *hdr) 396 { 397 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 398 "Sending message of type %u and length %u\n", 399 (unsigned int) ntohs (hdr->type), 400 (unsigned int) ntohs (hdr->size)); 401 return TES_transmit_raw (sock, 402 ntohs (hdr->size), 403 hdr); 404 } 405 406 407 struct GNUNET_NETWORK_Handle * 408 TES_open_socket (const char *my_unixpath) 409 { 410 int sock; 411 mode_t old_umask; 412 struct GNUNET_NETWORK_Handle *ret = NULL; 413 414 /* Change permissions so that group read/writes are allowed. 415 * We need this for multi-user exchange deployment with privilege 416 * separation, where taler-exchange-httpd is part of a group 417 * that allows it to talk to secmod. 418 */ 419 old_umask = umask (S_IROTH | S_IWOTH | S_IXOTH); 420 421 sock = socket (PF_UNIX, 422 SOCK_STREAM, 423 0); 424 if (-1 == sock) 425 { 426 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, 427 "socket"); 428 goto cleanup; 429 } 430 { 431 struct sockaddr_un un; 432 433 if (GNUNET_OK != 434 GNUNET_DISK_directory_create_for_file (my_unixpath)) 435 { 436 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 437 "mkdir(dirname)", 438 my_unixpath); 439 } 440 if (0 != unlink (my_unixpath)) 441 { 442 if (ENOENT != errno) 443 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 444 "unlink", 445 my_unixpath); 446 } 447 memset (&un, 448 0, 449 sizeof (un)); 450 un.sun_family = AF_UNIX; 451 strncpy (un.sun_path, 452 my_unixpath, 453 sizeof (un.sun_path) - 1); 454 if (0 != bind (sock, 455 (const struct sockaddr *) &un, 456 sizeof (un))) 457 { 458 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 459 "bind", 460 my_unixpath); 461 GNUNET_break (0 == close (sock)); 462 goto cleanup; 463 } 464 ret = GNUNET_NETWORK_socket_box_native (sock); 465 if (GNUNET_OK != 466 GNUNET_NETWORK_socket_listen (ret, 467 512)) 468 { 469 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 470 "listen", 471 my_unixpath); 472 GNUNET_break (GNUNET_OK == 473 GNUNET_NETWORK_socket_close (ret)); 474 ret = NULL; 475 } 476 } 477 cleanup: 478 (void) umask (old_umask); 479 return ret; 480 } 481 482 483 void 484 TES_wake_clients (void) 485 { 486 uint64_t num = 1; 487 488 GNUNET_assert (0 == pthread_mutex_lock (&TES_clients_lock)); 489 for (struct TES_Client *client = TES_clients_head; 490 NULL != client; 491 client = client->next) 492 { 493 #ifdef __linux__ 494 if (-1 == client->esock) 495 continue; 496 GNUNET_assert (sizeof (num) == 497 write (client->esock, 498 &num, 499 sizeof (num))); 500 #else 501 if (-1 == client->esock_in) 502 continue; 503 GNUNET_assert (sizeof (num) == 504 write (client->esock_in, 505 &num, 506 sizeof (num))); 507 #endif 508 } 509 GNUNET_assert (0 == pthread_mutex_unlock (&TES_clients_lock)); 510 } 511 512 513 enum GNUNET_GenericReturnValue 514 TES_read_work (void *cls, 515 TES_MessageDispatch dispatch) 516 { 517 struct TES_Client *client = cls; 518 char *buf = client->iobuf; 519 size_t off = 0; 520 uint16_t msize = 0; 521 const struct GNUNET_MessageHeader *hdr = NULL; 522 enum GNUNET_GenericReturnValue ret; 523 524 do 525 { 526 ssize_t recv_size; 527 528 recv_size = recv (client->csock, 529 &buf[off], 530 sizeof (client->iobuf) - off, 531 0); 532 if (-1 == recv_size) 533 { 534 if ( (0 == off) && 535 (EAGAIN == errno) ) 536 return GNUNET_NO; 537 if ( (EINTR == errno) || 538 (EAGAIN == errno) ) 539 { 540 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, 541 "recv"); 542 continue; 543 } 544 if (ECONNRESET != errno) 545 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 546 "recv"); 547 return GNUNET_SYSERR; 548 } 549 if (0 == recv_size) 550 { 551 /* regular disconnect? */ 552 GNUNET_break_op (0 == off); 553 return GNUNET_SYSERR; 554 } 555 off += recv_size; 556 more: 557 msize = sizeof (*hdr); /* at least */ 558 if (off < msize) 559 continue; 560 hdr = (const struct GNUNET_MessageHeader *) buf; 561 msize = ntohs (hdr->size); 562 #if 0 563 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 564 "Received message of type %u with %u bytes\n", 565 (unsigned int) ntohs (hdr->type), 566 (unsigned int) msize); 567 #endif 568 if (msize < sizeof (*hdr)) 569 { 570 GNUNET_break_op (0); 571 return GNUNET_SYSERR; 572 } 573 } while ( (NULL == hdr) || 574 (off < msize) ); 575 576 ret = dispatch (client, 577 hdr); 578 if ( (GNUNET_OK != ret) || 579 (off == msize) ) 580 return ret; 581 memmove (buf, 582 &buf[msize], 583 off - msize); 584 off -= msize; 585 goto more; 586 } 587 588 589 bool 590 TES_await_ready (struct TES_Client *client) 591 { 592 /* wait for reply with 1s timeout */ 593 struct pollfd pfds[] = { 594 { 595 .fd = client->csock, 596 .events = POLLIN 597 }, 598 { 599 #ifdef __linux__ 600 .fd = client->esock, 601 #else 602 .fd = client->esock_out, 603 #endif 604 .events = POLLIN 605 }, 606 }; 607 int ret; 608 609 ret = poll (pfds, 610 2, 611 -1); 612 if ( (-1 == ret) && 613 (EINTR != errno) ) 614 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, 615 "poll"); 616 for (int i = 0; i<2; i++) 617 { 618 if ( 619 #ifdef __linux__ 620 (pfds[i].fd == client->esock) && 621 #else 622 (pfds[i].fd == client->esock_out) && 623 #endif 624 (POLLIN == pfds[i].revents) ) 625 { 626 uint64_t num; 627 628 #ifdef __linux__ 629 GNUNET_assert (sizeof (num) == 630 read (client->esock, 631 &num, 632 sizeof (num))); 633 #else 634 GNUNET_assert (sizeof (num) == 635 read (client->esock_out, 636 &num, 637 sizeof (num))); 638 #endif 639 return true; 640 } 641 } 642 return false; 643 } 644 645 646 /** 647 * Main function of a worker thread that signs. 648 * 649 * @param cls the client we are working on 650 * @return NULL 651 */ 652 static void * 653 sign_worker (void *cls) 654 { 655 struct TES_Client *client = cls; 656 657 if (GNUNET_OK != 658 client->cb.init (client)) 659 { 660 GNUNET_break (0); 661 return NULL; 662 } 663 while (! in_shutdown) 664 { 665 if (TES_await_ready (client)) 666 { 667 if (GNUNET_OK != 668 client->cb.updater (client)) 669 break; 670 } 671 else 672 { 673 if (GNUNET_SYSERR == 674 TES_read_work (client, 675 client->cb.dispatch)) 676 break; 677 } 678 } 679 GNUNET_break (0 == close (client->csock)); 680 client->csock = -1; 681 return NULL; 682 } 683 684 685 /** 686 * Clean up @a pos, joining the thread and closing the 687 * file descriptors. 688 * 689 * @param[in] pos client to clean up 690 */ 691 static void 692 join_client (struct TES_Client *pos) 693 { 694 void *rval; 695 696 GNUNET_CONTAINER_DLL_remove (TES_clients_head, 697 TES_clients_tail, 698 pos); 699 GNUNET_break (0 == 700 pthread_join (pos->worker, 701 &rval)); 702 #ifdef __linux__ 703 GNUNET_break (0 == close (pos->esock)); 704 pos->esock = -1; 705 #else 706 GNUNET_break (0 == close (pos->esock_in)); 707 pos->esock_in = -1; 708 GNUNET_break (0 == close (pos->esock_out)); 709 pos->esock_out = -1; 710 #endif 711 GNUNET_free (pos); 712 } 713 714 715 /** 716 * Task that listens for incoming clients. 717 * 718 * @param cls a `struct TES_Callbacks` 719 */ 720 static void 721 listen_job (void *cls) 722 { 723 const struct TES_Callbacks *cb = cls; 724 int s; 725 #ifdef __linux__ 726 int e; 727 #else 728 int e[2]; 729 #endif 730 struct sockaddr_storage sa; 731 socklen_t sa_len = sizeof (sa); 732 733 listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 734 unix_sock, 735 &listen_job, 736 cls); 737 s = accept (GNUNET_NETWORK_get_fd (unix_sock), 738 (struct sockaddr *) &sa, 739 &sa_len); 740 if (-1 == s) 741 { 742 bool st = ( (ENFILE == errno) || 743 (EMFILE == errno) ); 744 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 745 "accept"); 746 if (st) 747 { 748 GNUNET_SCHEDULER_cancel (listen_task); 749 listen_task = NULL; 750 } 751 return; 752 } 753 #ifdef __linux__ 754 e = eventfd (0, 755 EFD_CLOEXEC); 756 if (-1 == e) 757 { 758 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 759 "eventfd"); 760 GNUNET_break (0 == close (s)); 761 return; 762 } 763 #else 764 if (0 != pipe (e)) 765 { 766 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 767 "pipe"); 768 GNUNET_break (0 == close (s)); 769 return; 770 } 771 #endif 772 { 773 struct TES_Client *client; 774 struct TES_Client *nxt; 775 776 client = GNUNET_new (struct TES_Client); 777 client->cb = *cb; 778 client->csock = s; 779 #ifdef __linux__ 780 client->esock = e; 781 #else 782 client->esock_in = e[1]; 783 client->esock_out = e[0]; 784 #endif 785 GNUNET_assert (0 == pthread_mutex_lock (&TES_clients_lock)); 786 for (struct TES_Client *pos = TES_clients_head; 787 NULL != pos; 788 pos = nxt) 789 { 790 nxt = pos->next; 791 if (-1 == pos->csock) 792 { 793 join_client (pos); 794 } 795 } 796 GNUNET_CONTAINER_DLL_insert (TES_clients_head, 797 TES_clients_tail, 798 client); 799 GNUNET_assert (0 == pthread_mutex_unlock (&TES_clients_lock)); 800 if (0 != 801 pthread_create (&client->worker, 802 NULL, 803 &sign_worker, 804 client)) 805 { 806 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 807 "pthread_create"); 808 GNUNET_assert (0 == pthread_mutex_lock (&TES_clients_lock)); 809 GNUNET_CONTAINER_DLL_remove (TES_clients_head, 810 TES_clients_tail, 811 client); 812 GNUNET_assert (0 == pthread_mutex_unlock (&TES_clients_lock)); 813 GNUNET_break (0 == close (client->csock)); 814 #ifdef __linux__ 815 GNUNET_break (0 == close (client->esock)); 816 #else 817 GNUNET_break (0 == close (client->esock_in)); 818 GNUNET_break (0 == close (client->esock_out)); 819 #endif 820 GNUNET_free (client); 821 } 822 } 823 } 824 825 826 int 827 TES_listen_start (const struct GNUNET_CONFIGURATION_Handle *cfg, 828 const char *section, 829 const struct TES_Callbacks *cb) 830 { 831 { 832 char *pfn; 833 834 if (GNUNET_OK != 835 GNUNET_CONFIGURATION_get_value_filename (cfg, 836 section, 837 "SM_PRIV_KEY", 838 &pfn)) 839 { 840 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 841 section, 842 "SM_PRIV_KEY"); 843 return EXIT_NOTCONFIGURED; 844 } 845 if (GNUNET_SYSERR == 846 GNUNET_CRYPTO_eddsa_key_from_file (pfn, 847 GNUNET_YES, 848 &TES_smpriv.eddsa_priv)) 849 { 850 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 851 section, 852 "SM_PRIV_KEY", 853 "Could not use file to persist private key"); 854 GNUNET_free (pfn); 855 return EXIT_NOPERMISSION; 856 } 857 GNUNET_free (pfn); 858 GNUNET_CRYPTO_eddsa_key_get_public (&TES_smpriv.eddsa_priv, 859 &TES_smpub.eddsa_pub); 860 } 861 862 if (GNUNET_OK != 863 GNUNET_CONFIGURATION_get_value_filename (cfg, 864 section, 865 "UNIXPATH", 866 &unixpath)) 867 { 868 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 869 section, 870 "UNIXPATH"); 871 return EXIT_NOTCONFIGURED; 872 } 873 GNUNET_assert (NULL != unixpath); 874 unix_sock = TES_open_socket (unixpath); 875 if (NULL == unix_sock) 876 { 877 GNUNET_free (unixpath); 878 GNUNET_break (0); 879 return EXIT_NOPERMISSION; 880 } 881 /* start job to accept incoming requests on 'sock' */ 882 listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 883 unix_sock, 884 &listen_job, 885 (void *) cb); 886 return 0; 887 } 888 889 890 void 891 TES_listen_stop (void) 892 { 893 struct TES_Client *client; 894 895 if (NULL != listen_task) 896 { 897 GNUNET_SCHEDULER_cancel (listen_task); 898 listen_task = NULL; 899 } 900 if (NULL != unix_sock) 901 { 902 GNUNET_break (GNUNET_OK == 903 GNUNET_NETWORK_socket_close (unix_sock)); 904 unix_sock = NULL; 905 } 906 if (0 != unlink (unixpath)) 907 { 908 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 909 "unlink", 910 unixpath); 911 } 912 GNUNET_free (unixpath); 913 in_shutdown = true; 914 TES_wake_clients (); 915 GNUNET_assert (0 == pthread_mutex_lock (&TES_clients_lock)); 916 while (NULL != (client = TES_clients_head)) 917 join_client (client); 918 GNUNET_assert (0 == pthread_mutex_unlock (&TES_clients_lock)); 919 }