exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

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 }