@@ -494,10 +494,12 @@ int pcsc_card_connected; SCARDHANDLE pcsc_card; int transaction_depth; + + int slot_reset; }; typedef enum { CACKEY_TLV_APP_GENERIC = 0x01, CACKEY_TLV_APP_SKI = 0x02, @@ -623,10 +625,16 @@ SCardDisconnect(cackey_slots[idx].pcsc_card, SCARD_LEAVE_CARD); } cackey_slots[idx].pcsc_card_connected = 0; cackey_slots[idx].transaction_depth = 0; + + if (cackey_slots[idx].active) { + CACKEY_DEBUG_PRINTF("Marking active slot %lu as being reset", (unsigned long) idx); + } + + cackey_slots[idx].slot_reset = 1; } CACKEY_DEBUG_PRINTF("Returning"); return; @@ -700,10 +708,47 @@ CACKEY_DEBUG_PRINTF("Handle has been re-established"); } #endif CACKEY_DEBUG_PRINTF("Sucessfully connected to PC/SC, returning in success"); + + return(CACKEY_PCSC_S_OK); +} + +/* + * SYNPOSIS + * cackey_ret cackey_pcsc_disconnect(void); + * + * ARGUMENTS + * None + * + * RETURN VALUE + * CACKEY_PCSC_S_OK On success + * CACKEY_PCSC_E_GENERIC On error + * + * NOTES + * This function disconnects from the PC/SC Connection manager and updates + * the global handle. + * + */ +static cackey_ret cackey_pcsc_disconnect(void) { + LONG scard_rel_context_ret; + + CACKEY_DEBUG_PRINTF("Called."); + + if (cackey_pcsc_handle == NULL) { + return(CACKEY_PCSC_S_OK); + } + + scard_rel_context_ret = SCardReleaseContext(*cackey_pcsc_handle); + + free(cackey_pcsc_handle); + cackey_pcsc_handle = NULL; + + if (scard_rel_context_ret != SCARD_S_SUCCESS) { + return(CACKEY_PCSC_E_GENERIC); + } return(CACKEY_PCSC_S_OK); } /* @@ -978,12 +1023,14 @@ recv_len = sizeof(recv_buf); scard_xmit_ret = SCardTransmit(slot->pcsc_card, SCARD_PCI_T0, xmit_buf, xmit_len, SCARD_PCI_T1, recv_buf, &recv_len); if (scard_xmit_ret != SCARD_S_SUCCESS) { CACKEY_DEBUG_PRINTF("Failed to send APDU to card (SCardTransmit() = %s/%lx)", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_xmit_ret), (unsigned long) scard_xmit_ret); + CACKEY_DEBUG_PRINTF("Marking slot as having been reset"); slot->transaction_depth = 0; + slot->slot_reset = 1; if (scard_xmit_ret == SCARD_W_RESET_CARD) { CACKEY_DEBUG_PRINTF("Reset required, please hold..."); scard_reconn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, SCARD_RESET_CARD, &protocol); @@ -1595,12 +1642,12 @@ CACKEY_DEBUG_PRINTF("count is NULL, returning in failure"); return(NULL); } - if (*count == 0) { - if (certs != NULL) { + if (certs != NULL) { + if (*count == 0) { CACKEY_DEBUG_PRINTF("Requested we return 0 objects, short-circuit"); return(certs); } } @@ -1972,11 +2019,11 @@ static void cackey_free_identities(struct cackey_identity *identities, unsigned long identities_count) { CK_ATTRIBUTE *curr_attr; unsigned long id_idx, attr_idx; - if (identities || identities_count == 0) { + if (identities == NULL || identities_count == 0) { return; } for (id_idx = 0; id_idx < identities_count; id_idx++) { if (identities[id_idx].attributes) { @@ -2382,10 +2429,11 @@ for (idx = 0; idx < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); idx++) { cackey_slots[idx].active = 0; cackey_slots[idx].pcsc_reader = NULL; cackey_slots[idx].transaction_depth = 0; + cackey_slots[idx].slot_reset = 0; } cackey_initialized = 1; if (!cackey_biglock_init) { @@ -2433,10 +2481,12 @@ for (idx = 0; idx < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); idx++) { if (cackey_slots[idx].pcsc_reader) { free(cackey_slots[idx].pcsc_reader); } } + + cackey_pcsc_disconnect(); cackey_initialized = 0; CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); @@ -2571,10 +2621,11 @@ if (pSlotList) { cackey_slots[currslot].active = 1; cackey_slots[currslot].pcsc_reader = strdup(pcsc_readers); cackey_slots[currslot].pcsc_card_connected = 0; cackey_slots[currslot].transaction_depth = 0; + cackey_slots[currslot].slot_reset = 1; } currslot++; pcsc_readers += curr_reader_len + 1; } @@ -2618,11 +2669,11 @@ pSlotList[currslot] = currslot; } *pulCount = slot_count; - CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); + CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i). Found %lu readers.", CKR_OK, (unsigned long) slot_count); return(CKR_OK); tokenPresent = tokenPresent; /* Supress unused variable warning */ } @@ -3618,15 +3669,21 @@ CACKEY_DEBUG_PRINTF("Error. Search already active."); return(CKR_OPERATION_ACTIVE); } - if (cackey_sessions[hSession].identities != NULL) { - cackey_free_identities(cackey_sessions[hSession].identities, cackey_sessions[hSession].identities_count); + if (cackey_slots[cackey_sessions[hSession].slotID].slot_reset) { + CACKEY_DEBUG_PRINTF("The slot has been reset since we last looked for identities -- rescanning"); - cackey_sessions[hSession].identities = NULL; - cackey_sessions[hSession].identities_count = 0; + if (cackey_sessions[hSession].identities != NULL) { + cackey_free_identities(cackey_sessions[hSession].identities, cackey_sessions[hSession].identities_count); + + cackey_sessions[hSession].identities = NULL; + cackey_sessions[hSession].identities_count = 0; + } + + cackey_slots[cackey_sessions[hSession].slotID].slot_reset = 0; } if (cackey_sessions[hSession].identities == NULL) { pcsc_identities = cackey_read_certs(&cackey_slots[cackey_sessions[hSession].slotID], NULL, &num_certs); if (pcsc_identities != NULL) {