scd: Support PC/SC for "getinfo reader_list".

* scd/apdu.c: Include membuf.h.
(pcsc): Add reader_list field.
(open_pcsc_reader): Fill that field.
(apdu_get_reader_list): New.
* scd/command.c: Remove header ccid-driver.h.
(pretty_assuan_send_data): New.
(cmd_getinfo): Print all reader names.
--

Note that depending on the card backend (ccid or PC/SC) it might be
necessary to first send a reset followed by SERIALNO to get an updated
list of reader.  Or well send KILLSCD.

The pretty printing of Assuan data lines does only work if you connect
direct to scdaemon because the wrapper in gpg-agent does not know
about this and combines the Assuan lines again.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2021-09-08 15:50:28 +02:00
parent 192113552f
commit f32994b0bf
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
3 changed files with 88 additions and 12 deletions

View File

@ -60,6 +60,7 @@
#include "../common/exechelp.h"
#endif /* GNUPG_MAJOR_VERSION != 1 */
#include "../common/host2net.h"
#include "../common/membuf.h"
#include "iso7816.h"
#include "apdu.h"
@ -92,6 +93,7 @@ typedef unsigned long pcsc_dword_t;
static struct pcsc {
int count; /* Reference count - valid if .context != -1 */
long context;
char *reader_list; /* List of detected readers. */
} pcsc;
/* A structure to collect information pertaining to one reader
@ -1204,6 +1206,10 @@ open_pcsc_reader (const char *portstr)
pcsc_dword_t nreader;
char *p;
size_t n;
membuf_t reader_mb;
xfree (pcsc.reader_list);
pcsc.reader_list = NULL;
if (pcsc.context == -1)
if (pcsc_init () < 0)
@ -1212,6 +1218,7 @@ open_pcsc_reader (const char *portstr)
if (DBG_READER)
log_debug ("open_pcsc_reader(portstr=%s)\n", portstr);
slot = new_reader_slot ();
if (slot == -1)
return -1; /* No need to cleanup here. */
@ -1243,6 +1250,8 @@ open_pcsc_reader (const char *portstr)
goto leave;
}
init_membuf (&reader_mb, 256);
p = list;
while (nreader > 0)
{
@ -1260,11 +1269,17 @@ open_pcsc_reader (const char *portstr)
}
log_info ("detected reader '%s'\n", p);
put_membuf_str (&reader_mb, p);
put_membuf (&reader_mb, "\n", 1);
if (!rdrname && portstr && !strncmp (p, portstr, strlen (portstr)))
rdrname = p;
nreader -= n + 1;
p += n + 1;
}
put_membuf (&reader_mb, "", 1);
pcsc.reader_list = get_membuf (&reader_mb, NULL);
if (!pcsc.reader_list)
log_error ("error allocating memory for reader list\n");
if (!rdrname)
rdrname = list;
@ -3353,6 +3368,35 @@ apdu_get_reader_name (int slot)
return reader_table[slot].rdrname;
}
/* Return the list of currently known readers. Caller must free the
* returned value. Might return NULL. */
char *
apdu_get_reader_list (void)
{
membuf_t mb;
char *ccidlist = NULL;
init_membuf (&mb, 256);
#ifdef HAVE_LIBUSB
ccidlist = ccid_get_reader_list ();
#endif
if (ccidlist && *ccidlist)
put_membuf_str (&mb, ccidlist);
if (pcsc.reader_list && *pcsc.reader_list)
{
if (ccidlist && *ccidlist)
put_membuf (&mb, "\n", 1);
put_membuf_str (&mb, pcsc.reader_list);
}
xfree (ccidlist);
put_membuf (&mb, "", 1);
return get_membuf (&mb, NULL);
}
gpg_error_t
apdu_init (void)
{
@ -3362,6 +3406,7 @@ apdu_init (void)
pcsc.count = 0;
pcsc.context = -1;
pcsc.reader_list = NULL;
if (npth_mutex_init (&reader_table_lock, NULL))
goto leave;

View File

@ -151,5 +151,6 @@ int apdu_send_direct (int slot, size_t extended_length,
int handle_more, unsigned int *r_sw,
unsigned char **retbuf, size_t *retbuflen);
const char *apdu_get_reader_name (int slot);
char *apdu_get_reader_list (void);
#endif /*APDU_H*/

View File

@ -36,9 +36,6 @@
#include "iso7816.h"
#include "apdu.h" /* Required for apdu_*_reader (). */
#include "atr.h"
#ifdef HAVE_LIBUSB
#include "ccid-driver.h"
#endif
#include "../common/asshelp.h"
#include "../common/server-help.h"
@ -1401,6 +1398,45 @@ cmd_unlock (assuan_context_t ctx, char *line)
}
/* Ease reading of Assuan data ;ines by sending a physical line after
* each LF. */
static gpg_error_t
pretty_assuan_send_data (assuan_context_t ctx,
const void *buffer_arg, size_t size)
{
const char *buffer = buffer_arg;
const char *p;
size_t n, nbytes;
gpg_error_t err;
nbytes = size;
do
{
p = memchr (buffer, '\n', nbytes);
n = p ? (p - buffer) + 1 : nbytes;
err = assuan_send_data (ctx, buffer, n);
if (err)
{
/* We also set ERRNO in case this function is used by a
* custom estream I/O handler. */
gpg_err_set_errno (EIO);
goto leave;
}
buffer += n;
nbytes -= n;
if (nbytes && (err=assuan_send_data (ctx, NULL, 0))) /* Flush line. */
{
gpg_err_set_errno (EIO);
goto leave;
}
}
while (nbytes);
leave:
return err;
}
static const char hlp_getinfo[] =
"GETINFO <what>\n"
"\n"
@ -1418,8 +1454,7 @@ static const char hlp_getinfo[] =
" 'u' Usable card present.\n"
" 'r' Card removed. A reset is necessary.\n"
" These flags are exclusive.\n"
" reader_list - Return a list of detected card readers. Does\n"
" currently only work with the internal CCID driver.\n"
" reader_list - Return a list of detected card readers.\n"
" deny_admin - Returns OK if admin commands are not allowed or\n"
" GPG_ERR_GENERAL if admin commands are allowed.\n"
" app_list - Return a list of supported applications. One\n"
@ -1474,14 +1509,9 @@ cmd_getinfo (assuan_context_t ctx, char *line)
}
else if (!strcmp (line, "reader_list"))
{
#ifdef HAVE_LIBUSB
char *s = ccid_get_reader_list ();
#else
char *s = NULL;
#endif
char *s = apdu_get_reader_list ();
if (s)
rc = assuan_send_data (ctx, s, strlen (s));
rc = pretty_assuan_send_data (ctx, s, strlen (s));
else
rc = gpg_error (GPG_ERR_NO_DATA);
xfree (s);