mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
card: Better detect removed cards. Add TCOS PIN menu.
* tools/card-call-scd.c (scd_change_pin): Add arg 'nullpin'. * tools/gpg-card.h (struct card_info_s): Add field 'card_removed'. * tools/gpg-card.c (fixup_scd_errors): New. (maybe_set_card_removed): New. (list_one_kinfo): Change type of first arg to get access to INFO. Set card_removed flag. (list_all_kinfo): Improve label alignment. (cmd_list): Check that the current card is still available. (cmd_passwd): Add option --nullpin and menu to chnage TCOS PINs. (dispatch_command): Handle card_removed flag. (interactive_loop): Ditto. -- Note that that I was not able to change the NullPIN of the standard PIN using a Signature V2 Brainpool test card. Changing the NullPIN of the QES PIN worked, though. I checked the commands send to scdaemon and they were correct - I used the very same command with gpg-connect-agent last week to set a Pin for a production Brainpool Signature card. Thus this might be a problem with this specific test card. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
45398518fb
commit
fb10b6cba4
@ -1586,17 +1586,10 @@ scd_applist (strlist_t *result, int all)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Change the PIN of an OpenPGP card or reset the retry counter.
|
/* Change the PIN of a card or reset the retry counter. If NULLPIN is
|
||||||
* CHVNO 1: Change the PIN
|
* set the TCOS specific NullPIN is changed. */
|
||||||
* 2: For v1 cards: Same as 1.
|
|
||||||
* For v2 cards: Reset the PIN using the Reset Code.
|
|
||||||
* 3: Change the admin PIN
|
|
||||||
* 101: Set a new PIN and reset the retry counter
|
|
||||||
* 102: For v1 cars: Same as 101.
|
|
||||||
* For v2 cards: Set a new Reset Code.
|
|
||||||
*/
|
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
scd_change_pin (const char *pinref, int reset_mode)
|
scd_change_pin (const char *pinref, int reset_mode, int nullpin)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
char line[ASSUAN_LINELENGTH];
|
char line[ASSUAN_LINELENGTH];
|
||||||
@ -1610,7 +1603,7 @@ scd_change_pin (const char *pinref, int reset_mode)
|
|||||||
dfltparm.ctx = agent_ctx;
|
dfltparm.ctx = agent_ctx;
|
||||||
|
|
||||||
snprintf (line, sizeof line, "SCD PASSWD%s %s",
|
snprintf (line, sizeof line, "SCD PASSWD%s %s",
|
||||||
reset_mode? " --reset":"", pinref);
|
nullpin? " --nullpin": reset_mode? " --reset":"", pinref);
|
||||||
err = assuan_transact (agent_ctx, line,
|
err = assuan_transact (agent_ctx, line,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
default_inq_cb, &dfltparm,
|
default_inq_cb, &dfltparm,
|
||||||
|
234
tools/gpg-card.c
234
tools/gpg-card.c
@ -409,6 +409,34 @@ get_data_from_file (const char *fname, char **r_buffer, size_t *r_buflen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Fixup the ENODEV error from scdaemon which we may see after
|
||||||
|
* removing a card due to scdaemon scanning for readers with cards.
|
||||||
|
* We also map the CAERD REMOVED error to the more useful CARD_NOT
|
||||||
|
* PRESENT. */
|
||||||
|
static gpg_error_t
|
||||||
|
fixup_scd_errors (gpg_error_t err)
|
||||||
|
{
|
||||||
|
if ((gpg_err_code (err) == GPG_ERR_ENODEV
|
||||||
|
|| gpg_err_code (err) == GPG_ERR_CARD_REMOVED)
|
||||||
|
&& gpg_err_source (err) == GPG_ERR_SOURCE_SCD)
|
||||||
|
err = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Set the card removed flag from INFO depending on ERR. This does
|
||||||
|
* not clear the flag. */
|
||||||
|
static gpg_error_t
|
||||||
|
maybe_set_card_removed (card_info_t info, gpg_error_t err)
|
||||||
|
{
|
||||||
|
if ((gpg_err_code (err) == GPG_ERR_ENODEV
|
||||||
|
|| gpg_err_code (err) == GPG_ERR_CARD_REMOVED)
|
||||||
|
&& gpg_err_source (err) == GPG_ERR_SOURCE_SCD)
|
||||||
|
info->card_removed = 1;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Write LENGTH bytes from BUFFER to file FNAME. Return 0 on
|
/* Write LENGTH bytes from BUFFER to file FNAME. Return 0 on
|
||||||
* success. */
|
* success. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
@ -601,10 +629,11 @@ mem_is_zero (const char *mem, unsigned int memlen)
|
|||||||
/* Helper to list a single keyref. LABEL_KEYREF is a fallback key
|
/* Helper to list a single keyref. LABEL_KEYREF is a fallback key
|
||||||
* reference if no info is available; it may be NULL. */
|
* reference if no info is available; it may be NULL. */
|
||||||
static void
|
static void
|
||||||
list_one_kinfo (key_info_t firstkinfo, key_info_t kinfo,
|
list_one_kinfo (card_info_t info, key_info_t kinfo,
|
||||||
const char *label_keyref, estream_t fp, int no_key_lookup)
|
const char *label_keyref, estream_t fp, int no_key_lookup)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
|
key_info_t firstkinfo = info->kinfo;
|
||||||
keyblock_t keyblock = NULL;
|
keyblock_t keyblock = NULL;
|
||||||
keyblock_t kb;
|
keyblock_t kb;
|
||||||
pubkey_t pubkey;
|
pubkey_t pubkey;
|
||||||
@ -643,7 +672,7 @@ list_one_kinfo (key_info_t firstkinfo, key_info_t kinfo,
|
|||||||
}
|
}
|
||||||
tty_fprintf (fp, "\n");
|
tty_fprintf (fp, "\n");
|
||||||
|
|
||||||
if (!scd_readkey (kinfo->keyref, &s_pkey))
|
if (!(err = scd_readkey (kinfo->keyref, &s_pkey)))
|
||||||
{
|
{
|
||||||
char *tmp = pubkey_algo_string (s_pkey, NULL);
|
char *tmp = pubkey_algo_string (s_pkey, NULL);
|
||||||
tty_fprintf (fp, " algorithm ..: %s\n", tmp);
|
tty_fprintf (fp, " algorithm ..: %s\n", tmp);
|
||||||
@ -653,6 +682,7 @@ list_one_kinfo (key_info_t firstkinfo, key_info_t kinfo,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
maybe_set_card_removed (info, err);
|
||||||
tty_fprintf (fp, " algorithm ..: %s\n", kinfo->keyalgo);
|
tty_fprintf (fp, " algorithm ..: %s\n", kinfo->keyalgo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -751,7 +781,7 @@ list_all_kinfo (card_info_t info, keyinfolabel_t labels, estream_t fp,
|
|||||||
int no_key_lookup)
|
int no_key_lookup)
|
||||||
{
|
{
|
||||||
key_info_t kinfo;
|
key_info_t kinfo;
|
||||||
int idx, i;
|
int idx, i, j;
|
||||||
|
|
||||||
/* Print the keyinfo. We first print those we known and then all
|
/* Print the keyinfo. We first print those we known and then all
|
||||||
* remaining item. */
|
* remaining item. */
|
||||||
@ -763,7 +793,7 @@ list_all_kinfo (card_info_t info, keyinfolabel_t labels, estream_t fp,
|
|||||||
{
|
{
|
||||||
tty_fprintf (fp, "%s", labels[idx].label);
|
tty_fprintf (fp, "%s", labels[idx].label);
|
||||||
kinfo = find_kinfo (info, labels[idx].keyref);
|
kinfo = find_kinfo (info, labels[idx].keyref);
|
||||||
list_one_kinfo (info->kinfo, kinfo, labels[idx].keyref,
|
list_one_kinfo (info, kinfo, labels[idx].keyref,
|
||||||
fp, no_key_lookup);
|
fp, no_key_lookup);
|
||||||
if (kinfo)
|
if (kinfo)
|
||||||
kinfo->xflag = 1;
|
kinfo->xflag = 1;
|
||||||
@ -773,11 +803,11 @@ list_all_kinfo (card_info_t info, keyinfolabel_t labels, estream_t fp,
|
|||||||
{
|
{
|
||||||
if (kinfo->xflag)
|
if (kinfo->xflag)
|
||||||
continue;
|
continue;
|
||||||
tty_fprintf (fp, "Key %s ", kinfo->keyref);
|
tty_fprintf (fp, "Key %s", kinfo->keyref);
|
||||||
for (i=5+strlen (kinfo->keyref); i < 18; i++)
|
for (i=4+strlen (kinfo->keyref), j=0; i < 18; i++, j=1)
|
||||||
tty_fprintf (fp, ".");
|
tty_fprintf (fp, j? ".":" ");
|
||||||
tty_fprintf (fp, ":");
|
tty_fprintf (fp, ":");
|
||||||
list_one_kinfo (info->kinfo, kinfo, NULL, fp, no_key_lookup);
|
list_one_kinfo (info, kinfo, NULL, fp, no_key_lookup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1206,7 +1236,7 @@ cmd_list (card_info_t info, char *argstr)
|
|||||||
err = scd_switchcard (sl->d);
|
err = scd_switchcard (sl->d);
|
||||||
need_learn = 1;
|
need_learn = 1;
|
||||||
}
|
}
|
||||||
else /* --info with not args - show app list. */
|
else /* show app list. */
|
||||||
{
|
{
|
||||||
err = scd_applist (&cards, 1);
|
err = scd_applist (&cards, 1);
|
||||||
if (err)
|
if (err)
|
||||||
@ -1232,7 +1262,43 @@ cmd_list (card_info_t info, char *argstr)
|
|||||||
else if (opt_info)
|
else if (opt_info)
|
||||||
print_card_list (fp, info, cards, 1);
|
print_card_list (fp, info, cards, 1);
|
||||||
else
|
else
|
||||||
list_card (info, opt_no_key_lookup);
|
{
|
||||||
|
size_t snlen;
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
/* First get the list of active cards and check whether the
|
||||||
|
* current card is still in the list. If not the card has
|
||||||
|
* been removed. Note that during the listing the card
|
||||||
|
* remove state might also be detected but only if an access
|
||||||
|
* to the scdaemon is required; it is anyway better to test
|
||||||
|
* that before starting a listing. */
|
||||||
|
free_strlist (cards);
|
||||||
|
err = scd_cardlist (&cards);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
for (sl = cards; sl; sl = sl->next)
|
||||||
|
{
|
||||||
|
if (info && info->serialno)
|
||||||
|
{
|
||||||
|
s = strchr (sl->d, ' ');
|
||||||
|
if (s)
|
||||||
|
snlen = s - sl->d;
|
||||||
|
else
|
||||||
|
snlen = strlen (sl->d);
|
||||||
|
if (strlen (info->serialno) == snlen
|
||||||
|
&& !memcmp (info->serialno, sl->d, snlen))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!sl)
|
||||||
|
{
|
||||||
|
info->need_sn_cmd = 1;
|
||||||
|
err = gpg_error (GPG_ERR_CARD_REMOVED);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_card (info, opt_no_key_lookup);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
@ -2560,16 +2626,18 @@ cmd_passwd (card_info_t info, char *argstr)
|
|||||||
char *answer = NULL;
|
char *answer = NULL;
|
||||||
const char *pinref = NULL;
|
const char *pinref = NULL;
|
||||||
int reset_mode = 0;
|
int reset_mode = 0;
|
||||||
|
int nullpin = 0;
|
||||||
int menu_used = 0;
|
int menu_used = 0;
|
||||||
|
|
||||||
if (!info)
|
if (!info)
|
||||||
return print_help
|
return print_help
|
||||||
("PASSWD [--reset] [PINREF]\n\n"
|
("PASSWD [--reset|--nullpin] [PINREF]\n\n"
|
||||||
"Change or unblock the PINs. Note that in interactive mode\n"
|
"Change or unblock the PINs. Note that in interactive mode\n"
|
||||||
"and without a PINREF a menu is presented for certain cards;\n"
|
"and without a PINREF a menu is presented for certain cards;\n"
|
||||||
"in non-interactive and without a PINREF a default value is\n"
|
"in non-interactive and without a PINREF a default value is\n"
|
||||||
"used for these cards. The option --reset is used with TCOS\n"
|
"used for these cards. The option --reset is used with TCOS\n"
|
||||||
"cards to reset the PIN using the PUK or vice versa.\n",
|
"cards to reset the PIN using the PUK or vice versa; --nullpin\n"
|
||||||
|
"is used for these cards to set the intial PIN.",
|
||||||
0);
|
0);
|
||||||
|
|
||||||
if (opt.interactive || opt.verbose)
|
if (opt.interactive || opt.verbose)
|
||||||
@ -2580,10 +2648,12 @@ cmd_passwd (card_info_t info, char *argstr)
|
|||||||
|
|
||||||
if (has_option (argstr, "--reset"))
|
if (has_option (argstr, "--reset"))
|
||||||
reset_mode = 1;
|
reset_mode = 1;
|
||||||
|
else if (has_option (argstr, "--nullpin"))
|
||||||
|
nullpin = 1;
|
||||||
argstr = skip_options (argstr);
|
argstr = skip_options (argstr);
|
||||||
|
|
||||||
/* If --reset has been given we force non-interactive mode. */
|
/* If --reset or --nullpin has been given we force non-interactive mode. */
|
||||||
if (*argstr || reset_mode)
|
if (*argstr || reset_mode || nullpin)
|
||||||
{
|
{
|
||||||
pinref = argstr;
|
pinref = argstr;
|
||||||
if (!*pinref)
|
if (!*pinref)
|
||||||
@ -2643,32 +2713,79 @@ cmd_passwd (card_info_t info, char *argstr)
|
|||||||
}
|
}
|
||||||
else if (opt.interactive && info->apptype == APP_TYPE_NKS)
|
else if (opt.interactive && info->apptype == APP_TYPE_NKS)
|
||||||
{
|
{
|
||||||
|
int for_qualified = 0;
|
||||||
|
|
||||||
menu_used = 1;
|
menu_used = 1;
|
||||||
while (!pinref)
|
|
||||||
|
for (;;)
|
||||||
{
|
{
|
||||||
xfree (answer);
|
xfree (answer);
|
||||||
answer = get_selection (" 1 - change Global PIN 1\n"
|
answer = get_selection (" 1 - Standard PIN/PUK\n"
|
||||||
" 2 - change Global PUK\n"
|
" 2 - PIN/PUK for qualified signature\n"
|
||||||
" 3 - change SigG PIN 1\n"
|
|
||||||
" 4 - change SigG PUK\n"
|
|
||||||
"11 - reset Global PIN 1\n"
|
|
||||||
"12 - reset Global PUK\n"
|
|
||||||
"13 - reset Sig PIN\n"
|
|
||||||
"14 - reset Sig PUK\n"
|
|
||||||
" Q - quit\n");
|
" Q - quit\n");
|
||||||
if (!ascii_strcasecmp (answer, "q"))
|
if (!ascii_strcasecmp (answer, "q"))
|
||||||
goto leave;
|
goto leave;
|
||||||
else if (!strcmp (answer, "1") || !strcmp (answer, "11"))
|
else if (!strcmp (answer, "1"))
|
||||||
pinref = "PW1.CH";
|
break;
|
||||||
else if (!strcmp (answer, "2") || !strcmp (answer, "12"))
|
else if (!strcmp (answer, "2"))
|
||||||
pinref = "PW2.CH";
|
{
|
||||||
else if (!strcmp (answer, "3") || !strcmp (answer, "13"))
|
for_qualified = 1;
|
||||||
pinref = "PW1.CH.SIG";
|
break;
|
||||||
else if (!strcmp (answer, "4") || !strcmp (answer, "14"))
|
}
|
||||||
pinref = "PW2.CH.SIG";
|
}
|
||||||
/* Set reset mode for 11 to 14. */
|
|
||||||
if (pinref && strlen (answer) == 2)
|
log_assert (DIM (info->chvinfo) >= 4);
|
||||||
reset_mode = 1;
|
if (info->chvinfo[for_qualified? 2 : 0] == -4)
|
||||||
|
{
|
||||||
|
while (!pinref)
|
||||||
|
{
|
||||||
|
xfree (answer);
|
||||||
|
answer = get_selection
|
||||||
|
("The NullPIN is still active on this card.\n"
|
||||||
|
"You need to choose and set a PIN first.\n"
|
||||||
|
"\n"
|
||||||
|
" 1 - Set your PIN\n"
|
||||||
|
" Q - quit\n");
|
||||||
|
if (!ascii_strcasecmp (answer, "q"))
|
||||||
|
goto leave;
|
||||||
|
else if (!strcmp (answer, "1"))
|
||||||
|
{
|
||||||
|
pinref = for_qualified? "PW1.CH.SIG" : "PW1.CH";
|
||||||
|
nullpin = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (!pinref)
|
||||||
|
{
|
||||||
|
xfree (answer);
|
||||||
|
answer = get_selection (" 1 - change PIN\n"
|
||||||
|
" 2 - reset PIN\n"
|
||||||
|
" 3 - change PUK\n"
|
||||||
|
" 4 - reset PUK\n"
|
||||||
|
" Q - quit\n");
|
||||||
|
if (!ascii_strcasecmp (answer, "q"))
|
||||||
|
goto leave;
|
||||||
|
else if (!strcmp (answer, "1"))
|
||||||
|
{
|
||||||
|
pinref = for_qualified? "PW1.CH.SIG" : "PW1.CH";
|
||||||
|
}
|
||||||
|
else if (!strcmp (answer, "2"))
|
||||||
|
{
|
||||||
|
pinref = for_qualified? "PW1.CH.SIG" : "PW1.CH";
|
||||||
|
reset_mode = 1;
|
||||||
|
}
|
||||||
|
else if (!strcmp (answer, "3"))
|
||||||
|
{
|
||||||
|
pinref = for_qualified? "PW2.CH.SIG" : "PW2.CH";
|
||||||
|
}
|
||||||
|
else if (!strcmp (answer, "4"))
|
||||||
|
{
|
||||||
|
pinref = for_qualified? "PW2.CH.SIG" : "PW2.CH";
|
||||||
|
reset_mode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (info->apptype == APP_TYPE_PIV)
|
else if (info->apptype == APP_TYPE_PIV)
|
||||||
@ -2679,7 +2796,7 @@ cmd_passwd (card_info_t info, char *argstr)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scd_change_pin (pinref, reset_mode);
|
err = scd_change_pin (pinref, reset_mode, nullpin);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
if (!opt.interactive && !menu_used && !opt.verbose)
|
if (!opt.interactive && !menu_used && !opt.verbose)
|
||||||
@ -2713,6 +2830,9 @@ cmd_passwd (card_info_t info, char *argstr)
|
|||||||
log_info ("PIN resetted.\n");
|
log_info ("PIN resetted.\n");
|
||||||
else
|
else
|
||||||
log_info ("PIN changed.\n");
|
log_info ("PIN changed.\n");
|
||||||
|
|
||||||
|
/* Update the CHV status. */
|
||||||
|
err = scd_getattr ("CHV-STATUS", info);
|
||||||
}
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
@ -2753,7 +2873,7 @@ cmd_unblock (card_info_t info)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err = scd_change_pin ("OPENPGP.2", 0);
|
err = scd_change_pin ("OPENPGP.2", 0, 0);
|
||||||
if (!err)
|
if (!err)
|
||||||
log_info ("PIN changed.\n");
|
log_info ("PIN changed.\n");
|
||||||
}
|
}
|
||||||
@ -2761,7 +2881,7 @@ cmd_unblock (card_info_t info)
|
|||||||
else if (info->apptype == APP_TYPE_PIV)
|
else if (info->apptype == APP_TYPE_PIV)
|
||||||
{
|
{
|
||||||
/* Unblock the Application PIN. */
|
/* Unblock the Application PIN. */
|
||||||
err = scd_change_pin ("PIV.80", 1);
|
err = scd_change_pin ("PIV.80", 1, 0);
|
||||||
if (!err)
|
if (!err)
|
||||||
log_info ("PIN unblocked and changed.\n");
|
log_info ("PIN unblocked and changed.\n");
|
||||||
}
|
}
|
||||||
@ -3477,11 +3597,15 @@ dispatch_command (card_info_t info, const char *orig_command)
|
|||||||
err = scd_learn (info);
|
err = scd_learn (info);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
|
err = fixup_scd_errors (err);
|
||||||
log_error ("Error reading card: %s\n", gpg_strerror (err));
|
log_error ("Error reading card: %s\n", gpg_strerror (err));
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info)
|
||||||
|
info->card_removed = 0;
|
||||||
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
case cmdNOP:
|
case cmdNOP:
|
||||||
@ -3568,8 +3692,17 @@ dispatch_command (card_info_t info, const char *orig_command)
|
|||||||
es_fflush (es_stdout);
|
es_fflush (es_stdout);
|
||||||
if (gpg_err_code (err) == GPG_ERR_EOF && cmd != cmdQUIT)
|
if (gpg_err_code (err) == GPG_ERR_EOF && cmd != cmdQUIT)
|
||||||
err = gpg_error (GPG_ERR_GENERAL);
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
|
|
||||||
|
if (!err && info && info->card_removed)
|
||||||
|
{
|
||||||
|
info->card_removed = 0;
|
||||||
|
info->need_sn_cmd = 1;
|
||||||
|
err = gpg_error (GPG_ERR_CARD_REMOVED);
|
||||||
|
}
|
||||||
|
|
||||||
if (err && gpg_err_code (err) != GPG_ERR_EOF)
|
if (err && gpg_err_code (err) != GPG_ERR_EOF)
|
||||||
{
|
{
|
||||||
|
err = fixup_scd_errors (err);
|
||||||
if (ignore_error)
|
if (ignore_error)
|
||||||
{
|
{
|
||||||
log_info ("Command '%s' failed: %s\n", command, gpg_strerror (err));
|
log_info ("Command '%s' failed: %s\n", command, gpg_strerror (err));
|
||||||
@ -3624,7 +3757,10 @@ interactive_loop (void)
|
|||||||
{
|
{
|
||||||
err = cmd_list (info, "");
|
err = cmd_list (info, "");
|
||||||
if (err)
|
if (err)
|
||||||
log_error ("Error reading card: %s\n", gpg_strerror (err));
|
{
|
||||||
|
err = fixup_scd_errors (err);
|
||||||
|
log_error ("Error reading card: %s\n", gpg_strerror (err));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tty_printf("\n");
|
tty_printf("\n");
|
||||||
@ -3696,12 +3832,19 @@ interactive_loop (void)
|
|||||||
{
|
{
|
||||||
/* Without a serial number most commands won't work.
|
/* Without a serial number most commands won't work.
|
||||||
* Catch it here. */
|
* Catch it here. */
|
||||||
tty_printf ("\n");
|
if (cmd == cmdRESET || cmd == cmdLIST)
|
||||||
tty_printf ("Serial number missing\n");
|
info->need_sn_cmd = 1;
|
||||||
continue;
|
else
|
||||||
|
{
|
||||||
|
tty_printf ("\n");
|
||||||
|
tty_printf ("Serial number missing\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info)
|
||||||
|
info->card_removed = 0;
|
||||||
err = 0;
|
err = 0;
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
@ -3791,6 +3934,13 @@ interactive_loop (void)
|
|||||||
break;
|
break;
|
||||||
} /* End command switch. */
|
} /* End command switch. */
|
||||||
|
|
||||||
|
if (!err && info && info->card_removed)
|
||||||
|
{
|
||||||
|
info->card_removed = 0;
|
||||||
|
info->need_sn_cmd = 1;
|
||||||
|
err = gpg_error (GPG_ERR_CARD_REMOVED);
|
||||||
|
}
|
||||||
|
|
||||||
if (gpg_err_code (err) == GPG_ERR_CANCELED)
|
if (gpg_err_code (err) == GPG_ERR_CANCELED)
|
||||||
tty_fprintf (NULL, "\n");
|
tty_fprintf (NULL, "\n");
|
||||||
else if (err)
|
else if (err)
|
||||||
@ -3802,6 +3952,8 @@ interactive_loop (void)
|
|||||||
s = cmds[i].name;
|
s = cmds[i].name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = fixup_scd_errors (err);
|
||||||
log_error ("Command '%s' failed: %s\n", s, gpg_strerror (err));
|
log_error ("Command '%s' failed: %s\n", s, gpg_strerror (err));
|
||||||
if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
|
if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
|
||||||
info->need_sn_cmd = 1;
|
info->need_sn_cmd = 1;
|
||||||
|
@ -139,6 +139,7 @@ struct card_info_s
|
|||||||
{
|
{
|
||||||
int initialized; /* True if a learn command was successful. */
|
int initialized; /* True if a learn command was successful. */
|
||||||
int need_sn_cmd; /* The SERIALNO command needs to be issued. */
|
int need_sn_cmd; /* The SERIALNO command needs to be issued. */
|
||||||
|
int card_removed; /* Helper flag set by some listing functions. */
|
||||||
int error; /* private. */
|
int error; /* private. */
|
||||||
char *reader; /* Reader information. */
|
char *reader; /* Reader information. */
|
||||||
char *cardtype; /* NULL or type of the card. */
|
char *cardtype; /* NULL or type of the card. */
|
||||||
@ -232,7 +233,7 @@ gpg_error_t scd_readcert (const char *certidstr,
|
|||||||
gpg_error_t scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result);
|
gpg_error_t scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result);
|
||||||
gpg_error_t scd_cardlist (strlist_t *result);
|
gpg_error_t scd_cardlist (strlist_t *result);
|
||||||
gpg_error_t scd_applist (strlist_t *result, int all);
|
gpg_error_t scd_applist (strlist_t *result, int all);
|
||||||
gpg_error_t scd_change_pin (const char *pinref, int reset_mode);
|
gpg_error_t scd_change_pin (const char *pinref, int reset_mode, int nullpin);
|
||||||
gpg_error_t scd_checkpin (const char *serialno);
|
gpg_error_t scd_checkpin (const char *serialno);
|
||||||
|
|
||||||
unsigned long agent_get_s2k_count (void);
|
unsigned long agent_get_s2k_count (void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user