diff --git a/scd/apdu.c b/scd/apdu.c index f00b35915..709ce3086 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -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; diff --git a/scd/apdu.h b/scd/apdu.h index a7f2b145f..32b8e9eff 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -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*/ diff --git a/scd/command.c b/scd/command.c index e2debf5b8..fab65860b 100644 --- a/scd/command.c +++ b/scd/command.c @@ -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 \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);