aboutsummaryrefslogtreecommitdiffstats
path: root/scd/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/command.c')
-rw-r--r--scd/command.c360
1 files changed, 282 insertions, 78 deletions
diff --git a/scd/command.c b/scd/command.c
index 0d1a5cd3f..0096ca96d 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -33,7 +33,6 @@
#include "scdaemon.h"
#include <assuan.h>
#include <ksba.h>
-#include "app-common.h"
#include "iso7816.h"
#include "apdu.h" /* Required for apdu_*_reader (). */
#include "atr.h"
@@ -145,10 +144,10 @@ hex_to_buffer (const char *string, size_t *r_length)
static void
do_reset (ctrl_t ctrl, int send_reset)
{
- app_t app = ctrl->app_ctx;
+ card_t card = ctrl->card_ctx;
- if (app)
- app_reset (app, ctrl, IS_LOCKED (ctrl)? 0: send_reset);
+ if (card)
+ card_reset (card, ctrl, IS_LOCKED (ctrl)? 0: send_reset);
/* If we hold a lock, unlock now. */
if (locked_session && ctrl->server_local == locked_session)
@@ -157,6 +156,8 @@ do_reset (ctrl_t ctrl, int send_reset)
log_info ("implicitly unlocking due to RESET\n");
}
}
+
+
static gpg_error_t
reset_notify (assuan_context_t ctx, char *line)
@@ -211,38 +212,50 @@ open_card (ctrl_t ctrl)
if ( IS_LOCKED (ctrl) )
return gpg_error (GPG_ERR_LOCKED);
- if (ctrl->app_ctx)
+ if (ctrl->card_ctx)
return 0;
- return select_application (ctrl, NULL, &ctrl->app_ctx, 0, NULL, 0);
+ return select_application (ctrl, NULL, &ctrl->card_ctx, 0, NULL, 0);
}
/* Explicitly open a card for a specific use of APPTYPE or SERIALNO. */
static gpg_error_t
-open_card_with_request (ctrl_t ctrl, const char *apptype, const char *serialno)
+open_card_with_request (ctrl_t ctrl,
+ const char *apptypestr, const char *serialno)
{
gpg_error_t err;
unsigned char *serialno_bin = NULL;
size_t serialno_bin_len = 0;
- app_t app = ctrl->app_ctx;
+ card_t card = ctrl->card_ctx;
+
+ if (serialno)
+ serialno_bin = hex_to_buffer (serialno, &serialno_bin_len);
/* 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 (apptype && ctrl->app_ctx)
- return check_application_conflict (apptype, ctrl->app_ctx);
-
- /* Re-scan USB devices. Release APP, before the scan. */
- ctrl->app_ctx = NULL;
- release_application (app, 0);
+ if (apptypestr && ctrl->card_ctx)
+ {
+ err = check_application_conflict (ctrl->card_ctx, 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);
+ }
+ goto leave;
+ }
- if (serialno)
- serialno_bin = hex_to_buffer (serialno, &serialno_bin_len);
+ /* 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;
+ card_unref (card);
- err = select_application (ctrl, apptype, &ctrl->app_ctx, 1,
+ err = select_application (ctrl, apptypestr, &ctrl->card_ctx, 1,
serialno_bin, serialno_bin_len);
- xfree (serialno_bin);
+ leave:
+ xfree (serialno_bin);
return err;
}
@@ -313,7 +326,7 @@ cmd_serialno (assuan_context_t ctx, char *line)
c->server_local->card_removed = 0;
}
- serial = app_get_serialno (ctrl->app_ctx);
+ serial = card_get_serialno (ctrl->card_ctx);
if (!serial)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -411,20 +424,20 @@ cmd_learn (assuan_context_t ctx, char *line)
{
const char *reader;
char *serial;
- app_t app = ctrl->app_ctx;
+ card_t card = ctrl->card_ctx;
- if (!app)
+ if (!card)
return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
- reader = apdu_get_reader_name (app->slot);
+ reader = apdu_get_reader_name (card->slot);
if (!reader)
return out_of_core ();
send_status_direct (ctrl, "READER", reader);
/* No need to free the string of READER. */
- serial = app_get_serialno (ctrl->app_ctx);
+ serial = card_get_serialno (ctrl->card_ctx);
if (!serial)
- return gpg_error (GPG_ERR_INV_VALUE);
+ return gpg_error (GPG_ERR_INV_VALUE);
rc = assuan_write_status (ctx, "SERIALNO", serial);
if (rc < 0)
@@ -461,7 +474,7 @@ cmd_learn (assuan_context_t ctx, char *line)
/* Let the application print out its collection of useful status
information. */
if (!rc)
- rc = app_write_learn_status (ctrl->app_ctx, ctrl, only_keypairinfo);
+ rc = app_write_learn_status (ctrl->card_ctx, ctrl, only_keypairinfo);
return rc;
}
@@ -484,7 +497,7 @@ cmd_readcert (assuan_context_t ctx, char *line)
return rc;
line = xstrdup (line); /* Need a copy of the line. */
- rc = app_readcert (ctrl->app_ctx, ctrl, line, &cert, &ncert);
+ rc = app_readcert (ctrl->card_ctx, ctrl, line, &cert, &ncert);
if (rc)
log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
xfree (line);
@@ -502,19 +515,20 @@ cmd_readcert (assuan_context_t ctx, char *line)
static const char hlp_readkey[] =
- "READKEY [--advanced] <keyid>|<oid>\n"
+ "READKEY [--advanced] [--info[-only]] <keyid>|<oid>\n"
"\n"
"Return the public key for the given cert or key ID as a standard\n"
- "S-expression.\n"
- "In --advanced mode it returns the S-expression in advanced format.\n"
- "\n"
- "Note that this function may even be used on a locked card.";
+ "S-expression. With --advanced the S-expression is returned in\n"
+ "advanced format. With --info a KEYPAIRINFO status line is also\n"
+ "emitted; with --info-only the regular output is suppressed.";
static gpg_error_t
cmd_readkey (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int rc;
int advanced = 0;
+ int opt_info = 0;
+ int opt_nokey = 0;
unsigned char *cert = NULL;
unsigned char *pk = NULL;
size_t ncert, pklen;
@@ -524,6 +538,10 @@ cmd_readkey (assuan_context_t ctx, char *line)
if (has_option (line, "--advanced"))
advanced = 1;
+ if (has_option (line, "--info"))
+ opt_info = 1;
+ if (has_option (line, "--info-only"))
+ opt_info = opt_nokey = 1;
line = skip_options (line);
line = xstrdup (line); /* Need a copy of the line. */
@@ -531,14 +549,16 @@ cmd_readkey (assuan_context_t ctx, char *line)
/* If the application supports the READKEY function we use that.
Otherwise we use the old way by extracting it from the
certificate. */
- rc = app_readkey (ctrl->app_ctx, ctrl, line, &pk, &pklen);
+ rc = app_readkey (ctrl->card_ctx, ctrl, line,
+ opt_info? APP_READKEY_FLAG_INFO : 0,
+ opt_nokey? NULL : &pk, &pklen);
if (!rc)
; /* Okay, got that key. */
else if (gpg_err_code (rc) == GPG_ERR_UNSUPPORTED_OPERATION
|| gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
{
/* Fall back to certificate reading. */
- rc = app_readcert (ctrl->app_ctx, ctrl, line, &cert, &ncert);
+ rc = app_readcert (ctrl->card_ctx, ctrl, line, &cert, &ncert);
if (rc)
{
log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
@@ -551,6 +571,26 @@ cmd_readkey (assuan_context_t ctx, char *line)
gpg_strerror (rc));
goto leave;
}
+
+ if (opt_info)
+ {
+ char keygripstr[KEYGRIP_LEN*2+1];
+
+ rc = app_help_get_keygrip_string_pk (pk, pklen, keygripstr);
+ if (rc)
+ {
+ log_error ("app_help_get_keygrip_string failed: %s\n",
+ gpg_strerror (rc));
+ goto leave;
+ }
+
+ /* FIXME: Using LINE is not correct because it might be an
+ * OID and has not been canonicalized (i.e. uppercased). */
+ send_status_info (ctrl, "KEYPAIRINFO",
+ keygripstr, strlen (keygripstr),
+ line, strlen (line),
+ NULL, (size_t)0);
+ }
}
else
{
@@ -558,7 +598,9 @@ cmd_readkey (assuan_context_t ctx, char *line)
goto leave;
}
- if (advanced)
+ if (opt_nokey)
+ ;
+ else if (advanced)
{
gcry_sexp_t s_key;
unsigned char *pkadv;
@@ -728,6 +770,8 @@ cmd_pksign (assuan_context_t ctx, char *line)
size_t outdatalen;
char *keyidstr;
int hash_algo;
+ card_t card;
+ int direct = 0;
if (has_option (line, "--hash=rmd160"))
hash_algo = GCRY_MD_RMD160;
@@ -760,11 +804,30 @@ cmd_pksign (assuan_context_t ctx, char *line)
if (!keyidstr)
return out_of_core ();
- rc = app_sign (ctrl->app_ctx, ctrl,
- keyidstr, hash_algo,
- pin_cb, ctx,
- ctrl->in_data.value, ctrl->in_data.valuelen,
- &outdata, &outdatalen);
+ /* 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);
+ direct = 1;
+ }
+ else
+ card = ctrl->card_ctx;
+
+ 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);
+ }
+ else
+ rc = gpg_error (GPG_ERR_NO_SECKEY);
xfree (keyidstr);
if (rc)
@@ -793,11 +856,13 @@ cmd_pkauth (assuan_context_t ctx, char *line)
unsigned char *outdata;
size_t outdatalen;
char *keyidstr;
+ card_t card;
+ int direct = 0;
if ((rc = open_card (ctrl)))
return rc;
- if (!ctrl->app_ctx)
+ 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
@@ -807,9 +872,29 @@ cmd_pkauth (assuan_context_t ctx, char *line)
if (!keyidstr)
return out_of_core ();
- rc = app_auth (ctrl->app_ctx, ctrl, keyidstr, pin_cb, ctx,
- ctrl->in_data.value, ctrl->in_data.valuelen,
- &outdata, &outdatalen);
+ /* 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);
+ direct = 1;
+ }
+ else
+ card = ctrl->card_ctx;
+
+ 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);
+ }
+ else
+ rc = gpg_error (GPG_ERR_NO_SECKEY);
+
xfree (keyidstr);
if (rc)
{
@@ -838,6 +923,8 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
size_t outdatalen;
char *keyidstr;
unsigned int infoflags;
+ card_t card;
+ int direct = 0;
if ((rc = open_card (ctrl)))
return rc;
@@ -845,9 +932,29 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
keyidstr = xtrystrdup (line);
if (!keyidstr)
return out_of_core ();
- rc = app_decipher (ctrl->app_ctx, ctrl, keyidstr, pin_cb, ctx,
- ctrl->in_data.value, ctrl->in_data.valuelen,
- &outdata, &outdatalen, &infoflags);
+
+ /* 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);
+ direct = 1;
+ }
+ else
+ card = ctrl->card_ctx;
+
+ 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);
+ }
+ else
+ rc = gpg_error (GPG_ERR_NO_SECKEY);
xfree (keyidstr);
if (rc)
@@ -905,7 +1012,7 @@ cmd_getattr (assuan_context_t ctx, char *line)
/* FIXME: Applications should not return sensitive data if the card
is locked. */
- rc = app_getattr (ctrl->app_ctx, ctrl, keyword);
+ rc = app_getattr (ctrl->card_ctx, ctrl, keyword);
return rc;
}
@@ -967,7 +1074,7 @@ cmd_setattr (assuan_context_t ctx, char *orig_line)
assuan_end_confidential (ctx);
if (!err)
{
- err = app_setattr (ctrl->app_ctx, ctrl, keyword, pin_cb, ctx,
+ err = app_setattr (ctrl->card_ctx, ctrl, keyword, pin_cb, ctx,
value, nbytes);
wipememory (value, nbytes);
xfree (value);
@@ -977,7 +1084,7 @@ cmd_setattr (assuan_context_t ctx, char *orig_line)
else
{
nbytes = percent_plus_unescape_inplace (line, 0);
- err = app_setattr (ctrl->app_ctx, ctrl, keyword, pin_cb, ctx,
+ err = app_setattr (ctrl->card_ctx, ctrl, keyword, pin_cb, ctx,
(const unsigned char*)line, nbytes);
}
@@ -1018,7 +1125,7 @@ cmd_writecert (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
certid = xtrystrdup (certid);
@@ -1035,7 +1142,7 @@ cmd_writecert (assuan_context_t ctx, char *line)
}
/* Write the certificate to the card. */
- rc = app_writecert (ctrl->app_ctx, ctrl, certid,
+ rc = app_writecert (ctrl->card_ctx, ctrl, certid,
pin_cb, ctx, certdata, certdatalen);
xfree (certid);
xfree (certdata);
@@ -1080,7 +1187,7 @@ cmd_writekey (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
keyid = xtrystrdup (keyid);
@@ -1098,7 +1205,7 @@ cmd_writekey (assuan_context_t ctx, char *line)
}
/* Write the key to the card. */
- rc = app_writekey (ctrl->app_ctx, ctrl, keyid, force? 1:0,
+ rc = app_writekey (ctrl->card_ctx, ctrl, keyid, force? 1:0,
pin_cb, ctx, keydata, keydatalen);
xfree (keyid);
xfree (keydata);
@@ -1172,7 +1279,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
if ((err = open_card (ctrl)))
goto leave;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
keyref = keyref_buffer = xtrystrdup (keyref);
@@ -1181,7 +1288,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
err = gpg_error_from_syserror ();
goto leave;
}
- err = app_genkey (ctrl->app_ctx, ctrl, keyref, opt_algo,
+ err = app_genkey (ctrl->card_ctx, ctrl, keyref, opt_algo,
force? APP_GENKEY_FLAG_FORCE : 0,
timestamp, pin_cb, ctx);
@@ -1216,14 +1323,14 @@ cmd_random (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
buffer = xtrymalloc (nbytes);
if (!buffer)
return out_of_core ();
- rc = app_get_challenge (ctrl->app_ctx, ctrl, nbytes, buffer);
+ rc = app_get_challenge (ctrl->card_ctx, ctrl, nbytes, buffer);
if (!rc)
{
rc = assuan_send_data (ctx, buffer, nbytes);
@@ -1277,13 +1384,13 @@ cmd_passwd (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
chvnostr = xtrystrdup (chvnostr);
if (!chvnostr)
return out_of_core ();
- rc = app_change_pin (ctrl->app_ctx, ctrl, chvnostr, flags, pin_cb, ctx);
+ rc = app_change_pin (ctrl->card_ctx, ctrl, chvnostr, flags, pin_cb, ctx);
if (rc)
log_error ("command passwd failed: %s\n", gpg_strerror (rc));
xfree (chvnostr);
@@ -1334,7 +1441,7 @@ cmd_checkpin (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
- if (!ctrl->app_ctx)
+ 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
@@ -1344,7 +1451,7 @@ cmd_checkpin (assuan_context_t ctx, char *line)
if (!idstr)
return out_of_core ();
- rc = app_check_pin (ctrl->app_ctx, ctrl, idstr, pin_cb, ctx);
+ rc = app_check_pin (ctrl->card_ctx, ctrl, idstr, pin_cb, ctx);
xfree (idstr);
if (rc)
log_error ("app_check_pin failed: %s\n", gpg_strerror (rc));
@@ -1525,7 +1632,7 @@ cmd_getinfo (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
- app_send_card_list (ctrl);
+ rc = app_send_card_list (ctrl);
}
else
rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
@@ -1547,14 +1654,14 @@ static gpg_error_t
cmd_restart (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
- app_t app = ctrl->app_ctx;
+ card_t card = ctrl->card_ctx;
(void)line;
- if (app)
+ if (card)
{
- ctrl->app_ctx = NULL;
- release_application (app, 0);
+ ctrl->card_ctx = NULL;
+ card_unref (card);
}
if (locked_session && ctrl->server_local == locked_session)
{
@@ -1576,10 +1683,10 @@ cmd_disconnect (assuan_context_t ctx, char *line)
(void)line;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- apdu_disconnect (ctrl->app_ctx->slot);
+ apdu_disconnect (ctrl->card_ctx->slot);
return 0;
}
@@ -1608,7 +1715,7 @@ static gpg_error_t
cmd_apdu (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
- app_t app;
+ card_t card;
int rc;
unsigned char *apdu;
size_t apdulen;
@@ -1638,8 +1745,8 @@ cmd_apdu (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
- app = ctrl->app_ctx;
- if (!app)
+ card = ctrl->card_ctx;
+ if (!card)
return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
if (with_atr)
@@ -1648,7 +1755,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
size_t atrlen;
char hexbuf[400];
- atr = apdu_get_atr (app->slot, &atrlen);
+ atr = apdu_get_atr (card->slot, &atrlen);
if (!atr || atrlen > sizeof hexbuf - 2 )
{
rc = gpg_error (GPG_ERR_INV_CARD);
@@ -1693,7 +1800,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
unsigned char *result = NULL;
size_t resultlen;
- rc = apdu_send_direct (app->slot, exlen,
+ rc = apdu_send_direct (card->slot, exlen,
apdu, apdulen, handle_more,
NULL, &result, &resultlen);
if (rc)
@@ -1728,6 +1835,87 @@ cmd_killscd (assuan_context_t ctx, char *line)
}
+static const char hlp_keyinfo[] =
+ "KEYINFO [--list] [--data] <keygrip>\n"
+ "\n"
+ "Return information about the key specified by the KEYGRIP. If the\n"
+ "key is not available GPG_ERR_NOT_FOUND is returned. If the option\n"
+ "--list is given the keygrip is ignored and information about all\n"
+ "available keys are returned. Unless --data is given, the\n"
+ "information is returned as a status line using the format:\n"
+ "\n"
+ " KEYINFO <keygrip> T <serialno> <idstr>\n"
+ "\n"
+ "KEYGRIP is the keygrip.\n"
+ "\n"
+ "SERIALNO is an ASCII string with the serial number of the\n"
+ " smartcard. If the serial number is not known a single\n"
+ " dash '-' is used instead.\n"
+ "\n"
+ "IDSTR is the IDSTR used to distinguish keys on a smartcard. If it\n"
+ " is not known a dash is used instead.\n"
+ "\n"
+ "More information may be added in the future.";
+static gpg_error_t
+cmd_keyinfo (assuan_context_t ctx, char *line)
+{
+ int list_mode;
+ int opt_data;
+ int action;
+ char *keygrip_str;
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ card_t card;
+
+ list_mode = has_option (line, "--list");
+ opt_data = has_option (line, "--data");
+ line = skip_options (line);
+
+ if (list_mode)
+ keygrip_str = NULL;
+ else
+ keygrip_str = line;
+
+ if (opt_data)
+ action = KEYGRIP_ACTION_SEND_DATA;
+ else
+ action = KEYGRIP_ACTION_WRITE_STATUS;
+
+ card = app_do_with_keygrip (ctrl, action, keygrip_str);
+
+ if (!list_mode && !card)
+ return gpg_error (GPG_ERR_NOT_FOUND);
+ return 0;
+}
+
+
+/* Send a keyinfo string as used by the KEYGRIP_ACTION_SEND_DATA. If
+ * DATA is true the string is emitted as a data line, else as a status
+ * line. */
+void
+send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str,
+ const char *serialno, const char *idstr)
+{
+ char *string;
+ assuan_context_t ctx = ctrl->server_local->assuan_ctx;
+
+ string = xtryasprintf ("%s T %s %s%s", keygrip_str,
+ serialno? serialno : "-",
+ idstr? idstr : "-",
+ data? "\n" : "");
+
+ if (!string)
+ return;
+
+ if (!data)
+ assuan_write_status (ctx, "KEYINFO", string);
+ else
+ assuan_send_data (ctx, string, strlen (string));
+
+ xfree (string);
+ return;
+}
+
+
/* Tell the assuan library about our commands */
static int
@@ -1763,6 +1951,7 @@ register_commands (assuan_context_t ctx)
{ "DISCONNECT", cmd_disconnect,hlp_disconnect },
{ "APDU", cmd_apdu, hlp_apdu },
{ "KILLSCD", cmd_killscd, hlp_killscd },
+ { "KEYINFO", cmd_keyinfo, hlp_keyinfo },
{ NULL }
};
int i, rc;
@@ -1890,6 +2079,20 @@ scd_command_handler (ctrl_t ctrl, int fd)
}
+/* Clear the current application info for CARD from all sessions.
+ * This is used while deallocating a card. */
+void
+scd_clear_current_app (card_t card)
+{
+ struct server_local_s *sl;
+
+ for (sl=session_list; sl; sl = sl->next_session)
+ {
+ if (sl->ctrl_backlink->card_ctx == card)
+ sl->ctrl_backlink->current_apptype = APPTYPE_NONE;
+ }
+}
+
/* Send a line with status information via assuan and escape all given
buffers. The variable elements are pairs of (char *, size_t),
terminated with a (NULL, 0). */
@@ -2001,9 +2204,10 @@ popup_prompt (void *opaque, int on)
}
-/* Helper to send the clients a status change notification. */
+/* Helper to send the clients a status change notification. Note that
+ * this function assumes that APP is already locked. */
void
-send_client_notifications (app_t app, int removal)
+send_client_notifications (card_t card, int removal)
{
struct {
pid_t pid;
@@ -2018,7 +2222,7 @@ send_client_notifications (app_t app, int removal)
struct server_local_s *sl;
for (sl=session_list; sl; sl = sl->next_session)
- if (sl->ctrl_backlink && sl->ctrl_backlink->app_ctx == app)
+ if (sl->ctrl_backlink && sl->ctrl_backlink->card_ctx == card)
{
pid_t pid;
#ifdef HAVE_W32_SYSTEM
@@ -2029,9 +2233,9 @@ send_client_notifications (app_t app, int removal)
if (removal)
{
- sl->ctrl_backlink->app_ctx = NULL;
+ sl->ctrl_backlink->card_ctx = NULL;
sl->card_removed = 1;
- release_application (app, 1);
+ card_unref_locked (card);
}
if (!sl->event_signal || !sl->assuan_ctx)