Collected changes
authorWerner Koch <wk@gnupg.org>
Mon, 3 May 2010 11:10:49 +0000 (11:10 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 3 May 2010 11:10:49 +0000 (11:10 +0000)
agent/ChangeLog
agent/call-scd.c
agent/gpg-agent.c
common/ChangeLog
common/asshelp.c
scd/ChangeLog
scd/apdu.c
scd/apdu.h
scd/command.c
scd/sc-copykeys.c

index 68accb8..0bca557 100644 (file)
@@ -1,3 +1,12 @@
+2010-05-03  Werner Koch  <wk@g10code.com>
+
+       * gpg-agent.c (check_own_socket_thread): Do not release SOCKNAME
+       too early.
+
+2010-03-17  Werner Koch  <wk@g10code.com>
+
+       * call-scd.c (unlock_scd): Send a BYE under certain conditions.
+
 2010-02-19  Werner Koch  <wk@g10code.com>
 
        * call-pinentry.c (start_pinentry): Remove a translation prefix.
index f3303c1..93f1cf7 100644 (file)
@@ -176,6 +176,17 @@ agent_scd_dump_state (void)
 static int 
 unlock_scd (ctrl_t ctrl, int rc)
 {
+  if (gpg_err_code (rc) == GPG_ERR_NOT_OPERATIONAL
+      && gpg_err_source (rc) == GPG_ERR_SOURCE_SCD)
+    {
+      /* If the SCdaemon returned this error, it detected a major
+         problem, like no reader connected.  To finish this we need to
+         stop the connection.  This simulates an explicit killing of
+         the SCdaemon.  */
+      assuan_transact (primary_scd_ctx, "BYE",
+                       NULL, NULL, NULL, NULL, NULL, NULL);
+    }
+      
   if (ctrl->scd_local->locked != 1)
     {
       log_error ("unlock_scd: invalid lock count (%d)\n",
index 73f84ed..eec2ca1 100644 (file)
@@ -2101,7 +2101,6 @@ check_own_socket_thread (void *arg)
   check_own_socket_running++;
 
   rc = assuan_new (&ctx);
-  xfree (sockname);
   if (rc)
     {
       log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
@@ -2137,6 +2136,7 @@ check_own_socket_thread (void *arg)
   xfree (buffer);
 
  leave:
+  xfree (sockname);
   if (ctx)
     assuan_release (ctx);
   if (rc)
index 99a1a09..5ca04c0 100644 (file)
@@ -1,3 +1,8 @@
+2010-03-17  Werner Koch  <wk@g10code.com>
+
+       * asshelp.c (start_new_gpg_agent) [W32]: Use a named mutex to
+       avoid starting two agents.
+
 2010-03-12  Werner Koch  <wk@g10code.com>
 
        * status.h (STATUS_ENTER): New.
index b2d13f3..615bb8d 100644 (file)
@@ -231,25 +231,68 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
                and thus there is no need for the GPG_AGENT_INFO
                envvar.  This is possible as we don't have a real unix
                domain socket but use a plain file and thus there is no
-               need to care about non-local file systems. */
+               need to care about non-local file systems.  We use a
+               named mutex to interlock the spawning.  There is just
+               one problem with that: If gpg-agent needs more than 3
+               seconds to come up and listen on the socket we might
+               still spawn another agent.  However this is no serious
+               problem because an agent detects this and handles it.
+               Thus the mutex merely helps to save resources in the
+               most common cases.  */
             const char *argv[3];
+            HANDLE mutex;
+            int waitrc;
 
             argv[0] = "--daemon";
             argv[1] = "--use-standard-socket"; 
             argv[2] = NULL;  
 
-            rc = gnupg_spawn_process_detached (agent_program, argv, NULL);
-            if (rc)
-              log_debug ("failed to start agent `%s': %s\n",
-                         agent_program, gpg_strerror (rc));
+            mutex = CreateMutex (NULL, FALSE, "GnuPG_spawn_agent_sentinel");
+            if (!mutex)
+              {
+                log_error ("failed to create the spawn_agent mutex: %s\n",
+                           w32_strerror (-1));
+                rc = gpg_error (GPG_ERR_GENERAL);
+              }
+            else if ((waitrc = WaitForSingleObject (mutex, 5000))
+                     == WAIT_OBJECT_0)
+              {
+                rc = assuan_socket_connect (&ctx, sockname, 0);
+                if (rc)
+                  {
+                    /* Still not available.  */
+                    rc = gnupg_spawn_process_detached (agent_program,
+                                                       argv, NULL);
+                    if (rc)
+                      log_debug ("failed to start agent `%s': %s\n",
+                                 agent_program, gpg_strerror (rc));
+                    else
+                      {
+                        /* Give the agent some time to prepare itself. */
+                        gnupg_sleep (3);
+                        /* Now try again to connect the agent.  */
+                        rc = assuan_socket_connect (&ctx, sockname, 0);
+                      }
+                  }
+                if (!ReleaseMutex (mutex))
+                  log_error ("failed to release the spawn_agent mutex: %s\n",
+                             w32_strerror (-1));
+              }
+            else if (waitrc == WAIT_TIMEOUT)
+              {
+                log_info ("error waiting for the spawn_agent mutex: timeout\n");
+                rc = gpg_error (GPG_ERR_GENERAL);
+              }
             else
               {
-                /* Give the agent some time to prepare itself. */
-                gnupg_sleep (3);
-                /* Now try again to connect the agent.  */
-                rc = assuan_socket_connect (ctx, sockname, 0, 0);
+                log_debug ("error waiting for the spawn_agent mutex: "
+                           "(code=%d) %s\n", waitrc, w32_strerror (-1));
+                rc = gpg_error (GPG_ERR_GENERAL);
               }
-          }
+            
+            if (mutex)
+              CloseHandle (mutex);
+        }
 #else /*!HAVE_W32_SYSTEM*/
           {
             const char *pgmname;
index 7c72ca8..419f9d4 100644 (file)
@@ -1,3 +1,14 @@
+2010-03-17  Werner Koch  <wk@g10code.com>
+
+       * command.c (open_card): Return GPG_ERR_NOT_OPERATIONAL if no
+       card services are available.
+       (get_reader_slot): Detect no services status.
+       (cmd_serialno): No reset if there are no services.
+       (scd_command_handler): Stop scdaemon in that case.
+       * apdu.c (pcsc_no_service): New.
+       (open_pcsc_reader_direct): Set it.
+       (apdu_open_reader): Add arg R_NO_SERVICE.
+
 2010-02-11  Marcus Brinkmann  <marcus@g10code.de>
 
        From trunk 2009-09-23, 2009-10-16, 2009-11-02, 2009-11-04, 2009-11-05,
index f382aea..0fe044c 100644 (file)
@@ -287,6 +287,9 @@ long (* DLSTDCALL pcsc_transmit) (unsigned long card,
 long (* DLSTDCALL pcsc_set_timeout) (unsigned long context,
                                      unsigned long timeout);
 
+/* Flag set if PC/SC returned the no-service error.  */
+static int pcsc_no_service;
+
 
 /*  Prototypes.  */
 static int pcsc_get_status (int slot, unsigned int *status);
@@ -1487,8 +1490,11 @@ open_pcsc_reader_direct (const char *portstr)
       log_error ("pcsc_establish_context failed: %s (0x%lx)\n",
                  pcsc_error_string (err), err);
       reader_table[slot].used = 0;
+      if (err == 0x8010001d)
+        pcsc_no_service = 1;
       return -1;
     }
+  pcsc_no_service = 0;
 
   err = pcsc_list_readers (reader_table[slot].pcsc.context,
                            NULL, NULL, &nreader);
@@ -2321,14 +2327,18 @@ unlock_slot (int slot)
    error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
    the first USB reader.  For PC/SC the first listed reader). */
 int
-apdu_open_reader (const char *portstr)
+apdu_open_reader (const char *portstr, int *r_no_service)
 {
   static int pcsc_api_loaded, ct_api_loaded;
+  int slot;
+
+  if (r_no_service)
+    *r_no_service = 0;
 
 #ifdef HAVE_LIBUSB
   if (!opt.disable_ccid)
     {
-      int slot, i;
+      int i;
       const char *s;
 
       slot = open_ccid_reader (portstr);
@@ -2458,7 +2468,11 @@ apdu_open_reader (const char *portstr)
       pcsc_api_loaded = 1;
     }
 
-  return open_pcsc_reader (portstr);
+  slot = open_pcsc_reader (portstr);
+  if (slot == -1 && r_no_service && pcsc_no_service)
+    *r_no_service = 1;
+
+  return slot;
 }
 
 
index c47dea8..d79f8b4 100644 (file)
@@ -80,8 +80,8 @@ enum {
 #define APDU_CARD_ACTIVE   (4)    /* Card is active.  */
 
 
-/* Note , that apdu_open_reader returns no status word but -1 on error. */
-int apdu_open_reader (const char *portstr);
+/* Note, that apdu_open_reader returns no status word but -1 on error. */
+int apdu_open_reader (const char *portstr, int *r_no_service);
 int apdu_open_remote_reader (const char *portstr,
                              const unsigned char *cookie, size_t length,
                              int (*readfnc) (void *opaque,
index ad1d6b9..e2cd1f5 100644 (file)
       && (c)->reader_slot == locked_session->ctrl_backlink->reader_slot)
 
 
+/* Flag indicating that the reader has been disabled.  */
+static int reader_disabled;
+
+
 /* This structure is used to keep track of open readers (slots). */
 struct slot_status_s 
 {
@@ -394,7 +398,15 @@ get_reader_slot (void)
 
   /* Try to open the reader. */
   if (ss->slot == -1)
-    ss->slot = apdu_open_reader (opt.reader_port);
+    {
+      int no_service_flag;
+      ss->slot = apdu_open_reader (opt.reader_port, &no_service_flag);
+      if (no_service_flag)
+        {
+          log_info ("no card services - disabling scdaemon\n");
+          reader_disabled = 1;
+        }
+    }
 
   /* Return the slot_table index.  */
   return 0;
@@ -409,6 +421,9 @@ open_card (ctrl_t ctrl, const char *apptype)
   gpg_error_t err;
   int slot;
 
+  if (reader_disabled)
+    return gpg_error (GPG_ERR_NOT_OPERATIONAL);
+
   /* If we ever got a card not present error code, return that.  Only
      the SERIALNO command and a reset are able to clear from that
      state. */
@@ -441,7 +456,7 @@ open_card (ctrl_t ctrl, const char *apptype)
     slot = get_reader_slot ();
   ctrl->reader_slot = slot;
   if (slot == -1)
-    err = gpg_error (GPG_ERR_CARD);
+    err = gpg_error (reader_disabled? GPG_ERR_NOT_OPERATIONAL: GPG_ERR_CARD);
   else
     {
       /* Fixme: We should move the apdu_connect call to
@@ -495,7 +510,7 @@ cmd_serialno (assuan_context_t ctx, char *line)
   time_t stamp;
 
   /* Clear the remove flag so that the open_card is able to reread it.  */
-  if (ctrl->server_local->card_removed)
+  if (!reader_disabled && ctrl->server_local->card_removed)
     {
       if ( IS_LOCKED (ctrl) )
         return gpg_error (GPG_ERR_LOCKED);
@@ -1995,7 +2010,7 @@ scd_command_handler (ctrl_t ctrl, int fd)
           BUG ();
       sl->next_session = ctrl->server_local->next_session;
     }
-  stopme = ctrl->server_local->stopme;
+  stopme = ctrl->server_local->stopme || reader_disabled;
   xfree (ctrl->server_local);
   ctrl->server_local = NULL;
 
index 615e4b2..b863b01 100644 (file)
@@ -139,7 +139,7 @@ main (int argc, char **argv )
   if (argc != 1)
     usage (1);
 
-  slot = apdu_open_reader (reader_port);
+  slot = apdu_open_reader (reader_port, NULL);
   if (slot == -1)
     exit (1);
   if (apdu_connect (slot))