diff --git a/scd/app-common.h b/scd/app-common.h index d1b0a9a17..2eeffbe95 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -255,11 +255,12 @@ void application_notify_card_reset (int slot); gpg_error_t check_application_conflict (card_t card, const char *name, const unsigned char *serialno_bin, 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, int scan, const unsigned char *serialno_bin, 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, 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); -card_t card_ref (card_t card); -void card_unref (card_t card); +card_t card_get (ctrl_t ctrl, const char *keygrip); +void card_put (card_t card); void card_unref_locked (card_t card); gpg_error_t app_munge_serialno (card_t card); diff --git a/scd/app.c b/scd/app.c index 1b5bfad53..a86b08cd2 100644 --- a/scd/app.c +++ b/scd/app.c @@ -503,18 +503,16 @@ check_application_conflict (card_t card, const char *name, gpg_error_t -card_reset (card_t card, ctrl_t ctrl) +card_reset (card_t card) { gpg_error_t err = 0; int sw; - lock_card (card, ctrl); sw = apdu_reset (card->slot); if (sw) err = gpg_error (GPG_ERR_CARD_RESET); card->reset_requested = 1; - unlock_card (card); scd_kick_the_loop (); gnupg_sleep (1); @@ -862,7 +860,6 @@ select_application (ctrl_t ctrl, const char *name, if (!err) { - /* Note: We do not use card_ref as we are already locked. */ card->ref_count++; ctrl->card_ctx = card; if (card_prev) @@ -895,7 +892,8 @@ app_switch_current_card (ctrl_t ctrl, lock_r_card_list (); - if (!ctrl->card_ctx) + cardtmp = ctrl->card_ctx; + if (!cardtmp) { err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); goto leave; @@ -915,10 +913,10 @@ app_switch_current_card (ctrl_t ctrl, goto leave; } - /* Note: We do not use card_ref here because we only swap the - * context of the current session and there is no chance of a - * context switch. This also works if the card stays the same. */ - cardtmp = ctrl->card_ctx; + /* Note: We do not lock CARD and CARDTMP here because we only + * swap the context of the current session and there is no + * chance of a context switch. This also works if the card + * stays the same. */ ctrl->card_ctx = card; card->ref_count++; 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. * Selecting an already selected application has no effect. */ 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; apptype_t req_apptype; - card_t card; if (!name) req_apptype = 0; @@ -1092,14 +1089,6 @@ select_additional_application (ctrl_t ctrl, const char *name) 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); @@ -1115,7 +1104,6 @@ select_additional_application (ctrl_t ctrl, const char *name) err = select_all_additional_applications_internal (ctrl, card); } - unlock_card (card); return err; } @@ -1183,35 +1171,104 @@ deallocate_card (card_t card) } -/* Increment the reference counter of CARD. Returns CARD. */ -card_t -card_ref (card_t card) +static card_t +do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str, + int capability) { - lock_card (card, NULL); - ++card->ref_count; - unlock_card (card); - return card; + int locked = 0; + card_t c; + app_t a, a_prev; + + 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 - * reference counting to track the users of the card's application and - * are deferring the actual deallocation to allow for a later reuse by - * a new connection. Using NULL for CARD is a no-op. */ -void -card_unref (card_t card) +/* Locking access to the card-list and CARD, returns CARD. */ +card_t +card_get (ctrl_t ctrl, const char *keygrip) { - if (!card) - return; + card_t card; + 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 useful so that a card does not get reset even if only one session is using the card - this way the PIN cache and other cached data are preserved. */ - - lock_card (card, NULL); - card_unref_locked (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; 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 * been selected and is at the top of the list. */ 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; } @@ -1781,12 +1830,6 @@ app_readcert (card_t card, ctrl_t ctrl, const char *certid, { 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))) ; 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); } - unlock_card (card); return err; } @@ -1826,11 +1868,8 @@ app_readkey (card_t card, ctrl_t ctrl, const char *keyid, unsigned int flags, if (pklen) *pklen = 0; - if (!card || !keyid) + if (!keyid) return gpg_error (GPG_ERR_INV_VALUE); - err = lock_card (card, ctrl); - if (err) - return err; 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); } - unlock_card (card); return err; } @@ -1858,11 +1896,8 @@ app_getattr (card_t card, ctrl_t ctrl, const char *name) { gpg_error_t err; - if (!card || !name || !*name) + if (!name || !*name) return gpg_error (GPG_ERR_INV_VALUE); - err = lock_card (card, ctrl); - if (err) - return err; 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); } - unlock_card (card); return err; } @@ -1914,11 +1948,8 @@ app_setattr (card_t card, ctrl_t ctrl, const char *name, { gpg_error_t err; - if (!card || !name || !*name || !value) + if (!name || !*name || !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))) ; @@ -1936,7 +1967,6 @@ app_setattr (card_t card, ctrl_t ctrl, const char *name, value, valuelen); } - unlock_card (card); return err; } @@ -1953,11 +1983,8 @@ app_sign (card_t card, ctrl_t ctrl, const char *keyidstr, int hashalgo, { gpg_error_t err; - if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) + if (!indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - err = lock_card (card, ctrl); - if (err) - return err; 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); } - unlock_card (card); if (opt.verbose) log_info ("operation sign result: %s\n", gpg_strerror (err)); return err; @@ -1997,11 +2023,8 @@ app_auth (card_t card, ctrl_t ctrl, const char *keyidstr, { gpg_error_t err; - if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) + if (!indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - err = lock_card (card, ctrl); - if (err) - return err; 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); } - unlock_card (card); if (opt.verbose) log_info ("operation auth result: %s\n", gpg_strerror (err)); return err; @@ -2043,11 +2065,8 @@ app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr, *r_info = 0; - if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) + if (!indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - err = lock_card (card, ctrl); - if (err) - return err; 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); } - unlock_card (card); if (opt.verbose) log_info ("operation decipher result: %s\n", gpg_strerror (err)); return err; @@ -2085,11 +2103,8 @@ app_writecert (card_t card, ctrl_t ctrl, { gpg_error_t err; - if (!card || !certidstr || !*certidstr || !pincb) + if (!certidstr || !*certidstr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - err = lock_card (card, ctrl); - if (err) - return err; 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); } - unlock_card (card); if (opt.verbose) log_info ("operation writecert result: %s\n", gpg_strerror (err)); return err; @@ -2124,11 +2138,8 @@ app_writekey (card_t card, ctrl_t ctrl, { gpg_error_t err; - if (!card || !keyidstr || !*keyidstr || !pincb) + if (!keyidstr || !*keyidstr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - err = lock_card (card, ctrl); - if (err) - return err; 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); } - unlock_card (card); if (opt.verbose) log_info ("operation writekey result: %s\n", gpg_strerror (err)); return err; @@ -2162,11 +2172,8 @@ app_genkey (card_t card, ctrl_t ctrl, const char *keynostr, { gpg_error_t err; - if (!card || !keynostr || !*keynostr || !pincb) + if (!keynostr || !*keynostr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - err = lock_card (card, ctrl); - if (err) - return err; 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); } - unlock_card (card); if (opt.verbose) log_info ("operation genkey result: %s\n", gpg_strerror (err)); return err; @@ -2200,18 +2206,15 @@ app_get_challenge (card_t card, ctrl_t ctrl, { gpg_error_t err; - if (!card || !nbytes || !buffer) + (void)ctrl; + if (!nbytes || !buffer) return gpg_error (GPG_ERR_INV_VALUE); - err = lock_card (card, ctrl); - if (err) - return err; if (!card->ref_count) err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); else err = iso7816_get_challenge (card->slot, nbytes, buffer); - unlock_card (card); return err; } @@ -2225,11 +2228,8 @@ app_change_pin (card_t card, ctrl_t ctrl, const char *chvnostr, { gpg_error_t err; - if (!card || !chvnostr || !*chvnostr || !pincb) + if (!chvnostr || !*chvnostr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - err = lock_card (card, ctrl); - if (err) - return err; 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); } - unlock_card (card); if (opt.verbose) log_info ("operation change_pin result: %s\n", gpg_strerror (err)); return err; @@ -2264,11 +2263,8 @@ app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr, { gpg_error_t err; - if (!card || !keyidstr || !*keyidstr || !pincb) + if (!keyidstr || !*keyidstr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - err = lock_card (card, ctrl); - if (err) - return err; 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); } - unlock_card (card); if (opt.verbose) log_info ("operation check_pin result: %s\n", gpg_strerror (err)); return err; @@ -2616,12 +2611,6 @@ app_switch_active_app (card_t card, ctrl_t ctrl, const char *appname) gpg_error_t err; 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 * added to the card context (which is commonly done by means of * "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); leave: - unlock_card (card); return err; } @@ -2682,69 +2670,12 @@ card_t app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str, int capability) { - int locked = 0; - card_t c; - app_t a, a_prev; + card_t card; lock_r_card_list (); - - 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; - } + card = do_with_keygrip (ctrl, action, keygrip_str, capability); unlock_r_card_list (); - return c; + return card; } void diff --git a/scd/command.c b/scd/command.c index d45d9da82..5ba71a4aa 100644 --- a/scd/command.c +++ b/scd/command.c @@ -154,18 +154,19 @@ hex_to_buffer (const char *string, size_t *r_length) static void 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 (!IS_LOCKED (ctrl) && send_reset) - card_reset (card, ctrl); + card_reset (card); else { ctrl->card_ctx = NULL; ctrl->current_apptype = APPTYPE_NONE; - card_unref (card); + card_unref_locked (card); } + card_put (card); } /* 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. * If OPT_ALL is set also add all possible additional apps. */ 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, int opt_all) { gpg_error_t err; unsigned char *serialno_bin = NULL; size_t serialno_bin_len = 0; - card_t card = ctrl->card_ctx; + card_t card = card_get (ctrl, NULL); if (serialno) 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 need to check that the client didn't requested a specific 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); if (gpg_err_code (err) == GPG_ERR_FALSE) { /* 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; } /* Re-scan USB devices. Release CARD, before the scan. */ - /* FIXME: Is a card_unref sufficient or do we need to deallocate? */ - ctrl->card_ctx = NULL; - ctrl->current_apptype = APPTYPE_NONE; - card_unref (card); + if (card) + { + ctrl->card_ctx = NULL; + ctrl->current_apptype = APPTYPE_NONE; + card_unref_locked (card); + card_put (card); + } err = select_application (ctrl, apptypestr, 1, serialno_bin, serialno_bin_len); + card = card_get (ctrl, NULL); 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: + if (!err) + *card_p = card; xfree (serialno_bin); return err; } @@ -311,10 +327,11 @@ cmd_serialno (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); struct server_local_s *sl; - int rc = 0; + gpg_error_t err = 0; char *serial; const char *demand; int opt_all = has_option (line, "--all"); + card_t card = NULL; int thisslot; 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. */ 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 * current slot. In the error case make sure that the flag is set * 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) { ctrl_t c = sl->ctrl_backlink; 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; - return rc; + return err; } - serial = card_get_serialno (ctrl->card_ctx); + serial = card_get_serialno (card); + card_put (card); if (!serial) return gpg_error (GPG_ERR_INV_VALUE); - rc = assuan_write_status (ctx, "SERIALNO", serial); + err = assuan_write_status (ctx, "SERIALNO", 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); gpg_error_t err = 0; + card_t card; if ((err = open_card (ctrl))) return err; 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_reread = has_option (line, "--reread"); unsigned int flags; + card_t card; if ((rc = open_card (ctrl))) 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 the card using a serial number and inquiring the client with 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; 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); if (!reader) - return out_of_core (); + { + card_put (card); + return out_of_core (); + } send_status_direct (ctrl, "READER", reader); /* No need to free the string of READER. */ - serial = card_get_serialno (ctrl->card_ctx); + serial = card_get_serialno (card); 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); if (rc < 0) { xfree (serial); + card_put (card); return out_of_core (); } @@ -552,6 +588,7 @@ cmd_learn (assuan_context_t ctx, char *line) if (rc < 0) { xfree (serial); + card_put (card); return out_of_core (); } 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", gpg_strerror (rc)); xfree (serial); + card_put (card); return rc; } /* Not canceled, so we have to proceed. */ @@ -580,8 +618,9 @@ cmd_learn (assuan_context_t ctx, char *line) flags |= APP_LEARN_FLAG_REREAD; 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; } @@ -598,6 +637,7 @@ cmd_readcert (assuan_context_t ctx, char *line) int rc; unsigned char *cert; size_t ncert; + card_t card; if ((rc = open_card (ctrl))) return rc; @@ -606,9 +646,17 @@ cmd_readcert (assuan_context_t ctx, char *line) if (!line) 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) log_error ("app_readcert failed: %s\n", gpg_strerror (rc)); + card_put (card); xfree (line); line = NULL; if (!rc) @@ -708,7 +756,7 @@ cmd_readkey (assuan_context_t ctx, char *line) unsigned char *pk = NULL; size_t pklen; card_t card; - int direct = 0; + const char *keygrip = NULL; if ((rc = open_card (ctrl))) return rc; @@ -727,22 +775,13 @@ cmd_readkey (assuan_context_t ctx, char *line) return gpg_error_from_syserror (); if (strlen (line) == 40) - { - card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, line, 0); - direct = 1; - } - else - card = ctrl->card_ctx; + keygrip = line; + card = card_get (ctrl, keygrip); if (card) { - if (direct) - card_ref (card); - rc = do_readkey (card, ctrl, line, opt_info, &pk, &pklen); - - if (direct) - card_unref (card); + card_put (card); } else rc = gpg_error (GPG_ERR_NO_SECKEY); @@ -923,7 +962,7 @@ cmd_pksign (assuan_context_t ctx, char *line) char *keyidstr; int hash_algo; card_t card; - int direct = 0; + const char *keygrip = NULL; if (has_option (line, "--hash=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 ctrl->card_ctx. */ if (strlen (keyidstr) == 40) - { - card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr, 0); - direct = 1; - } - else - card = ctrl->card_ctx; + keygrip = keyidstr; + card = card_get (ctrl, keygrip); if (card) { - if (direct) - card_ref (card); rc = app_sign (card, ctrl, keyidstr, hash_algo, pin_cb, ctx, ctrl->in_data.value, ctrl->in_data.valuelen, &outdata, &outdatalen); - if (direct) - card_unref (card); + card_put (card); } else rc = gpg_error (GPG_ERR_NO_SECKEY); @@ -1011,14 +1043,11 @@ cmd_pkauth (assuan_context_t ctx, char *line) size_t outdatalen; char *keyidstr; card_t card; - int direct = 0; + const char *keygrip = NULL; if ((rc = open_card (ctrl))) 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 the pin_cb which in turn uses the assuan line buffer and thus 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 ctrl->card_ctx. */ if (strlen (keyidstr) == 40) - { - card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr, 0); - direct = 1; - } - else - card = ctrl->card_ctx; + keygrip = keyidstr; + card = card_get (ctrl, keygrip); if (card) { - if (direct) - card_ref (card); rc = app_auth (card, ctrl, keyidstr, pin_cb, ctx, ctrl->in_data.value, ctrl->in_data.valuelen, &outdata, &outdatalen); - if (direct) - card_unref (card); + card_put (card); } else - rc = gpg_error (GPG_ERR_NO_SECKEY); + rc = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); xfree (keyidstr); if (rc) @@ -1078,7 +1100,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) char *keyidstr; unsigned int infoflags; card_t card; - int direct = 0; + const char *keygrip = NULL; if ((rc = open_card (ctrl))) 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 ctrl->card_ctx. */ if (strlen (keyidstr) == 40) - { - card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr, 0); - direct = 1; - } - else - card = ctrl->card_ctx; + keygrip = keyidstr; + card = card_get (ctrl, keygrip); if (card) { - if (direct) - card_ref (card); rc = app_decipher (card, ctrl, keyidstr, pin_cb, ctx, ctrl->in_data.value, ctrl->in_data.valuelen, &outdata, &outdatalen, &infoflags); - if (direct) - card_unref (card); + card_put (card); } else rc = gpg_error (GPG_ERR_NO_SECKEY); @@ -1154,7 +1169,7 @@ cmd_getattr (assuan_context_t ctx, char *line) int rc; const char *keyword; card_t card; - int direct = 0; + const char *keygrip = NULL; if ((rc = open_card (ctrl))) return rc; @@ -1166,24 +1181,15 @@ cmd_getattr (assuan_context_t ctx, char *line) *line++ = 0; if (strlen (line) == 40) - { - card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, line, 0); - direct = 1; - } - else - card = ctrl->card_ctx; + keygrip = line; + card = card_get (ctrl, keygrip); if (card) { - if (direct) - card_ref (card); - /* FIXME: Applications should not return sensitive data if the card is locked. */ rc = app_getattr (card, ctrl, keyword); - - if (direct) - card_unref (card); + card_put (card); } else rc = gpg_error (GPG_ERR_NO_SECKEY); @@ -1219,6 +1225,7 @@ cmd_setattr (assuan_context_t ctx, char *orig_line) size_t nbytes; char *line, *linebuf; int opt_inquire; + card_t card; opt_inquire = has_option (orig_line, "--inquire"); orig_line = skip_options (orig_line); @@ -1232,6 +1239,13 @@ cmd_setattr (assuan_context_t ctx, char *orig_line) if (!line) return out_of_core (); + card = card_get (ctrl, NULL); + if (!card) + { + xfree (linebuf); + return gpg_error (GPG_ERR_CARD_NOT_PRESENT); + } + keyword = line; 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); if (!err) { - err = app_setattr (ctrl->card_ctx, ctrl, keyword, pin_cb, ctx, + err = app_setattr (card, ctrl, keyword, pin_cb, ctx, value, nbytes); wipememory (value, nbytes); xfree (value); @@ -1258,10 +1272,11 @@ cmd_setattr (assuan_context_t ctx, char *orig_line) else { 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); } + card_put (card); xfree (linebuf); return err; } @@ -1286,6 +1301,7 @@ cmd_writecert (assuan_context_t ctx, char *line) char *certid; unsigned char *certdata; size_t certdatalen; + card_t card; line = skip_options (line); @@ -1299,25 +1315,31 @@ cmd_writecert (assuan_context_t ctx, char *line) if ((rc = open_card (ctrl))) return rc; - if (!ctrl->card_ctx) + card = card_get (ctrl, NULL); + if (!card) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); certid = xtrystrdup (certid); if (!certid) - return out_of_core (); + { + card_put (card); + return out_of_core (); + } /* Now get the actual keydata. */ rc = assuan_inquire (ctx, "CERTDATA", &certdata, &certdatalen, MAXLEN_CERTDATA); if (rc) { + card_put (card); xfree (certid); return rc; } /* 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); + card_put (card); xfree (certid); xfree (certdata); @@ -1348,6 +1370,7 @@ cmd_writekey (assuan_context_t ctx, char *line) int force = has_option (line, "--force"); unsigned char *keydata; size_t keydatalen; + card_t card; line = skip_options (line); @@ -1361,12 +1384,16 @@ cmd_writekey (assuan_context_t ctx, char *line) if ((rc = open_card (ctrl))) return rc; - if (!ctrl->card_ctx) + card = card_get (ctrl, NULL); + if (!card) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); keyid = xtrystrdup (keyid); if (!keyid) - return out_of_core (); + { + card_put (card); + return out_of_core (); + } /* Now get the actual keydata. */ assuan_begin_confidential (ctx); @@ -1379,8 +1406,9 @@ cmd_writekey (assuan_context_t ctx, char *line) } /* 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); + card_put (card); xfree (keyid); xfree (keydata); @@ -1427,6 +1455,7 @@ cmd_genkey (assuan_context_t ctx, char *line) const char *s; char *opt_algo = NULL; time_t timestamp; + card_t card; force = has_option (line, "--force"); @@ -1459,7 +1488,8 @@ cmd_genkey (assuan_context_t ctx, char *line) if ((err = open_card (ctrl))) goto leave; - if (!ctrl->card_ctx) + card = card_get (ctrl, NULL); + if (!card) { err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); goto leave; @@ -1469,11 +1499,13 @@ cmd_genkey (assuan_context_t ctx, char *line) if (!keyref) { err = gpg_error_from_syserror (); + card_put (card); 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, timestamp, pin_cb, ctx); + card_put (card); leave: xfree (keyref_buffer); @@ -1497,6 +1529,7 @@ cmd_random (assuan_context_t ctx, char *line) int rc; size_t nbytes; unsigned char *buffer; + card_t card; if (!*line) return set_error (GPG_ERR_ASS_PARAMETER, @@ -1506,14 +1539,19 @@ cmd_random (assuan_context_t ctx, char *line) if ((rc = open_card (ctrl))) return rc; - if (!ctrl->card_ctx) + card = card_get (ctrl, NULL); + if (!card) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); buffer = xtrymalloc (nbytes); 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) { rc = assuan_send_data (ctx, buffer, nbytes); @@ -1542,6 +1580,7 @@ cmd_passwd (assuan_context_t ctx, char *line) int rc; char *chvnostr; unsigned int flags = 0; + card_t card; if (has_option (line, "--reset")) flags |= APP_CHANGE_FLAG_RESET; @@ -1567,13 +1606,18 @@ cmd_passwd (assuan_context_t ctx, char *line) if ((rc = open_card (ctrl))) return rc; - if (!ctrl->card_ctx) + card = card_get (ctrl, NULL); + if (!card) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); chvnostr = xtrystrdup (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) log_error ("command passwd failed: %s\n", gpg_strerror (rc)); xfree (chvnostr); @@ -1622,13 +1666,15 @@ static gpg_error_t cmd_checkpin (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); - int rc; + gpg_error_t err; char *idstr; + card_t card; - if ((rc = open_card (ctrl))) - return rc; + if ((err = open_card (ctrl))) + return err; - if (!ctrl->card_ctx) + card = card_get (ctrl, NULL); + if (!card) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); /* 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. */ idstr = xtrystrdup (line); 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); - if (rc) - log_error ("app_check_pin failed: %s\n", gpg_strerror (rc)); + if (err) + 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")) { 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. */ 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")) { @@ -1899,7 +1954,7 @@ static gpg_error_t cmd_restart (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); - card_t card = ctrl->card_ctx; + card_t card = card_get (ctrl, NULL); (void)line; @@ -1907,7 +1962,8 @@ cmd_restart (assuan_context_t ctx, char *line) { ctrl->card_ctx = NULL; ctrl->current_apptype = APPTYPE_NONE; - card_unref (card); + card_unref_locked (card); + card_put (card); } if (locked_session && ctrl->server_local == locked_session) { @@ -1926,14 +1982,19 @@ static gpg_error_t cmd_disconnect (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); + card_t card; (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); - - 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))) return rc; - card = ctrl->card_ctx; + card = card_get (ctrl, NULL); if (!card) return gpg_error (GPG_ERR_CARD_NOT_PRESENT); @@ -2074,6 +2135,7 @@ cmd_apdu (assuan_context_t ctx, char *line) xfree (apdu); leave: + card_put (card); return rc; } @@ -2208,6 +2270,7 @@ cmd_devinfo (assuan_context_t ctx, char *line) ctrl_t ctrl = assuan_get_pointer (ctx); gpg_error_t err = 0; int watch = 0; + card_t card; if (has_option (line, "--watch")) { @@ -2237,10 +2300,15 @@ cmd_devinfo (assuan_context_t ctx, char *line) err = 0; - /* Remove reference(s) to the card. */ - ctrl->card_ctx = NULL; - ctrl->current_apptype = APPTYPE_NONE; - card_unref (ctrl->card_ctx); + card = card_get (ctrl, NULL); + if (card) + { + /* 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. */ while (!err)