1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-01 22:28:02 +02:00

scd: Simplify saving application context.

* scd/app.c (lock_table): Remove LAST_APP field.
(lock_reader, app_dump_state, application_notify_card_reset)
(release_application): Follow the change.
(check_conflict): New.
(check_application_conflict): Lock the slot and call check_conflict.
(select_application): Call check_conflict and not use LAST_APP.

--

We don't need LAST_APP field but just keep the application context by
APP field.  Since we have a reference counter, it is possible if we
can deallocate or not.

(backport of commit 9639af5f16)
This commit is contained in:
NIIBE Yutaka 2015-12-04 14:13:23 +09:00
parent 9934889415
commit 520c85ed94

106
scd/app.c
View File

@ -39,7 +39,6 @@ static struct
int initialized; int initialized;
pth_mutex_t lock; pth_mutex_t lock;
app_t app; /* Application context in use or NULL. */ app_t app; /* Application context in use or NULL. */
app_t last_app; /* Last application object used as this slot or NULL. */
} lock_table[10]; } lock_table[10];
@ -87,7 +86,6 @@ lock_reader (int slot, ctrl_t ctrl)
} }
lock_table[slot].initialized = 1; lock_table[slot].initialized = 1;
lock_table[slot].app = NULL; lock_table[slot].app = NULL;
lock_table[slot].last_app = NULL;
} }
if (!pth_mutex_acquire (&lock_table[slot].lock, 0, NULL)) if (!pth_mutex_acquire (&lock_table[slot].lock, 0, NULL))
@ -154,12 +152,6 @@ app_dump_state (void)
if (lock_table[slot].app->apptype) if (lock_table[slot].app->apptype)
log_printf (" type=`%s'", lock_table[slot].app->apptype); log_printf (" type=`%s'", lock_table[slot].app->apptype);
} }
if (lock_table[slot].last_app)
{
log_printf (" lastapp=%p", lock_table[slot].last_app);
if (lock_table[slot].last_app->apptype)
log_printf (" type=`%s'", lock_table[slot].last_app->apptype);
}
log_printf ("\n"); log_printf ("\n");
} }
} }
@ -182,8 +174,6 @@ is_app_allowed (const char *name)
void void
application_notify_card_reset (int slot) application_notify_card_reset (int slot)
{ {
app_t app;
if (slot < 0 || slot >= DIM (lock_table)) if (slot < 0 || slot >= DIM (lock_table))
return; return;
@ -197,20 +187,35 @@ application_notify_card_reset (int slot)
lock_table[slot].app = NULL; lock_table[slot].app = NULL;
} }
/* 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. */
app = lock_table[slot].last_app;
if (app)
{
lock_table[slot].last_app = NULL;
deallocate_app (app);
}
unlock_reader (slot); unlock_reader (slot);
} }
/*
* This function is called with lock held.
*/
static gpg_error_t
check_conflict (int slot, const char *name)
{
app_t app = lock_table[slot].app;
if (!app || !name || (app->apptype && !ascii_strcasecmp (app->apptype, name)))
return 0;
if (!app->ref_count)
{
lock_table[slot].app = NULL;
deallocate_app (app);
return 0;
}
else
{
log_info ("application '%s' in use by reader %d - can't switch\n",
app->apptype? app->apptype : "<null>", slot);
return gpg_error (GPG_ERR_CONFLICT);
}
}
/* This function is used by the serialno command to check for an /* This function is used by the serialno command to check for an
application conflict which may appear if the serialno command is application conflict which may appear if the serialno command is
used to request a specific application and the connection has used to request a specific application and the connection has
@ -218,17 +223,18 @@ application_notify_card_reset (int slot)
gpg_error_t gpg_error_t
check_application_conflict (ctrl_t ctrl, const char *name) check_application_conflict (ctrl_t ctrl, const char *name)
{ {
int slot = ctrl->reader_slot; gpg_error_t err;
app_t app;
if (slot < 0 || slot >= DIM (lock_table)) if (slot < 0 || slot >= DIM (lock_table))
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
app = lock_table[slot].initialized ? lock_table[slot].app : NULL; err = lock_reader (slot, ctrl);
if (app && app->apptype && name) if (err)
if ( ascii_strcasecmp (app->apptype, name)) return err;
return gpg_error (GPG_ERR_CONFLICT);
return 0; err = check_conflict (slot, name);
unlock_reader (slot);
return err;
} }
@ -257,41 +263,15 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
return err; return err;
/* First check whether we already have an application to share. */ /* First check whether we already have an application to share. */
app = lock_table[slot].initialized ? lock_table[slot].app : NULL; err = check_conflict (slot, name);
if (app && name) if (err)
if (!app->apptype || ascii_strcasecmp (app->apptype, name))
{
unlock_reader (slot);
if (app->apptype)
log_info ("application `%s' in use by reader %d - can't switch\n",
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
way the PIN cache and other cached data are preserved. */
if (!app && lock_table[slot].initialized && lock_table[slot].last_app)
{ {
app = lock_table[slot].last_app; unlock_reader (slot);
if (!name || (app->apptype && !ascii_strcasecmp (app->apptype, name)) ) return err;
{
/* Yes, we can reuse this application - either the caller
requested an unspecific one or the requested one matches
the saved one. */
lock_table[slot].app = app;
lock_table[slot].last_app = NULL;
}
else
{
/* No, this saved application can't be used - deallocate it. */
lock_table[slot].last_app = NULL;
deallocate_app (app);
app = NULL;
}
} }
app = lock_table[slot].app;
/* If we can reuse an application, bump the reference count and /* If we can reuse an application, bump the reference count and
return it. */ return it. */
if (app) if (app)
@ -497,10 +477,10 @@ release_application (app_t app)
return; return;
} }
if (lock_table[slot].last_app) /* We don't deallocate app here. Instead, we keep it. This is
deallocate_app (lock_table[slot].last_app); useful so that a card does not get reset even if only one session
lock_table[slot].last_app = lock_table[slot].app; is using the card - this way the PIN cache and other cached data
lock_table[slot].app = NULL; are preserved. */
unlock_reader (slot); unlock_reader (slot);
} }