mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
scd: Make SERIALNO --all work correctly and use it.
* scd/app.c (maybe_switch_app): Factor reselect code out to ... (run_reselect): new. (app_write_learn_status): Tweak diagnostics. (app_do_with_keygrip): Run reselect if a card has more than one switchable application. * agent/call-scd.c (agent_card_serialno): Ditto. * tools/card-call-scd.c (start_agent): Use option --all with SERIALNO. (scd_serialno): Ditto. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
15028627a1
commit
0e48aa0849
@ -854,7 +854,7 @@ agent_card_serialno (ctrl_t ctrl, char **r_serialno, const char *demand)
|
|||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if (!demand)
|
if (!demand)
|
||||||
strcpy (line, "SERIALNO");
|
strcpy (line, "SERIALNO --all");
|
||||||
else
|
else
|
||||||
snprintf (line, DIM(line), "SERIALNO --demand=%s", demand);
|
snprintf (line, DIM(line), "SERIALNO --demand=%s", demand);
|
||||||
|
|
||||||
|
@ -764,13 +764,13 @@ get_dispserialno (app_t app, int failmode)
|
|||||||
|
|
||||||
|
|
||||||
/* The verify command can be used to retrieve the security status of
|
/* The verify command can be used to retrieve the security status of
|
||||||
* the card. Given the PIN name (e.g. "PIV.80" for thge application
|
* the card. Given the PIN name (e.g. "PIV.80" for the application
|
||||||
* pin, a status is returned:
|
* pin, a status is returned:
|
||||||
*
|
*
|
||||||
* -1 = Error retrieving the data,
|
* -1 = Error retrieving the data,
|
||||||
* -2 = No such PIN,
|
* -2 = No such PIN,
|
||||||
* -3 = PIN blocked,
|
* -3 = PIN blocked,
|
||||||
* -5 = Verify still valid,
|
* -5 = Verified and still valid,
|
||||||
* n >= 0 = Number of verification attempts left.
|
* n >= 0 = Number of verification attempts left.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
139
scd/app.c
139
scd/app.c
@ -300,7 +300,7 @@ is_app_allowed (const char *name)
|
|||||||
* to switch to the requested application.
|
* to switch to the requested application.
|
||||||
* Other code - Switching is not possible.
|
* Other code - Switching is not possible.
|
||||||
*
|
*
|
||||||
* If SERIALNO_BIN is not NULL a coflict is onl asserted if the
|
* If SERIALNO_BIN is not NULL a conflict is only asserted if the
|
||||||
* serialno of the card matches.
|
* serialno of the card matches.
|
||||||
*/
|
*/
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
@ -1032,7 +1032,7 @@ card_unref_locked (card_t card)
|
|||||||
FF 02 00 = Serial number from Yubikey config
|
FF 02 00 = Serial number from Yubikey config
|
||||||
FF 7F 00 = No serialno.
|
FF 7F 00 = No serialno.
|
||||||
|
|
||||||
All other serial number not starting with FF are used as they are.
|
All other serial numbers not starting with FF are used as they are.
|
||||||
*/
|
*/
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
app_munge_serialno (card_t card)
|
app_munge_serialno (card_t card)
|
||||||
@ -1094,6 +1094,46 @@ app_get_serialno (app_t app)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper to run the reselect function. */
|
||||||
|
static gpg_error_t
|
||||||
|
run_reselect (ctrl_t ctrl, card_t c, app_t a, app_t a_prev)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
|
||||||
|
if (!a->fnc.reselect)
|
||||||
|
{
|
||||||
|
log_info ("slot %d, app %s: re-select not implemented\n",
|
||||||
|
c->slot, xstrapptype (a));
|
||||||
|
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Give the current app a chance to save some state before another
|
||||||
|
* app is selected. We ignore errors here because that state saving
|
||||||
|
* (e.g. putting PINs into a cache) is a convenience feature and not
|
||||||
|
* required to always work. */
|
||||||
|
if (a_prev && a_prev->fnc.prep_reselect)
|
||||||
|
{
|
||||||
|
err = a_prev->fnc.prep_reselect (a_prev, ctrl);
|
||||||
|
if (err)
|
||||||
|
log_error ("slot %d, app %s: preparing re-select from %s failed: %s\n",
|
||||||
|
c->slot, xstrapptype (a),
|
||||||
|
xstrapptype (a_prev), gpg_strerror (err));
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a->fnc.reselect (a, ctrl);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("slot %d, app %s: error re-selecting: %s\n",
|
||||||
|
c->slot, xstrapptype (a), gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (DBG_APP)
|
||||||
|
log_debug ("slot %d, app %s: re-selected\n", c->slot, xstrapptype (a));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Check that the card has been initialized and whether we need to
|
/* Check that the card has been initialized and whether we need to
|
||||||
* switch to another application on the same card. Switching means
|
* switch to another application on the same card. Switching means
|
||||||
* that the new active app will be moved to the head of the list at
|
* that the new active app will be moved to the head of the list at
|
||||||
@ -1162,33 +1202,9 @@ maybe_switch_app (ctrl_t ctrl, card_t card, const char *keyref)
|
|||||||
if (!app)
|
if (!app)
|
||||||
return gpg_error (GPG_ERR_WRONG_CARD);
|
return gpg_error (GPG_ERR_WRONG_CARD);
|
||||||
|
|
||||||
if (!app->fnc.reselect)
|
err = run_reselect (ctrl, card, app, app_prev);
|
||||||
{
|
|
||||||
log_error ("oops: reselect function missing for '%s'\n",
|
|
||||||
strapptype (app->apptype));
|
|
||||||
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Give the current app a chance to save some state before another
|
|
||||||
* app is selected. We ignore errors here because that state saving
|
|
||||||
* (e.g. putting PINs into a cache) is a convenience feature and not
|
|
||||||
* required to always work. */
|
|
||||||
if (app_prev && app_prev->fnc.prep_reselect)
|
|
||||||
{
|
|
||||||
err = app_prev->fnc.prep_reselect (app_prev, ctrl);
|
|
||||||
if (err)
|
|
||||||
log_info ("card %d: preparing re-select failed for '%s': %s\n",
|
|
||||||
card->slot, xstrapptype (app_prev), gpg_strerror (err));
|
|
||||||
err = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = app->fnc.reselect (app, ctrl);
|
|
||||||
if (err)
|
if (err)
|
||||||
{
|
return 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 if needed. Note that APP
|
/* Swap APP with the head of the app list if needed. Note that APP
|
||||||
* is not the head of the list. */
|
* is not the head of the list. */
|
||||||
@ -1200,9 +1216,9 @@ maybe_switch_app (ctrl_t ctrl, card_t card, const char *keyref)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
log_info ("card %d: %s '%s'\n",
|
log_info ("slot %d, app %s: %s\n",
|
||||||
card->slot, app_prev? "switched to":"re-selected",
|
card->slot, xstrapptype (app),
|
||||||
xstrapptype (app));
|
app_prev? "switched":"re-selected");
|
||||||
|
|
||||||
ctrl->current_apptype = app->apptype;
|
ctrl->current_apptype = app->apptype;
|
||||||
|
|
||||||
@ -1271,8 +1287,10 @@ app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
|
|||||||
{
|
{
|
||||||
tmperr = last_app->fnc.prep_reselect (last_app, ctrl);
|
tmperr = last_app->fnc.prep_reselect (last_app, ctrl);
|
||||||
if (tmperr)
|
if (tmperr)
|
||||||
log_info ("card %d: preparing re-select failed for '%s'"
|
log_info ("slot %d, app %s:"
|
||||||
": %s\n", card->slot, xstrapptype (last_app),
|
" preparing re-select from %s failed: %s\n",
|
||||||
|
card->slot, xstrapptype (app),
|
||||||
|
xstrapptype (last_app),
|
||||||
gpg_strerror (tmperr));
|
gpg_strerror (tmperr));
|
||||||
}
|
}
|
||||||
any_reselect = 1;
|
any_reselect = 1;
|
||||||
@ -1290,9 +1308,10 @@ app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
|
|||||||
{
|
{
|
||||||
tmperr = last_app->fnc.prep_reselect (last_app, ctrl);
|
tmperr = last_app->fnc.prep_reselect (last_app, ctrl);
|
||||||
if (tmperr)
|
if (tmperr)
|
||||||
log_info ("card %d: preparing re-select failed for '%s'"
|
log_info ("slot %d, app %s:"
|
||||||
": %s\n", card->slot, xstrapptype (last_app),
|
" preparing re-select from %s failed: %s\n",
|
||||||
gpg_strerror (tmperr));
|
card->slot, xstrapptype (app),
|
||||||
|
xstrapptype (last_app), gpg_strerror (tmperr));
|
||||||
}
|
}
|
||||||
err2 = app->fnc.reselect (app, ctrl);
|
err2 = app->fnc.reselect (app, ctrl);
|
||||||
if (err2)
|
if (err2)
|
||||||
@ -2027,8 +2046,9 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str,
|
|||||||
int capability)
|
int capability)
|
||||||
{
|
{
|
||||||
int locked = 0;
|
int locked = 0;
|
||||||
|
gpg_error_t err;
|
||||||
card_t c;
|
card_t c;
|
||||||
app_t a;
|
app_t a, a_prev;
|
||||||
|
|
||||||
npth_mutex_lock (&card_list_lock);
|
npth_mutex_lock (&card_list_lock);
|
||||||
|
|
||||||
@ -2040,26 +2060,43 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str,
|
|||||||
goto leave_the_loop;
|
goto leave_the_loop;
|
||||||
}
|
}
|
||||||
locked = 1;
|
locked = 1;
|
||||||
|
a_prev = NULL;
|
||||||
for (a = c->app; a; a = a->next)
|
for (a = c->app; a; a = a->next)
|
||||||
if (a->fnc.with_keygrip)
|
{
|
||||||
{
|
if (!a->fnc.with_keygrip)
|
||||||
if (DBG_APP)
|
continue;
|
||||||
log_debug ("slot %d app %s: calling with_keygrip(action=%d)\n",
|
|
||||||
c->slot, xstrapptype (a), action);
|
/* Note that we need to do a re-select even for the current
|
||||||
if (!a->fnc.with_keygrip (a, ctrl, action, keygrip_str, capability))
|
* app because the last selected application (e.g. after
|
||||||
goto leave_the_loop;
|
* 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? "write_data":
|
||||||
|
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);
|
unlock_card (c);
|
||||||
locked = 0;
|
locked = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
leave_the_loop:
|
leave_the_loop:
|
||||||
|
|
||||||
/* FIXME: Add app switching logic. The above code assumes that the
|
|
||||||
* actions can be performend without switching. This needs to be
|
|
||||||
* checked. */
|
|
||||||
|
|
||||||
/* Force switching of the app if the selected one is not the current
|
/* Force switching of the app if the selected one is not the current
|
||||||
* one. Changing the current apptype is sufficient to do this. */
|
* one. Changing the current apptype is sufficient to do this. */
|
||||||
if (c && c->app && c->app->apptype != a->apptype)
|
if (c && c->app && c->app->apptype != a->apptype)
|
||||||
|
@ -282,7 +282,7 @@ static const char hlp_serialno[] =
|
|||||||
"selected and an error is returned if no such card available.\n"
|
"selected and an error is returned if no such card available.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"If --all is given, all possible other applications of the card are\n"
|
"If --all is given, all possible other applications of the card are\n"
|
||||||
"also selected to prepare for \"LEARN --force --multi\".\n"
|
"also selected to prepare for things like \"LEARN --force --multi\".\n"
|
||||||
"\n"
|
"\n"
|
||||||
"If APPTYPE is given, an application of that type is selected and an\n"
|
"If APPTYPE is given, an application of that type is selected and an\n"
|
||||||
"error is returned if the application is not supported or available.\n"
|
"error is returned if the application is not supported or available.\n"
|
||||||
|
@ -360,7 +360,7 @@ start_agent (unsigned int flags)
|
|||||||
err = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2);
|
err = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2);
|
||||||
|
|
||||||
if (!err)
|
if (!err)
|
||||||
err = assuan_transact (agent_ctx, "SCD SERIALNO",
|
err = assuan_transact (agent_ctx, "SCD SERIALNO --all",
|
||||||
NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL,
|
||||||
learn_status_cb, &info);
|
learn_status_cb, &info);
|
||||||
if (err && !(flags & START_AGENT_SUPPRESS_ERRORS))
|
if (err && !(flags & START_AGENT_SUPPRESS_ERRORS))
|
||||||
@ -1284,7 +1284,7 @@ scd_serialno (char **r_serialno, const char *demand)
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (!demand)
|
if (!demand)
|
||||||
strcpy (line, "SCD SERIALNO");
|
strcpy (line, "SCD SERIALNO --all");
|
||||||
else
|
else
|
||||||
snprintf (line, DIM(line), "SCD SERIALNO --demand=%s", demand);
|
snprintf (line, DIM(line), "SCD SERIALNO --demand=%s", demand);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user