[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH] Provide a VCARD_DIRECT implementation.
From: |
Marc-André Lureau |
Subject: |
Re: [Qemu-devel] [PATCH] Provide a VCARD_DIRECT implementation. |
Date: |
Mon, 19 Jan 2015 18:16:24 +0100 |
Hey
Thanks for proposing passthrough mode. It can be useful in some cases,
although it's good to mention it's not safe to concurrently share a
card with other applications since no locking is provided (and I don't
know if and how it's possible atm).
You should fix your patch to pass qemu scripts/checkpatch.pl (too many
errors to report here)
Some review notes follow.
On Mon, Jan 19, 2015 at 4:00 PM, Jeremy White <address@hidden> wrote:
> This enables a passthru mode in the spice client, where we relay
> apdus from the client to the host, rather than passing through nss
> and emulating a card.
Could you explain how you handle multiple readers, and what is the
sender PID used for?
>
> Signed-off-by: Jeremy White <address@hidden>
> ---
> Makefile.objs | 5 +
> configure | 38 +++
Although I am not very picky about splitting things, I would say you
could easily split the configure part first.
> libcacard/capcsc.c | 612
> +++++++++++++++++++++++++++++++++++++++++++
> libcacard/capcsc.h | 16 ++
> libcacard/libcacard.syms | 1 +
Then the PCSC/passthrough card.
I haven't done a thorough review of capcsc yet, just a few comments below.
> libcacard/vcard.c | 2 +-
> libcacard/vcard.h | 2 +-
> libcacard/vcard_emul_nss.c | 28 +-
> libcacard/vcard_emul_type.c | 3 +-
Then integration with vcard,
> libcacard/vscclient.c | 16 +-
And the vscclient part.
> 10 files changed, 706 insertions(+), 17 deletions(-)
> create mode 100644 libcacard/capcsc.c
> create mode 100644 libcacard/capcsc.h
>
> diff --git a/Makefile.objs b/Makefile.objs
> index abeb902..bb9659e 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -32,6 +32,11 @@ libcacard-y += libcacard/card_7816.o
> libcacard-y += libcacard/vcardt.o
> libcacard/vcard_emul_nss.o-cflags := $(NSS_CFLAGS)
> libcacard/vcard_emul_nss.o-libs := $(NSS_LIBS)
> +ifeq ($(CONFIG_SMARTCARD_PCSC),y)
> +libcacard-y += libcacard/capcsc.o
> +libcacard/capcsc.o-cflags := $(PCSC_CFLAGS)
> +libcacard/capcsc.o-libs := $(PCSC_LIBS)
> +endif
>
> ######################################################################
> # Target independent part of system emulation. The long term path is to
> diff --git a/configure b/configure
> index cae588c..f1dd05c 100755
> --- a/configure
> +++ b/configure
> @@ -307,6 +307,7 @@ trace_file="trace"
> spice=""
> rbd=""
> smartcard_nss=""
> +smartcard_pcsc=""
> libusb=""
> usb_redir=""
> glx=""
> @@ -1042,6 +1043,10 @@ for opt do
> ;;
> --enable-smartcard-nss) smartcard_nss="yes"
> ;;
> + --disable-smartcard-pcsc) smartcard_pcsc="no"
> + ;;
> + --enable-smartcard-pcsc) smartcard_pcsc="yes"
> + ;;
> --disable-libusb) libusb="no"
> ;;
> --enable-libusb) libusb="yes"
> @@ -1368,6 +1373,8 @@ Advanced options (experts only):
> --enable-libnfs enable nfs support
> --disable-smartcard-nss disable smartcard nss support
> --enable-smartcard-nss enable smartcard nss support
> + --disable-smartcard-pcsc disable smartcard pcsc passthru support
> + --enable-smartcard-pcsc enable smartcard pcsc passthru support
> --disable-libusb disable libusb (for usb passthrough)
> --enable-libusb enable libusb (for usb passthrough)
> --disable-usb-redir disable usb network redirection support
> @@ -3648,6 +3655,30 @@ EOF
> fi
> fi
>
> +# check for pcsclite for smartcard passthru support
(perhaps it's good to keep in mind that this code should be fairly
easy to port to winscard, perhaps a TODO would be worth here?)
> +if test "$smartcard_pcsc" != "no"; then
> + cat > $TMPC << EOF
> +#include <winscard.h>
> +int main(void) { SCardEstablishContext(0, 0, 0, 0); return 0; }
> +EOF
> + # FIXME: do not include $glib_* in here
> + pcsc_libs="$($pkg_config --libs libpcsclite 2>/dev/null) $glib_libs"
> + pcsc_cflags="$($pkg_config --cflags libpcsclite 2>/dev/null)
> $glib_cflags"
It seems you can remove the $glib here.
> + test_cflags="$pcsc_cflags"
> + if test "$werror" = "yes"; then
> + test_cflags="-Werror $test_cflags"
> + fi
> + if test -n "$libtool" &&
> + compile_prog "$test_cflags" "$pcsc_libs"; then
> + smartcard_pcsc="yes"
> + else
> + if test "$smartcard_pcsc" = "yes"; then
> + feature_not_found "pcsc" "Install libpcsclite"
> + fi
> + smartcard_pcsc="no"
> + fi
> +fi
> +
> # check for libusb
> if test "$libusb" != "no" ; then
> if $pkg_config --atleast-version=1.0.13 libusb-1.0; then
> @@ -4318,6 +4349,7 @@ fi
> echo "rbd support $rbd"
> echo "xfsctl support $xfs"
> echo "nss used $smartcard_nss"
> +echo "pcsc used $smartcard_pcsc"
> echo "libusb $libusb"
> echo "usb net redir $usb_redir"
> echo "GLX support $glx"
> @@ -4674,6 +4706,12 @@ if test "$smartcard_nss" = "yes" ; then
> echo "NSS_CFLAGS=$nss_cflags" >> $config_host_mak
> fi
>
> +if test "$smartcard_pcsc" = "yes" ; then
> + echo "CONFIG_SMARTCARD_PCSC=y" >> $config_host_mak
> + echo "PCSC_LIBS=$pcsc_libs" >> $config_host_mak
> + echo "PCSC_CFLAGS=$pcsc_cflags" >> $config_host_mak
> +fi
> +
> if test "$libusb" = "yes" ; then
> echo "CONFIG_USB_LIBUSB=y" >> $config_host_mak
> fi
> diff --git a/libcacard/capcsc.c b/libcacard/capcsc.c
> new file mode 100644
> index 0000000..c7da458
> --- /dev/null
> +++ b/libcacard/capcsc.c
> @@ -0,0 +1,612 @@
> +/*
> + * Supply a vreader using the PC/SC interface.
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or
> later.
> + * See the COPYING.LIB file in the top-level directory.
> + */
> +
> +/* avoid including prototypes.h that causes some qemu type conflicts */
> +#define NO_NSPR_10_SUPPORT
> +#include <prthread.h>
> +
> +#include "qemu-common.h"
> +
> +#include "vcard.h"
> +#include "card_7816.h"
> +#include "capcsc.h"
> +#include "vreader.h"
> +#include "vevent.h"
> +
> +#include <PCSC/wintypes.h>
> +#include <PCSC/winscard.h>
> +
> +
> +typedef struct _PCSCContext PCSCContext;
> +
> +typedef struct _APDUMsg {
> + void *data;
> + int len;
> + pid_t sender;
> + LONG rc;
> + struct _APDUMsg *next;
> +} APDUMsg;
> +
> +typedef struct
> +{
> + PCSCContext *context;
> + int index;
> + char *name;
> + DWORD protocol;
> + DWORD state;
> + SCARDHANDLE card;
> + BYTE atr[MAX_ATR_SIZE];
> + DWORD atrlen;
> + int card_connected;
> + CompatGMutex request_lock;
> + APDUMsg *requests;
> + unsigned long request_count;
> + CompatGMutex response_lock;
> + APDUMsg *responses;
> +} SCardReader;
> +
> +typedef struct _PCSCContext
> +{
> + SCARDCONTEXT context;
> + SCardReader readers[CAPCSC_MAX_READERS];
> + int reader_count;
> + int readers_changed;
> + PRThread *thread;
> + CompatGMutex lock;
> +} PCSCContext;
> +
> +
> +static void push_request(SCardReader *r, void *data, int len)
> +{
> + APDUMsg *a = malloc(sizeof(*a));
qemu uses quite consistently g_malloc/new/slice & friends nowadays afaict.
> + APDUMsg **p;
> +
> + a->data = malloc(len);
> + a->len = len;
> + a->sender = getpid();
> + a->next = NULL;
> + memcpy(a->data, data, len);
> +
> + g_mutex_lock(&r->request_lock);
> + for (p = &r->requests; *p; p = &(*p)->next)
> + ;
> + *p = a;
> + r->request_count++;
Why not use GQueue or GAsyncQueue?
> +
> + g_mutex_unlock(&r->request_lock);
> +}
> +
> +static APDUMsg * get_request(SCardReader *r)
> +{
> + APDUMsg *p;
> + g_mutex_lock(&r->request_lock);
> + p = r->requests;
> + if (r->requests)
> + r->requests = p->next;
> + g_mutex_unlock(&r->request_lock);
> + return p;
> +}
> +
> +static void push_response(SCardReader *r, void *data, int len, LONG rc,
> pid_t sender)
> +{
> + APDUMsg *a = malloc(sizeof(*a));
> + APDUMsg **p;
> +
> + a->data = malloc(len);
> + a->len = len;
> + a->sender = sender;
> + a->next = NULL;
> + a->rc = rc;
> + memcpy(a->data, data, len);
> +
> + g_mutex_lock(&r->response_lock);
> + for (p = &r->responses; *p; p = &(*p)->next)
> + ;
> + *p = a;
> +
> + g_mutex_unlock(&r->response_lock);
> +}
> +
> +static APDUMsg * get_response(SCardReader *r)
> +{
> + APDUMsg **p;
> + APDUMsg *ret = NULL;
> + g_mutex_lock(&r->response_lock);
> + for (p = &r->responses; *p && (*p)->sender != getpid(); p =
> &((*p)->next))
> + ;
> + if (*p)
> + {
> + ret = *p;
> + *p = ret->next;
> + }
> + g_mutex_unlock(&r->response_lock);
> + return ret;
> +}
> +
> +static void free_msg(APDUMsg *m)
> +{
> + free(m->data);
> + free(m);
> +}
> +
> +
> +static void delete_reader(PCSCContext *pc, int i)
> +{
> + SCardReader *r = &pc->readers[i];
> + g_mutex_clear(&r->request_lock);
> + g_mutex_clear(&r->response_lock);
> + free(r->name);
> + r->name = NULL;
> +
> + if (i < (pc->reader_count - 1))
> + {
> + int rem = pc->reader_count - i - 1;
> + memmove(&pc->readers[i], &pc->readers[i + 1], sizeof(SCardReader) *
> rem);
> + }
> +
> + pc->reader_count--;
> +}
> +
> +static void delete_reader_cb(VReaderEmul *ve)
> +{
> + SCardReader *r = (SCardReader *) ve;
> +
> + g_mutex_lock(&r->context->lock);
> + delete_reader(r->context, r->index);
> + g_mutex_unlock(&r->context->lock);
> +}
> +
> +static int new_reader(PCSCContext *pc, const char *name, DWORD state)
> +{
> + SCardReader *r;
> + VReader *vreader;
> +
> + if (pc->reader_count >= CAPCSC_MAX_READERS - 1)
> + return 1;
> +
> + r = &pc->readers[pc->reader_count];
> + memset(r, 0, sizeof(*r));
> + r->index = pc->reader_count++;
> + r->context = pc;
> + r->name = strdup(name);
> + g_mutex_init(&r->request_lock);
> + g_mutex_init(&r->response_lock);
> +
> + vreader = vreader_new(name, (VReaderEmul *) r, delete_reader_cb);
> + vreader_add_reader(vreader);
> + vreader_free(vreader);
> +
> + return 0;
> +}
> +
> +static int find_reader(PCSCContext *pc, const char *name)
> +{
> + int i;
> + for (i = 0; i < pc->reader_count; i++)
> + if (strcmp(pc->readers[i].name, name) == 0)
> + return i;
> +
> + return -1;
> +}
> +
> +
> +static int scan_for_readers(PCSCContext *pc)
> +{
> + LONG rc;
> +
> + int i;
> + char buf[8192];
> + DWORD buflen = sizeof(buf);
> +
> + char *p;
> + int matches[CAPCSC_MAX_READERS];
> +
> + g_mutex_lock(&pc->lock);
> +
> + for (i = 0; i < CAPCSC_MAX_READERS; i++)
> + matches[i] = 0;
> +
> + pc->readers_changed = 1;
> + memset(buf, 0, sizeof(buf));
> + rc = SCardListReaders(pc->context, NULL, buf, &buflen);
> + if (rc == SCARD_E_NO_READERS_AVAILABLE)
> + {
> + rc = 0;
> + goto exit;
> + }
> +
> + if (rc != SCARD_S_SUCCESS)
> + {
> + fprintf(stderr, "SCardListReaders failed: %s (0x%lX)\n",
> + pcsc_stringify_error(rc), rc);
> + goto exit;
> + }
> +
> + for (p = buf; p && p < buf + sizeof(buf); p += (strlen(p) + 1))
> + {
> + if (strlen(p) > 0)
> + {
> + i = find_reader(pc, p);
> + if (i >= 0)
> + matches[i]++;
> + else
> + {
> + if (! new_reader(pc, p, SCARD_STATE_UNAWARE))
> + matches[pc->reader_count - 1]++;
> + }
> + }
> + }
> +
> + rc = 0;
> +
> +exit:
> + i = pc->reader_count - 1;
> + g_mutex_unlock(&pc->lock);
> +
> + for (; i >= 0; i--)
> + if (! matches[i])
> + {
> + VReader *reader =
> vreader_get_reader_by_name(pc->readers[i].name);
> + if (reader)
> + {
> + vreader_free(reader);
> + vreader_remove_reader(reader);
> + }
> + }
> +
> +
> + return rc;
> +}
> +
> +static int init_pcsc(PCSCContext *pc)
> +{
> + LONG rc;
> +
> + memset(pc, 0, sizeof(*pc));
> +
> + rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &pc->context);
> + if (rc != SCARD_S_SUCCESS)
> + {
> + fprintf(stderr, "SCardEstablishContext: Cannot Connect to Resource
> Manager %lX\n", rc);
> + return rc;
> + }
> +
> + return 0;
> +}
> +
> +
> +static void prepare_reader_states(PCSCContext *pc, SCARD_READERSTATE
> **states, DWORD *reader_count)
> +{
> + SCARD_READERSTATE *state;
> + int i;
> +
> + if (*states)
> + free(*states);
> +
> + *reader_count = pc->reader_count;
> +
> + (*reader_count)++;
> + *states = malloc((*reader_count) * sizeof(**states));
> + memset(*states, 0, sizeof((*reader_count) * sizeof(**states)));
> +
> + for (i = 0, state = *states; i < pc->reader_count; i++, state++)
> + {
> + state->szReader = pc->readers[i].name;
> + state->dwCurrentState = pc->readers[i].state;
> + }
> +
> + /* Leave a space to be notified of new readers */
> + state->szReader = "\\\\?PnP?\\Notification";
> + state->dwCurrentState = SCARD_STATE_UNAWARE;
> +}
> +
> +static int connect_card(SCardReader *r)
> +{
> + LONG rc;
> +
> + r->protocol = -1;
> + rc = SCardConnect(r->context->context, r->name, SCARD_SHARE_SHARED,
> + SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
> + &r->card, &r->protocol);
> + if (rc != SCARD_S_SUCCESS)
> + {
> + fprintf(stderr, "Failed to connect to a card reader: %s (0x%lX)\n",
> + pcsc_stringify_error(rc), rc);
> + return rc;
> + }
> +
> + r->card_connected = 1;
> + r->request_count = 0;
> +
> + return 0;
> +}
> +
> +static LONG send_receive(SCardReader *r, BYTE *transmit, DWORD transmit_len,
> + BYTE *receive, DWORD *receive_len)
> +{
> + const SCARD_IO_REQUEST *send_header;
> + SCARD_IO_REQUEST receive_header;
> + LONG rc;
> +
> + if (! r->card_connected)
> + {
> + rc = connect_card(r);
> + if (rc)
> + return rc;
> + }
> +
> + if (r->protocol == SCARD_PROTOCOL_T0)
> + send_header = SCARD_PCI_T0;
> + else if (r->protocol == SCARD_PROTOCOL_T1)
> + send_header = SCARD_PCI_T1;
> + else
> + {
> + fprintf(stderr, "Unknown protocol %lX\n", r->protocol);
> + return 1;
> + }
> +
> + rc = SCardTransmit(r->card, send_header, transmit, transmit_len,
> + &receive_header, receive, receive_len);
> + if (rc != SCARD_S_SUCCESS)
> + {
> + fprintf(stderr, "Failed to transmit %ld bytes: %s (0x%lX)\n",
> + transmit_len, pcsc_stringify_error(rc), rc);
> + return rc;
> + }
> +
> + return 0;
> +}
> +
> +
> +static VCardStatus apdu_cb(VCard *card, VCardAPDU *apdu, VCardResponse
> **response)
> +{
> + VCardStatus ret = VCARD_DONE;
> + SCardReader *r = (SCardReader *) vcard_get_private(card);
> + APDUMsg *resp;
> +
> +
> + push_request(r, apdu->a_data, apdu->a_len);
> + while (1)
> + {
> + resp = get_response(r);
> + if (resp)
> + break;
> +
> + usleep(1);
> + }
> +
> + if (resp->rc || resp->len < 2)
> + ret = VCARD_FAIL;
> + else
> + *response = vcard_response_new_bytes(card, resp->data, resp->len -
> 2, apdu->a_Le,
> + ((BYTE *)resp->data)[resp->len - 2],
> + ((BYTE *)resp->data)[resp->len - 1]);
> +
> + free_msg(resp);
> +
> + return ret;
> +}
> +
> +static VCardStatus reset_cb(VCard *card, int channel)
> +{
> + SCardReader *r = (SCardReader *) vcard_get_private(card);
> + LONG rc;
> + unsigned long count;
> +
> + while (get_request(r) || get_response(r))
> + ;
> +
> + /* vreader_power_on is a bit too free with it's resets.
> + And a reconnect is expensive; as much as 10-20 seconds.
> + Hence, we discard any initial reconnect request. */
> + g_mutex_lock(&r->request_lock);
> + count = r->request_count++;
> + g_mutex_unlock(&r->request_lock);
> + if (count == 0)
> + return VCARD_DONE;
> +
> + rc = SCardReconnect(r->card, SCARD_SHARE_SHARED,
> + SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
> SCARD_RESET_CARD, &r->protocol);
> + if (rc != SCARD_S_SUCCESS)
> + {
> + fprintf(stderr, "Failed to reconnect to a card reader: %s (0x%lX)\n",
> + pcsc_stringify_error(rc), rc);
> + return VCARD_FAIL;
> + }
> + return VCARD_DONE;
> +}
> +
> +static void get_atr_cb (VCard *card, unsigned char *atr, int *atr_len)
> +{
> + SCardReader *r = (SCardReader *) vcard_get_private(card);
> + *atr_len = r->atrlen;
> + if (atr)
> + memcpy(atr, r->atr, r->atrlen);
> +}
> +
> +static void delete_card_cb (VCardEmul *ve)
> +{
> + fprintf(stderr, "TODO, got a delete_card_cb\n");
> +}
> +
> +static void insert_card(SCardReader *r, SCARD_READERSTATE *s)
> +{
> + memcpy(r->atr, s->rgbAtr, MIN(sizeof(r->atr), sizeof(s->rgbAtr)));
> + r->atrlen = s->cbAtr;
> +
> + VReader *reader = vreader_get_reader_by_name(r->name);
> + if (! reader)
> + return;
> +
> + if (connect_card(r))
> + return;
> +
> + VCardApplet * applet = vcard_new_applet(apdu_cb, reset_cb, (const
> unsigned char *) CAPCSC_APPLET, strlen(CAPCSC_APPLET));
> + if (! applet)
> + return;
> +
> + VCard * card = vcard_new((VCardEmul *) r, delete_card_cb);
> + if (! card)
> + {
> + vcard_delete_applet(applet);
> + vreader_free(reader);
> + return;
> + }
> +
> + vcard_set_type(card, VCARD_DIRECT);
> + vcard_set_atr_func(card, get_atr_cb);
> + vcard_add_applet(card, applet);
> +
> + vreader_insert_card(reader, card);
> + vreader_free(reader);
> +}
> +
> +static void remove_card(SCardReader *r)
> +{
> + LONG rc;
> + memset(r->atr, 0, sizeof(r->atr));
> + r->atrlen = 0;
> +
> + rc = SCardDisconnect(r->card, SCARD_LEAVE_CARD);
> + if (rc != SCARD_S_SUCCESS)
> + fprintf(stderr, "Non fatal info: failed to disconnect card reader:
> %s (0x%lX)\n",
> + pcsc_stringify_error(rc), rc);
> + r->card_connected = 0;
> +
> + VReader *reader = vreader_get_reader_by_name(r->name);
> + if (! reader)
> + return;
> +
> + vreader_insert_card(reader, NULL);
> + vreader_free(reader);
> +}
> +
> +static void process_reader_change(SCardReader *r, SCARD_READERSTATE *s)
> +{
> + if (s->dwEventState & SCARD_STATE_PRESENT)
> + insert_card(r, s);
> + else if (s->dwEventState & SCARD_STATE_EMPTY)
> + remove_card(r);
> + else
> + fprintf(stderr, "Unexpected card state change from %lx to %lx:\n",
> r->state, s->dwEventState);
> +
> + r->state = s->dwEventState & ~SCARD_STATE_CHANGED;
> +}
> +
> +static void process_requests(SCardReader *r)
> +{
> + BYTE outbuf[4096];
> + DWORD outlen = sizeof(outbuf);
> + LONG rc;
> + APDUMsg *request = get_request(r);
> +
> + if (request)
> + {
> + rc = send_receive(r, request->data, request->len, outbuf, &outlen);
> + push_response(r, outbuf, outlen, rc, request->sender);
> + free_msg(request);
> + }
> +}
> +
> +/*
> + * This thread looks for card and reader insertions and puts events on the
> + * event queue. PCSC is also not thread safe, so we relay requests for
> + * the smart card stack through here as well.
> + */
> +static void event_thread(void *arg)
> +{
> + PCSCContext *pc = (PCSCContext *) arg;
> + DWORD reader_count = 0;
> + SCARD_READERSTATE *reader_states = NULL;
> + LONG rc;
> +
> + scan_for_readers(pc);
> +
> + do {
> + int i;
> + DWORD timeout = INFINITE;
> +
> + g_mutex_lock(&pc->lock);
> + if (pc->readers_changed)
> + {
> + prepare_reader_states(pc, &reader_states, &reader_count);
> + timeout = 0;
> + }
> + else if (reader_count > 1)
> + timeout = CAPCSC_POLL_TIME;
> +
> + pc->readers_changed = 0;
> + g_mutex_unlock(&pc->lock);
> +
> + rc = SCardGetStatusChange(pc->context, timeout, reader_states,
> reader_count);
> +
> + /* If we have a new reader, or an unknown reader, rescan and go back
> and do it again */
> + if ( (rc == SCARD_S_SUCCESS && (reader_states[reader_count -
> 1].dwEventState & SCARD_STATE_CHANGED)) ||
> + rc == SCARD_E_UNKNOWN_READER )
> + {
> + scan_for_readers(pc);
> + continue;
> + }
> +
> + if (rc == SCARD_E_TIMEOUT)
> + {
> + g_mutex_lock(&pc->lock);
> + /* TODO - get an EINTR to speed this up? */
> + for (i = 0; i < reader_count - 1; i++)
> + process_requests(&pc->readers[i]);
> + g_mutex_unlock(&pc->lock);
> +
> + continue;
> + }
> +
> + if (rc != SCARD_S_SUCCESS)
> + {
> + fprintf(stderr, "Unexpected SCardGetStatusChange ret %lx(%s)\n",
> rc, pcsc_stringify_error(rc));
> + continue;
> + }
> +
> + g_mutex_lock(&pc->lock);
> + for (i = 0; i < reader_count; i++)
> + {
> + if (reader_states[i].dwEventState & SCARD_STATE_CHANGED)
> + {
> + process_reader_change(&pc->readers[i], &reader_states[i]);
> + pc->readers_changed++;
> + }
> +
> + }
> + g_mutex_unlock(&pc->lock);
> +
> + } while (1);
> +}
> +
> +/*
> + * We poll the PC/SC interface, looking for device changes
> + */
> +static int new_event_thread(PCSCContext *pc)
> +{
> + pc->thread = PR_CreateThread(PR_SYSTEM_THREAD, event_thread,
> + pc, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
> + PR_UNJOINABLE_THREAD, 0);
I would rather use GThread rather than depending on NSPR here (also
because you use GMutex and friends).
> + return pc->thread == NULL;
> +}
> +
> +
> +static PCSCContext context;
> +
> +int capcsc_init(void)
> +{
> + g_mutex_init(&context.lock);
> +
> + if (init_pcsc(&context))
> + return -1;
> +
> + if (new_event_thread(&context))
> + return -1;
> +
> + return 0;
> +}
> diff --git a/libcacard/capcsc.h b/libcacard/capcsc.h
> new file mode 100644
> index 0000000..4e292cf
> --- /dev/null
> +++ b/libcacard/capcsc.h
> @@ -0,0 +1,16 @@
> +/*
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or
> later.
> + * See the COPYING.LIB file in the top-level directory.
> + */
> +#ifndef CAPCSC_H
> +#define CAPCSC_H 1
> +
> +#define CAPCSC_POLL_TIME 50 /* ms - Time we will poll for
> card change when a reader is connected */
> +#define CAPCSC_MAX_READERS 16 /* Technically, -1, as we leave
> a space to find new readers */
> +
> +#define CAPCSC_APPLET "CAPCSC APPLET"
> +
> +int capcsc_init(void);
> +
> +
> +#endif
> diff --git a/libcacard/libcacard.syms b/libcacard/libcacard.syms
> index 1697515..0e44dc0 100644
> --- a/libcacard/libcacard.syms
> +++ b/libcacard/libcacard.syms
> @@ -1,5 +1,6 @@
> cac_card_init
> cac_is_cac_card
> +capcsc_init
> vcard_add_applet
> vcard_apdu_delete
> vcard_apdu_new
> diff --git a/libcacard/vcard.c b/libcacard/vcard.c
> index d140a8e..4a1d91e 100644
> --- a/libcacard/vcard.c
> +++ b/libcacard/vcard.c
> @@ -95,7 +95,7 @@ vcard_reset(VCard *card, VCardPower power)
> VCardApplet *
> vcard_new_applet(VCardProcessAPDU applet_process_function,
> VCardResetApplet applet_reset_function,
> - unsigned char *aid, int aid_len)
> + const unsigned char *aid, int aid_len)
> {
> VCardApplet *applet;
>
> diff --git a/libcacard/vcard.h b/libcacard/vcard.h
> index 47dc703..c16b944 100644
> --- a/libcacard/vcard.h
> +++ b/libcacard/vcard.h
> @@ -30,7 +30,7 @@ void vcard_reset(VCard *card, VCardPower power);
> */
> VCardApplet *vcard_new_applet(VCardProcessAPDU applet_process_function,
> VCardResetApplet applet_reset_function,
> - unsigned char *aid, int aid_len);
> + const unsigned char *aid, int aid_len);
>
> /*
> * destructor for a VCardApplet
> diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c
> index 950edee..18e6871 100644
> --- a/libcacard/vcard_emul_nss.c
> +++ b/libcacard/vcard_emul_nss.c
> @@ -25,6 +25,7 @@
> #include <prthread.h>
> #include <secerr.h>
>
> +#include "config-host.h"
> #include "qemu-common.h"
>
> #include "vcard.h"
> @@ -34,6 +35,9 @@
> #include "vevent.h"
>
> #include "libcacard/vcardt_internal.h"
> +#if defined(CONFIG_SMARTCARD_PCSC)
> +#include "capcsc.h"
> +#endif
>
>
> typedef enum {
> @@ -892,6 +896,22 @@ vcard_emul_init(const VCardEmulOptions *options)
> options = &default_options;
> }
>
> +#if defined(CONFIG_SMARTCARD_PCSC)
> + if (options->use_hw && options->hw_card_type == VCARD_EMUL_PASSTHRU) {
> + if (options->vreader_count > 0) {
> + fprintf(stderr, "Error: you cannot use a soft card and a
> passthru card simultaneously.\n");
> + return VCARD_EMUL_FAIL;
> + }
> +
> + if (capcsc_init()) {
Why is this needed? Would it be possible to initialize implicitely
when using passthrough?
> + fprintf(stderr, "Error initializing PCSC interface.\n");
> + return VCARD_EMUL_FAIL;
> + }
> +
> + return VCARD_EMUL_OK;
> + }
> +#endif
> +
> /* first initialize NSS */
> if (options->nss_db) {
> rv = NSS_Init(options->nss_db);
> @@ -1270,5 +1290,11 @@ vcard_emul_usage(void)
> "hw_type, and parameters of hw_param.\n"
> "\n"
> "If more one or more soft= parameters are specified, these readers will be\n"
> -"presented to the guest\n");
> +"presented to the guest\n"
> +#if defined(CONFIG_SMARTCARD_PCSC)
> +"\n"
> +"If a hw_type of PASSTHRU is given, a connection will be made to the
> hardware\n"
> +"using libpcscslite. Note that in that case, no soft cards are permitted.\n"
> +#endif
> +);
> }
> diff --git a/libcacard/vcard_emul_type.c b/libcacard/vcard_emul_type.c
> index 59a1458..e8f6a4c 100644
> --- a/libcacard/vcard_emul_type.c
> +++ b/libcacard/vcard_emul_type.c
> @@ -9,6 +9,7 @@
> */
>
> #include <strings.h>
> +#include "config-host.h"
> #include "vcardt.h"
> #include "vcard_emul_type.h"
> #include "cac.h"
> @@ -48,7 +49,7 @@ VCardEmulType vcard_emul_type_from_string(const char
> *type_string)
> if (strcasecmp(type_string, "CAC") == 0) {
> return VCARD_EMUL_CAC;
> }
> -#ifdef USE_PASSTHRU
> +#ifdef CONFIG_SMARTCARD_PCSC
> if (strcasecmp(type_string, "PASSTHRU") == 0) {
> return VCARD_EMUL_PASSTHRU;
> }
> diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c
> index fa6041d..8573f50 100644
> --- a/libcacard/vscclient.c
> +++ b/libcacard/vscclient.c
> @@ -41,14 +41,8 @@ print_byte_array(
>
> static void
> print_usage(void) {
> - printf("vscclient [-c <certname> .. -e <emul_args> -d <level>%s] "
> - "<host> <port>\n",
> -#ifdef USE_PASSTHRU
> - " -p");
> - printf(" -p use passthrough mode\n");
> -#else
> - "");
> -#endif
> + printf("vscclient [-c <certname> .. -e <emul_args> -d <level>] "
> + "<host> <port>\n");
> vcard_emul_usage();
> }
>
> @@ -673,7 +667,7 @@ main(
> }
> #endif
>
> - while ((c = getopt(argc, argv, "c:e:pd:")) != -1) {
> + while ((c = getopt(argc, argv, "c:e:d:")) != -1) {
> switch (c) {
> case 'c':
> if (cert_count >= MAX_CERTS) {
> @@ -685,10 +679,6 @@ main(
> case 'e':
> emul_args = optarg;
> break;
> - case 'p':
> - print_usage();
> - exit(4);
> - break;
> case 'd':
> verbose = get_id_from_string(optarg, 1);
> break;
> --
> 1.7.10.4
>
>
--
Marc-André Lureau