aboutsummaryrefslogtreecommitdiffstats
path: root/scd/app.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/app.c')
-rw-r--r--scd/app.c558
1 files changed, 433 insertions, 125 deletions
diff --git a/scd/app.c b/scd/app.c
index 57c4b7743..fff2b307f 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -30,6 +30,11 @@
#include "apdu.h"
#include "../common/tlv.h"
+
+/* Forward declaration of internal function. */
+static gpg_error_t
+select_additional_application_internal (card_t card, apptype_t req_apptype);
+
/* Lock to protect the list of cards and its associated
* applications. */
static npth_mutex_t card_list_lock;
@@ -91,6 +96,13 @@ strapptype (apptype_t t)
}
+const char *
+xstrapptype (app_t app)
+{
+ return app? strapptype (app->apptype) : "[no_app]";
+}
+
+
/* Return the apptype for NAME. */
static apptype_t
apptype_from_name (const char *name)
@@ -109,6 +121,31 @@ apptype_from_name (const char *name)
}
+/* Return the apptype for KEYREF. This is the first part of the
+ * KEYREF up to the dot. */
+static apptype_t
+apptype_from_keyref (const char *keyref)
+{
+ int i;
+ unsigned int n;
+ const char *s;
+
+ if (!keyref)
+ return APPTYPE_NONE;
+ s = strchr (keyref, '.');
+ if (!s || s == keyref || !s[1])
+ return APPTYPE_NONE; /* Not a valid keyref. */
+ n = s - keyref;
+
+ for (i=0; app_priority_list[i].apptype; i++)
+ if (strlen (app_priority_list[i].name) == n
+ && !ascii_strncasecmp (app_priority_list[i].name, keyref, n))
+ return app_priority_list[i].apptype;
+
+ return APPTYPE_NONE;
+}
+
+
/* Initialization function to change the default app_priority_list.
* LIST is a list of comma or space separated strings with application
* names. Unknown names will only result in warning message.
@@ -231,6 +268,7 @@ app_dump_state (void)
{
log_info ("app_dump_state: card=%p slot=%d type=%s\n",
c, c->slot, strcardtype (c->cardtype));
+ /* FIXME The use of log_info risks a race! */
for (a=c->app; a; a = a->next)
log_info ("app_dump_state: app=%p type='%s'\n",
a, strapptype (a->apptype));
@@ -270,7 +308,7 @@ check_application_conflict (card_t card, const char *name,
const unsigned char *serialno_bin,
size_t serialno_bin_len)
{
- app_t app;
+ apptype_t apptype;
if (!card || !name)
return 0;
@@ -284,11 +322,9 @@ check_application_conflict (card_t card, const char *name,
return 0; /* The card does not match the requested S/N. */
}
- /* Check whether the requested NAME matches any already selected
- * application. */
- for (app = card->app; app; app = app->next)
- if (!ascii_strcasecmp (strapptype (app->apptype), name))
- return 0;
+ apptype = apptype_from_name (name);
+ if (card->app->apptype == apptype)
+ return 0;
if (card->app->apptype == APPTYPE_UNDEFINED)
return 0;
@@ -339,6 +375,7 @@ card_reset (card_t card, ctrl_t ctrl, int send_reset)
else
{
ctrl->card_ctx = NULL;
+ ctrl->current_apptype = APPTYPE_NONE;
card_unref (card);
}
@@ -608,7 +645,7 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card,
int slot;
int periodical_check_needed_this;
- slot = apdu_open_reader (l, !card_top);
+ slot = apdu_open_reader (l);
if (slot < 0)
break;
@@ -652,6 +689,22 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card,
{
err = check_application_conflict (card, name, NULL, 0);
if (!err)
+ ctrl->current_apptype = card->app ? card->app->apptype : APPTYPE_NONE;
+ else if (gpg_err_code (err) == GPG_ERR_FALSE)
+ {
+ apptype_t req_apptype = apptype_from_name (name);
+
+ if (!req_apptype)
+ err = gpg_error (GPG_ERR_NOT_FOUND);
+ else
+ {
+ err = select_additional_application_internal (card, req_apptype);
+ if (!err)
+ ctrl->current_apptype = req_apptype;
+ }
+ }
+
+ if (!err)
{
/* Note: We do not use card_ref as we are already locked. */
card->ref_count++;
@@ -662,8 +715,6 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card,
card->next = card_top;
card_top = card;
}
-
- ctrl->current_apptype = card->app ? card->app->apptype : 0;
}
unlock_card (card);
}
@@ -676,32 +727,13 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card,
}
-/* This function needs to be called with the NAME of the new
- * application to be selected on CARD. On success the application is
- * added to the list of the card's active applications as currently
- * active application. On error no new application is allocated.
- * Selecting an already selected application has no effect. */
-gpg_error_t
-select_additional_application (ctrl_t ctrl, const char *name)
+static gpg_error_t
+select_additional_application_internal (card_t card, apptype_t req_apptype)
{
gpg_error_t err = 0;
- apptype_t req_apptype;
- card_t card;
- app_t app = NULL;
+ app_t app;
int i;
- req_apptype = apptype_from_name (name);
- if (!req_apptype)
- err = 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;
-
/* Check that the requested app has not yet been put onto the list. */
for (app = card->app; app; app = app->next)
if (app->apptype == req_apptype)
@@ -713,7 +745,6 @@ select_additional_application (ctrl_t ctrl, const char *name)
app = NULL;
goto leave;
}
- app = NULL;
/* Allocate a new app object. */
app = xtrycalloc (1, sizeof *app);
@@ -723,13 +754,17 @@ select_additional_application (ctrl_t ctrl, const char *name)
log_info ("error allocating app context: %s\n", gpg_strerror (err));
goto leave;
}
+ app->card = card;
/* Find the app and run the select. */
for (i=0; app_priority_list[i].apptype; i++)
{
if (app_priority_list[i].apptype == req_apptype
&& is_app_allowed (app_priority_list[i].name))
- err = app_priority_list[i].select_func (app);
+ {
+ err = app_priority_list[i].select_func (app);
+ break;
+ }
}
if (!app_priority_list[i].apptype
|| (err && gpg_err_code (err) != GPG_ERR_OBJ_TERM_STATE))
@@ -742,12 +777,131 @@ select_additional_application (ctrl_t ctrl, const char *name)
* reselect by maybe_switch_app after the select we just did. */
app->next = card->app;
card->app = app;
- ctrl->current_apptype = app->apptype;
- log_error ("added app '%s' to the card context\n", strapptype(app->apptype));
+ log_info ("added app '%s' to the card context and switched\n",
+ strapptype (app->apptype));
leave:
+ if (err)
+ xfree (app);
+ return err;
+}
+
+
+/* Add all possible additional applications to the card context but do
+ * not change the current one. This current works only for Yubikeys. */
+static gpg_error_t
+select_all_additional_applications_internal (card_t card)
+{
+ gpg_error_t err = 0;
+ apptype_t candidates[3];
+ int i, j;
+
+ if (card->cardtype == CARDTYPE_YUBIKEY)
+ {
+ candidates[0] = APPTYPE_OPENPGP;
+ candidates[1] = APPTYPE_PIV;
+ candidates[2] = APPTYPE_NONE;
+ }
+ else
+ {
+ candidates[0] = APPTYPE_NONE;
+ }
+
+ /* Find the app and run the select. */
+ for (i=0; app_priority_list[i].apptype; i++)
+ {
+ app_t app, app_r, app_prev;
+
+ for (j=0; candidates[j]; j++)
+ if (candidates[j] == app_priority_list[i].apptype
+ && is_app_allowed (app_priority_list[i].name))
+ break;
+ if (!candidates[j])
+ continue;
+
+ for (app = card->app; app; app = app->next)
+ if (app->apptype == candidates[j])
+ break;
+ if (app)
+ continue; /* Already on the list of apps. */
+
+ app = xtrycalloc (1, sizeof *app);
+ if (!app)
+ {
+ err = gpg_error_from_syserror ();
+ log_info ("error allocating app context: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+ app->card = card;
+ err = app_priority_list[i].select_func (app);
+ if (err)
+ {
+ log_error ("error selecting additional app '%s': %s - skipped\n",
+ strapptype (candidates[j]), gpg_strerror (err));
+ err = 0;
+ xfree (app);
+ }
+ else
+ {
+ /* Append to the list of apps. */
+ app_prev = card->app;
+ for (app_r=app_prev->next; app_r; app_prev=app_r, app_r=app_r->next)
+ ;
+ app_prev->next = app;
+ log_info ("added app '%s' to the card context\n",
+ strapptype (app->apptype));
+ }
+ }
+
+ leave:
+ return err;
+}
+
+
+/* This function needs to be called with the NAME of the new
+ * application to be selected on CARD. On success the application is
+ * added to the list of the card's active applications as currently
+ * active application. On error no new application is allocated.
+ * Selecting an already selected application has no effect. */
+gpg_error_t
+select_additional_application (ctrl_t ctrl, const char *name)
+{
+ gpg_error_t err = 0;
+ apptype_t req_apptype;
+ card_t card;
+
+ if (!name)
+ req_apptype = 0;
+ else
+ {
+ req_apptype = apptype_from_name (name);
+ if (!req_apptype)
+ 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)
+ {
+ err = select_additional_application_internal (card, req_apptype);
+ if (!err)
+ {
+ ctrl->current_apptype = req_apptype;
+ log_debug ("current_apptype is set to %s\n", name);
+ }
+ }
+ else
+ {
+ err = select_all_additional_applications_internal (card);
+ }
+
unlock_card (card);
- xfree (app);
return err;
}
@@ -809,8 +963,6 @@ deallocate_card (card_t card)
xfree (a);
}
- scd_clear_current_app (card);
-
xfree (card->serialno);
unlock_card (card);
xfree (card);
@@ -944,10 +1096,12 @@ app_get_serialno (app_t app)
* that the new active app will be moved to the head of the list at
* CARD->app. Thus function must be called with the card lock held. */
static gpg_error_t
-maybe_switch_app (ctrl_t ctrl, card_t card)
+maybe_switch_app (ctrl_t ctrl, card_t card, const char *keyref)
{
gpg_error_t err;
- app_t app, app_prev;
+ app_t app;
+ app_t app_prev = NULL;
+ apptype_t apptype;
if (!card->ref_count || !card->app)
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
@@ -958,51 +1112,117 @@ maybe_switch_app (ctrl_t ctrl, card_t card)
ctrl->current_apptype = card->app->apptype;
return 0;
}
- log_debug ("card=%p want=%s card->app=%s\n",
- card, strapptype (ctrl->current_apptype),
- strapptype (card->app->apptype));
- app_dump_state ();
- if (ctrl->current_apptype == card->app->apptype)
- return 0; /* No need to switch. */
- app_prev = card->app;
- for (app = app_prev->next; app; app_prev = app, app = app->next)
- if (app->apptype == ctrl->current_apptype)
- break;
+ if (DBG_APP)
+ log_debug ("slot %d: have=%s want=%s keyref=%s\n",
+ card->slot, strapptype (card->app->apptype),
+ strapptype (ctrl->current_apptype),
+ keyref? keyref:"[none]");
+
+ app = NULL;
+ if (keyref)
+ {
+ /* Switch based on the requested KEYREF. */
+ apptype = apptype_from_keyref (keyref);
+ if (apptype)
+ {
+ for (app = card->app; app; app_prev = app, app = app->next)
+ if (app->apptype == apptype)
+ break;
+ if (!app_prev && ctrl->current_apptype == card->app->apptype)
+ return 0; /* Already the first app - no need to switch. */
+ }
+ else if (strlen (keyref) == 40)
+ {
+ /* This looks like a keygrip. Iterate over all apps to find
+ * the corresponding app. */
+ for (app = card->app; app; app_prev = app, app = app->next)
+ if (app->fnc.with_keygrip
+ && !app->fnc.with_keygrip (app, ctrl,
+ KEYGRIP_ACTION_LOOKUP, keyref))
+ break;
+ if (!app_prev && ctrl->current_apptype == card->app->apptype)
+ return 0; /* Already the first app - no need to switch. */
+ }
+ }
+
+ if (!app)
+ {
+ /* Switch based on the current application of this connection or
+ * if a keyref based switch didn't worked. */
+ if (ctrl->current_apptype == card->app->apptype)
+ return 0; /* No need to switch. */
+ app_prev = card->app;
+ for (app = app_prev->next; app; app_prev = app, app = app->next)
+ if (app->apptype == ctrl->current_apptype)
+ break;
+ }
if (!app)
return gpg_error (GPG_ERR_WRONG_CARD);
if (!app->fnc.reselect)
{
log_error ("oops: reselect function missing for '%s'\n",
- strapptype(app->apptype));
+ strapptype (app->apptype));
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
}
err = app->fnc.reselect (app, ctrl);
if (err)
{
- log_error ("error re-selecting '%s': %s\n",
- strapptype(app->apptype), gpg_strerror (err));
+ log_error ("card %d: error re-selecting '%s': %s\n",
+ card->slot, xstrapptype (app), gpg_strerror (err));
return err;
}
- /* Swap APP with the head of the app list. Note that APP is not the
- * head of the list. */
- app_prev->next = app->next;
- app->next = card->app;
- card->app = app;
+
+ /* Swap APP with the head of the app list if needed. Note that APP
+ * is not the head of the list. */
+ if (app_prev)
+ {
+ app_prev->next = app->next;
+ app->next = card->app;
+ card->app = app;
+ }
+
+ if (opt.verbose)
+ log_info ("card %d: %s '%s'\n",
+ card->slot, app_prev? "switched to":"re-selected",
+ xstrapptype (app));
+
ctrl->current_apptype = app->apptype;
- log_error ("switched to '%s'\n", strapptype(app->apptype));
return 0;
}
+/* Helper for app_write_learn_status. */
+static gpg_error_t
+write_learn_status_core (card_t card, app_t app, ctrl_t ctrl,
+ unsigned int flags)
+{
+ /* We do not send CARD and APPTYPE if only keypairinfo is requested. */
+ if (!(flags & APP_LEARN_FLAG_KEYPAIRINFO))
+ {
+ if (card && card->cardtype)
+ send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype));
+ if (card && card->cardversion)
+ send_status_printf (ctrl, "CARDVERSION", "%X", card->cardversion);
+ if (app->apptype)
+ send_status_direct (ctrl, "APPTYPE", strapptype (app->apptype));
+ if (app->appversion)
+ send_status_printf (ctrl, "APPVERSION", "%X", app->appversion);
+ }
+
+ return app->fnc.learn_status (app, ctrl, flags);
+}
+
+
/* Write out the application specific status lines for the LEARN
command. */
gpg_error_t
app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
{
- gpg_error_t err;
+ gpg_error_t err, err2;
app_t app;
+ int any_reselect = 0;
if (!card)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -1011,29 +1231,43 @@ app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ /* Always make sure that the current app for this connection has
+ * been selected and is at the top of the list. */
+ if ((err = maybe_switch_app (ctrl, card, NULL)))
;
else if (!card->app->fnc.learn_status)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
{
- app = card->app;
-
- /* We do not send CARD and APPTYPE if only keypairinfo is requested. */
- if (!(flags &1))
+ err = write_learn_status_core (card, card->app, ctrl, flags);
+ if (!err && card->app->fnc.reselect && (flags & APP_LEARN_FLAG_MULTI))
{
- if (card->cardtype)
- send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype));
- if (card->cardversion)
- send_status_printf (ctrl, "CARDVERSION", "%X", card->cardversion);
- if (app->apptype)
- send_status_direct (ctrl, "APPTYPE", strapptype (app->apptype));
- if (app->appversion)
- send_status_printf (ctrl, "APPVERSION", "%X", app->appversion);
- /* FIXME: Send info for the other active apps of the card? */
+ /* The current app has the reselect feature so that we can
+ * loop over all other apps which are capable of a reselect
+ * and finally reselect the first app again. Note that we
+ * did the learn for the currently selected card above. */
+ app = card->app;
+ for (app = app->next; app && !err; app = app->next)
+ if (app->fnc.reselect)
+ {
+ any_reselect = 1;
+ err = app->fnc.reselect (app, ctrl);
+ if (!err)
+ err = write_learn_status_core (NULL, app, ctrl, flags);
+ }
+ app = card->app;
+ if (any_reselect)
+ {
+ err2 = app->fnc.reselect (app, ctrl);
+ if (err2)
+ {
+ log_error ("error re-selecting '%s': %s\n",
+ strapptype(app->apptype), gpg_strerror (err2));
+ if (!err)
+ err = err2;
+ }
+ }
}
-
- err = app->fnc.learn_status (app, ctrl, flags);
}
unlock_card (card);
@@ -1057,12 +1291,17 @@ app_readcert (card_t card, ctrl_t ctrl, const char *certid,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, certid)))
;
else if (!card->app->fnc.readcert)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.readcert (card->app, certid, cert, certlen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling readcert(%s)\n",
+ card->slot, xstrapptype (card->app), certid);
+ err = card->app->fnc.readcert (card->app, certid, cert, certlen);
+ }
unlock_card (card);
return err;
@@ -1094,12 +1333,17 @@ app_readkey (card_t card, ctrl_t ctrl, const char *keyid, unsigned int flags,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, keyid)))
;
else if (!card->app->fnc.readkey)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling readkey(%s)\n",
+ card->slot, xstrapptype (card->app), keyid);
+ err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen);
+ }
unlock_card (card);
return err;
@@ -1118,7 +1362,7 @@ app_getattr (card_t card, ctrl_t ctrl, const char *name)
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, NULL)))
;
else if (name && !strcmp (name, "CARDTYPE"))
{
@@ -1144,7 +1388,12 @@ app_getattr (card_t card, ctrl_t ctrl, const char *name)
else if (!card->app->fnc.getattr)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.getattr (card->app, ctrl, name);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling getattr(%s)\n",
+ card->slot, xstrapptype (card->app), name);
+ err = card->app->fnc.getattr (card->app, ctrl, name);
+ }
unlock_card (card);
return err;
@@ -1166,13 +1415,18 @@ app_setattr (card_t card, ctrl_t ctrl, const char *name,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, NULL)))
;
else if (!card->app->fnc.setattr)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.setattr (card->app, name, pincb, pincb_arg,
- value, valuelen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling setattr(%s)\n",
+ card->slot, xstrapptype (card->app), name);
+ err = card->app->fnc.setattr (card->app, name, pincb, pincb_arg,
+ value, valuelen);
+ }
unlock_card (card);
return err;
@@ -1197,15 +1451,20 @@ app_sign (card_t card, ctrl_t ctrl, const char *keyidstr, int hashalgo,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, keyidstr)))
;
else if (!card->app->fnc.sign)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.sign (card->app, keyidstr, hashalgo,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling sign(%s)\n",
+ card->slot, xstrapptype (card->app), keyidstr);
+ err = card->app->fnc.sign (card->app, keyidstr, hashalgo,
+ pincb, pincb_arg,
+ indata, indatalen,
+ outdata, outdatalen);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1233,15 +1492,20 @@ app_auth (card_t card, ctrl_t ctrl, const char *keyidstr,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, keyidstr)))
;
else if (!card->app->fnc.auth)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.auth (card->app, keyidstr,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling auth(%s)\n",
+ card->slot, xstrapptype (card->app), keyidstr);
+ err = card->app->fnc.auth (card->app, keyidstr,
+ pincb, pincb_arg,
+ indata, indatalen,
+ outdata, outdatalen);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1271,16 +1535,21 @@ app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, keyidstr)))
;
else if (!card->app->fnc.decipher)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.decipher (card->app, keyidstr,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen,
- r_info);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling decipher(%s)\n",
+ card->slot, xstrapptype (card->app), keyidstr);
+ err = card->app->fnc.decipher (card->app, keyidstr,
+ pincb, pincb_arg,
+ indata, indatalen,
+ outdata, outdatalen,
+ r_info);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1305,13 +1574,18 @@ app_writecert (card_t card, ctrl_t ctrl,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, certidstr)))
;
else if (!card->app->fnc.writecert)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.writecert (card->app, ctrl, certidstr,
- pincb, pincb_arg, data, datalen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling writecert(%s)\n",
+ card->slot, xstrapptype (card->app), certidstr);
+ err = card->app->fnc.writecert (card->app, ctrl, certidstr,
+ pincb, pincb_arg, data, datalen);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1336,13 +1610,18 @@ app_writekey (card_t card, ctrl_t ctrl,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, keyidstr)))
;
else if (!card->app->fnc.writekey)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.writekey (card->app, ctrl, keyidstr, flags,
- pincb, pincb_arg, keydata, keydatalen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling writekey(%s)\n",
+ card->slot, xstrapptype (card->app), keyidstr);
+ err = card->app->fnc.writekey (card->app, ctrl, keyidstr, flags,
+ pincb, pincb_arg, keydata, keydatalen);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1366,13 +1645,18 @@ app_genkey (card_t card, ctrl_t ctrl, const char *keynostr,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, keynostr)))
;
else if (!card->app->fnc.genkey)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.genkey (card->app, ctrl, keynostr, keytype, flags,
- createtime, pincb, pincb_arg);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling genkey(%s)\n",
+ card->slot, xstrapptype (card->app), keynostr);
+ err = card->app->fnc.genkey (card->app, ctrl, keynostr, keytype, flags,
+ createtime, pincb, pincb_arg);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1421,13 +1705,18 @@ app_change_pin (card_t card, ctrl_t ctrl, const char *chvnostr,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, NULL)))
;
else if (!card->app->fnc.change_pin)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.change_pin (card->app, ctrl,
- chvnostr, flags, pincb, pincb_arg);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling change_pin(%s)\n",
+ card->slot, xstrapptype (card->app), chvnostr);
+ err = card->app->fnc.change_pin (card->app, ctrl,
+ chvnostr, flags, pincb, pincb_arg);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1452,12 +1741,17 @@ app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, NULL)))
;
else if (!card->app->fnc.check_pin)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.check_pin (card->app, keyidstr, pincb, pincb_arg);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling check_pin(%s)\n",
+ card->slot, xstrapptype (card->app), keyidstr);
+ err = card->app->fnc.check_pin (card->app, keyidstr, pincb, pincb_arg);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1691,24 +1985,33 @@ app_send_card_list (ctrl_t ctrl)
card_t
app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str)
{
- gpg_error_t err;
+ int locked = 0;
card_t c;
app_t a;
npth_mutex_lock (&card_list_lock);
for (c = card_top; c; c = c->next)
- for (a = c->app; a; a = a->next)
- if (a->fnc.with_keygrip)
+ {
+ if (lock_card (c, ctrl))
{
- if (!lock_card (c, ctrl))
- {
- err = a->fnc.with_keygrip (a, ctrl, action, keygrip_str);
- unlock_card (c);
- if (!err)
- goto leave_the_loop;
- }
+ c = NULL;
+ goto leave_the_loop;
}
+ locked = 1;
+ for (a = c->app; a; a = a->next)
+ if (a->fnc.with_keygrip)
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling with_keygrip(action=%d)\n",
+ c->slot, xstrapptype (a), action);
+ if (!a->fnc.with_keygrip (a, ctrl, action, keygrip_str))
+ goto leave_the_loop;
+ }
+ unlock_card (c);
+ locked = 0;
+ }
+
leave_the_loop:
@@ -1721,6 +2024,11 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str)
if (c && c->app && c->app->apptype != a->apptype)
ctrl->current_apptype = a->apptype;
+ if (locked && c)
+ {
+ unlock_card (c);
+ locked = 0;
+ }
npth_mutex_unlock (&card_list_lock);
return c;
}