Allow decryption with card keys > 3072 bits
[gnupg.git] / agent / gpg-agent.c
index 89027b5..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
 #include "gc-opt-flags.h"
 #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 
+
+enum cmd_and_opt_values
 { aNull = 0,
   oCsh           = 'c',
   oQuiet         = 'q',
@@ -99,12 +102,12 @@ enum cmd_and_opt_values
   oEnablePassphraseHistory,
   oUseStandardSocket,
   oNoUseStandardSocket,
-  oStandardSocketP,
   oFakedSystemTime,
 
   oIgnoreCacheForSigning,
   oAllowMarkTrusted,
   oAllowPresetPassphrase,
+  oAllowLoopbackPinentry,
   oKeepTTY,
   oKeepDISPLAY,
   oSSHSupport,
@@ -118,8 +121,8 @@ static ARGPARSE_OPTS opts[] = {
 
   { aGPGConfList, "gpgconf-list", 256, "@" },
   { aGPGConfTest, "gpgconf-test", 256, "@" },
-  { aUseStandardSocketP, "use-standard-socket-p", 256, "@" }, 
-  
+  { aUseStandardSocketP, "use-standard-socket-p", 256, "@" },
+
   { 301, NULL, 0, N_("@Options:\n ") },
 
   { oServer,   "server",     0, N_("run in server mode (foreground)") },
@@ -148,7 +151,7 @@ static ARGPARSE_OPTS opts[] = {
   { oFakedSystemTime, "faked-system-time", 2, "@" }, /* (epoch time) */
 
   { oBatch,      "batch",       0, "@" },
-  { oHomedir,    "homedir",     2, "@"},   
+  { oHomedir,    "homedir",     2, "@"},
 
   { oDisplay,    "display",     2, "@" },
   { oTTYname,    "ttyname",     2, "@" },
@@ -179,6 +182,8 @@ static ARGPARSE_OPTS opts[] = {
                              N_("allow clients to mark keys as \"trusted\"")},
   { oAllowPresetPassphrase, "allow-preset-passphrase", 0,
                              N_("allow presetting passphrase")},
+  { oAllowLoopbackPinentry, "allow-loopback-pinentry", 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")},
@@ -190,17 +195,24 @@ static ARGPARSE_OPTS opts[] = {
 #define DEFAULT_CACHE_TTL_SSH (30*60)  /* 30 minutes */
 #define MAX_CACHE_TTL         (120*60) /* 2 hours */
 #define MAX_CACHE_TTL_SSH     (120*60) /* 2 hours */
-#define MIN_PASSPHRASE_LEN    (8)      
-#define MIN_PASSPHRASE_NONALPHA (1)      
+#define MIN_PASSPHRASE_LEN    (8)
+#define MIN_PASSPHRASE_NONALPHA (1)
 #define MAX_PASSPHRASE_DAYS   (0)
 
 /* The timer tick used for housekeeping stuff.  For Windows we use a
    longer period as the SetWaitableTimer seems to signal earlier than
-   the 2 seconds.  */
-#ifdef HAVE_W32_SYSTEM
-#define TIMERTICK_INTERVAL    (4)
+   the 2 seconds.  CHECK_OWN_SOCKET_INTERVAL defines how often we
+   check our own socket in standard socket mode.  If that value is 0
+   we don't check at all.   All values are in seconds. */
+#if defined(HAVE_W32CE_SYSTEM)
+# define TIMERTICK_INTERVAL         (60)
+# define CHECK_OWN_SOCKET_INTERVAL   (0)  /* Never */
+#elif defined(HAVE_W32_SYSTEM)
+# define TIMERTICK_INTERVAL          (4)
+# define CHECK_OWN_SOCKET_INTERVAL  (60)
 #else
-#define TIMERTICK_INTERVAL    (2)    /* Seconds.  */
+# define TIMERTICK_INTERVAL          (2)
+# define CHECK_OWN_SOCKET_INTERVAL  (60)
 #endif
 
 
@@ -220,9 +232,6 @@ static int shutdown_pending;
 /* Counter for the currently running own socket checks.  */
 static int check_own_socket_running;
 
-/* True if we are listening on the standard socket.  */
-static int use_standard_socket;
-
 /* It is possible that we are currently running under setuid permissions */
 static int maybe_setuid = 1;
 
@@ -261,13 +270,16 @@ static char *current_logfile;
    watched. */
 static pid_t parent_pid = (pid_t)(-1);
 
+/* Number of active connections.  */
+static int active_connections;
+
 \f
 /*
-   Local prototypes. 
+   Local prototypes.
  */
 
 static char *create_socket_name (char *standard_name, char *template);
-static gnupg_fd_t create_server_socket (char *name, int is_ssh, 
+static gnupg_fd_t create_server_socket (char *name, int is_ssh,
                                         assuan_sock_nonce_t *nonce);
 static void create_directories (void);
 
@@ -280,34 +292,22 @@ 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. 
+   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*))
 {
   const char *s;
   char *result;
-  
+
   if (maybe_setuid)
     {
       gcry_control (GCRYCTL_INIT_SECMEM, 0, 0);  /* Drop setuid. */
@@ -319,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)
 {
@@ -349,7 +351,7 @@ my_strusage (int level)
     case 41: p =  _("Syntax: gpg-agent [options] [command [args]]\n"
                     "Secret key management for GnuPG\n");
     break;
-    
+
     default: p = NULL;
     }
   return p;
@@ -386,13 +388,13 @@ set_debug (void)
       /* Unless the "guru" string has been used we don't want to allow
          hashing debugging.  The rationale is that people tend to
          select the highest debug value and would then clutter their
-         disk with debug files which may reveal confidential data.  */ 
+         disk with debug files which may reveal confidential data.  */
       if (numok)
         opt.debug &= ~(DBG_HASHING_VALUE);
     }
   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. */
     }
@@ -410,16 +412,16 @@ set_debug (void)
 
   if (opt.debug)
     log_info ("enabled debug flags:%s%s%s%s%s%s%s%s\n",
-              (opt.debug & DBG_COMMAND_VALUE)? " command":"",    
-              (opt.debug & DBG_MPI_VALUE    )? " mpi":"",    
-              (opt.debug & DBG_CRYPTO_VALUE )? " crypto":"",    
-              (opt.debug & DBG_MEMORY_VALUE )? " memory":"", 
-              (opt.debug & DBG_CACHE_VALUE  )? " cache":"", 
-              (opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"", 
-              (opt.debug & DBG_HASHING_VALUE)? " hashing":"", 
+              (opt.debug & DBG_COMMAND_VALUE)? " command":"",
+              (opt.debug & DBG_MPI_VALUE    )? " mpi":"",
+              (opt.debug & DBG_CRYPTO_VALUE )? " crypto":"",
+              (opt.debug & DBG_MEMORY_VALUE )? " memory":"",
+              (opt.debug & DBG_CACHE_VALUE  )? " cache":"",
+              (opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"",
+              (opt.debug & DBG_HASHING_VALUE)? " hashing":"",
               (opt.debug & DBG_ASSUAN_VALUE )? " assuan":"");
 }
+
 
 /* Helper for cleanup to remove one socket with NAME.  */
 static void
@@ -439,11 +441,20 @@ remove_socket (char *name)
        }
       *name = 0;
     }
-}  
+}
+
 
+/* Cleanup code for this program.  This is either called has an atexit
+   handler or directly.  */
 static void
 cleanup (void)
 {
+  static int done;
+
+  if (done)
+    return;
+  done = 1;
+  deinitialize_module_cache ();
   remove_socket (socket_name);
   remove_socket (socket_name_ssh);
 }
@@ -505,7 +516,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       break;
 
     case oNoGrab: opt.no_grab = 1; break;
-      
+
     case oPinentryProgram: opt.pinentry_program = pargs->r.ret_str; break;
     case oPinentryTouchFile: opt.pinentry_touch_file = pargs->r.ret_str; break;
     case oScdaemonProgram: opt.scdaemon_program = pargs->r.ret_str; break;
@@ -515,19 +526,19 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
     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 oEnforcePassphraseConstraints: 
+
+    case oEnforcePassphraseConstraints:
       opt.enforce_passphrase_constraints=1;
       break;
     case oMinPassphraseLen: opt.min_passphrase_len = pargs->r.ret_ulong; break;
-    case oMinPassphraseNonalpha: 
+    case oMinPassphraseNonalpha:
       opt.min_passphrase_nonalpha = pargs->r.ret_ulong;
       break;
     case oCheckPassphrasePattern:
       opt.check_passphrase_pattern = pargs->r.ret_str;
       break;
     case oMaxPassphraseDays:
-      opt.max_passphrase_days = pargs->r.ret_ulong; 
+      opt.max_passphrase_days = pargs->r.ret_ulong;
       break;
     case oEnablePassphraseHistory:
       opt.enable_passhrase_history = 1;
@@ -539,6 +550,8 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
 
     case oAllowPresetPassphrase: opt.allow_preset_passphrase = 1; break;
 
+    case oAllowLoopbackPinentry: opt.allow_loopback_pinentry = 1; break;
+
     default:
       return 0; /* not handled */
     }
@@ -553,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;
@@ -589,23 +601,13 @@ main (int argc, char **argv )
   /* Please note that we may running SUID(ROOT), so be very CAREFUL
      when adding any stuff between here and the call to INIT_SECMEM()
      somewhere after the option parsing */
-  log_set_prefix ("gpg-agent", JNLIB_LOG_WITH_PREFIX|JNLIB_LOG_WITH_PID); 
+  log_set_prefix ("gpg-agent", JNLIB_LOG_WITH_PREFIX|JNLIB_LOG_WITH_PID);
 
   /* Make sure that our subsystems are ready.  */
   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. */
@@ -620,22 +622,21 @@ 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. */
-#ifdef HAVE_W32_SYSTEM
-  use_standard_socket = 1;  /* Under Windows we always use a standard
-                               socket.  */
+#ifdef USE_STANDARD_SOCKET
+  opt.use_standard_socket = 1;
 #endif
-  
+
   shell = getenv ("SHELL");
   if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
     csh_style = 1;
@@ -646,7 +647,7 @@ main (int argc, char **argv )
   {
     const char *s;
     int idx;
-    static const char *names[] = 
+    static const char *names[] =
       { "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL };
 
     err = 0;
@@ -668,10 +669,10 @@ main (int argc, char **argv )
     if (err)
       log_fatal ("error recording startup environment: %s\n",
                  gpg_strerror (err));
-    
+
     /* Fixme: Better use the locale function here.  */
     opt.startup_lc_ctype = getenv ("LC_CTYPE");
-    if (opt.startup_lc_ctype) 
+    if (opt.startup_lc_ctype)
       opt.startup_lc_ctype = xstrdup (opt.startup_lc_ctype);
     opt.startup_lc_messages = getenv ("LC_MESSAGES");
     if (opt.startup_lc_messages)
@@ -704,13 +705,13 @@ main (int argc, char **argv )
   gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
   maybe_setuid = 0;
 
-  /* 
-     Now we are now working under our real uid 
+  /*
+     Now we are now working under our real uid
   */
 
   if (default_config)
     configname = make_filename (opt.homedir, "gpg-agent.conf", NULL );
-  
+
   argc = orig_argc;
   argv = orig_argv;
   pargs.argc = &argc;
@@ -726,20 +727,26 @@ 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
+                 config file has been created in the meantime.  */
+              xfree (config_filename);
+              config_filename = configname;
+              configname = NULL;
            }
           else
             {
-              log_error (_("option file `%s': %s\n"),
+              log_error (_("option file '%s': %s\n"),
                          configname, strerror(errno) );
               exit(2);
            }
-          xfree (configname); 
+          xfree (configname);
           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;
     }
 
@@ -781,15 +788,16 @@ 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;
 
-        case oUseStandardSocket: use_standard_socket = 1; break;
-        case oNoUseStandardSocket: use_standard_socket = 0; break;
+        case oUseStandardSocket:   opt.use_standard_socket = 1; break;
+        case oNoUseStandardSocket: opt.use_standard_socket = 0; break;
 
         case oFakedSystemTime:
           {
-            time_t faked_time = isotime2epoch (pargs.r.ret_str); 
+            time_t faked_time = isotime2epoch (pargs.r.ret_str);
             if (faked_time == (time_t)(-1))
               faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
             gnupg_set_time (faked_time, 0);
@@ -815,10 +823,15 @@ main (int argc, char **argv )
       fclose( configfp );
       configfp = NULL;
       /* Keep a copy of the name so that it can be read on SIGHUP. */
-      config_filename = configname;
+      if (config_filename != configname)
+        {
+          xfree (config_filename);
+          config_filename = configname;
+        }
       configname = NULL;
       goto next_pass;
     }
+
   xfree (configname);
   configname = NULL;
   if (log_get_errorcount(0))
@@ -828,9 +841,9 @@ main (int argc, char **argv )
 
   if (greeting)
     {
-      fprintf (stderr, "%s %s; %s\n",
-                 strusage(11), strusage(13), strusage(14) );
-      fprintf (stderr, "%s\n", strusage(15) );
+      es_fprintf (es_stderr, "%s %s; %s\n",
+                  strusage(11), strusage(13), strusage(14) );
+      es_fprintf (es_stderr, "%s\n", strusage(15) );
     }
 #ifdef IS_DEVELOPMENT_VERSION
   /* We don't want to print it here because gpg-agent is useful of its
@@ -838,8 +851,41 @@ 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
+     always encoded in utf-8.  We switch here to utf-8, so that
+     commands like --help still give native messages.  It is far
+     easier to switch only once instead of for every message and it
+     actually helps when more then one thread is active (avoids an
+     extra copy step). */
+    bind_textdomain_codeset (PACKAGE_GT, "UTF-8");
+#endif
+
+  if (!pipe_server && !is_daemon && !gpgconf_list)
+    {
+     /* We have been called without any options and thus we merely
+        check whether an agent is already running.  We do this right
+        here so that we don't clobber a logfile with this check but
+        print the status directly to stderr. */
+      opt.debug = 0;
+      set_debug ();
+      check_for_running_agent (0, 0);
+      agent_exit (0);
+    }
+
   set_debug ();
-  
+
   if (atexit (cleanup))
     {
       log_error ("atexit failed\n");
@@ -847,10 +893,11 @@ main (int argc, char **argv )
       exit (1);
     }
 
+  initialize_module_cache ();
   initialize_module_call_pinentry ();
   initialize_module_call_scd ();
   initialize_module_trustlist ();
-  
+
   /* Try to create missing directories. */
   create_directories ();
 
@@ -861,9 +908,13 @@ main (int argc, char **argv )
       gnupg_sleep (debug_wait);
       log_debug ("... okay\n");
     }
-  
+
   if (gpgconf_list == 3)
-    agent_exit (!use_standard_socket);
+    {
+      if (opt.use_standard_socket && !opt.quiet)
+        log_info ("configured to use the standard socket\n");
+      agent_exit (!opt.use_standard_socket);
+    }
   else if (gpgconf_list == 2)
     agent_exit (0);
   else if (gpgconf_list)
@@ -875,12 +926,12 @@ main (int argc, char **argv )
       filename = make_filename (opt.homedir, "gpg-agent.conf", NULL );
       filename_esc = percent_escape (filename, NULL);
 
-      printf ("gpgconf-gpg-agent.conf:%lu:\"%s\n",
+      es_printf ("gpgconf-gpg-agent.conf:%lu:\"%s\n",
               GC_OPT_FLAG_DEFAULT, filename_esc);
       xfree (filename);
       xfree (filename_esc);
 
-      printf ("verbose:%lu:\n"
+      es_printf ("verbose:%lu:\n"
               "quiet:%lu:\n"
               "debug-level:%lu:\"none:\n"
               "log-file:%lu:\n",
@@ -888,61 +939,40 @@ main (int argc, char **argv )
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME,
               GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME,
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME );
-      printf ("default-cache-ttl:%lu:%d:\n",
+      es_printf ("default-cache-ttl:%lu:%d:\n",
               GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, DEFAULT_CACHE_TTL );
-      printf ("default-cache-ttl-ssh:%lu:%d:\n",
+      es_printf ("default-cache-ttl-ssh:%lu:%d:\n",
               GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, DEFAULT_CACHE_TTL_SSH );
-      printf ("max-cache-ttl:%lu:%d:\n",
+      es_printf ("max-cache-ttl:%lu:%d:\n",
               GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MAX_CACHE_TTL );
-      printf ("max-cache-ttl-ssh:%lu:%d:\n",
+      es_printf ("max-cache-ttl-ssh:%lu:%d:\n",
               GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MAX_CACHE_TTL_SSH );
-      printf ("enforce-passphrase-constraints:%lu:\n", 
+      es_printf ("enforce-passphrase-constraints:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
-      printf ("min-passphrase-len:%lu:%d:\n",
+      es_printf ("min-passphrase-len:%lu:%d:\n",
               GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MIN_PASSPHRASE_LEN );
-      printf ("min-passphrase-nonalpha:%lu:%d:\n",
-              GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, 
+      es_printf ("min-passphrase-nonalpha:%lu:%d:\n",
+              GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME,
               MIN_PASSPHRASE_NONALPHA);
-      printf ("check-passphrase-pattern:%lu:\n",
+      es_printf ("check-passphrase-pattern:%lu:\n",
               GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME);
-      printf ("max-passphrase-days:%lu:%d:\n",
-              GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, 
+      es_printf ("max-passphrase-days:%lu:%d:\n",
+              GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME,
               MAX_PASSPHRASE_DAYS);
-      printf ("enable-passphrase-history:%lu:\n", 
+      es_printf ("enable-passphrase-history:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
-      printf ("no-grab:%lu:\n", 
+      es_printf ("no-grab:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
-      printf ("ignore-cache-for-signing:%lu:\n",
+      es_printf ("ignore-cache-for-signing:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
-      printf ("allow-mark-trusted:%lu:\n",
+      es_printf ("allow-mark-trusted:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
-      printf ("disable-scdaemon:%lu:\n",
+      es_printf ("disable-scdaemon:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
 
       agent_exit (0);
     }
 
-  /* If this has been called without any options, we merely check
-     whether an agent is already running.  We do this here so that we
-     don't clobber a logfile but print it directly to stderr. */
-  if (!pipe_server && !is_daemon)
-    {
-      log_set_prefix (NULL, JNLIB_LOG_WITH_PREFIX); 
-      check_for_running_agent (0, 0);
-      agent_exit (0);
-    }
-  
-#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
-     always encoded in utf-8.  We switch here to utf-8, so that
-     commands like --help still give native messages.  It is far
-     easier to switch only once instead of for every message and it
-     actually helps when more then one thread is active (avoids an
-     extra copy step). */
-    bind_textdomain_codeset (PACKAGE_GT, "UTF-8");
-#endif
-
   /* Now start with logging to a file if this is desired. */
   if (logfile)
     {
@@ -961,7 +991,7 @@ main (int argc, char **argv )
 
 
   if (pipe_server)
-    { 
+    {
       /* This is the simple pipe based server */
       ctrl_t ctrl;
 
@@ -1006,11 +1036,11 @@ main (int argc, char **argv )
 
 
       /* Create the sockets.  */
-      socket_name = create_socket_name 
-        ("S.gpg-agent", "/tmp/gpg-XXXXXX/S.gpg-agent");
+      socket_name = create_socket_name
+        ("S.gpg-agent", "gpg-XXXXXX/S.gpg-agent");
       if (opt.ssh_support)
-       socket_name_ssh = create_socket_name 
-          ("S.gpg-agent.ssh", "/tmp/gpg-XXXXXX/S.gpg-agent.ssh");
+       socket_name_ssh = create_socket_name
+          ("S.gpg-agent.ssh", "gpg-XXXXXX/S.gpg-agent.ssh");
 
       fd = create_server_socket (socket_name, 0, &socket_nonce);
       if (opt.ssh_support)
@@ -1027,34 +1057,25 @@ main (int argc, char **argv )
       fflush (NULL);
 #ifdef HAVE_W32_SYSTEM
       pid = getpid ();
-      printf ("set GPG_AGENT_INFO=%s;%lu;1\n", socket_name, (ulong)pid);
+      es_printf ("set GPG_AGENT_INFO=%s;%lu;1\n", socket_name, (ulong)pid);
 #else /*!HAVE_W32_SYSTEM*/
       pid = fork ();
-      if (pid == (pid_t)-1) 
+      if (pid == (pid_t)-1)
         {
           log_fatal ("fork failed: %s\n", strerror (errno) );
           exit (1);
         }
-      else if (pid) 
+      else if (pid)
         { /* We are the parent */
-          char *infostr, *infostr_ssh_sock, *infostr_ssh_pid;
+          char *infostr, *infostr_ssh_sock;
 
           /* 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.  */
-          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)
             {
@@ -1064,7 +1085,7 @@ main (int argc, char **argv )
             }
           else
             log_info ("no saved signal mask\n");
-#endif /*HAVE_SIGPROCMASK*/          
+#endif /*HAVE_SIGPROCMASK*/
 
           /* Create the info string: <name>:<pid>:<protocol_version> */
           if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1",
@@ -1083,13 +1104,6 @@ main (int argc, char **argv )
                  kill (pid, SIGTERM);
                  exit (1);
                }
-             if (asprintf (&infostr_ssh_pid, "SSH_AGENT_PID=%u",
-                           pid) < 0)
-               {
-                 log_error ("out of core\n");
-                 kill (pid, SIGTERM);
-                 exit (1);
-               }
            }
 
           *socket_name = 0; /* Don't let cleanup() remove the socket -
@@ -1099,29 +1113,27 @@ main (int argc, char **argv )
 
           if (env_file_name)
             {
-              FILE *fp;
-              
-              fp = fopen (env_file_name, "w");
+              estream_t fp;
+
+              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
                 {
-                  fputs (infostr, fp);
-                  putc ('\n', fp);
+                  es_fputs (infostr, fp);
+                  es_putc ('\n', fp);
                   if (opt.ssh_support)
                     {
-                      fputs (infostr_ssh_sock, fp);
-                      putc ('\n', fp);
-                      fputs (infostr_ssh_pid, fp);
-                      putc ('\n', fp);
+                      es_fputs (infostr_ssh_sock, fp);
+                      es_putc ('\n', fp);
                     }
-                  fclose (fp);
+                  es_fclose (fp);
                 }
             }
 
 
-          if (argc) 
+          if (argc)
             { /* Run the program given on the commandline.  */
               if (putenv (infostr))
                 {
@@ -1137,13 +1149,6 @@ main (int argc, char **argv )
                   kill (pid, SIGTERM );
                   exit (1);
                 }
-              if (opt.ssh_support && putenv (infostr_ssh_pid))
-                {
-                  log_error ("failed to set environment: %s\n",
-                             strerror (errno) );
-                  kill (pid, SIGTERM );
-                  exit (1);
-                }
 
               /* Close all the file descriptors except the standard
                  ones and those open at startup.  We explicitly don't
@@ -1164,54 +1169,51 @@ main (int argc, char **argv )
               if (csh_style)
                 {
                   *strchr (infostr, '=') = ' ';
-                  printf ("setenv %s\n", infostr);
+                  es_printf ("setenv %s;\n", infostr);
                  if (opt.ssh_support)
                    {
                      *strchr (infostr_ssh_sock, '=') = ' ';
-                     printf ("setenv %s\n", infostr_ssh_sock);
-                     *strchr (infostr_ssh_pid, '=') = ' ';
-                     printf ("setenv %s\n", infostr_ssh_pid);
+                     es_printf ("setenv %s;\n", infostr_ssh_sock);
                    }
                 }
               else
                 {
-                  printf ( "%s; export GPG_AGENT_INFO;\n", infostr);
+                  es_printf ( "%s; export GPG_AGENT_INFO;\n", infostr);
                  if (opt.ssh_support)
                    {
-                     printf ("%s; export SSH_AUTH_SOCK;\n", infostr_ssh_sock);
-                     printf ("%s; export SSH_AGENT_PID;\n", infostr_ssh_pid);
+                     es_printf ("%s; export SSH_AUTH_SOCK;\n",
+                                 infostr_ssh_sock);
                    }
                 }
-              xfree (infostr); 
+              xfree (infostr);
              if (opt.ssh_support)
                {
                  xfree (infostr_ssh_sock);
-                 xfree (infostr_ssh_pid);
                }
-              exit (0); 
+              exit (0);
             }
           /*NOTREACHED*/
         } /* End parent */
 
-      /* 
+      /*
          This is the child
        */
 
       /* Detach from tty and put process into a new session */
       if (!nodetach )
-        { 
+        {
           int i;
           unsigned int oldflags;
 
           /* Close stdin, stdout and stderr unless it is the log stream */
-          for (i=0; i <= 2; i++) 
+          for (i=0; i <= 2; i++)
             {
               if (!log_test_fd (i) && i != fd )
                 {
                   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);
@@ -1238,7 +1240,7 @@ main (int argc, char **argv )
 
       {
         struct sigaction sa;
-        
+
         sa.sa_handler = SIG_IGN;
         sigemptyset (&sa.sa_mask);
         sa.sa_flags = 0;
@@ -1250,15 +1252,23 @@ main (int argc, char **argv )
       handle_connections (fd, opt.ssh_support ? fd_ssh : GNUPG_INVALID_FD);
       assuan_sock_close (fd);
     }
-  
+
   return 0;
 }
 
 
+/* Exit entry point.  This function should be called instead of a
+   plain exit.  */
 void
 agent_exit (int rc)
 {
   /*FIXME: update_random_seed_file();*/
+
+  /* We run our cleanup handler because that may close cipher contexts
+     stored in secure memory and thus this needs to be done before we
+     explicitly terminate secure memory.  */
+  cleanup ();
+
 #if 1
   /* at this time a bit annoying */
   if (opt.debug & DBG_MEMSTAT_VALUE)
@@ -1275,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)
 {
@@ -1286,19 +1301,22 @@ agent_init_default_ctrl (ctrl_t ctrl)
   session_env_setenv (ctrl->session_env, "TERM", default_ttytype);
   session_env_setenv (ctrl->session_env, "XAUTHORITY", default_xauthority);
   session_env_setenv (ctrl->session_env, "PINENTRY_USER_DATA", NULL);
-  
+
   if (ctrl->lc_ctype)
     xfree (ctrl->lc_ctype);
   ctrl->lc_ctype = default_lc_ctype? xtrystrdup (default_lc_ctype) : NULL;
-  
+
   if (ctrl->lc_messages)
     xfree (ctrl->lc_messages);
   ctrl->lc_messages = default_lc_messages? xtrystrdup (default_lc_messages)
                                     /**/ : NULL;
 
+  ctrl->cache_ttl_opt_preset = CACHE_TTL_OPT_PRESET;
 }
 
 
+/* 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)
 {
@@ -1313,7 +1331,7 @@ agent_deinit_default_ctrl (ctrl_t ctrl)
 
 /* Reread parts of the configuration.  Note, that this function is
    obviously not thread-safe and should only be called from the PTH
-   signal handler. 
+   signal handler.
 
    Fixme: Due to the way the argument parsing works, we create a
    memory leak here for all string type arguments.  There is currently
@@ -1334,8 +1352,8 @@ reread_configuration (void)
   fp = fopen (config_filename, "r");
   if (!fp)
     {
-      log_error (_("option file `%s': %s\n"),
-                 config_filename, strerror(errno) );
+      log_info (_("option file '%s': %s\n"),
+                config_filename, strerror(errno) );
       return;
     }
 
@@ -1385,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};
@@ -1403,7 +1421,7 @@ get_agent_scd_notify_event (void)
         log_error ("can't create scd notify event: %s\n", w32_strerror (-1) );
       else if (!DuplicateHandle (GetCurrentProcess(), h,
                                  GetCurrentProcess(), &h2,
-                                 EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0)) 
+                                 EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0))
         {
           log_error ("setting syncronize for scd notify event failed: %s\n",
                      w32_strerror (-1) );
@@ -1416,7 +1434,6 @@ get_agent_scd_notify_event (void)
         }
     }
 
-  log_debug  ("returning notify handle %p\n", the_event);
   return the_event;
 }
 #endif /*HAVE_W32_SYSTEM && !HAVE_W32CE_SYSTEM*/
@@ -1436,18 +1453,26 @@ create_socket_name (char *standard_name, char *template)
 {
   char *name, *p;
 
-  if (use_standard_socket)
+  if (opt.use_standard_socket)
     name = make_filename (opt.homedir, standard_name, NULL);
   else
     {
-      name = xstrdup (template);
+      /* Prepend the tmp directory to the template.  */
+      p = getenv ("TMPDIR");
+      if (!p || !*p)
+        p = "/tmp";
+      if (p[strlen (p) - 1] == '/')
+        name = xstrconcat (p, template, NULL);
+      else
+        name = xstrconcat (p, "/", template, NULL);
+
       p = strrchr (name, '/');
       if (!p)
        BUG ();
       *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);
        }
@@ -1456,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) )
@@ -1488,12 +1513,12 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
       agent_exit (2);
     }
 
-  serv_addr = xmalloc (sizeof (*serv_addr)); 
+  serv_addr = xmalloc (sizeof (*serv_addr));
   memset (serv_addr, 0, sizeof *serv_addr);
   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);
@@ -1502,7 +1527,7 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
 
   /* Our error code mapping on W32CE returns EEXIST thus we also test
      for this. */
-  if (use_standard_socket && rc == -1 
+  if (opt.use_standard_socket && rc == -1
       && (errno == EADDRINUSE
 #ifdef HAVE_W32_SYSTEM
           || errno == EEXIST
@@ -1519,6 +1544,8 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
          a hang.  */
       if (!is_ssh && !check_for_running_agent (1, 1))
         {
+          log_set_prefix (NULL, JNLIB_LOG_WITH_PREFIX);
+          log_set_file (NULL);
           log_error (_("a gpg-agent is already running - "
                        "not starting a new one\n"));
           *name = 0; /* Inhibit removal of the socket by cleanup(). */
@@ -1528,19 +1555,19 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
       gnupg_remove (name);
       rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len);
     }
-  if (rc != -1 
+  if (rc != -1
       && (rc=assuan_sock_get_nonce ((struct sockaddr*)serv_addr, len, nonce)))
     log_error (_("error getting nonce for the socket\n"));
   if (rc == -1)
     {
       /* 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"),
-                serv_addr->sun_path, 
+      log_error (_("error binding socket to '%s': %s\n"),
+                serv_addr->sun_path,
                  gpg_strerror (gpg_error_from_errno (errno)));
-      
+
       assuan_sock_close (fd);
-      if (use_standard_socket)
+      if (opt.use_standard_socket)
         *name = 0; /* Inhibit removal of the socket by cleanup(). */
       agent_exit (2);
     }
@@ -1551,9 +1578,9 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
       assuan_sock_close (fd);
       agent_exit (2);
     }
-          
+
   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;
 }
@@ -1572,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);
 }
@@ -1611,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 
+              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. */
     {
@@ -1665,13 +1692,15 @@ handle_tick (void)
         }
     }
 #endif /*HAVE_W32_SYSTEM*/
-  
-  /* Code to be run every minute.  */
-  if (last_minute + 60 <= time (NULL))
+
+  /* Code to be run from time to time.  */
+#if CHECK_OWN_SOCKET_INTERVAL > 0
+  if (last_minute + CHECK_OWN_SOCKET_INTERVAL <= time (NULL))
     {
       check_own_socket ();
       last_minute = time (NULL);
     }
+#endif
 
 }
 
@@ -1689,6 +1718,7 @@ agent_sighup_action (void)
 }
 
 
+/* A helper function to handle SIGUSR2.  */
 static void
 agent_sigusr2_action (void)
 {
@@ -1699,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)
 {
@@ -1708,7 +1741,7 @@ handle_signal (int signo)
     case SIGHUP:
       agent_sighup_action ();
       break;
-      
+
     case SIGUSR1:
       log_info ("SIGUSR1 received - printing internal information:\n");
       /* Fixme: We need to see how to integrate pth dumping into our
@@ -1717,7 +1750,7 @@ handle_signal (int signo)
       agent_query_dump_state ();
       agent_scd_dump_state ();
       break;
-      
+
     case SIGUSR2:
       agent_sigusr2_action ();
       break;
@@ -1726,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)
         {
@@ -1737,7 +1770,7 @@ handle_signal (int signo)
           agent_exit (0);
        }
       break;
-        
+
     case SIGINT:
       log_info ("SIGINT received - immediate shutdown\n");
       log_info( "%s %s stopped\n", strusage(11), strusage(13));
@@ -1749,16 +1782,16 @@ 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.  */
-static int 
+static int
 check_nonce (ctrl_t ctrl, assuan_sock_nonce_t *nonce)
 {
   if (assuan_sock_check_nonce (ctrl->thread_startup.fd, nonce))
     {
-      log_info (_("error reading nonce on fd %d: %s\n"), 
+      log_info (_("error reading nonce on fd %d: %s\n"),
                 FD2INT(ctrl->thread_startup.fd), strerror (errno));
       assuan_sock_close (ctrl->thread_startup.fd);
       xfree (ctrl);
@@ -1776,18 +1809,22 @@ start_connection_thread (void *arg)
   ctrl_t ctrl = arg;
 
   if (check_nonce (ctrl, &socket_nonce))
-    return NULL;
+    {
+      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));
+    log_info (_("handler 0x%lx for fd %d started\n"),
+              (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));
-  
+    log_info (_("handler 0x%lx for fd %d terminated\n"),
+              (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
+
   agent_deinit_default_ctrl (ctrl);
   xfree (ctrl);
   return NULL;
@@ -1806,13 +1843,13 @@ 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);
   return NULL;
@@ -1824,59 +1861,50 @@ 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.  */
+  opt.sigusr2_enabled = 1;
 
   FD_ZERO (&fdset);
   FD_SET (FD2INT (listen_fd), &fdset);
@@ -1888,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
@@ -1904,87 +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));
@@ -2002,34 +2003,33 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
               xfree (ctrl);
               assuan_sock_close (fd);
             }
-          else 
+          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;
        }
 
-      if (!shutdown_pending && listen_fd_ssh != GNUPG_INVALID_FD 
+      if (!shutdown_pending && listen_fd_ssh != GNUPG_INVALID_FD
           && FD_ISSET ( FD2INT (listen_fd_ssh), &read_fdset))
        {
           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));
@@ -2049,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);
                 }
@@ -2069,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);
 }
 
 
@@ -2115,7 +2111,7 @@ check_own_socket_thread (void *arg)
       log_error ("can't connect my own socket: %s\n", gpg_strerror (rc));
       goto leave;
     }
+
   init_membuf (&mb, 100);
   rc = assuan_transact (ctx, "GETINFO pid", check_own_socket_pid_cb, &mb,
                         NULL, NULL, NULL, NULL);
@@ -2123,7 +2119,7 @@ check_own_socket_thread (void *arg)
   buffer = get_membuf (&mb, NULL);
   if (rc || !buffer)
     {
-      log_error ("sending command \"%s\" to my own socket failed: %s\n", 
+      log_error ("sending command \"%s\" to my own socket failed: %s\n",
                  "GETINFO pid", gpg_strerror (rc));
       rc = 1;
     }
@@ -2134,7 +2130,7 @@ check_own_socket_thread (void *arg)
     }
   else if (opt.verbose > 1)
     log_error ("socket is still served by this server\n");
-    
+
   xfree (buffer);
 
  leave:
@@ -2159,15 +2155,17 @@ check_own_socket_thread (void *arg)
 
 /* Check whether we are still listening on our own socket.  In case
    another gpg-agent process started after us has taken ownership of
-   our socket, we woulf linger around without any real task.  Thus we
+   our socket, we would linger around without any real task.  Thus we
    better check once in a while whether we are really needed.  */
 static void
 check_own_socket (void)
 {
   char *sockname;
-  pth_attr_t tattr;
+  npth_t thread;
+  npth_attr_t tattr;
+  int err;
 
-  if (!use_standard_socket)
+  if (!opt.use_standard_socket)
     return; /* This check makes only sense in standard socket mode.  */
 
   if (check_own_socket_running || shutdown_pending)
@@ -2177,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);
 }
 
 
@@ -2269,3 +2266,12 @@ check_for_running_agent (int silent, int mode)
   assuan_release (ctx);
   return 0;
 }
+
+/* TODO: it is also in misc, which is not linked with the agent */
+/* FIXME: The agent should not know about openpgp internals - weel
+   except for some stuff in cvt-openpgp.  */
+int
+map_pk_openpgp_to_gcry (int algo)
+{
+  return (algo==PUBKEY_ALGO_ECDSA ? GCRY_PK_ECDSA : (algo==PUBKEY_ALGO_ECDH ? GCRY_PK_ECDH : algo));
+}