Detect non operational readers.
authorWerner Koch <wk@gnupg.org>
Mon, 3 May 2010 11:10:49 +0000 (11:10 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 25 Jan 2011 20:51:58 +0000 (21:51 +0100)
Backport from 2.0.

scd/ChangeLog
scd/apdu.c
scd/apdu.h
scd/command.c
scd/sc-copykeys.c

index 41a0f76..d1e942a 100644 (file)
@@ -1,3 +1,16 @@
+2011-01-25  Werner Koch  <wk@g10code.com>
+
+       From 2.0 branch, 2010-03-17:
+
+       * 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.
+
 2011-01-05  Werner Koch  <wk@g10code.com>
 
        * ccid-driver.c (ccid_transceive_secure): Support the gnuk token.
index 80c933e..dcb0e23 100644 (file)
@@ -304,6 +304,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);
@@ -1504,8 +1507,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);
@@ -2338,14 +2344,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);
@@ -2475,7 +2485,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 fa1d46c..36aff97 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);
@@ -1993,7 +2008,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))