Generate the ChangeLog from commit logs.
[gnupg.git] / agent / gpg-agent.c
index 0ab3055..0616875 100644 (file)
@@ -1,6 +1,6 @@
 /* gpg-agent.c  -  The GnuPG Agent
- * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005,
- *               2006, 2007, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009,
+ *               2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 # include <sys/un.h>
 #endif /*!HAVE_W32_SYSTEM*/
 #include <unistd.h>
-#include <signal.h>
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
 #include <pth.h>
 
 #define JNLIB_NEED_LOG_LOGV
+#define JNLIB_NEED_AFLOCAL
 #include "agent.h"
 #include <assuan.h> /* Malloc hooks  and socket wrappers. */
 
 #include "i18n.h"
 #include "mkdtemp.h" /* Gnulib replacement. */
 #include "sysutils.h"
-#include "setenv.h"
 #include "gc-opt-flags.h"
+#include "exechelp.h"
+#include "asshelp.h"
+#include "../include/cipher.h" /* for PUBKEY_ALGO_ECDSA, PUBKEY_ALGO_ECDH */
 
-
-enum cmd_and_opt_values 
+enum cmd_and_opt_values
 { aNull = 0,
   oCsh           = 'c',
   oQuiet         = 'q',
@@ -59,6 +63,7 @@ enum cmd_and_opt_values
   oNoVerbose = 500,
   aGPGConfList,
   aGPGConfTest,
+  aUseStandardSocketP,
   oOptions,
   oDebug,
   oDebugAll,
@@ -100,6 +105,7 @@ enum cmd_and_opt_values
   oIgnoreCacheForSigning,
   oAllowMarkTrusted,
   oAllowPresetPassphrase,
+  oAllowLoopbackPinentry,
   oKeepTTY,
   oKeepDISPLAY,
   oSSHSupport,
@@ -113,7 +119,8 @@ static ARGPARSE_OPTS opts[] = {
 
   { aGPGConfList, "gpgconf-list", 256, "@" },
   { aGPGConfTest, "gpgconf-test", 256, "@" },
-  
+  { aUseStandardSocketP, "use-standard-socket-p", 256, "@" },
+
   { 301, NULL, 0, N_("@Options:\n ") },
 
   { oServer,   "server",     0, N_("run in server mode (foreground)") },
@@ -142,7 +149,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, "@" },
@@ -173,6 +180,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")},
@@ -184,17 +193,35 @@ 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
+
+
+/* The list of open file descriptors at startup.  Note that this list
+   has been allocated using the standard malloc.  */
+static int *startup_fd_list;
+
+/* The signal mask at startup and a flag telling whether it is valid.  */
+#ifdef HAVE_SIGPROCMASK
+static sigset_t startup_signal_mask;
+static int startup_signal_mask_valid;
 #endif
 
 /* Flag to indicate that a shutdown was requested.  */
@@ -203,9 +230,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;
 
@@ -246,11 +270,11 @@ static pid_t parent_pid = (pid_t)(-1);
 
 \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);
 
@@ -263,6 +287,8 @@ 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)
 {
@@ -280,7 +306,7 @@ static unsigned long pth_thread_id (void)
 
 \f
 /*
-   Functions. 
+   Functions.
  */
 
 static char *
@@ -288,7 +314,7 @@ 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. */
@@ -313,8 +339,11 @@ my_strusage (int level)
       break;
     case 13: p = VERSION; break;
     case 17: p = PRINTABLE_OS_NAME; break;
-    case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
-      break;
+      /* TRANSLATORS: @EMAIL@ will get replaced by the actual bug
+         reporting address.  This is so that we can change the
+         reporting address without breaking the translations.  */
+    case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
+
     case 20:
       if (!ver_gcry)
         ver_gcry = make_libversion ("libgcrypt", gcry_check_version);
@@ -327,7 +356,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;
@@ -344,19 +373,30 @@ my_strusage (int level)
 static void
 set_debug (void)
 {
+  int numok = (debug_level && digitp (debug_level));
+  int numlvl = numok? atoi (debug_level) : 0;
+
   if (!debug_level)
     ;
-  else if (!strcmp (debug_level, "none"))
+  else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
     opt.debug = 0;
-  else if (!strcmp (debug_level, "basic"))
+  else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
     opt.debug = DBG_ASSUAN_VALUE;
-  else if (!strcmp (debug_level, "advanced"))
+  else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
     opt.debug = DBG_ASSUAN_VALUE|DBG_COMMAND_VALUE;
-  else if (!strcmp (debug_level, "expert"))
+  else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
     opt.debug = (DBG_ASSUAN_VALUE|DBG_COMMAND_VALUE
                  |DBG_CACHE_VALUE);
-  else if (!strcmp (debug_level, "guru"))
-    opt.debug = ~0;
+  else if (!strcmp (debug_level, "guru") || numok)
+    {
+      opt.debug = ~0;
+      /* 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.  */
+      if (numok)
+        opt.debug &= ~(DBG_HASHING_VALUE);
+    }
   else
     {
       log_error (_("invalid debug-level `%s' given\n"), debug_level);
@@ -374,8 +414,19 @@ set_debug (void)
   if (opt.debug & DBG_CRYPTO_VALUE )
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
   gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
+
+  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_ASSUAN_VALUE )? " assuan":"");
 }
+
 
 /* Helper for cleanup to remove one socket with NAME.  */
 static void
@@ -385,7 +436,7 @@ remove_socket (char *name)
     {
       char *p;
 
-      remove (name);
+      gnupg_remove (name);
       p = strrchr (name, '/');
       if (p)
        {
@@ -395,11 +446,17 @@ remove_socket (char *name)
        }
       *name = 0;
     }
-}  
+}
 
 static void
 cleanup (void)
 {
+  static int done;
+
+  if (done)
+    return;
+  done = 1;
+  deinitialize_module_cache ();
   remove_socket (socket_name);
   remove_socket (socket_name_ssh);
 }
@@ -461,7 +518,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;
@@ -471,19 +528,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;
@@ -495,6 +552,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 */
     }
@@ -509,7 +568,6 @@ main (int argc, char **argv )
 {
   ARGPARSE_ARGS pargs;
   int orig_argc;
-  int may_coredump;
   char **orig_argv;
   FILE *configfp = NULL;
   char *configname = NULL;
@@ -528,18 +586,28 @@ main (int argc, char **argv )
   int gpgconf_list = 0;
   gpg_error_t err;
   const char *env_file_name = NULL;
-
-
+  struct assuan_malloc_hooks malloc_hooks;
+
+  /* Before we do anything else we save the list of currently open
+     file descriptors and the signal mask.  This info is required to
+     do the exec call properly. */
+  startup_fd_list = get_all_open_fds ();
+#ifdef HAVE_SIGPROCMASK
+  if (!sigprocmask (SIG_UNBLOCK, NULL, &startup_signal_mask))
+    startup_signal_mask_valid = 1;
+#endif /*HAVE_SIGPROCMASK*/
+
+  /* Set program name etc.  */
   set_strusage (my_strusage);
   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
   /* 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 ();
+  init_common_subsystems (&argc, &argv);
 
 
   /* Libgcrypt requires us to register the threading model first.
@@ -561,23 +629,26 @@ main (int argc, char **argv )
                  NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
     }
 
-  assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
-  assuan_set_assuan_log_stream (log_get_stream ());
-  assuan_set_assuan_log_prefix (log_get_prefix (NULL));
-  assuan_set_assuan_err_source (GPG_ERR_SOURCE_DEFAULT);
+  malloc_hooks.malloc = gcry_malloc;
+  malloc_hooks.realloc = gcry_realloc;
+  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_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;
@@ -585,28 +656,40 @@ main (int argc, char **argv )
   opt.homedir = default_homedir ();
 
   /* Record some of the original environment strings. */
-  opt.startup_display = getenv ("DISPLAY");
-  if (opt.startup_display)
-    opt.startup_display = xstrdup (opt.startup_display);
-  opt.startup_ttyname = ttyname (0);
-  if (opt.startup_ttyname)
-    opt.startup_ttyname = xstrdup (opt.startup_ttyname);
-  opt.startup_ttytype = getenv ("TERM");
-  if (opt.startup_ttytype)
-    opt.startup_ttytype = xstrdup (opt.startup_ttytype);
-  /* 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);
-  opt.startup_lc_messages = getenv ("LC_MESSAGES");
-  if (opt.startup_lc_messages)
-    opt.startup_lc_messages = xstrdup (opt.startup_lc_messages);
-  opt.startup_xauthority = getenv ("XAUTHORITY");
-  if (opt.startup_xauthority)
-    opt.startup_xauthority = xstrdup (opt.startup_xauthority);
-  opt.startup_pinentry_user_data = getenv ("PINENTRY_USER_DATA");
-  if (opt.startup_pinentry_user_data)
-    opt.startup_pinentry_user_data = xstrdup (opt.startup_pinentry_user_data);
+  {
+    const char *s;
+    int idx;
+    static const char *names[] =
+      { "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL };
+
+    err = 0;
+    opt.startup_env = session_env_new ();
+    if (!opt.startup_env)
+      err = gpg_error_from_syserror ();
+    for (idx=0; !err && names[idx]; idx++)
+      {
+        s = getenv (names[idx]);
+        if (s)
+          err = session_env_setenv (opt.startup_env, names[idx], s);
+      }
+    if (!err)
+      {
+        s = ttyname (0);
+        if (s)
+          err = session_env_setenv (opt.startup_env, "GPG_TTY", s);
+      }
+    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)
+      opt.startup_lc_ctype = xstrdup (opt.startup_lc_ctype);
+    opt.startup_lc_messages = getenv ("LC_MESSAGES");
+    if (opt.startup_lc_messages)
+      opt.startup_lc_messages = xstrdup (opt.startup_lc_messages);
+  }
 
   /* Check whether we have a config file on the commandline */
   orig_argc = argc;
@@ -634,13 +717,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;
@@ -658,6 +741,12 @@ main (int argc, char **argv )
               if( parse_debug )
                 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
             {
@@ -665,7 +754,7 @@ main (int argc, char **argv )
                          configname, strerror(errno) );
               exit(2);
            }
-          xfree (configname); 
+          xfree (configname);
           configname = NULL;
        }
       if (parse_debug && configname )
@@ -681,6 +770,7 @@ main (int argc, char **argv )
         {
         case aGPGConfList: gpgconf_list = 1; break;
         case aGPGConfTest: gpgconf_list = 2; break;
+        case aUseStandardSocketP: gpgconf_list = 3; break;
         case oBatch: opt.batch=1; break;
 
         case oDebugWait: debug_wait = pargs.r.ret_int; break;
@@ -713,12 +803,12 @@ main (int argc, char **argv )
         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);
@@ -744,10 +834,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))
@@ -757,9 +852,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
@@ -767,8 +862,31 @@ main (int argc, char **argv )
   /*log_info ("NOTE: this is a development version!\n");*/
 #endif
 
+#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");
@@ -776,10 +894,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 ();
 
@@ -790,10 +909,16 @@ main (int argc, char **argv )
       gnupg_sleep (debug_wait);
       log_debug ("... okay\n");
     }
-  
-  if (gpgconf_list == 2)
+
+  if (gpgconf_list == 3)
+    {
+      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);
-  if (gpgconf_list)
+  else if (gpgconf_list)
     {
       char *filename;
       char *filename_esc;
@@ -802,12 +927,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",
@@ -815,61 +940,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)
     {
@@ -878,7 +982,6 @@ main (int argc, char **argv )
                              |JNLIB_LOG_WITH_TIME
                              |JNLIB_LOG_WITH_PID));
       current_logfile = xstrdup (logfile);
-      assuan_set_assuan_log_stream (log_get_stream ());
     }
 
   /* Make sure that we have a default ttyname. */
@@ -889,7 +992,7 @@ main (int argc, char **argv )
 
 
   if (pipe_server)
-    { 
+    {
       /* This is the simple pipe based server */
       ctrl_t ctrl;
 
@@ -900,6 +1003,14 @@ main (int argc, char **argv )
                      strerror (errno) );
           agent_exit (1);
         }
+      ctrl->session_env = session_env_new ();
+      if (!ctrl->session_env)
+        {
+          log_error ("error allocating session environment block: %s\n",
+                     strerror (errno) );
+          xfree (ctrl);
+          agent_exit (1);
+        }
       agent_init_default_ctrl (ctrl);
       start_command_handler (ctrl, GNUPG_INVALID_FD, GNUPG_INVALID_FD);
       agent_deinit_default_ctrl (ctrl);
@@ -921,16 +1032,16 @@ main (int argc, char **argv )
          exec the program given as arguments). */
 #ifndef HAVE_W32_SYSTEM
       if (!opt.keep_display && !argc)
-        unsetenv ("DISPLAY");
+        gnupg_unsetenv ("DISPLAY");
 #endif
 
 
       /* 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)
@@ -947,20 +1058,46 @@ 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.  */
+#warning need to do something about pth_kill - see bug#1320
+          if ( !pth_kill () )
+            log_error ("pth_kill failed in forked process\n");
+
+#ifdef HAVE_SIGPROCMASK
+          if (startup_signal_mask_valid)
+            {
+              if (sigprocmask (SIG_SETMASK, &startup_signal_mask, NULL))
+                log_error ("error restoring signal mask: %s\n",
+                           strerror (errno));
+            }
+          else
+            log_info ("no saved signal mask\n");
+#endif /*HAVE_SIGPROCMASK*/
+
           /* Create the info string: <name>:<pid>:<protocol_version> */
           if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1",
                         socket_name, (ulong)pid ) < 0)
@@ -978,13 +1115,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 -
@@ -994,29 +1124,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"),
                              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))
                 {
@@ -1032,13 +1160,14 @@ 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
+                 close 0,1,2 in case something went wrong collecting
+                 them at startup.  */
+              close_all_fds (3, startup_fd_list);
+
+              /* Run the command.  */
               execvp (argv[0], argv);
               log_error ("failed to run the command: %s\n", strerror (errno));
               kill (pid, SIGTERM);
@@ -1051,47 +1180,44 @@ 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 )
                 {
@@ -1125,7 +1251,7 @@ main (int argc, char **argv )
 
       {
         struct sigaction sa;
-        
+
         sa.sa_handler = SIG_IGN;
         sigemptyset (&sa.sa_mask);
         sa.sa_flags = 0;
@@ -1133,10 +1259,11 @@ main (int argc, char **argv )
       }
 #endif /*!HAVE_W32_SYSTEM*/
 
+      log_info ("%s %s started\n", strusage(11), strusage(13) );
       handle_connections (fd, opt.ssh_support ? fd_ssh : GNUPG_INVALID_FD);
       assuan_sock_close (fd);
     }
-  
+
   return 0;
 }
 
@@ -1145,6 +1272,12 @@ 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)
@@ -1160,23 +1293,18 @@ agent_exit (int rc)
   exit (rc);
 }
 
+
 static void
 agent_init_default_ctrl (ctrl_t ctrl)
 {
   /* Note we ignore malloc errors because we can't do much about it
      and the request will fail anyway shortly after this
      initialization. */
-  if (ctrl->display)
-    xfree (ctrl->display);
-  ctrl->display = default_display? xtrystrdup (default_display) : NULL;
-
-  if (ctrl->ttyname)
-    xfree (ctrl->ttyname);
-  ctrl->ttyname = default_ttyname? xtrystrdup (default_ttyname) : NULL;
-
-  if (ctrl->ttytype)
-    xfree (ctrl->ttytype);
-  ctrl->ttytype = default_ttytype? xtrystrdup (default_ttytype) : NULL;
+  session_env_setenv (ctrl->session_env, "DISPLAY", default_display);
+  session_env_setenv (ctrl->session_env, "GPG_TTY", default_ttyname);
+  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);
@@ -1187,39 +1315,25 @@ agent_init_default_ctrl (ctrl_t ctrl)
   ctrl->lc_messages = default_lc_messages? xtrystrdup (default_lc_messages)
                                     /**/ : NULL;
 
-  if (ctrl->xauthority)
-    xfree (ctrl->xauthority);
-  ctrl->xauthority = default_xauthority? xtrystrdup (default_xauthority)
-                                   /**/: NULL;
-
-  if (ctrl->pinentry_user_data)
-    xfree (ctrl->pinentry_user_data);
-  ctrl->pinentry_user_data = NULL;
+  ctrl->cache_ttl_opt_preset = CACHE_TTL_OPT_PRESET;
 }
 
 
 static void
 agent_deinit_default_ctrl (ctrl_t ctrl)
 {
-  if (ctrl->display)
-    xfree (ctrl->display);
-  if (ctrl->ttyname)
-    xfree (ctrl->ttyname);
-  if (ctrl->ttytype)
-    xfree (ctrl->ttytype);
+  session_env_release (ctrl->session_env);
+
   if (ctrl->lc_ctype)
     xfree (ctrl->lc_ctype);
   if (ctrl->lc_messages)
     xfree (ctrl->lc_messages);
-  if (ctrl->xauthority)
-    xfree (ctrl->xauthority);
-  if (ctrl->pinentry_user_data)
-    xfree (ctrl->pinentry_user_data);
 }
 
+
 /* 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
@@ -1240,8 +1354,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;
     }
 
@@ -1287,7 +1401,7 @@ get_agent_ssh_socket_name (void)
 /* Under W32, this function returns the handle of the scdaemon
    notification event.  Calling it the first time creates that
    event.  */
-#ifdef HAVE_W32_SYSTEM
+#if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM)
 void *
 get_agent_scd_notify_event (void)
 {
@@ -1298,7 +1412,7 @@ get_agent_scd_notify_event (void)
       HANDLE h, h2;
       SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
 
-      /* We need to use manual reset evet object due to the way our
+      /* We need to use a manual reset event object due to the way our
          w32-pth wait function works: If we would use an automatic
          reset event we are not able to figure out which handle has
          been signaled because at the time we single out the signaled
@@ -1309,7 +1423,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) );
@@ -1322,10 +1436,9 @@ get_agent_scd_notify_event (void)
         }
     }
 
-  log_debug  ("returning notify handle %p\n", the_event);
   return the_event;
 }
-#endif /*HAVE_W32_SYSTEM*/
+#endif /*HAVE_W32_SYSTEM && !HAVE_W32CE_SYSTEM*/
 
 
 
@@ -1342,11 +1455,19 @@ 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 ();
@@ -1394,7 +1515,7 @@ 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))
@@ -1403,11 +1524,17 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
       agent_exit (2);
     }
   strcpy (serv_addr->sun_path, name);
-  len = (offsetof (struct sockaddr_un, sun_path)
-        + strlen (serv_addr->sun_path) + 1);
-
+  len = SUN_LEN (serv_addr);
   rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len);
-  if (use_standard_socket && rc == -1 && errno == EADDRINUSE)
+
+  /* Our error code mapping on W32CE returns EEXIST thus we also test
+     for this. */
+  if (opt.use_standard_socket && rc == -1
+      && (errno == EADDRINUSE
+#ifdef HAVE_W32_SYSTEM
+          || errno == EEXIST
+#endif
+          ))
     {
       /* Check whether a gpg-agent is already running on the standard
          socket.  We do this test only if this is not the ssh socket.
@@ -1419,16 +1546,18 @@ 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(). */
           assuan_sock_close (fd);
           agent_exit (2);
         }
-      remove (name);
+      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)
@@ -1436,11 +1565,11 @@ 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"),
-                serv_addr->sun_path, 
+                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);
     }
@@ -1451,7 +1580,7 @@ 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);
 
@@ -1471,15 +1600,9 @@ create_private_keys_directory (const char *home)
   fname = make_filename (home, GNUPG_PRIVATE_KEYS_DIR, NULL);
   if (stat (fname, &statbuf) && errno == ENOENT)
     {
-#ifdef HAVE_W32_SYSTEM  /*FIXME: Setup proper permissions.  */
-      if (!CreateDirectory (fname, NULL))
-        log_error (_("can't create directory `%s': %s\n"),
-                   fname, w32_strerror (-1) );
-#else
-      if (mkdir (fname, S_IRUSR|S_IWUSR|S_IXUSR ))
+      if (gnupg_mkdir (fname, "-rwx"))
         log_error (_("can't create directory `%s': %s\n"),
                    fname, strerror (errno) );
-#endif
       else if (!opt.quiet)
         log_info (_("directory `%s' created\n"), fname);
     }
@@ -1516,16 +1639,10 @@ create_directories (void)
 #endif
                )
             {
-#ifdef HAVE_W32_SYSTEM
-              if (!CreateDirectory (home, NULL))
-                log_error (_("can't create directory `%s': %s\n"),
-                           home, w32_strerror (-1) );
-#else
-              if (mkdir (home, S_IRUSR|S_IWUSR|S_IXUSR ))
+              if (gnupg_mkdir (home, "-rwx"))
                 log_error (_("can't create directory `%s': %s\n"),
                            home, strerror (errno) );
-#endif
-              else 
+              else
                 {
                   if (!opt.quiet)
                     log_info (_("directory `%s' created\n"), home);
@@ -1577,13 +1694,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
 
 }
 
@@ -1620,14 +1739,16 @@ handle_signal (int signo)
     case SIGHUP:
       agent_sighup_action ();
       break;
-      
+
     case SIGUSR1:
       log_info ("SIGUSR1 received - printing internal information:\n");
-      pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ());
+      /* Fixme: We need to see how to integrate pth dumping into our
+         logging system.  */
+      /* pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ()); */
       agent_query_dump_state ();
       agent_scd_dump_state ();
       break;
-      
+
     case SIGUSR2:
       agent_sigusr2_action ();
       break;
@@ -1647,7 +1768,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));
@@ -1663,12 +1784,12 @@ handle_signal (int signo)
 
 /* 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);
@@ -1686,18 +1807,21 @@ 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", pth_thread_id ());
+      return NULL;
+    }
 
   agent_init_default_ctrl (ctrl);
   if (opt.verbose)
-    log_info (_("handler 0x%lx for fd %d started\n"), 
+    log_info (_("handler 0x%lx for fd %d started\n"),
               pth_thread_id (), 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"), 
+    log_info (_("handler 0x%lx for fd %d terminated\n"),
               pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
-  
+
   agent_deinit_default_ctrl (ctrl);
   xfree (ctrl);
   return NULL;
@@ -1722,7 +1846,7 @@ start_connection_thread_ssh (void *arg)
   if (opt.verbose)
     log_info (_("ssh handler 0x%lx for fd %d terminated\n"),
               pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
-  
+
   agent_deinit_default_ctrl (ctrl);
   xfree (ctrl);
   return NULL;
@@ -1768,7 +1892,7 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
         sa.sa_handler = SIG_IGN;
         sa.sa_flags = 0;
         sigaction (mysigs[i], &sa, NULL);
-        
+
         sigaddset (&sigs, mysigs[i]);
       }
   }
@@ -1776,18 +1900,22 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
   pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
   ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
 #else
-# ifdef PTH_EVENT_HANDLE
-  sigs = 0;
-  ev = pth_event (PTH_EVENT_HANDLE, get_agent_scd_notify_event ());
-  signo = 0;
-# 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;
 # 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);
   nfd = FD2INT (listen_fd);
@@ -1835,6 +1963,7 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
 
       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);
@@ -1905,7 +2034,14 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
                          strerror (errno) );
               assuan_sock_close (fd);
             }
-          else 
+          else if ( !(ctrl->session_env = session_env_new ()) )
+            {
+              log_error ("error allocating session environment block: %s\n",
+                         strerror (errno) );
+              xfree (ctrl);
+              assuan_sock_close (fd);
+            }
+          else
             {
               char threadname[50];
 
@@ -1925,7 +2061,7 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
           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;
@@ -1943,6 +2079,13 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
                          strerror (errno) );
               assuan_sock_close (fd);
             }
+          else if ( !(ctrl->session_env = session_env_new ()) )
+            {
+              log_error ("error allocating session environment block: %s\n",
+                         strerror (errno) );
+              xfree (ctrl);
+              assuan_sock_close (fd);
+            }
           else
             {
               char threadname[50];
@@ -1975,7 +2118,7 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
 
 
 /* Helper for check_own_socket.  */
-static int
+static gpg_error_t
 check_own_socket_pid_cb (void *opaque, const void *buffer, size_t length)
 {
   membuf_t *mb = opaque;
@@ -1992,20 +2135,26 @@ check_own_socket_thread (void *arg)
 {
   int rc;
   char *sockname = arg;
-  assuan_context_t ctx;
+  assuan_context_t ctx = NULL;
   membuf_t mb;
   char *buffer;
 
   check_own_socket_running++;
 
-  rc = assuan_socket_connect (&ctx, sockname, (pid_t)(-1));
-  xfree (sockname);
+  rc = assuan_new (&ctx);
+  if (rc)
+    {
+      log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
+      goto leave;
+    }
+
+  rc = assuan_socket_connect (ctx, sockname, (pid_t)(-1), 0);
   if (rc)
     {
       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);
@@ -2013,7 +2162,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;
     }
@@ -2022,13 +2171,15 @@ check_own_socket_thread (void *arg)
       log_error ("socket is now serviced by another server\n");
       rc = 1;
     }
-  else if (opt.verbose)
+  else if (opt.verbose > 1)
     log_error ("socket is still served by this server\n");
-    
+
   xfree (buffer);
-  assuan_disconnect (ctx);
 
  leave:
+  xfree (sockname);
+  if (ctx)
+    assuan_release (ctx);
   if (rc)
     {
       /* We may not remove the socket as it is now in use by another
@@ -2047,7 +2198,7 @@ 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 woul linger around without any real taks.  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)
@@ -2055,7 +2206,7 @@ check_own_socket (void)
   char *sockname;
   pth_attr_t tattr;
 
-  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)
@@ -2086,7 +2237,7 @@ check_for_running_agent (int silent, int mode)
 {
   int rc;
   char *infostr, *p;
-  assuan_context_t ctx;
+  assuan_context_t ctx = NULL;
   int prot, pid;
 
   if (!mode)
@@ -2134,8 +2285,9 @@ check_for_running_agent (int silent, int mode)
       pid = (pid_t)(-1);
     }
 
-
-  rc = assuan_socket_connect (&ctx, infostr, pid);
+  rc = assuan_new (&ctx);
+  if (! rc)
+    rc = assuan_socket_connect (ctx, infostr, pid, 0);
   xfree (infostr);
   if (rc)
     {
@@ -2144,12 +2296,24 @@ check_for_running_agent (int silent, int mode)
 
       if (!mode && !silent)
         log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
+
+      if (ctx)
+       assuan_release (ctx);
       return -1;
     }
 
   if (!opt.quiet && !silent)
     log_info ("gpg-agent running and available\n");
 
-  assuan_disconnect (ctx);
+  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));
+}