agent: Fix length test in sshcontrol parser.
[gnupg.git] / agent / gpg-agent.c
index 8907e92..bf2a26d 100644 (file)
@@ -1,12 +1,13 @@
 /* gpg-agent.c  -  The GnuPG Agent
 /* gpg-agent.c  -  The GnuPG Agent
- *     Copyright (C) 2000, 2001, 2002, 2003, 2004,
- *                    2005 Free Software Foundation, Inc.
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005,
+ *               2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Werner Koch
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -15,9 +16,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
  */
 
 #include <config.h>
 #include <time.h>
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <time.h>
 #include <fcntl.h>
 #include <sys/stat.h>
-#ifndef HAVE_W32_SYSTEM
+#ifdef HAVE_W32_SYSTEM
+# ifndef WINVER
+#  define WINVER 0x0500  /* Same as in common/sysutils.c */
+# endif
+# ifdef HAVE_WINSOCK2_H
+#  include <winsock2.h>
+# endif
+# include <aclapi.h>
+# include <sddl.h>
+#else /*!HAVE_W32_SYSTEM*/
 # include <sys/socket.h>
 # include <sys/un.h>
 #endif /*!HAVE_W32_SYSTEM*/
 # include <sys/socket.h>
 # include <sys/un.h>
 #endif /*!HAVE_W32_SYSTEM*/
 #include <pth.h>
 
 #define JNLIB_NEED_LOG_LOGV
 #include <pth.h>
 
 #define JNLIB_NEED_LOG_LOGV
+#define JNLIB_NEED_AFLOCAL
 #include "agent.h"
 #include "agent.h"
-#include <assuan.h> /* Malloc hooks */
+#include <assuan.h> /* Malloc hooks  and socket wrappers. */
 
 #include "i18n.h"
 
 #include "i18n.h"
+#include "mkdtemp.h" /* Gnulib replacement. */
 #include "sysutils.h"
 #include "sysutils.h"
-#ifdef HAVE_W32_SYSTEM
-# include "../jnlib/w32-afunix.h"
-# include "w32main.h"
-#endif
 #include "setenv.h"
 #include "setenv.h"
+#include "gc-opt-flags.h"
+#include "exechelp.h"
+#include "../common/estream.h"
 
 
-
-enum cmd_and_opt_values 
+enum cmd_and_opt_values
 { aNull = 0,
   oCsh           = 'c',
   oQuiet         = 'q',
 { aNull = 0,
   oCsh           = 'c',
   oQuiet         = 'q',
@@ -63,6 +71,7 @@ enum cmd_and_opt_values
   oNoVerbose = 500,
   aGPGConfList,
   aGPGConfTest,
   oNoVerbose = 500,
   aGPGConfList,
   aGPGConfTest,
+  aUseStandardSocketP,
   oOptions,
   oDebug,
   oDebugAll,
   oOptions,
   oDebug,
   oDebugAll,
@@ -85,22 +94,30 @@ enum cmd_and_opt_values
   oTTYtype,
   oLCctype,
   oLCmessages,
   oTTYtype,
   oLCctype,
   oLCmessages,
+  oXauthority,
   oScdaemonProgram,
   oDefCacheTTL,
   oDefCacheTTLSSH,
   oMaxCacheTTL,
   oMaxCacheTTLSSH,
   oScdaemonProgram,
   oDefCacheTTL,
   oDefCacheTTLSSH,
   oMaxCacheTTL,
   oMaxCacheTTLSSH,
+  oEnforcePassphraseConstraints,
   oMinPassphraseLen,
   oMinPassphraseLen,
+  oMinPassphraseNonalpha,
+  oCheckPassphrasePattern,
+  oMaxPassphraseDays,
+  oEnablePassphraseHistory,
   oUseStandardSocket,
   oNoUseStandardSocket,
   oUseStandardSocket,
   oNoUseStandardSocket,
-  oNoReuseStandardSocket,
+  oFakedSystemTime,
 
   oIgnoreCacheForSigning,
   oAllowMarkTrusted,
 
   oIgnoreCacheForSigning,
   oAllowMarkTrusted,
+  oNoAllowMarkTrusted,
   oAllowPresetPassphrase,
   oKeepTTY,
   oKeepDISPLAY,
   oSSHSupport,
   oAllowPresetPassphrase,
   oKeepTTY,
   oKeepDISPLAY,
   oSSHSupport,
+  oPuttySupport,
   oDisableScdaemon,
   oWriteEnvFile
 };
   oDisableScdaemon,
   oWriteEnvFile
 };
@@ -111,11 +128,12 @@ static ARGPARSE_OPTS opts[] = {
 
   { aGPGConfList, "gpgconf-list", 256, "@" },
   { aGPGConfTest, "gpgconf-test", 256, "@" },
 
   { aGPGConfList, "gpgconf-list", 256, "@" },
   { aGPGConfTest, "gpgconf-test", 256, "@" },
-  
+  { aUseStandardSocketP, "use-standard-socket-p", 256, "@" },
+
   { 301, NULL, 0, N_("@Options:\n ") },
 
   { 301, NULL, 0, N_("@Options:\n ") },
 
-  { oServer,   "server",     0, N_("run in server mode (foreground)") },
   { oDaemon,   "daemon",     0, N_("run in daemon mode (background)") },
   { oDaemon,   "daemon",     0, N_("run in daemon mode (background)") },
+  { oServer,   "server",     0, N_("run in server mode (foreground)") },
   { oVerbose, "verbose",     0, N_("verbose") },
   { oQuiet,    "quiet",     0, N_("be somewhat more quiet") },
   { oSh,       "sh",        0, N_("sh-style command output") },
   { oVerbose, "verbose",     0, N_("verbose") },
   { oQuiet,    "quiet",     0, N_("be somewhat more quiet") },
   { oSh,       "sh",        0, N_("sh-style command output") },
@@ -131,21 +149,24 @@ static ARGPARSE_OPTS opts[] = {
   { oUseStandardSocket, "use-standard-socket", 0,
                       N_("use a standard location for the socket")},
   { oNoUseStandardSocket, "no-use-standard-socket", 0, "@"},
   { oUseStandardSocket, "use-standard-socket", 0,
                       N_("use a standard location for the socket")},
   { oNoUseStandardSocket, "no-use-standard-socket", 0, "@"},
-  { oNoReuseStandardSocket, "no-reuse-standard-socket", 0, "@"},
-
   { oPinentryProgram, "pinentry-program", 2 ,
                                N_("|PGM|use PGM as the PIN-Entry program") },
   { oPinentryTouchFile, "pinentry-touch-file", 2 , "@" },
   { oScdaemonProgram, "scdaemon-program", 2 ,
                                N_("|PGM|use PGM as the SCdaemon program") },
   { oDisableScdaemon, "disable-scdaemon", 0, N_("do not use the SCdaemon") },
   { oPinentryProgram, "pinentry-program", 2 ,
                                N_("|PGM|use PGM as the PIN-Entry program") },
   { oPinentryTouchFile, "pinentry-touch-file", 2 , "@" },
   { oScdaemonProgram, "scdaemon-program", 2 ,
                                N_("|PGM|use PGM as the SCdaemon program") },
   { oDisableScdaemon, "disable-scdaemon", 0, N_("do not use the SCdaemon") },
+  { oFakedSystemTime, "faked-system-time", 2, "@" }, /* (epoch time) */
+
+  { oBatch,      "batch",       0, "@" },
+  { oHomedir,    "homedir",     2, "@"},
 
   { oDisplay,    "display",     2, "@" },
   { oTTYname,    "ttyname",     2, "@" },
   { oTTYtype,    "ttytype",     2, "@" },
   { oLCctype,    "lc-ctype",    2, "@" },
   { oLCmessages, "lc-messages", 2, "@" },
 
   { oDisplay,    "display",     2, "@" },
   { oTTYname,    "ttyname",     2, "@" },
   { oTTYtype,    "ttytype",     2, "@" },
   { oLCctype,    "lc-ctype",    2, "@" },
   { oLCmessages, "lc-messages", 2, "@" },
-  { oKeepTTY, "keep-tty", 0,  N_("ignore requests to change the TTY")},
+  { oXauthority, "xauthority",  2, "@" },
+  { oKeepTTY,    "keep-tty",    0,  N_("ignore requests to change the TTY")},
   { oKeepDISPLAY, "keep-display",
                           0, N_("ignore requests to change the X display")},
 
   { oKeepDISPLAY, "keep-display",
                           0, N_("ignore requests to change the X display")},
 
@@ -154,14 +175,29 @@ static ARGPARSE_OPTS opts[] = {
   { oDefCacheTTLSSH, "default-cache-ttl-ssh", 4, "@" },
   { oMaxCacheTTL, "max-cache-ttl", 4, "@" },
   { oMaxCacheTTLSSH, "max-cache-ttl-ssh", 4, "@" },
   { oDefCacheTTLSSH, "default-cache-ttl-ssh", 4, "@" },
   { oMaxCacheTTL, "max-cache-ttl", 4, "@" },
   { oMaxCacheTTLSSH, "max-cache-ttl-ssh", 4, "@" },
+
+  { oEnforcePassphraseConstraints, "enforce-passphrase-constraints", 0, "@"},
   { oMinPassphraseLen, "min-passphrase-len", 4, "@" },
   { oMinPassphraseLen, "min-passphrase-len", 4, "@" },
+  { oMinPassphraseNonalpha, "min-passphrase-nonalpha", 4, "@" },
+  { oCheckPassphrasePattern, "check-passphrase-pattern", 2, "@" },
+  { oMaxPassphraseDays, "max-passphrase-days", 4, "@" },
+  { oEnablePassphraseHistory, "enable-passphrase-history", 0, "@" },
+
   { oIgnoreCacheForSigning, "ignore-cache-for-signing", 0,
                                N_("do not use the PIN cache when signing")},
   { oIgnoreCacheForSigning, "ignore-cache-for-signing", 0,
                                N_("do not use the PIN cache when signing")},
-  { oAllowMarkTrusted, "allow-mark-trusted", 0,
-                             N_("allow clients to mark keys as \"trusted\"")},
+  { oNoAllowMarkTrusted, "no-allow-mark-trusted", 0,
+                            N_("disallow clients to mark keys as \"trusted\"")},
+  { oAllowMarkTrusted, "allow-mark-trusted", 0, "@"},
   { oAllowPresetPassphrase, "allow-preset-passphrase", 0,
                              N_("allow presetting passphrase")},
   { oAllowPresetPassphrase, "allow-preset-passphrase", 0,
                              N_("allow presetting passphrase")},
-  { oSSHSupport, "enable-ssh-support", 0, N_("enable ssh-agent emulation") },
+  { oSSHSupport, "enable-ssh-support", 0, N_("enable ssh support") },
+  { oPuttySupport, "enable-putty-support", 0,
+#ifdef HAVE_W32_SYSTEM
+      N_("enable putty support")
+#else
+      "@"
+#endif
+  },
   { oWriteEnvFile, "write-env-file", 2|8,
             N_("|FILE|write environment settings also to FILE")},
   {0}
   { oWriteEnvFile, "write-env-file", 2|8,
             N_("|FILE|write environment settings also to FILE")},
   {0}
@@ -172,12 +208,46 @@ 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 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_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)
+#else
+#define TIMERTICK_INTERVAL    (2)    /* Seconds.  */
+#endif
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Flag indicating that support for Putty has been enabled.  */
+static int putty_support;
+/* A magic value used with WM_COPYDATA.  */
+#define PUTTY_IPC_MAGIC 0x804e50ba
+/* To avoid surprises we limit the size of the mapped IPC file to this
+   value.  Putty currently (0.62) uses 8k, thus 16k should be enough
+   for the foreseeable future.  */
+#define PUTTY_IPC_MAXLEN 16384
+#endif /*HAVE_W32_SYSTEM*/
 
 
-/* flag to indicate that a shutdown was requested */
+/* 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.  */
 static int shutdown_pending;
 
 static int shutdown_pending;
 
+/* Counter for the currently running own socket checks.  */
+static int check_own_socket_running;
 
 /* It is possible that we are currently running under setuid permissions */
 static int maybe_setuid = 1;
 
 /* It is possible that we are currently running under setuid permissions */
 static int maybe_setuid = 1;
@@ -188,9 +258,11 @@ static char *socket_name;
 /* Name of the communication socket used for ssh-agent-emulation.  */
 static char *socket_name_ssh;
 
 /* Name of the communication socket used for ssh-agent-emulation.  */
 static char *socket_name_ssh;
 
-/* If set to true and a standard socket is requested, we won't try to
-   bind to a socket which is already in use.  */
-static int no_reuse_standard_socket;
+/* We need to keep track of the server's nonces (these are dummies for
+   POSIX systems). */
+static assuan_sock_nonce_t socket_nonce;
+static assuan_sock_nonce_t socket_nonce_ssh;
+
 
 /* Default values for options passed to the pinentry. */
 static char *default_display;
 
 /* Default values for options passed to the pinentry. */
 static char *default_display;
@@ -198,6 +270,7 @@ static char *default_ttyname;
 static char *default_ttytype;
 static char *default_lc_ctype;
 static char *default_lc_messages;
 static char *default_ttytype;
 static char *default_lc_ctype;
 static char *default_lc_messages;
+static char *default_xauthority;
 
 /* Name of a config file, which will be reread on a HUP if it is not NULL. */
 static char *config_filename;
 
 /* Name of a config file, which will be reread on a HUP if it is not NULL. */
 static char *config_filename;
@@ -216,50 +289,96 @@ static pid_t parent_pid = (pid_t)(-1);
 
 \f
 /*
 
 \f
 /*
-   Local prototypes. 
+   Local prototypes.
  */
 
  */
 
-static char *create_socket_name (int use_standard_socket,
-                                 char *standard_name, char *template);
-static int create_server_socket (int is_standard_name, char *name);
+static char *create_socket_name (char *standard_name, char *template);
+static gnupg_fd_t create_server_socket (char *name, int is_ssh,
+                                        assuan_sock_nonce_t *nonce);
 static void create_directories (void);
 
 static void agent_init_default_ctrl (ctrl_t ctrl);
 static void agent_deinit_default_ctrl (ctrl_t ctrl);
 
 static void create_directories (void);
 
 static void agent_init_default_ctrl (ctrl_t ctrl);
 static void agent_deinit_default_ctrl (ctrl_t ctrl);
 
-static void handle_connections (int listen_fd, int listen_fd_ssh);
-static int check_for_running_agent (int);
+static void handle_connections (gnupg_fd_t listen_fd,
+                                gnupg_fd_t listen_fd_ssh);
+static void check_own_socket (void);
+static int check_for_running_agent (int silent, int mode);
 
 /* Pth wrapper function definitions. */
 
 /* Pth wrapper function definitions. */
+ASSUAN_SYSTEM_PTH_IMPL;
+
+#if GCRYPT_VERSION_NUMBER < 0x010600
 GCRY_THREAD_OPTION_PTH_IMPL;
 GCRY_THREAD_OPTION_PTH_IMPL;
+#if GCRY_THREAD_OPTION_VERSION < 1
+static int fixed_gcry_pth_init (void)
+{
+  return pth_self ()? 0 : (pth_init () == FALSE) ? errno : 0;
+}
+#endif
+#endif /*GCRYPT_VERSION_NUMBER < 0x10600*/
 
 
+#ifndef PTH_HAVE_PTH_THREAD_ID
+static unsigned long pth_thread_id (void)
+{
+  return (unsigned long)pth_self ();
+}
+#endif
 
 
 \f
 /*
 
 
 \f
 /*
-   Functions. 
+   Functions.
  */
 
  */
 
+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. */
+      maybe_setuid = 0;
+    }
+  s = getfnc (NULL);
+  result = xmalloc (strlen (libname) + 1 + strlen (s) + 1);
+  strcpy (stpcpy (stpcpy (result, libname), " "), s);
+  return result;
+}
+
 
 static const char *
 my_strusage (int level)
 {
 
 static const char *
 my_strusage (int level)
 {
+  static char *ver_gcry;
   const char *p;
   const char *p;
+
   switch (level)
     {
     case 11: p = "gpg-agent (GnuPG)";
       break;
     case 13: p = VERSION; break;
     case 17: p = PRINTABLE_OS_NAME; break;
   switch (level)
     {
     case 11: p = "gpg-agent (GnuPG)";
       break;
     case 13: p = VERSION; break;
     case 17: p = PRINTABLE_OS_NAME; break;
-    case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
+      /* 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);
+      p = ver_gcry;
       break;
       break;
+
     case 1:
     case 40: p =  _("Usage: gpg-agent [options] (-h for help)");
       break;
     case 41: p =  _("Syntax: gpg-agent [options] [command [args]]\n"
                     "Secret key management for GnuPG\n");
     break;
     case 1:
     case 40: p =  _("Usage: gpg-agent [options] (-h for help)");
       break;
     case 41: p =  _("Syntax: gpg-agent [options] [command [args]]\n"
                     "Secret key management for GnuPG\n");
     break;
-    
+
     default: p = NULL;
     }
   return p;
     default: p = NULL;
     }
   return p;
@@ -276,19 +395,30 @@ my_strusage (int level)
 static void
 set_debug (void)
 {
 static void
 set_debug (void)
 {
+  int numok = (debug_level && digitp (debug_level));
+  int numlvl = numok? atoi (debug_level) : 0;
+
   if (!debug_level)
     ;
   if (!debug_level)
     ;
-  else if (!strcmp (debug_level, "none"))
+  else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
     opt.debug = 0;
     opt.debug = 0;
-  else if (!strcmp (debug_level, "basic"))
+  else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
     opt.debug = DBG_ASSUAN_VALUE;
     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;
     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);
     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);
   else
     {
       log_error (_("invalid debug-level `%s' given\n"), debug_level);
@@ -306,8 +436,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 & 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
 
 /* Helper for cleanup to remove one socket with NAME.  */
 static void
@@ -327,7 +468,7 @@ remove_socket (char *name)
        }
       *name = 0;
     }
        }
       *name = 0;
     }
-}  
+}
 
 static void
 cleanup (void)
 
 static void
 cleanup (void)
@@ -359,9 +500,14 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       opt.def_cache_ttl_ssh = DEFAULT_CACHE_TTL_SSH;
       opt.max_cache_ttl = MAX_CACHE_TTL;
       opt.max_cache_ttl_ssh = MAX_CACHE_TTL_SSH;
       opt.def_cache_ttl_ssh = DEFAULT_CACHE_TTL_SSH;
       opt.max_cache_ttl = MAX_CACHE_TTL;
       opt.max_cache_ttl_ssh = MAX_CACHE_TTL_SSH;
+      opt.enforce_passphrase_constraints = 0;
       opt.min_passphrase_len = MIN_PASSPHRASE_LEN;
       opt.min_passphrase_len = MIN_PASSPHRASE_LEN;
+      opt.min_passphrase_nonalpha = MIN_PASSPHRASE_NONALPHA;
+      opt.check_passphrase_pattern = NULL;
+      opt.max_passphrase_days = MAX_PASSPHRASE_DAYS;
+      opt.enable_passhrase_history = 0;
       opt.ignore_cache_for_signing = 0;
       opt.ignore_cache_for_signing = 0;
-      opt.allow_mark_trusted = 0;
+      opt.allow_mark_trusted = 1;
       opt.disable_scdaemon = 0;
       return 1;
     }
       opt.disable_scdaemon = 0;
       return 1;
     }
@@ -382,13 +528,15 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
           || strcmp (current_logfile, pargs->r.ret_str))
         {
           log_set_file (pargs->r.ret_str);
           || strcmp (current_logfile, pargs->r.ret_str))
         {
           log_set_file (pargs->r.ret_str);
+         if (DBG_ASSUAN)
+           assuan_set_assuan_log_stream (log_get_stream ());
           xfree (current_logfile);
           current_logfile = xtrystrdup (pargs->r.ret_str);
         }
       break;
 
     case oNoGrab: opt.no_grab = 1; break;
           xfree (current_logfile);
           current_logfile = xtrystrdup (pargs->r.ret_str);
         }
       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;
     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;
@@ -398,12 +546,28 @@ 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 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:
+      opt.enforce_passphrase_constraints=1;
+      break;
     case oMinPassphraseLen: opt.min_passphrase_len = pargs->r.ret_ulong; break;
     case oMinPassphraseLen: opt.min_passphrase_len = pargs->r.ret_ulong; break;
+    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;
+      break;
+    case oEnablePassphraseHistory:
+      opt.enable_passhrase_history = 1;
+      break;
 
     case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
 
     case oAllowMarkTrusted: opt.allow_mark_trusted = 1; break;
 
     case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
 
     case oAllowMarkTrusted: opt.allow_mark_trusted = 1; break;
+    case oNoAllowMarkTrusted: opt.allow_mark_trusted = 0; break;
 
     case oAllowPresetPassphrase: opt.allow_preset_passphrase = 1; break;
 
 
     case oAllowPresetPassphrase: opt.allow_preset_passphrase = 1; break;
 
@@ -415,20 +579,12 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
 }
 
 
 }
 
 
-/* The main entry point.  For W32 another name is used as the real
-   entry points needs to be named WinMain and is defined in
-   w32main.c. */
-#ifdef HAVE_W32_SYSTEM
-int
-w32_main (int argc, char **argv )
-#else
+/* The main entry point.  */
 int
 main (int argc, char **argv )
 int
 main (int argc, char **argv )
-#endif
 {
   ARGPARSE_ARGS pargs;
   int orig_argc;
 {
   ARGPARSE_ARGS pargs;
   int orig_argc;
-  int may_coredump;
   char **orig_argv;
   FILE *configfp = NULL;
   char *configname = NULL;
   char **orig_argv;
   FILE *configfp = NULL;
   char *configname = NULL;
@@ -445,31 +601,45 @@ main (int argc, char **argv )
   char *logfile = NULL;
   int debug_wait = 0;
   int gpgconf_list = 0;
   char *logfile = NULL;
   int debug_wait = 0;
   int gpgconf_list = 0;
-  int standard_socket = 0;
   gpg_error_t err;
   const char *env_file_name = NULL;
   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 */
   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.  */
 
   /* Make sure that our subsystems are ready.  */
+  i18n_init ();
   init_common_subsystems ();
 
   init_common_subsystems ();
 
-  i18n_init ();
 
 
-  /* Libgcrypt requires us to register the threading model first.
+#if GCRYPT_VERSION_NUMBER < 0x010600
+  /* Libgcrypt < 1.6 requires us to register the threading model first.
      Note that this will also do the pth_init. */
      Note that this will also do the pth_init. */
+#if GCRY_THREAD_OPTION_VERSION < 1
+  gcry_threads_pth.init = fixed_gcry_pth_init;
+#endif
   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));
     }
   err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
   if (err)
     {
       log_fatal ("can't register GNU Pth with Libgcrypt: %s\n",
                  gpg_strerror (err));
     }
+#endif /*GCRYPT_VERSION_NUMBER < 0x010600*/
 
 
   /* Check that the libraries are suitable.  Do it here because
 
 
   /* Check that the libraries are suitable.  Do it here because
@@ -480,23 +650,27 @@ main (int argc, char **argv )
                  NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
     }
 
                  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 ());
+  malloc_hooks.malloc = gcry_malloc;
+  malloc_hooks.realloc = gcry_realloc;
+  malloc_hooks.free = gcry_free;
+  assuan_set_malloc_hooks (&malloc_hooks);
   assuan_set_assuan_log_prefix (log_get_prefix (NULL));
   assuan_set_assuan_log_prefix (log_get_prefix (NULL));
-  assuan_set_assuan_err_source (GPG_ERR_SOURCE_DEFAULT);
+  assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
+  assuan_set_system_hooks (ASSUAN_SYSTEM_PTH);
+  assuan_sock_init ();
 
   setup_libgcrypt_logging ();
   gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
 
 
   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. */
 
   /* Set default options.  */
   parse_rereadable_options (NULL, 0); /* Reset them to default values. */
-#ifdef HAVE_W32_SYSTEM
-  standard_socket = 1;  /* Under Windows we always use a standard
-                           socket.  */
+#ifdef USE_STANDARD_SOCKET
+  opt.use_standard_socket = 1;  /* Under Windows we always use a standard
+                                   socket.  */
 #endif
 #endif
-  
+
   shell = getenv ("SHELL");
   if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
     csh_style = 1;
   shell = getenv ("SHELL");
   if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
     csh_style = 1;
@@ -504,22 +678,40 @@ main (int argc, char **argv )
   opt.homedir = default_homedir ();
 
   /* Record some of the original environment strings. */
   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);
+  {
+    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;
 
   /* Check whether we have a config file on the commandline */
   orig_argc = argc;
@@ -547,13 +739,13 @@ main (int argc, char **argv )
   gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
   maybe_setuid = 0;
 
   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 );
   */
 
   if (default_config)
     configname = make_filename (opt.homedir, "gpg-agent.conf", NULL );
-  
+
   argc = orig_argc;
   argv = orig_argv;
   pargs.argc = &argc;
   argc = orig_argc;
   argv = orig_argv;
   pargs.argc = &argc;
@@ -571,6 +763,12 @@ main (int argc, char **argv )
               if( parse_debug )
                 log_info (_("NOTE: no default option file `%s'\n"),
                           configname );
               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
             {
            }
           else
             {
@@ -578,7 +776,7 @@ main (int argc, char **argv )
                          configname, strerror(errno) );
               exit(2);
            }
                          configname, strerror(errno) );
               exit(2);
            }
-          xfree (configname); 
+          xfree (configname);
           configname = NULL;
        }
       if (parse_debug && configname )
           configname = NULL;
        }
       if (parse_debug && configname )
@@ -594,6 +792,7 @@ main (int argc, char **argv )
         {
         case aGPGConfList: gpgconf_list = 1; break;
         case aGPGConfTest: gpgconf_list = 2; break;
         {
         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;
         case oBatch: opt.batch=1; break;
 
         case oDebugWait: debug_wait = pargs.r.ret_int; break;
@@ -623,16 +822,32 @@ 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);
         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);
+        case oXauthority: default_xauthority = xstrdup (pargs.r.ret_str);
           break;
 
           break;
 
-        case oUseStandardSocket: standard_socket = 1; break;
-        case oNoUseStandardSocket: standard_socket = 0; break;
-        case oNoReuseStandardSocket: no_reuse_standard_socket = 1; 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);
+            if (faked_time == (time_t)(-1))
+              faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
+            gnupg_set_time (faked_time, 0);
+          }
+          break;
 
         case oKeepTTY: opt.keep_tty = 1; break;
         case oKeepDISPLAY: opt.keep_display = 1; break;
 
        case oSSHSupport:  opt.ssh_support = 1; break;
 
         case oKeepTTY: opt.keep_tty = 1; break;
         case oKeepDISPLAY: opt.keep_display = 1; break;
 
        case oSSHSupport:  opt.ssh_support = 1; break;
+        case oPuttySupport:
+#        ifdef HAVE_W32_SYSTEM
+          putty_support = 1;
+          opt.ssh_support = 1;
+#        endif
+          break;
+
         case oWriteEnvFile:
           if (pargs.r_type)
             env_file_name = pargs.r.ret_str;
         case oWriteEnvFile:
           if (pargs.r_type)
             env_file_name = pargs.r.ret_str;
@@ -648,10 +863,15 @@ main (int argc, char **argv )
       fclose( configfp );
       configfp = NULL;
       /* Keep a copy of the name so that it can be read on SIGHUP. */
       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;
     }
       configname = NULL;
       goto next_pass;
     }
+
   xfree (configname);
   configname = NULL;
   if (log_get_errorcount(0))
   xfree (configname);
   configname = NULL;
   if (log_get_errorcount(0))
@@ -672,7 +892,7 @@ main (int argc, char **argv )
 #endif
 
   set_debug ();
 #endif
 
   set_debug ();
-  
+
   if (atexit (cleanup))
     {
       log_error ("atexit failed\n");
   if (atexit (cleanup))
     {
       log_error ("atexit failed\n");
@@ -683,7 +903,7 @@ main (int argc, char **argv )
   initialize_module_call_pinentry ();
   initialize_module_call_scd ();
   initialize_module_trustlist ();
   initialize_module_call_pinentry ();
   initialize_module_call_scd ();
   initialize_module_trustlist ();
-  
+
   /* Try to create missing directories. */
   create_directories ();
 
   /* Try to create missing directories. */
   create_directories ();
 
@@ -691,10 +911,12 @@ main (int argc, char **argv )
     {
       log_debug ("waiting for debugger - my pid is %u .....\n",
                  (unsigned int)getpid());
     {
       log_debug ("waiting for debugger - my pid is %u .....\n",
                  (unsigned int)getpid());
-      sleep (debug_wait);
+      gnupg_sleep (debug_wait);
       log_debug ("... okay\n");
     }
       log_debug ("... okay\n");
     }
-  
+
+  if (gpgconf_list == 3)
+    agent_exit (!opt.use_standard_socket);
   if (gpgconf_list == 2)
     agent_exit (0);
   if (gpgconf_list)
   if (gpgconf_list == 2)
     agent_exit (0);
   if (gpgconf_list)
@@ -703,24 +925,6 @@ main (int argc, char **argv )
       char *filename_esc;
 
       /* List options and default values in the GPG Conf format.  */
       char *filename_esc;
 
       /* List options and default values in the GPG Conf format.  */
-
-      /* The following list is taken from gnupg/tools/gpgconf-comp.c.  */
-      /* Option flags.  YOU MUST NOT CHANGE THE NUMBERS OF THE EXISTING
-         FLAGS, AS THEY ARE PART OF THE EXTERNAL INTERFACE.  */
-#define GC_OPT_FLAG_NONE       0UL
-      /* The RUNTIME flag for an option indicates that the option can be
-         changed at runtime.  */
-#define GC_OPT_FLAG_RUNTIME    (1UL << 3)
-      /* The DEFAULT flag for an option indicates that the option has a
-         default value.  */
-#define GC_OPT_FLAG_DEFAULT    (1UL << 4)
-      /* The DEF_DESC flag for an option indicates that the option has a
-         default, which is described by the value of the default field.  */
-#define GC_OPT_FLAG_DEF_DESC   (1UL << 5)
-      /* The NO_ARG_DESC flag for an option indicates that the argument has
-         a default, which is described by the value of the ARGDEF field.  */
-#define GC_OPT_FLAG_NO_ARG_DESC        (1UL << 6)
-
       filename = make_filename (opt.homedir, "gpg-agent.conf", NULL );
       filename_esc = percent_escape (filename, NULL);
 
       filename = make_filename (opt.homedir, "gpg-agent.conf", NULL );
       filename_esc = percent_escape (filename, NULL);
 
@@ -745,16 +949,33 @@ main (int argc, char **argv )
               GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MAX_CACHE_TTL );
       printf ("max-cache-ttl-ssh:%lu:%d:\n",
               GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MAX_CACHE_TTL_SSH );
               GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MAX_CACHE_TTL );
       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",
+              GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
       printf ("min-passphrase-len:%lu:%d:\n",
               GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MIN_PASSPHRASE_LEN );
       printf ("min-passphrase-len:%lu:%d:\n",
               GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MIN_PASSPHRASE_LEN );
-      printf ("no-grab:%lu:\n", 
+      printf ("min-passphrase-nonalpha:%lu:%d:\n",
+              GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME,
+              MIN_PASSPHRASE_NONALPHA);
+      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,
+              MAX_PASSPHRASE_DAYS);
+      printf ("enable-passphrase-history:%lu:\n",
+              GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
+      printf ("no-grab:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
       printf ("ignore-cache-for-signing:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
       printf ("ignore-cache-for-signing:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
-      printf ("allow-mark-trusted:%lu:\n",
+      printf ("no-allow-mark-trusted:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
       printf ("disable-scdaemon:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
       printf ("disable-scdaemon:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
+#ifdef HAVE_W32_SYSTEM
+      printf ("enable-putty-support:%lu:\n", GC_OPT_FLAG_NONE);
+#else
+      printf ("enable-ssh-support:%lu:\n", GC_OPT_FLAG_NONE);
+#endif
 
       agent_exit (0);
     }
 
       agent_exit (0);
     }
@@ -764,11 +985,11 @@ main (int argc, char **argv )
      don't clobber a logfile but print it directly to stderr. */
   if (!pipe_server && !is_daemon)
     {
      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);
+      log_set_prefix (NULL, JNLIB_LOG_WITH_PREFIX);
+      check_for_running_agent (0, 0);
       agent_exit (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
 #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
@@ -789,6 +1010,8 @@ main (int argc, char **argv )
                              |JNLIB_LOG_WITH_PID));
       current_logfile = xstrdup (logfile);
     }
                              |JNLIB_LOG_WITH_PID));
       current_logfile = xstrdup (logfile);
     }
+  if (DBG_ASSUAN)
+    assuan_set_assuan_log_stream (log_get_stream ());
 
   /* Make sure that we have a default ttyname. */
   if (!default_ttyname && ttyname (1))
 
   /* Make sure that we have a default ttyname. */
   if (!default_ttyname && ttyname (1))
@@ -798,7 +1021,7 @@ main (int argc, char **argv )
 
 
   if (pipe_server)
 
 
   if (pipe_server)
-    { 
+    {
       /* This is the simple pipe based server */
       ctrl_t ctrl;
 
       /* This is the simple pipe based server */
       ctrl_t ctrl;
 
@@ -809,8 +1032,16 @@ main (int argc, char **argv )
                      strerror (errno) );
           agent_exit (1);
         }
                      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);
       agent_init_default_ctrl (ctrl);
-      start_command_handler (ctrl, -1, -1);
+      start_command_handler (ctrl, GNUPG_INVALID_FD, GNUPG_INVALID_FD);
       agent_deinit_default_ctrl (ctrl);
       xfree (ctrl);
     }
       agent_deinit_default_ctrl (ctrl);
       xfree (ctrl);
     }
@@ -818,8 +1049,8 @@ main (int argc, char **argv )
     ; /* NOTREACHED */
   else
     { /* Regular server mode */
     ; /* NOTREACHED */
   else
     { /* Regular server mode */
-      int fd;
-      int fd_ssh;
+      gnupg_fd_t fd;
+      gnupg_fd_t fd_ssh;
       pid_t pid;
 
       /* Remove the DISPLAY variable so that a pinentry does not
       pid_t pid;
 
       /* Remove the DISPLAY variable so that a pinentry does not
@@ -835,19 +1066,17 @@ main (int argc, char **argv )
 
 
       /* Create the sockets.  */
 
 
       /* Create the sockets.  */
-      socket_name = create_socket_name (standard_socket,
-                                        "S.gpg-agent",
-                                        "/tmp/gpg-XXXXXX/S.gpg-agent");
+      socket_name = create_socket_name
+        ("S.gpg-agent", "/tmp/gpg-XXXXXX/S.gpg-agent");
       if (opt.ssh_support)
       if (opt.ssh_support)
-       socket_name_ssh = create_socket_name (standard_socket, 
-                                            "S.gpg-agent.ssh",
-                                            "/tmp/gpg-XXXXXX/S.gpg-agent.ssh");
+       socket_name_ssh = create_socket_name
+          ("S.gpg-agent.ssh", "/tmp/gpg-XXXXXX/S.gpg-agent.ssh");
 
 
-      fd = create_server_socket (standard_socket, socket_name);
+      fd = create_server_socket (socket_name, 0, &socket_nonce);
       if (opt.ssh_support)
       if (opt.ssh_support)
-       fd_ssh = create_server_socket (standard_socket, socket_name_ssh);
+       fd_ssh = create_server_socket (socket_name_ssh, 1, &socket_nonce_ssh);
       else
       else
-       fd_ssh = -1;
+       fd_ssh = GNUPG_INVALID_FD;
 
       /* If we are going to exec a program in the parent, we record
          the PID, so that the child may check whether the program is
 
       /* If we are going to exec a program in the parent, we record
          the PID, so that the child may check whether the program is
@@ -859,20 +1088,46 @@ main (int argc, char **argv )
 #ifdef HAVE_W32_SYSTEM
       pid = getpid ();
       printf ("set GPG_AGENT_INFO=%s;%lu;1\n", socket_name, (ulong)pid);
 #ifdef HAVE_W32_SYSTEM
       pid = getpid ();
       printf ("set GPG_AGENT_INFO=%s;%lu;1\n", socket_name, (ulong)pid);
-      w32_setup_taskbar ();
 #else /*!HAVE_W32_SYSTEM*/
       pid = fork ();
 #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);
         }
         {
           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;
         { /* We are the parent */
           char *infostr, *infostr_ssh_sock, *infostr_ssh_pid;
-          
+
+          /* Close the socket FD. */
           close (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.  es_pth_kill is a wrapper around pth_kill to
+             take care not to use any Pth functions in the estream
+             code after Pth has been killed.  */
+          if ( !es_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)
           /* Create the info string: <name>:<pid>:<protocol_version> */
           if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1",
                         socket_name, (ulong)pid ) < 0)
@@ -907,7 +1162,7 @@ main (int argc, char **argv )
           if (env_file_name)
             {
               FILE *fp;
           if (env_file_name)
             {
               FILE *fp;
-              
+
               fp = fopen (env_file_name, "w");
               if (!fp)
                 log_error (_("error creating `%s': %s\n"),
               fp = fopen (env_file_name, "w");
               if (!fp)
                 log_error (_("error creating `%s': %s\n"),
@@ -928,7 +1183,7 @@ main (int argc, char **argv )
             }
 
 
             }
 
 
-          if (argc) 
+          if (argc)
             { /* Run the program given on the commandline.  */
               if (putenv (infostr))
                 {
             { /* Run the program given on the commandline.  */
               if (putenv (infostr))
                 {
@@ -951,6 +1206,14 @@ main (int argc, char **argv )
                   kill (pid, SIGTERM );
                   exit (1);
                 }
                   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);
               execvp (argv[0], argv);
               log_error ("failed to run the command: %s\n", strerror (errno));
               kill (pid, SIGTERM);
@@ -963,13 +1226,13 @@ main (int argc, char **argv )
               if (csh_style)
                 {
                   *strchr (infostr, '=') = ' ';
               if (csh_style)
                 {
                   *strchr (infostr, '=') = ' ';
-                  printf ("setenv %s\n", infostr);
+                  printf ("setenv %s;\n", infostr);
                  if (opt.ssh_support)
                    {
                      *strchr (infostr_ssh_sock, '=') = ' ';
                  if (opt.ssh_support)
                    {
                      *strchr (infostr_ssh_sock, '=') = ' ';
-                     printf ("setenv %s\n", infostr_ssh_sock);
+                     printf ("setenv %s;\n", infostr_ssh_sock);
                      *strchr (infostr_ssh_pid, '=') = ' ';
                      *strchr (infostr_ssh_pid, '=') = ' ';
-                     printf ("setenv %s\n", infostr_ssh_pid);
+                     printf ("setenv %s;\n", infostr_ssh_pid);
                    }
                 }
               else
                    }
                 }
               else
@@ -981,29 +1244,29 @@ main (int argc, char **argv )
                      printf ("%s; export SSH_AGENT_PID;\n", infostr_ssh_pid);
                    }
                 }
                      printf ("%s; export SSH_AGENT_PID;\n", infostr_ssh_pid);
                    }
                 }
-              free (infostr); /* (Note that a vanilla free is here correct.) */
+              xfree (infostr);
              if (opt.ssh_support)
                {
              if (opt.ssh_support)
                {
-                 free (infostr_ssh_sock);
-                 free (infostr_ssh_pid);
+                 xfree (infostr_ssh_sock);
+                 xfree (infostr_ssh_pid);
                }
                }
-              exit (0); 
+              exit (0);
             }
           /*NOTREACHED*/
         } /* End parent */
 
             }
           /*NOTREACHED*/
         } /* End parent */
 
-      /* 
+      /*
          This is the child
        */
 
       /* Detach from tty and put process into a new session */
       if (!nodetach )
          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 */
           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 (!log_test_fd (i) && i != fd )
                 {
@@ -1037,7 +1300,7 @@ main (int argc, char **argv )
 
       {
         struct sigaction sa;
 
       {
         struct sigaction sa;
-        
+
         sa.sa_handler = SIG_IGN;
         sigemptyset (&sa.sa_mask);
         sa.sa_flags = 0;
         sa.sa_handler = SIG_IGN;
         sigemptyset (&sa.sa_mask);
         sa.sa_flags = 0;
@@ -1045,10 +1308,11 @@ main (int argc, char **argv )
       }
 #endif /*!HAVE_W32_SYSTEM*/
 
       }
 #endif /*!HAVE_W32_SYSTEM*/
 
-      handle_connections (fd, opt.ssh_support ? fd_ssh : -1);
-      close (fd);
+      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;
 }
 
   return 0;
 }
 
@@ -1072,54 +1336,47 @@ agent_exit (int rc)
   exit (rc);
 }
 
   exit (rc);
 }
 
+
 static void
 agent_init_default_ctrl (ctrl_t ctrl)
 {
 static void
 agent_init_default_ctrl (ctrl_t ctrl)
 {
-  ctrl->connection_fd = -1;
+  assert (ctrl->session_env);
 
   /* Note we ignore malloc errors because we can't do much about it
      and the request will fail anyway shortly after this
      initialization. */
 
   /* 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)
-    free (ctrl->display);
-  ctrl->display = default_display? strdup (default_display) : NULL;
-
-  if (ctrl->ttyname)
-    free (ctrl->ttyname);
-  ctrl->ttyname = default_ttyname? strdup (default_ttyname) : NULL;
-
-  if (ctrl->ttytype)
-    free (ctrl->ttytype);
-  ctrl->ttytype = default_ttytype? strdup (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)
 
   if (ctrl->lc_ctype)
-    free (ctrl->lc_ctype);
-  ctrl->lc_ctype = default_lc_ctype? strdup (default_lc_ctype) : NULL;
+    xfree (ctrl->lc_ctype);
+  ctrl->lc_ctype = default_lc_ctype? xtrystrdup (default_lc_ctype) : NULL;
 
   if (ctrl->lc_messages)
 
   if (ctrl->lc_messages)
-    free (ctrl->lc_messages);
-  ctrl->lc_messages = default_lc_messages? strdup (default_lc_messages) : NULL;
+    xfree (ctrl->lc_messages);
+  ctrl->lc_messages = default_lc_messages? xtrystrdup (default_lc_messages)
+                                    /**/ : NULL;
 }
 
 
 static void
 agent_deinit_default_ctrl (ctrl_t ctrl)
 {
 }
 
 
 static void
 agent_deinit_default_ctrl (ctrl_t ctrl)
 {
-  if (ctrl->display)
-    free (ctrl->display);
-  if (ctrl->ttyname)
-    free (ctrl->ttyname);
-  if (ctrl->ttytype)
-    free (ctrl->ttytype);
+  session_env_release (ctrl->session_env);
+
   if (ctrl->lc_ctype)
   if (ctrl->lc_ctype)
-    free (ctrl->lc_ctype);
+    xfree (ctrl->lc_ctype);
   if (ctrl->lc_messages)
   if (ctrl->lc_messages)
-    free (ctrl->lc_messages);
+    xfree (ctrl->lc_messages);
 }
 
 }
 
+
 /* Reread parts of the configuration.  Note, that this function is
    obviously not thread-safe and should only be called from the PTH
 /* 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
 
    Fixme: Due to the way the argument parsing works, we create a
    memory leak here for all string type arguments.  There is currently
@@ -1140,8 +1397,8 @@ reread_configuration (void)
   fp = fopen (config_filename, "r");
   if (!fp)
     {
   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;
     }
 
       return;
     }
 
@@ -1184,6 +1441,50 @@ 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
+void *
+get_agent_scd_notify_event (void)
+{
+  static HANDLE the_event;
+
+  if (!the_event)
+    {
+      HANDLE h, h2;
+      SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
+
+      /* We need to use manual reset evet 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
+         handles using WFSO the event has already been reset due to
+         the WFMO.  */
+      h = CreateEvent (&sa, TRUE, FALSE, NULL);
+      if (!h)
+        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))
+        {
+          log_error ("setting syncronize for scd notify event failed: %s\n",
+                     w32_strerror (-1) );
+          CloseHandle (h);
+        }
+      else
+        {
+          CloseHandle (h);
+          the_event = h2;
+        }
+    }
+
+  log_debug  ("returning notify handle %p\n", the_event);
+  return the_event;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
 
 /* Create a name for the socket.  With USE_STANDARD_SOCKET given as
    true using STANDARD_NAME in the home directory or if given as
 
 /* Create a name for the socket.  With USE_STANDARD_SOCKET given as
    true using STANDARD_NAME in the home directory or if given as
@@ -1194,12 +1495,11 @@ get_agent_ssh_socket_name (void)
    terminates the process in case of an error.  Returns: Pointer to an
    allocated string with the absolute name of the socket used.  */
 static char *
    terminates the process in case of an error.  Returns: Pointer to an
    allocated string with the absolute name of the socket used.  */
 static char *
-create_socket_name (int use_standard_socket,
-                   char *standard_name, char *template)
+create_socket_name (char *standard_name, char *template)
 {
   char *name, *p;
 
 {
   char *name, *p;
 
-  if (use_standard_socket)
+  if (opt.use_standard_socket)
     name = make_filename (opt.homedir, standard_name, NULL);
   else
     {
     name = make_filename (opt.homedir, standard_name, NULL);
   else
     {
@@ -1232,74 +1532,81 @@ create_socket_name (int use_standard_socket,
 
 
 
 
 
 
-/* Create a Unix domain socket with NAME.  IS_STANDARD_NAME indicates
-   whether a non-random socket is used.  Returns the file descriptor or
-   terminates the process in case of an error. */
-static int
-create_server_socket (int is_standard_name, char *name)
+/* Create a Unix domain socket with NAME.  Returns the file descriptor
+   or terminates the process in case of an error.  Not that this
+   function needs to be used for the regular socket first and only
+   then for the ssh socket.  */
+static gnupg_fd_t
+create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
 {
   struct sockaddr_un *serv_addr;
   socklen_t len;
 {
   struct sockaddr_un *serv_addr;
   socklen_t len;
-  int fd;
+  gnupg_fd_t fd;
   int rc;
 
   int rc;
 
-#ifdef HAVE_W32_SYSTEM
-  fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
-#else
-  fd = socket (AF_UNIX, SOCK_STREAM, 0);
-#endif
-  if (fd == -1)
+  fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
+  if (fd == ASSUAN_INVALID_FD)
     {
       log_error (_("can't create socket: %s\n"), strerror (errno));
       agent_exit (2);
     }
 
     {
       log_error (_("can't create socket: %s\n"), strerror (errno));
       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;
   memset (serv_addr, 0, sizeof *serv_addr);
   serv_addr->sun_family = AF_UNIX;
-  assert (strlen (name) + 1 < sizeof (serv_addr->sun_path));
-  strcpy (serv_addr->sun_path, name);
-  len = (offsetof (struct sockaddr_un, sun_path)
-        + strlen (serv_addr->sun_path) + 1);
-
-#ifdef HAVE_W32_SYSTEM
-  rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len);
-  if (is_standard_name && rc == -1 && errno == WSAEADDRINUSE
-      && !no_reuse_standard_socket)
+  if (strlen (name) + 1 >= sizeof (serv_addr->sun_path))
     {
     {
-      remove (name);
-      rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len);
+      log_error (_("socket name `%s' is too long\n"), name);
+      agent_exit (2);
     }
     }
-#else
-  rc = bind (fd, (struct sockaddr*) serv_addr, len);
-  if (is_standard_name && rc == -1 && errno == EADDRINUSE  
-      && !no_reuse_standard_socket)
+  strcpy (serv_addr->sun_path, name);
+  len = SUN_LEN (serv_addr);
+  rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len);
+  if (opt.use_standard_socket && rc == -1 && errno == EADDRINUSE)
     {
     {
+      /* Check whether a gpg-agent is already running on the standard
+         socket.  We do this test only if this is not the ssh socket.
+         For ssh we assume that a test for gpg-agent has already been
+         done and reuse the requested ssh socket.  Testing the
+         ssh-socket is not possible because at this point, though we
+         know the new Assuan socket, the Assuan server and thus the
+         ssh-agent server is not yet operational.  This would lead to
+         a hang.  */
+      if (!is_ssh && !check_for_running_agent (1, 1))
+        {
+          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);
       remove (name);
-      rc = bind (fd, (struct sockaddr*) serv_addr, len);
+      rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len);
     }
     }
-#endif
+  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"),
   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, 
+                serv_addr->sun_path,
                  gpg_strerror (gpg_error_from_errno (errno)));
                  gpg_strerror (gpg_error_from_errno (errno)));
-      
-      close (fd);
-      if (is_standard_name && no_reuse_standard_socket)
+
+      assuan_sock_close (fd);
+      if (opt.use_standard_socket)
         *name = 0; /* Inhibit removal of the socket by cleanup(). */
       agent_exit (2);
     }
 
         *name = 0; /* Inhibit removal of the socket by cleanup(). */
       agent_exit (2);
     }
 
-  if (listen (fd, 5 ) == -1)
+  if (listen (FD2INT(fd), 5 ) == -1)
     {
       log_error (_("listen() failed: %s\n"), strerror (errno));
     {
       log_error (_("listen() failed: %s\n"), strerror (errno));
-      close (fd);
+      assuan_sock_close (fd);
       agent_exit (2);
     }
       agent_exit (2);
     }
-          
+
   if (opt.verbose)
     log_info (_("listening on socket `%s'\n"), serv_addr->sun_path);
 
   if (opt.verbose)
     log_info (_("listening on socket `%s'\n"), serv_addr->sun_path);
 
@@ -1344,10 +1651,7 @@ static void
 create_directories (void)
 {
   struct stat statbuf;
 create_directories (void)
 {
   struct stat statbuf;
-#ifdef HAVE_W32_SYSTEM
-#warning change it so that it works like in gpg.
-#endif
-  const char *defhome = GNUPG_DEFAULT_HOMEDIR;
+  const char *defhome = standard_homedir ();
   char *home;
 
   home = make_filename (opt.homedir, NULL);
   char *home;
 
   home = make_filename (opt.homedir, NULL);
@@ -1355,11 +1659,16 @@ create_directories (void)
     {
       if (errno == ENOENT)
         {
     {
       if (errno == ENOENT)
         {
-          if ( (*defhome == '~'
+          if (
+#ifdef HAVE_W32_SYSTEM
+              ( !compare_filenames (home, defhome) )
+#else
+              (*defhome == '~'
                 && (strlen (home) >= strlen (defhome+1)
                     && !strcmp (home + strlen(home)
                                 - strlen (defhome+1), defhome+1)))
                || (*defhome != '~' && !strcmp (home, defhome) )
                 && (strlen (home) >= strlen (defhome+1)
                     && !strcmp (home + strlen(home)
                                 - strlen (defhome+1), defhome+1)))
                || (*defhome != '~' && !strcmp (home, defhome) )
+#endif
                )
             {
 #ifdef HAVE_W32_SYSTEM
                )
             {
 #ifdef HAVE_W32_SYSTEM
@@ -1371,7 +1680,7 @@ create_directories (void)
                 log_error (_("can't create directory `%s': %s\n"),
                            home, strerror (errno) );
 #endif
                 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);
                 {
                   if (!opt.quiet)
                     log_info (_("directory `%s' created\n"), home);
@@ -1400,6 +1709,11 @@ create_directories (void)
 static void
 handle_tick (void)
 {
 static void
 handle_tick (void)
 {
+  static time_t last_minute;
+
+  if (!last_minute)
+    last_minute = time (NULL);
+
   /* Check whether the scdaemon has died and cleanup in this case. */
   agent_scd_check_aliveness ();
 
   /* Check whether the scdaemon has died and cleanup in this case. */
   agent_scd_check_aliveness ();
 
@@ -1411,13 +1725,47 @@ handle_tick (void)
       if (kill (parent_pid, 0))
         {
           shutdown_pending = 2;
       if (kill (parent_pid, 0))
         {
           shutdown_pending = 2;
-          log_info ("parent process died - shutting down\n");
-          log_info ("%s %s stopped\n", strusage(11), strusage(13) );
+          if (!opt.quiet)
+            {
+              log_info ("parent process died - shutting down\n");
+              log_info ("%s %s stopped\n", strusage(11), strusage(13) );
+            }
           cleanup ();
           agent_exit (0);
         }
     }
 #endif /*HAVE_W32_SYSTEM*/
           cleanup ();
           agent_exit (0);
         }
     }
 #endif /*HAVE_W32_SYSTEM*/
+
+  /* Code to be run every minute.  */
+  if (last_minute + 60 <= time (NULL))
+    {
+      check_own_socket ();
+      last_minute = time (NULL);
+    }
+
+}
+
+
+/* A global function which allows us to call the reload stuff from
+   other places too.  This is only used when build for W32.  */
+void
+agent_sighup_action (void)
+{
+  log_info ("SIGHUP received - "
+            "re-reading configuration and flushing cache\n");
+  agent_flush_cache ();
+  reread_configuration ();
+  agent_reload_trustlist ();
+}
+
+
+static void
+agent_sigusr2_action (void)
+{
+  if (opt.verbose)
+    log_info ("SIGUSR2 received - updating card event counter\n");
+  /* Nothing to check right now.  We only increment a counter.  */
+  bump_card_eventcounter ();
 }
 
 
 }
 
 
@@ -1428,25 +1776,18 @@ handle_signal (int signo)
     {
 #ifndef HAVE_W32_SYSTEM
     case SIGHUP:
     {
 #ifndef HAVE_W32_SYSTEM
     case SIGHUP:
-      log_info ("SIGHUP received - "
-                "re-reading configuration and flushing cache\n");
-      agent_flush_cache ();
-      reread_configuration ();
-      agent_reload_trustlist ();
+      agent_sighup_action ();
       break;
       break;
-      
+
     case SIGUSR1:
       log_info ("SIGUSR1 received - printing internal information:\n");
       pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ());
       agent_query_dump_state ();
       agent_scd_dump_state ();
       break;
     case SIGUSR1:
       log_info ("SIGUSR1 received - printing internal information:\n");
       pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ());
       agent_query_dump_state ();
       agent_scd_dump_state ();
       break;
-      
+
     case SIGUSR2:
     case SIGUSR2:
-      if (opt.verbose)
-        log_info ("SIGUSR2 received - checking smartcard status\n");
-      /* Nothing to check right now.  We only increment a counter.  */
-      bump_card_eventcounter ();
+      agent_sigusr2_action ();
       break;
 
     case SIGTERM:
       break;
 
     case SIGTERM:
@@ -1464,7 +1805,7 @@ handle_signal (int signo)
           agent_exit (0);
        }
       break;
           agent_exit (0);
        }
       break;
-        
+
     case SIGINT:
       log_info ("SIGINT received - immediate shutdown\n");
       log_info( "%s %s stopped\n", strusage(11), strusage(13));
     case SIGINT:
       log_info ("SIGINT received - immediate shutdown\n");
       log_info( "%s %s stopped\n", strusage(11), strusage(13));
@@ -1478,22 +1819,236 @@ 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
+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"),
+                FD2INT(ctrl->thread_startup.fd), strerror (errno));
+      assuan_sock_close (ctrl->thread_startup.fd);
+      xfree (ctrl);
+      return -1;
+    }
+  else
+    return 0;
+}
+
+
+#ifdef HAVE_W32_SYSTEM
+/* The window message processing function for Putty.  Warning: This
+   code runs as a native Windows thread.  Use of our own functions
+   needs to be bracket with pth_leave/pth_enter. */
+static LRESULT CALLBACK
+putty_message_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+  int ret = 0;
+  int w32rc;
+  COPYDATASTRUCT *cds;
+  const char *mapfile;
+  HANDLE maphd;
+  PSID mysid = NULL;
+  PSID mapsid = NULL;
+  void *data = NULL;
+  PSECURITY_DESCRIPTOR psd = NULL;
+  ctrl_t ctrl = NULL;
+
+  if (msg != WM_COPYDATA)
+    {
+      /* pth_leave (); */
+      /* log_debug ("putty loop: received WM_%u\n", msg ); */
+      /* pth_enter (); */
+      return DefWindowProc (hwnd, msg, wparam, lparam);
+    }
+
+  cds = (COPYDATASTRUCT*)lparam;
+  if (cds->dwData != PUTTY_IPC_MAGIC)
+    return 0;  /* Ignore data with the wrong magic.  */
+  mapfile = cds->lpData;
+  if (!cds->cbData || mapfile[cds->cbData - 1])
+    return 0;  /* Ignore empty and non-properly terminated strings.  */
+
+  if (DBG_ASSUAN)
+    {
+      pth_leave ();
+      log_debug ("ssh map file '%s'", mapfile);
+      pth_enter ();
+    }
+
+  maphd = OpenFileMapping (FILE_MAP_ALL_ACCESS, FALSE, mapfile);
+  if (DBG_ASSUAN)
+    {
+      pth_leave ();
+      log_debug ("ssh map handle %p\n", maphd);
+      pth_enter ();
+    }
+
+  if (!maphd || maphd == INVALID_HANDLE_VALUE)
+    return 0;
+
+  pth_leave ();
+
+  mysid = w32_get_user_sid ();
+  if (!mysid)
+    {
+      log_error ("error getting my sid\n");
+      goto leave;
+    }
+
+  w32rc = GetSecurityInfo (maphd, SE_KERNEL_OBJECT,
+                           OWNER_SECURITY_INFORMATION,
+                           &mapsid, NULL, NULL, NULL,
+                           &psd);
+  if (w32rc)
+    {
+      log_error ("error getting sid of ssh map file: rc=%d", w32rc);
+      goto leave;
+    }
+
+  if (DBG_ASSUAN)
+    {
+      char *sidstr;
+
+      if (!ConvertSidToStringSid (mysid, &sidstr))
+        sidstr = NULL;
+      log_debug ("          my sid: '%s'", sidstr? sidstr: "[error]");
+      LocalFree (sidstr);
+      if (!ConvertSidToStringSid (mapsid, &sidstr))
+        sidstr = NULL;
+      log_debug ("ssh map file sid: '%s'", sidstr? sidstr: "[error]");
+      LocalFree (sidstr);
+    }
+
+  if (!EqualSid (mysid, mapsid))
+    {
+      log_error ("ssh map file has a non-matching sid\n");
+      goto leave;
+    }
+
+  data = MapViewOfFile (maphd, FILE_MAP_ALL_ACCESS, 0, 0, 0);
+  if (DBG_ASSUAN)
+    log_debug ("ssh IPC buffer at %p\n", data);
+  if (!data)
+    goto leave;
+
+  /* log_printhex ("request:", data, 20); */
+
+  ctrl = xtrycalloc (1, sizeof *ctrl);
+  if (!ctrl)
+    {
+      log_error ("error allocating connection control data: %s\n",
+                 strerror (errno) );
+      goto leave;
+    }
+  ctrl->session_env = session_env_new ();
+  if (!ctrl->session_env)
+    {
+      log_error ("error allocating session environment block: %s\n",
+                 strerror (errno) );
+      goto leave;
+    }
+
+  agent_init_default_ctrl (ctrl);
+  if (!serve_mmapped_ssh_request (ctrl, data, PUTTY_IPC_MAXLEN))
+    ret = 1; /* Valid ssh message has been constructed.  */
+  agent_deinit_default_ctrl (ctrl);
+  /* log_printhex ("  reply:", data, 20); */
+
+ leave:
+  xfree (ctrl);
+  if (data)
+    UnmapViewOfFile (data);
+  xfree (mapsid);
+  if (psd)
+    LocalFree (psd);
+  xfree (mysid);
+  CloseHandle (maphd);
+
+  pth_enter ();
+
+  return ret;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+#ifdef HAVE_W32_SYSTEM
+/* The thread handling Putty's IPC requests.  */
+static void *
+putty_message_thread (void *arg)
+{
+  WNDCLASS wndwclass = {0, putty_message_proc, 0, 0,
+                        NULL, NULL, NULL, NULL, NULL, "Pageant"};
+  HWND hwnd;
+  MSG msg;
+
+  (void)arg;
+
+  if (opt.verbose)
+    log_info ("putty message loop thread 0x%lx started\n", pth_thread_id ());
+
+  /* The message loop runs as thread independet from out Pth system.
+     This also meand that we need to make sure that we switch back to
+     our system before calling any no-windows function.  */
+  pth_enter ();
+
+  /* First create a window to make sure that a message queue exists
+     for this thread.  */
+  if (!RegisterClass (&wndwclass))
+    {
+      pth_leave ();
+      log_error ("error registering Pageant window class");
+      return NULL;
+    }
+  hwnd = CreateWindowEx (0, "Pageant", "Pageant", 0,
+                         0, 0, 0, 0,
+                         HWND_MESSAGE,  /* hWndParent */
+                         NULL,          /* hWndMenu   */
+                         NULL,          /* hInstance  */
+                         NULL);         /* lpParm     */
+  if (!hwnd)
+    {
+      pth_leave ();
+      log_error ("error creating Pageant window");
+      return NULL;
+    }
+
+  while (GetMessage(&msg, NULL, 0, 0))
+    {
+      TranslateMessage(&msg);
+      DispatchMessage(&msg);
+    }
+
+  /* Back to Pth.  */
+  pth_leave ();
+
+  if (opt.verbose)
+    log_info ("putty message loop thread 0x%lx stopped\n", pth_thread_id ());
+  return NULL;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
 /* This is the standard connection thread's main function.  */
 static void *
 start_connection_thread (void *arg)
 {
   ctrl_t ctrl = arg;
 
 /* This is the standard connection thread's main function.  */
 static void *
 start_connection_thread (void *arg)
 {
   ctrl_t ctrl = arg;
 
+  if (check_nonce (ctrl, &socket_nonce))
+    return NULL;
+
   agent_init_default_ctrl (ctrl);
   if (opt.verbose)
   agent_init_default_ctrl (ctrl);
   if (opt.verbose)
-    log_info (_("handler 0x%lx for fd %d started\n"), 
-              (long)pth_self (), ctrl->thread_startup.fd);
+    log_info (_("handler 0x%lx for fd %d started\n"),
+              pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
 
 
-  start_command_handler (ctrl, -1, ctrl->thread_startup.fd);
+  start_command_handler (ctrl, GNUPG_INVALID_FD, ctrl->thread_startup.fd);
   if (opt.verbose)
   if (opt.verbose)
-    log_info (_("handler 0x%lx for fd %d terminated\n"), 
-              (long)pth_self (), ctrl->thread_startup.fd);
-  
+    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;
   agent_deinit_default_ctrl (ctrl);
   xfree (ctrl);
   return NULL;
@@ -1506,16 +2061,19 @@ start_connection_thread_ssh (void *arg)
 {
   ctrl_t ctrl = arg;
 
 {
   ctrl_t ctrl = arg;
 
+  if (check_nonce (ctrl, &socket_nonce_ssh))
+    return NULL;
+
   agent_init_default_ctrl (ctrl);
   if (opt.verbose)
     log_info (_("ssh handler 0x%lx for fd %d started\n"),
   agent_init_default_ctrl (ctrl);
   if (opt.verbose)
     log_info (_("ssh handler 0x%lx for fd %d started\n"),
-              (long)pth_self (), ctrl->thread_startup.fd);
+              pth_thread_id (), 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"),
 
   start_command_handler_ssh (ctrl, ctrl->thread_startup.fd);
   if (opt.verbose)
     log_info (_("ssh handler 0x%lx for fd %d terminated\n"),
-              (long)pth_self (), ctrl->thread_startup.fd);
-  
+              pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
+
   agent_deinit_default_ctrl (ctrl);
   xfree (ctrl);
   return NULL;
   agent_deinit_default_ctrl (ctrl);
   xfree (ctrl);
   return NULL;
@@ -1525,7 +2083,7 @@ start_connection_thread_ssh (void *arg)
 /* Connection handler loop.  Wait for connection requests and spawn a
    thread after accepting a connection.  */
 static void
 /* Connection handler loop.  Wait for connection requests and spawn a
    thread after accepting a connection.  */
 static void
-handle_connections (int listen_fd, int listen_fd_ssh)
+handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
 {
   pth_attr_t tattr;
   pth_event_t ev, time_ev;
 {
   pth_attr_t tattr;
   pth_event_t ev, time_ev;
@@ -1535,7 +2093,8 @@ handle_connections (int listen_fd, int listen_fd_ssh)
   socklen_t plen;
   fd_set fdset, read_fdset;
   int ret;
   socklen_t plen;
   fd_set fdset, read_fdset;
   int ret;
-  int fd;
+  gnupg_fd_t fd;
+  int nfd;
 
   tattr = pth_attr_new();
   pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
 
   tattr = pth_attr_new();
   pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
@@ -1543,51 +2102,102 @@ handle_connections (int listen_fd, int listen_fd_ssh)
 
 #ifndef HAVE_W32_SYSTEM /* fixme */
   /* Make sure that the signals we are going to handle are not blocked
 
 #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. */
+     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 );
   sigemptyset (&sigs );
-  sigaddset (&sigs, SIGHUP);
-  sigaddset (&sigs, SIGUSR1);
-  sigaddset (&sigs, SIGUSR2);
-  sigaddset (&sigs, SIGINT);
-  sigaddset (&sigs, SIGTERM);
+  {
+    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]);
+      }
+  }
+
   pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
   ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
 #else
   pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
   ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
 #else
-  ev = NULL;
+# ifdef PTH_EVENT_HANDLE
+  sigs = 0;
+  ev = pth_event (PTH_EVENT_HANDLE, get_agent_scd_notify_event ());
   signo = 0;
   signo = 0;
+# else
+  /* Use a dummy event. */
+  sigs = 0;
+  ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
+# endif
 #endif
   time_ev = NULL;
 
 #endif
   time_ev = NULL;
 
+  /* On Windows we need to fire up a separate thread to listen for
+     requests from Putty (an SSH client), so we can replace Putty's
+     Pageant (its ssh-agent implementation). */
+#ifdef HAVE_W32_SYSTEM
+  if (putty_support)
+    {
+      pth_attr_set (tattr, PTH_ATTR_NAME, "putty message loop");
+      if (!pth_spawn (tattr, putty_message_thread, NULL))
+        {
+          log_error ("error spawning putty message loop: %s\n",
+                     strerror (errno) );
+        }
+    }
+#endif /*HAVE_W32_SYSTEM*/
+
+  /* Set a flag to tell call-scd.c that it may enable event
+     notifications.  */
+  opt.sigusr2_enabled = 1;
+
   FD_ZERO (&fdset);
   FD_ZERO (&fdset);
-  FD_SET (listen_fd, &fdset);
-  if (listen_fd_ssh != -1)
-    FD_SET (listen_fd_ssh, &fdset);
+  FD_SET (FD2INT (listen_fd), &fdset);
+  nfd = FD2INT (listen_fd);
+  if (listen_fd_ssh != GNUPG_INVALID_FD)
+    {
+      FD_SET ( FD2INT(listen_fd_ssh), &fdset);
+      if (FD2INT (listen_fd_ssh) > nfd)
+        nfd = FD2INT (listen_fd_ssh);
+    }
 
   for (;;)
     {
 
   for (;;)
     {
-      sigset_t oldsigs;
-
-#ifdef HAVE_W32_SYSTEM
-      w32_poll_events ();
-#endif
+      /* 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)
             break; /* ready */
 
       if (shutdown_pending)
         {
           if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1)
             break; /* ready */
 
-          /* Do not accept anymore connections and wait for existing
-             connections to terminate */
-          signo = 0;
-          pth_wait (ev);
-          if (pth_event_occurred (ev) && signo)
-            handle_signal (signo);
-          continue;
+          /* Do not accept new connections but keep on running the
+             loop to cope with the timer events.  */
+          FD_ZERO (&fdset);
        }
 
        }
 
-      /* Create a timeout event if needed. */
+      /* Create a timeout event if needed.  To help with power saving
+         we syncronize the ticks to the next full second.  */
       if (!time_ev)
       if (!time_ev)
-        time_ev = pth_event (PTH_EVENT_TIME, pth_timeout (2, 0));
+        {
+          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.  */
 
       /* POSIX says that fd_set should be implemented as a structure,
          thus a simple assignment is fine to copy the entire set.  */
@@ -1595,7 +2205,7 @@ handle_connections (int listen_fd, int listen_fd_ssh)
 
       if (time_ev)
         pth_event_concat (ev, time_ev, NULL);
 
       if (time_ev)
         pth_event_concat (ev, time_ev, NULL);
-      ret = pth_select_ev (FD_SETSIZE, &read_fdset, NULL, NULL, NULL, ev);
+      ret = pth_select_ev (nfd+1, &read_fdset, NULL, NULL, NULL, ev);
       if (time_ev)
         pth_event_isolate (time_ev);
 
       if (time_ev)
         pth_event_isolate (time_ev);
 
@@ -1605,7 +2215,13 @@ handle_connections (int listen_fd, int listen_fd_ssh)
               || (time_ev && pth_event_occurred (time_ev)))
             {
               if (pth_event_occurred (ev))
               || (time_ev && pth_event_occurred (time_ev)))
             {
               if (pth_event_occurred (ev))
-                handle_signal (signo);
+                {
+#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);
               if (time_ev && pth_event_occurred (time_ev))
                 {
                   pth_event_free (time_ev, PTH_FREE_ALL);
@@ -1617,12 +2233,16 @@ handle_connections (int listen_fd, int listen_fd_ssh)
           log_error (_("pth_select failed: %s - waiting 1s\n"),
                      strerror (errno));
           pth_sleep (1);
           log_error (_("pth_select failed: %s - waiting 1s\n"),
                      strerror (errno));
           pth_sleep (1);
-         continue;
+          continue;
        }
 
       if (pth_event_occurred (ev))
         {
        }
 
       if (pth_event_occurred (ev))
         {
+#if defined(HAVE_W32_SYSTEM) && defined(PTH_EVENT_HANDLE)
+          agent_sigusr2_action ();
+#else
           handle_signal (signo);
           handle_signal (signo);
+#endif
         }
 
       if (time_ev && pth_event_occurred (time_ev))
         }
 
       if (time_ev && pth_event_occurred (time_ev))
@@ -1632,19 +2252,20 @@ handle_connections (int listen_fd, int listen_fd_ssh)
           handle_tick ();
         }
 
           handle_tick ();
         }
 
-      
+
       /* We now might create new threads and because we don't want any
       /* We now might create new threads and because we don't want any
-         signals - we are handling here - to be delivered to a new
-         thread. Thus we need to block those signals. */
-      pth_sigmask (SIG_BLOCK, &sigs, &oldsigs);
+         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 (FD_ISSET (listen_fd, &read_fdset))
+      if (!shutdown_pending && FD_ISSET (FD2INT (listen_fd), &read_fdset))
        {
           ctrl_t ctrl;
 
           plen = sizeof paddr;
        {
           ctrl_t ctrl;
 
           plen = sizeof paddr;
-         fd = pth_accept (listen_fd, (struct sockaddr *)&paddr, &plen);
-         if (fd == -1)
+         fd = INT2FD (pth_accept (FD2INT(listen_fd),
+                                   (struct sockaddr *)&paddr, &plen));
+         if (fd == GNUPG_INVALID_FD)
            {
              log_error ("accept failed: %s\n", strerror (errno));
            }
            {
              log_error ("accept failed: %s\n", strerror (errno));
            }
@@ -1652,14 +2273,21 @@ handle_connections (int listen_fd, int listen_fd_ssh)
             {
               log_error ("error allocating connection control data: %s\n",
                          strerror (errno) );
             {
               log_error ("error allocating connection control data: %s\n",
                          strerror (errno) );
-              close (fd);
+              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 
+          else
             {
               char threadname[50];
 
               snprintf (threadname, sizeof threadname-1,
             {
               char threadname[50];
 
               snprintf (threadname, sizeof threadname-1,
-                        "conn fd=%d (gpg)", fd);
+                        "conn fd=%d (gpg)", FD2INT(fd));
               threadname[sizeof threadname -1] = 0;
               pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
               ctrl->thread_startup.fd = fd;
               threadname[sizeof threadname -1] = 0;
               pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
               ctrl->thread_startup.fd = fd;
@@ -1667,20 +2295,22 @@ handle_connections (int listen_fd, int listen_fd_ssh)
                 {
                   log_error ("error spawning connection handler: %s\n",
                              strerror (errno) );
                 {
                   log_error ("error spawning connection handler: %s\n",
                              strerror (errno) );
-                  close (fd);
+                  assuan_sock_close (fd);
                   xfree (ctrl);
                 }
             }
                   xfree (ctrl);
                 }
             }
-          fd = -1;
+          fd = GNUPG_INVALID_FD;
        }
 
        }
 
-      if (listen_fd_ssh != -1 && FD_ISSET (listen_fd_ssh, &read_fdset))
+      if (!shutdown_pending && listen_fd_ssh != GNUPG_INVALID_FD
+          && FD_ISSET ( FD2INT (listen_fd_ssh), &read_fdset))
        {
           ctrl_t ctrl;
 
           plen = sizeof paddr;
        {
           ctrl_t ctrl;
 
           plen = sizeof paddr;
-         fd = pth_accept (listen_fd_ssh, (struct sockaddr *)&paddr, &plen);
-         if (fd == -1)
+         fd = INT2FD(pth_accept (FD2INT(listen_fd_ssh),
+                                  (struct sockaddr *)&paddr, &plen));
+         if (fd == GNUPG_INVALID_FD)
            {
              log_error ("accept failed for ssh: %s\n", strerror (errno));
            }
            {
              log_error ("accept failed for ssh: %s\n", strerror (errno));
            }
@@ -1688,7 +2318,14 @@ handle_connections (int listen_fd, int listen_fd_ssh)
             {
               log_error ("error allocating connection control data: %s\n",
                          strerror (errno) );
             {
               log_error ("error allocating connection control data: %s\n",
                          strerror (errno) );
-              close (fd);
+              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
             {
             }
           else
             {
@@ -1696,7 +2333,7 @@ handle_connections (int listen_fd, int listen_fd_ssh)
 
               agent_init_default_ctrl (ctrl);
               snprintf (threadname, sizeof threadname-1,
 
               agent_init_default_ctrl (ctrl);
               snprintf (threadname, sizeof threadname-1,
-                        "conn fd=%d (ssh)", fd);
+                        "conn fd=%d (ssh)", FD2INT(fd));
               threadname[sizeof threadname -1] = 0;
               pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
               ctrl->thread_startup.fd = fd;
               threadname[sizeof threadname -1] = 0;
               pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
               ctrl->thread_startup.fd = fd;
@@ -1704,16 +2341,12 @@ handle_connections (int listen_fd, int listen_fd_ssh)
                 {
                   log_error ("error spawning ssh connection handler: %s\n",
                              strerror (errno) );
                 {
                   log_error ("error spawning ssh connection handler: %s\n",
                              strerror (errno) );
-                  close (fd);
+                  assuan_sock_close (fd);
                   xfree (ctrl);
                 }
             }
                   xfree (ctrl);
                 }
             }
-          fd = -1;
+          fd = GNUPG_INVALID_FD;
        }
        }
-
-      /* Restore the signal mask. */
-      pth_sigmask (SIG_SETMASK, &oldsigs, NULL);
-
     }
 
   pth_event_free (ev, PTH_FREE_ALL);
     }
 
   pth_event_free (ev, PTH_FREE_ALL);
@@ -1724,14 +2357,128 @@ handle_connections (int listen_fd, int listen_fd_ssh)
 }
 
 
 }
 
 
+
+/* Helper for check_own_socket.  */
+static gpg_error_t
+check_own_socket_pid_cb (void *opaque, const void *buffer, size_t length)
+{
+  membuf_t *mb = opaque;
+  put_membuf (mb, buffer, length);
+  return 0;
+}
+
+
+/* The thread running the actual check.  We need to run this in a
+   separate thread so that check_own_thread can be called from the
+   timer tick.  */
+static void *
+check_own_socket_thread (void *arg)
+{
+  int rc;
+  char *sockname = arg;
+  assuan_context_t ctx = NULL;
+  membuf_t mb;
+  char *buffer;
+
+  check_own_socket_running++;
+
+  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);
+  put_membuf (&mb, "", 1);
+  buffer = get_membuf (&mb, NULL);
+  if (rc || !buffer)
+    {
+      log_error ("sending command \"%s\" to my own socket failed: %s\n",
+                 "GETINFO pid", gpg_strerror (rc));
+      rc = 1;
+    }
+  else if ( (pid_t)strtoul (buffer, NULL, 10) != getpid ())
+    {
+      log_error ("socket is now serviced by another server\n");
+      rc = 1;
+    }
+  else if (opt.verbose > 1)
+    log_error ("socket is still served by this server\n");
+
+  xfree (buffer);
+
+ leave:
+  xfree (sockname);
+  if (ctx)
+    assuan_release (ctx);
+  if (rc)
+    {
+      /* We may not remove the socket as it is now in use by another
+         server.  Setting the name to empty does this.  */
+      if (socket_name)
+        *socket_name = 0;
+      if (socket_name_ssh)
+        *socket_name_ssh = 0;
+      shutdown_pending = 2;
+      log_info ("this process is useless - shutting down\n");
+    }
+  check_own_socket_running--;
+  return NULL;
+}
+
+
+/* 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
+   better check once in a while whether we are really needed.  */
+static void
+check_own_socket (void)
+{
+  char *sockname;
+  pth_attr_t tattr;
+
+  if (!opt.use_standard_socket)
+    return; /* This check makes only sense in standard socket mode.  */
+
+  if (check_own_socket_running || shutdown_pending)
+    return;  /* Still running or already shutting down.  */
+
+  sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
+  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);
+}
+
+
+
 /* Figure out whether an agent is available and running. Prints an
 /* Figure out whether an agent is available and running. Prints an
-   error if not.  Usually started with MODE 0. */
+   error if not.  If SILENT is true, no messages are printed.  Usually
+   started with MODE 0.  Returns 0 if the agent is running. */
 static int
 static int
-check_for_running_agent (int mode)
+check_for_running_agent (int silent, int mode)
 {
   int rc;
   char *infostr, *p;
 {
   int rc;
   char *infostr, *p;
-  assuan_context_t ctx;
+  assuan_context_t ctx = NULL;
   int prot, pid;
 
   if (!mode)
   int prot, pid;
 
   if (!mode)
@@ -1739,9 +2486,10 @@ check_for_running_agent (int mode)
       infostr = getenv ("GPG_AGENT_INFO");
       if (!infostr || !*infostr)
         {
       infostr = getenv ("GPG_AGENT_INFO");
       if (!infostr || !*infostr)
         {
-          if (!check_for_running_agent (1))
+          if (!check_for_running_agent (silent, 1))
             return 0; /* Okay, its running on the standard socket. */
             return 0; /* Okay, its running on the standard socket. */
-          log_error (_("no gpg-agent running in this session\n"));
+          if (!silent)
+            log_error (_("no gpg-agent running in this session\n"));
           return -1;
         }
 
           return -1;
         }
 
@@ -1749,9 +2497,10 @@ check_for_running_agent (int mode)
       if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
         {
           xfree (infostr);
       if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
         {
           xfree (infostr);
-          if (!check_for_running_agent (1))
+          if (!check_for_running_agent (silent, 1))
             return 0; /* Okay, its running on the standard socket. */
             return 0; /* Okay, its running on the standard socket. */
-          log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
+          if (!silent)
+            log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
           return -1;
         }
 
           return -1;
         }
 
@@ -1763,9 +2512,10 @@ check_for_running_agent (int mode)
       if (prot != 1)
         {
           xfree (infostr);
       if (prot != 1)
         {
           xfree (infostr);
-          log_error (_("gpg-agent protocol version %d is not supported\n"),
-                     prot);
-          if (!check_for_running_agent (1))
+          if (!silent)
+            log_error (_("gpg-agent protocol version %d is not supported\n"),
+                       prot);
+          if (!check_for_running_agent (silent, 1))
             return 0; /* Okay, its running on the standard socket. */
           return -1;
         }
             return 0; /* Okay, its running on the standard socket. */
           return -1;
         }
@@ -1776,22 +2526,26 @@ check_for_running_agent (int mode)
       pid = (pid_t)(-1);
     }
 
       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)
     {
   xfree (infostr);
   if (rc)
     {
-      if (!mode && !check_for_running_agent (1))
+      if (!mode && !check_for_running_agent (silent, 1))
         return 0; /* Okay, its running on the standard socket. */
 
         return 0; /* Okay, its running on the standard socket. */
 
-      if (!mode)
+      if (!mode && !silent)
         log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
         log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
+
+      if (ctx)
+       assuan_release (ctx);
       return -1;
     }
 
       return -1;
     }
 
-  if (!opt.quiet)
+  if (!opt.quiet && !silent)
     log_info ("gpg-agent running and available\n");
 
     log_info ("gpg-agent running and available\n");
 
-  assuan_disconnect (ctx);
+  assuan_release (ctx);
   return 0;
 }
   return 0;
 }