po: Auto-update
[gnupg.git] / agent / gpg-agent.c
index e65198a..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>
 #ifdef HAVE_SIGNAL_H
 # include <signal.h>
 #endif
-#ifdef HAVE_INOTIFY_INIT
-# include <sys/inotify.h>
-#endif /*HAVE_INOTIFY_INIT*/
 #include <npth.h>
 
 #define GNUPG_COMMON_NEED_AFLOCAL
 #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"
 
 
@@ -86,10 +83,12 @@ enum cmd_and_opt_values
   oNoOptions,
   oHomedir,
   oNoDetach,
+  oGrab,
   oNoGrab,
   oLogFile,
   oServer,
   oDaemon,
+  oSupervised,
   oBatch,
 
   oPinentryProgram,
@@ -113,6 +112,7 @@ enum cmd_and_opt_values
   oCheckPassphrasePattern,
   oMaxPassphraseDays,
   oEnablePassphraseHistory,
+  oEnableExtendedKeyFormat,
   oUseStandardSocket,
   oNoUseStandardSocket,
   oExtraSocket,
@@ -130,9 +130,14 @@ enum cmd_and_opt_values
   oKeepTTY,
   oKeepDISPLAY,
   oSSHSupport,
+  oSSHFingerprintDigest,
   oPuttySupport,
   oDisableScdaemon,
   oDisableCheckOwnSocket,
+  oS2KCount,
+  oAutoExpandSecmem,
+  oListenBacklog,
+
   oWriteEnvFile
 };
 
@@ -152,6 +157,9 @@ static ARGPARSE_OPTS opts[] = {
 
   ARGPARSE_s_n (oDaemon,  "daemon", N_("run in daemon mode (background)")),
   ARGPARSE_s_n (oServer,  "server", N_("run in server mode (foreground)")),
+#ifndef HAVE_W32_SYSTEM
+  ARGPARSE_s_n (oSupervised,  "supervised", N_("run in supervised mode")),
+#endif
   ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
   ARGPARSE_s_n (oQuiet,          "quiet",     N_("be somewhat more quiet")),
   ARGPARSE_s_n (oSh,     "sh",        N_("sh-style command output")),
@@ -161,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")),
@@ -230,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")
@@ -237,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"  },
@@ -271,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
 
@@ -303,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
@@ -321,6 +340,12 @@ static int check_own_socket_running;
 /* Flags to indicate that check_own_socket shall not be called.  */
 static int disable_check_own_socket;
 
+/* Flag indicating that we are in supervised mode.  */
+static int is_supervised;
+
+/* Flag to inhibit socket removal in cleanup.  */
+static int inhibit_socket_removal;
+
 /* It is possible that we are currently running under setuid permissions */
 static int maybe_setuid = 1;
 
@@ -338,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;
 
@@ -349,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;
@@ -369,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;
@@ -513,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;
@@ -566,6 +604,168 @@ remove_socket (char *name, char *redir_name)
 }
 
 
+/* 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",
+ * "extra", and "browser".  "std" or other labels will be interpreted
+ * as the standard socket.
+ *
+ * This function is designed to log errors when the expected file
+ * descriptors don't make sense, but to do its best to continue to
+ * work even in the face of minor misconfigurations.
+ *
+ * For more information on the LISTEN_FDS convention, see
+ * sd_listen_fds(3) on certain Linux distributions.
+ */
+#ifndef HAVE_W32_SYSTEM
+static void
+map_supervised_sockets (gnupg_fd_t *r_fd,
+                        gnupg_fd_t *r_fd_extra,
+                        gnupg_fd_t *r_fd_browser,
+                        gnupg_fd_t *r_fd_ssh)
+{
+  struct {
+    const char *label;
+    int **fdaddr;
+    char **nameaddr;
+  } tbl[] = {
+    { "ssh",     &r_fd_ssh,     &socket_name_ssh },
+    { "browser", &r_fd_browser, &socket_name_browser },
+    { "extra",   &r_fd_extra,   &socket_name_extra },
+    { "std",     &r_fd,         &socket_name }  /* (Must be the last item.)  */
+  };
+  const char *envvar;
+  char **fdnames;
+  int nfdnames;
+  int fd_count;
+
+  *r_fd = *r_fd_extra = *r_fd_browser = *r_fd_ssh = -1;
+
+  /* Print a warning if LISTEN_PID does not match outr pid.  */
+  envvar = getenv ("LISTEN_PID");
+  if (!envvar)
+    log_error ("no LISTEN_PID environment variable found in "
+               "--supervised mode (ignoring)\n");
+  else if (strtoul (envvar, NULL, 10) != (unsigned long)getpid ())
+    log_error ("environment variable LISTEN_PID (%lu) does not match"
+               " our pid (%lu) in --supervised mode (ignoring)\n",
+               (unsigned long)strtoul (envvar, NULL, 10),
+               (unsigned long)getpid ());
+
+  /* Parse LISTEN_FDNAMES into the array FDNAMES.  */
+  envvar = getenv ("LISTEN_FDNAMES");
+  if (envvar)
+    {
+      fdnames = strtokenize (envvar, ":");
+      if (!fdnames)
+        {
+          log_error ("strtokenize failed: %s\n",
+                     gpg_strerror (gpg_error_from_syserror ()));
+          agent_exit (1);
+        }
+      for (nfdnames=0; fdnames[nfdnames]; nfdnames++)
+        ;
+    }
+  else
+    {
+      fdnames = NULL;
+      nfdnames = 0;
+    }
+
+  /* Parse LISTEN_FDS into fd_count or provide a replacement.  */
+  envvar = getenv ("LISTEN_FDS");
+  if (envvar)
+    fd_count = atoi (envvar);
+  else if (fdnames)
+    {
+      log_error ("no LISTEN_FDS environment variable found in --supervised"
+                 " mode (relying on LISTEN_FDNAMES instead)\n");
+      fd_count = nfdnames;
+    }
+  else
+    {
+      log_error ("no LISTEN_FDS or LISTEN_FDNAMES environment variables "
+                "found in --supervised mode"
+                " (assuming 1 active descriptor)\n");
+      fd_count = 1;
+    }
+
+  if (fd_count < 1)
+    {
+      log_error ("--supervised mode expects at least one file descriptor"
+                 " (was told %d, carrying on as though it were 1)\n",
+                 fd_count);
+      fd_count = 1;
+    }
+
+  /* Assign the descriptors to the return values.  */
+  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"
+                   " if LISTEN_FDNAMES is not set\n");
+      *r_fd = 3;
+      socket_name = gnupg_get_socket_name (3);
+    }
+  else if (fd_count != nfdnames)
+    {
+      log_fatal ("number of items in LISTEN_FDNAMES (%d) does not match "
+                 "LISTEN_FDS (%d) in --supervised mode\n",
+                 nfdnames, fd_count);
+    }
+  else
+    {
+      int i, j, fd;
+      char *name;
+
+      for (i = 0; i < nfdnames; i++)
+        {
+          for (j = 0; j < DIM (tbl); j++)
+            {
+              if (!strcmp (fdnames[i], tbl[j].label) || j == DIM(tbl)-1)
+                {
+                  fd = 3 + i;
+                  if (**tbl[j].fdaddr == -1)
+                    {
+                      name = gnupg_get_socket_name (fd);
+                      if (name)
+                        {
+                          **tbl[j].fdaddr = fd;
+                          *tbl[j].nameaddr = name;
+                          log_info ("using fd %d for %s socket (%s)\n",
+                                    fd, tbl[j].label, name);
+                        }
+                      else
+                        {
+                          log_error ("cannot listen on fd %d for %s socket\n",
+                                     fd, tbl[j].label);
+                          close (fd);
+                        }
+                    }
+                  else
+                    {
+                      log_error ("cannot listen on more than one %s socket\n",
+                                 tbl[j].label);
+                      close (fd);
+                    }
+                  break;
+                }
+            }
+        }
+    }
+
+  xfree (fdnames);
+}
+#endif /*!HAVE_W32_SYSTEM*/
+
+
 /* Cleanup code for this program.  This is either called has an atexit
    handler or directly.  */
 static void
@@ -577,12 +777,15 @@ cleanup (void)
     return;
   done = 1;
   deinitialize_module_cache ();
-  remove_socket (socket_name, redir_socket_name);
-  if (opt.extra_socket > 1)
-    remove_socket (socket_name_extra, redir_socket_name_extra);
-  if (opt.browser_socket > 1)
-    remove_socket (socket_name_browser, redir_socket_name_browser);
-  remove_socket (socket_name_ssh, redir_socket_name_ssh);
+  if (!is_supervised && !inhibit_socket_removal)
+    {
+      remove_socket (socket_name, redir_socket_name);
+      if (opt.extra_socket > 1)
+        remove_socket (socket_name_extra, redir_socket_name_extra);
+      if (opt.browser_socket > 1)
+        remove_socket (socket_name_browser, redir_socket_name_browser);
+      remove_socket (socket_name_ssh, redir_socket_name_ssh);
+    }
 }
 
 
@@ -595,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;
@@ -617,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;
@@ -625,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;
     }
 
@@ -652,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;
@@ -684,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;
@@ -703,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 */
     }
@@ -715,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;
 }
 
 
@@ -728,8 +957,18 @@ thread_init_once (void)
       npth_initialized++;
       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
 }
 
+
 static void
 initialize_modules (void)
 {
@@ -769,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;
@@ -794,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 ();
@@ -873,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;
 
   /*
@@ -954,6 +1196,7 @@ main (int argc, char **argv )
         case oSh: csh_style = 0; break;
         case oServer: pipe_server = 1; break;
         case oDaemon: is_daemon = 1; break;
+        case oSupervised: is_supervised = 1; break;
 
         case oDisplay: default_display = xstrdup (pargs.r.ret_str); break;
         case oTTYname: default_ttyname = xstrdup (pargs.r.ret_str); break;
@@ -984,6 +1227,7 @@ main (int argc, char **argv )
        case oSSHSupport:
           ssh_support = 1;
           break;
+
         case oPuttySupport:
 #        ifdef HAVE_W32_SYSTEM
           putty_support = 1;
@@ -1000,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;
@@ -1053,9 +1309,9 @@ main (int argc, char **argv )
     bind_textdomain_codeset (PACKAGE_GT, "UTF-8");
 #endif
 
-  if (!pipe_server && !is_daemon && !gpgconf_list)
+  if (!pipe_server && !is_daemon && !gpgconf_list && !is_supervised)
     {
-     /* We have been called without any options and thus we merely
+     /* We have been called without any command and thus we merely
         check whether an agent is already running.  We do this right
         here so that we don't clobber a logfile with this check but
         print the status directly to stderr. */
@@ -1065,10 +1321,10 @@ main (int argc, char **argv )
       agent_exit (0);
     }
 
-  if (! opt.extra_socket)
-    {
-      opt.extra_socket = 1;
-    }
+  if (is_supervised)
+    ;
+  else if (!opt.extra_socket)
+    opt.extra_socket = 1;
   else if (socket_name_extra
            && (!strcmp (socket_name_extra, "none")
                || !strcmp (socket_name_extra, "/dev/null")))
@@ -1078,10 +1334,10 @@ main (int argc, char **argv )
       socket_name_extra = NULL;
     }
 
-  if (! opt.browser_socket)
-    {
-      opt.browser_socket = 1;
-    }
+  if (is_supervised)
+    ;
+  else if (!opt.browser_socket)
+    opt.browser_socket = 1;
   else if (socket_name_browser
            && (!strcmp (socket_name_browser, "none")
                || !strcmp (socket_name_browser, "/dev/null")))
@@ -1177,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
@@ -1186,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);
     }
@@ -1234,6 +1496,50 @@ main (int argc, char **argv )
       agent_deinit_default_ctrl (ctrl);
       xfree (ctrl);
     }
+  else if (is_supervised)
+    {
+#ifndef HAVE_W32_SYSTEM
+      gnupg_fd_t fd, fd_extra, fd_browser, fd_ssh;
+
+      initialize_modules ();
+
+      /* when supervised and sending logs to stderr, the process
+         supervisor should handle log entry metadata (pid, name,
+         timestamp) */
+      if (!logfile)
+        log_set_prefix (NULL, 0);
+
+      log_info ("%s %s starting in supervised mode.\n",
+                strusage(11), strusage(13) );
+
+      /* See below in "regular server mode" on why we remove certain
+       * envvars.  */
+      if (!opt.keep_display)
+        gnupg_unsetenv ("DISPLAY");
+      gnupg_unsetenv ("INSIDE_EMACS");
+
+      /* Virtually create the sockets.  Note that we use -1 here
+       * because the whole thing works only on Unix. */
+      map_supervised_sockets (&fd, &fd_extra, &fd_browser, &fd_ssh);
+      if (fd == -1)
+        log_fatal ("no standard socket provided\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*/
+
+      log_info ("listening on: std=%d extra=%d browser=%d ssh=%d\n",
+                fd, fd_extra, fd_browser, fd_ssh);
+      handle_connections (fd, fd_extra, fd_browser, fd_ssh);
+#endif /*!HAVE_W32_SYSTEM*/
+    }
   else if (!is_daemon)
     ; /* NOTREACHED */
   else
@@ -1305,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)
         {
@@ -1454,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;
         }
 
       {
@@ -1472,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);
@@ -1526,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
 }
 
 
@@ -1651,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)
@@ -1860,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)
@@ -1897,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);
@@ -1909,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);
     }
 
@@ -1921,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;
 }
 
@@ -2024,6 +2365,7 @@ static void
 handle_tick (void)
 {
   static time_t last_minute;
+  struct stat statbuf;
 
   if (!last_minute)
     last_minute = time (NULL);
@@ -2056,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");
+    }
 }
 
 
@@ -2090,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)
 {
@@ -2143,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)
@@ -2452,31 +2802,6 @@ start_connection_thread_ssh (void *arg)
 }
 
 
-#ifdef HAVE_INOTIFY_INIT
-/* Read an inotify event and return true if it matches NAME.  */
-static int
-my_inotify_is_name (int fd, const char *name)
-{
-  union {
-    struct inotify_event ev;
-    char _buf[sizeof (struct inotify_event) + 100 + 1];
-  } buf;
-  int n;
-
-  n = npth_read (fd, &buf, sizeof buf);
-  if (n < sizeof (struct inotify_event))
-    return 0;
-  if (buf.ev.len < strlen (name)+1)
-    return 0;
-  if (strcmp (buf.ev.name, name))
-    return 0; /* Not the desired file.  */
-
-  return 1; /* Found.  */
-}
-#endif /*HAVE_INOTIFY_INIT*/
-
-
-
 /* Connection handler loop.  Wait for connection requests and spawn a
    thread after accepting a connection.  */
 static void
@@ -2485,6 +2810,7 @@ handle_connections (gnupg_fd_t listen_fd,
                     gnupg_fd_t listen_fd_browser,
                     gnupg_fd_t listen_fd_ssh)
 {
+  gpg_error_t err;
   npth_attr_t tattr;
   struct sockaddr_un paddr;
   socklen_t plen;
@@ -2500,9 +2826,8 @@ handle_connections (gnupg_fd_t listen_fd,
   HANDLE events[2];
   unsigned int events_set;
 #endif
-#ifdef HAVE_INOTIFY_INIT
-  int my_inotify_fd;
-#endif /*HAVE_INOTIFY_INIT*/
+  int sock_inotify_fd = -1;
+  int home_inotify_fd = -1;
   struct {
     const char *name;
     void *(*func) (void *arg);
@@ -2540,27 +2865,26 @@ handle_connections (gnupg_fd_t listen_fd,
 # endif
 #endif
 
-#ifdef HAVE_INOTIFY_INIT
   if (disable_check_own_socket)
-    my_inotify_fd = -1;
-  else if ((my_inotify_fd = inotify_init ()) == -1)
-    log_info ("error enabling fast daemon termination: %s\n",
-              strerror (errno));
-  else
+    sock_inotify_fd = -1;
+  else if ((err = gnupg_inotify_watch_socket (&sock_inotify_fd, socket_name)))
     {
-      /* We need to watch the directory for the file because there
-       * won't be an IN_DELETE_SELF for a socket file.  */
-      char *slash = strrchr (socket_name, '/');
-      log_assert (slash && slash[1]);
-      *slash = 0;
-      if (inotify_add_watch (my_inotify_fd, socket_name, IN_DELETE) == -1)
-        {
-          close (my_inotify_fd);
-          my_inotify_fd = -1;
-        }
-      *slash = '/';
+      if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED)
+        log_info ("error enabling daemon termination by socket removal: %s\n",
+                  gpg_strerror (err));
     }
-#endif /*HAVE_INOTIFY_INIT*/
+
+  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 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
@@ -2603,14 +2927,18 @@ handle_connections (gnupg_fd_t listen_fd,
       if (FD2INT (listen_fd_ssh) > nfd)
         nfd = FD2INT (listen_fd_ssh);
     }
-#ifdef HAVE_INOTIFY_INIT
-  if (my_inotify_fd != -1)
+  if (sock_inotify_fd != -1)
     {
-      FD_SET (my_inotify_fd, &fdset);
-      if (my_inotify_fd > nfd)
-        nfd = my_inotify_fd;
+      FD_SET (sock_inotify_fd, &fdset);
+      if (sock_inotify_fd > nfd)
+        nfd = sock_inotify_fd;
+    }
+  if (home_inotify_fd != -1)
+    {
+      FD_SET (home_inotify_fd, &fdset);
+      if (home_inotify_fd > nfd)
+        nfd = home_inotify_fd;
     }
-#endif /*HAVE_INOTIFY_INIT*/
 
   listentbl[0].l_fd = listen_fd;
   listentbl[1].l_fd = listen_fd_extra;
@@ -2629,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,
@@ -2679,21 +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;
 
-#ifdef HAVE_INOTIFY_INIT
-          if (my_inotify_fd != -1 && FD_ISSET (my_inotify_fd, &read_fdset)
-              && my_inotify_is_name (my_inotify_fd, GPG_AGENT_SOCK_NAME))
-            {
-              shutdown_pending = 1;
-              log_info ("socket file has been removed - shutting down\n");
-            }
-#endif /*HAVE_INOTIFY_INIT*/
-
           for (idx=0; idx < DIM(listentbl); idx++)
             {
               if (listentbl[idx].l_fd == GNUPG_INVALID_FD)
@@ -2735,15 +3093,14 @@ handle_connections (gnupg_fd_t listen_fd,
                       xfree (ctrl);
                     }
                 }
-              fd = GNUPG_INVALID_FD;
             }
         }
     }
 
-#ifdef HAVE_INOTIFY_INIT
-  if (my_inotify_fd != -1)
-    close (my_inotify_fd);
-#endif /*HAVE_INOTIFY_INIT*/
+  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);
@@ -2818,11 +3175,8 @@ check_own_socket_thread (void *arg)
   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;
+         server. */
+      inhibit_socket_removal = 1;
       shutdown_pending = 2;
       log_info ("this process is useless - shutting down\n");
     }