scd: Fix access to list of cards (3/3).

* scd/app-common.h (card_reset): Simplify more.
(select_additional_application): Supply CARD.
(card_ref, card_unref): Remove.
(card_get, card_put): New.
* scd/app.c (card_reset): No locking/unlocking inside.
(app_switch_current_card): Fix comment.
(select_additional_application): No locking/unlocking inside.
(do_with_keygrip): New, unlocked version.
(card_get): New, with support of KEYGRIP.
(card_unref): Remove.
(card_put): New.
(app_write_learn_status, app_readcert: No locking/unlocking inside.
(app_readkey, app_getattr, app_setattr, app_sign, app_auth): Likewise.
(app_decipher, app_writecert, app_writekey): Likewise.
(app_genkey, app_get_challenge, app_change_pin): Likewise.
(app_check_pin, app_switch_active_app): Likewise.
* scd/command.c (do_reset): Use card_get/card_put.
(open_card_with_request): Use card_get/card_put, return CARD locked.
(cmd_serialno): Follow the change of open_card_with_request.
(cmd_switchapp): Use card_get/card_put.
(cmd_learn, cmd_readcert, cmd_readkey, cmd_pksign): Likewise.
(cmd_pkauth, cmd_pkdecrypt, cmd_getattr): Likewise.
(cmd_setattr, cmd_writecert, cmd_writekey): Likewise.
(cmd_genkey, cmd_random, cmd_passwd): Likewise.
(cmd_checkpin, cmd_getinfo, cmd_restart): Likewise.
(cmd_disconnect, cmd_apdu, cmd_devinfo): Likewise.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2021-07-21 17:08:40 +09:00
parent b436fb6766
commit 0d6b4210cf
3 changed files with 317 additions and 317 deletions

View File

@ -255,11 +255,12 @@ void application_notify_card_reset (int slot);
gpg_error_t check_application_conflict (card_t card, const char *name, gpg_error_t check_application_conflict (card_t card, const char *name,
const unsigned char *serialno_bin, const unsigned char *serialno_bin,
size_t serialno_bin_len); size_t serialno_bin_len);
gpg_error_t card_reset (card_t card, ctrl_t ctrl); gpg_error_t card_reset (card_t card);
gpg_error_t select_application (ctrl_t ctrl, const char *name, gpg_error_t select_application (ctrl_t ctrl, const char *name,
int scan, const unsigned char *serialno_bin, int scan, const unsigned char *serialno_bin,
size_t serialno_bin_len); size_t serialno_bin_len);
gpg_error_t select_additional_application (ctrl_t ctrl, const char *name); gpg_error_t select_additional_application (card_t card,
ctrl_t ctrl, const char *name);
gpg_error_t app_switch_current_card (ctrl_t ctrl, gpg_error_t app_switch_current_card (ctrl_t ctrl,
const unsigned char *serialno, const unsigned char *serialno,
@ -269,8 +270,8 @@ gpg_error_t app_switch_active_app (card_t card, ctrl_t ctrl,
char *get_supported_applications (void); char *get_supported_applications (void);
card_t card_ref (card_t card); card_t card_get (ctrl_t ctrl, const char *keygrip);
void card_unref (card_t card); void card_put (card_t card);
void card_unref_locked (card_t card); void card_unref_locked (card_t card);
gpg_error_t app_munge_serialno (card_t card); gpg_error_t app_munge_serialno (card_t card);

291
scd/app.c
View File

@ -503,18 +503,16 @@ check_application_conflict (card_t card, const char *name,
gpg_error_t gpg_error_t
card_reset (card_t card, ctrl_t ctrl) card_reset (card_t card)
{ {
gpg_error_t err = 0; gpg_error_t err = 0;
int sw; int sw;
lock_card (card, ctrl);
sw = apdu_reset (card->slot); sw = apdu_reset (card->slot);
if (sw) if (sw)
err = gpg_error (GPG_ERR_CARD_RESET); err = gpg_error (GPG_ERR_CARD_RESET);
card->reset_requested = 1; card->reset_requested = 1;
unlock_card (card);
scd_kick_the_loop (); scd_kick_the_loop ();
gnupg_sleep (1); gnupg_sleep (1);
@ -862,7 +860,6 @@ select_application (ctrl_t ctrl, const char *name,
if (!err) if (!err)
{ {
/* Note: We do not use card_ref as we are already locked. */
card->ref_count++; card->ref_count++;
ctrl->card_ctx = card; ctrl->card_ctx = card;
if (card_prev) if (card_prev)
@ -895,7 +892,8 @@ app_switch_current_card (ctrl_t ctrl,
lock_r_card_list (); lock_r_card_list ();
if (!ctrl->card_ctx) cardtmp = ctrl->card_ctx;
if (!cardtmp)
{ {
err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
goto leave; goto leave;
@ -915,10 +913,10 @@ app_switch_current_card (ctrl_t ctrl,
goto leave; goto leave;
} }
/* Note: We do not use card_ref here because we only swap the /* Note: We do not lock CARD and CARDTMP here because we only
* context of the current session and there is no chance of a * swap the context of the current session and there is no
* context switch. This also works if the card stays the same. */ * chance of a context switch. This also works if the card
cardtmp = ctrl->card_ctx; * stays the same. */
ctrl->card_ctx = card; ctrl->card_ctx = card;
card->ref_count++; card->ref_count++;
card_unref_locked (cardtmp); card_unref_locked (cardtmp);
@ -1077,11 +1075,10 @@ select_all_additional_applications_internal (ctrl_t ctrl, card_t card)
* active application. On error no new application is allocated. * active application. On error no new application is allocated.
* Selecting an already selected application has no effect. */ * Selecting an already selected application has no effect. */
gpg_error_t gpg_error_t
select_additional_application (ctrl_t ctrl, const char *name) select_additional_application (card_t card, ctrl_t ctrl, const char *name)
{ {
gpg_error_t err = 0; gpg_error_t err = 0;
apptype_t req_apptype; apptype_t req_apptype;
card_t card;
if (!name) if (!name)
req_apptype = 0; req_apptype = 0;
@ -1092,14 +1089,6 @@ select_additional_application (ctrl_t ctrl, const char *name)
return gpg_error (GPG_ERR_NOT_FOUND); return gpg_error (GPG_ERR_NOT_FOUND);
} }
card = ctrl->card_ctx;
if (!card)
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
err = lock_card (card, ctrl);
if (err)
return err;
if (req_apptype) if (req_apptype)
{ {
err = select_additional_application_internal (card, req_apptype); err = select_additional_application_internal (card, req_apptype);
@ -1115,7 +1104,6 @@ select_additional_application (ctrl_t ctrl, const char *name)
err = select_all_additional_applications_internal (ctrl, card); err = select_all_additional_applications_internal (ctrl, card);
} }
unlock_card (card);
return err; return err;
} }
@ -1183,35 +1171,104 @@ deallocate_card (card_t card)
} }
/* Increment the reference counter of CARD. Returns CARD. */ static card_t
card_t do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str,
card_ref (card_t card) int capability)
{ {
lock_card (card, NULL); int locked = 0;
++card->ref_count; card_t c;
unlock_card (card); app_t a, a_prev;
return card;
for (c = card_top; c; c = c->next)
{
if (lock_card (c, ctrl))
{
c = NULL;
goto leave_the_loop;
}
locked = 1;
a_prev = NULL;
for (a = c->app; a; a = a->next)
{
if (!a->fnc.with_keygrip || a->need_reset)
continue;
/* Note that we need to do a re-select even for the current
* app because the last selected application (e.g. after
* init) might be a different one and we do not run
* maybe_switch_app here. Of course we we do this only iff
* we have an additional app. */
if (c->app->next)
{
if (run_reselect (ctrl, c, a, a_prev))
continue;
}
a_prev = a;
if (DBG_APP)
log_debug ("slot %d, app %s: calling with_keygrip(%s)\n",
c->slot, xstrapptype (a),
action == KEYGRIP_ACTION_SEND_DATA? "send_data":
action == KEYGRIP_ACTION_WRITE_STATUS? "status":
action == KEYGRIP_ACTION_LOOKUP? "lookup":"?");
if (!a->fnc.with_keygrip (a, ctrl, action, keygrip_str, capability))
goto leave_the_loop; /* ACTION_LOOKUP succeeded. */
}
/* Select the first app again. */
if (c->app->next)
run_reselect (ctrl, c, c->app, a_prev);
unlock_card (c);
locked = 0;
}
leave_the_loop:
/* Force switching of the app if the selected one is not the current
* one. Changing the current apptype is sufficient to do this. */
if (c && c->app && c->app->apptype != a->apptype)
ctrl->current_apptype = a->apptype;
if (locked && c)
{
unlock_card (c);
locked = 0;
}
return c;
} }
/* Decrement the reference counter for CARD. Note that we are using /* Locking access to the card-list and CARD, returns CARD. */
* reference counting to track the users of the card's application and card_t
* are deferring the actual deallocation to allow for a later reuse by card_get (ctrl_t ctrl, const char *keygrip)
* a new connection. Using NULL for CARD is a no-op. */
void
card_unref (card_t card)
{ {
if (!card) card_t card;
return;
lock_r_card_list ();
if (keygrip)
card = do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keygrip, 0);
else
card = ctrl->card_ctx;
if (!card)
{
unlock_r_card_list ();
return NULL;
}
lock_card (card, NULL);
return card;
}
/* Release the lock of CARD and the card-list. */
void
card_put (card_t card)
{
/* We don't deallocate CARD here. Instead, we keep it. This is /* We don't deallocate CARD here. Instead, we keep it. This is
useful so that a card does not get reset even if only one session 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 is using the card - this way the PIN cache and other cached data
are preserved. */ are preserved. */
lock_card (card, NULL);
card_unref_locked (card);
unlock_card (card); unlock_card (card);
unlock_r_card_list ();
} }
@ -1698,13 +1755,6 @@ app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
app_t app, last_app; app_t app, last_app;
int any_reselect = 0; int any_reselect = 0;
if (!card)
return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
/* Always make sure that the current app for this connection has /* Always make sure that the current app for this connection has
* been selected and is at the top of the list. */ * been selected and is at the top of the list. */
if ((err = maybe_switch_app (ctrl, card, NULL))) if ((err = maybe_switch_app (ctrl, card, NULL)))
@ -1766,7 +1816,6 @@ app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
} }
} }
unlock_card (card);
return err; return err;
} }
@ -1781,12 +1830,6 @@ app_readcert (card_t card, ctrl_t ctrl, const char *certid,
{ {
gpg_error_t err; gpg_error_t err;
if (!card)
return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
if ((err = maybe_switch_app (ctrl, card, certid))) if ((err = maybe_switch_app (ctrl, card, certid)))
; ;
else if (!card->app->fnc.readcert) else if (!card->app->fnc.readcert)
@ -1802,7 +1845,6 @@ app_readcert (card_t card, ctrl_t ctrl, const char *certid,
err = card->app->fnc.readcert (card->app, certid, cert, certlen); err = card->app->fnc.readcert (card->app, certid, cert, certlen);
} }
unlock_card (card);
return err; return err;
} }
@ -1826,11 +1868,8 @@ app_readkey (card_t card, ctrl_t ctrl, const char *keyid, unsigned int flags,
if (pklen) if (pklen)
*pklen = 0; *pklen = 0;
if (!card || !keyid) if (!keyid)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
if ((err = maybe_switch_app (ctrl, card, keyid))) if ((err = maybe_switch_app (ctrl, card, keyid)))
; ;
@ -1847,7 +1886,6 @@ app_readkey (card_t card, ctrl_t ctrl, const char *keyid, unsigned int flags,
err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen); err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen);
} }
unlock_card (card);
return err; return err;
} }
@ -1858,11 +1896,8 @@ app_getattr (card_t card, ctrl_t ctrl, const char *name)
{ {
gpg_error_t err; gpg_error_t err;
if (!card || !name || !*name) if (!name || !*name)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
if ((err = maybe_switch_app (ctrl, card, NULL))) if ((err = maybe_switch_app (ctrl, card, NULL)))
; ;
@ -1900,7 +1935,6 @@ app_getattr (card_t card, ctrl_t ctrl, const char *name)
err = card->app->fnc.getattr (card->app, ctrl, name); err = card->app->fnc.getattr (card->app, ctrl, name);
} }
unlock_card (card);
return err; return err;
} }
@ -1914,11 +1948,8 @@ app_setattr (card_t card, ctrl_t ctrl, const char *name,
{ {
gpg_error_t err; gpg_error_t err;
if (!card || !name || !*name || !value) if (!name || !*name || !value)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
if ((err = maybe_switch_app (ctrl, card, NULL))) if ((err = maybe_switch_app (ctrl, card, NULL)))
; ;
@ -1936,7 +1967,6 @@ app_setattr (card_t card, ctrl_t ctrl, const char *name,
value, valuelen); value, valuelen);
} }
unlock_card (card);
return err; return err;
} }
@ -1953,11 +1983,8 @@ app_sign (card_t card, ctrl_t ctrl, const char *keyidstr, int hashalgo,
{ {
gpg_error_t err; gpg_error_t err;
if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) if (!indata || !indatalen || !outdata || !outdatalen || !pincb)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
if ((err = maybe_switch_app (ctrl, card, keyidstr))) if ((err = maybe_switch_app (ctrl, card, keyidstr)))
; ;
@ -1977,7 +2004,6 @@ app_sign (card_t card, ctrl_t ctrl, const char *keyidstr, int hashalgo,
outdata, outdatalen); outdata, outdatalen);
} }
unlock_card (card);
if (opt.verbose) if (opt.verbose)
log_info ("operation sign result: %s\n", gpg_strerror (err)); log_info ("operation sign result: %s\n", gpg_strerror (err));
return err; return err;
@ -1997,11 +2023,8 @@ app_auth (card_t card, ctrl_t ctrl, const char *keyidstr,
{ {
gpg_error_t err; gpg_error_t err;
if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) if (!indata || !indatalen || !outdata || !outdatalen || !pincb)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
if ((err = maybe_switch_app (ctrl, card, keyidstr))) if ((err = maybe_switch_app (ctrl, card, keyidstr)))
; ;
@ -2021,7 +2044,6 @@ app_auth (card_t card, ctrl_t ctrl, const char *keyidstr,
outdata, outdatalen); outdata, outdatalen);
} }
unlock_card (card);
if (opt.verbose) if (opt.verbose)
log_info ("operation auth result: %s\n", gpg_strerror (err)); log_info ("operation auth result: %s\n", gpg_strerror (err));
return err; return err;
@ -2043,11 +2065,8 @@ app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr,
*r_info = 0; *r_info = 0;
if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) if (!indata || !indatalen || !outdata || !outdatalen || !pincb)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
if ((err = maybe_switch_app (ctrl, card, keyidstr))) if ((err = maybe_switch_app (ctrl, card, keyidstr)))
; ;
@ -2068,7 +2087,6 @@ app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr,
r_info); r_info);
} }
unlock_card (card);
if (opt.verbose) if (opt.verbose)
log_info ("operation decipher result: %s\n", gpg_strerror (err)); log_info ("operation decipher result: %s\n", gpg_strerror (err));
return err; return err;
@ -2085,11 +2103,8 @@ app_writecert (card_t card, ctrl_t ctrl,
{ {
gpg_error_t err; gpg_error_t err;
if (!card || !certidstr || !*certidstr || !pincb) if (!certidstr || !*certidstr || !pincb)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
if ((err = maybe_switch_app (ctrl, card, certidstr))) if ((err = maybe_switch_app (ctrl, card, certidstr)))
; ;
@ -2107,7 +2122,6 @@ app_writecert (card_t card, ctrl_t ctrl,
pincb, pincb_arg, data, datalen); pincb, pincb_arg, data, datalen);
} }
unlock_card (card);
if (opt.verbose) if (opt.verbose)
log_info ("operation writecert result: %s\n", gpg_strerror (err)); log_info ("operation writecert result: %s\n", gpg_strerror (err));
return err; return err;
@ -2124,11 +2138,8 @@ app_writekey (card_t card, ctrl_t ctrl,
{ {
gpg_error_t err; gpg_error_t err;
if (!card || !keyidstr || !*keyidstr || !pincb) if (!keyidstr || !*keyidstr || !pincb)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
if ((err = maybe_switch_app (ctrl, card, keyidstr))) if ((err = maybe_switch_app (ctrl, card, keyidstr)))
; ;
@ -2146,7 +2157,6 @@ app_writekey (card_t card, ctrl_t ctrl,
pincb, pincb_arg, keydata, keydatalen); pincb, pincb_arg, keydata, keydatalen);
} }
unlock_card (card);
if (opt.verbose) if (opt.verbose)
log_info ("operation writekey result: %s\n", gpg_strerror (err)); log_info ("operation writekey result: %s\n", gpg_strerror (err));
return err; return err;
@ -2162,11 +2172,8 @@ app_genkey (card_t card, ctrl_t ctrl, const char *keynostr,
{ {
gpg_error_t err; gpg_error_t err;
if (!card || !keynostr || !*keynostr || !pincb) if (!keynostr || !*keynostr || !pincb)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
if ((err = maybe_switch_app (ctrl, card, keynostr))) if ((err = maybe_switch_app (ctrl, card, keynostr)))
; ;
@ -2184,7 +2191,6 @@ app_genkey (card_t card, ctrl_t ctrl, const char *keynostr,
createtime, pincb, pincb_arg); createtime, pincb, pincb_arg);
} }
unlock_card (card);
if (opt.verbose) if (opt.verbose)
log_info ("operation genkey result: %s\n", gpg_strerror (err)); log_info ("operation genkey result: %s\n", gpg_strerror (err));
return err; return err;
@ -2200,18 +2206,15 @@ app_get_challenge (card_t card, ctrl_t ctrl,
{ {
gpg_error_t err; gpg_error_t err;
if (!card || !nbytes || !buffer) (void)ctrl;
if (!nbytes || !buffer)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
if (!card->ref_count) if (!card->ref_count)
err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
else else
err = iso7816_get_challenge (card->slot, nbytes, buffer); err = iso7816_get_challenge (card->slot, nbytes, buffer);
unlock_card (card);
return err; return err;
} }
@ -2225,11 +2228,8 @@ app_change_pin (card_t card, ctrl_t ctrl, const char *chvnostr,
{ {
gpg_error_t err; gpg_error_t err;
if (!card || !chvnostr || !*chvnostr || !pincb) if (!chvnostr || !*chvnostr || !pincb)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
if ((err = maybe_switch_app (ctrl, card, NULL))) if ((err = maybe_switch_app (ctrl, card, NULL)))
; ;
@ -2247,7 +2247,6 @@ app_change_pin (card_t card, ctrl_t ctrl, const char *chvnostr,
chvnostr, flags, pincb, pincb_arg); chvnostr, flags, pincb, pincb_arg);
} }
unlock_card (card);
if (opt.verbose) if (opt.verbose)
log_info ("operation change_pin result: %s\n", gpg_strerror (err)); log_info ("operation change_pin result: %s\n", gpg_strerror (err));
return err; return err;
@ -2264,11 +2263,8 @@ app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr,
{ {
gpg_error_t err; gpg_error_t err;
if (!card || !keyidstr || !*keyidstr || !pincb) if (!keyidstr || !*keyidstr || !pincb)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
if ((err = maybe_switch_app (ctrl, card, NULL))) if ((err = maybe_switch_app (ctrl, card, NULL)))
; ;
@ -2286,7 +2282,6 @@ app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr,
pincb, pincb_arg); pincb, pincb_arg);
} }
unlock_card (card);
if (opt.verbose) if (opt.verbose)
log_info ("operation check_pin result: %s\n", gpg_strerror (err)); log_info ("operation check_pin result: %s\n", gpg_strerror (err));
return err; return err;
@ -2616,12 +2611,6 @@ app_switch_active_app (card_t card, ctrl_t ctrl, const char *appname)
gpg_error_t err; gpg_error_t err;
apptype_t apptype; apptype_t apptype;
if (!card)
return gpg_error (GPG_ERR_INV_VALUE);
err = lock_card (card, ctrl);
if (err)
return err;
/* Note that in case the additional applications have not yet been /* Note that in case the additional applications have not yet been
* added to the card context (which is commonly done by means of * added to the card context (which is commonly done by means of
* "SERIALNO --all", we do that here. */ * "SERIALNO --all", we do that here. */
@ -2648,7 +2637,6 @@ app_switch_active_app (card_t card, ctrl_t ctrl, const char *appname)
err = send_serialno_and_app_status (card, 1, ctrl); err = send_serialno_and_app_status (card, 1, ctrl);
leave: leave:
unlock_card (card);
return err; return err;
} }
@ -2682,69 +2670,12 @@ card_t
app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str, app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str,
int capability) int capability)
{ {
int locked = 0; card_t card;
card_t c;
app_t a, a_prev;
lock_r_card_list (); lock_r_card_list ();
card = do_with_keygrip (ctrl, action, keygrip_str, capability);
for (c = card_top; c; c = c->next)
{
if (lock_card (c, ctrl))
{
c = NULL;
goto leave_the_loop;
}
locked = 1;
a_prev = NULL;
for (a = c->app; a; a = a->next)
{
if (!a->fnc.with_keygrip || a->need_reset)
continue;
/* Note that we need to do a re-select even for the current
* app because the last selected application (e.g. after
* init) might be a different one and we do not run
* maybe_switch_app here. Of course we we do this only iff
* we have an additional app. */
if (c->app->next)
{
if (run_reselect (ctrl, c, a, a_prev))
continue;
}
a_prev = a;
if (DBG_APP)
log_debug ("slot %d, app %s: calling with_keygrip(%s)\n",
c->slot, xstrapptype (a),
action == KEYGRIP_ACTION_SEND_DATA? "send_data":
action == KEYGRIP_ACTION_WRITE_STATUS? "status":
action == KEYGRIP_ACTION_LOOKUP? "lookup":"?");
if (!a->fnc.with_keygrip (a, ctrl, action, keygrip_str, capability))
goto leave_the_loop; /* ACTION_LOOKUP succeeded. */
}
/* Select the first app again. */
if (c->app->next)
run_reselect (ctrl, c, c->app, a_prev);
unlock_card (c);
locked = 0;
}
leave_the_loop:
/* Force switching of the app if the selected one is not the current
* one. Changing the current apptype is sufficient to do this. */
if (c && c->app && c->app->apptype != a->apptype)
ctrl->current_apptype = a->apptype;
if (locked && c)
{
unlock_card (c);
locked = 0;
}
unlock_r_card_list (); unlock_r_card_list ();
return c; return card;
} }
void void

View File

@ -154,18 +154,19 @@ hex_to_buffer (const char *string, size_t *r_length)
static void static void
do_reset (ctrl_t ctrl, int send_reset, int keep_lock) do_reset (ctrl_t ctrl, int send_reset, int keep_lock)
{ {
card_t card = ctrl->card_ctx; card_t card = card_get (ctrl, NULL);
if (card) if (card)
{ {
if (!IS_LOCKED (ctrl) && send_reset) if (!IS_LOCKED (ctrl) && send_reset)
card_reset (card, ctrl); card_reset (card);
else else
{ {
ctrl->card_ctx = NULL; ctrl->card_ctx = NULL;
ctrl->current_apptype = APPTYPE_NONE; ctrl->current_apptype = APPTYPE_NONE;
card_unref (card); card_unref_locked (card);
} }
card_put (card);
} }
/* If we hold a lock, unlock now. */ /* If we hold a lock, unlock now. */
@ -238,14 +239,14 @@ open_card (ctrl_t ctrl)
/* Explicitly open a card for a specific use of APPTYPE or SERIALNO. /* Explicitly open a card for a specific use of APPTYPE or SERIALNO.
* If OPT_ALL is set also add all possible additional apps. */ * If OPT_ALL is set also add all possible additional apps. */
static gpg_error_t static gpg_error_t
open_card_with_request (ctrl_t ctrl, open_card_with_request (card_t *card_p, ctrl_t ctrl,
const char *apptypestr, const char *serialno, const char *apptypestr, const char *serialno,
int opt_all) int opt_all)
{ {
gpg_error_t err; gpg_error_t err;
unsigned char *serialno_bin = NULL; unsigned char *serialno_bin = NULL;
size_t serialno_bin_len = 0; size_t serialno_bin_len = 0;
card_t card = ctrl->card_ctx; card_t card = card_get (ctrl, NULL);
if (serialno) if (serialno)
serialno_bin = hex_to_buffer (serialno, &serialno_bin_len); serialno_bin = hex_to_buffer (serialno, &serialno_bin_len);
@ -253,30 +254,45 @@ open_card_with_request (ctrl_t ctrl,
/* If we are already initialized for one specific application we /* If we are already initialized for one specific application we
need to check that the client didn't requested a specific need to check that the client didn't requested a specific
application different from the one in use before we continue. */ application different from the one in use before we continue. */
if (apptypestr && ctrl->card_ctx) if (apptypestr && card)
{ {
err = check_application_conflict (ctrl->card_ctx, apptypestr, err = check_application_conflict (card, apptypestr,
serialno_bin, serialno_bin_len); serialno_bin, serialno_bin_len);
if (gpg_err_code (err) == GPG_ERR_FALSE) if (gpg_err_code (err) == GPG_ERR_FALSE)
{ {
/* Different application but switching is supported. */ /* Different application but switching is supported. */
err = select_additional_application (ctrl, apptypestr); err = select_additional_application (card, ctrl, apptypestr);
} }
if (err)
card_put (card);
goto leave; goto leave;
} }
/* Re-scan USB devices. Release CARD, before the scan. */ /* Re-scan USB devices. Release CARD, before the scan. */
/* FIXME: Is a card_unref sufficient or do we need to deallocate? */ if (card)
ctrl->card_ctx = NULL; {
ctrl->current_apptype = APPTYPE_NONE; ctrl->card_ctx = NULL;
card_unref (card); ctrl->current_apptype = APPTYPE_NONE;
card_unref_locked (card);
card_put (card);
}
err = select_application (ctrl, apptypestr, 1, err = select_application (ctrl, apptypestr, 1,
serialno_bin, serialno_bin_len); serialno_bin, serialno_bin_len);
card = card_get (ctrl, NULL);
if (!err && opt_all) if (!err && opt_all)
err = select_additional_application (ctrl, NULL); {
if (card)
{
err = select_additional_application (card, ctrl, NULL);
if (err)
card_put (card);
}
}
leave: leave:
if (!err)
*card_p = card;
xfree (serialno_bin); xfree (serialno_bin);
return err; return err;
} }
@ -311,10 +327,11 @@ cmd_serialno (assuan_context_t ctx, char *line)
{ {
ctrl_t ctrl = assuan_get_pointer (ctx); ctrl_t ctrl = assuan_get_pointer (ctx);
struct server_local_s *sl; struct server_local_s *sl;
int rc = 0; gpg_error_t err = 0;
char *serial; char *serial;
const char *demand; const char *demand;
int opt_all = has_option (line, "--all"); int opt_all = has_option (line, "--all");
card_t card = NULL;
int thisslot; int thisslot;
if ( IS_LOCKED (ctrl) ) if ( IS_LOCKED (ctrl) )
@ -337,30 +354,31 @@ cmd_serialno (assuan_context_t ctx, char *line)
/* Clear the remove flag so that the open_card is able to reread it. */ /* Clear the remove flag so that the open_card is able to reread it. */
ctrl->server_local->card_removed = 0; ctrl->server_local->card_removed = 0;
rc = open_card_with_request (ctrl, *line? line:NULL, demand, opt_all); err = open_card_with_request (&card, ctrl, *line? line:NULL, demand, opt_all);
/* Now clear or set the card_removed flag for all sessions using the /* Now clear or set the card_removed flag for all sessions using the
* current slot. In the error case make sure that the flag is set * current slot. In the error case make sure that the flag is set
* for the current session. */ * for the current session. */
thisslot = ctrl->card_ctx? ctrl->card_ctx->slot : -1; thisslot = card? card->slot : -1;
for (sl=session_list; sl; sl = sl->next_session) for (sl=session_list; sl; sl = sl->next_session)
{ {
ctrl_t c = sl->ctrl_backlink; ctrl_t c = sl->ctrl_backlink;
if (c && c->card_ctx && c->card_ctx->slot == thisslot) if (c && c->card_ctx && c->card_ctx->slot == thisslot)
c->server_local->card_removed = rc? 1 : 0; c->server_local->card_removed = err? 1 : 0;
} }
if (rc) if (err)
{ {
ctrl->server_local->card_removed = 1; ctrl->server_local->card_removed = 1;
return rc; return err;
} }
serial = card_get_serialno (ctrl->card_ctx); serial = card_get_serialno (card);
card_put (card);
if (!serial) if (!serial)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
rc = assuan_write_status (ctx, "SERIALNO", serial); err = assuan_write_status (ctx, "SERIALNO", serial);
xfree (serial); xfree (serial);
return rc; return err;
} }
@ -419,12 +437,22 @@ cmd_switchapp (assuan_context_t ctx, char *line)
{ {
ctrl_t ctrl = assuan_get_pointer (ctx); ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0; gpg_error_t err = 0;
card_t card;
if ((err = open_card (ctrl))) if ((err = open_card (ctrl)))
return err; return err;
line = skip_options (line); line = skip_options (line);
return app_switch_active_app (ctrl->card_ctx, ctrl, line); card = card_get (ctrl, NULL);
if (card)
{
err = app_switch_active_app (card, ctrl, line);
card_put (card);
}
else
err = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
return err;
} }
@ -510,10 +538,15 @@ cmd_learn (assuan_context_t ctx, char *line)
int opt_multi = has_option (line, "--multi"); int opt_multi = has_option (line, "--multi");
int opt_reread = has_option (line, "--reread"); int opt_reread = has_option (line, "--reread");
unsigned int flags; unsigned int flags;
card_t card;
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
card = card_get (ctrl, NULL);
if (!card)
return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
/* Unless the force option is used we try a shortcut by identifying /* Unless the force option is used we try a shortcut by identifying
the card using a serial number and inquiring the client with the card using a serial number and inquiring the client with
that. The client may choose to cancel the operation if he already that. The client may choose to cancel the operation if he already
@ -522,25 +555,28 @@ cmd_learn (assuan_context_t ctx, char *line)
{ {
const char *reader; const char *reader;
char *serial; char *serial;
card_t card = ctrl->card_ctx;
if (!card)
return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
reader = apdu_get_reader_name (card->slot); reader = apdu_get_reader_name (card->slot);
if (!reader) if (!reader)
return out_of_core (); {
card_put (card);
return out_of_core ();
}
send_status_direct (ctrl, "READER", reader); send_status_direct (ctrl, "READER", reader);
/* No need to free the string of READER. */ /* No need to free the string of READER. */
serial = card_get_serialno (ctrl->card_ctx); serial = card_get_serialno (card);
if (!serial) if (!serial)
return gpg_error (GPG_ERR_INV_VALUE); {
card_put (card);
return gpg_error (GPG_ERR_INV_VALUE);
}
rc = assuan_write_status (ctx, "SERIALNO", serial); rc = assuan_write_status (ctx, "SERIALNO", serial);
if (rc < 0) if (rc < 0)
{ {
xfree (serial); xfree (serial);
card_put (card);
return out_of_core (); return out_of_core ();
} }
@ -552,6 +588,7 @@ cmd_learn (assuan_context_t ctx, char *line)
if (rc < 0) if (rc < 0)
{ {
xfree (serial); xfree (serial);
card_put (card);
return out_of_core (); return out_of_core ();
} }
rc = assuan_inquire (ctx, command, NULL, NULL, 0); rc = assuan_inquire (ctx, command, NULL, NULL, 0);
@ -562,6 +599,7 @@ cmd_learn (assuan_context_t ctx, char *line)
log_error ("inquire KNOWNCARDP failed: %s\n", log_error ("inquire KNOWNCARDP failed: %s\n",
gpg_strerror (rc)); gpg_strerror (rc));
xfree (serial); xfree (serial);
card_put (card);
return rc; return rc;
} }
/* Not canceled, so we have to proceed. */ /* Not canceled, so we have to proceed. */
@ -580,8 +618,9 @@ cmd_learn (assuan_context_t ctx, char *line)
flags |= APP_LEARN_FLAG_REREAD; flags |= APP_LEARN_FLAG_REREAD;
if (!rc) if (!rc)
rc = app_write_learn_status (ctrl->card_ctx, ctrl, flags); rc = app_write_learn_status (card, ctrl, flags);
card_put (card);
return rc; return rc;
} }
@ -598,6 +637,7 @@ cmd_readcert (assuan_context_t ctx, char *line)
int rc; int rc;
unsigned char *cert; unsigned char *cert;
size_t ncert; size_t ncert;
card_t card;
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
@ -606,9 +646,17 @@ cmd_readcert (assuan_context_t ctx, char *line)
if (!line) if (!line)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
rc = app_readcert (ctrl->card_ctx, ctrl, line, &cert, &ncert); card = card_get (ctrl, NULL);
if (!card)
{
xfree (line);
return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
}
rc = app_readcert (card, ctrl, line, &cert, &ncert);
if (rc) if (rc)
log_error ("app_readcert failed: %s\n", gpg_strerror (rc)); log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
card_put (card);
xfree (line); xfree (line);
line = NULL; line = NULL;
if (!rc) if (!rc)
@ -708,7 +756,7 @@ cmd_readkey (assuan_context_t ctx, char *line)
unsigned char *pk = NULL; unsigned char *pk = NULL;
size_t pklen; size_t pklen;
card_t card; card_t card;
int direct = 0; const char *keygrip = NULL;
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
@ -727,22 +775,13 @@ cmd_readkey (assuan_context_t ctx, char *line)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
if (strlen (line) == 40) if (strlen (line) == 40)
{ keygrip = line;
card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, line, 0);
direct = 1;
}
else
card = ctrl->card_ctx;
card = card_get (ctrl, keygrip);
if (card) if (card)
{ {
if (direct)
card_ref (card);
rc = do_readkey (card, ctrl, line, opt_info, &pk, &pklen); rc = do_readkey (card, ctrl, line, opt_info, &pk, &pklen);
card_put (card);
if (direct)
card_unref (card);
} }
else else
rc = gpg_error (GPG_ERR_NO_SECKEY); rc = gpg_error (GPG_ERR_NO_SECKEY);
@ -923,7 +962,7 @@ cmd_pksign (assuan_context_t ctx, char *line)
char *keyidstr; char *keyidstr;
int hash_algo; int hash_algo;
card_t card; card_t card;
int direct = 0; const char *keygrip = NULL;
if (has_option (line, "--hash=rmd160")) if (has_option (line, "--hash=rmd160"))
hash_algo = GCRY_MD_RMD160; hash_algo = GCRY_MD_RMD160;
@ -961,24 +1000,17 @@ cmd_pksign (assuan_context_t ctx, char *line)
/* When it's a keygrip, we directly use the card, with no change of /* When it's a keygrip, we directly use the card, with no change of
ctrl->card_ctx. */ ctrl->card_ctx. */
if (strlen (keyidstr) == 40) if (strlen (keyidstr) == 40)
{ keygrip = keyidstr;
card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr, 0);
direct = 1;
}
else
card = ctrl->card_ctx;
card = card_get (ctrl, keygrip);
if (card) if (card)
{ {
if (direct)
card_ref (card);
rc = app_sign (card, ctrl, rc = app_sign (card, ctrl,
keyidstr, hash_algo, keyidstr, hash_algo,
pin_cb, ctx, pin_cb, ctx,
ctrl->in_data.value, ctrl->in_data.valuelen, ctrl->in_data.value, ctrl->in_data.valuelen,
&outdata, &outdatalen); &outdata, &outdatalen);
if (direct) card_put (card);
card_unref (card);
} }
else else
rc = gpg_error (GPG_ERR_NO_SECKEY); rc = gpg_error (GPG_ERR_NO_SECKEY);
@ -1011,14 +1043,11 @@ cmd_pkauth (assuan_context_t ctx, char *line)
size_t outdatalen; size_t outdatalen;
char *keyidstr; char *keyidstr;
card_t card; card_t card;
int direct = 0; const char *keygrip = NULL;
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
/* We have to use a copy of the key ID because the function may use /* We have to use a copy of the key ID because the function may use
the pin_cb which in turn uses the assuan line buffer and thus the pin_cb which in turn uses the assuan line buffer and thus
overwriting the original line with the keyid */ overwriting the original line with the keyid */
@ -1029,25 +1058,18 @@ cmd_pkauth (assuan_context_t ctx, char *line)
/* When it's a keygrip, we directly use CARD, with no change of /* When it's a keygrip, we directly use CARD, with no change of
ctrl->card_ctx. */ ctrl->card_ctx. */
if (strlen (keyidstr) == 40) if (strlen (keyidstr) == 40)
{ keygrip = keyidstr;
card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr, 0);
direct = 1;
}
else
card = ctrl->card_ctx;
card = card_get (ctrl, keygrip);
if (card) if (card)
{ {
if (direct)
card_ref (card);
rc = app_auth (card, ctrl, keyidstr, pin_cb, ctx, rc = app_auth (card, ctrl, keyidstr, pin_cb, ctx,
ctrl->in_data.value, ctrl->in_data.valuelen, ctrl->in_data.value, ctrl->in_data.valuelen,
&outdata, &outdatalen); &outdata, &outdatalen);
if (direct) card_put (card);
card_unref (card);
} }
else else
rc = gpg_error (GPG_ERR_NO_SECKEY); rc = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
xfree (keyidstr); xfree (keyidstr);
if (rc) if (rc)
@ -1078,7 +1100,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
char *keyidstr; char *keyidstr;
unsigned int infoflags; unsigned int infoflags;
card_t card; card_t card;
int direct = 0; const char *keygrip = NULL;
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
@ -1090,22 +1112,15 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
/* When it's a keygrip, we directly use CARD, with no change of /* When it's a keygrip, we directly use CARD, with no change of
ctrl->card_ctx. */ ctrl->card_ctx. */
if (strlen (keyidstr) == 40) if (strlen (keyidstr) == 40)
{ keygrip = keyidstr;
card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr, 0);
direct = 1;
}
else
card = ctrl->card_ctx;
card = card_get (ctrl, keygrip);
if (card) if (card)
{ {
if (direct)
card_ref (card);
rc = app_decipher (card, ctrl, keyidstr, pin_cb, ctx, rc = app_decipher (card, ctrl, keyidstr, pin_cb, ctx,
ctrl->in_data.value, ctrl->in_data.valuelen, ctrl->in_data.value, ctrl->in_data.valuelen,
&outdata, &outdatalen, &infoflags); &outdata, &outdatalen, &infoflags);
if (direct) card_put (card);
card_unref (card);
} }
else else
rc = gpg_error (GPG_ERR_NO_SECKEY); rc = gpg_error (GPG_ERR_NO_SECKEY);
@ -1154,7 +1169,7 @@ cmd_getattr (assuan_context_t ctx, char *line)
int rc; int rc;
const char *keyword; const char *keyword;
card_t card; card_t card;
int direct = 0; const char *keygrip = NULL;
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
@ -1166,24 +1181,15 @@ cmd_getattr (assuan_context_t ctx, char *line)
*line++ = 0; *line++ = 0;
if (strlen (line) == 40) if (strlen (line) == 40)
{ keygrip = line;
card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, line, 0);
direct = 1;
}
else
card = ctrl->card_ctx;
card = card_get (ctrl, keygrip);
if (card) if (card)
{ {
if (direct)
card_ref (card);
/* FIXME: Applications should not return sensitive data if the card /* FIXME: Applications should not return sensitive data if the card
is locked. */ is locked. */
rc = app_getattr (card, ctrl, keyword); rc = app_getattr (card, ctrl, keyword);
card_put (card);
if (direct)
card_unref (card);
} }
else else
rc = gpg_error (GPG_ERR_NO_SECKEY); rc = gpg_error (GPG_ERR_NO_SECKEY);
@ -1219,6 +1225,7 @@ cmd_setattr (assuan_context_t ctx, char *orig_line)
size_t nbytes; size_t nbytes;
char *line, *linebuf; char *line, *linebuf;
int opt_inquire; int opt_inquire;
card_t card;
opt_inquire = has_option (orig_line, "--inquire"); opt_inquire = has_option (orig_line, "--inquire");
orig_line = skip_options (orig_line); orig_line = skip_options (orig_line);
@ -1232,6 +1239,13 @@ cmd_setattr (assuan_context_t ctx, char *orig_line)
if (!line) if (!line)
return out_of_core (); return out_of_core ();
card = card_get (ctrl, NULL);
if (!card)
{
xfree (linebuf);
return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
}
keyword = line; keyword = line;
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
; ;
@ -1248,7 +1262,7 @@ cmd_setattr (assuan_context_t ctx, char *orig_line)
assuan_end_confidential (ctx); assuan_end_confidential (ctx);
if (!err) if (!err)
{ {
err = app_setattr (ctrl->card_ctx, ctrl, keyword, pin_cb, ctx, err = app_setattr (card, ctrl, keyword, pin_cb, ctx,
value, nbytes); value, nbytes);
wipememory (value, nbytes); wipememory (value, nbytes);
xfree (value); xfree (value);
@ -1258,10 +1272,11 @@ cmd_setattr (assuan_context_t ctx, char *orig_line)
else else
{ {
nbytes = percent_plus_unescape_inplace (line, 0); nbytes = percent_plus_unescape_inplace (line, 0);
err = app_setattr (ctrl->card_ctx, ctrl, keyword, pin_cb, ctx, err = app_setattr (card, ctrl, keyword, pin_cb, ctx,
(const unsigned char*)line, nbytes); (const unsigned char*)line, nbytes);
} }
card_put (card);
xfree (linebuf); xfree (linebuf);
return err; return err;
} }
@ -1286,6 +1301,7 @@ cmd_writecert (assuan_context_t ctx, char *line)
char *certid; char *certid;
unsigned char *certdata; unsigned char *certdata;
size_t certdatalen; size_t certdatalen;
card_t card;
line = skip_options (line); line = skip_options (line);
@ -1299,25 +1315,31 @@ cmd_writecert (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
if (!ctrl->card_ctx) card = card_get (ctrl, NULL);
if (!card)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
certid = xtrystrdup (certid); certid = xtrystrdup (certid);
if (!certid) if (!certid)
return out_of_core (); {
card_put (card);
return out_of_core ();
}
/* Now get the actual keydata. */ /* Now get the actual keydata. */
rc = assuan_inquire (ctx, "CERTDATA", rc = assuan_inquire (ctx, "CERTDATA",
&certdata, &certdatalen, MAXLEN_CERTDATA); &certdata, &certdatalen, MAXLEN_CERTDATA);
if (rc) if (rc)
{ {
card_put (card);
xfree (certid); xfree (certid);
return rc; return rc;
} }
/* Write the certificate to the card. */ /* Write the certificate to the card. */
rc = app_writecert (ctrl->card_ctx, ctrl, certid, rc = app_writecert (card, ctrl, certid,
pin_cb, ctx, certdata, certdatalen); pin_cb, ctx, certdata, certdatalen);
card_put (card);
xfree (certid); xfree (certid);
xfree (certdata); xfree (certdata);
@ -1348,6 +1370,7 @@ cmd_writekey (assuan_context_t ctx, char *line)
int force = has_option (line, "--force"); int force = has_option (line, "--force");
unsigned char *keydata; unsigned char *keydata;
size_t keydatalen; size_t keydatalen;
card_t card;
line = skip_options (line); line = skip_options (line);
@ -1361,12 +1384,16 @@ cmd_writekey (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
if (!ctrl->card_ctx) card = card_get (ctrl, NULL);
if (!card)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
keyid = xtrystrdup (keyid); keyid = xtrystrdup (keyid);
if (!keyid) if (!keyid)
return out_of_core (); {
card_put (card);
return out_of_core ();
}
/* Now get the actual keydata. */ /* Now get the actual keydata. */
assuan_begin_confidential (ctx); assuan_begin_confidential (ctx);
@ -1379,8 +1406,9 @@ cmd_writekey (assuan_context_t ctx, char *line)
} }
/* Write the key to the card. */ /* Write the key to the card. */
rc = app_writekey (ctrl->card_ctx, ctrl, keyid, force? 1:0, rc = app_writekey (card, ctrl, keyid, force? 1:0,
pin_cb, ctx, keydata, keydatalen); pin_cb, ctx, keydata, keydatalen);
card_put (card);
xfree (keyid); xfree (keyid);
xfree (keydata); xfree (keydata);
@ -1427,6 +1455,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
const char *s; const char *s;
char *opt_algo = NULL; char *opt_algo = NULL;
time_t timestamp; time_t timestamp;
card_t card;
force = has_option (line, "--force"); force = has_option (line, "--force");
@ -1459,7 +1488,8 @@ cmd_genkey (assuan_context_t ctx, char *line)
if ((err = open_card (ctrl))) if ((err = open_card (ctrl)))
goto leave; goto leave;
if (!ctrl->card_ctx) card = card_get (ctrl, NULL);
if (!card)
{ {
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
goto leave; goto leave;
@ -1469,11 +1499,13 @@ cmd_genkey (assuan_context_t ctx, char *line)
if (!keyref) if (!keyref)
{ {
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
card_put (card);
goto leave; goto leave;
} }
err = app_genkey (ctrl->card_ctx, ctrl, keyref, opt_algo, err = app_genkey (card, ctrl, keyref, opt_algo,
force? APP_GENKEY_FLAG_FORCE : 0, force? APP_GENKEY_FLAG_FORCE : 0,
timestamp, pin_cb, ctx); timestamp, pin_cb, ctx);
card_put (card);
leave: leave:
xfree (keyref_buffer); xfree (keyref_buffer);
@ -1497,6 +1529,7 @@ cmd_random (assuan_context_t ctx, char *line)
int rc; int rc;
size_t nbytes; size_t nbytes;
unsigned char *buffer; unsigned char *buffer;
card_t card;
if (!*line) if (!*line)
return set_error (GPG_ERR_ASS_PARAMETER, return set_error (GPG_ERR_ASS_PARAMETER,
@ -1506,14 +1539,19 @@ cmd_random (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
if (!ctrl->card_ctx) card = card_get (ctrl, NULL);
if (!card)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
buffer = xtrymalloc (nbytes); buffer = xtrymalloc (nbytes);
if (!buffer) if (!buffer)
return out_of_core (); {
card_put (card);
return out_of_core ();
}
rc = app_get_challenge (ctrl->card_ctx, ctrl, nbytes, buffer); rc = app_get_challenge (card, ctrl, nbytes, buffer);
card_put (card);
if (!rc) if (!rc)
{ {
rc = assuan_send_data (ctx, buffer, nbytes); rc = assuan_send_data (ctx, buffer, nbytes);
@ -1542,6 +1580,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
int rc; int rc;
char *chvnostr; char *chvnostr;
unsigned int flags = 0; unsigned int flags = 0;
card_t card;
if (has_option (line, "--reset")) if (has_option (line, "--reset"))
flags |= APP_CHANGE_FLAG_RESET; flags |= APP_CHANGE_FLAG_RESET;
@ -1567,13 +1606,18 @@ cmd_passwd (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
if (!ctrl->card_ctx) card = card_get (ctrl, NULL);
if (!card)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
chvnostr = xtrystrdup (chvnostr); chvnostr = xtrystrdup (chvnostr);
if (!chvnostr) if (!chvnostr)
return out_of_core (); {
rc = app_change_pin (ctrl->card_ctx, ctrl, chvnostr, flags, pin_cb, ctx); card_put (card);
return out_of_core ();
}
rc = app_change_pin (card, ctrl, chvnostr, flags, pin_cb, ctx);
card_put (card);
if (rc) if (rc)
log_error ("command passwd failed: %s\n", gpg_strerror (rc)); log_error ("command passwd failed: %s\n", gpg_strerror (rc));
xfree (chvnostr); xfree (chvnostr);
@ -1622,13 +1666,15 @@ static gpg_error_t
cmd_checkpin (assuan_context_t ctx, char *line) cmd_checkpin (assuan_context_t ctx, char *line)
{ {
ctrl_t ctrl = assuan_get_pointer (ctx); ctrl_t ctrl = assuan_get_pointer (ctx);
int rc; gpg_error_t err;
char *idstr; char *idstr;
card_t card;
if ((rc = open_card (ctrl))) if ((err = open_card (ctrl)))
return rc; return err;
if (!ctrl->card_ctx) card = card_get (ctrl, NULL);
if (!card)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
/* We have to use a copy of the key ID because the function may use /* We have to use a copy of the key ID because the function may use
@ -1636,14 +1682,18 @@ cmd_checkpin (assuan_context_t ctx, char *line)
overwriting the original line with the keyid. */ overwriting the original line with the keyid. */
idstr = xtrystrdup (line); idstr = xtrystrdup (line);
if (!idstr) if (!idstr)
return out_of_core (); {
card_put (card);
return out_of_core ();
}
rc = app_check_pin (ctrl->card_ctx, ctrl, idstr, pin_cb, ctx); err = app_check_pin (card, ctrl, idstr, pin_cb, ctx);
card_put (card);
xfree (idstr); xfree (idstr);
if (rc) if (err)
log_error ("app_check_pin failed: %s\n", gpg_strerror (rc)); log_error ("app_check_pin failed: %s\n", gpg_strerror (err));
return rc; return err;
} }
@ -1863,10 +1913,15 @@ cmd_getinfo (assuan_context_t ctx, char *line)
else if (!strcmp (line, "active_apps")) else if (!strcmp (line, "active_apps"))
{ {
ctrl_t ctrl = assuan_get_pointer (ctx); ctrl_t ctrl = assuan_get_pointer (ctx);
if (!ctrl->card_ctx) card_t card = card_get (ctrl, NULL);
if (!card)
rc = 0; /* No current card - no active apps. */ rc = 0; /* No current card - no active apps. */
else else
rc = app_send_active_apps (ctrl->card_ctx, ctrl); {
rc = app_send_active_apps (card, ctrl);
card_put (card);
}
} }
else if (!strcmp (line, "all_active_apps")) else if (!strcmp (line, "all_active_apps"))
{ {
@ -1899,7 +1954,7 @@ static gpg_error_t
cmd_restart (assuan_context_t ctx, char *line) cmd_restart (assuan_context_t ctx, char *line)
{ {
ctrl_t ctrl = assuan_get_pointer (ctx); ctrl_t ctrl = assuan_get_pointer (ctx);
card_t card = ctrl->card_ctx; card_t card = card_get (ctrl, NULL);
(void)line; (void)line;
@ -1907,7 +1962,8 @@ cmd_restart (assuan_context_t ctx, char *line)
{ {
ctrl->card_ctx = NULL; ctrl->card_ctx = NULL;
ctrl->current_apptype = APPTYPE_NONE; ctrl->current_apptype = APPTYPE_NONE;
card_unref (card); card_unref_locked (card);
card_put (card);
} }
if (locked_session && ctrl->server_local == locked_session) if (locked_session && ctrl->server_local == locked_session)
{ {
@ -1926,14 +1982,19 @@ static gpg_error_t
cmd_disconnect (assuan_context_t ctx, char *line) cmd_disconnect (assuan_context_t ctx, char *line)
{ {
ctrl_t ctrl = assuan_get_pointer (ctx); ctrl_t ctrl = assuan_get_pointer (ctx);
card_t card;
(void)line; (void)line;
if (!ctrl->card_ctx) card = card_get (ctrl, NULL);
if (card)
{
apdu_disconnect (card->slot);
card_put (card);
return 0;
}
else
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
apdu_disconnect (ctrl->card_ctx->slot);
return 0;
} }
@ -1993,7 +2054,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
card = ctrl->card_ctx; card = card_get (ctrl, NULL);
if (!card) if (!card)
return gpg_error (GPG_ERR_CARD_NOT_PRESENT); return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
@ -2074,6 +2135,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
xfree (apdu); xfree (apdu);
leave: leave:
card_put (card);
return rc; return rc;
} }
@ -2208,6 +2270,7 @@ cmd_devinfo (assuan_context_t ctx, char *line)
ctrl_t ctrl = assuan_get_pointer (ctx); ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0; gpg_error_t err = 0;
int watch = 0; int watch = 0;
card_t card;
if (has_option (line, "--watch")) if (has_option (line, "--watch"))
{ {
@ -2237,10 +2300,15 @@ cmd_devinfo (assuan_context_t ctx, char *line)
err = 0; err = 0;
/* Remove reference(s) to the card. */ card = card_get (ctrl, NULL);
ctrl->card_ctx = NULL; if (card)
ctrl->current_apptype = APPTYPE_NONE; {
card_unref (ctrl->card_ctx); /* If any, remove reference to the card in CTRL. */
ctrl->card_ctx = NULL;
ctrl->current_apptype = APPTYPE_NONE;
card_unref_locked (card);
card_put (card);
}
/* Then, keep watching the status change. */ /* Then, keep watching the status change. */
while (!err) while (!err)