From f07e762d688fd560cca57ca1917b66c06782c2d6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 24 Mar 2009 11:40:57 +0000 Subject: [PATCH] Better syncronization of several smartcard sessions. --- NEWS | 2 ++ scd/ChangeLog | 11 +++++++++++ scd/app-common.h | 20 ++++++++++++-------- scd/app.c | 26 ++++++++++++++++++++++++-- scd/command.c | 40 +++++++++++++++++++++++++++++++++------- 5 files changed, 82 insertions(+), 17 deletions(-) diff --git a/NEWS b/NEWS index 59fb8ff7f..002fce0b3 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,8 @@ Noteworthy changes in version 2.0.12 * Changed order of the confirmation questions for root certificates and stores negative answers in trustlist.txt. + * Better synchronization of several smartcard sessions. + Noteworthy changes in version 2.0.11 (2009-03-03) ------------------------------------------------- diff --git a/scd/ChangeLog b/scd/ChangeLog index 70972c2aa..c12603a59 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,14 @@ +2009-03-24 Werner Koch + + * command.c (struct server_local_s): Add flag + APP_CTX_MARKED_FOR_RELEASE. + (do_reset): Set the flag. + (open_card): Act on this flag. + * app-common.h (struct app_ctx_s): Add flag NO_REUSE. + (application_notify_card_reset): Set the flag. + * app.c (select_application, release_application): Take care of + that flag. + 2009-03-20 Werner Koch * app-nks.c (keygripstr_from_pk_file): Fix for TCOS 3 cards. diff --git a/scd/app-common.h b/scd/app-common.h index 85ac9e2b5..e5a0dc5e0 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -38,15 +38,19 @@ struct app_local_s; /* Defined by all app-*.c. */ struct app_ctx_s { - unsigned int ref_count; /* Number of connections currently using - this application context. If this is - not 0 the application has been - initialized and the function pointers - may be used. Note that for unsupported - operations the particular function - pointer is set to NULL */ + /* Number of connections currently using this application context. + If this is not 0 the application has been initialized and the + function pointers may be used. Note that for unsupported + operations the particular function pointer is set to NULL */ + unsigned int ref_count; - int slot; /* Used reader. */ + /* Flag indicating that a reset has been done for that application + and that this context is merely lingering and just should not be + reused. */ + int no_reuse; + + /* Used reader slot. */ + int slot; /* If this is used by GnuPG 1.4 we need to know the assuan context in case we need to divert the operation to an already running diff --git a/scd/app.c b/scd/app.c index e66c6cb7a..eb97d846a 100644 --- a/scd/app.c +++ b/scd/app.c @@ -173,6 +173,10 @@ application_notify_card_reset (int slot) /* FIXME: We are ignoring any error value here. */ lock_reader (slot); + /* Mark application as non-reusable. */ + if (lock_table[slot].app) + lock_table[slot].app->no_reuse = 1; + /* Deallocate a saved application for that slot, so that we won't try to reuse it. If there is no saved application, set a flag so that we won't save the current state. */ @@ -241,6 +245,16 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) return gpg_error (GPG_ERR_CONFLICT); } + /* Don't use a non-reusable marked application. */ + if (app && app->no_reuse) + { + unlock_reader (slot); + log_info ("lingering application `%s' in use by reader %d" + " - can't switch\n", + app->apptype? app->apptype:"?", slot); + return gpg_error (GPG_ERR_CONFLICT); + } + /* If we don't have an app, check whether we have a saved application for that slot. This is useful so that a card does not get reset even if only one session is using the card - this @@ -278,7 +292,7 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) unlock_reader (slot); return 0; /* Okay: We share that one. */ } - + /* Need to allocate a new one. */ app = xtrycalloc (1, sizeof *app); if (!app) @@ -458,7 +472,15 @@ release_application (app_t app) if (lock_table[slot].last_app) deallocate_app (lock_table[slot].last_app); - lock_table[slot].last_app = lock_table[slot].app; + if (app->no_reuse) + { + /* If we shall not re-use the application we can't save it for + later use. */ + deallocate_app (app); + lock_table[slot].last_app = NULL; + } + else + lock_table[slot].last_app = lock_table[slot].app; lock_table[slot].app = NULL; unlock_reader (slot); } diff --git a/scd/command.c b/scd/command.c index 242342484..aa0e6350a 100644 --- a/scd/command.c +++ b/scd/command.c @@ -112,6 +112,10 @@ 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; @@ -165,7 +169,7 @@ initialize_module_command (void) /* Update the CARD_REMOVED element of all sessions using the reader - given by SLOT to VALUE */ + given by SLOT to VALUE. */ static void update_card_removed (int slot, int value) { @@ -274,11 +278,24 @@ do_reset (ctrl_t ctrl, int send_reset) if (!(slot == -1 || (slot >= 0 && slot < DIM(slot_table)))) BUG (); - /* If there is an active application, release it. */ + /* If there is an active application, release it. Tell all other + sessions using the same application to release the + application. */ if (ctrl->app_ctx) { release_application (ctrl->app_ctx); ctrl->app_ctx = NULL; + if (send_reset) + { + struct server_local_s *sl; + + for (sl=session_list; sl; sl = sl->next_session) + if (sl->ctrl_backlink + && sl->ctrl_backlink->reader_slot == slot) + { + sl->app_ctx_marked_for_release = 1; + } + } } /* If we want a real reset for the card, send the reset APDU and @@ -397,14 +414,23 @@ open_card (ctrl_t ctrl, const char *apptype) if ( IS_LOCKED (ctrl) ) return gpg_error (GPG_ERR_LOCKED); - if (ctrl->app_ctx) + /* 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) { - /* Already initialized for one specific application. Need to - check that the client didn't requested a specific application - different from the one in use. */ - return check_application_conflict (ctrl, apptype); + 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. */ + if (ctrl->app_ctx) + return check_application_conflict (ctrl, apptype); + + /* Setup the slot and select the application. */ if (ctrl->reader_slot != -1) slot = ctrl->reader_slot; else