/* Re-insert of a card that has been removed by force removal */ VCardEmulError vcard_emul_force_card_insert(VReader *vreader) { VReaderEmul *vreader_emul; VCard *vcard; if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) { return VCARD_EMUL_FAIL; /* card is already removed */ } vreader_emul = vreader_get_private(vreader); /* if it's a softcard, get the saved vcard from the reader emul structure */ if (vreader_emul->saved_vcard) { vcard = vcard_reference(vreader_emul->saved_vcard); } else { /* it must be a physical card, rebuild it */ if (!PK11_IsPresent(vreader_emul->slot)) { /* physical card has been removed, not way to reinsert it */ return VCARD_EMUL_FAIL; } vcard = vcard_emul_mirror_card(vreader); } vreader_insert_card(vreader, vcard); vcard_free(vcard); return VCARD_EMUL_OK; }
/* Force a card removal even if the card is not physically removed */ VCardEmulError vcard_emul_force_card_remove(VReader *vreader) { if (!nss_emul_init || (vreader_card_is_present(vreader) != VREADER_OK)) { return VCARD_EMUL_FAIL; /* card is already removed */ } /* OK, remove it */ vreader_insert_card(vreader, NULL); return VCARD_EMUL_OK; }
/* * This is the main work of the emulator, handling the thread that looks for * changes in the readers and the cards. */ static void * passthru_emul_event_thread(void *args) { char *reader_list = NULL; int reader_list_len = 0; SCARD_READERSTATE_A *reader_states = NULL; int reader_count = 0; /* number of active readers */ int max_reader_count = 0; /* size of the reader_state array (including inactive readers) */ LONG rv; int timeout=1000; int i; do { /* variables to hold on to our new values until we are ready to replace * our old values */ char *new_reader_list = NULL; int new_reader_list_len = 0; int new_reader_count = 0; /* other temps */ char * reader_entry; VReader *reader; /* * First check to see if the reader list has changed */ rv = SCardListReaders(global_context, NULL, NULL, &new_reader_list_len); if (rv != SCARD_S_SUCCESS) { goto next; } /* * If the names have changed, we need to update our list and states. * This is where we detect reader insertions and removals. */ if (new_reader_list_len != reader_list_len) { /* update the list */ new_reader_list = (char *)malloc(new_reader_list_len); if (new_reader_list == NULL) { goto next; } rv = SCardListReaders(global_context, NULL, new_reader_list, &new_reader_list_len); if (rv != SCARD_S_SUCCESS) { free(new_reader_list); goto next; } /* clear out our event state */ for (i=0; i < reader_count; i++) { reader_states[i].dwEventState = 0; } /* count the readers and mark the ones that are still with us */ for (reader_entry = new_reader_list; *reader_entry; reader_entry += strlen(reader_entry)+1) { SCARD_READERSTATE_A *this_state; new_reader_count++; /* if the reader is still on the list, mark it present */ this_state = passthru_get_reader_state(reader_states, reader_count, reader_entry); if (this_state) { this_state->dwEventState = SCARD_STATE_PRESENT; } } /* eject any removed readers */ for (i=0; i < reader_count; i++) { if (reader_states[i].dwEventState == SCARD_STATE_PRESENT) { reader_states[i].dwEventState = 0; continue; } reader = vreader_get_reader_by_name(reader_states[i].szReader); vreader_remove_reader(reader); vreader_free(reader); reader_states[i].szReader = NULL; } /* handle the shrinking list */ if (new_reader_count < reader_count) { /* fold all the valid entries at the end of our reader_states * array up into those locations vacated by ejected readers. */ for (i=reader_count-1; i < (new_reader_count -1); i--) { if (reader_states[i].szReader) { SCARD_READERSTATE_A *blank_reader; blank_reader = passthru_get_blank_reader(reader_states, new_reader_count); assert(blank_reader); *blank_reader = reader_states[i]; reader_states[i].szReader = NULL; } } } /* handle the growing list */ if (new_reader_count > max_reader_count) { SCARD_READERSTATE_A *new_reader_states; /* grow the list */ new_reader_states = (SCARD_READERSTATE_A *)realloc(reader_states, sizeof(SCARD_READERSTATE_A)*new_reader_count); if (new_reader_states) { /* successful, update our current state */ reader_states = new_reader_states; max_reader_count = new_reader_count; } else { new_reader_count = max_reader_count; /* couldn't get enough * space to handle * all the new readers * */ } /* mark our new entries as empty */ for (i=reader_count; i > new_reader_count; i++) { reader_states[i].szReader = NULL; } } /* now walk the reader list, updating the state */ for (reader_entry = new_reader_list; *reader_entry; reader_entry += strlen(reader_entry)+1) { SCARD_READERSTATE_A *this_state; this_state = passthru_get_reader_state(reader_states, new_reader_count, reader_entry); if (this_state) { /* replace the old copy of the string with the new copy. * This will allow us to free reader_list at the end */ reader_states->szReader = reader_entry; continue; } /* this is a new reader, add it to the list */ this_state = passthru_get_blank_reader(reader_states, new_reader_count); if (!this_state) { continue; /* this can happen of we couldn't get enough slots in the grow list */ } this_state->szReader = reader_entry; this_state->dwCurrentState = SCARD_STATE_UNAWARE; reader = vreader_new(reader_entry, NULL, NULL); if (reader) { vreader_add_reader(reader); } vreader_free(reader); } /* finally update our current variables */ free(reader_list); reader_list = new_reader_list; reader_list_len = new_reader_list_len; reader_count = new_reader_count; } next: rv = SCardGetStatusChange(global_context, timeout, reader_states, reader_count); if (rv == SCARD_E_TIMEOUT) { continue; /* check for new readers */ } if (rv != SCARD_S_SUCCESS) { static int restarts = 0; VCardStatus status; /* try resetting the pcsc_lite subsystem */ SCardReleaseContext(global_context); global_context = 0; /* should close it */ printf("***** SCard failure %x\n", rv); restarts++; if (restarts >= 3) { printf("***** SCard failed %d times\n", restarts); return; /* exit thread */ } status = passthru_pcsc_lite_init(); assert(status == CARD_DONE); sleep(1); continue; } /* deal with card insertion/removal */ for (i=0; i < reader_count ; i++) { if ((reader_states[i].dwEventState & SCARD_STATE_CHANGED) == 0) { continue; } reader_states[i].dwCurrentState = reader_states[i].dwEventState; reader = vreader_get_reader_by_name(reader_states[i].szReader); if (reader == NULL) { continue; } if (reader_states[i].dwEventState & SCARD_STATE_EMPTY) { if (vreader_card_is_present(reader) == VREADER_OK) { vreader_insert_card(reader, NULL); } } if (reader_states[i].dwEventState & SCARD_STATE_PRESENT) { VCard *card; VCardStatus status = VCARD_FAIL; /* if there already was a card present, eject it before we * insert the new one */ if (vreader_card_is_present(reader) == VREADER_OK) { vreader_insert_card(reader, NULL); } card = vcard_new(NULL, NULL); if (card != NULL) { status = passthru_card_init(reader, card, "", NULL, NULL, NULL, 0); passthru_card_set_atr(card, reader_states[i].rgbAtr, reader_states[i].cbAtr); vcard_set_atr_func(card, passthru_card_get_atr); } if (status == VCARD_DONE) { vreader_insert_card(reader, card); } vcard_free(card); } vreader_free(reader); } } while (1); return NULL; }
static void do_command(void) { char inbuf[255]; char *string; VCardEmulError error; static unsigned int default_reader_id; unsigned int reader_id; VReader *reader = NULL; reader_id = default_reader_id; string = fgets(inbuf, sizeof(inbuf), stdin); if (string != NULL) { if (strncmp(string, "exit", 4) == 0) { /* remove all the readers */ VReaderList *list = vreader_get_reader_list(); VReaderListEntry *reader_entry; printf("Active Readers:\n"); for (reader_entry = vreader_list_get_first(list); reader_entry; reader_entry = vreader_list_get_next(reader_entry)) { VReader *reader = vreader_list_get_reader(reader_entry); vreader_id_t reader_id; reader_id = vreader_get_id(reader); if (reader_id == -1) { continue; } /* be nice and signal card removal first (qemu probably should * do this itself) */ if (vreader_card_is_present(reader) == VREADER_OK) { send_msg(VSC_CardRemove, reader_id, NULL, 0); } send_msg(VSC_ReaderRemove, reader_id, NULL, 0); } exit(0); } else if (strncmp(string, "insert", 6) == 0) { if (string[6] == ' ') { reader_id = get_id_from_string(&string[7], reader_id); } reader = vreader_get_reader_by_id(reader_id); if (reader != NULL) { error = vcard_emul_force_card_insert(reader); printf("insert %s, returned %d\n", reader ? vreader_get_name(reader) : "invalid reader", error); } else { printf("no reader by id %u found\n", reader_id); } } else if (strncmp(string, "remove", 6) == 0) { if (string[6] == ' ') { reader_id = get_id_from_string(&string[7], reader_id); } reader = vreader_get_reader_by_id(reader_id); if (reader != NULL) { error = vcard_emul_force_card_remove(reader); printf("remove %s, returned %d\n", reader ? vreader_get_name(reader) : "invalid reader", error); } else { printf("no reader by id %u found\n", reader_id); } } else if (strncmp(string, "select", 6) == 0) { if (string[6] == ' ') { reader_id = get_id_from_string(&string[7], VSCARD_UNDEFINED_READER_ID); } if (reader_id != VSCARD_UNDEFINED_READER_ID) { reader = vreader_get_reader_by_id(reader_id); } if (reader) { printf("Selecting reader %u, %s\n", reader_id, vreader_get_name(reader)); default_reader_id = reader_id; } else { printf("Reader with id %u not found\n", reader_id); } } else if (strncmp(string, "debug", 5) == 0) { if (string[5] == ' ') { verbose = get_id_from_string(&string[6], 0); } printf("debug level = %d\n", verbose); } else if (strncmp(string, "list", 4) == 0) { VReaderList *list = vreader_get_reader_list(); VReaderListEntry *reader_entry; printf("Active Readers:\n"); for (reader_entry = vreader_list_get_first(list); reader_entry; reader_entry = vreader_list_get_next(reader_entry)) { VReader *reader = vreader_list_get_reader(reader_entry); vreader_id_t reader_id; reader_id = vreader_get_id(reader); if (reader_id == -1) { continue; } printf("%3u %s %s\n", reader_id, vreader_card_is_present(reader) == VREADER_OK ? "CARD_PRESENT" : " ", vreader_get_name(reader)); } printf("Inactive Readers:\n"); for (reader_entry = vreader_list_get_first(list); reader_entry; reader_entry = vreader_list_get_next(reader_entry)) { VReader *reader = vreader_list_get_reader(reader_entry); vreader_id_t reader_id; reader_id = vreader_get_id(reader); if (reader_id != -1) { continue; } printf("INA %s %s\n", vreader_card_is_present(reader) == VREADER_OK ? "CARD_PRESENT" : " ", vreader_get_name(reader)); } } else if (*string != 0) { printf("valid commands:\n"); printf("insert [reader_id]\n"); printf("remove [reader_id]\n"); printf("select reader_id\n"); printf("list\n"); printf("debug [level]\n"); printf("exit\n"); } } vreader_free(reader); printf("> "); fflush(stdout); }