Allow decryption with card keys > 3072 bits
[gnupg.git] / agent / gpg-agent.c
index a548664..b117849 100644 (file)
@@ -38,7 +38,7 @@
 #ifdef HAVE_SIGNAL_H
 # include <signal.h>
 #endif
-#include <pth.h>
+#include <npth.h>
 
 #define JNLIB_NEED_LOG_LOGV
 #define JNLIB_NEED_AFLOCAL
@@ -52,6 +52,8 @@
 #include "exechelp.h"
 #include "asshelp.h"
 #include "../include/cipher.h" /* for PUBKEY_ALGO_ECDSA, PUBKEY_ALGO_ECDH */
+#include "../common/init.h"
+
 
 enum cmd_and_opt_values
 { aNull = 0,
@@ -268,6 +270,9 @@ static char *current_logfile;
    watched. */
 static pid_t parent_pid = (pid_t)(-1);
 
+/* Number of active connections.  */
+static int active_connections;
+
 \f
 /*
    Local prototypes.
@@ -287,28 +292,16 @@ static void check_own_socket (void);
 static int check_for_running_agent (int silent, int mode);
 
 /* Pth wrapper function definitions. */
-ASSUAN_SYSTEM_PTH_IMPL;
-
-GCRY_THREAD_OPTION_PTH_IMPL;
-static int fixed_gcry_pth_init (void)
-{
-  return pth_self ()? 0 : (pth_init () == FALSE) ? errno : 0;
-}
-
-
-#ifndef PTH_HAVE_PTH_THREAD_ID
-static unsigned long pth_thread_id (void)
-{
-  return (unsigned long)pth_self ();
-}
-#endif
-
+ASSUAN_SYSTEM_NPTH_IMPL;
 
 \f
 /*
    Functions.
  */
 
+/* Allocate a string describing a library version by calling a GETFNC.
+   This function is expected to be called only once.  GETFNC is
+   expected to have a semantic like gcry_check_version ().  */
 static char *
 make_libversion (const char *libname, const char *(*getfnc)(const char*))
 {
@@ -326,7 +319,9 @@ make_libversion (const char *libname, const char *(*getfnc)(const char*))
   return result;
 }
 
-
+/* Return strings describing this program.  The case values are
+   described in common/argparse.c:strusage.  The values here override
+   the default values given by strusage.  */
 static const char *
 my_strusage (int level)
 {
@@ -399,7 +394,7 @@ set_debug (void)
     }
   else
     {
-      log_error (_("invalid debug-level `%s' given\n"), debug_level);
+      log_error (_("invalid debug-level '%s' given\n"), debug_level);
       opt.debug = 0; /* Reset debugging, so that prior debug
                         statements won't have an undesired effect. */
     }
@@ -448,6 +443,9 @@ remove_socket (char *name)
     }
 }
 
+
+/* Cleanup code for this program.  This is either called has an atexit
+   handler or directly.  */
 static void
 cleanup (void)
 {
@@ -568,7 +566,6 @@ main (int argc, char **argv )
 {
   ARGPARSE_ARGS pargs;
   int orig_argc;
-  int may_coredump;
   char **orig_argv;
   FILE *configfp = NULL;
   char *configname = NULL;
@@ -610,17 +607,7 @@ main (int argc, char **argv )
   i18n_init ();
   init_common_subsystems (&argc, &argv);
 
-
-  /* Libgcrypt requires us to register the threading model first.
-     Note that this will also do the pth_init. */
-  gcry_threads_pth.init = fixed_gcry_pth_init;
-  err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
-  if (err)
-    {
-      log_fatal ("can't register GNU Pth with Libgcrypt: %s\n",
-                 gpg_strerror (err));
-    }
-
+  npth_init ();
 
   /* Check that the libraries are suitable.  Do it here because
      the option parsing may need services of the library. */
@@ -635,14 +622,14 @@ main (int argc, char **argv )
   malloc_hooks.free = gcry_free;
   assuan_set_malloc_hooks (&malloc_hooks);
   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
-  assuan_set_system_hooks (ASSUAN_SYSTEM_PTH);
+  assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
   assuan_sock_init ();
   setup_libassuan_logging (&opt.debug);
 
   setup_libgcrypt_logging ();
   gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
 
-  may_coredump = disable_core_dumps ();
+  disable_core_dumps ();
 
   /* Set default options.  */
   parse_rereadable_options (NULL, 0); /* Reset them to default values. */
@@ -740,7 +727,7 @@ main (int argc, char **argv )
           if (default_config)
             {
               if( parse_debug )
-                log_info (_("NOTE: no default option file `%s'\n"),
+                log_info (_("NOTE: no default option file '%s'\n"),
                           configname );
               /* Save the default conf file name so that
                  reread_configuration is able to test whether the
@@ -751,7 +738,7 @@ main (int argc, char **argv )
            }
           else
             {
-              log_error (_("option file `%s': %s\n"),
+              log_error (_("option file '%s': %s\n"),
                          configname, strerror(errno) );
               exit(2);
            }
@@ -759,7 +746,7 @@ main (int argc, char **argv )
           configname = NULL;
        }
       if (parse_debug && configname )
-        log_info (_("reading options from `%s'\n"), configname );
+        log_info (_("reading options from '%s'\n"), configname );
       default_config = 0;
     }
 
@@ -801,6 +788,7 @@ main (int argc, char **argv )
         case oTTYtype: default_ttytype = xstrdup (pargs.r.ret_str); break;
         case oLCctype: default_lc_ctype = xstrdup (pargs.r.ret_str); break;
         case oLCmessages: default_lc_messages = xstrdup (pargs.r.ret_str);
+          break;
         case oXauthority: default_xauthority = xstrdup (pargs.r.ret_str);
           break;
 
@@ -863,6 +851,16 @@ main (int argc, char **argv )
   /*log_info ("NOTE: this is a development version!\n");*/
 #endif
 
+  /* Print a warning if an argument looks like an option.  */
+  if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
+    {
+      int i;
+
+      for (i=0; i < argc; i++)
+        if (argv[i][0] == '-' && argv[i][1] == '-')
+          log_info (_("NOTE: '%s' is not considered an option\n"), argv[i]);
+    }
+
 #ifdef ENABLE_NLS
   /* gpg-agent usually does not output any messages because it runs in
      the background.  For log files it is acceptable to have messages
@@ -1074,19 +1072,9 @@ main (int argc, char **argv )
           /* Close the socket FD. */
           close (fd);
 
-          /* Note that we used a standard fork so that Pth runs in
-             both the parent and the child.  The pth_fork would
-             terminate Pth in the child but that is not the way we
-             want it.  Thus we use a plain fork and terminate Pth here
-             in the parent.  The pth_kill may or may not work reliable
-             but it should not harm to call it.  Because Pth fiddles
-             with the signal mask the signal mask might not be correct
-             right now and thus we restore it.  That is not strictly
-             necessary but some programs falsely assume a cleared
-             signal mask.  */
-#warning need to do something about pth_kill - see bug#1320
-          if ( !pth_kill () )
-            log_error ("pth_kill failed in forked process\n");
+          /* The signal mask might not be correct right now and thus
+             we restore it.  That is not strictly necessary but some
+             programs falsely assume a cleared signal mask.  */
 
 #ifdef HAVE_SIGPROCMASK
           if (startup_signal_mask_valid)
@@ -1129,7 +1117,7 @@ main (int argc, char **argv )
 
               fp = es_fopen (env_file_name, "w,mode=-rw");
               if (!fp)
-                log_error (_("error creating `%s': %s\n"),
+                log_error (_("error creating '%s': %s\n"),
                              env_file_name, strerror (errno));
               else
                 {
@@ -1181,11 +1169,11 @@ main (int argc, char **argv )
               if (csh_style)
                 {
                   *strchr (infostr, '=') = ' ';
-                  es_printf ("setenv %s\n", infostr);
+                  es_printf ("setenv %s;\n", infostr);
                  if (opt.ssh_support)
                    {
                      *strchr (infostr_ssh_sock, '=') = ' ';
-                     es_printf ("setenv %s\n", infostr_ssh_sock);
+                     es_printf ("setenv %s;\n", infostr_ssh_sock);
                    }
                 }
               else
@@ -1225,7 +1213,7 @@ main (int argc, char **argv )
                   if ( ! close (i)
                        && open ("/dev/null", i? O_WRONLY : O_RDONLY) == -1)
                     {
-                      log_error ("failed to open `%s': %s\n",
+                      log_error ("failed to open '%s': %s\n",
                                  "/dev/null", strerror (errno));
                       cleanup ();
                       exit (1);
@@ -1269,6 +1257,8 @@ main (int argc, char **argv )
 }
 
 
+/* Exit entry point.  This function should be called instead of a
+   plain exit.  */
 void
 agent_exit (int rc)
 {
@@ -1295,6 +1285,11 @@ agent_exit (int rc)
 }
 
 
+/* Each thread has its own local variables conveyed by a control
+   structure usually identified by an argument named CTRL.  This
+   function is called immediately after allocating the control
+   structure.  Its purpose is to setup the default values for that
+   structure.  */
 static void
 agent_init_default_ctrl (ctrl_t ctrl)
 {
@@ -1320,6 +1315,8 @@ agent_init_default_ctrl (ctrl_t ctrl)
 }
 
 
+/* Release all resources allocated by default in the control
+   structure.  This is the counterpart to agent_init_default_ctrl.  */
 static void
 agent_deinit_default_ctrl (ctrl_t ctrl)
 {
@@ -1355,7 +1352,7 @@ reread_configuration (void)
   fp = fopen (config_filename, "r");
   if (!fp)
     {
-      log_info (_("option file `%s': %s\n"),
+      log_info (_("option file '%s': %s\n"),
                 config_filename, strerror(errno) );
       return;
     }
@@ -1406,9 +1403,9 @@ get_agent_ssh_socket_name (void)
 void *
 get_agent_scd_notify_event (void)
 {
-  static HANDLE the_event;
+  static HANDLE the_event = INVALID_HANDLE_VALUE;
 
-  if (!the_event)
+  if (the_event == INVALID_HANDLE_VALUE)
     {
       HANDLE h, h2;
       SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
@@ -1475,7 +1472,7 @@ create_socket_name (char *standard_name, char *template)
       *p = 0;
       if (!mkdtemp (name))
        {
-         log_error (_("can't create directory `%s': %s\n"),
+         log_error (_("can't create directory '%s': %s\n"),
                     name, strerror (errno));
          agent_exit (2);
        }
@@ -1484,7 +1481,7 @@ create_socket_name (char *standard_name, char *template)
 
   if (strchr (name, PATHSEP_C))
     {
-      log_error (("`%s' are not allowed in the socket name\n"), PATHSEP_S);
+      log_error (("'%s' are not allowed in the socket name\n"), PATHSEP_S);
       agent_exit (2);
     }
   if (strlen (name) + 1 >= DIMof (struct sockaddr_un, sun_path) )
@@ -1521,7 +1518,7 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
   serv_addr->sun_family = AF_UNIX;
   if (strlen (name) + 1 >= sizeof (serv_addr->sun_path))
     {
-      log_error (_("socket name `%s' is too long\n"), name);
+      log_error (_("socket name '%s' is too long\n"), name);
       agent_exit (2);
     }
   strcpy (serv_addr->sun_path, name);
@@ -1565,7 +1562,7 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
     {
       /* We use gpg_strerror here because it allows us to get strings
          for some W32 socket error codes.  */
-      log_error (_("error binding socket to `%s': %s\n"),
+      log_error (_("error binding socket to '%s': %s\n"),
                 serv_addr->sun_path,
                  gpg_strerror (gpg_error_from_errno (errno)));
 
@@ -1583,7 +1580,7 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
     }
 
   if (opt.verbose)
-    log_info (_("listening on socket `%s'\n"), serv_addr->sun_path);
+    log_info (_("listening on socket '%s'\n"), serv_addr->sun_path);
 
   return fd;
 }
@@ -1602,10 +1599,10 @@ create_private_keys_directory (const char *home)
   if (stat (fname, &statbuf) && errno == ENOENT)
     {
       if (gnupg_mkdir (fname, "-rwx"))
-        log_error (_("can't create directory `%s': %s\n"),
+        log_error (_("can't create directory '%s': %s\n"),
                    fname, strerror (errno) );
       else if (!opt.quiet)
-        log_info (_("directory `%s' created\n"), fname);
+        log_info (_("directory '%s' created\n"), fname);
     }
   xfree (fname);
 }
@@ -1641,22 +1638,22 @@ create_directories (void)
                )
             {
               if (gnupg_mkdir (home, "-rwx"))
-                log_error (_("can't create directory `%s': %s\n"),
+                log_error (_("can't create directory '%s': %s\n"),
                            home, strerror (errno) );
               else
                 {
                   if (!opt.quiet)
-                    log_info (_("directory `%s' created\n"), home);
+                    log_info (_("directory '%s' created\n"), home);
                   create_private_keys_directory (home);
                 }
             }
         }
       else
-        log_error (_("stat() failed for `%s': %s\n"), home, strerror (errno));
+        log_error (_("stat() failed for '%s': %s\n"), home, strerror (errno));
     }
   else if ( !S_ISDIR(statbuf.st_mode))
     {
-      log_error (_("can't use `%s' as home directory\n"), home);
+      log_error (_("can't use '%s' as home directory\n"), home);
     }
   else /* exists and is a directory. */
     {
@@ -1721,6 +1718,7 @@ agent_sighup_action (void)
 }
 
 
+/* A helper function to handle SIGUSR2.  */
 static void
 agent_sigusr2_action (void)
 {
@@ -1731,6 +1729,9 @@ agent_sigusr2_action (void)
 }
 
 
+#ifndef HAVE_W32_SYSTEM
+/* The signal handler for this program.  It is expected to be run in
+   its own trhead and not in the context of a signal handler.  */
 static void
 handle_signal (int signo)
 {
@@ -1758,8 +1759,8 @@ handle_signal (int signo)
       if (!shutdown_pending)
         log_info ("SIGTERM received - shutting down ...\n");
       else
-        log_info ("SIGTERM received - still %ld running threads\n",
-                  pth_ctrl( PTH_CTRL_GETTHREADS ));
+        log_info ("SIGTERM received - still %i open connections\n",
+                 active_connections);
       shutdown_pending++;
       if (shutdown_pending > 2)
         {
@@ -1781,7 +1782,7 @@ handle_signal (int signo)
       log_info ("signal %d received - no action defined\n", signo);
     }
 }
-
+#endif
 
 /* Check the nonce on a new connection.  This is a NOP unless we we
    are using our Unix domain socket emulation under Windows.  */
@@ -1809,19 +1810,20 @@ start_connection_thread (void *arg)
 
   if (check_nonce (ctrl, &socket_nonce))
     {
-      log_error ("handler 0x%lx nonce check FAILED\n", pth_thread_id ());
+      log_error ("handler 0x%lx nonce check FAILED\n",
+                 (unsigned long) npth_self());
       return NULL;
     }
 
   agent_init_default_ctrl (ctrl);
   if (opt.verbose)
     log_info (_("handler 0x%lx for fd %d started\n"),
-              pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
+              (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
 
   start_command_handler (ctrl, GNUPG_INVALID_FD, ctrl->thread_startup.fd);
   if (opt.verbose)
     log_info (_("handler 0x%lx for fd %d terminated\n"),
-              pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
+              (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
 
   agent_deinit_default_ctrl (ctrl);
   xfree (ctrl);
@@ -1841,12 +1843,12 @@ start_connection_thread_ssh (void *arg)
   agent_init_default_ctrl (ctrl);
   if (opt.verbose)
     log_info (_("ssh handler 0x%lx for fd %d started\n"),
-              pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
+              (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
 
   start_command_handler_ssh (ctrl, ctrl->thread_startup.fd);
   if (opt.verbose)
     log_info (_("ssh handler 0x%lx for fd %d terminated\n"),
-              pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
+              (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
 
   agent_deinit_default_ctrl (ctrl);
   xfree (ctrl);
@@ -1859,59 +1861,46 @@ start_connection_thread_ssh (void *arg)
 static void
 handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
 {
-  pth_attr_t tattr;
-  pth_event_t ev, time_ev;
-  sigset_t sigs;
-  int signo;
+  npth_attr_t tattr;
   struct sockaddr_un paddr;
   socklen_t plen;
   fd_set fdset, read_fdset;
   int ret;
   gnupg_fd_t fd;
   int nfd;
+  int saved_errno;
+  struct timespec abstime;
+  struct timespec curtime;
+  struct timespec timeout;
+#ifdef HAVE_W32_SYSTEM
+  HANDLE events[2];
+  int events_set;
+#endif
 
-  tattr = pth_attr_new();
-  pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
-  pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
-
-#ifndef HAVE_W32_SYSTEM /* fixme */
-  /* Make sure that the signals we are going to handle are not blocked
-     and create an event object for them.  We also set the default
-     action to ignore because we use an Pth event to get notified
-     about signals.  This avoids that the default action is taken in
-     case soemthing goes wrong within Pth.  The problem might also be
-     a Pth bug.  */
-  sigemptyset (&sigs );
-  {
-    static const int mysigs[] = { SIGHUP, SIGUSR1, SIGUSR2, SIGINT, SIGTERM };
-    struct sigaction sa;
-    int i;
-
-    for (i=0; i < DIM (mysigs); i++)
-      {
-        sigemptyset (&sa.sa_mask);
-        sa.sa_handler = SIG_IGN;
-        sa.sa_flags = 0;
-        sigaction (mysigs[i], &sa, NULL);
-
-        sigaddset (&sigs, mysigs[i]);
-      }
-  }
+  ret = npth_attr_init(&tattr);
+  if (ret)
+    log_fatal ("error allocating thread attributes: %s\n",
+              strerror (ret));
+  npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
 
-  pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
-  ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
+#ifndef HAVE_W32_SYSTEM
+  npth_sigev_init ();
+  npth_sigev_add (SIGHUP);
+  npth_sigev_add (SIGUSR1);
+  npth_sigev_add (SIGUSR2);
+  npth_sigev_add (SIGINT);
+  npth_sigev_add (SIGTERM);
+  npth_sigev_fini ();
 #else
 # ifdef HAVE_W32CE_SYSTEM
   /* Use a dummy event. */
   sigs = 0;
   ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
 # else
-  sigs = 0;
-  ev = pth_event (PTH_EVENT_HANDLE, get_agent_scd_notify_event ());
-  signo = 0;
+  events[0] = get_agent_scd_notify_event ();
+  events[1] = INVALID_HANDLE_VALUE;
 # endif
 #endif
-  time_ev = NULL;
 
   /* Set a flag to tell call-scd.c that it may enable event
      notifications.  */
@@ -1927,15 +1916,15 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
         nfd = FD2INT (listen_fd_ssh);
     }
 
+  npth_clock_gettime (&abstime);
+  abstime.tv_sec += TIMERTICK_INTERVAL;
+
   for (;;)
     {
-      /* Make sure that our signals are not blocked.  */
-      pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
-
       /* Shutdown test.  */
       if (shutdown_pending)
         {
-          if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1)
+          if (active_connections == 0)
             break; /* ready */
 
           /* Do not accept new connections but keep on running the
@@ -1943,88 +1932,60 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
           FD_ZERO (&fdset);
        }
 
-      /* Create a timeout event if needed.  To help with power saving
-         we syncronize the ticks to the next full second.  */
-      if (!time_ev)
-        {
-          pth_time_t nexttick;
-
-          nexttick = pth_timeout (TIMERTICK_INTERVAL, 0);
-          if (nexttick.tv_usec > 10)  /* Use a 10 usec threshhold.  */
-            {
-              nexttick.tv_sec++;
-              nexttick.tv_usec = 0;
-            }
-          time_ev = pth_event (PTH_EVENT_TIME, nexttick);
-        }
-
       /* POSIX says that fd_set should be implemented as a structure,
          thus a simple assignment is fine to copy the entire set.  */
       read_fdset = fdset;
 
-      if (time_ev)
-        pth_event_concat (ev, time_ev, NULL);
-
-      ret = pth_select_ev (nfd+1, &read_fdset, NULL, NULL, NULL, ev);
-      if (time_ev)
-        pth_event_isolate (time_ev);
-
-      if (ret == -1)
+      npth_clock_gettime (&curtime);
+      if (!(npth_timercmp (&curtime, &abstime, <)))
        {
-          if (pth_event_occurred (ev)
-              || (time_ev && pth_event_occurred (time_ev)))
-            {
-              if (pth_event_occurred (ev))
-                {
-#if defined(HAVE_W32_SYSTEM) && defined(PTH_EVENT_HANDLE)
-                  agent_sigusr2_action ();
-#else
-                  handle_signal (signo);
-#endif
-                }
-              if (time_ev && pth_event_occurred (time_ev))
-                {
-                  pth_event_free (time_ev, PTH_FREE_ALL);
-                  time_ev = NULL;
-                  handle_tick ();
-                }
-              continue;
-            }
-          log_error (_("pth_select failed: %s - waiting 1s\n"),
-                     strerror (errno));
-          pth_sleep (1);
-          continue;
+         /* Timeout.  */
+         handle_tick ();
+         npth_clock_gettime (&abstime);
+         abstime.tv_sec += TIMERTICK_INTERVAL;
        }
+      npth_timersub (&abstime, &curtime, &timeout);
 
-      if (pth_event_occurred (ev))
-        {
-#if defined(HAVE_W32_SYSTEM) && defined(PTH_EVENT_HANDLE)
-          agent_sigusr2_action ();
-#else
+#ifndef HAVE_W32_SYSTEM
+      ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
+                          npth_sigev_sigmask ());
+      saved_errno = errno;
+
+      {
+        int signo;
+        while (npth_sigev_get_pending (&signo))
           handle_signal (signo);
+      }
+#else
+      events_set = 0;
+      ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
+                          events, &events_set);
+      saved_errno = errno;
+
+      /* This is valid even if npth_eselect returns an error.  */
+      if (events_set & 1)
+       agent_sigusr2_action ();
 #endif
-        }
-
-      if (time_ev && pth_event_occurred (time_ev))
-        {
-          pth_event_free (time_ev, PTH_FREE_ALL);
-          time_ev = NULL;
-          handle_tick ();
-        }
-
 
-      /* We now might create new threads and because we don't want any
-         signals (as we are handling them here) to be delivered to a
-         new thread.  Thus we need to block those signals. */
-      pth_sigmask (SIG_BLOCK, &sigs, NULL);
+      if (ret == -1 && saved_errno != EINTR)
+       {
+          log_error (_("npth_pselect failed: %s - waiting 1s\n"),
+                     strerror (saved_errno));
+          npth_sleep (1);
+          continue;
+       }
+      if (ret <= 0)
+       /* Interrupt or timeout.  Will be handled when calculating the
+          next timeout.  */
+       continue;
 
       if (!shutdown_pending && FD_ISSET (FD2INT (listen_fd), &read_fdset))
        {
           ctrl_t ctrl;
 
           plen = sizeof paddr;
-         fd = INT2FD (pth_accept (FD2INT(listen_fd),
-                                   (struct sockaddr *)&paddr, &plen));
+         fd = INT2FD (npth_accept (FD2INT(listen_fd),
+                                   (struct sockaddr *)&paddr, &plen));
          if (fd == GNUPG_INVALID_FD)
            {
              log_error ("accept failed: %s\n", strerror (errno));
@@ -2044,20 +2005,19 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
             }
           else
             {
-              char threadname[50];
+             npth_t thread;
 
-              snprintf (threadname, sizeof threadname-1,
-                        "conn fd=%d (gpg)", FD2INT(fd));
-              threadname[sizeof threadname -1] = 0;
-              pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
               ctrl->thread_startup.fd = fd;
-              if (!pth_spawn (tattr, start_connection_thread, ctrl))
+             ret = npth_create (&thread, &tattr,
+                                 start_connection_thread, ctrl);
+              if (ret)
                 {
                   log_error ("error spawning connection handler: %s\n",
-                             strerror (errno) );
+                            strerror (ret));
                   assuan_sock_close (fd);
                   xfree (ctrl);
                 }
+
             }
           fd = GNUPG_INVALID_FD;
        }
@@ -2068,8 +2028,8 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
           ctrl_t ctrl;
 
           plen = sizeof paddr;
-         fd = INT2FD(pth_accept (FD2INT(listen_fd_ssh),
-                                  (struct sockaddr *)&paddr, &plen));
+         fd = INT2FD(npth_accept (FD2INT(listen_fd_ssh),
+                                  (struct sockaddr *)&paddr, &plen));
          if (fd == GNUPG_INVALID_FD)
            {
              log_error ("accept failed for ssh: %s\n", strerror (errno));
@@ -2089,18 +2049,16 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
             }
           else
             {
-              char threadname[50];
+             npth_t thread;
 
               agent_init_default_ctrl (ctrl);
-              snprintf (threadname, sizeof threadname-1,
-                        "conn fd=%d (ssh)", FD2INT(fd));
-              threadname[sizeof threadname -1] = 0;
-              pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
               ctrl->thread_startup.fd = fd;
-              if (!pth_spawn (tattr, start_connection_thread_ssh, ctrl) )
+              ret = npth_create (&thread, &tattr,
+                                 start_connection_thread_ssh, ctrl);
+             if (ret)
                 {
                   log_error ("error spawning ssh connection handler: %s\n",
-                             strerror (errno) );
+                            strerror (ret));
                   assuan_sock_close (fd);
                   xfree (ctrl);
                 }
@@ -2109,11 +2067,9 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
        }
     }
 
-  pth_event_free (ev, PTH_FREE_ALL);
-  if (time_ev)
-    pth_event_free (time_ev, PTH_FREE_ALL);
   cleanup ();
   log_info (_("%s %s stopped\n"), strusage(11), strusage(13));
+  npth_attr_destroy (&tattr);
 }
 
 
@@ -2205,7 +2161,9 @@ static void
 check_own_socket (void)
 {
   char *sockname;
-  pth_attr_t tattr;
+  npth_t thread;
+  npth_attr_t tattr;
+  int err;
 
   if (!opt.use_standard_socket)
     return; /* This check makes only sense in standard socket mode.  */
@@ -2217,15 +2175,14 @@ check_own_socket (void)
   if (!sockname)
     return; /* Out of memory.  */
 
-  tattr = pth_attr_new();
-  pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
-  pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
-  pth_attr_set (tattr, PTH_ATTR_NAME, "check-own-socket");
-
-  if (!pth_spawn (tattr, check_own_socket_thread, sockname))
-      log_error ("error spawning check_own_socket_thread: %s\n",
-                 strerror (errno) );
-  pth_attr_destroy (tattr);
+  err = npth_attr_init (&tattr);
+  if (err)
+    return;
+  npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
+  err = npth_create (&thread, &tattr, check_own_socket_thread, sockname);
+  if (err)
+    log_error ("error spawning check_own_socket_thread: %s\n", strerror (err));
+  npth_attr_destroy (&tattr);
 }