qemu-devel
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]