Annotation of qemu/hw/ccid-card-emulated.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * CCID Card Device. Emulated card.
        !             3:  *
        !             4:  * Copyright (c) 2011 Red Hat.
        !             5:  * Written by Alon Levy.
        !             6:  *
        !             7:  * This code is licensed under the GNU LGPL, version 2 or later.
        !             8:  */
        !             9: 
        !            10: /*
        !            11:  * It can be used to provide access to the local hardware in a non exclusive
        !            12:  * way, or it can use certificates. It requires the usb-ccid bus.
        !            13:  *
        !            14:  * Usage 1: standard, mirror hardware reader+card:
        !            15:  * qemu .. -usb -device usb-ccid -device ccid-card-emulated
        !            16:  *
        !            17:  * Usage 2: use certificates, no hardware required
        !            18:  * one time: create the certificates:
        !            19:  *  for i in 1 2 3; do
        !            20:  *      certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=user$i" -n user$i
        !            21:  *  done
        !            22:  * qemu .. -usb -device usb-ccid \
        !            23:  *  -device ccid-card-emulated,cert1=user1,cert2=user2,cert3=user3
        !            24:  *
        !            25:  * If you use a non default db for the certificates you can specify it using
        !            26:  * the db parameter.
        !            27:  */
        !            28: 
        !            29: #include <eventt.h>
        !            30: #include <vevent.h>
        !            31: #include <vreader.h>
        !            32: #include <vcard_emul.h>
        !            33: 
        !            34: #include "qemu-thread.h"
        !            35: #include "qemu-char.h"
        !            36: #include "monitor.h"
        !            37: #include "hw/ccid.h"
        !            38: 
        !            39: #define DPRINTF(card, lvl, fmt, ...) \
        !            40: do {\
        !            41:     if (lvl <= card->debug) {\
        !            42:         printf("ccid-card-emul: %s: " fmt , __func__, ## __VA_ARGS__);\
        !            43:     } \
        !            44: } while (0)
        !            45: 
        !            46: #define EMULATED_DEV_NAME "ccid-card-emulated"
        !            47: 
        !            48: #define BACKEND_NSS_EMULATED_NAME "nss-emulated"
        !            49: #define BACKEND_CERTIFICATES_NAME "certificates"
        !            50: 
        !            51: enum {
        !            52:     BACKEND_NSS_EMULATED = 1,
        !            53:     BACKEND_CERTIFICATES
        !            54: };
        !            55: 
        !            56: #define DEFAULT_BACKEND BACKEND_NSS_EMULATED
        !            57: 
        !            58: typedef struct EmulatedState EmulatedState;
        !            59: 
        !            60: enum {
        !            61:     EMUL_READER_INSERT = 0,
        !            62:     EMUL_READER_REMOVE,
        !            63:     EMUL_CARD_INSERT,
        !            64:     EMUL_CARD_REMOVE,
        !            65:     EMUL_GUEST_APDU,
        !            66:     EMUL_RESPONSE_APDU,
        !            67:     EMUL_ERROR,
        !            68: };
        !            69: 
        !            70: static const char *emul_event_to_string(uint32_t emul_event)
        !            71: {
        !            72:     switch (emul_event) {
        !            73:     case EMUL_READER_INSERT:
        !            74:         return "EMUL_READER_INSERT";
        !            75:     case EMUL_READER_REMOVE:
        !            76:         return "EMUL_READER_REMOVE";
        !            77:     case EMUL_CARD_INSERT:
        !            78:         return "EMUL_CARD_INSERT";
        !            79:     case EMUL_CARD_REMOVE:
        !            80:         return "EMUL_CARD_REMOVE";
        !            81:     case EMUL_GUEST_APDU:
        !            82:         return "EMUL_GUEST_APDU";
        !            83:     case EMUL_RESPONSE_APDU:
        !            84:         return "EMUL_RESPONSE_APDU";
        !            85:     case EMUL_ERROR:
        !            86:         return "EMUL_ERROR";
        !            87:     }
        !            88:     return "UNKNOWN";
        !            89: }
        !            90: 
        !            91: typedef struct EmulEvent {
        !            92:     QSIMPLEQ_ENTRY(EmulEvent) entry;
        !            93:     union {
        !            94:         struct {
        !            95:             uint32_t type;
        !            96:         } gen;
        !            97:         struct {
        !            98:             uint32_t type;
        !            99:             uint64_t code;
        !           100:         } error;
        !           101:         struct {
        !           102:             uint32_t type;
        !           103:             uint32_t len;
        !           104:             uint8_t data[];
        !           105:         } data;
        !           106:     } p;
        !           107: } EmulEvent;
        !           108: 
        !           109: #define MAX_ATR_SIZE 40
        !           110: struct EmulatedState {
        !           111:     CCIDCardState base;
        !           112:     uint8_t  debug;
        !           113:     char    *backend_str;
        !           114:     uint32_t backend;
        !           115:     char    *cert1;
        !           116:     char    *cert2;
        !           117:     char    *cert3;
        !           118:     char    *db;
        !           119:     uint8_t  atr[MAX_ATR_SIZE];
        !           120:     uint8_t  atr_length;
        !           121:     QSIMPLEQ_HEAD(event_list, EmulEvent) event_list;
        !           122:     QemuMutex event_list_mutex;
        !           123:     VReader *reader;
        !           124:     QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list;
        !           125:     QemuMutex vreader_mutex; /* and guest_apdu_list mutex */
        !           126:     QemuMutex handle_apdu_mutex;
        !           127:     QemuCond handle_apdu_cond;
        !           128:     int      pipe[2];
        !           129:     int      quit_apdu_thread;
        !           130:     QemuMutex apdu_thread_quit_mutex;
        !           131:     QemuCond apdu_thread_quit_cond;
        !           132: };
        !           133: 
        !           134: static void emulated_apdu_from_guest(CCIDCardState *base,
        !           135:     const uint8_t *apdu, uint32_t len)
        !           136: {
        !           137:     EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
        !           138:     EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent) + len);
        !           139: 
        !           140:     assert(event);
        !           141:     event->p.data.type = EMUL_GUEST_APDU;
        !           142:     event->p.data.len = len;
        !           143:     memcpy(event->p.data.data, apdu, len);
        !           144:     qemu_mutex_lock(&card->vreader_mutex);
        !           145:     QSIMPLEQ_INSERT_TAIL(&card->guest_apdu_list, event, entry);
        !           146:     qemu_mutex_unlock(&card->vreader_mutex);
        !           147:     qemu_mutex_lock(&card->handle_apdu_mutex);
        !           148:     qemu_cond_signal(&card->handle_apdu_cond);
        !           149:     qemu_mutex_unlock(&card->handle_apdu_mutex);
        !           150: }
        !           151: 
        !           152: static const uint8_t *emulated_get_atr(CCIDCardState *base, uint32_t *len)
        !           153: {
        !           154:     EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
        !           155: 
        !           156:     *len = card->atr_length;
        !           157:     return card->atr;
        !           158: }
        !           159: 
        !           160: static void emulated_push_event(EmulatedState *card, EmulEvent *event)
        !           161: {
        !           162:     qemu_mutex_lock(&card->event_list_mutex);
        !           163:     QSIMPLEQ_INSERT_TAIL(&(card->event_list), event, entry);
        !           164:     qemu_mutex_unlock(&card->event_list_mutex);
        !           165:     if (write(card->pipe[1], card, 1) != 1) {
        !           166:         DPRINTF(card, 1, "write to pipe failed\n");
        !           167:     }
        !           168: }
        !           169: 
        !           170: static void emulated_push_type(EmulatedState *card, uint32_t type)
        !           171: {
        !           172:     EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent));
        !           173: 
        !           174:     assert(event);
        !           175:     event->p.gen.type = type;
        !           176:     emulated_push_event(card, event);
        !           177: }
        !           178: 
        !           179: static void emulated_push_error(EmulatedState *card, uint64_t code)
        !           180: {
        !           181:     EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent));
        !           182: 
        !           183:     assert(event);
        !           184:     event->p.error.type = EMUL_ERROR;
        !           185:     event->p.error.code = code;
        !           186:     emulated_push_event(card, event);
        !           187: }
        !           188: 
        !           189: static void emulated_push_data_type(EmulatedState *card, uint32_t type,
        !           190:     const uint8_t *data, uint32_t len)
        !           191: {
        !           192:     EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent) + len);
        !           193: 
        !           194:     assert(event);
        !           195:     event->p.data.type = type;
        !           196:     event->p.data.len = len;
        !           197:     memcpy(event->p.data.data, data, len);
        !           198:     emulated_push_event(card, event);
        !           199: }
        !           200: 
        !           201: static void emulated_push_reader_insert(EmulatedState *card)
        !           202: {
        !           203:     emulated_push_type(card, EMUL_READER_INSERT);
        !           204: }
        !           205: 
        !           206: static void emulated_push_reader_remove(EmulatedState *card)
        !           207: {
        !           208:     emulated_push_type(card, EMUL_READER_REMOVE);
        !           209: }
        !           210: 
        !           211: static void emulated_push_card_insert(EmulatedState *card,
        !           212:     const uint8_t *atr, uint32_t len)
        !           213: {
        !           214:     emulated_push_data_type(card, EMUL_CARD_INSERT, atr, len);
        !           215: }
        !           216: 
        !           217: static void emulated_push_card_remove(EmulatedState *card)
        !           218: {
        !           219:     emulated_push_type(card, EMUL_CARD_REMOVE);
        !           220: }
        !           221: 
        !           222: static void emulated_push_response_apdu(EmulatedState *card,
        !           223:     const uint8_t *apdu, uint32_t len)
        !           224: {
        !           225:     emulated_push_data_type(card, EMUL_RESPONSE_APDU, apdu, len);
        !           226: }
        !           227: 
        !           228: #define APDU_BUF_SIZE 270
        !           229: static void *handle_apdu_thread(void* arg)
        !           230: {
        !           231:     EmulatedState *card = arg;
        !           232:     uint8_t recv_data[APDU_BUF_SIZE];
        !           233:     int recv_len;
        !           234:     VReaderStatus reader_status;
        !           235:     EmulEvent *event;
        !           236: 
        !           237:     while (1) {
        !           238:         qemu_mutex_lock(&card->handle_apdu_mutex);
        !           239:         qemu_cond_wait(&card->handle_apdu_cond, &card->handle_apdu_mutex);
        !           240:         qemu_mutex_unlock(&card->handle_apdu_mutex);
        !           241:         if (card->quit_apdu_thread) {
        !           242:             card->quit_apdu_thread = 0; /* debugging */
        !           243:             break;
        !           244:         }
        !           245:         qemu_mutex_lock(&card->vreader_mutex);
        !           246:         while (!QSIMPLEQ_EMPTY(&card->guest_apdu_list)) {
        !           247:             event = QSIMPLEQ_FIRST(&card->guest_apdu_list);
        !           248:             assert((unsigned long)event > 1000);
        !           249:             QSIMPLEQ_REMOVE_HEAD(&card->guest_apdu_list, entry);
        !           250:             if (event->p.data.type != EMUL_GUEST_APDU) {
        !           251:                 DPRINTF(card, 1, "unexpected message in handle_apdu_thread\n");
        !           252:                 qemu_free(event);
        !           253:                 continue;
        !           254:             }
        !           255:             if (card->reader == NULL) {
        !           256:                 DPRINTF(card, 1, "reader is NULL\n");
        !           257:                 qemu_free(event);
        !           258:                 continue;
        !           259:             }
        !           260:             recv_len = sizeof(recv_data);
        !           261:             reader_status = vreader_xfr_bytes(card->reader,
        !           262:                     event->p.data.data, event->p.data.len,
        !           263:                     recv_data, &recv_len);
        !           264:             DPRINTF(card, 2, "got back apdu of length %d\n", recv_len);
        !           265:             if (reader_status == VREADER_OK) {
        !           266:                 emulated_push_response_apdu(card, recv_data, recv_len);
        !           267:             } else {
        !           268:                 emulated_push_error(card, reader_status);
        !           269:             }
        !           270:             qemu_free(event);
        !           271:         }
        !           272:         qemu_mutex_unlock(&card->vreader_mutex);
        !           273:     }
        !           274:     qemu_mutex_lock(&card->apdu_thread_quit_mutex);
        !           275:     qemu_cond_signal(&card->apdu_thread_quit_cond);
        !           276:     qemu_mutex_unlock(&card->apdu_thread_quit_mutex);
        !           277:     return NULL;
        !           278: }
        !           279: 
        !           280: static void *event_thread(void *arg)
        !           281: {
        !           282:     int atr_len = MAX_ATR_SIZE;
        !           283:     uint8_t atr[MAX_ATR_SIZE];
        !           284:     VEvent *event = NULL;
        !           285:     EmulatedState *card = arg;
        !           286: 
        !           287:     while (1) {
        !           288:         const char *reader_name;
        !           289: 
        !           290:         event = vevent_wait_next_vevent();
        !           291:         if (event == NULL || event->type == VEVENT_LAST) {
        !           292:             break;
        !           293:         }
        !           294:         if (event->type != VEVENT_READER_INSERT) {
        !           295:             if (card->reader == NULL && event->reader != NULL) {
        !           296:                 /* Happens after device_add followed by card remove or insert.
        !           297:                  * XXX: create synthetic add_reader events if vcard_emul_init
        !           298:                  * already called, which happens if device_del and device_add
        !           299:                  * are called */
        !           300:                 card->reader = vreader_reference(event->reader);
        !           301:             } else {
        !           302:                 if (event->reader != card->reader) {
        !           303:                     fprintf(stderr,
        !           304:                         "ERROR: wrong reader: quiting event_thread\n");
        !           305:                     break;
        !           306:                 }
        !           307:             }
        !           308:         }
        !           309:         switch (event->type) {
        !           310:         case VEVENT_READER_INSERT:
        !           311:             /* TODO: take a specific reader. i.e. track which reader
        !           312:              * we are seeing here, check it is the one we want (the first,
        !           313:              * or by a particular name), and ignore if we don't want it.
        !           314:              */
        !           315:             reader_name = vreader_get_name(event->reader);
        !           316:             if (card->reader != NULL) {
        !           317:                 DPRINTF(card, 2, "READER INSERT - replacing %s with %s\n",
        !           318:                     vreader_get_name(card->reader), reader_name);
        !           319:                 qemu_mutex_lock(&card->vreader_mutex);
        !           320:                 vreader_free(card->reader);
        !           321:                 qemu_mutex_unlock(&card->vreader_mutex);
        !           322:                 emulated_push_reader_remove(card);
        !           323:             }
        !           324:             qemu_mutex_lock(&card->vreader_mutex);
        !           325:             DPRINTF(card, 2, "READER INSERT %s\n", reader_name);
        !           326:             card->reader = vreader_reference(event->reader);
        !           327:             qemu_mutex_unlock(&card->vreader_mutex);
        !           328:             emulated_push_reader_insert(card);
        !           329:             break;
        !           330:         case VEVENT_READER_REMOVE:
        !           331:             DPRINTF(card, 2, " READER REMOVE: %s\n",
        !           332:                     vreader_get_name(event->reader));
        !           333:             qemu_mutex_lock(&card->vreader_mutex);
        !           334:             vreader_free(card->reader);
        !           335:             card->reader = NULL;
        !           336:             qemu_mutex_unlock(&card->vreader_mutex);
        !           337:             emulated_push_reader_remove(card);
        !           338:             break;
        !           339:         case VEVENT_CARD_INSERT:
        !           340:             /* get the ATR (intended as a response to a power on from the
        !           341:              * reader */
        !           342:             atr_len = MAX_ATR_SIZE;
        !           343:             vreader_power_on(event->reader, atr, &atr_len);
        !           344:             card->atr_length = (uint8_t)atr_len;
        !           345:             DPRINTF(card, 2, " CARD INSERT\n");
        !           346:             emulated_push_card_insert(card, atr, atr_len);
        !           347:             break;
        !           348:         case VEVENT_CARD_REMOVE:
        !           349:             DPRINTF(card, 2, " CARD REMOVE\n");
        !           350:             emulated_push_card_remove(card);
        !           351:             break;
        !           352:         case VEVENT_LAST: /* quit */
        !           353:             vevent_delete(event);
        !           354:             return NULL;
        !           355:             break;
        !           356:         default:
        !           357:             break;
        !           358:         }
        !           359:         vevent_delete(event);
        !           360:     }
        !           361:     return NULL;
        !           362: }
        !           363: 
        !           364: static void pipe_read(void *opaque)
        !           365: {
        !           366:     EmulatedState *card = opaque;
        !           367:     EmulEvent *event, *next;
        !           368:     char dummy;
        !           369:     int len;
        !           370: 
        !           371:     do {
        !           372:         len = read(card->pipe[0], &dummy, sizeof(dummy));
        !           373:     } while (len == sizeof(dummy));
        !           374:     qemu_mutex_lock(&card->event_list_mutex);
        !           375:     QSIMPLEQ_FOREACH_SAFE(event, &card->event_list, entry, next) {
        !           376:         DPRINTF(card, 2, "event %s\n", emul_event_to_string(event->p.gen.type));
        !           377:         switch (event->p.gen.type) {
        !           378:         case EMUL_RESPONSE_APDU:
        !           379:             ccid_card_send_apdu_to_guest(&card->base, event->p.data.data,
        !           380:                 event->p.data.len);
        !           381:             break;
        !           382:         case EMUL_READER_INSERT:
        !           383:             ccid_card_ccid_attach(&card->base);
        !           384:             break;
        !           385:         case EMUL_READER_REMOVE:
        !           386:             ccid_card_ccid_detach(&card->base);
        !           387:             break;
        !           388:         case EMUL_CARD_INSERT:
        !           389:             assert(event->p.data.len <= MAX_ATR_SIZE);
        !           390:             card->atr_length = event->p.data.len;
        !           391:             memcpy(card->atr, event->p.data.data, card->atr_length);
        !           392:             ccid_card_card_inserted(&card->base);
        !           393:             break;
        !           394:         case EMUL_CARD_REMOVE:
        !           395:             ccid_card_card_removed(&card->base);
        !           396:             break;
        !           397:         case EMUL_ERROR:
        !           398:             ccid_card_card_error(&card->base, event->p.error.code);
        !           399:             break;
        !           400:         default:
        !           401:             DPRINTF(card, 2, "unexpected event\n");
        !           402:             break;
        !           403:         }
        !           404:         qemu_free(event);
        !           405:     }
        !           406:     QSIMPLEQ_INIT(&card->event_list);
        !           407:     qemu_mutex_unlock(&card->event_list_mutex);
        !           408: }
        !           409: 
        !           410: static int init_pipe_signaling(EmulatedState *card)
        !           411: {
        !           412:     if (pipe(card->pipe) < 0) {
        !           413:         DPRINTF(card, 2, "pipe creation failed\n");
        !           414:         return -1;
        !           415:     }
        !           416:     fcntl(card->pipe[0], F_SETFL, O_NONBLOCK);
        !           417:     fcntl(card->pipe[1], F_SETFL, O_NONBLOCK);
        !           418:     fcntl(card->pipe[0], F_SETOWN, getpid());
        !           419:     qemu_set_fd_handler(card->pipe[0], pipe_read, NULL, card);
        !           420:     return 0;
        !           421: }
        !           422: 
        !           423: #define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
        !           424: #define CERTIFICATES_ARGS_TEMPLATE\
        !           425:     "db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"
        !           426: 
        !           427: static int wrap_vcard_emul_init(VCardEmulOptions *options)
        !           428: {
        !           429:     static int called;
        !           430:     static int options_was_null;
        !           431: 
        !           432:     if (called) {
        !           433:         if ((options == NULL) != options_was_null) {
        !           434:             printf("%s: warning: running emulated with certificates"
        !           435:                    " and emulated side by side is not supported\n",
        !           436:                    __func__);
        !           437:             return VCARD_EMUL_FAIL;
        !           438:         }
        !           439:         vcard_emul_replay_insertion_events();
        !           440:         return VCARD_EMUL_OK;
        !           441:     }
        !           442:     options_was_null = (options == NULL);
        !           443:     called = 1;
        !           444:     return vcard_emul_init(options);
        !           445: }
        !           446: 
        !           447: static int emulated_initialize_vcard_from_certificates(EmulatedState *card)
        !           448: {
        !           449:     char emul_args[200];
        !           450:     VCardEmulOptions *options = NULL;
        !           451: 
        !           452:     snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
        !           453:         card->db ? card->db : CERTIFICATES_DEFAULT_DB,
        !           454:         card->cert1, card->cert2, card->cert3);
        !           455:     options = vcard_emul_options(emul_args);
        !           456:     if (options == NULL) {
        !           457:         printf("%s: warning: not using certificates due to"
        !           458:                " initialization error\n", __func__);
        !           459:     }
        !           460:     return wrap_vcard_emul_init(options);
        !           461: }
        !           462: 
        !           463: typedef struct EnumTable {
        !           464:     const char *name;
        !           465:     uint32_t value;
        !           466: } EnumTable;
        !           467: 
        !           468: EnumTable backend_enum_table[] = {
        !           469:     {BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED},
        !           470:     {BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES},
        !           471:     {NULL, 0},
        !           472: };
        !           473: 
        !           474: static uint32_t parse_enumeration(char *str,
        !           475:     EnumTable *table, uint32_t not_found_value)
        !           476: {
        !           477:     uint32_t ret = not_found_value;
        !           478: 
        !           479:     while (table->name != NULL) {
        !           480:         if (strcmp(table->name, str) == 0) {
        !           481:             ret = table->value;
        !           482:             break;
        !           483:         }
        !           484:         table++;
        !           485:     }
        !           486:     return ret;
        !           487: }
        !           488: 
        !           489: static int emulated_initfn(CCIDCardState *base)
        !           490: {
        !           491:     EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
        !           492:     QemuThread thread_id;
        !           493:     VCardEmulError ret;
        !           494:     EnumTable *ptable;
        !           495: 
        !           496:     QSIMPLEQ_INIT(&card->event_list);
        !           497:     QSIMPLEQ_INIT(&card->guest_apdu_list);
        !           498:     qemu_mutex_init(&card->event_list_mutex);
        !           499:     qemu_mutex_init(&card->vreader_mutex);
        !           500:     qemu_mutex_init(&card->handle_apdu_mutex);
        !           501:     qemu_cond_init(&card->handle_apdu_cond);
        !           502:     card->reader = NULL;
        !           503:     card->quit_apdu_thread = 0;
        !           504:     if (init_pipe_signaling(card) < 0) {
        !           505:         return -1;
        !           506:     }
        !           507:     card->backend = parse_enumeration(card->backend_str, backend_enum_table, 0);
        !           508:     if (card->backend == 0) {
        !           509:         printf("unknown backend, must be one of:\n");
        !           510:         for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) {
        !           511:             printf("%s\n", ptable->name);
        !           512:         }
        !           513:         return -1;
        !           514:     }
        !           515: 
        !           516:     /* TODO: a passthru backened that works on local machine. third card type?*/
        !           517:     if (card->backend == BACKEND_CERTIFICATES) {
        !           518:         if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) {
        !           519:             ret = emulated_initialize_vcard_from_certificates(card);
        !           520:         } else {
        !           521:             printf("%s: you must provide all three certs for"
        !           522:                    " certificates backend\n", EMULATED_DEV_NAME);
        !           523:             return -1;
        !           524:         }
        !           525:     } else {
        !           526:         if (card->backend != BACKEND_NSS_EMULATED) {
        !           527:             printf("%s: bad backend specified. The options are:\n%s (default),"
        !           528:                 " %s.\n", EMULATED_DEV_NAME, BACKEND_NSS_EMULATED_NAME,
        !           529:                 BACKEND_CERTIFICATES_NAME);
        !           530:             return -1;
        !           531:         }
        !           532:         if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) {
        !           533:             printf("%s: unexpected cert parameters to nss emulated backend\n",
        !           534:                    EMULATED_DEV_NAME);
        !           535:             return -1;
        !           536:         }
        !           537:         /* default to mirroring the local hardware readers */
        !           538:         ret = wrap_vcard_emul_init(NULL);
        !           539:     }
        !           540:     if (ret != VCARD_EMUL_OK) {
        !           541:         printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME);
        !           542:         return -1;
        !           543:     }
        !           544:     qemu_thread_create(&thread_id, event_thread, card);
        !           545:     qemu_thread_create(&thread_id, handle_apdu_thread, card);
        !           546:     return 0;
        !           547: }
        !           548: 
        !           549: static int emulated_exitfn(CCIDCardState *base)
        !           550: {
        !           551:     EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
        !           552:     VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL);
        !           553: 
        !           554:     vevent_queue_vevent(vevent); /* stop vevent thread */
        !           555:     qemu_mutex_lock(&card->apdu_thread_quit_mutex);
        !           556:     card->quit_apdu_thread = 1; /* stop handle_apdu thread */
        !           557:     qemu_cond_signal(&card->handle_apdu_cond);
        !           558:     qemu_cond_wait(&card->apdu_thread_quit_cond,
        !           559:                       &card->apdu_thread_quit_mutex);
        !           560:     /* handle_apdu thread stopped, can destroy all of it's mutexes */
        !           561:     qemu_cond_destroy(&card->handle_apdu_cond);
        !           562:     qemu_cond_destroy(&card->apdu_thread_quit_cond);
        !           563:     qemu_mutex_destroy(&card->apdu_thread_quit_mutex);
        !           564:     qemu_mutex_destroy(&card->handle_apdu_mutex);
        !           565:     qemu_mutex_destroy(&card->vreader_mutex);
        !           566:     qemu_mutex_destroy(&card->event_list_mutex);
        !           567:     return 0;
        !           568: }
        !           569: 
        !           570: static CCIDCardInfo emulated_card_info = {
        !           571:     .qdev.name = EMULATED_DEV_NAME,
        !           572:     .qdev.desc = "emulated smartcard",
        !           573:     .qdev.size = sizeof(EmulatedState),
        !           574:     .initfn = emulated_initfn,
        !           575:     .exitfn = emulated_exitfn,
        !           576:     .get_atr = emulated_get_atr,
        !           577:     .apdu_from_guest = emulated_apdu_from_guest,
        !           578:     .qdev.unplug    = qdev_simple_unplug_cb,
        !           579:     .qdev.props     = (Property[]) {
        !           580:         DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
        !           581:         DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
        !           582:         DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
        !           583:         DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
        !           584:         DEFINE_PROP_STRING("db", EmulatedState, db),
        !           585:         DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
        !           586:         DEFINE_PROP_END_OF_LIST(),
        !           587:     },
        !           588: };
        !           589: 
        !           590: static void ccid_card_emulated_register_devices(void)
        !           591: {
        !           592:     ccid_card_qdev_register(&emulated_card_info);
        !           593: }
        !           594: 
        !           595: device_init(ccid_card_emulated_register_devices)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.