Enhanced last patch.
[gnupg.git] / agent / gpg-agent.c
index ba98b38..6cb0840 100644 (file)
@@ -1,6 +1,6 @@
 /* gpg-agent.c  -  The GnuPG Agent
  * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005,
- *               2006, 2007 Free Software Foundation, Inc.
+ *               2006, 2007, 2009 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -81,6 +81,7 @@ enum cmd_and_opt_values
   oTTYtype,
   oLCctype,
   oLCmessages,
+  oXauthority,
   oScdaemonProgram,
   oDefCacheTTL,
   oDefCacheTTLSSH,
@@ -140,12 +141,16 @@ static ARGPARSE_OPTS opts[] = {
   { 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, "@" },
-  { 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")},
 
@@ -192,9 +197,14 @@ static ARGPARSE_OPTS opts[] = {
 #define TIMERTICK_INTERVAL    (2)    /* Seconds.  */
 #endif
 
-/* flag to indicate that a shutdown was requested */
+/* Flag to indicate that a shutdown was requested.  */
 static int shutdown_pending;
 
+/* Counter for the currently running own socket checks.  */
+static int check_own_socket_running;
+
+/* True if we are listening on the standard socket.  */
+static int use_standard_socket;
 
 /* It is possible that we are currently running under setuid permissions */
 static int maybe_setuid = 1;
@@ -217,6 +227,7 @@ static char *default_ttyname;
 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;
@@ -238,9 +249,8 @@ static pid_t parent_pid = (pid_t)(-1);
    Local prototypes. 
  */
 
-static char *create_socket_name (int use_standard_socket,
-                                 char *standard_name, char *template);
-static gnupg_fd_t 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);
 
@@ -249,6 +259,7 @@ static void agent_deinit_default_ctrl (ctrl_t ctrl);
 
 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. */
@@ -259,17 +270,43 @@ static int fixed_gcry_pth_init (void)
 }
 
 
+#ifndef PTH_HAVE_PTH_THREAD_ID
+static unsigned long pth_thread_id (void)
+{
+  return (unsigned long)pth_self ();
+}
+#endif
+
 
 \f
 /*
    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 char *ver_gcry;
   const char *p;
+
   switch (level)
     {
     case 11: p = "gpg-agent (GnuPG)";
@@ -278,6 +315,12 @@ my_strusage (int level)
     case 17: p = PRINTABLE_OS_NAME; break;
     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
       break;
+    case 20:
+      if (!ver_gcry)
+        ver_gcry = make_libversion ("libgcrypt", gcry_check_version);
+      p = ver_gcry;
+      break;
+
     case 1:
     case 40: p =  _("Usage: gpg-agent [options] (-h for help)");
       break;
@@ -483,7 +526,6 @@ main (int argc, char **argv )
   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;
 
@@ -496,9 +538,9 @@ main (int argc, char **argv )
   log_set_prefix ("gpg-agent", JNLIB_LOG_WITH_PREFIX|JNLIB_LOG_WITH_PID); 
 
   /* Make sure that our subsystems are ready.  */
+  i18n_init ();
   init_common_subsystems ();
 
-  i18n_init ();
 
   /* Libgcrypt requires us to register the threading model first.
      Note that this will also do the pth_init. */
@@ -532,8 +574,8 @@ main (int argc, char **argv )
   /* 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.  */
+  use_standard_socket = 1;  /* Under Windows we always use a standard
+                               socket.  */
 #endif
   
   shell = getenv ("SHELL");
@@ -559,6 +601,12 @@ main (int argc, char **argv )
   opt.startup_lc_messages = getenv ("LC_MESSAGES");
   if (opt.startup_lc_messages)
     opt.startup_lc_messages = xstrdup (opt.startup_lc_messages);
+  opt.startup_xauthority = getenv ("XAUTHORITY");
+  if (opt.startup_xauthority)
+    opt.startup_xauthority = xstrdup (opt.startup_xauthority);
+  opt.startup_pinentry_user_data = getenv ("PINENTRY_USER_DATA");
+  if (opt.startup_pinentry_user_data)
+    opt.startup_pinentry_user_data = xstrdup (opt.startup_pinentry_user_data);
 
   /* Check whether we have a config file on the commandline */
   orig_argc = argc;
@@ -662,10 +710,11 @@ 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 oXauthority: default_xauthority = xstrdup (pargs.r.ret_str);
           break;
 
-        case oUseStandardSocket: standard_socket = 1; break;
-        case oNoUseStandardSocket: standard_socket = 0; break;
+        case oUseStandardSocket: use_standard_socket = 1; break;
+        case oNoUseStandardSocket: use_standard_socket = 0; break;
 
         case oFakedSystemTime:
           {
@@ -829,6 +878,7 @@ main (int argc, char **argv )
                              |JNLIB_LOG_WITH_TIME
                              |JNLIB_LOG_WITH_PID));
       current_logfile = xstrdup (logfile);
+      assuan_set_assuan_log_stream (log_get_stream ());
     }
 
   /* Make sure that we have a default ttyname. */
@@ -876,19 +926,15 @@ main (int argc, char **argv )
 
 
       /* 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)
-       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,
-                                 &socket_nonce);
+      fd = create_server_socket (socket_name, 0, &socket_nonce);
       if (opt.ssh_support)
-       fd_ssh = create_server_socket (standard_socket, socket_name_ssh,
-                                       &socket_nonce_ssh);
+       fd_ssh = create_server_socket (socket_name_ssh, 1, &socket_nonce_ssh);
       else
        fd_ssh = GNUPG_INVALID_FD;
 
@@ -1023,11 +1069,11 @@ main (int argc, char **argv )
                      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)
                {
-                 free (infostr_ssh_sock);
-                 free (infostr_ssh_pid);
+                 xfree (infostr_ssh_sock);
+                 xfree (infostr_ssh_pid);
                }
               exit (0); 
             }
@@ -1121,24 +1167,34 @@ agent_init_default_ctrl (ctrl_t ctrl)
      and the request will fail anyway shortly after this
      initialization. */
   if (ctrl->display)
-    free (ctrl->display);
-  ctrl->display = default_display? strdup (default_display) : NULL;
+    xfree (ctrl->display);
+  ctrl->display = default_display? xtrystrdup (default_display) : NULL;
 
   if (ctrl->ttyname)
-    free (ctrl->ttyname);
-  ctrl->ttyname = default_ttyname? strdup (default_ttyname) : NULL;
+    xfree (ctrl->ttyname);
+  ctrl->ttyname = default_ttyname? xtrystrdup (default_ttyname) : NULL;
 
   if (ctrl->ttytype)
-    free (ctrl->ttytype);
-  ctrl->ttytype = default_ttytype? strdup (default_ttytype) : NULL;
+    xfree (ctrl->ttytype);
+  ctrl->ttytype = default_ttytype? xtrystrdup (default_ttytype) : NULL;
 
   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)
-    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;
+
+  if (ctrl->xauthority)
+    xfree (ctrl->xauthority);
+  ctrl->xauthority = default_xauthority? xtrystrdup (default_xauthority)
+                                   /**/: NULL;
+
+  if (ctrl->pinentry_user_data)
+    xfree (ctrl->pinentry_user_data);
+  ctrl->pinentry_user_data = NULL;
 }
 
 
@@ -1146,15 +1202,19 @@ static void
 agent_deinit_default_ctrl (ctrl_t ctrl)
 {
   if (ctrl->display)
-    free (ctrl->display);
+    xfree (ctrl->display);
   if (ctrl->ttyname)
-    free (ctrl->ttyname);
+    xfree (ctrl->ttyname);
   if (ctrl->ttytype)
-    free (ctrl->ttytype);
+    xfree (ctrl->ttytype);
   if (ctrl->lc_ctype)
-    free (ctrl->lc_ctype);
+    xfree (ctrl->lc_ctype);
   if (ctrl->lc_messages)
-    free (ctrl->lc_messages);
+    xfree (ctrl->lc_messages);
+  if (ctrl->xauthority)
+    xfree (ctrl->xauthority);
+  if (ctrl->pinentry_user_data)
+    xfree (ctrl->pinentry_user_data);
 }
 
 /* Reread parts of the configuration.  Note, that this function is
@@ -1224,6 +1284,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
@@ -1234,8 +1338,7 @@ 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 *
-create_socket_name (int use_standard_socket,
-                   char *standard_name, char *template)
+create_socket_name (char *standard_name, char *template)
 {
   char *name, *p;
 
@@ -1272,12 +1375,12 @@ 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. */
+/* 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 (int is_standard_name, char *name,
-                      assuan_sock_nonce_t *nonce)
+create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
 {
   struct sockaddr_un *serv_addr;
   socklen_t len;
@@ -1304,9 +1407,17 @@ create_server_socket (int is_standard_name, char *name,
         + strlen (serv_addr->sun_path) + 1);
 
   rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len);
-  if (is_standard_name && rc == -1 && errno == EADDRINUSE)
+  if (use_standard_socket && rc == -1 && errno == EADDRINUSE)
     {
-      if (!check_for_running_agent (1, 1))
+      /* 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"));
@@ -1329,7 +1440,7 @@ create_server_socket (int is_standard_name, char *name,
                  gpg_strerror (gpg_error_from_errno (errno)));
       
       assuan_sock_close (fd);
-      if (is_standard_name)
+      if (use_standard_socket)
         *name = 0; /* Inhibit removal of the socket by cleanup(). */
       agent_exit (2);
     }
@@ -1443,6 +1554,11 @@ create_directories (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 ();
 
@@ -1461,14 +1577,24 @@ handle_tick (void)
         }
     }
 #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 fucntion which allows us to call the reload stuff from
-   other palces too.  This is only used when build for W32.  */
+/* 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 ();
@@ -1476,14 +1602,22 @@ agent_sighup_action (void)
 
 
 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 ();
+}
+
+
+static void
 handle_signal (int signo)
 {
   switch (signo)
     {
 #ifndef HAVE_W32_SYSTEM
     case SIGHUP:
-      log_info ("SIGHUP received - "
-                "re-reading configuration and flushing cache\n");
       agent_sighup_action ();
       break;
       
@@ -1495,10 +1629,7 @@ handle_signal (int signo)
       break;
       
     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:
@@ -1560,12 +1691,12 @@ start_connection_thread (void *arg)
   agent_init_default_ctrl (ctrl);
   if (opt.verbose)
     log_info (_("handler 0x%lx for fd %d started\n"), 
-              (long)pth_self (), FD2INT(ctrl->thread_startup.fd));
+              pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
 
   start_command_handler (ctrl, GNUPG_INVALID_FD, ctrl->thread_startup.fd);
   if (opt.verbose)
     log_info (_("handler 0x%lx for fd %d terminated\n"), 
-              (long)pth_self (), FD2INT(ctrl->thread_startup.fd));
+              pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
   
   agent_deinit_default_ctrl (ctrl);
   xfree (ctrl);
@@ -1585,12 +1716,12 @@ start_connection_thread_ssh (void *arg)
   agent_init_default_ctrl (ctrl);
   if (opt.verbose)
     log_info (_("ssh handler 0x%lx for fd %d started\n"),
-              (long)pth_self (), FD2INT(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"),
-              (long)pth_self (), FD2INT(ctrl->thread_startup.fd));
+              pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
   
   agent_deinit_default_ctrl (ctrl);
   xfree (ctrl);
@@ -1620,18 +1751,40 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
 
 #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 );
-  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
+# ifdef PTH_EVENT_HANDLE
+  sigs = 0;
+  ev = pth_event (PTH_EVENT_HANDLE, get_agent_scd_notify_event ());
+  signo = 0;
+# else
+  /* Use a dummy event. */
   sigs = 0;
   ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
+# endif
 #endif
   time_ev = NULL;
 
@@ -1647,26 +1800,34 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
 
   for (;;)
     {
-      sigset_t oldsigs;
+      /* 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 */
 
-          /* 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)
-        time_ev = pth_event (PTH_EVENT_TIME, 
-                             pth_timeout (TIMERTICK_INTERVAL, 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.  */
@@ -1684,7 +1845,13 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
               || (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);
@@ -1696,12 +1863,16 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
           log_error (_("pth_select failed: %s - waiting 1s\n"),
                      strerror (errno));
           pth_sleep (1);
-         continue;
+          continue;
        }
 
       if (pth_event_occurred (ev))
         {
+#if defined(HAVE_W32_SYSTEM) && defined(PTH_EVENT_HANDLE)
+          agent_sigusr2_action ();
+#else
           handle_signal (signo);
+#endif
         }
 
       if (time_ev && pth_event_occurred (time_ev))
@@ -1711,13 +1882,13 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
           handle_tick ();
         }
 
-      
+
       /* We now might create new threads and because we don't want any
          signals (as we are handling them here) to be delivered to a
          new thread.  Thus we need to block those signals. */
-      pth_sigmask (SIG_BLOCK, &sigs, &oldsigs);
+      pth_sigmask (SIG_BLOCK, &sigs, NULL);
 
-      if (FD_ISSET (FD2INT (listen_fd), &read_fdset))
+      if (!shutdown_pending && FD_ISSET (FD2INT (listen_fd), &read_fdset))
        {
           ctrl_t ctrl;
 
@@ -1754,7 +1925,7 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
           fd = GNUPG_INVALID_FD;
        }
 
-      if (listen_fd_ssh != GNUPG_INVALID_FD 
+      if (!shutdown_pending && listen_fd_ssh != GNUPG_INVALID_FD 
           && FD_ISSET ( FD2INT (listen_fd_ssh), &read_fdset))
        {
           ctrl_t ctrl;
@@ -1792,10 +1963,6 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
             }
           fd = GNUPG_INVALID_FD;
        }
-
-      /* Restore the signal mask. */
-      pth_sigmask (SIG_SETMASK, &oldsigs, NULL);
-
     }
 
   pth_event_free (ev, PTH_FREE_ALL);
@@ -1806,8 +1973,113 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
 }
 
 
+
+/* Helper for check_own_socket.  */
+static int
+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;
+  membuf_t mb;
+  char *buffer;
+
+  check_own_socket_running++;
+
+  rc = assuan_socket_connect (&ctx, sockname, (pid_t)(-1));
+  xfree (sockname);
+  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);
+  assuan_disconnect (ctx);
+
+ leave:
+  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 (!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
-   error if not.  If SILENT is true, no mesdsages are printed.  Usually
+   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
 check_for_running_agent (int silent, int mode)