po: Auto-update
[gnupg.git] / agent / gpg-agent.c
index 8e2d012..a1964ec 100644 (file)
@@ -15,7 +15,7 @@
  * 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, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include "agent.h"
 #include <assuan.h> /* Malloc hooks  and socket wrappers. */
 
-#include "i18n.h"
-#include "sysutils.h"
-#include "gc-opt-flags.h"
-#include "exechelp.h"
-#include "asshelp.h"
+#include "../common/i18n.h"
+#include "../common/sysutils.h"
+#include "../common/gc-opt-flags.h"
+#include "../common/exechelp.h"
+#include "../common/asshelp.h"
 #include "../common/init.h"
 
 
@@ -83,6 +83,7 @@ enum cmd_and_opt_values
   oNoOptions,
   oHomedir,
   oNoDetach,
+  oGrab,
   oNoGrab,
   oLogFile,
   oServer,
@@ -111,6 +112,7 @@ enum cmd_and_opt_values
   oCheckPassphrasePattern,
   oMaxPassphraseDays,
   oEnablePassphraseHistory,
+  oEnableExtendedKeyFormat,
   oUseStandardSocket,
   oNoUseStandardSocket,
   oExtraSocket,
@@ -128,9 +130,14 @@ enum cmd_and_opt_values
   oKeepTTY,
   oKeepDISPLAY,
   oSSHSupport,
+  oSSHFingerprintDigest,
   oPuttySupport,
   oDisableScdaemon,
   oDisableCheckOwnSocket,
+  oS2KCount,
+  oAutoExpandSecmem,
+  oListenBacklog,
+
   oWriteEnvFile
 };
 
@@ -162,12 +169,15 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oDebug,             "debug",       "@"),
   ARGPARSE_s_n (oDebugAll,   "debug-all",   "@"),
   ARGPARSE_s_s (oDebugLevel, "debug-level", "@"),
-  ARGPARSE_s_i (oDebugWait,"  debug-wait",  "@"),
+  ARGPARSE_s_i (oDebugWait,  "debug-wait",  "@"),
   ARGPARSE_s_n (oDebugQuickRandom, "debug-quick-random", "@"),
   ARGPARSE_s_n (oDebugPinentry, "debug-pinentry", "@"),
 
   ARGPARSE_s_n (oNoDetach,  "no-detach", N_("do not detach from the console")),
-  ARGPARSE_s_n (oNoGrab,    "no-grab",   N_("do not grab keyboard and mouse")),
+  ARGPARSE_s_n (oGrab,      "grab",      "@"),
+                /* FIXME: Add the below string for 2.3 */
+                /* N_("let PIN-Entry grab keyboard and mouse")), */
+  ARGPARSE_s_n (oNoGrab,    "no-grab",   "@"),
   ARGPARSE_s_s (oLogFile,   "log-file",  N_("use a log file for the server")),
   ARGPARSE_s_s (oPinentryProgram, "pinentry-program",
                 /* */             N_("|PGM|use PGM as the PIN-Entry program")),
@@ -231,6 +241,8 @@ static ARGPARSE_OPTS opts[] = {
                 /* */    N_("allow passphrase to be prompted through Emacs")),
 
   ARGPARSE_s_n (oSSHSupport,   "enable-ssh-support", N_("enable ssh support")),
+  ARGPARSE_s_s (oSSHFingerprintDigest, "ssh-fingerprint-digest",
+                N_("|ALGO|use ALGO to show ssh fingerprints")),
   ARGPARSE_s_n (oPuttySupport, "enable-putty-support",
 #ifdef HAVE_W32_SYSTEM
                 /* */           N_("enable putty support")
@@ -238,20 +250,26 @@ static ARGPARSE_OPTS opts[] = {
                 /* */           "@"
 #endif
                 ),
+  ARGPARSE_s_n (oEnableExtendedKeyFormat, "enable-extended-key-format", "@"),
+
+  ARGPARSE_s_u (oS2KCount, "s2k-count", "@"),
+
+  ARGPARSE_op_u (oAutoExpandSecmem, "auto-expand-secmem", "@"),
+
+  ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"),
 
   /* Dummy options for backward compatibility.  */
   ARGPARSE_o_s (oWriteEnvFile, "write-env-file", "@"),
   ARGPARSE_s_n (oUseStandardSocket, "use-standard-socket", "@"),
   ARGPARSE_s_n (oNoUseStandardSocket, "no-use-standard-socket", "@"),
 
-  {0} /* End of list */
+  ARGPARSE_end () /* End of list */
 };
 
 
 /* The list of supported debug flags.  */
 static struct debug_flags_s debug_flags [] =
   {
-    { DBG_COMMAND_VALUE, "command"  },
     { DBG_MPI_VALUE    , "mpi"     },
     { DBG_CRYPTO_VALUE , "crypto"  },
     { DBG_MEMORY_VALUE , "memory"  },
@@ -272,19 +290,17 @@ static struct debug_flags_s debug_flags [] =
 #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.  CHECK_OWN_SOCKET_INTERVAL defines how often we
-   check our own socket in standard socket mode.  If that value is 0
-   we don't check at all.   All values are in seconds. */
+/* The timer tick used for housekeeping stuff.  Note that on Windows
+ * we use a SetWaitableTimer seems to signal earlier than about 2
+ * seconds.  Thus we use 4 seconds on all platforms except for
+ * Windowsce.  CHECK_OWN_SOCKET_INTERVAL defines how often we check
+ * our own socket in standard socket mode.  If that value is 0 we
+ * don't check at all.  All values are in seconds. */
 #if defined(HAVE_W32CE_SYSTEM)
 # define TIMERTICK_INTERVAL         (60)
 # define CHECK_OWN_SOCKET_INTERVAL   (0)  /* Never */
-#elif defined(HAVE_W32_SYSTEM)
-# define TIMERTICK_INTERVAL          (4)
-# define CHECK_OWN_SOCKET_INTERVAL  (60)
 #else
-# define TIMERTICK_INTERVAL          (2)
+# define TIMERTICK_INTERVAL          (4)
 # define CHECK_OWN_SOCKET_INTERVAL  (60)
 #endif
 
@@ -304,8 +320,10 @@ static int putty_support;
 #endif /*HAVE_W32_SYSTEM*/
 
 /* The list of open file descriptors at startup.  Note that this list
-   has been allocated using the standard malloc.  */
+ * has been allocated using the standard malloc.  */
+#ifndef HAVE_W32_SYSTEM
 static int *startup_fd_list;
+#endif
 
 /* The signal mask at startup and a flag telling whether it is valid.  */
 #ifdef HAVE_SIGPROCMASK
@@ -345,7 +363,7 @@ static char *redir_socket_name_extra;
 static char *socket_name_browser;
 static char *redir_socket_name_browser;
 
-/* Name of the communication socket used for ssh-agent-emulation.  */
+/* Name of the communication socket used for ssh-agent protocol.  */
 static char *socket_name_ssh;
 static char *redir_socket_name_ssh;
 
@@ -356,6 +374,10 @@ static assuan_sock_nonce_t socket_nonce_extra;
 static assuan_sock_nonce_t socket_nonce_browser;
 static assuan_sock_nonce_t socket_nonce_ssh;
 
+/* Value for the listen() backlog argument.  We use the same value for
+ * all sockets - 64 is on current Linux half of the default maximum.
+ * Let's try this as default.  Change at runtime with --listen-backlog.  */
+static int listen_backlog = 64;
 
 /* Default values for options passed to the pinentry. */
 static char *default_display;
@@ -376,17 +398,27 @@ static const char *debug_level;
 static char *current_logfile;
 
 /* The handle_tick() function may test whether a parent is still
-   running.  We record the PID of the parent here or -1 if it should be
  watched. */
+ * running.  We record the PID of the parent here or -1 if it should
* be watched.  */
 static pid_t parent_pid = (pid_t)(-1);
 
+/* This flag is true if the inotify mechanism for detecting the
+ * removal of the homedir is active.  This flag is used to disable the
+ * alternative but portable stat based check.  */
+static int have_homedir_inotify;
+
+/* Depending on how gpg-agent was started, the homedir inotify watch
+ * may not be reliable.  This flag is set if we assume that inotify
+ * works reliable.  */
+static int reliable_homedir_inotify;
+
 /* Number of active connections.  */
 static int active_connections;
 
 /* This object is used to dispatch progress messages from Libgcrypt to
- * the right thread.  Given that we won't have at max a few dozen
- * connections at the same time using a linked list is the easiest way
- * to handle this. */
+ * the right thread.  Given that we will have at max only a few dozen
+ * connections at a time, using a linked list is the easiest way to
+ * handle this. */
 struct progress_dispatch_s
 {
   struct progress_dispatch_s *next;
@@ -520,10 +552,9 @@ set_debug (void)
   else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
     opt.debug = DBG_IPC_VALUE;
   else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
-    opt.debug = DBG_IPC_VALUE|DBG_COMMAND_VALUE;
+    opt.debug = DBG_IPC_VALUE;
   else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
-    opt.debug = (DBG_IPC_VALUE|DBG_COMMAND_VALUE
-                 |DBG_CACHE_VALUE);
+    opt.debug = (DBG_IPC_VALUE | DBG_CACHE_VALUE);
   else if (!strcmp (debug_level, "guru") || numok)
     {
       opt.debug = ~0;
@@ -573,52 +604,6 @@ remove_socket (char *name, char *redir_name)
 }
 
 
-/* Return a malloc'ed string that is the path to the passed
- * unix-domain socket (or return NULL if this is not a valid
- * unix-domain socket).  We use a plain int here because it is only
- * used on Linux.
- *
- * FIXME: This function needs to be moved to libassuan.  */
-#ifndef HAVE_W32_SYSTEM
-static char *
-get_socket_name (int fd)
-{
-  struct sockaddr_un un;
-  socklen_t len = sizeof(un);
-  char *name = NULL;
-
-  if (getsockname (fd, (struct sockaddr*)&un, &len) != 0)
-    log_error ("could not getsockname(%d): %s\n", fd,
-               gpg_strerror (gpg_error_from_syserror ()));
-  else if (un.sun_family != AF_UNIX)
-    log_error ("file descriptor %d is not a unix-domain socket\n", fd);
-  else if (len <= offsetof (struct sockaddr_un, sun_path))
-    log_error ("socket name not present for file descriptor %d\n", fd);
-  else if (len > sizeof(un))
-    log_error ("socket name for file descriptor %d was truncated "
-               "(passed %zu bytes, wanted %u)\n", fd, sizeof(un), len);
-  else
-    {
-      size_t namelen = len - offsetof (struct sockaddr_un, sun_path);
-
-      log_debug ("file descriptor %d has path %s (%zu octets)\n", fd,
-                 un.sun_path, namelen);
-      name = xtrymalloc (namelen + 1);
-      if (!name)
-        log_error ("failed to allocate memory for name of fd %d: %s\n",
-                   fd, gpg_strerror (gpg_error_from_syserror ()));
-      else
-        {
-          memcpy (name, un.sun_path, namelen);
-          name[namelen] = 0;
-        }
-    }
-
-  return name;
-}
-#endif /*!HAVE_W32_SYSTEM*/
-
-
 /* Discover which inherited file descriptors correspond to which
  * services/sockets offered by gpg-agent, using the LISTEN_FDS and
  * LISTEN_FDNAMES convention.  The understood labels are "ssh",
@@ -717,18 +702,17 @@ map_supervised_sockets (gnupg_fd_t *r_fd,
   if (!fdnames)
     {
       struct stat statbuf;
+
       if (fd_count != 1)
         log_error ("no LISTEN_FDNAMES and LISTEN_FDS (%d) != 1"
                    " in --supervised mode."
                    " (ignoring all sockets but the first one)\n",
                    fd_count);
       if (fstat (3, &statbuf) == -1 && errno ==EBADF)
-        log_fatal ("file descriptor 3 must be valid in --supervised mode (as the "
-                   "agent's standard socket) if LISTEN_FDNAMES is not set\n");
+        log_fatal ("file descriptor 3 must be valid in --supervised mode"
+                   " if LISTEN_FDNAMES is not set\n");
       *r_fd = 3;
-      socket_name = get_socket_name (3);
-      if (!socket_name)
-          log_error ("cannot learn socket name for fd 3\n");
+      socket_name = gnupg_get_socket_name (3);
     }
   else if (fd_count != nfdnames)
     {
@@ -750,7 +734,7 @@ map_supervised_sockets (gnupg_fd_t *r_fd,
                   fd = 3 + i;
                   if (**tbl[j].fdaddr == -1)
                     {
-                      name = get_socket_name (fd);
+                      name = gnupg_get_socket_name (fd);
                       if (name)
                         {
                           **tbl[j].fdaddr = fd;
@@ -814,12 +798,14 @@ cleanup (void)
 static int
 parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
 {
+  int i;
+
   if (!pargs)
     { /* reset mode */
       opt.quiet = 0;
       opt.verbose = 0;
       opt.debug = 0;
-      opt.no_grab = 0;
+      opt.no_grab = 1;
       opt.debug_pinentry = 0;
       opt.pinentry_program = NULL;
       opt.pinentry_touch_file = NULL;
@@ -836,7 +822,8 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       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.enable_passphrase_history = 0;
+      opt.enable_extended_key_format = 0;
       opt.ignore_cache_for_signing = 0;
       opt.allow_mark_trusted = 1;
       opt.allow_external_cache = 1;
@@ -844,6 +831,9 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       opt.allow_emacs_pinentry = 0;
       opt.disable_scdaemon = 0;
       disable_check_own_socket = 0;
+      /* Note: When changing the next line, change also gpgconf_list.  */
+      opt.ssh_fingerprint_digest = GCRY_MD_MD5;
+      opt.s2k_count = 0;
       return 1;
     }
 
@@ -871,7 +861,8 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
         }
       break;
 
-    case oNoGrab: opt.no_grab = 1; break;
+    case oNoGrab: opt.no_grab |= 1; break;
+    case oGrab: opt.no_grab |= 2; break;
 
     case oPinentryProgram: opt.pinentry_program = pargs->r.ret_str; break;
     case oPinentryTouchFile: opt.pinentry_touch_file = pargs->r.ret_str; break;
@@ -903,7 +894,11 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       opt.max_passphrase_days = pargs->r.ret_ulong;
       break;
     case oEnablePassphraseHistory:
-      opt.enable_passhrase_history = 1;
+      opt.enable_passphrase_history = 1;
+      break;
+
+    case oEnableExtendedKeyFormat:
+      opt.enable_extended_key_format = 1;
       break;
 
     case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
@@ -922,6 +917,18 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
     case oAllowEmacsPinentry: opt.allow_emacs_pinentry = 1;
       break;
 
+    case oSSHFingerprintDigest:
+      i = gcry_md_map_name (pargs->r.ret_str);
+      if (!i)
+        log_error (_("selected digest algorithm is invalid\n"));
+      else
+        opt.ssh_fingerprint_digest = i;
+      break;
+
+    case oS2KCount:
+      opt.s2k_count = pargs->r.ret_ulong;
+      break;
+
     default:
       return 0; /* not handled */
     }
@@ -934,6 +941,9 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
 static void
 finalize_rereadable_options (void)
 {
+  /* Hack to allow --grab to override --no-grab.  */
+  if ((opt.no_grab & 2))
+    opt.no_grab = 0;
 }
 
 
@@ -948,6 +958,14 @@ thread_init_once (void)
       npth_init ();
     }
   gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
+  /* Now that we have set the syscall clamp we need to tell Libgcrypt
+   * that it should get them from libgpg-error.  Note that Libgcrypt
+   * has already been initialized but at that point nPth was not
+   * initialized and thus Libgcrypt could not set its system call
+   * clamp.  */
+#if GCRYPT_VERSION_NUMBER >= 0x010800 /* 1.8.0 */
+  gcry_control (GCRYCTL_REINIT_SYSCALL_CLAMP, 0, 0);
+#endif
 }
 
 
@@ -990,8 +1008,10 @@ main (int argc, char **argv )
 
   /* 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. */
+     do the exec call properly.  We don't need it on Windows.  */
+#ifndef HAVE_W32_SYSTEM
   startup_fd_list = get_all_open_fds ();
+#endif /*!HAVE_W32_SYSTEM*/
 #ifdef HAVE_SIGPROCMASK
   if (!sigprocmask (SIG_UNBLOCK, NULL, &startup_signal_mask))
     startup_signal_mask_valid = 1;
@@ -1015,6 +1035,7 @@ main (int argc, char **argv )
   assuan_set_malloc_hooks (&malloc_hooks);
   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
   assuan_sock_init ();
+  assuan_sock_set_system_hooks (ASSUAN_SYSTEM_NPTH);
   setup_libassuan_logging (&opt.debug, NULL);
 
   setup_libgcrypt_logging ();
@@ -1094,7 +1115,7 @@ main (int argc, char **argv )
     }
 
   /* Initialize the secure memory. */
-  gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
+  gcry_control (GCRYCTL_INIT_SECMEM, SECMEM_BUFFER_SIZE, 0);
   maybe_setuid = 0;
 
   /*
@@ -1206,6 +1227,7 @@ main (int argc, char **argv )
        case oSSHSupport:
           ssh_support = 1;
           break;
+
         case oPuttySupport:
 #        ifdef HAVE_W32_SYSTEM
           putty_support = 1;
@@ -1222,6 +1244,18 @@ main (int argc, char **argv )
           socket_name_browser = pargs.r.ret_str;
           break;
 
+        case oAutoExpandSecmem:
+          /* Try to enable this option.  It will officially only be
+           * supported by Libgcrypt 1.9 but 1.8.2 already supports it
+           * on the quiet and thus we use the numeric value value.  */
+          gcry_control (78 /*GCRYCTL_AUTO_EXPAND_SECMEM*/,
+                        (unsigned int)pargs.r.ret_ulong,  0);
+          break;
+
+        case oListenBacklog:
+          listen_backlog = pargs.r.ret_int;
+          break;
+
         case oDebugQuickRandom:
           /* Only used by the first stage command line parser.  */
           break;
@@ -1399,6 +1433,8 @@ main (int argc, char **argv )
       es_printf ("disable-scdaemon:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
       es_printf ("enable-ssh-support:%lu:\n", GC_OPT_FLAG_NONE);
+      es_printf ("ssh-fingerprint-digest:%lu:\"%s:\n",
+                 GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, "md5");
 #ifdef HAVE_W32_SYSTEM
       es_printf ("enable-putty-support:%lu:\n", GC_OPT_FLAG_NONE);
 #endif
@@ -1408,6 +1444,10 @@ main (int argc, char **argv )
                  GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
       es_printf ("pinentry-timeout:%lu:0:\n",
                  GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME);
+      es_printf ("enable-extended-key-format:%lu:\n",
+                 GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
+      es_printf ("grab:%lu:\n",
+                 GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
 
       agent_exit (0);
     }
@@ -1512,8 +1552,6 @@ main (int argc, char **argv )
       pid_t pid;
 #endif
 
-      initialize_modules ();
-
       /* Remove the DISPLAY variable so that a pinentry does not
          default to a specific display.  There is still a default
          display when gpg-agent was started using --display or a
@@ -1573,10 +1611,15 @@ main (int argc, char **argv )
         parent_pid = getpid ();
 
       fflush (NULL);
+
 #ifdef HAVE_W32_SYSTEM
+
       (void)csh_style;
       (void)nodetach;
+      initialize_modules ();
+
 #else /*!HAVE_W32_SYSTEM*/
+
       pid = fork ();
       if (pid == (pid_t)-1)
         {
@@ -1722,12 +1765,12 @@ main (int argc, char **argv )
           log_get_prefix (&oldflags);
           log_set_prefix (NULL, oldflags | GPGRT_LOG_RUN_DETACHED);
           opt.running_detached = 1;
-        }
 
-      if (chdir("/"))
-        {
-          log_error ("chdir to / failed: %s\n", strerror (errno));
-          exit (1);
+          /* Unless we are running with a program given on the command
+           * line we can assume that the inotify things works and thus
+           * we can avoid tye regular stat calls.  */
+          if (!argc)
+            reliable_homedir_inotify = 1;
         }
 
       {
@@ -1740,6 +1783,13 @@ main (int argc, char **argv )
       }
 #endif /*!HAVE_W32_SYSTEM*/
 
+      if (gnupg_chdir (gnupg_daemon_rootdir ()))
+        {
+          log_error ("chdir to '%s' failed: %s\n",
+                     gnupg_daemon_rootdir (), strerror (errno));
+          exit (1);
+        }
+
       log_info ("%s %s started\n", strusage(11), strusage(13) );
       handle_connections (fd, fd_extra, fd_browser, fd_ssh);
       assuan_sock_close (fd);
@@ -1794,6 +1844,23 @@ agent_libgcrypt_progress_cb (void *data, const char *what, int printchar,
       break;
   if (dispatch && dispatch->cb)
     dispatch->cb (dispatch->ctrl, what, printchar, current, total);
+
+  /* Libgcrypt < 1.8 does not know about nPth and thus when it reads
+   * from /dev/random this will block the process.  To mitigate this
+   * problem we yield the thread when Libgcrypt tells us that it needs
+   * more entropy.  This way other threads have chance to run.  */
+#if GCRYPT_VERSION_NUMBER < 0x010800 /* 1.8.0 */
+  if (what && !strcmp (what, "need_entropy"))
+    {
+#if GPGRT_VERSION_NUMBER < 0x011900 /* 1.25 */
+      /* In older gpg-error versions gpgrt_yield is buggy for use with
+       * nPth and thus we need to resort to a sleep call.  */
+      npth_usleep (1000); /* 1ms */
+#else
+      gpgrt_yield ();
+#endif
+    }
+#endif
 }
 
 
@@ -1919,7 +1986,7 @@ agent_copy_startup_env (ctrl_t ctrl)
   const char *value;
 
   for (idx=0; !err && names[idx]; idx++)
-      if ((value = session_env_getenv (opt.startup_env, names[idx])))
+    if ((value = session_env_getenv (opt.startup_env, names[idx])))
       err = session_env_setenv (ctrl->session_env, names[idx], value);
 
   if (!err && !ctrl->lc_ctype && opt.startup_lc_ctype)
@@ -2128,6 +2195,7 @@ create_server_socket (char *name, int primary, int cygwin,
           log_error ("error preparing socket '%s': %s\n",
                      name, gpg_strerror (gpg_error_from_syserror ()));
         *name = 0; /* Inhibit removal of the socket by cleanup(). */
+        xfree (unaddr);
         agent_exit (2);
       }
     if (redirected)
@@ -2165,6 +2233,7 @@ create_server_socket (char *name, int primary, int cygwin,
                        "not starting a new one\n"));
           *name = 0; /* Inhibit removal of the socket by cleanup(). */
           assuan_sock_close (fd);
+          xfree (unaddr);
           agent_exit (2);
         }
       gnupg_remove (unaddr->sun_path);
@@ -2177,11 +2246,12 @@ create_server_socket (char *name, int primary, int cygwin,
       /* 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"),
-                unaddr->sun_path,
+                 unaddr->sun_path,
                  gpg_strerror (gpg_error_from_syserror ()));
 
       assuan_sock_close (fd);
       *name = 0; /* Inhibit removal of the socket by cleanup(). */
+      xfree (unaddr);
       agent_exit (2);
     }
 
@@ -2189,17 +2259,20 @@ create_server_socket (char *name, int primary, int cygwin,
     log_error (_("can't set permissions of '%s': %s\n"),
                unaddr->sun_path, strerror (errno));
 
-  if (listen (FD2INT(fd), 5 ) == -1)
+  if (listen (FD2INT(fd), listen_backlog ) == -1)
     {
-      log_error (_("listen() failed: %s\n"), strerror (errno));
+      log_error ("listen(fd,%d) failed: %s\n",
+                 listen_backlog, strerror (errno));
       *name = 0; /* Inhibit removal of the socket by cleanup(). */
       assuan_sock_close (fd);
+      xfree (unaddr);
       agent_exit (2);
     }
 
   if (opt.verbose)
     log_info (_("listening on socket '%s'\n"), unaddr->sun_path);
 
+  xfree (unaddr);
   return fd;
 }
 
@@ -2292,6 +2365,7 @@ static void
 handle_tick (void)
 {
   static time_t last_minute;
+  struct stat statbuf;
 
   if (!last_minute)
     last_minute = time (NULL);
@@ -2324,6 +2398,14 @@ handle_tick (void)
     }
 #endif
 
+  /* Check whether the homedir is still available.  */
+  if (!shutdown_pending
+      && (!have_homedir_inotify || !reliable_homedir_inotify)
+      && stat (gnupg_homedir (), &statbuf) && errno == ENOENT)
+    {
+      shutdown_pending = 1;
+      log_info ("homedir has been removed - shutting down\n");
+    }
 }
 
 
@@ -2358,7 +2440,7 @@ agent_sigusr2_action (void)
 
 #ifndef HAVE_W32_SYSTEM
 /* The signal handler for this program.  It is expected to be run in
-   its own trhead and not in the context of a signal handler.  */
+   its own thread and not in the context of a signal handler.  */
 static void
 handle_signal (int signo)
 {
@@ -2411,7 +2493,7 @@ handle_signal (int signo)
 }
 #endif
 
-/* Check the nonce on a new connection.  This is a NOP unless we we
+/* Check the nonce on a new connection.  This is a NOP unless we
    are using our Unix domain socket emulation under Windows.  */
 static int
 check_nonce (ctrl_t ctrl, assuan_sock_nonce_t *nonce)
@@ -2744,7 +2826,8 @@ handle_connections (gnupg_fd_t listen_fd,
   HANDLE events[2];
   unsigned int events_set;
 #endif
-  int my_inotify_fd = -1;
+  int sock_inotify_fd = -1;
+  int home_inotify_fd = -1;
   struct {
     const char *name;
     void *(*func) (void *arg);
@@ -2783,13 +2866,25 @@ handle_connections (gnupg_fd_t listen_fd,
 #endif
 
   if (disable_check_own_socket)
-    my_inotify_fd = -1;
-  else if ((err = gnupg_inotify_watch_socket (&my_inotify_fd, socket_name)))
+    sock_inotify_fd = -1;
+  else if ((err = gnupg_inotify_watch_socket (&sock_inotify_fd, socket_name)))
+    {
+      if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED)
+        log_info ("error enabling daemon termination by socket removal: %s\n",
+                  gpg_strerror (err));
+    }
+
+  if (disable_check_own_socket)
+    home_inotify_fd = -1;
+  else if ((err = gnupg_inotify_watch_delete_self (&home_inotify_fd,
+                                                   gnupg_homedir ())))
     {
       if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED)
-        log_info ("error enabling fast daemon termination: %s\n",
+        log_info ("error enabling daemon termination by homedir removal: %s\n",
                   gpg_strerror (err));
     }
+  else
+    have_homedir_inotify = 1;
 
   /* 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
@@ -2832,11 +2927,17 @@ handle_connections (gnupg_fd_t listen_fd,
       if (FD2INT (listen_fd_ssh) > nfd)
         nfd = FD2INT (listen_fd_ssh);
     }
-  if (my_inotify_fd != -1)
+  if (sock_inotify_fd != -1)
+    {
+      FD_SET (sock_inotify_fd, &fdset);
+      if (sock_inotify_fd > nfd)
+        nfd = sock_inotify_fd;
+    }
+  if (home_inotify_fd != -1)
     {
-      FD_SET (my_inotify_fd, &fdset);
-      if (my_inotify_fd > nfd)
-        nfd = my_inotify_fd;
+      FD_SET (home_inotify_fd, &fdset);
+      if (home_inotify_fd > nfd)
+        nfd = home_inotify_fd;
     }
 
   listentbl[0].l_fd = listen_fd;
@@ -2856,8 +2957,25 @@ handle_connections (gnupg_fd_t listen_fd,
             break; /* ready */
 
           /* Do not accept new connections but keep on running the
-             loop to cope with the timer events.  */
+           * loop to cope with the timer events.
+           *
+           * Note that we do not close the listening socket because a
+           * client trying to connect to that socket would instead
+           * restart a new dirmngr instance - which is unlikely the
+           * intention of a shutdown. */
           FD_ZERO (&fdset);
+          nfd = -1;
+          if (sock_inotify_fd != -1)
+            {
+              FD_SET (sock_inotify_fd, &fdset);
+              nfd = sock_inotify_fd;
+            }
+          if (home_inotify_fd != -1)
+            {
+              FD_SET (home_inotify_fd, &fdset);
+              if (home_inotify_fd > nfd)
+                nfd = home_inotify_fd;
+            }
        }
 
       /* POSIX says that fd_set should be implemented as a structure,
@@ -2906,20 +3024,34 @@ handle_connections (gnupg_fd_t listen_fd,
           next timeout.  */
        continue;
 
+      /* The inotify fds are set even when a shutdown is pending (see
+       * above).  So we must handle them in any case.  To avoid that
+       * they trigger a second time we close them immediately.  */
+      if (sock_inotify_fd != -1
+          && FD_ISSET (sock_inotify_fd, &read_fdset)
+          && gnupg_inotify_has_name (sock_inotify_fd, GPG_AGENT_SOCK_NAME))
+        {
+          shutdown_pending = 1;
+          close (sock_inotify_fd);
+          sock_inotify_fd = -1;
+          log_info ("socket file has been removed - shutting down\n");
+        }
+
+      if (home_inotify_fd != -1
+          && FD_ISSET (home_inotify_fd, &read_fdset))
+        {
+          shutdown_pending = 1;
+          close (home_inotify_fd);
+          home_inotify_fd = -1;
+          log_info ("homedir has been removed - shutting down\n");
+        }
+
       if (!shutdown_pending)
         {
           int idx;
           ctrl_t ctrl;
           npth_t thread;
 
-          if (my_inotify_fd != -1
-              && FD_ISSET (my_inotify_fd, &read_fdset)
-              && gnupg_inotify_has_name (my_inotify_fd, GPG_AGENT_SOCK_NAME))
-            {
-              shutdown_pending = 1;
-              log_info ("socket file has been removed - shutting down\n");
-            }
-
           for (idx=0; idx < DIM(listentbl); idx++)
             {
               if (listentbl[idx].l_fd == GNUPG_INVALID_FD)
@@ -2961,13 +3093,14 @@ handle_connections (gnupg_fd_t listen_fd,
                       xfree (ctrl);
                     }
                 }
-              fd = GNUPG_INVALID_FD;
             }
         }
     }
 
-  if (my_inotify_fd != -1)
-    close (my_inotify_fd);
+  if (sock_inotify_fd != -1)
+    close (sock_inotify_fd);
+  if (home_inotify_fd != -1)
+    close (home_inotify_fd);
   cleanup ();
   log_info (_("%s %s stopped\n"), strusage(11), strusage(13));
   npth_attr_destroy (&tattr);