Updated FSF's address.
[gnupg.git] / agent / gpg-agent.c
index 1134893..fc2a200 100644 (file)
@@ -16,7 +16,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #include <config.h>
@@ -37,9 +38,7 @@
 #endif /*HAVE_W32_SYSTEM*/
 #include <unistd.h>
 #include <signal.h>
-#ifdef USE_GNU_PTH
-# include <pth.h>
-#endif
+#include <pth.h>
 
 #define JNLIB_NEED_LOG_LOGV
 #include "agent.h"
@@ -50,6 +49,7 @@
 #ifdef HAVE_W32_SYSTEM
 #include "../jnlib/w32-afunix.h"
 #endif
+#include "setenv.h"
 
 
 enum cmd_and_opt_values 
@@ -83,9 +83,10 @@ enum cmd_and_opt_values
   oLCctype,
   oLCmessages,
   oScdaemonProgram,
-  oDisablePth,
   oDefCacheTTL,
+  oDefCacheTTLSSH,
   oMaxCacheTTL,
+  oMaxCacheTTLSSH,
   oUseStandardSocket,
   oNoUseStandardSocket,
 
@@ -94,7 +95,9 @@ enum cmd_and_opt_values
   oAllowPresetPassphrase,
   oKeepTTY,
   oKeepDISPLAY,
-  oSSHSupport
+  oSSHSupport,
+  oDisableScdaemon,
+  oWriteEnvFile
 };
 
 
@@ -119,7 +122,6 @@ static ARGPARSE_OPTS opts[] = {
   { oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
   { oNoGrab, "no-grab"     ,0, N_("do not grab keyboard and mouse")},
   { oLogFile, "log-file"   ,2, N_("use a log file for the server")},
-  { oDisablePth, "disable-pth", 0, N_("do not allow multiple connections")},
   { oUseStandardSocket, "use-standard-socket", 0,
                       N_("use a standard location for the socket")},
   { oNoUseStandardSocket, "no-use-standard-socket", 0, "@"},
@@ -128,6 +130,7 @@ static ARGPARSE_OPTS opts[] = {
                                N_("|PGM|use PGM as the PIN-Entry program") },
   { oScdaemonProgram, "scdaemon-program", 2 ,
                                N_("|PGM|use PGM as the SCdaemon program") },
+  { oDisableScdaemon, "disable-scdaemon", 0, N_("do not use the SCdaemon") },
 
   { oDisplay,    "display",     2, "@" },
   { oTTYname,    "ttyname",     2, "@" },
@@ -140,7 +143,9 @@ static ARGPARSE_OPTS opts[] = {
 
   { oDefCacheTTL, "default-cache-ttl", 4,
                                N_("|N|expire cached PINs after N seconds")},
+  { oDefCacheTTLSSH, "default-cache-ttl-ssh", 4, "@" },
   { oMaxCacheTTL, "max-cache-ttl", 4, "@" },
+  { oMaxCacheTTLSSH, "max-cache-ttl-ssh", 4, "@" },
   { oIgnoreCacheForSigning, "ignore-cache-for-signing", 0,
                                N_("do not use the PIN cache when signing")},
   { oAllowMarkTrusted, "allow-mark-trusted", 0,
@@ -148,14 +153,16 @@ static ARGPARSE_OPTS opts[] = {
   { oAllowPresetPassphrase, "allow-preset-passphrase", 0,
                              N_("allow presetting passphrase")},
   { oSSHSupport, "enable-ssh-support", 0, N_("enable ssh-agent emulation") },
+  { oWriteEnvFile, "write-env-file", 2|8,
+            N_("|FILE|write environment settings also to FILE")},
   {0}
 };
 
 
-#define DEFAULT_CACHE_TTL (10*60)  /* 10 minutes */
-#define MAX_CACHE_TTL     (120*60) /* 2 hours */
+#define DEFAULT_CACHE_TTL     (10*60)  /* 10 minutes */
+#define DEFAULT_CACHE_TTL_SSH (30*60)  /* 30 minutes */
+#define MAX_CACHE_TTL         (120*60) /* 2 hours */
 
-static volatile int caught_fatal_sig = 0;
 
 /* flag to indicate that a shutdown was requested */
 static int shutdown_pending;
@@ -187,6 +194,12 @@ static const char *debug_level;
    the log file after a SIGHUP if it didn't changed. Malloced. */
 static char *current_logfile;
 
+/* The handle_tick() function may test whether a parent is still
+   running.  We record the PID of the parent here or -1 if it should be
+   watched. */
+static pid_t parent_pid = (pid_t)(-1);
+
+\f
 /*
    Local prototypes. 
  */
@@ -196,17 +209,15 @@ static char *create_socket_name (int use_standard_socket,
 static int create_server_socket (int is_standard_name, const char *name);
 static void create_directories (void);
 
-#ifdef USE_GNU_PTH
 static void handle_connections (int listen_fd, int listen_fd_ssh);
-/* Pth wrapper function definitions. */
-GCRY_THREAD_OPTION_PTH_IMPL;
-#endif /*USE_GNU_PTH*/
-
 static int check_for_running_agent (int);
 
+/* Pth wrapper function definitions. */
+GCRY_THREAD_OPTION_PTH_IMPL;
 
 
 
+\f
 /*
    Functions. 
  */
@@ -344,28 +355,6 @@ cleanup (void)
 }
 
 
-static RETSIGTYPE
-cleanup_sh (int sig)
-{
-  if (caught_fatal_sig)
-    raise (sig);
-  caught_fatal_sig = 1;
-
-  /* gcry_control( GCRYCTL_TERM_SECMEM );*/
-  cleanup ();
-
-#ifndef HAVE_DOSISH_SYSTEM
-  {    /* reset action to default action and raise signal again */
-    struct sigaction nact;
-    nact.sa_handler = SIG_DFL;
-    sigemptyset( &nact.sa_mask );
-    nact.sa_flags = 0;
-    sigaction( sig, &nact, NULL);
-  }
-#endif
-  raise( sig );
-}
-
 
 /* Handle options which are allowed to be reset after program start.
    Return true when the current option in PARGS could be handled and
@@ -384,9 +373,12 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       opt.pinentry_program = NULL;
       opt.scdaemon_program = NULL;
       opt.def_cache_ttl = DEFAULT_CACHE_TTL;
+      opt.def_cache_ttl_ssh = DEFAULT_CACHE_TTL_SSH;
       opt.max_cache_ttl = MAX_CACHE_TTL;
+      opt.max_cache_ttl_ssh = MAX_CACHE_TTL;
       opt.ignore_cache_for_signing = 0;
       opt.allow_mark_trusted = 0;
+      opt.disable_scdaemon = 0;
       return 1;
     }
 
@@ -415,9 +407,12 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       
     case oPinentryProgram: opt.pinentry_program = pargs->r.ret_str; break;
     case oScdaemonProgram: opt.scdaemon_program = pargs->r.ret_str; break;
+    case oDisableScdaemon: opt.disable_scdaemon = 1; break;
 
     case oDefCacheTTL: opt.def_cache_ttl = pargs->r.ret_ulong; break;
+    case oDefCacheTTLSSH: opt.def_cache_ttl_ssh = pargs->r.ret_ulong; break;
     case oMaxCacheTTL: opt.max_cache_ttl = pargs->r.ret_ulong; break;
+    case oMaxCacheTTLSSH: opt.max_cache_ttl_ssh = pargs->r.ret_ulong; break;
       
     case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
 
@@ -428,6 +423,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
     default:
       return 0; /* not handled */
     }
+
   return 1; /* handled */
 }
 
@@ -453,10 +449,10 @@ main (int argc, char **argv )
   int csh_style = 0;
   char *logfile = NULL;
   int debug_wait = 0;
-  int disable_pth = 0;
   int gpgconf_list = 0;
   int standard_socket = 0;
   gpg_error_t err;
+  const char *env_file_name = NULL;
 
   set_strusage (my_strusage);
   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
@@ -472,14 +468,12 @@ main (int argc, char **argv )
 
   /* Libgcrypt requires us to register the threading model first.
      Note that this will also do the pth_init. */
-#ifdef USE_GNU_PTH
   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));
     }
-#endif /*USE_GNU_PTH*/
 
 
   /* Check that the libraries are suitable.  Do it here because
@@ -512,7 +506,7 @@ main (int argc, char **argv )
 
   opt.homedir = default_homedir ();
 
-  /* Record the some original Denvironment settings. */
+  /* Record some of the original environment strings. */
   opt.startup_display = getenv ("DISPLAY");
   if (opt.startup_display)
     opt.startup_display = xstrdup (opt.startup_display);
@@ -522,7 +516,7 @@ main (int argc, char **argv )
   opt.startup_ttytype = getenv ("TERM");
   if (opt.startup_ttytype)
     opt.startup_ttytype = xstrdup (opt.startup_ttytype);
-  /* Fixme: Neen to use the locale fucntion here.  */
+  /* Fixme: Better use the locale function here.  */
   opt.startup_lc_ctype = getenv ("LC_CTYPE");
   if (opt.startup_lc_ctype) 
     opt.startup_lc_ctype = xstrdup (opt.startup_lc_ctype);
@@ -625,7 +619,6 @@ main (int argc, char **argv )
         case oSh: csh_style = 0; break;
         case oServer: pipe_server = 1; break;
         case oDaemon: is_daemon = 1; break;
-        case oDisablePth: disable_pth = 1; break;
 
         case oDisplay: default_display = xstrdup (pargs.r.ret_str); break;
         case oTTYname: default_ttyname = xstrdup (pargs.r.ret_str); break;
@@ -641,6 +634,12 @@ main (int argc, char **argv )
         case oKeepDISPLAY: opt.keep_display = 1; break;
 
        case oSSHSupport:  opt.ssh_support = 1; break;
+        case oWriteEnvFile:
+          if (pargs.r_type)
+            env_file_name = pargs.r.ret_str;
+          else
+            env_file_name = make_filename ("~/.gpg-agent-info", NULL);
+          break;
 
         default : pargs.err = configfp? 1:2; break;
        }
@@ -740,6 +739,8 @@ main (int argc, char **argv )
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
       printf ("allow-mark-trusted:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
+      printf ("disable-scdaemon:%lu:\n",
+              GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
 
       agent_exit (0);
     }
@@ -797,9 +798,11 @@ main (int argc, char **argv )
       /* Remove the DISPLAY variable so that a pinentry does not
          default to a specific display.  There is still a default
          display when gpg-agent was started using --display or a
-         client requested this using an OPTION command. */
+         client requested this using an OPTION command.  Note, that we
+         don't do this when running in reverse daemon mode (i.e. when
+         exec the program given as arguments). */
 #ifndef HAVE_W32_SYSTEM
-      if (!opt.keep_display)
+      if (!opt.keep_display && !argc)
         unsetenv ("DISPLAY");
 #endif
 
@@ -819,6 +822,11 @@ main (int argc, char **argv )
       else
        fd_ssh = -1;
 
+      /* If we are going to exec a program in the parent, we record
+         the PID, so that the child may check whether the program is
+         still alive. */
+      if (argc)
+        parent_pid = getpid ();
 
       fflush (NULL);
 #ifdef HAVE_W32_SYSTEM
@@ -868,6 +876,29 @@ main (int argc, char **argv )
          if (opt.ssh_support)
            *socket_name_ssh = 0;
 
+          if (env_file_name)
+            {
+              FILE *fp;
+              
+              fp = fopen (env_file_name, "w");
+              if (!fp)
+                log_error (_("error creating `%s': %s\n"),
+                             env_file_name, strerror (errno));
+              else
+                {
+                  fputs (infostr, fp);
+                  putc ('\n', fp);
+                  if (opt.ssh_support)
+                    {
+                      fputs (infostr_ssh_sock, fp);
+                      putc ('\n', fp);
+                      fputs (infostr_ssh_pid, fp);
+                      putc ('\n', fp);
+                    }
+                  fclose (fp);
+                }
+            }
+
 
           if (argc) 
             { /* Run the program given on the commandline.  */
@@ -878,14 +909,14 @@ main (int argc, char **argv )
                   kill (pid, SIGTERM );
                   exit (1);
                 }
-              if (putenv (infostr_ssh_sock))
+              if (opt.ssh_support && putenv (infostr_ssh_sock))
                 {
                   log_error ("failed to set environment: %s\n",
                              strerror (errno) );
                   kill (pid, SIGTERM );
                   exit (1);
                 }
-              if (putenv (infostr_ssh_pid))
+              if (opt.ssh_support && putenv (infostr_ssh_pid))
                 {
                   log_error ("failed to set environment: %s\n",
                              strerror (errno) );
@@ -922,8 +953,7 @@ main (int argc, char **argv )
                      printf ("%s; export SSH_AGENT_PID;\n", infostr_ssh_pid);
                    }
                 }
-              /* Note: teh standard free is here correct.  */
-              free (infostr);
+              free (infostr); /* (Note that a vanilla free is here correct.) */
              if (opt.ssh_support)
                {
                  free (infostr_ssh_sock);
@@ -968,45 +998,17 @@ main (int argc, char **argv )
           exit (1);
         }
 
+      {
+        struct sigaction sa;
+        
+        sa.sa_handler = SIG_IGN;
+        sigemptyset (&sa.sa_mask);
+        sa.sa_flags = 0;
+        sigaction (SIGPIPE, &sa, NULL);
+      }
 #endif /*!HAVE_W32_SYSTEM*/
 
-
-#ifdef USE_GNU_PTH
-      if (!disable_pth)
-        {
-#ifndef HAVE_W32_SYSTEM  /* FIXME */
-         struct sigaction sa;
-
-         sa.sa_handler = SIG_IGN;
-         sigemptyset (&sa.sa_mask);
-         sa.sa_flags = 0;
-         sigaction (SIGPIPE, &sa, NULL);
-#endif
-          handle_connections (fd, opt.ssh_support ? fd_ssh : -1);
-        }
-      else
-#endif /*!USE_GNU_PTH*/
-      /* setup signals */
-        {
-#ifndef HAVE_W32_SYSTEM  /* FIXME */
-          struct sigaction oact, nact;
-          
-          nact.sa_handler = cleanup_sh;
-          sigemptyset (&nact.sa_mask);
-          nact.sa_flags = 0;
-          
-          sigaction (SIGHUP, NULL, &oact);
-          if (oact.sa_handler != SIG_IGN)
-            sigaction (SIGHUP, &nact, NULL);
-          sigaction( SIGTERM, NULL, &oact );
-          if (oact.sa_handler != SIG_IGN)
-            sigaction (SIGTERM, &nact, NULL);
-          nact.sa_handler = SIG_IGN;
-          sigaction (SIGPIPE, &nact, NULL);
-          sigaction (SIGINT, &nact, NULL);
-#endif
-          start_command_handler (fd, -1);
-        }
+      handle_connections (fd, opt.ssh_support ? fd_ssh : -1);
       close (fd);
     }
   
@@ -1112,7 +1114,7 @@ reread_configuration (void)
 
 
 /* Create a name for the socket.  With USE_STANDARD_SOCKET given as
-   true ising STANDARD_NAME in the home directory or if given has
+   true using STANDARD_NAME in the home directory or if given has
    false from the mkdir type name TEMPLATE.  In the latter case a
    unique name in a unique new directory will be created.  In both
    cases check for valid characters as well as against a maximum
@@ -1180,7 +1182,7 @@ create_server_socket (int is_standard_name, const char *name)
       agent_exit (2);
     }
 
-  serv_addr = malloc (sizeof (*serv_addr)); /* FIXME. */
+  serv_addr = xmalloc (sizeof (*serv_addr)); 
   memset (serv_addr, 0, sizeof *serv_addr);
   serv_addr->sun_family = AF_UNIX;
   assert (strlen (name) + 1 < sizeof (serv_addr->sun_path));
@@ -1310,7 +1312,32 @@ create_directories (void)
 
 
 
-#ifdef USE_GNU_PTH
+/* This is the worker for the ticker.  It is called every few seconds
+   and may only do fast operations. */
+static void
+handle_tick (void)
+{
+  /* Check whether the scdaemon has died and cleanup in this case. */
+  agent_scd_check_aliveness ();
+
+  /* If we are running as a child of another process, check whether
+     the parent is still alive and shutdown if not. */
+#ifndef HAVE_W32_SYSTEM
+  if (parent_pid != (pid_t)(-1))
+    {
+      if (kill (parent_pid, 0))
+        {
+          shutdown_pending = 2;
+          log_info ("parent process died - shutting down\n");
+          log_info ("%s %s stopped\n", strusage(11), strusage(13) );
+          cleanup ();
+          agent_exit (0);
+        }
+    }
+#endif /*HAVE_W32_SYSTEM*/
+}
+
+
 static void
 handle_signal (int signo)
 {
@@ -1326,7 +1353,10 @@ handle_signal (int signo)
       break;
       
     case SIGUSR1:
-      log_info ("SIGUSR1 received - no action defined\n");
+      log_info ("SIGUSR1 received - printing internal information:\n");
+      pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ());
+      agent_query_dump_state ();
+      agent_scd_dump_state ();
       break;
       
     case SIGUSR2:
@@ -1369,7 +1399,8 @@ start_connection_thread (void *arg)
   int fd = (int)arg;
 
   if (opt.verbose)
-    log_info (_("handler for fd %d started\n"), fd);
+    log_info (_("handler 0x%lx for fd %d started\n"), 
+              (long)pth_self (), fd);
 
   /* FIXME: Move this housekeeping into a ticker function.  Calling it
      for each connection should work but won't work anymore if our
@@ -1378,7 +1409,8 @@ start_connection_thread (void *arg)
 
   start_command_handler (-1, fd);
   if (opt.verbose)
-    log_info (_("handler for fd %d terminated\n"), fd);
+    log_info (_("handler 0x%lx for fd %d terminated\n"), 
+              (long)pth_self (), fd);
   
   return NULL;
 }
@@ -1391,13 +1423,15 @@ start_connection_thread_ssh (void *arg)
   int fd = (int)arg;
 
   if (opt.verbose)
-    log_info (_("ssh handler for fd %d started\n"), fd);
+    log_info (_("ssh handler 0x%lx for fd %d started\n"),
+              (long)pth_self (), fd);
 
   agent_trustlist_housekeeping ();
 
   start_command_handler_ssh (fd);
   if (opt.verbose)
-    log_info (_("ssh handler for fd %d terminated\n"), fd);
+    log_info (_("ssh handler 0x%lx for fd %d terminated\n"),
+              (long)pth_self (), fd);
   
   return NULL;
 }
@@ -1409,7 +1443,7 @@ static void
 handle_connections (int listen_fd, int listen_fd_ssh)
 {
   pth_attr_t tattr;
-  pth_event_t ev;
+  pth_event_t ev, time_ev;
   sigset_t sigs;
   int signo;
   struct sockaddr_un paddr;
@@ -1421,19 +1455,22 @@ handle_connections (int listen_fd, int listen_fd_ssh)
   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, "gpg-agent");
 
 #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. */
   sigemptyset (&sigs );
   sigaddset (&sigs, SIGHUP);
   sigaddset (&sigs, SIGUSR1);
   sigaddset (&sigs, SIGUSR2);
   sigaddset (&sigs, SIGINT);
   sigaddset (&sigs, SIGTERM);
+  pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
   ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
 #else
   ev = NULL;
 #endif
+  time_ev = NULL;
 
   FD_ZERO (&fdset);
   FD_SET (listen_fd, &fdset);
@@ -1442,6 +1479,8 @@ handle_connections (int listen_fd, int listen_fd_ssh)
 
   for (;;)
     {
+      sigset_t oldsigs;
+
       if (shutdown_pending)
         {
           if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1)
@@ -1456,16 +1495,33 @@ handle_connections (int listen_fd, int listen_fd_ssh)
           continue;
        }
 
+      /* Create a timeout event if needed. */
+      if (!time_ev)
+        time_ev = pth_event (PTH_EVENT_TIME, pth_timeout (2, 0));
+
       /* 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 (FD_SETSIZE, &read_fdset, NULL, NULL, NULL, ev);
+      if (time_ev)
+        pth_event_isolate (time_ev);
+
       if (ret == -1)
        {
-          if (pth_event_occurred (ev))
+          if (pth_event_occurred (ev)
+              || (time_ev && pth_event_occurred (time_ev)))
             {
-              handle_signal (signo);
+              if (pth_event_occurred (ev))
+                handle_signal (signo);
+              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"),
@@ -1479,6 +1535,19 @@ handle_connections (int listen_fd, int listen_fd_ssh)
           handle_signal (signo);
         }
 
+      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 - we are handling here - to be delivered to a new
+         thread. Thus we need to block those signals. */
+      pth_sigmask (SIG_BLOCK, &sigs, &oldsigs);
+
       if (FD_ISSET (listen_fd, &read_fdset))
        {
           plen = sizeof paddr;
@@ -1487,12 +1556,20 @@ handle_connections (int listen_fd, int listen_fd_ssh)
            {
              log_error ("accept failed: %s\n", strerror (errno));
            }
-          else if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
-           {
-             log_error ("error spawning connection handler: %s\n",
-                        strerror (errno) );
-             close (fd);
-           }
+          else 
+            {
+              char threadname[50];
+              snprintf (threadname, sizeof threadname-1,
+                        "conn fd=%d (gpg)", fd);
+              threadname[sizeof threadname -1] = 0;
+              pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
+              if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
+                {
+                  log_error ("error spawning connection handler: %s\n",
+                             strerror (errno) );
+                  close (fd);
+                }
+            }
           fd = -1;
        }
 
@@ -1504,21 +1581,35 @@ handle_connections (int listen_fd, int listen_fd_ssh)
            {
              log_error ("accept failed for ssh: %s\n", strerror (errno));
            }
-          else if (!pth_spawn (tattr, start_connection_thread_ssh, (void*)fd))
-           {
-             log_error ("error spawning ssh connection handler: %s\n",
-                        strerror (errno) );
-             close (fd);
-           }
+          else
+            {
+              char threadname[50];
+              snprintf (threadname, sizeof threadname-1,
+                        "conn fd=%d (ssh)", fd);
+              threadname[sizeof threadname -1] = 0;
+              pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
+
+              if (!pth_spawn (tattr, start_connection_thread_ssh, (void*)fd))
+                {
+                  log_error ("error spawning ssh connection handler: %s\n",
+                             strerror (errno) );
+                  close (fd);
+                }
+            }
           fd = -1;
        }
+
+      /* Restore the signal mask. */
+      pth_sigmask (SIG_SETMASK, &oldsigs, NULL);
+
     }
 
   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));
 }
-#endif /*USE_GNU_PTH*/
 
 
 /* Figure out whether an agent is available and running. Prints an