[Spice-commits] 13 commits - client/application.cpp client/application.h client/Makefile.am client/smartcard_channel.cpp client/smartcard_channel.h client/x11 configure.ac python_modules/ptypes.py server/char_device.h server/Makefile.am server/reds.c server/smartcard.c server/smartcard.h server/spice-experimental.h spice.proto
Alon Levy
alon at kemper.freedesktop.org
Tue Dec 7 03:35:29 PST 2010
client/Makefile.am | 10
client/application.cpp | 65 +++++
client/application.h | 12
client/smartcard_channel.cpp | 481 ++++++++++++++++++++++++++++++++++++++
client/smartcard_channel.h | 135 ++++++++++
client/x11/Makefile.am | 9
configure.ac | 22 +
python_modules/ptypes.py | 2
server/Makefile.am | 11
server/char_device.h | 11
server/reds.c | 54 +++-
server/smartcard.c | 532 +++++++++++++++++++++++++++++++++++++++++++
server/smartcard.h | 18 +
server/spice-experimental.h | 8
spice.proto | 8
15 files changed, 1363 insertions(+), 15 deletions(-)
New commits:
commit 9dfeeaefbe10163863192703ca35ac65e02bc0db
Author: Alon Levy <alevy at redhat.com>
Date: Tue Nov 30 20:34:20 2010 +0200
client/smartcard: add files to Makefile.am for make dist
diff --git a/client/Makefile.am b/client/Makefile.am
index 166ce5e..da859f4 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -28,8 +28,10 @@ else
GL_SRCS =
endif
+SMARTCARD_SRC_ENABLED = smartcard_channel.cpp smartcard_channel.h
+
if SUPPORT_SMARTCARD
-SMARTCARD_SRCS = smartcard_channel.cpp
+SMARTCARD_SRCS = $(SMARTCARD_SRC_ENABLED)
else
SMARTCARD_SRCS =
endif
@@ -140,6 +142,6 @@ GDI_FILES = \
MAINTAINERCLEANFILES = $(spice_built_sources)
-EXTRA_DIST = $(RED_COMMON_SRCS) $(spice_built_sources) $(GL_SRCS) $(GDI_FILES) $(SMARTCARD_SRCS)
+EXTRA_DIST = $(RED_COMMON_SRCS) $(spice_built_sources) $(GL_SRCS) $(GDI_FILES) $(SMARTCARD_SRC_ENABLED)
BUILT_SOURCES = $(spice_built_sources)
commit 7e0a1dfa75d9c967b96929c56dce4cecb7151a85
Author: Alon Levy <alevy at redhat.com>
Date: Wed Sep 15 15:55:37 2010 +0200
smartcard: configure option --enable-smartcard
diff --git a/client/Makefile.am b/client/Makefile.am
index 5a14f5f..166ce5e 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -28,6 +28,12 @@ else
GL_SRCS =
endif
+if SUPPORT_SMARTCARD
+SMARTCARD_SRCS = smartcard_channel.cpp
+else
+SMARTCARD_SRCS =
+endif
+
RED_COMMON_SRCS = \
application.cpp \
application.h \
@@ -134,6 +140,6 @@ GDI_FILES = \
MAINTAINERCLEANFILES = $(spice_built_sources)
-EXTRA_DIST = $(RED_COMMON_SRCS) $(spice_built_sources) $(GL_SRCS) $(GDI_FILES)
+EXTRA_DIST = $(RED_COMMON_SRCS) $(spice_built_sources) $(GL_SRCS) $(GDI_FILES) $(SMARTCARD_SRCS)
BUILT_SOURCES = $(spice_built_sources)
diff --git a/client/x11/Makefile.am b/client/x11/Makefile.am
index 45ff7fc..42b8b0a 100644
--- a/client/x11/Makefile.am
+++ b/client/x11/Makefile.am
@@ -27,6 +27,7 @@ INCLUDES = \
$(CEGUI_CFLAGS) \
$(WARN_CFLAGS) \
$(SPICE_NONPKGCONFIG_CFLAGS) \
+ $(SMARTCARD_CFLAGS) \
$(NULL)
@@ -158,6 +159,12 @@ else
RED_OGL_SRCS =
endif
+if SUPPORT_SMARTCARD
+RED_SCARD_SRCS = $(CLIENT_DIR)/smartcard_channel.cpp
+else
+RED_SCARD_SRCS =
+endif
+
bin_PROGRAMS = spicec
spicec_SOURCES = \
@@ -191,6 +198,7 @@ spicec_SOURCES = \
$(RED_GUI_SRCS) \
$(RED_TUNNEL_SRCS) \
$(RED_OGL_SRCS) \
+ $(RED_SCARD_SRCS) \
$(NULL)
spicec_LDFLAGS = \
@@ -200,6 +208,7 @@ spicec_LDFLAGS = \
$(CEGUI_LIBS) \
$(JPEG_LIBS) \
$(Z_LIBS) \
+ $(SMARTCARD_LIBS) \
$(SPICE_NONPKGCONFIG_LIBS)
spicec_LDADD = \
diff --git a/configure.ac b/configure.ac
index 8742fab..4f3b118 100644
--- a/configure.ac
+++ b/configure.ac
@@ -113,6 +113,16 @@ AC_ARG_ENABLE(opengl,
[ --enable-opengl Enable opengl requirement / support (not recommended)],
[ have_opengl=yes])
AM_CONDITIONAL(SUPPORT_GL, test "x$have_opengl" = "xyes")
+
+have_smartcard=no
+AC_ARG_ENABLE(smartcard,
+[ --enable-smartcard Enable network redirection],
+[ have_smartcard=yes])
+AM_CONDITIONAL(SUPPORT_SMARTCARD, test "x$have_smartcard" = "xyes")
+if test "x$have_smartcard" = "xyes"; then
+ AC_DEFINE(USE_SMARTCARD, [1], [Define if supporting smartcard proxying])
+fi
+
dnl =========================================================================
dnl Check deps
@@ -168,6 +178,16 @@ if test "x$have_tunnel" = "xyes"; then
AC_DEFINE([HAVE_SLIRP], [], [Define if we have slirp])
fi
+if test "x$have_smartcard" = "xyes"; then
+ PKG_CHECK_MODULES(CAC_CARD, cac_card >= 0.0.1)
+ SMARTCARD_LIBS="$CAC_CARD_LIBS"
+ SMARTCARD_CFLAGS="$CAC_CARD_CFLAGS"
+ SPICE_REQUIRES+=" cac_card"
+ AC_SUBST(SMARTCARD_LIBS)
+ AC_SUBST(SMARTCARD_CFLAGS)
+fi
+
+
PKG_CHECK_MODULES(PIXMAN, pixman-1 >= 0.17.7)
AC_SUBST(PIXMAN_CFLAGS)
AC_SUBST(PIXMAN_LIBS)
@@ -422,5 +442,7 @@ echo "
GUI: ${use_gui}
+ Smartcard: ${have_smartcard}
+
Now type 'make' to build $PACKAGE
"
diff --git a/server/Makefile.am b/server/Makefile.am
index ff7b485..2c86a2c 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -17,6 +17,7 @@ INCLUDES = \
-DRED_STATISTICS \
$(WARN_CFLAGS) \
$(VISIBILITY_HIDDEN_CFLAGS) \
+ $(SMARTCARD_CFLAGS) \
$(NULL)
spice_built_sources = generated_marshallers.c generated_marshallers.h generated_demarshallers.c
@@ -81,6 +82,15 @@ else
TUNNEL_SRCS =
endif
+if SUPPORT_SMARTCARD
+SMARTCARD_SRCS = \
+ smartcard.c \
+ smartcard.h \
+ $(NULL)
+else
+SMARTCARD_SRCS =
+endif
+
libspice_server_la_SOURCES = \
demarshallers.h \
glz_encoder.c \
@@ -121,6 +131,7 @@ libspice_server_la_SOURCES = \
zlib_encoder.h \
char_device.h \
$(TUNNEL_SRCS) \
+ $(SMARTCARD_SRCS) \
$(COMMON_SRCS) \
$(GL_SRCS) \
$(NULL)
commit d99ec6c35b02a64950c4397644a9a81fad1d4492
Author: Alon Levy <alevy at redhat.com>
Date: Wed Sep 15 15:55:11 2010 +0200
smartcard: server side (not enabled yet)
diff --git a/server/reds.c b/server/reds.c
index 3edf474..b4ec6e1 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -59,6 +59,9 @@
#ifdef USE_TUNNEL
#include "red_tunnel_worker.h"
#endif
+#ifdef USE_SMARTCARD
+#include "smartcard.h"
+#endif
SpiceCoreInterface *core = NULL;
static SpiceKbdInstance *keyboard = NULL;
@@ -1251,6 +1254,7 @@ static int read_from_vdi_port(void)
VDIReadBuf *dispatch_buf;
int total = 0;
int n;
+
if (inside_call) {
return 0;
}
@@ -3432,9 +3436,13 @@ __visible__ void spice_server_char_device_wakeup(SpiceCharDeviceInstance* sin)
}
#define SUBTYPE_VDAGENT "vdagent"
+#define SUBTYPE_SMARTCARD "smartcard"
const char *spice_server_char_device_recognized_subtypes_list[] = {
SUBTYPE_VDAGENT,
+#ifdef USE_SMARTCARD
+ SUBTYPE_SMARTCARD,
+#endif
NULL,
};
@@ -3460,6 +3468,13 @@ static int spice_server_char_device_add_interface(SpiceServer *s,
char_device->st = &vdagent_char_device_state;
attach_to_red_agent(char_device);
}
+#ifdef USE_SMARTCARD
+ else if (strcmp(char_device->subtype, SUBTYPE_SMARTCARD) == 0) {
+ if (smartcard_device_connect(char_device) == -1) {
+ return -1;
+ }
+ }
+#endif
return 0;
}
@@ -3474,6 +3489,11 @@ static void spice_server_char_device_remove_interface(SpiceBaseInstance *sin)
reds_agent_remove();
}
}
+#ifdef USE_SMARTCARD
+ else if (strcmp(char_device->subtype, SUBTYPE_SMARTCARD) == 0) {
+ smartcard_device_disconnect(char_device);
+ }
+#endif
}
__visible__ int spice_server_add_interface(SpiceServer *s,
@@ -3759,6 +3779,10 @@ static void do_spice_init(SpiceCoreInterface *core_interface)
}
inputs_init();
+#ifdef USE_SMARTCARD
+ smartcard_channel_init();
+#endif
+
reds->mouse_mode = SPICE_MOUSE_MODE_SERVER;
atexit(reds_exit);
}
diff --git a/server/smartcard.c b/server/smartcard.c
new file mode 100644
index 0000000..7c0a5aa
--- /dev/null
+++ b/server/smartcard.c
@@ -0,0 +1,532 @@
+#include "server/char_device.h"
+#include "server/red_channel.h"
+#include "server/smartcard.h"
+#include "vscard_common.h"
+
+#define SMARTCARD_MAX_READERS 10
+
+typedef struct SmartCardDeviceState {
+ SpiceCharDeviceState base;
+ reader_id_t reader_id;
+ uint32_t attached;
+ uint8_t *buf;
+ uint32_t buf_size;
+ uint8_t *buf_pos;
+ uint32_t buf_used;
+} SmartCardDeviceState;
+
+enum {
+ PIPE_ITEM_TYPE_ERROR=1,
+ PIPE_ITEM_TYPE_READER_ADD_RESPONSE,
+ PIPE_ITEM_TYPE_MSG,
+};
+
+typedef struct ErrorItem {
+ PipeItem base;
+ reader_id_t reader_id;
+ uint32_t error;
+} ErrorItem;
+
+typedef struct ReaderAddResponseItem {
+ PipeItem base;
+ uint32_t reader_id;
+} ReaderAddResponseItem;
+
+typedef struct MsgItem {
+ PipeItem base;
+ VSCMsgHeader* vheader;
+} MsgItem;
+
+typedef struct SmartCardChannel {
+ RedChannel base;
+} SmartCardChannel;
+
+static SmartCardChannel *g_smartcard_channel = NULL;
+
+static struct Readers {
+ uint32_t num;
+ SpiceCharDeviceInstance* sin[SMARTCARD_MAX_READERS];
+} g_smartcard_readers = {0, {NULL}};
+
+static SpiceCharDeviceInstance* smartcard_readers_get_unattached();
+static SpiceCharDeviceInstance* smartcard_readers_get(reader_id_t reader_id);
+static int smartcard_char_device_add_to_readers(SpiceCharDeviceInstance *sin);
+static void smartcard_char_device_attach(
+ SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel);
+static void smartcard_char_device_detach(
+ SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel);
+static void smartcard_channel_write_to_reader(
+ SmartCardChannel *smartcard_channel, VSCMsgHeader *vheader);
+
+static void smartcard_char_device_on_message_from_device(
+ SmartCardDeviceState *state, VSCMsgHeader *header);
+static void smartcard_on_message_from_device(
+ SmartCardChannel *smartcard_channel, VSCMsgHeader *vheader);
+static SmartCardDeviceState* smartcard_device_state_new();
+static void smartcard_device_state_free(SmartCardDeviceState* st);
+
+void smartcard_char_device_wakeup(SpiceCharDeviceInstance *sin)
+{
+ SmartCardDeviceState* state = SPICE_CONTAINEROF(
+ sin->st, SmartCardDeviceState, base);
+ SpiceCharDeviceInterface *sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base);
+ VSCMsgHeader *vheader = (VSCMsgHeader*)state->buf;
+ int n;
+ int remaining;
+
+ while ((n = sif->read(sin, state->buf_pos, state->buf_size - state->buf_used)) > 0) {
+ state->buf_pos += n;
+ state->buf_used += n;
+ if (state->buf_used < sizeof(VSCMsgHeader)) {
+ continue;
+ }
+ if (vheader->length > state->buf_size) {
+ state->buf_size = MAX(state->buf_size*2, vheader->length + sizeof(VSCMsgHeader));
+ state->buf = spice_realloc(state->buf, state->buf_size);
+ ASSERT(state->buf != NULL);
+ }
+ if (state->buf_used - sizeof(VSCMsgHeader) < vheader->length) {
+ continue;
+ }
+ smartcard_char_device_on_message_from_device(state, vheader);
+ remaining = state->buf_used - sizeof(VSCMsgHeader) > vheader->length;
+ if (remaining > 0) {
+ memcpy(state->buf, state->buf_pos, remaining);
+ }
+ state->buf_pos = state->buf;
+ state->buf_used = remaining;
+ }
+}
+
+void smartcard_char_device_on_message_from_device(
+ SmartCardDeviceState *state,
+ VSCMsgHeader *vheader)
+{
+ VSCMsgHeader *sent_header;
+
+ switch (vheader->type) {
+ case VSC_Init:
+ return;
+ break;
+ case VSC_ReaderAddResponse:
+ /* The device sends this for vscclient, we send one ourselves,
+ * a second would be an error. */
+ return;
+ break;
+ case VSC_Reconnect:
+ /* Ignore VSC_Reconnect messages, spice channel reconnection does the same. */
+ return;
+ break;
+ default:
+ break;
+ }
+ ASSERT(state->reader_id != VSCARD_UNDEFINED_READER_ID);
+ ASSERT(g_smartcard_channel != NULL);
+ sent_header = spice_memdup(vheader, sizeof(*vheader) + vheader->length);
+ sent_header->reader_id = state->reader_id;
+ smartcard_on_message_from_device(g_smartcard_channel, sent_header);
+}
+
+static void smartcard_readers_detach_all(SmartCardChannel *smartcard_channel)
+{
+ int i;
+
+ for (i = 0 ; i < g_smartcard_readers.num; ++i) {
+ smartcard_char_device_detach(g_smartcard_readers.sin[i],
+ smartcard_channel);
+ }
+}
+
+static int smartcard_char_device_add_to_readers(SpiceCharDeviceInstance *char_device)
+{
+ SmartCardDeviceState* state = SPICE_CONTAINEROF(
+ char_device->st, SmartCardDeviceState, base);
+
+ if (g_smartcard_readers.num >= SMARTCARD_MAX_READERS) {
+ return -1;
+ }
+ state->reader_id = g_smartcard_readers.num;
+ g_smartcard_readers.sin[g_smartcard_readers.num++] = char_device;
+ return 0;
+}
+
+static SpiceCharDeviceInstance *smartcard_readers_get(reader_id_t reader_id)
+{
+ ASSERT(reader_id < g_smartcard_readers.num);
+ return g_smartcard_readers.sin[reader_id];
+}
+
+static SpiceCharDeviceInstance *smartcard_readers_get_unattached()
+{
+ int i;
+ SmartCardDeviceState* state;
+
+ for (i = 0; i < g_smartcard_readers.num; ++i) {
+ state = SPICE_CONTAINEROF(g_smartcard_readers.sin[i]->st,
+ SmartCardDeviceState, base);
+ if (!state->attached) {
+ return g_smartcard_readers.sin[i];
+ }
+ }
+ return NULL;
+}
+
+static SmartCardDeviceState* smartcard_device_state_new()
+{
+ SmartCardDeviceState *st;
+
+ st = spice_new0(SmartCardDeviceState, 1);
+ st->base.wakeup = smartcard_char_device_wakeup;
+ st->reader_id = VSCARD_UNDEFINED_READER_ID;
+ st->attached = FALSE;
+ st->buf_size = APDUBufSize + sizeof(VSCMsgHeader);
+ st->buf = spice_malloc(st->buf_size);
+ st->buf_pos = st->buf;
+ st->buf_used = 0;
+ return st;
+}
+
+static void smartcard_device_state_free(SmartCardDeviceState* st)
+{
+ free(st->buf);
+ free(st);
+}
+
+void smartcard_device_disconnect(SpiceCharDeviceInstance *char_device)
+{
+ SmartCardDeviceState *st = SPICE_CONTAINEROF(char_device->st,
+ SmartCardDeviceState, base);
+
+ smartcard_device_state_free(st);
+}
+
+int smartcard_device_connect(SpiceCharDeviceInstance *char_device)
+{
+ SmartCardDeviceState *st;
+
+ st = smartcard_device_state_new();
+ char_device->st = &st->base;
+ if (smartcard_char_device_add_to_readers(char_device) == -1) {
+ smartcard_device_state_free(st);
+ return -1;
+ }
+ return 0;
+}
+
+static void smartcard_char_device_attach(
+ SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel)
+{
+ SmartCardDeviceState *st = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base);
+
+ if (st->attached == TRUE) {
+ return;
+ }
+ st->attached = TRUE;
+ VSCMsgHeader vheader = {.type = VSC_ReaderAdd, .reader_id=st->reader_id,
+ .length=0};
+ smartcard_channel_write_to_reader(smartcard_channel, &vheader);
+}
+
+static void smartcard_char_device_detach(
+ SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel)
+{
+ SmartCardDeviceState *st = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base);
+
+ if (st->attached == FALSE) {
+ return;
+ }
+ st->attached = FALSE;
+ VSCMsgHeader vheader = {.type = VSC_ReaderRemove, .reader_id=st->reader_id,
+ .length=0};
+ smartcard_channel_write_to_reader(smartcard_channel, &vheader);
+}
+
+static int smartcard_channel_config_socket(RedChannel *channel)
+{
+ return TRUE;
+}
+
+static uint8_t *smartcard_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header)
+{
+ //red_printf("allocing %d bytes", msg_header->size);
+ return spice_malloc(msg_header->size);
+}
+
+static void smartcard_channel_release_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header,
+ uint8_t *msg)
+{
+ red_printf("freeing %d bytes", msg_header->size);
+ free(msg);
+}
+
+static void smartcard_channel_send_data(RedChannel *channel, PipeItem *item, VSCMsgHeader *vheader)
+{
+ ASSERT(channel);
+ ASSERT(vheader);
+ red_channel_init_send_data(channel, SPICE_MSG_SMARTCARD_DATA, item);
+ red_channel_add_buf(channel, vheader, sizeof(VSCMsgHeader));
+ if (vheader->length > 0) {
+ red_channel_add_buf(channel, (uint8_t*)(vheader+1), vheader->length);
+ }
+ red_channel_begin_send_message(channel);
+}
+
+static void smartcard_channel_send_message(RedChannel *channel, PipeItem *item,
+ uint32_t reader_id, VSCMsgType type, uint8_t* data, uint32_t len)
+{
+ VSCMsgHeader mhHeader;
+ //SpiceMarshaller* m = msg->marshaller();
+
+ mhHeader.type = type;
+ mhHeader.length = len;
+ mhHeader.reader_id = reader_id;
+ //_marshallers->msg_SpiceMsgData(m, &msgdata);
+ //spice_marshaller_add(m, (uint8_t*)&mhHeader, sizeof(mhHeader));
+ //spice_marshaller_add(m, data, len);
+ //marshaller_outgoing_write(msg);
+
+ smartcard_channel_send_data(channel, item, &mhHeader);
+}
+
+static void smartcard_channel_send_error(
+ SmartCardChannel *smartcard_channel, PipeItem *item)
+{
+ ErrorItem* error_item = (ErrorItem*)item;
+ VSCMsgError error;
+
+ error.code = error_item->error;
+ smartcard_channel_send_message(&smartcard_channel->base, item, error_item->reader_id,
+ VSC_Error, (uint8_t*)&error, sizeof(error));
+}
+
+static void smartcard_channel_send_reader_add_response(
+ SmartCardChannel *smartcard_channel, PipeItem *item)
+{
+ ReaderAddResponseItem* rar_item = (ReaderAddResponseItem*)item;
+ VSCMsgReaderAddResponse rar;
+
+ smartcard_channel_send_message(&smartcard_channel->base, item, rar_item->reader_id,
+ VSC_ReaderAddResponse, (uint8_t*)&rar, sizeof(rar));
+}
+
+static void smartcard_channel_send_msg(
+ SmartCardChannel *smartcard_channel, PipeItem *item)
+{
+ MsgItem* msg_item = (MsgItem*)item;
+
+ smartcard_channel_send_data(&smartcard_channel->base, item, msg_item->vheader);
+}
+
+static void smartcard_channel_send_item(RedChannel *channel, PipeItem *item)
+{
+ SmartCardChannel *smartcard_channel = (SmartCardChannel *)channel;
+
+ red_channel_reset_send_data(channel);
+ switch (item->type) {
+ case PIPE_ITEM_TYPE_ERROR:
+ smartcard_channel_send_error(smartcard_channel, item);
+ break;
+ case PIPE_ITEM_TYPE_READER_ADD_RESPONSE:
+ smartcard_channel_send_reader_add_response(smartcard_channel, item);
+ break;
+ case PIPE_ITEM_TYPE_MSG:
+ smartcard_channel_send_msg(smartcard_channel, item);
+ }
+}
+
+
+static void smartcard_channel_release_pipe_item(RedChannel *channel, PipeItem *item, int item_pushed)
+{
+ free(item);
+ if (item->type == PIPE_ITEM_TYPE_MSG) {
+ free(((MsgItem*)item)->vheader);
+ }
+}
+
+static void smartcard_channel_disconnect(RedChannel *channel)
+{
+ smartcard_readers_detach_all((SmartCardChannel*)channel);
+ red_channel_destroy(channel);
+ g_smartcard_channel = NULL;
+}
+
+/* this is called from both device input and client input. since the device is
+ * a usb device, the context is still the main thread (kvm_main_loop, timers)
+ * so no mutex is required. */
+static void smartcard_channel_pipe_add(SmartCardChannel *channel, PipeItem *item)
+{
+ red_channel_pipe_add(&channel->base, item);
+}
+
+static void smartcard_push_error(SmartCardChannel* channel, reader_id_t reader_id, VSCErrorCode error)
+{
+ ErrorItem *error_item = spice_new0(ErrorItem, 1);
+
+ error_item->base.type = PIPE_ITEM_TYPE_ERROR;
+ error_item->reader_id = reader_id;
+ error_item->error = error;
+ smartcard_channel_pipe_add(channel, &error_item->base);
+}
+
+static void smartcard_push_reader_add_response(SmartCardChannel *channel, uint32_t reader_id)
+{
+ ReaderAddResponseItem *rar_item = spice_new0(ReaderAddResponseItem, 1);
+
+ rar_item->base.type = PIPE_ITEM_TYPE_READER_ADD_RESPONSE;
+ rar_item->reader_id = reader_id;
+ smartcard_channel_pipe_add(channel, &rar_item->base);
+}
+
+static void smartcard_push_vscmsg(SmartCardChannel *channel, VSCMsgHeader *vheader)
+{
+ MsgItem *msg_item = spice_new0(MsgItem, 1);
+
+ msg_item->base.type = PIPE_ITEM_TYPE_MSG;
+ msg_item->vheader = vheader;
+ smartcard_channel_pipe_add(channel, &msg_item->base);
+}
+
+void smartcard_on_message_from_device(SmartCardChannel *smartcard_channel,
+ VSCMsgHeader* vheader)
+{
+ smartcard_push_vscmsg(smartcard_channel, vheader);
+}
+
+static void smartcard_remove_reader(SmartCardChannel *smartcard_channel, reader_id_t reader_id)
+{
+ SpiceCharDeviceInstance *char_device = smartcard_readers_get(reader_id);
+ SmartCardDeviceState *state;
+
+ if (char_device == NULL) {
+ smartcard_push_error(smartcard_channel, reader_id,
+ VSC_GENERAL_ERROR);
+ return;
+ }
+
+ state = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base);
+ if (state->attached == FALSE) {
+ smartcard_push_error(smartcard_channel, reader_id,
+ VSC_GENERAL_ERROR);
+ return;
+ }
+ smartcard_char_device_detach(char_device, smartcard_channel);
+}
+
+static void smartcard_add_reader(SmartCardChannel *smartcard_channel, uint8_t *name)
+{
+ // TODO - save name somewhere
+ SpiceCharDeviceInstance *char_device =
+ smartcard_readers_get_unattached();
+ SmartCardDeviceState *state;
+
+ if (char_device != NULL) {
+ state = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base);
+ smartcard_char_device_attach(char_device, smartcard_channel);
+ smartcard_push_reader_add_response(smartcard_channel, state->reader_id);
+ } else {
+ smartcard_push_error(smartcard_channel, VSCARD_UNDEFINED_READER_ID,
+ VSC_CANNOT_ADD_MORE_READERS);
+ }
+}
+
+static void smartcard_channel_write_to_reader(
+ SmartCardChannel *smartcard_channel, VSCMsgHeader *vheader)
+{
+ SpiceCharDeviceInstance *sin;
+ SpiceCharDeviceInterface *sif;
+ uint32_t n;
+
+ ASSERT(vheader->reader_id >= 0 &&
+ vheader->reader_id <= g_smartcard_readers.num);
+ sin = g_smartcard_readers.sin[vheader->reader_id];
+ sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base);
+ n = sif->write(sin, (uint8_t*)vheader,
+ vheader->length + sizeof(VSCMsgHeader));
+ // TODO - add ring
+ ASSERT(n == vheader->length + sizeof(VSCMsgHeader));
+}
+
+static int smartcard_channel_handle_message(RedChannel *channel, SpiceDataHeader *header, uint8_t *msg)
+{
+ VSCMsgHeader* vheader = (VSCMsgHeader*)msg;
+ SmartCardChannel* smartcard_channel = (SmartCardChannel*)channel;
+
+ ASSERT(header->size == vheader->length + sizeof(VSCMsgHeader));
+ switch (vheader->type) {
+ case VSC_ReaderAdd:
+ smartcard_add_reader(smartcard_channel, msg + sizeof(VSCMsgHeader));
+ return TRUE;
+ break;
+ case VSC_ReaderRemove:
+ smartcard_remove_reader(smartcard_channel, vheader->reader_id);
+ return TRUE;
+ break;
+ case VSC_ReaderAddResponse:
+ /* We shouldn't get this - we only send it */
+ return TRUE;
+ break;
+ case VSC_Init:
+ case VSC_Error:
+ case VSC_ATR:
+ case VSC_CardRemove:
+ case VSC_APDU:
+ break; // passed on to device
+ default:
+ printf("ERROR: unexpected message on smartcard channel\n");
+ return TRUE;
+ }
+
+ if (vheader->reader_id >= g_smartcard_readers.num) {
+ red_printf("ERROR: received message for non existent reader: %d, %d, %d", vheader->reader_id,
+ vheader->type, vheader->length);
+ return FALSE;
+ }
+ smartcard_channel_write_to_reader(smartcard_channel, vheader);
+ return TRUE;
+}
+
+static void smartcard_link(Channel *channel, RedsStreamContext *peer,
+ int migration, int num_common_caps,
+ uint32_t *common_caps, int num_caps,
+ uint32_t *caps)
+{
+ if (g_smartcard_channel) {
+ red_channel_destroy(&g_smartcard_channel->base);
+ }
+ g_smartcard_channel =
+ (SmartCardChannel *)red_channel_create(sizeof(*g_smartcard_channel),
+ peer, core,
+ migration, FALSE /* handle_acks */,
+ smartcard_channel_config_socket,
+ smartcard_channel_disconnect,
+ smartcard_channel_handle_message,
+ smartcard_channel_alloc_msg_rcv_buf,
+ smartcard_channel_release_msg_rcv_buf,
+ smartcard_channel_send_item,
+ smartcard_channel_release_pipe_item);
+ if (!g_smartcard_channel) {
+ return;
+ }
+ red_channel_init_outgoing_messages_window(&g_smartcard_channel->base);
+}
+
+static void smartcard_shutdown(Channel *channel)
+{
+}
+
+static void smartcard_migrate(Channel *channel)
+{
+}
+
+void smartcard_channel_init()
+{
+ Channel *channel;
+
+ channel = spice_new0(Channel, 1);
+ channel->type = SPICE_CHANNEL_SMARTCARD;
+ channel->link = smartcard_link;
+ channel->shutdown = smartcard_shutdown;
+ channel->migrate = smartcard_migrate;
+ reds_register_channel(channel);
+}
+
diff --git a/server/smartcard.h b/server/smartcard.h
new file mode 100644
index 0000000..790eb87
--- /dev/null
+++ b/server/smartcard.h
@@ -0,0 +1,18 @@
+#ifndef __SMART_CARD_H__
+#define __SMART_CARD_H__
+
+#include "server/spice-experimental.h"
+
+// Maximal length of APDU
+#define APDUBufSize 270
+
+/** connect to smartcard interface, used by smartcard channel
+ * returns -1 if failed, 0 if successfull
+ */
+int smartcard_device_connect(SpiceCharDeviceInstance *char_device);
+void smartcard_device_disconnect(SpiceCharDeviceInstance *char_device);
+
+void smartcard_channel_init();
+
+#endif // __SMART_CARD_H__
+
commit 757686384fc47746891b6280b9f27404420c8dea
Author: Alon Levy <alevy at redhat.com>
Date: Sat Oct 23 18:29:45 2010 +0200
smartcard: client: add keyboard shortcuts for remove/insert virtual card
diff --git a/client/application.cpp b/client/application.cpp
index ae19785..a484bbc 100644
--- a/client/application.cpp
+++ b/client/application.cpp
@@ -339,6 +339,10 @@ enum AppCommands {
#ifdef USE_GUI
APP_CMD_SHOW_GUI,
#endif // USE_GUI
+#ifdef USE_SMARTCARD
+ APP_CMD_SMARTCARD_INSERT,
+ APP_CMD_SMARTCARD_REMOVE,
+#endif
APP_CMD_EXTERNAL_BEGIN = 0x400,
APP_CMD_EXTERNAL_END = 0x800,
};
@@ -391,6 +395,10 @@ Application::Application()
#ifdef USE_GUI
_commands_map["show-gui"] = APP_CMD_SHOW_GUI;
#endif // USE_GUI
+#ifdef USE_SMARTCARD
+ _commands_map["smartcard-insert"] = APP_CMD_SMARTCARD_INSERT;
+ _commands_map["smartcard-remove"] = APP_CMD_SMARTCARD_REMOVE;
+#endif
_canvas_types.resize(1);
#ifdef WIN32
@@ -413,6 +421,10 @@ Application::Application()
#ifdef USE_GUI
",show-gui=shift+f7"
#endif // USE_GUI
+#ifdef USE_SMARTCARD
+ ",smartcard-insert=shift+f8"
+ ",smartcard-remove=shift+f9"
+#endif
, _commands_map));
_hot_keys = parser->get();
@@ -1007,6 +1019,14 @@ void Application::do_command(int command)
show_gui();
break;
#endif // USE_GUI
+#ifdef USE_SMARTCARD
+ case APP_CMD_SMARTCARD_INSERT:
+ virtual_card_insert();
+ break;
+ case APP_CMD_SMARTCARD_REMOVE:
+ virtual_card_remove();
+ break;
+#endif
default:
AppMenuItemMap::iterator iter = _app_menu_items.find(command);
ASSERT(iter != _app_menu_items.end());
diff --git a/client/smartcard_channel.cpp b/client/smartcard_channel.cpp
index d585c9a..994671f 100644
--- a/client/smartcard_channel.cpp
+++ b/client/smartcard_channel.cpp
@@ -228,6 +228,38 @@ void SmartCardChannel::cac_card_events_thread_main()
}
}
+void virtual_card_insert()
+{
+ if (g_smartcard_channel == NULL) {
+ return;
+ }
+ g_smartcard_channel->virtual_card_insert();
+}
+
+void SmartCardChannel::virtual_card_insert()
+{
+ if (_readers_by_id.size() == 0) {
+ return;
+ }
+ vcard_emul_force_card_insert(_readers_by_id.begin()->second->vreader);
+}
+
+void virtual_card_remove()
+{
+ if (g_smartcard_channel == NULL) {
+ return;
+ }
+ g_smartcard_channel->virtual_card_remove();
+}
+
+void SmartCardChannel::virtual_card_remove()
+{
+ if (_readers_by_id.size() == 0) {
+ return;
+ }
+ vcard_emul_force_card_remove(_readers_by_id.begin()->second->vreader);
+}
+
#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
#define CERTIFICATES_ARGS_TEMPLATE "db=\"%s\" use_hw=no soft=(,Virtual Card,CAC,,%s,%s,%s)"
diff --git a/client/smartcard_channel.h b/client/smartcard_channel.h
index ee0d0d0..60c6db5 100644
--- a/client/smartcard_channel.h
+++ b/client/smartcard_channel.h
@@ -92,6 +92,8 @@ public:
SmartCardChannel(RedClient& client, uint32_t id);
void handle_smartcard_data(RedPeer::InMessage* message);
+ void virtual_card_remove();
+ void virtual_card_insert();
static ChannelFactory& Factory();
protected:
virtual void on_connect();
commit a2afcde061a488713119e03774915ea752757824
Author: Alon Levy <alevy at redhat.com>
Date: Wed Sep 15 15:54:43 2010 +0200
smartcard: client side (not enabled yet)
diff --git a/client/application.cpp b/client/application.cpp
index c380373..ae19785 100644
--- a/client/application.cpp
+++ b/client/application.cpp
@@ -47,6 +47,10 @@
#include <stdio.h>
#include <time.h>
+#ifdef USE_SMARTCARD
+#include <smartcard_channel.h>
+#endif
+
#define STICKY_KEY_PIXMAP ALT_IMAGE_RES_ID
#define STICKY_KEY_TIMEOUT 750
@@ -364,6 +368,9 @@ Application::Application()
#endif // USE_GUI
, _during_host_switch(false)
, _state (DISCONNECTED)
+#ifdef USE_SMARTCARD
+ , _smartcard_options(new SmartcardOptions())
+#endif
{
DBG(0, "");
Platform::set_process_loop(*this);
@@ -447,6 +454,9 @@ Application::~Application()
_main_screen->unref();
destroy_monitors();
+#ifdef USE_SMARTCARD
+ delete _smartcard_options;
+#endif
}
void Application::init_menu()
@@ -2148,6 +2158,12 @@ void Application::register_channels()
_client.register_channel_factory(TunnelChannel::Factory());
}
#endif
+#ifdef USE_SMARTCARD
+ if (_enabled_channels[SPICE_CHANNEL_SMARTCARD] && _smartcard_options->enable) {
+ smartcard_init(_smartcard_options); // throws Exception
+ _client.register_channel_factory(SmartCardChannel::Factory());
+ }
+#endif
}
bool Application::process_cmd_line(int argc, char** argv)
@@ -2177,6 +2193,12 @@ bool Application::process_cmd_line(int argc, char** argv)
SPICE_OPT_DISPLAY_COLOR_DEPTH,
SPICE_OPT_DISABLE_DISPLAY_EFFECTS,
SPICE_OPT_CONTROLLER,
+#ifdef USE_SMARTCARD
+ SPICE_OPT_SMARTCARD,
+ SPICE_OPT_NOSMARTCARD,
+ SPICE_OPT_SMARTCARD_CERT,
+ SPICE_OPT_SMARTCARD_DB,
+#endif
};
#ifdef USE_GUI
@@ -2235,6 +2257,15 @@ bool Application::process_cmd_line(int argc, char** argv)
parser.add(SPICE_OPT_CONTROLLER, "controller", "enable external controller");
+#ifdef USE_SMARTCARD
+ parser.add(SPICE_OPT_SMARTCARD, "smartcard", "enable smartcard channel");
+ parser.add(SPICE_OPT_NOSMARTCARD, "nosmartcard", "disable smartcard channel");
+ parser.add(SPICE_OPT_SMARTCARD_CERT, "smartcard-cert", "Use virtual reader+card with given cert(s)",
+ "smartcard-cert", true);
+ parser.set_multi(SPICE_OPT_SMARTCARD_CERT, ',');
+ parser.add(SPICE_OPT_SMARTCARD_DB, "smartcard-db", "Use given db for smartcard certs");
+#endif
+
for (int i = SPICE_CHANNEL_MAIN; i < SPICE_END_CHANNEL; i++) {
_peer_con_opt[i] = RedPeer::ConnectionOptions::CON_OP_INVALID;
}
@@ -2340,6 +2371,20 @@ bool Application::process_cmd_line(int argc, char** argv)
}
_enable_controller = true;
return true;
+#ifdef USE_SMARTCARD
+ case SPICE_OPT_SMARTCARD:
+ _smartcard_options->enable= true;
+ break;
+ case SPICE_OPT_NOSMARTCARD:
+ _smartcard_options->enable= false; // default
+ break;
+ case SPICE_OPT_SMARTCARD_CERT:
+ do {
+ _smartcard_options->certs.insert(
+ _smartcard_options->certs.end(), std::string(val));
+ } while ((val=parser.next_argument()));
+ break;
+#endif
case CmdLineParser::OPTION_HELP:
parser.show_help();
return false;
diff --git a/client/application.h b/client/application.h
index 5a5a488..f9bbd53 100644
--- a/client/application.h
+++ b/client/application.h
@@ -29,6 +29,9 @@
#include "foreign_menu.h"
#include "controller.h"
+#ifdef USE_SMARTCARD
+struct SmartcardOptions;
+#endif
class RedScreen;
class Application;
class ScreenLayer;
@@ -268,6 +271,12 @@ public:
void message_box_test();
#endif
+#ifdef USE_SMARTCARD
+ const SmartcardOptions* get_smartcard_options() const {
+ return _smartcard_options;
+ }
+#endif
+
static int main(int argc, char** argv, const char* version_str);
private:
@@ -386,6 +395,9 @@ private:
bool _during_host_switch;
State _state;
+#ifdef USE_SMARTCARD
+ SmartcardOptions* _smartcard_options;
+#endif
};
#endif
diff --git a/client/smartcard_channel.cpp b/client/smartcard_channel.cpp
new file mode 100644
index 0000000..d585c9a
--- /dev/null
+++ b/client/smartcard_channel.cpp
@@ -0,0 +1,449 @@
+#include <spice/enums.h>
+
+#include "client/red_client.h"
+#include "mutex.h"
+
+extern "C" {
+#include "vscard_common.h"
+#include "vreader.h"
+#include "vcard_emul.h"
+#include "vevent.h"
+}
+
+#include "smartcard_channel.h"
+
+#define APDUBufSize 270
+
+#define MAX_ATR_LEN 40
+
+//#define DEBUG_SMARTCARD
+
+#ifdef DEBUG_SMARTCARD
+void PrintByteArray(uint8_t *arrBytes, unsigned int nSize)
+{
+ int i;
+
+ for (i=0; i < nSize; i++) {
+ DBG(0, "%X ", arrBytes[i]);
+ }
+ DBG(0, "\n");
+}
+#define DEBUG_PRINT_BYTE_ARRAY(arrBytes, nSize) PrintByteArray(arrBytes, nSize)
+#else
+#define DEBUG_PRINT_BYTE_ARRAY(arrBytes, nSize)
+#endif
+
+SmartCardChannel* g_smartcard_channel = NULL; // used for insert/remove of virtual card. Can be
+ // changed if we let Application store the SmartCard instance.
+
+class SmartCardHandler: public MessageHandlerImp<SmartCardChannel, SPICE_CHANNEL_SMARTCARD> {
+public:
+ SmartCardHandler(SmartCardChannel& channel)
+ : MessageHandlerImp<SmartCardChannel, SPICE_CHANNEL_SMARTCARD>(channel) {}
+};
+
+
+SmartCardChannel::SmartCardChannel(RedClient& client, uint32_t id)
+ : RedChannel(client, SPICE_CHANNEL_SMARTCARD, id, new SmartCardHandler(*this))
+{
+ SmartCardHandler* handler = static_cast<SmartCardHandler*>(get_message_handler());
+
+ g_smartcard_channel = this;
+ handler->set_handler(SPICE_MSG_SMARTCARD_DATA,
+ &SmartCardChannel::handle_smartcard_data);
+}
+
+ReaderData* SmartCardChannel::reader_data_from_vreader(VReader* vreader)
+{
+ if (vreader == NULL) {
+ assert(_readers_by_vreader.size() > 0);
+ return _readers_by_vreader.begin()->second;
+ }
+ if (_readers_by_vreader.count(vreader) > 0) {
+ return _readers_by_vreader.find(vreader)->second;
+ }
+ assert(_unallocated_readers_by_vreader.count(vreader) > 0);
+ return _unallocated_readers_by_vreader.find(vreader)->second;
+}
+
+ReaderData* SmartCardChannel::reader_data_from_reader_id(reader_id_t reader_id)
+{
+ if (_readers_by_id.count(reader_id) > 0) {
+ return _readers_by_id.find(reader_id)->second;
+ }
+ return NULL;
+}
+
+/** On VEVENT_READER_INSERT we call this, send a VSC_ReaderAdd, and wait for a VSC_ReaderAddResponse
+ */
+void SmartCardChannel::add_unallocated_reader(VReader* vreader, const char* name)
+{
+ ReaderData* data = new ReaderData();
+
+ data->vreader = vreader;
+ data->reader_id = VSCARD_UNDEFINED_READER_ID;
+ data->name = spice_strdup(name);
+ _unallocated_readers_by_vreader.insert(std::pair<VReader*, ReaderData*>(vreader, data));
+}
+
+/** called upon the VSC_ReaderAddResponse
+ */
+ReaderData* SmartCardChannel::add_reader(reader_id_t reader_id)
+{
+ ReaderData* data;
+ size_t unallocated = _unallocated_readers_by_vreader.size();
+
+ assert(unallocated > 0);
+ data = _unallocated_readers_by_vreader.begin()->second;
+ data->reader_id = reader_id;
+ _readers_by_vreader.insert(
+ std::pair<VReader*, ReaderData*>(data->vreader, data));
+ assert(_readers_by_vreader.count(data->vreader) == 1);
+ _readers_by_id.insert(std::pair<reader_id_t, ReaderData*>(reader_id, data));
+ assert(_readers_by_id.count(reader_id) == 1);
+ _unallocated_readers_by_vreader.erase(_unallocated_readers_by_vreader.begin());
+ assert(_unallocated_readers_by_vreader.size() == unallocated - 1);
+ assert(_unallocated_readers_by_vreader.count(data->vreader) == 0);
+ return data;
+}
+
+void* SmartCardChannel::cac_card_events_thread_entry(void* data)
+{
+ static_cast<SmartCardChannel*>(data)->cac_card_events_thread_main();
+ return NULL;
+}
+
+VEventEvent::VEventEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
+ : _smartcard_channel(smartcard_channel)
+ , _vreader(vevent->reader)
+ , _vevent(vevent)
+{
+}
+
+VEventEvent::~VEventEvent()
+{
+ vevent_delete(_vevent);
+}
+
+void ReaderAddEvent::response(AbstractProcessLoop& events_loop)
+{
+ static int num = 0;
+ char name[20];
+
+ sprintf(name, "test%4d", num++);
+ _smartcard_channel->add_unallocated_reader(_vreader, name);
+ _smartcard_channel->send_reader_added(name);
+}
+
+void ReaderRemoveEvent::response(AbstractProcessLoop& events_loop)
+{
+ ReaderData* data;
+
+ data = _smartcard_channel->reader_data_from_vreader(_vreader);
+ _smartcard_channel->send_reader_removed(data->reader_id);
+ _smartcard_channel->remove_reader(data);
+}
+
+void CardInsertEvent::response(AbstractProcessLoop& events_loop)
+{
+ ReaderData* data = _smartcard_channel->reader_data_from_vreader(
+ _vreader);
+
+ if (data->reader_id == VSCARD_UNDEFINED_READER_ID) {
+ data->card_insert_pending = true;
+ } else {
+ _smartcard_channel->send_atr(_vreader);
+ }
+}
+
+void CardRemoveEvent::response(AbstractProcessLoop& events_loop)
+{
+ ReaderData* data = _smartcard_channel->reader_data_from_vreader(
+ _vreader);
+
+ ASSERT(data->reader_id != VSCARD_UNDEFINED_READER_ID);
+ _smartcard_channel->send_message(data->reader_id, VSC_CardRemove, NULL, 0);
+}
+
+void SmartCardChannel::remove_reader(ReaderData* data)
+{
+ // TODO - untested code (caccard doesn't produce these events yet)
+ if (_readers_by_vreader.count(data->vreader) > 0) {
+ _readers_by_vreader.erase(_readers_by_vreader.find(data->vreader));
+ _readers_by_id.erase(_readers_by_id.find(data->reader_id));
+ } else {
+ _unallocated_readers_by_vreader.erase(
+ _unallocated_readers_by_vreader.find(data->vreader));
+ }
+ free(data->name);
+ delete data;
+}
+
+void SmartCardChannel::cac_card_events_thread_main()
+{
+ VEvent *vevent = NULL;
+ bool cont = true;
+
+ while (cont) {
+ vevent = vevent_wait_next_vevent();
+ if (vevent == NULL) {
+ break;
+ }
+ switch (vevent->type) {
+ case VEVENT_READER_INSERT:
+ LOG_INFO("VEVENT_READER_INSERT");
+ {
+ AutoRef<ReaderAddEvent> event(new ReaderAddEvent(this, vevent));
+ get_client().push_event(*event);
+ }
+ break;
+ case VEVENT_READER_REMOVE:
+ LOG_INFO("VEVENT_READER_REMOVE");
+ {
+ AutoRef<ReaderRemoveEvent> event(new ReaderRemoveEvent(this, vevent));
+ get_client().push_event(*event);
+ }
+ break;
+ case VEVENT_CARD_INSERT:
+ LOG_INFO("VEVENT_CARD_INSERT");
+ {
+ AutoRef<CardInsertEvent> event(new CardInsertEvent(this, vevent));
+ get_client().push_event(*event);
+ }
+ break;
+ case VEVENT_CARD_REMOVE:
+ LOG_INFO("VEVENT_CARD_REMOVE");
+ {
+ AutoRef<CardRemoveEvent> event(new CardRemoveEvent(this, vevent));
+ get_client().push_event(*event);
+ }
+ break;
+ case VEVENT_LAST:
+ cont = false;
+ default:
+ /* anything except VEVENT_LAST and default
+ * gets to VEventEvent which does vevent_delete in VEventEvent~ */
+ vevent_delete(vevent);
+ }
+ }
+}
+
+#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
+#define CERTIFICATES_ARGS_TEMPLATE "db=\"%s\" use_hw=no soft=(,Virtual Card,CAC,,%s,%s,%s)"
+
+SmartcardOptions::SmartcardOptions() :
+dbname(CERTIFICATES_DEFAULT_DB),
+enable(false)
+{
+}
+
+static VCardEmulError init_vcard_local_certs(const char* dbname, const char* cert1,
+ const char* cert2, const char* cert3)
+{
+ char emul_args[200];
+ VCardEmulOptions *options = NULL;
+
+ snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
+ dbname, cert1, cert2, cert3);
+ options = vcard_emul_options(emul_args);
+ if (options == NULL) {
+ LOG_WARN("not using certificates due to initialization error");
+ }
+ return vcard_emul_init(options);
+}
+
+static bool g_vcard_inited = false;
+
+void smartcard_init(const SmartcardOptions* options)
+{
+ if (g_vcard_inited) {
+ return;
+ }
+ if (options->certs.size() == 3) {
+ const char* dbname = options->dbname.c_str();
+ if (init_vcard_local_certs(dbname, options->certs[0].c_str(),
+ options->certs[1].c_str(), options->certs[2].c_str()) != VCARD_EMUL_OK) {
+ throw Exception("smartcard: emulated card initialization failed (check certs/db)");
+ }
+ } else {
+ if (options->certs.size() > 0) {
+ LOG_WARN("Ignoring smartcard certificates - must be exactly three for virtual card emulation");
+ }
+ if (vcard_emul_init(NULL) != VCARD_EMUL_OK) {
+ throw Exception("smartcard: vcard initialization failed (check hardware/drivers)");
+ }
+ }
+ g_vcard_inited = true;
+}
+
+void SmartCardChannel::on_connect()
+{
+ _event_thread = new Thread(SmartCardChannel::cac_card_events_thread_entry, this);
+}
+
+void SmartCardChannel::on_disconnect()
+{
+ VEvent *stop_event;
+
+ if (_event_thread == NULL) {
+ return;
+ }
+ stop_event = vevent_new(VEVENT_LAST, NULL, NULL);
+ vevent_queue_vevent(stop_event);
+ _event_thread->join();
+ delete _event_thread;
+ _event_thread = NULL;
+}
+
+
+void SmartCardChannel::send_reader_removed(reader_id_t reader_id)
+{
+ send_message(reader_id, VSC_ReaderRemove, NULL, 0);
+}
+
+void SmartCardChannel::send_reader_added(const char* reader_name)
+{
+ send_message(VSCARD_UNDEFINED_READER_ID,
+ VSC_ReaderAdd, (uint8_t*)reader_name, strlen(reader_name));
+}
+
+void SmartCardChannel::send_atr(VReader* vreader)
+{
+ unsigned char atr[ MAX_ATR_LEN];
+ int atr_len = MAX_ATR_LEN;
+ reader_id_t reader_id = reader_data_from_vreader(vreader)->reader_id;
+
+ assert(reader_id != VSCARD_UNDEFINED_READER_ID);
+ vreader_power_on(vreader, atr, &atr_len);
+ DBG(0, "ATR: ");
+ DEBUG_PRINT_BYTE_ARRAY(atr, atr_len);
+ send_message(reader_id, VSC_ATR, (uint8_t*)atr, atr_len);
+}
+
+void SmartCardChannel::send_message(uint32_t reader_id, VSCMsgType type, uint8_t* data, uint32_t len)
+{
+ VSCMsgHeader mhHeader;
+ Message* msg = new Message(SPICE_MSGC_SMARTCARD_DATA);
+ SpiceMarshaller* m = msg->marshaller();
+
+ mhHeader.type = type;
+ mhHeader.length = len;
+ mhHeader.reader_id = reader_id;
+ spice_marshaller_add(m, (uint8_t*)&mhHeader, sizeof(mhHeader));
+ spice_marshaller_add(m, data, len);
+ post_message(msg);
+}
+
+VSCMessageEvent::VSCMessageEvent(SmartCardChannel* smartcard_channel,
+ VSCMsgHeader* vheader)
+ : _smartcard_channel(smartcard_channel)
+ , _vheader(NULL)
+{
+ _vheader = (VSCMsgHeader*)spice_memdup(vheader,
+ sizeof(VSCMsgHeader) + vheader->length);
+ ASSERT(_vheader);
+}
+
+VSCMessageEvent::~VSCMessageEvent()
+{
+ free(_vheader);
+}
+
+void VSCMessageEvent::response(AbstractProcessLoop& loop)
+{
+ static int recv_count = 0;
+ int dwSendLength;
+ int dwRecvLength;
+ uint8_t* pbSendBuffer = _vheader->data;
+ uint8_t pbRecvBuffer[APDUBufSize+sizeof(uint32_t)];
+ VReaderStatus reader_status;
+ uint32_t rv;
+ ReaderData* data;
+
+ switch (_vheader->type) {
+ case (VSC_ReaderAddResponse):
+ data = _smartcard_channel->add_reader(_vheader->reader_id);
+ if (data->card_insert_pending) {
+ data->card_insert_pending = false;
+ _smartcard_channel->send_atr(data->vreader);
+ }
+ return;
+ break;
+ case VSC_APDU:
+ break;
+ case VSC_Error:
+ {
+ VSCMsgError *error = (VSCMsgError*)_vheader->data;
+ LOG_WARN("VSC Error: reader %d, code %d",
+ _vheader->reader_id, error->code);
+ }
+ return;
+ default:
+ LOG_WARN("unhandled VSC %d of length %d, reader %d",
+ _vheader->type, _vheader->length, _vheader->reader_id);
+ return;
+ }
+
+ /* Transmit recieved APDU */
+ dwSendLength = _vheader->length;
+ dwRecvLength = sizeof(pbRecvBuffer);
+
+ DBG(0, " %3d: recv APDU: ", recv_count++);
+ DEBUG_PRINT_BYTE_ARRAY(pbSendBuffer, _vheader->length);
+
+ ReaderData* reader_data = _smartcard_channel->reader_data_from_reader_id(
+ _vheader->reader_id);
+ if (reader_data == NULL) {
+ LOG_WARN("got message for non existant reader");
+ return;
+ }
+
+ VReader* vreader = reader_data->vreader;
+
+ reader_status = vreader_xfr_bytes(vreader,
+ pbSendBuffer, dwSendLength,
+ pbRecvBuffer, &dwRecvLength);
+ if (reader_status == VREADER_OK) {
+ DBG(0, " sent APDU: ");
+ DEBUG_PRINT_BYTE_ARRAY(pbRecvBuffer, dwRecvLength);
+ _smartcard_channel->send_message (
+ _vheader->reader_id,
+ VSC_APDU,
+ pbRecvBuffer,
+ dwRecvLength
+ );
+ } else {
+ rv = reader_status; /* warning: not meaningful */
+ _smartcard_channel->send_message (
+ _vheader->reader_id,
+ VSC_Error,
+ (uint8_t*)&rv,
+ sizeof (uint32_t)
+ );
+ }
+}
+
+void SmartCardChannel::handle_smartcard_data(RedPeer::InMessage* message)
+{
+ VSCMsgHeader* mhHeader = (VSCMsgHeader*)(message->data());
+
+ AutoRef<VSCMessageEvent> event(new VSCMessageEvent(this, mhHeader));
+ get_client().push_event(*event);
+}
+
+class SmartCardFactory: public ChannelFactory {
+public:
+ SmartCardFactory() : ChannelFactory(SPICE_CHANNEL_SMARTCARD) {}
+ virtual RedChannel* construct(RedClient& client, uint32_t id)
+ {
+ return new SmartCardChannel(client, id);
+ }
+};
+
+static SmartCardFactory factory;
+
+ChannelFactory& SmartCardChannel::Factory()
+{
+ return factory;
+}
+
diff --git a/client/smartcard_channel.h b/client/smartcard_channel.h
new file mode 100644
index 0000000..ee0d0d0
--- /dev/null
+++ b/client/smartcard_channel.h
@@ -0,0 +1,133 @@
+#ifndef __SMART_CARD_H__
+#define __SMART_CARD_H__
+
+#include <map>
+
+#include <vreadert.h>
+#include <vscard_common.h>
+#include <eventt.h>
+
+#include "red_channel.h"
+#include "red_peer.h"
+
+class Application;
+
+struct SmartcardOptions {
+ std::vector<std::string> certs;
+ std::string dbname;
+ bool enable;
+ SmartcardOptions();
+};
+
+void smartcard_init(const SmartcardOptions* options);
+
+struct ReaderData {
+ ReaderData() :
+ vreader(NULL),
+ reader_id(VSCARD_UNDEFINED_READER_ID),
+ name(NULL),
+ card_insert_pending(false)
+ {}
+ VReader *vreader;
+ reader_id_t reader_id;
+ char* name;
+ bool card_insert_pending;
+};
+
+void virtual_card_remove();
+void virtual_card_insert();
+
+class SmartCardChannel;
+
+class VEventEvent : public Event {
+public:
+ VEventEvent(SmartCardChannel* smartcard_channel, VEvent* vevent);
+ ~VEventEvent();
+ SmartCardChannel* _smartcard_channel;
+ VReader* _vreader;
+ VEvent* _vevent;
+};
+
+class ReaderAddEvent: public VEventEvent {
+public:
+ ReaderAddEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
+ : VEventEvent(smartcard_channel, vevent) {}
+ virtual void response(AbstractProcessLoop& events_loop);
+};
+
+class ReaderRemoveEvent: public VEventEvent {
+public:
+ ReaderRemoveEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
+ : VEventEvent(smartcard_channel, vevent) {}
+ virtual void response(AbstractProcessLoop& events_loop);
+};
+
+class CardInsertEvent: public VEventEvent {
+public:
+ CardInsertEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
+ : VEventEvent(smartcard_channel, vevent) {}
+ virtual void response(AbstractProcessLoop& events_loop);
+};
+
+class CardRemoveEvent: public VEventEvent {
+public:
+ CardRemoveEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
+ : VEventEvent(smartcard_channel, vevent) {}
+ virtual void response(AbstractProcessLoop& events_loop);
+};
+
+class VSCMessageEvent: public Event {
+public:
+ VSCMessageEvent(SmartCardChannel* smartcard_channel,
+ VSCMsgHeader* vheader);
+ ~VSCMessageEvent();
+ SmartCardChannel* _smartcard_channel;
+ VSCMsgHeader* _vheader;
+ virtual void response(AbstractProcessLoop& events_loop);
+};
+
+class SmartCardChannel : public RedChannel {
+
+public:
+ SmartCardChannel(RedClient& client, uint32_t id);
+ void handle_smartcard_data(RedPeer::InMessage* message);
+
+ static ChannelFactory& Factory();
+protected:
+ virtual void on_connect();
+ virtual void on_disconnect();
+
+private:
+ static void* cac_card_events_thread_entry(void* data);
+ void cac_card_events_thread_main();
+ void send_message(reader_id_t reader_id, VSCMsgType type, uint8_t* data, uint32_t len);
+
+ Thread* _event_thread;
+
+ Application* _app;
+
+ VReaderList *_reader_list;
+ typedef std::map<reader_id_t, ReaderData*> readers_by_id_t;
+ readers_by_id_t _readers_by_id;
+ typedef std::map<VReader*, ReaderData*> readers_by_vreader_t;
+ readers_by_vreader_t _readers_by_vreader;
+ readers_by_vreader_t _unallocated_readers_by_vreader;
+
+ ReaderData* reader_data_from_vreader(VReader* vreader);
+ ReaderData* reader_data_from_reader_id(reader_id_t reader_id);
+ void add_unallocated_reader(VReader* vreader, const char* name);
+ ReaderData* add_reader(reader_id_t reader_id);
+ void remove_reader(ReaderData* data);
+ void send_reader_added(const char* reader_name);
+ void send_reader_removed(reader_id_t reader_id);
+ void send_atr(VReader* vreader);
+
+ friend class ReaderAddEvent;
+ friend class ReaderRemoveEvent;
+ friend class CardInsertEvent;
+ friend class CardRemoveEvent;
+ friend class VSCMessageEvent;
+};
+
+#endif // __SMART_CARD_H__
+
commit 611e542c6c2b6f9aa0dea90f4f5949d1e52fd543
Author: Alon Levy <alevy at redhat.com>
Date: Mon Sep 13 20:02:42 2010 +0200
smartcard: add to spice.proto
diff --git a/spice.proto b/spice.proto
index 3c0911d..4eeb159 100644
--- a/spice.proto
+++ b/spice.proto
@@ -1084,6 +1084,13 @@ channel TunnelChannel : BaseChannel {
} @ctype(SpiceMsgcTunnelSocketTokens) socket_token;
};
+channel SmartcardChannel : BaseChannel {
+server:
+ Data data = 101;
+client:
+ Data data = 101;
+};
+
protocol Spice {
MainChannel main = 1;
DisplayChannel display;
@@ -1092,4 +1099,5 @@ protocol Spice {
PlaybackChannel playback;
RecordChannel record;
TunnelChannel tunnel;
+ SmartcardChannel smartcard;
};
commit 7461ee17cf4e59c30d3c7d83c1bb7b029c6cfb9b
Author: Alon Levy <alevy at redhat.com>
Date: Wed Sep 15 10:06:58 2010 +0200
server: add spice_server_char_device_remove_interface
diff --git a/server/reds.c b/server/reds.c
index d71ecb1..3edf474 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -3463,6 +3463,19 @@ static int spice_server_char_device_add_interface(SpiceServer *s,
return 0;
}
+static void spice_server_char_device_remove_interface(SpiceBaseInstance *sin)
+{
+ SpiceCharDeviceInstance* char_device =
+ SPICE_CONTAINEROF(sin, SpiceCharDeviceInstance, base);
+
+ red_printf("remove CHAR_DEVICE %s", char_device->subtype);
+ if (strcmp(char_device->subtype, SUBTYPE_VDAGENT) == 0) {
+ if (vdagent) {
+ reds_agent_remove();
+ }
+ }
+}
+
__visible__ int spice_server_add_interface(SpiceServer *s,
SpiceBaseInstance *sin)
{
@@ -3605,11 +3618,7 @@ __visible__ int spice_server_remove_interface(SpiceBaseInstance *sin)
snd_detach_record(SPICE_CONTAINEROF(sin, SpiceRecordInstance, base));
} else if (strcmp(interface->type, SPICE_INTERFACE_CHAR_DEVICE) == 0) {
- red_printf("remove SPICE_INTERFACE_CHAR_DEVICE");
- if (vdagent && sin == &vdagent->base) {
- reds_agent_remove();
- }
-
+ spice_server_char_device_remove_interface(sin);
} else {
red_error("VD_INTERFACE_REMOVING unsupported");
return -1;
commit 5220e0a7062a5fa5dadd386b9d3a0794a4844b17
Author: Alon Levy <alevy at redhat.com>
Date: Wed Sep 15 10:06:18 2010 +0200
server: print subtype when adding CHAR_DEVICE interfaces
diff --git a/server/reds.c b/server/reds.c
index eee8f35..d71ecb1 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -3451,6 +3451,7 @@ static int spice_server_char_device_add_interface(SpiceServer *s,
SpiceCharDeviceInterface* sif;
sif = SPICE_CONTAINEROF(char_device->base.sif, SpiceCharDeviceInterface, base);
+ red_printf("CHAR_DEVICE %s", char_device->subtype);
if (strcmp(char_device->subtype, SUBTYPE_VDAGENT) == 0) {
if (vdagent) {
red_printf("vdagent already attached");
@@ -3552,7 +3553,6 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
snd_attach_record(SPICE_CONTAINEROF(sin, SpiceRecordInstance, base));
} else if (strcmp(interface->type, SPICE_INTERFACE_CHAR_DEVICE) == 0) {
- red_printf("SPICE_INTERFACE_CHAR_DEVICE");
if (interface->major_version != SPICE_INTERFACE_CHAR_DEVICE_MAJOR ||
interface->minor_version < SPICE_INTERFACE_CHAR_DEVICE_MINOR) {
red_printf("unsupported char device interface");
commit 0ac9ca51f4cecce8d1146c23c3032f3dcda6954b
Author: Alon Levy <alevy at redhat.com>
Date: Wed Sep 15 10:05:32 2010 +0200
server: add static to spice_server_char_device_add_interface
diff --git a/server/reds.c b/server/reds.c
index aff8b6f..eee8f35 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -3443,7 +3443,7 @@ __visible__ const char** spice_server_char_device_recognized_subtypes()
return spice_server_char_device_recognized_subtypes_list;
}
-int spice_server_char_device_add_interface(SpiceServer *s,
+static int spice_server_char_device_add_interface(SpiceServer *s,
SpiceBaseInstance *sin)
{
SpiceCharDeviceInstance* char_device =
commit beca39aa87e5644c6d8210860037cb2220256b7a
Author: Alon Levy <alevy at redhat.com>
Date: Mon Oct 4 22:02:41 2010 +0200
spice codegen: fix copy-o, no such variable value
diff --git a/python_modules/ptypes.py b/python_modules/ptypes.py
index 0ae57ec..9c4b7de 100644
--- a/python_modules/ptypes.py
+++ b/python_modules/ptypes.py
@@ -240,7 +240,7 @@ class EnumBaseType(Type):
def c_enumname_by_name(self, name):
if self.has_attr("prefix"):
- return self.attributes["prefix"][0] + self.names[value]
+ return self.attributes["prefix"][0] + name
return codegen.prefix_underscore_upper(self.name.upper(), name)
def is_primitive(self):
commit b2f1b80a634cdda2a86d48ee7b823d287371f3fe
Author: Alon Levy <alevy at redhat.com>
Date: Sun Aug 29 17:21:28 2010 +0300
server: fix print text on vdagent interface addition
diff --git a/server/reds.c b/server/reds.c
index ca6522d..aff8b6f 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -3453,7 +3453,7 @@ int spice_server_char_device_add_interface(SpiceServer *s,
sif = SPICE_CONTAINEROF(char_device->base.sif, SpiceCharDeviceInterface, base);
if (strcmp(char_device->subtype, SUBTYPE_VDAGENT) == 0) {
if (vdagent) {
- red_printf("vdi port already attached");
+ red_printf("vdagent already attached");
return -1;
}
char_device->st = &vdagent_char_device_state;
commit 673ade8a6fdfd9b9160f1ddc838f4ddcc80502ec
Author: Alon Levy <alevy at redhat.com>
Date: Tue Aug 31 12:42:30 2010 +0300
server: add char_device.h header, use in reds.c
diff --git a/server/char_device.h b/server/char_device.h
new file mode 100644
index 0000000..486df6f
--- /dev/null
+++ b/server/char_device.h
@@ -0,0 +1,11 @@
+#ifndef __CHAR_DEVICE_H__
+#define __CHAR_DEVICE_H__
+
+#include "server/spice-experimental.h"
+
+struct SpiceCharDeviceState {
+ void (*wakeup)(SpiceCharDeviceInstance *sin);
+};
+
+#endif // __CHAR_DEVICE_H__
+
diff --git a/server/reds.c b/server/reds.c
index c7181ee..ca6522d 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -55,6 +55,7 @@
#include "demarshallers.h"
#include "marshaller.h"
#include "generated_marshallers.h"
+#include "server/char_device.h"
#ifdef USE_TUNNEL
#include "red_tunnel_worker.h"
#endif
@@ -174,10 +175,6 @@ enum {
VDI_PORT_READ_STATE_READ_DATA,
};
-struct SpiceCharDeviceState {
- void (*wakeup)(SpiceCharDeviceInstance *sin);
-};
-
void vdagent_char_device_wakeup(SpiceCharDeviceInstance *sin);
struct SpiceCharDeviceState vdagent_char_device_state = {
.wakeup = &vdagent_char_device_wakeup,
commit 14f2b0f52a48b987f5ae5bde06820081ad50af3d
Author: Alon Levy <alevy at redhat.com>
Date: Sun Aug 29 17:16:26 2010 +0300
spice-experimental.h: add multiple include protection
diff --git a/server/spice-experimental.h b/server/spice-experimental.h
index 7c1fdf2..526062f 100644
--- a/server/spice-experimental.h
+++ b/server/spice-experimental.h
@@ -1,5 +1,9 @@
-/* char device interfaces */
+#ifndef __SPICE_EXPERIMENTAL_H__
+#define __SPICE_EXPERIMENTAL_H__
+
+#include "spice.h"
+/* char device interfaces */
#define SPICE_INTERFACE_CHAR_DEVICE "char_device"
#define SPICE_INTERFACE_CHAR_DEVICE_MAJOR 1
#define SPICE_INTERFACE_CHAR_DEVICE_MINOR 1
@@ -63,3 +67,5 @@ int spice_server_migrate_start(SpiceServer *s);
int spice_server_migrate_client_state(SpiceServer *s);
int spice_server_migrate_end(SpiceServer *s, int completed);
+#endif // __SPICE_EXPERIMENTAL_H__
+
More information about the Spice-commits
mailing list