scd: Fix card removal/reset on multiple contexts.
authorNIIBE Yutaka <gniibe@fsij.org>
Wed, 20 Jul 2016 02:35:05 +0000 (11:35 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Wed, 20 Jul 2016 02:35:05 +0000 (11:35 +0900)
* scd/app.c (application_notify_card_reset): Add message for debug.
*scd/command.c (update_card_removed): Call release_application and set
SLOT -1 here.
(struct server_local_s): Remove app_ctx_marked_for_release.
(do_reset): Don't mark release but call release_application here.
(open_card): Remove app_ctx_marked_for_release handling.
(update_reader_status_file): Don't set SLOT here, so that it can be
released the APP by application_notify_card_reset in
update_card_removed.
--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
scd/app.c
scd/command.c

index 51464a2..55b8edd 100644 (file)
--- a/scd/app.c
+++ b/scd/app.c
@@ -168,8 +168,12 @@ application_notify_card_reset (int slot)
   /* Release the APP, as it's not reusable any more.  */
   if (lock_table[slot].app)
     {
+      if (lock_table[slot].app->ref_count)
+        log_bug ("trying to release active context\n");
+
       deallocate_app (lock_table[slot].app);
       lock_table[slot].app = NULL;
+      log_debug ("application has been released\n");
     }
 
   unlock_reader (slot);
index 5842ee7..d90c320 100644 (file)
@@ -129,10 +129,6 @@ struct server_local_s
      continue operation. */
   int card_removed;
 
-  /* Flag indicating that the application context needs to be released
-     at the next opportunity.  */
-  int app_ctx_marked_for_release;
-
   /* A disconnect command has been sent.  */
   int disconnect_allowed;
 
@@ -209,14 +205,28 @@ update_card_removed (int vrdr, int value)
     return;
 
   for (sl=session_list; sl; sl = sl->next_session)
-    if (sl->ctrl_backlink
-        && sl->ctrl_backlink->server_local->vreader_idx == vrdr)
-      {
-        sl->card_removed = value;
-      }
+    {
+      ctrl_t ctrl = sl->ctrl_backlink;
+
+      if (ctrl && ctrl->server_local->vreader_idx == vrdr)
+        {
+          sl->card_removed = value;
+          if (value)
+            {
+              struct app_ctx_s *app = ctrl->app_ctx;
+              ctrl->app_ctx = NULL;
+              release_application (app);
+            }
+        }
+    }
+
   /* Let the card application layer know about the removal.  */
   if (value)
-    application_notify_card_reset (vreader_slot (vrdr));
+    {
+      log_debug ("Removal of a card: %d\n", vrdr);
+      application_notify_card_reset (vreader_slot (vrdr));
+      vreader_table[vrdr].slot = -1;
+    }
 }
 
 
@@ -266,23 +276,31 @@ do_reset (ctrl_t ctrl, int send_reset)
   if (!(vrdr == -1 || (vrdr >= 0 && vrdr < DIM(vreader_table))))
     BUG ();
 
-  /* If there is an active application, release it.  Tell all other
-     sessions using the same application to release the
-     application.  */
+  /* If there is an active application, release it. */
   if (app)
     {
       ctrl->app_ctx = NULL;
       release_application (app);
-      if (send_reset)
+    }
+
+  /* Release the same application which is used by other sessions.  */
+  if (send_reset)
+    {
+      struct server_local_s *sl;
+
+      for (sl=session_list; sl; sl = sl->next_session)
         {
-          struct server_local_s *sl;
+          ctrl_t c = sl->ctrl_backlink;
 
-          for (sl=session_list; sl; sl = sl->next_session)
-            if (sl->ctrl_backlink
-                && sl->ctrl_backlink->server_local->vreader_idx == vrdr)
-              {
-                sl->app_ctx_marked_for_release = 1;
-              }
+          if (c && c != ctrl && c->server_local->vreader_idx == vrdr)
+            {
+              struct app_ctx_s *app0 = c->app_ctx;
+              if (app0)
+                {
+                  c->app_ctx = NULL;
+                  release_application (app0);
+                }
+            }
         }
     }
 
@@ -300,8 +318,8 @@ do_reset (ctrl_t ctrl, int send_reset)
         case SW_HOST_CARD_INACTIVE:
           break;
         default:
-         apdu_close_reader (slot);
-          vreader_table[vrdr].slot = slot = -1;
+          apdu_close_reader (slot);
+          vreader_table[vrdr].slot = -1;
           break;
         }
     }
@@ -427,16 +445,6 @@ open_card (ctrl_t ctrl, const char *apptype)
   if ( IS_LOCKED (ctrl) )
     return gpg_error (GPG_ERR_LOCKED);
 
-  /* If the application has been marked for release do it now.  We
-     can't do it immediately in do_reset because the application may
-     still be in use.  */
-  if (ctrl->server_local->app_ctx_marked_for_release)
-    {
-      ctrl->server_local->app_ctx_marked_for_release = 0;
-      release_application (ctrl->app_ctx);
-      ctrl->app_ctx = NULL;
-    }
-
   /* If we are already initialized for one specific application we
      need to check that the client didn't requested a specific
      application different from the one in use before we continue. */
@@ -2031,14 +2039,10 @@ scd_command_handler (ctrl_t ctrl, int fd)
   session_list = ctrl->server_local;
   ctrl->server_local->ctrl_backlink = ctrl;
   ctrl->server_local->assuan_ctx = ctx;
-  ctrl->server_local->vreader_idx = -1;
 
   /* We open the reader right at startup so that the ticker is able to
      update the status file. */
-  if (ctrl->server_local->vreader_idx == -1)
-    {
-      ctrl->server_local->vreader_idx = get_current_reader ();
-    }
+  ctrl->server_local->vreader_idx = get_current_reader ();
 
   /* Command processing loop. */
   for (;;)
@@ -2256,9 +2260,7 @@ update_reader_status_file (int set_card_removed_flag)
       if (sw_apdu == SW_HOST_NO_READER)
         {
           /* Most likely the _reader_ has been unplugged.  */
-          application_notify_card_reset (vr->slot);
-         apdu_close_reader (vr->slot);
-          vr->slot = -1;
+          apdu_close_reader (vr->slot);
           status = 0;
           changed = vr->changed;
         }