diff options
Diffstat (limited to 'scd/app.c')
-rw-r--r-- | scd/app.c | 558 |
1 files changed, 433 insertions, 125 deletions
@@ -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; } |