Better syncronization of several smartcard sessions.

This commit is contained in:
Werner Koch 2009-03-24 11:40:57 +00:00
parent 9828f9be11
commit f07e762d68
5 changed files with 82 additions and 17 deletions

2
NEWS
View File

@ -13,6 +13,8 @@ Noteworthy changes in version 2.0.12
* Changed order of the confirmation questions for root certificates * Changed order of the confirmation questions for root certificates
and stores negative answers in trustlist.txt. and stores negative answers in trustlist.txt.
* Better synchronization of several smartcard sessions.
Noteworthy changes in version 2.0.11 (2009-03-03) Noteworthy changes in version 2.0.11 (2009-03-03)
------------------------------------------------- -------------------------------------------------

View File

@ -1,3 +1,14 @@
2009-03-24 Werner Koch <wk@g10code.com>
* 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 <wk@g10code.com> 2009-03-20 Werner Koch <wk@g10code.com>
* app-nks.c (keygripstr_from_pk_file): Fix for TCOS 3 cards. * app-nks.c (keygripstr_from_pk_file): Fix for TCOS 3 cards.

View File

@ -38,15 +38,19 @@
struct app_local_s; /* Defined by all app-*.c. */ struct app_local_s; /* Defined by all app-*.c. */
struct app_ctx_s { struct app_ctx_s {
unsigned int ref_count; /* Number of connections currently using /* Number of connections currently using this application context.
this application context. If this is If this is not 0 the application has been initialized and the
not 0 the application has been function pointers may be used. Note that for unsupported
initialized and the function pointers operations the particular function pointer is set to NULL */
may be used. Note that for unsupported unsigned int ref_count;
operations the particular function
pointer is set to NULL */
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 /* 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 in case we need to divert the operation to an already running

View File

@ -173,6 +173,10 @@ application_notify_card_reset (int slot)
/* FIXME: We are ignoring any error value here. */ /* FIXME: We are ignoring any error value here. */
lock_reader (slot); 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 /* 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 try to reuse it. If there is no saved application, set a flag so
that we won't save the current state. */ 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); 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 /* 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 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 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); unlock_reader (slot);
return 0; /* Okay: We share that one. */ return 0; /* Okay: We share that one. */
} }
/* Need to allocate a new one. */ /* Need to allocate a new one. */
app = xtrycalloc (1, sizeof *app); app = xtrycalloc (1, sizeof *app);
if (!app) if (!app)
@ -458,7 +472,15 @@ release_application (app_t app)
if (lock_table[slot].last_app) if (lock_table[slot].last_app)
deallocate_app (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; lock_table[slot].app = NULL;
unlock_reader (slot); unlock_reader (slot);
} }

View File

@ -112,6 +112,10 @@ struct server_local_s
continue operation. */ continue operation. */
int card_removed; 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. */ /* A disconnect command has been sent. */
int disconnect_allowed; int disconnect_allowed;
@ -165,7 +169,7 @@ initialize_module_command (void)
/* Update the CARD_REMOVED element of all sessions using the reader /* Update the CARD_REMOVED element of all sessions using the reader
given by SLOT to VALUE */ given by SLOT to VALUE. */
static void static void
update_card_removed (int slot, int value) 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)))) if (!(slot == -1 || (slot >= 0 && slot < DIM(slot_table))))
BUG (); 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) if (ctrl->app_ctx)
{ {
release_application (ctrl->app_ctx); release_application (ctrl->app_ctx);
ctrl->app_ctx = NULL; 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 /* 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) ) if ( IS_LOCKED (ctrl) )
return gpg_error (GPG_ERR_LOCKED); 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 ctrl->server_local->app_ctx_marked_for_release = 0;
check that the client didn't requested a specific application release_application (ctrl->app_ctx);
different from the one in use. */ ctrl->app_ctx = NULL;
return check_application_conflict (ctrl, apptype);
} }
/* 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) if (ctrl->reader_slot != -1)
slot = ctrl->reader_slot; slot = ctrl->reader_slot;
else else