diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2013-03-01 13:59:19 +0100 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2013-04-08 18:13:12 +0200 |
commit | 49ab747f668f421138d5b40d83fa279c4c5e278d (patch) | |
tree | 943225a04eac885aed038731adf058f2250a2f40 /hw/ccid-card-emulated.c | |
parent | ce3b494cb504f96992f2d37ebc8f56deed202b06 (diff) |
hw: move target-independent files to subdirectories
This patch tackles all files that are compiled once, moving
them to subdirectories of hw/.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw/ccid-card-emulated.c')
-rw-r--r-- | hw/ccid-card-emulated.c | 602 |
1 files changed, 0 insertions, 602 deletions
diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c deleted file mode 100644 index c8f8ba3792..0000000000 --- a/hw/ccid-card-emulated.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - * CCID Card Device. Emulated card. - * - * Copyright (c) 2011 Red Hat. - * Written by Alon Levy. - * - * This code is licensed under the GNU LGPL, version 2 or later. - */ - -/* - * It can be used to provide access to the local hardware in a non exclusive - * way, or it can use certificates. It requires the usb-ccid bus. - * - * Usage 1: standard, mirror hardware reader+card: - * qemu .. -usb -device usb-ccid -device ccid-card-emulated - * - * Usage 2: use certificates, no hardware required - * one time: create the certificates: - * for i in 1 2 3; do - * certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=user$i" -n user$i - * done - * qemu .. -usb -device usb-ccid \ - * -device ccid-card-emulated,cert1=user1,cert2=user2,cert3=user3 - * - * If you use a non default db for the certificates you can specify it using - * the db parameter. - */ - -#include <eventt.h> -#include <vevent.h> -#include <vreader.h> -#include <vcard_emul.h> - -#include "qemu/thread.h" -#include "char/char.h" -#include "monitor/monitor.h" -#include "hw/ccid.h" - -#define DPRINTF(card, lvl, fmt, ...) \ -do {\ - if (lvl <= card->debug) {\ - printf("ccid-card-emul: %s: " fmt , __func__, ## __VA_ARGS__);\ - } \ -} while (0) - -#define EMULATED_DEV_NAME "ccid-card-emulated" - -#define BACKEND_NSS_EMULATED_NAME "nss-emulated" -#define BACKEND_CERTIFICATES_NAME "certificates" - -enum { - BACKEND_NSS_EMULATED = 1, - BACKEND_CERTIFICATES -}; - -#define DEFAULT_BACKEND BACKEND_NSS_EMULATED - -typedef struct EmulatedState EmulatedState; - -enum { - EMUL_READER_INSERT = 0, - EMUL_READER_REMOVE, - EMUL_CARD_INSERT, - EMUL_CARD_REMOVE, - EMUL_GUEST_APDU, - EMUL_RESPONSE_APDU, - EMUL_ERROR, -}; - -static const char *emul_event_to_string(uint32_t emul_event) -{ - switch (emul_event) { - case EMUL_READER_INSERT: - return "EMUL_READER_INSERT"; - case EMUL_READER_REMOVE: - return "EMUL_READER_REMOVE"; - case EMUL_CARD_INSERT: - return "EMUL_CARD_INSERT"; - case EMUL_CARD_REMOVE: - return "EMUL_CARD_REMOVE"; - case EMUL_GUEST_APDU: - return "EMUL_GUEST_APDU"; - case EMUL_RESPONSE_APDU: - return "EMUL_RESPONSE_APDU"; - case EMUL_ERROR: - return "EMUL_ERROR"; - } - return "UNKNOWN"; -} - -typedef struct EmulEvent { - QSIMPLEQ_ENTRY(EmulEvent) entry; - union { - struct { - uint32_t type; - } gen; - struct { - uint32_t type; - uint64_t code; - } error; - struct { - uint32_t type; - uint32_t len; - uint8_t data[]; - } data; - } p; -} EmulEvent; - -#define MAX_ATR_SIZE 40 -struct EmulatedState { - CCIDCardState base; - uint8_t debug; - char *backend_str; - uint32_t backend; - char *cert1; - char *cert2; - char *cert3; - char *db; - uint8_t atr[MAX_ATR_SIZE]; - uint8_t atr_length; - QSIMPLEQ_HEAD(event_list, EmulEvent) event_list; - QemuMutex event_list_mutex; - QemuThread event_thread_id; - VReader *reader; - QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list; - QemuMutex vreader_mutex; /* and guest_apdu_list mutex */ - QemuMutex handle_apdu_mutex; - QemuCond handle_apdu_cond; - int pipe[2]; - int quit_apdu_thread; - QemuThread apdu_thread_id; -}; - -static void emulated_apdu_from_guest(CCIDCardState *base, - const uint8_t *apdu, uint32_t len) -{ - EmulatedState *card = DO_UPCAST(EmulatedState, base, base); - EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len); - - assert(event); - event->p.data.type = EMUL_GUEST_APDU; - event->p.data.len = len; - memcpy(event->p.data.data, apdu, len); - qemu_mutex_lock(&card->vreader_mutex); - QSIMPLEQ_INSERT_TAIL(&card->guest_apdu_list, event, entry); - qemu_mutex_unlock(&card->vreader_mutex); - qemu_mutex_lock(&card->handle_apdu_mutex); - qemu_cond_signal(&card->handle_apdu_cond); - qemu_mutex_unlock(&card->handle_apdu_mutex); -} - -static const uint8_t *emulated_get_atr(CCIDCardState *base, uint32_t *len) -{ - EmulatedState *card = DO_UPCAST(EmulatedState, base, base); - - *len = card->atr_length; - return card->atr; -} - -static void emulated_push_event(EmulatedState *card, EmulEvent *event) -{ - qemu_mutex_lock(&card->event_list_mutex); - QSIMPLEQ_INSERT_TAIL(&(card->event_list), event, entry); - qemu_mutex_unlock(&card->event_list_mutex); - if (write(card->pipe[1], card, 1) != 1) { - DPRINTF(card, 1, "write to pipe failed\n"); - } -} - -static void emulated_push_type(EmulatedState *card, uint32_t type) -{ - EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent)); - - assert(event); - event->p.gen.type = type; - emulated_push_event(card, event); -} - -static void emulated_push_error(EmulatedState *card, uint64_t code) -{ - EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent)); - - assert(event); - event->p.error.type = EMUL_ERROR; - event->p.error.code = code; - emulated_push_event(card, event); -} - -static void emulated_push_data_type(EmulatedState *card, uint32_t type, - const uint8_t *data, uint32_t len) -{ - EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len); - - assert(event); - event->p.data.type = type; - event->p.data.len = len; - memcpy(event->p.data.data, data, len); - emulated_push_event(card, event); -} - -static void emulated_push_reader_insert(EmulatedState *card) -{ - emulated_push_type(card, EMUL_READER_INSERT); -} - -static void emulated_push_reader_remove(EmulatedState *card) -{ - emulated_push_type(card, EMUL_READER_REMOVE); -} - -static void emulated_push_card_insert(EmulatedState *card, - const uint8_t *atr, uint32_t len) -{ - emulated_push_data_type(card, EMUL_CARD_INSERT, atr, len); -} - -static void emulated_push_card_remove(EmulatedState *card) -{ - emulated_push_type(card, EMUL_CARD_REMOVE); -} - -static void emulated_push_response_apdu(EmulatedState *card, - const uint8_t *apdu, uint32_t len) -{ - emulated_push_data_type(card, EMUL_RESPONSE_APDU, apdu, len); -} - -#define APDU_BUF_SIZE 270 -static void *handle_apdu_thread(void* arg) -{ - EmulatedState *card = arg; - uint8_t recv_data[APDU_BUF_SIZE]; - int recv_len; - VReaderStatus reader_status; - EmulEvent *event; - - while (1) { - qemu_mutex_lock(&card->handle_apdu_mutex); - qemu_cond_wait(&card->handle_apdu_cond, &card->handle_apdu_mutex); - qemu_mutex_unlock(&card->handle_apdu_mutex); - if (card->quit_apdu_thread) { - card->quit_apdu_thread = 0; /* debugging */ - break; - } - qemu_mutex_lock(&card->vreader_mutex); - while (!QSIMPLEQ_EMPTY(&card->guest_apdu_list)) { - event = QSIMPLEQ_FIRST(&card->guest_apdu_list); - assert((unsigned long)event > 1000); - QSIMPLEQ_REMOVE_HEAD(&card->guest_apdu_list, entry); - if (event->p.data.type != EMUL_GUEST_APDU) { - DPRINTF(card, 1, "unexpected message in handle_apdu_thread\n"); - g_free(event); - continue; - } - if (card->reader == NULL) { - DPRINTF(card, 1, "reader is NULL\n"); - g_free(event); - continue; - } - recv_len = sizeof(recv_data); - reader_status = vreader_xfr_bytes(card->reader, - event->p.data.data, event->p.data.len, - recv_data, &recv_len); - DPRINTF(card, 2, "got back apdu of length %d\n", recv_len); - if (reader_status == VREADER_OK) { - emulated_push_response_apdu(card, recv_data, recv_len); - } else { - emulated_push_error(card, reader_status); - } - g_free(event); - } - qemu_mutex_unlock(&card->vreader_mutex); - } - return NULL; -} - -static void *event_thread(void *arg) -{ - int atr_len = MAX_ATR_SIZE; - uint8_t atr[MAX_ATR_SIZE]; - VEvent *event = NULL; - EmulatedState *card = arg; - - while (1) { - const char *reader_name; - - event = vevent_wait_next_vevent(); - if (event == NULL || event->type == VEVENT_LAST) { - break; - } - if (event->type != VEVENT_READER_INSERT) { - if (card->reader == NULL && event->reader != NULL) { - /* Happens after device_add followed by card remove or insert. - * XXX: create synthetic add_reader events if vcard_emul_init - * already called, which happens if device_del and device_add - * are called */ - card->reader = vreader_reference(event->reader); - } else { - if (event->reader != card->reader) { - fprintf(stderr, - "ERROR: wrong reader: quiting event_thread\n"); - break; - } - } - } - switch (event->type) { - case VEVENT_READER_INSERT: - /* TODO: take a specific reader. i.e. track which reader - * we are seeing here, check it is the one we want (the first, - * or by a particular name), and ignore if we don't want it. - */ - reader_name = vreader_get_name(event->reader); - if (card->reader != NULL) { - DPRINTF(card, 2, "READER INSERT - replacing %s with %s\n", - vreader_get_name(card->reader), reader_name); - qemu_mutex_lock(&card->vreader_mutex); - vreader_free(card->reader); - qemu_mutex_unlock(&card->vreader_mutex); - emulated_push_reader_remove(card); - } - qemu_mutex_lock(&card->vreader_mutex); - DPRINTF(card, 2, "READER INSERT %s\n", reader_name); - card->reader = vreader_reference(event->reader); - qemu_mutex_unlock(&card->vreader_mutex); - emulated_push_reader_insert(card); - break; - case VEVENT_READER_REMOVE: - DPRINTF(card, 2, " READER REMOVE: %s\n", - vreader_get_name(event->reader)); - qemu_mutex_lock(&card->vreader_mutex); - vreader_free(card->reader); - card->reader = NULL; - qemu_mutex_unlock(&card->vreader_mutex); - emulated_push_reader_remove(card); - break; - case VEVENT_CARD_INSERT: - /* get the ATR (intended as a response to a power on from the - * reader */ - atr_len = MAX_ATR_SIZE; - vreader_power_on(event->reader, atr, &atr_len); - card->atr_length = (uint8_t)atr_len; - DPRINTF(card, 2, " CARD INSERT\n"); - emulated_push_card_insert(card, atr, atr_len); - break; - case VEVENT_CARD_REMOVE: - DPRINTF(card, 2, " CARD REMOVE\n"); - emulated_push_card_remove(card); - break; - case VEVENT_LAST: /* quit */ - vevent_delete(event); - return NULL; - break; - default: - break; - } - vevent_delete(event); - } - return NULL; -} - -static void pipe_read(void *opaque) -{ - EmulatedState *card = opaque; - EmulEvent *event, *next; - char dummy; - int len; - - do { - len = read(card->pipe[0], &dummy, sizeof(dummy)); - } while (len == sizeof(dummy)); - qemu_mutex_lock(&card->event_list_mutex); - QSIMPLEQ_FOREACH_SAFE(event, &card->event_list, entry, next) { - DPRINTF(card, 2, "event %s\n", emul_event_to_string(event->p.gen.type)); - switch (event->p.gen.type) { - case EMUL_RESPONSE_APDU: - ccid_card_send_apdu_to_guest(&card->base, event->p.data.data, - event->p.data.len); - break; - case EMUL_READER_INSERT: - ccid_card_ccid_attach(&card->base); - break; - case EMUL_READER_REMOVE: - ccid_card_ccid_detach(&card->base); - break; - case EMUL_CARD_INSERT: - assert(event->p.data.len <= MAX_ATR_SIZE); - card->atr_length = event->p.data.len; - memcpy(card->atr, event->p.data.data, card->atr_length); - ccid_card_card_inserted(&card->base); - break; - case EMUL_CARD_REMOVE: - ccid_card_card_removed(&card->base); - break; - case EMUL_ERROR: - ccid_card_card_error(&card->base, event->p.error.code); - break; - default: - DPRINTF(card, 2, "unexpected event\n"); - break; - } - g_free(event); - } - QSIMPLEQ_INIT(&card->event_list); - qemu_mutex_unlock(&card->event_list_mutex); -} - -static int init_pipe_signaling(EmulatedState *card) -{ - if (pipe(card->pipe) < 0) { - DPRINTF(card, 2, "pipe creation failed\n"); - return -1; - } - fcntl(card->pipe[0], F_SETFL, O_NONBLOCK); - fcntl(card->pipe[1], F_SETFL, O_NONBLOCK); - fcntl(card->pipe[0], F_SETOWN, getpid()); - qemu_set_fd_handler(card->pipe[0], pipe_read, NULL, card); - return 0; -} - -#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb" -#define CERTIFICATES_ARGS_TEMPLATE\ - "db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)" - -static int wrap_vcard_emul_init(VCardEmulOptions *options) -{ - static int called; - static int options_was_null; - - if (called) { - if ((options == NULL) != options_was_null) { - printf("%s: warning: running emulated with certificates" - " and emulated side by side is not supported\n", - __func__); - return VCARD_EMUL_FAIL; - } - vcard_emul_replay_insertion_events(); - return VCARD_EMUL_OK; - } - options_was_null = (options == NULL); - called = 1; - return vcard_emul_init(options); -} - -static int emulated_initialize_vcard_from_certificates(EmulatedState *card) -{ - char emul_args[200]; - VCardEmulOptions *options = NULL; - - snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE, - card->db ? card->db : CERTIFICATES_DEFAULT_DB, - card->cert1, card->cert2, card->cert3); - options = vcard_emul_options(emul_args); - if (options == NULL) { - printf("%s: warning: not using certificates due to" - " initialization error\n", __func__); - } - return wrap_vcard_emul_init(options); -} - -typedef struct EnumTable { - const char *name; - uint32_t value; -} EnumTable; - -EnumTable backend_enum_table[] = { - {BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED}, - {BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES}, - {NULL, 0}, -}; - -static uint32_t parse_enumeration(char *str, - EnumTable *table, uint32_t not_found_value) -{ - uint32_t ret = not_found_value; - - while (table->name != NULL) { - if (strcmp(table->name, str) == 0) { - ret = table->value; - break; - } - table++; - } - return ret; -} - -static int emulated_initfn(CCIDCardState *base) -{ - EmulatedState *card = DO_UPCAST(EmulatedState, base, base); - VCardEmulError ret; - EnumTable *ptable; - - QSIMPLEQ_INIT(&card->event_list); - QSIMPLEQ_INIT(&card->guest_apdu_list); - qemu_mutex_init(&card->event_list_mutex); - qemu_mutex_init(&card->vreader_mutex); - qemu_mutex_init(&card->handle_apdu_mutex); - qemu_cond_init(&card->handle_apdu_cond); - card->reader = NULL; - card->quit_apdu_thread = 0; - if (init_pipe_signaling(card) < 0) { - return -1; - } - card->backend = parse_enumeration(card->backend_str, backend_enum_table, 0); - if (card->backend == 0) { - printf("unknown backend, must be one of:\n"); - for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) { - printf("%s\n", ptable->name); - } - return -1; - } - - /* TODO: a passthru backened that works on local machine. third card type?*/ - if (card->backend == BACKEND_CERTIFICATES) { - if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) { - ret = emulated_initialize_vcard_from_certificates(card); - } else { - printf("%s: you must provide all three certs for" - " certificates backend\n", EMULATED_DEV_NAME); - return -1; - } - } else { - if (card->backend != BACKEND_NSS_EMULATED) { - printf("%s: bad backend specified. The options are:\n%s (default)," - " %s.\n", EMULATED_DEV_NAME, BACKEND_NSS_EMULATED_NAME, - BACKEND_CERTIFICATES_NAME); - return -1; - } - if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) { - printf("%s: unexpected cert parameters to nss emulated backend\n", - EMULATED_DEV_NAME); - return -1; - } - /* default to mirroring the local hardware readers */ - ret = wrap_vcard_emul_init(NULL); - } - if (ret != VCARD_EMUL_OK) { - printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME); - return -1; - } - qemu_thread_create(&card->event_thread_id, event_thread, card, - QEMU_THREAD_JOINABLE); - qemu_thread_create(&card->apdu_thread_id, handle_apdu_thread, card, - QEMU_THREAD_JOINABLE); - return 0; -} - -static int emulated_exitfn(CCIDCardState *base) -{ - EmulatedState *card = DO_UPCAST(EmulatedState, base, base); - VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL); - - vevent_queue_vevent(vevent); /* stop vevent thread */ - qemu_thread_join(&card->event_thread_id); - - card->quit_apdu_thread = 1; /* stop handle_apdu thread */ - qemu_cond_signal(&card->handle_apdu_cond); - qemu_thread_join(&card->apdu_thread_id); - - /* threads exited, can destroy all condvars/mutexes */ - qemu_cond_destroy(&card->handle_apdu_cond); - qemu_mutex_destroy(&card->handle_apdu_mutex); - qemu_mutex_destroy(&card->vreader_mutex); - qemu_mutex_destroy(&card->event_list_mutex); - return 0; -} - -static Property emulated_card_properties[] = { - DEFINE_PROP_STRING("backend", EmulatedState, backend_str), - DEFINE_PROP_STRING("cert1", EmulatedState, cert1), - DEFINE_PROP_STRING("cert2", EmulatedState, cert2), - DEFINE_PROP_STRING("cert3", EmulatedState, cert3), - DEFINE_PROP_STRING("db", EmulatedState, db), - DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void emulated_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - CCIDCardClass *cc = CCID_CARD_CLASS(klass); - - cc->initfn = emulated_initfn; - cc->exitfn = emulated_exitfn; - cc->get_atr = emulated_get_atr; - cc->apdu_from_guest = emulated_apdu_from_guest; - dc->desc = "emulated smartcard"; - dc->props = emulated_card_properties; -} - -static const TypeInfo emulated_card_info = { - .name = EMULATED_DEV_NAME, - .parent = TYPE_CCID_CARD, - .instance_size = sizeof(EmulatedState), - .class_init = emulated_class_initfn, -}; - -static void ccid_card_emulated_register_types(void) -{ - type_register_static(&emulated_card_info); -} - -type_init(ccid_card_emulated_register_types) |