From 31d8c2dfd14ed01b430def2f46cc718ef4b595fc Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Wed, 19 Feb 2020 16:09:20 +0100 Subject: [PATCH] Revert "pkcs11: fixed slotIDs when a new slot list is requested" This reverts commit 7fb72ccf7bf3ca2ff3979b7ffbb690eed41ddb5f. --- src/pkcs11/pkcs11-global.c | 22 +--------------------- src/pkcs11/slot.c | 2 +- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/src/pkcs11/pkcs11-global.c b/src/pkcs11/pkcs11-global.c index 71e13831..c51f2fb9 100644 --- a/src/pkcs11/pkcs11-global.c +++ b/src/pkcs11/pkcs11-global.c @@ -451,13 +451,8 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese pSlotList==NULL_PTR? "plug-n-play":"refresh"); /* Slot list can only change in v2.20 */ - if (pSlotList == NULL_PTR) { + if (pSlotList == NULL_PTR) sc_ctx_detect_readers(context); - for (i=0; iflags &= ~SC_PKCS11_SLOT_FLAG_SEEN; - } - } card_detect_all(); @@ -488,21 +483,6 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese prev_reader = slot->reader; } - /* Slot list can only change in v2.20 */ - if (pSlotList == NULL_PTR) { - /* slot->id is derived from its location in the list virtual_slots. - * When the slot list changes, so does slot->id, so we reindex the - * slots here the same way it is done in `create_slot()` - * - * TODO use a persistent CK_SLOT_ID, e.g. by using something like - * `slot->id = sc_crc32(slot, sizeof *slot);` (this example, however, - * is currently not thread safe). */ - for (i=0; iid = (CK_SLOT_ID) list_locate(&virtual_slots, slot); - } - } - if (pSlotList == NULL_PTR) { sc_log(context, "was only a size inquiry (%lu)\n", numMatches); *pulCount = numMatches; diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c index 423457b4..12dea459 100644 --- a/src/pkcs11/slot.c +++ b/src/pkcs11/slot.c @@ -115,6 +115,7 @@ CK_RV create_slot(sc_reader_t *reader) } slot->login_user = -1; + slot->id = (CK_SLOT_ID) list_locate(&virtual_slots, slot); init_slot_info(&slot->slot_info, reader); sc_log(context, "Initializing slot with id 0x%lx", slot->id); @@ -125,7 +126,6 @@ CK_RV create_slot(sc_reader_t *reader) slot->slot_info.hardwareVersion.major = reader->version_major; slot->slot_info.hardwareVersion.minor = reader->version_minor; } - slot->id = (CK_SLOT_ID) list_locate(&virtual_slots, slot); return CKR_OK; } -- 2.40.1 From 8f4a6c703b5ae7d4f44cf33c85330171afa917bf Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Thu, 20 Feb 2020 01:42:18 +0100 Subject: [PATCH] align comment with implementation order --- src/pkcs11/pkcs11-global.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/pkcs11/pkcs11-global.c b/src/pkcs11/pkcs11-global.c index c51f2fb9..b1e0ab57 100644 --- a/src/pkcs11/pkcs11-global.c +++ b/src/pkcs11/pkcs11-global.c @@ -469,8 +469,8 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i); /* the list of available slots contains: * - if present, virtual hotplug slot; - * - any slot with token; * - without token(s), one empty slot per reader; + * - any slot with token; * - any slot that has already been seen; */ if ((!tokenPresent && !slot->reader) @@ -504,10 +504,7 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese sc_log(context, "returned %lu slots\n", numMatches); out: - if (found != NULL) { - free (found); - found = NULL; - } + free (found); sc_pkcs11_unlock(); return rv; } -- 2.40.1 From bae42473f68e7ca15fcf273348019361ccdc4e59 Mon Sep 17 00:00:00 2001 From: Doug Engert Date: Tue, 25 Feb 2020 20:24:00 -0600 Subject: [PATCH 2/7] Improved Handling of PKCS11 Slots OpenSC PKCS11 now retains slots even when the reader is removed. It can do this because existing OpenSC reader handling in ctx.c, reader-pcsc.c and PC/SC allow OpenSC to do this. This simplifies the code, and allow a reader to be reinserted and use the existing slot. This matching is actually done in reader-pcsc.c because PC/SC returns the unique ids based on the OS reader names. This is then used as the manufacturerID By not deleting slots the slot list can only increase which is a restriction of Firefox. It does not fix all the Firefox issues, but it does not go into a loop, when all the readers are removed. The defaults in opensc.conf for max-virtual-readers and slots-per-card allow for 4 different readers used during one session. On branch PKCS11-SLOTS-3 Changes to be committed: modified: sc-pkcs11.h modified: slot.c --- src/pkcs11/sc-pkcs11.h | 5 +++++ src/pkcs11/slot.c | 43 ++++++++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h index 4309b63116..55236d2163 100644 --- a/src/pkcs11/sc-pkcs11.h +++ b/src/pkcs11/sc-pkcs11.h @@ -206,6 +206,11 @@ struct sc_pkcs11_card { * the application calls `C_GetSlotList` with `NULL`. This flag tracks the * visibility to the application */ #define SC_PKCS11_SLOT_FLAG_SEEN 1 +/* reader-pcsc.c can reuse a removed reader, as the ctx->reader list contains + * readers which have been removed retain removed readers. + * Take advantage of this feature to allow for reinsertion of a reader*/ +#define SC_PKCS11_SLOT_FLAG_READER_REMOVED 2 + struct sc_pkcs11_slot { CK_SLOT_ID id; /* ID of the slot */ diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c index 12dea4599c..daaac6bb19 100644 --- a/src/pkcs11/slot.c +++ b/src/pkcs11/slot.c @@ -133,18 +133,8 @@ CK_RV create_slot(sc_reader_t *reader) void empty_slot(struct sc_pkcs11_slot *slot) { if (slot) { - if (slot->flags & SC_PKCS11_SLOT_FLAG_SEEN) { - /* Keep the slot visible to the application. The slot's state has - * already been reset by `slot_token_removed()`, lists have been - * emptied. We replace the reader with a virtual hotplug slot. */ - slot->reader = NULL; - init_slot_info(&slot->slot_info, NULL); - } else { - list_destroy(&slot->objects); - list_destroy(&slot->logins); - list_delete(&virtual_slots, slot); - free(slot); - } + list_clear(&slot->objects); + list_clear(&slot->logins); } } @@ -383,21 +373,38 @@ CK_RV card_detect(sc_reader_t *reader) CK_RV card_detect_all(void) { - unsigned int i; + unsigned int i, j; sc_log(context, "Detect all cards"); /* Detect cards in all initialized readers */ for (i=0; i< sc_ctx_get_reader_count(context); i++) { sc_reader_t *reader = sc_ctx_get_reader(context, i); + int removed = 0; /* have we called card_removed for this reader */ + if (reader->flags & SC_READER_REMOVED) { struct sc_pkcs11_slot *slot; - card_removed(reader); - while ((slot = reader_get_slot(reader))) { - empty_slot(slot); + /* look at all slots to call card_removed amd empty_slot */ + for (j = 0; jreader == reader) { + if (!removed) { + card_removed(reader); + removed = 1; /* only need to call once for this reader */ + } + if (slot->flags & SC_PKCS11_SLOT_FLAG_READER_REMOVED) { + empty_slot(slot); + slot->flags |= SC_PKCS11_SLOT_FLAG_READER_REMOVED; + } + } } - _sc_delete_reader(context, reader); - i--; } else { + struct sc_pkcs11_slot *slot; + for (j = 0; jreader == reader) + slot->flags &= ~SC_PKCS11_SLOT_FLAG_READER_REMOVED; + } + if (!reader_get_slot(reader)) initialize_reader(reader); else From cf4f21236060c35e566de2712a6a54ea0e2eabe5 Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Mon, 2 Mar 2020 22:24:54 +0100 Subject: [PATCH 3/7] pkcs11: simpify reader removal - reader (slot) description is already initialized init_slot_info() - objects and logins are already released in slot_token_removed --- src/pkcs11/pkcs11-global.c | 4 +--- src/pkcs11/sc-pkcs11.h | 11 ---------- src/pkcs11/slot.c | 43 ++++++-------------------------------- 3 files changed, 7 insertions(+), 51 deletions(-) diff --git a/src/pkcs11/pkcs11-global.c b/src/pkcs11/pkcs11-global.c index b1e0ab57c9..25c4cd362e 100644 --- a/src/pkcs11/pkcs11-global.c +++ b/src/pkcs11/pkcs11-global.c @@ -475,10 +475,8 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese */ if ((!tokenPresent && !slot->reader) || (!tokenPresent && slot->reader != prev_reader) - || (slot->slot_info.flags & CKF_TOKEN_PRESENT) - || (slot->flags & SC_PKCS11_SLOT_FLAG_SEEN)) { + || (slot->slot_info.flags & CKF_TOKEN_PRESENT)) { found[numMatches++] = slot->id; - slot->flags |= SC_PKCS11_SLOT_FLAG_SEEN; } prev_reader = slot->reader; } diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h index 55236d2163..16e8fdf797 100644 --- a/src/pkcs11/sc-pkcs11.h +++ b/src/pkcs11/sc-pkcs11.h @@ -201,16 +201,6 @@ struct sc_pkcs11_card { unsigned int nmechanisms; }; -/* If the slot did already show with `C_GetSlotList`, then we need to keep this - * slot alive. PKCS#11 2.30 allows allows adding but not removing slots until - * the application calls `C_GetSlotList` with `NULL`. This flag tracks the - * visibility to the application */ -#define SC_PKCS11_SLOT_FLAG_SEEN 1 -/* reader-pcsc.c can reuse a removed reader, as the ctx->reader list contains - * readers which have been removed retain removed readers. - * Take advantage of this feature to allow for reinsertion of a reader*/ -#define SC_PKCS11_SLOT_FLAG_READER_REMOVED 2 - struct sc_pkcs11_slot { CK_SLOT_ID id; /* ID of the slot */ @@ -232,7 +222,6 @@ struct sc_pkcs11_slot { }; typedef struct sc_pkcs11_slot sc_pkcs11_slot_t; - /* Forward decl */ typedef struct sc_pkcs11_operation sc_pkcs11_operation_t; diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c index daaac6bb19..2fb495d295 100644 --- a/src/pkcs11/slot.c +++ b/src/pkcs11/slot.c @@ -121,24 +121,11 @@ CK_RV create_slot(sc_reader_t *reader) if (reader != NULL) { slot->reader = reader; - strcpy_bp(slot->slot_info.manufacturerID, reader->vendor, 32); - strcpy_bp(slot->slot_info.slotDescription, reader->name, 64); - slot->slot_info.hardwareVersion.major = reader->version_major; - slot->slot_info.hardwareVersion.minor = reader->version_minor; } return CKR_OK; } -void empty_slot(struct sc_pkcs11_slot *slot) -{ - if (slot) { - list_clear(&slot->objects); - list_clear(&slot->logins); - } -} - - /* create slots associated with a reader, called whenever a reader is seen. */ CK_RV initialize_reader(sc_reader_t *reader) { @@ -373,38 +360,20 @@ CK_RV card_detect(sc_reader_t *reader) CK_RV card_detect_all(void) { - unsigned int i, j; + unsigned int i; sc_log(context, "Detect all cards"); /* Detect cards in all initialized readers */ for (i=0; i< sc_ctx_get_reader_count(context); i++) { sc_reader_t *reader = sc_ctx_get_reader(context, i); - int removed = 0; /* have we called card_removed for this reader */ if (reader->flags & SC_READER_REMOVED) { - struct sc_pkcs11_slot *slot; - /* look at all slots to call card_removed amd empty_slot */ - for (j = 0; jreader == reader) { - if (!removed) { - card_removed(reader); - removed = 1; /* only need to call once for this reader */ - } - if (slot->flags & SC_PKCS11_SLOT_FLAG_READER_REMOVED) { - empty_slot(slot); - slot->flags |= SC_PKCS11_SLOT_FLAG_READER_REMOVED; - } - } - } + card_removed(reader); + /* do not remove slots related to this reader which would be + * possible according to PKCS#11 2.20 and later, because NSS can't + * handle a shrinking slot list + * https://bugzilla.mozilla.org/show_bug.cgi?id=1613632 */ } else { - struct sc_pkcs11_slot *slot; - for (j = 0; jreader == reader) - slot->flags &= ~SC_PKCS11_SLOT_FLAG_READER_REMOVED; - } - if (!reader_get_slot(reader)) initialize_reader(reader); else From 87d2798e72ab940b7f7a57490663751ae4dc8842 Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Tue, 3 Mar 2020 12:38:37 +0100 Subject: [PATCH 4/7] removed unused plug_and_play parameter see 1fb741338a010515b35f28cd9c769561f3e574a2 --- src/pkcs11/sc-pkcs11.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h index 16e8fdf797..c3a13934bc 100644 --- a/src/pkcs11/sc-pkcs11.h +++ b/src/pkcs11/sc-pkcs11.h @@ -65,7 +65,6 @@ struct sc_pkcs11_slot; struct sc_pkcs11_card; struct sc_pkcs11_config { - unsigned int plug_and_play; unsigned int max_virtual_slots; unsigned int slots_per_card; unsigned char lock_login; From cc4d4ff0b069c5517cce1ccbd374b6a18d61e020 Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Tue, 3 Mar 2020 15:09:17 +0100 Subject: [PATCH 5/7] pkcs11: reclaim unused slots based on reader description When a reader is removed and reattached, this re-uses the old slot without relying on the fact that the sc_reader_t is unchanged. --- src/pkcs11/pkcs11-global.c | 5 ++--- src/pkcs11/slot.c | 46 ++++++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/pkcs11/pkcs11-global.c b/src/pkcs11/pkcs11-global.c index 25c4cd362e..95c37f3c72 100644 --- a/src/pkcs11/pkcs11-global.c +++ b/src/pkcs11/pkcs11-global.c @@ -468,8 +468,7 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese for (i=0; iname, 64); + strcpy_bp(manufacturerID, reader->vendor, 32); /* Locate a slot related to the reader */ for (i = 0; ireader == reader) return slot; + if (slot->reader == NULL && reader != NULL + && 0 == memcmp(slot->slot_info.slotDescription, slotDescription, 64) + && 0 == memcmp(slot->slot_info.manufacturerID, manufacturerID, 32) + && slot->slot_info.hardwareVersion.major == reader->version_major + && slot->slot_info.hardwareVersion.minor == reader->version_minor) + return slot; } return NULL; } @@ -82,8 +93,8 @@ static int object_list_seeker(const void *el, const void *key) CK_RV create_slot(sc_reader_t *reader) { - /* find unused virtual hotplug slots */ - struct sc_pkcs11_slot *slot = reader_get_slot(NULL); + /* find unused slots previously allocated for the same reader */ + struct sc_pkcs11_slot *slot = reader_reclaim_slot(reader); /* create a new slot if no empty slot is available */ if (!slot) { @@ -373,11 +384,32 @@ card_detect_all(void) * possible according to PKCS#11 2.20 and later, because NSS can't * handle a shrinking slot list * https://bugzilla.mozilla.org/show_bug.cgi?id=1613632 */ + + /* Instead, remove the releation between reader and slot */ + for (i = 0; ireader == reader) { + slot->reader = NULL; + } + } } else { - if (!reader_get_slot(reader)) - initialize_reader(reader); - else - card_detect(sc_ctx_get_reader(context, i)); + /* Locate a slot related to the reader */ + int found = 0; + for (i = 0; ireader == reader) { + found = 1; + break; + } + } + if (!found) { + for (i = 0; i < sc_pkcs11_conf.slots_per_card; i++) { + CK_RV rv = create_slot(reader); + if (rv != CKR_OK) + return rv; + } + } + card_detect(reader); } } sc_log(context, "All cards detected"); From 61a2c6aaff0aa3add222f8560a8075637ee9b1fd Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Mon, 13 Jan 2020 17:21:18 +0100 Subject: [PATCH 6/7] reader-pcsc: fixed handling of detatching events - allows re-attatching a reader to an existing reader object by resetting the SC_READER_REMOVED flag - readers that are flagged with SC_READER_REMOVED are not used for SCardGetStatusChange to avoid SCARD_E_UNKNOWN_READER fixes https://github.com/OpenSC/OpenSC/issues/1903 --- src/libopensc/reader-pcsc.c | 48 ++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 66b426e436..14e3b4e0ec 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -181,6 +181,9 @@ static int pcsc_to_opensc_error(LONG rv) return SC_ERROR_READER_LOCKED; case SCARD_E_NO_READERS_AVAILABLE: return SC_ERROR_NO_READERS_FOUND; + case SCARD_E_UNKNOWN_READER: + return SC_ERROR_READER_DETACHED; + case SCARD_E_NO_SERVICE: /* If the service is (auto)started, there could be readers later */ return SC_ERROR_NO_READERS_FOUND; @@ -1467,8 +1470,13 @@ static int pcsc_detect_readers(sc_context_t *ctx) for (reader_name = reader_buf; *reader_name != '\x0'; reader_name += strlen(reader_name) + 1) { - if (!strcmp(reader->name, reader_name)) + if (!strcmp(reader->name, reader_name)) { + if (reader->flags & SC_READER_REMOVED) { + reader->flags &= ~SC_READER_REMOVED; + refresh_attributes(reader); + } break; + } } if (*reader_name != '\x0') { @@ -1546,7 +1554,7 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re LONG rv; SCARD_READERSTATE *rgReaderStates; size_t i; - unsigned int num_watch; + unsigned int num_watch, count; int r = SC_ERROR_INTERNAL; DWORD dwtimeout; @@ -1565,22 +1573,30 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); /* Find out the current status */ - num_watch = sc_ctx_get_reader_count(ctx); - sc_log(ctx, "Trying to watch %d readers", num_watch); - for (i = 0; i < num_watch; i++) { - rgReaderStates[i].szReader = sc_ctx_get_reader(ctx, i)->name; - rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE; - rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE; + num_watch = 0; + count = sc_ctx_get_reader_count(ctx); + for (i = 0; i < count; i++) { + sc_reader_t *reader = sc_ctx_get_reader(ctx, i); + if (reader->flags & SC_READER_REMOVED) + continue; + rgReaderStates[num_watch].szReader = reader->name; + rgReaderStates[num_watch].dwCurrentState = SCARD_STATE_UNAWARE; + rgReaderStates[num_watch].dwEventState = SCARD_STATE_UNAWARE; + num_watch++; } -#ifndef __APPLE__ - /* OS X 10.6.2 - 10.12.6 do not support PnP notification */ + sc_log(ctx, "Trying to watch %d reader%s", num_watch, num_watch == 1 ? "" : "s"); if (event_mask & SC_EVENT_READER_ATTACHED) { - rgReaderStates[i].szReader = "\\\\?PnP?\\Notification"; - rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE; - rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE; +#ifdef __APPLE__ + /* OS X 10.6.2 - 10.12.6 do not support PnP notification */ + sc_log(ctx, "PnP notification not supported"); +#else + rgReaderStates[num_watch].szReader = "\\\\?PnP?\\Notification"; + rgReaderStates[num_watch].dwCurrentState = SCARD_STATE_UNAWARE; + rgReaderStates[num_watch].dwEventState = SCARD_STATE_UNAWARE; num_watch++; - } + sc_log(ctx, "Trying to detect new readers"); #endif + } } else { rgReaderStates = (SCARD_READERSTATE *)(*reader_states); @@ -1606,14 +1622,12 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re goto out; } -#ifdef __APPLE__ if (num_watch == 0) { - sc_log(ctx, "No readers available, PnP notification not supported"); + sc_log(ctx, "No readers available to be watched"); *event_reader = NULL; r = SC_ERROR_NO_READERS_FOUND; goto out; } -#endif rv = gpriv->SCardGetStatusChange(gpriv->pcsc_wait_ctx, 0, rgReaderStates, num_watch); if (rv != SCARD_S_SUCCESS) { From 2901a2d040ec13b70c9cd212f7cbf9ad4ef8c602 Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Mon, 13 Jan 2020 17:25:38 +0100 Subject: [PATCH] opensc-notify: handle reader insertion/removal events - If readers are attatched, the new reader is probed for a card to check if a notification needs to be sent - removal of readers are not notified to the user, we assume that PC/SC sends the correct card removal event - The list of readers to be monitored is adjusted once a reader (dis)appears - On macOS, without PnP notification, we always check for new/removed readers with SCardListReaders - fixes interrupt handling in opensc-notify on Unix fixes https://github.com/OpenSC/OpenSC/issues/1874 --- src/libopensc/errors.c | 4 +- src/libopensc/internal-winscard.h | 1 + src/libopensc/opensc.h | 33 +++-- src/libopensc/reader-pcsc.c | 205 +++++++++++++++++++++--------- src/tools/opensc-notify.c | 125 ++++++++++-------- src/ui/strings.c | 10 +- 6 files changed, 248 insertions(+), 130 deletions(-) diff --git a/src/libopensc/errors.c b/src/libopensc/errors.c index 5b58b7ea6c..03cb79dd1f 100644 --- a/src/libopensc/errors.c +++ b/src/libopensc/errors.c @@ -45,8 +45,8 @@ const char *sc_strerror(int error) "Message too long (keypad)", "Timeout while waiting for event from card reader", "Unresponsive card (correctly inserted?)", - "Reader detached (hotplug device?)", - "Reader reattached (hotplug device?)", + "Reader detached", + "Reader reattached", "Reader in use by another application" }; const int rdr_base = -SC_ERROR_READER; diff --git a/src/libopensc/internal-winscard.h b/src/libopensc/internal-winscard.h index edc315ca2f..6b2a21c569 100644 --- a/src/libopensc/internal-winscard.h +++ b/src/libopensc/internal-winscard.h @@ -100,6 +100,7 @@ typedef unsigned __int8 uint8_t; #define SCARD_E_NOT_TRANSACTED 0x80100016 /**< An attempt was made to end a non-existent transaction. */ #define SCARD_E_READER_UNAVAILABLE 0x80100017 /**< The specified reader is not currently available for use. */ #define SCARD_E_NO_SERVICE 0x8010001D /**< The Smart card resource manager is not running. */ +#define SCARD_E_SERVICE_STOPPED 0x8010001E /**< The smart card resource manager has shut down. */ #define SCARD_E_NO_READERS_AVAILABLE 0x8010002E /**< Cannot find a smart card reader. */ #define SCARD_W_UNRESPONSIVE_CARD 0x80100066 /**< The smart card is not responding to a reset. */ #define SCARD_W_UNPOWERED_CARD 0x80100067 /**< Power has been removed from the smart card, so that further communication is not possible. */ diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 10bea0a013..9e764665b2 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -213,10 +213,10 @@ extern "C" { /* Event masks for sc_wait_for_event() */ #define SC_EVENT_CARD_INSERTED 0x0001 #define SC_EVENT_CARD_REMOVED 0x0002 -#define SC_EVENT_CARD_EVENTS SC_EVENT_CARD_INSERTED|SC_EVENT_CARD_REMOVED +#define SC_EVENT_CARD_EVENTS (SC_EVENT_CARD_INSERTED|SC_EVENT_CARD_REMOVED) #define SC_EVENT_READER_ATTACHED 0x0004 #define SC_EVENT_READER_DETACHED 0x0008 -#define SC_EVENT_READER_EVENTS SC_EVENT_READER_ATTACHED|SC_EVENT_READER_DETACHED +#define SC_EVENT_READER_EVENTS (SC_EVENT_READER_ATTACHED|SC_EVENT_READER_DETACHED) #define MAX_FILE_SIZE 65535 @@ -1024,18 +1024,25 @@ int sc_disconnect_card(struct sc_card *card); int sc_detect_card_presence(sc_reader_t *reader); /** - * Waits for an event on readers. Note: only the event is detected, - * there is no update of any card or other info. - * NOTE: Only PC/SC backend implements this. - * @param ctx pointer to a Context structure - * @param event_mask The types of events to wait for; this should - * be ORed from one of the following - * SC_EVENT_CARD_REMOVED - * SC_EVENT_CARD_INSERTED - * SC_EVENT_READER_ATTACHED - * @param event_reader (OUT) the reader on which the event was detected, or NULL if new reader + * Waits for an event on readers. + * + * In case of a reader event (attached/detached), the list of reader is + * adjusted accordingly. This means that a subsequent call to + * `sc_ctx_detect_readers()` is not needed. + * + * @note Only PC/SC backend implements this. An infinite timeout on macOS does + * not detect reader events (use a limited timeout instead if needed). + * + * @param ctx (IN) pointer to a Context structure + * @param event_mask (IN) The types of events to wait for; this should + * be ORed from one of the following: + * - SC_EVENT_CARD_REMOVED + * - SC_EVENT_CARD_INSERTED + * - SC_EVENT_READER_ATTACHED + * - SC_EVENT_READER_DETACHED + * @param event_reader (OUT) the reader on which the event was detected * @param event (OUT) the events that occurred. This is also ORed - * from the SC_EVENT_CARD_* constants listed above. + * from the constants listed above. * @param timeout Amount of millisecs to wait; -1 means forever * @retval < 0 if an error occurred * @retval = 0 if a an event happened diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 14e3b4e0ec..34dc821bfa 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -127,6 +127,9 @@ struct pcsc_global_private_data { SCardTransmit_t SCardTransmit; SCardListReaders_t SCardListReaders; SCardGetAttrib_t SCardGetAttrib; + + sc_reader_t *attached_reader; + sc_reader_t *removed_reader; }; struct pcsc_private_data { @@ -185,6 +188,7 @@ static int pcsc_to_opensc_error(LONG rv) return SC_ERROR_READER_DETACHED; case SCARD_E_NO_SERVICE: + case SCARD_E_SERVICE_STOPPED: /* If the service is (auto)started, there could be readers later */ return SC_ERROR_NO_READERS_FOUND; case SCARD_E_NO_SMARTCARD: @@ -358,7 +362,7 @@ static int refresh_attributes(sc_reader_t *reader) if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) return SC_ERROR_NOT_ALLOWED; - if (priv->reader_state.szReader == NULL) { + if (priv->reader_state.szReader == NULL || reader->ctx->flags & SC_READER_REMOVED) { priv->reader_state.szReader = reader->name; priv->reader_state.dwCurrentState = SCARD_STATE_UNAWARE; priv->reader_state.dwEventState = SCARD_STATE_UNAWARE; @@ -382,12 +386,11 @@ static int refresh_attributes(sc_reader_t *reader) } /* the system could not detect the reader. It means, the prevoiusly attached reader is disconnected. */ - if ( + if (rv == (LONG)SCARD_E_UNKNOWN_READER #ifdef SCARD_E_NO_READERS_AVAILABLE - (rv == (LONG)SCARD_E_NO_READERS_AVAILABLE) || + || rv == (LONG)SCARD_E_NO_READERS_AVAILABLE #endif - (rv == (LONG)SCARD_E_UNKNOWN_READER) || (rv == (LONG)SCARD_E_SERVICE_STOPPED)) { - + || rv == (LONG)SCARD_E_SERVICE_STOPPED) { if (old_flags & SC_READER_CARD_PRESENT) { reader->flags |= SC_READER_CARD_CHANGED; } @@ -1143,7 +1146,7 @@ static void detect_reader_features(sc_reader_t *reader, SCARDHANDLE card_handle) return; rv = gpriv->SCardControl(card_handle, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0, feature_buf, sizeof(feature_buf), &feature_len); - if (rv != (LONG)SCARD_S_SUCCESS) { + if (rv != SCARD_S_SUCCESS) { PCSC_TRACE(reader, "SCardControl failed", rv); return; } @@ -1382,6 +1385,8 @@ static int pcsc_detect_readers(sc_context_t *ctx) } sc_log(ctx, "Probing PC/SC readers"); + gpriv->attached_reader = NULL; + gpriv->removed_reader = NULL; do { if (gpriv->pcsc_ctx == (SCARDCONTEXT)-1) { @@ -1399,12 +1404,11 @@ static int pcsc_detect_readers(sc_context_t *ctx) * All readers have disappeared, so mark them as * such so we don't keep polling them over and over. */ - if ( + if (rv == (LONG)SCARD_E_NO_SERVICE #ifdef SCARD_E_NO_READERS_AVAILABLE - (rv == (LONG)SCARD_E_NO_READERS_AVAILABLE) || + || rv == (LONG)SCARD_E_NO_READERS_AVAILABLE #endif - (rv == (LONG)SCARD_E_NO_SERVICE) || (rv == (LONG)SCARD_E_SERVICE_STOPPED)) { - + || rv == (LONG)SCARD_E_SERVICE_STOPPED) { for (i = 0; i < sc_ctx_get_reader_count(ctx); i++) { sc_reader_t *reader = sc_ctx_get_reader(ctx, i); @@ -1414,6 +1418,7 @@ static int pcsc_detect_readers(sc_context_t *ctx) } reader->flags |= SC_READER_REMOVED; + gpriv->removed_reader = reader; } } @@ -1473,6 +1478,7 @@ static int pcsc_detect_readers(sc_context_t *ctx) if (!strcmp(reader->name, reader_name)) { if (reader->flags & SC_READER_REMOVED) { reader->flags &= ~SC_READER_REMOVED; + gpriv->attached_reader = reader; refresh_attributes(reader); } break; @@ -1487,8 +1493,11 @@ static int pcsc_detect_readers(sc_context_t *ctx) (reader_buf + reader_buf_size) - next_reader_name); reader_buf_size -= (next_reader_name - reader_name); } else { - /* existing reader not found */ - reader->flags |= SC_READER_REMOVED; + if (!(reader->flags & SC_READER_REMOVED)) { + /* existing reader not found */ + reader->flags |= SC_READER_REMOVED; + gpriv->removed_reader = reader; + } } } @@ -1503,6 +1512,7 @@ static int pcsc_detect_readers(sc_context_t *ctx) _sc_delete_reader(ctx, reader); continue; } + gpriv->attached_reader = reader; /* check for pinpad support early, to allow opensc-tool -l display accurate information */ priv = reader->drv_data; @@ -1555,7 +1565,7 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re SCARD_READERSTATE *rgReaderStates; size_t i; unsigned int num_watch, count; - int r = SC_ERROR_INTERNAL; + int r = SC_ERROR_INTERNAL, detect_readers = 0, detected_hotplug = 0; DWORD dwtimeout; LOG_FUNC_CALLED(ctx); @@ -1579,8 +1589,13 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re sc_reader_t *reader = sc_ctx_get_reader(ctx, i); if (reader->flags & SC_READER_REMOVED) continue; + struct pcsc_private_data *priv = reader->drv_data; rgReaderStates[num_watch].szReader = reader->name; - rgReaderStates[num_watch].dwCurrentState = SCARD_STATE_UNAWARE; + if (priv->reader_state.szReader == NULL) { + rgReaderStates[num_watch].dwCurrentState = SCARD_STATE_UNAWARE; + } else { + rgReaderStates[num_watch].dwCurrentState = priv->reader_state.dwEventState; + } rgReaderStates[num_watch].dwEventState = SCARD_STATE_UNAWARE; num_watch++; } @@ -1589,6 +1604,12 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re #ifdef __APPLE__ /* OS X 10.6.2 - 10.12.6 do not support PnP notification */ sc_log(ctx, "PnP notification not supported"); + /* Always check on new readers as if a hotplug + * event was detected. This overwrites a + * SC_ERROR_EVENT_TIMEOUT if a new reader is + * detected with SC_SUCCESS. */ + detect_readers = 1; + detected_hotplug = 1; #else rgReaderStates[num_watch].szReader = "\\\\?PnP?\\Notification"; rgReaderStates[num_watch].dwCurrentState = SCARD_STATE_UNAWARE; @@ -1622,9 +1643,11 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re goto out; } + *event_reader = NULL; + *event = 0; + if (num_watch == 0) { sc_log(ctx, "No readers available to be watched"); - *event_reader = NULL; r = SC_ERROR_NO_READERS_FOUND; goto out; } @@ -1646,7 +1669,6 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re /* Scan the current state of all readers to see if they * match any of the events we're polling for */ - *event = 0; for (i = 0, rsp = rgReaderStates; i < num_watch; i++, rsp++) { DWORD state, prev_state; sc_log(ctx, "'%s' before=0x%08X now=0x%08X", @@ -1657,51 +1679,72 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re state = rsp->dwEventState; rsp->dwCurrentState = rsp->dwEventState; if (state & SCARD_STATE_CHANGED) { - /* check for hotplug events */ - if (!strcmp(rgReaderStates[i].szReader, "\\\\?PnP?\\Notification")) { + if (!strcmp(rsp->szReader, "\\\\?PnP?\\Notification")) { sc_log(ctx, "detected hotplug event"); - *event |= SC_EVENT_READER_ATTACHED; - *event_reader = NULL; - } + /* Windows sends hotplug event on both, attaching and + * detaching a reader. pcscd only sends it in case of + * attaching a reader. We'll detect later in which case we + * are. */ + detect_readers = 1; + detected_hotplug = 1; + + /* Windows wants us to manually reset the changed state */ + rsp->dwEventState &= ~SCARD_STATE_CHANGED; + + /* By default, ignore a hotplug event as if a timout + * occurred, since it may be an unrequested removal or + * false alarm. Just continue to loop and check at the end + * of this function whether we need to return the attached + * reader or not. */ + r = SC_ERROR_EVENT_TIMEOUT; + } else { + sc_reader_t *reader = sc_ctx_get_reader_by_name(ctx, rsp->szReader); + if (reader) { + /* copy the state so we know what to watch out for */ + struct pcsc_private_data *priv = reader->drv_data; + priv->reader_state.dwEventState = state; + priv->reader_state.dwCurrentState = prev_state; + } - if ((state & SCARD_STATE_PRESENT) && !(prev_state & SCARD_STATE_PRESENT)) { - sc_log(ctx, "card inserted event"); - *event |= SC_EVENT_CARD_INSERTED; - } + if ((state & SCARD_STATE_PRESENT) && !(prev_state & SCARD_STATE_PRESENT)) { + sc_log(ctx, "card inserted event"); + *event |= SC_EVENT_CARD_INSERTED; + } - if ((prev_state & SCARD_STATE_PRESENT) && !(state & SCARD_STATE_PRESENT)) { - sc_log(ctx, "card removed event"); - *event |= SC_EVENT_CARD_REMOVED; - } + if ((prev_state & SCARD_STATE_PRESENT) && !(state & SCARD_STATE_PRESENT)) { + sc_log(ctx, "card removed event"); + *event |= SC_EVENT_CARD_REMOVED; + } - if ((state & SCARD_STATE_UNKNOWN) && !(prev_state & SCARD_STATE_UNKNOWN)) { - sc_log(ctx, "reader detached event"); - *event |= SC_EVENT_READER_DETACHED; - } + if ((state & SCARD_STATE_UNKNOWN) && !(prev_state & SCARD_STATE_UNKNOWN)) { + sc_log(ctx, "reader detached event"); + *event |= SC_EVENT_READER_DETACHED; + detect_readers = 1; + } - if ((prev_state & SCARD_STATE_UNKNOWN) && !(state & SCARD_STATE_UNKNOWN)) { - sc_log(ctx, "reader re-attached event"); - *event |= SC_EVENT_READER_ATTACHED; - } + if ((state & SCARD_STATE_IGNORE) && !(prev_state & SCARD_STATE_IGNORE)) { + sc_log(ctx, "reader detached event"); + *event |= SC_EVENT_READER_DETACHED; + detect_readers = 1; + } - if (*event & event_mask) { - sc_log(ctx, "Matching event 0x%02X in reader %s", *event, rsp->szReader); - *event_reader = sc_ctx_get_reader_by_name(ctx, rsp->szReader); - r = SC_SUCCESS; - goto out; - } + if ((prev_state & SCARD_STATE_UNKNOWN) && !(state & SCARD_STATE_UNKNOWN)) { + sc_log(ctx, "reader re-attached event"); + *event |= SC_EVENT_READER_ATTACHED; + detect_readers = 1; + } + if (*event & event_mask) { + sc_log(ctx, "Matching event 0x%02X in reader %s", *event, rsp->szReader); + *event_reader = reader; + r = SC_SUCCESS; + goto out; + } else { + *event = 0; + } + } } - - /* No match - copy the state so pcscd knows - * what to watch out for */ - /* rsp->dwCurrentState = rsp->dwEventState; */ - } - - if (timeout == 0) { - r = SC_ERROR_EVENT_TIMEOUT; - goto out; } /* Set the timeout if caller wants to time out */ @@ -1713,13 +1756,13 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re rv = gpriv->SCardGetStatusChange(gpriv->pcsc_wait_ctx, dwtimeout, rgReaderStates, num_watch); - if (rv == (LONG) SCARD_E_CANCELLED) { + if (rv == (LONG)SCARD_E_CANCELLED) { /* C_Finalize was called, events don't matter */ r = SC_ERROR_EVENT_TIMEOUT; goto out; } - if (rv == (LONG) SCARD_E_TIMEOUT) { + if (rv == (LONG)SCARD_E_TIMEOUT) { r = SC_ERROR_EVENT_TIMEOUT; goto out; } @@ -1731,12 +1774,54 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re } } out: - if (!reader_states) { - free(rgReaderStates); + /* in case of an error re-detect all readers */ + if (r < 0 && r != SC_ERROR_EVENT_TIMEOUT) + detect_readers = 1; + + if (detect_readers) { + pcsc_detect_readers(ctx); } - else if (*reader_states == NULL) { - sc_log(ctx, "return allocated 'reader states'"); - *reader_states = rgReaderStates; + + if (detected_hotplug) { + if (gpriv->attached_reader) { + if (event_reader && event && !*event) { + /* no other event has been detected, yet */ + *event_reader = gpriv->attached_reader; + *event = SC_EVENT_READER_ATTACHED; + r = SC_SUCCESS; + } + gpriv->attached_reader = NULL; + } else if (gpriv->removed_reader) { + /* Normally, we only check the hotplug event for attached readers. + * However, Windows also notifies on removal. Check, if the latter + * was requested by the caller. */ + if (event_mask & SC_EVENT_READER_DETACHED + && event_reader && event && !*event) { + /* no other event has been detected, yet */ + *event_reader = gpriv->removed_reader; + *event = SC_EVENT_READER_DETACHED; + r = SC_SUCCESS; + } + gpriv->removed_reader = NULL; + } else { + /* false alarm, there was no reader attached or removed, + * avoid re-initialize the reader states by resetting detect_readers */ + detect_readers = 0; + } + } + + if (detect_readers) { + free(rgReaderStates); + if (reader_states && *reader_states) + *reader_states = NULL; + } else { + if (!reader_states) { + free(rgReaderStates); + } + else if (*reader_states == NULL) { + sc_log(ctx, "return allocated reader states"); + *reader_states = rgReaderStates; + } } LOG_FUNC_RETURN(ctx, r); @@ -2449,6 +2534,7 @@ int pcsc_use_reader(sc_context_t *ctx, void * pcsc_context_handle, void * pcsc_c } sc_log(ctx, "Probing PC/SC reader"); + gpriv->attached_reader = NULL; gpriv->pcsc_ctx = *(SCARDCONTEXT *)pcsc_context_handle; card_handle = *(SCARDHANDLE *)pcsc_card_handle; @@ -2467,6 +2553,7 @@ int pcsc_use_reader(sc_context_t *ctx, void * pcsc_context_handle, void * pcsc_c } else { _sc_delete_reader(ctx, reader); } + gpriv->attached_reader = reader; } out: diff --git a/src/tools/opensc-notify.c b/src/tools/opensc-notify.c index afc24353a8..87d66c6721 100644 --- a/src/tools/opensc-notify.c +++ b/src/tools/opensc-notify.c @@ -49,26 +49,21 @@ void Sleep(unsigned int Milliseconds) } #endif -void stop_daemon() -{ -#ifdef PCSCLITE_GOOD - sc_cancel(ctx); -#endif - run_daemon = 0; -} - void notify_daemon() { int r; - const unsigned int event_mask = SC_EVENT_CARD_EVENTS; + const unsigned int event_mask = SC_EVENT_CARD_EVENTS|SC_EVENT_READER_EVENTS; unsigned int event; struct sc_reader *event_reader = NULL; - size_t error_count = 0; + void *reader_states = NULL; +#ifndef __APPLE__ /* timeout adjusted to the maximum response time for WM_CLOSE in case * canceling doesn't work */ const int timeout = 20000; - struct sc_atr old_atr; - void *reader_states = NULL; +#else + /* lower timeout, because Apple doesn't support hotplug events */ + const int timeout = 2000; +#endif r = sc_establish_context(&ctx, "opensc-notify"); if (r < 0 || !ctx) { @@ -76,50 +71,51 @@ void notify_daemon() return; } - while (run_daemon && error_count < 1000) { + while (run_daemon) { + r = sc_wait_for_event(ctx, event_mask, &event_reader, &event, timeout, &reader_states); if (r < 0) { if (r == SC_ERROR_NO_READERS_FOUND) { - /* No readers available, PnP notification not supported */ - Sleep(200); - } else { - error_count++; + Sleep(timeout); + continue; } - continue; } - error_count = 0; - - if (event & SC_EVENT_CARD_REMOVED) { - sc_notify_id(ctx, &old_atr, NULL, NOTIFY_CARD_REMOVED); - } - if (event & SC_EVENT_CARD_INSERTED) { - if (event_reader) { - /* FIXME `pcsc_wait_for_event` has all the information that's - * requested again with `pcsc_detect_card_presence`, but it - * doesn't use the ATR, for example, to refresh the reader's - * attributes. To get the ATR we need to call - * sc_detect_card_presence. Eventually this should be fixed. */ - sc_detect_card_presence(event_reader); - memcpy(old_atr.value, event_reader->atr.value, - event_reader->atr.len); - old_atr.len = event_reader->atr.len; - } else { - old_atr.len = 0; + if (event_reader) { + if (event & SC_EVENT_CARD_REMOVED + || (event & SC_EVENT_READER_DETACHED + && event_reader->flags & SC_READER_CARD_PRESENT)) { + /* sc_notify_id uses only the reader's name for displaying on + * removal, so use a dummy card here to get that information + * into the notification */ + struct sc_pkcs15_card p15card; + sc_card_t card; + memset(&card, 0, sizeof card); + card.reader = event_reader; + memset(&p15card, 0, sizeof p15card); + p15card.card = &card; + sc_notify_id(ctx, &event_reader->atr, &p15card, NOTIFY_CARD_REMOVED); + } else if (event & SC_EVENT_CARD_INSERTED + || (event & SC_EVENT_READER_ATTACHED + && event_reader->flags & SC_READER_CARD_PRESENT)) { + /* sc_notify_id prevers the reader's name for displaying on + * insertion, so use a dummy card here to get that information + * into the notification */ + struct sc_pkcs15_card p15card; + sc_card_t card; + memset(&card, 0, sizeof card); + card.reader = event_reader; + memset(&p15card, 0, sizeof p15card); + p15card.card = &card; + sc_notify_id(ctx, &event_reader->atr, &p15card, NOTIFY_CARD_INSERTED); } - sc_notify_id(ctx, old_atr.len ? &old_atr : NULL, NULL, - NOTIFY_CARD_INSERTED); } } if (ctx) { - if (error_count >= 1000) { - sc_log(ctx, "Too many errors; aborting."); - } /* free `reader_states` */ sc_wait_for_event(ctx, 0, NULL, NULL, 0, &reader_states); - reader_states = NULL; sc_release_context(ctx); ctx = NULL; } @@ -132,7 +128,8 @@ void notify_daemon() LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_CLOSE || message == WM_QUIT) { - stop_daemon(); + run_daemon = 0; + sc_cancel(ctx); return TRUE; } @@ -182,32 +179,54 @@ WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nShowC #else -#ifdef HAVE_SIGACTION +#if defined(HAVE_SIGACTION) && defined(HAVE_PTHREAD) +#include +#include #include +#include + +static int cancellation_fd[] = {-1, -1}; void sig_handler(int sig) { - stop_daemon(); + run_daemon = 0; + write(cancellation_fd[1], &sig, sizeof sig); } -void set_sa_handler(void) +static void *cancellation_proc(void *arg) { - struct sigaction new_sig, old_sig; + (void)arg; + while (run_daemon) { + int sig; + if (sizeof sig == read(cancellation_fd[0], &sig, sizeof sig)) { + break; + } + } + sc_cancel(ctx); + return NULL; +} - /* Register signal handlers */ +void setup_cancellation(void) +{ + pthread_t cancellation_thread; + struct sigaction new_sig, old_sig; new_sig.sa_handler = sig_handler; sigemptyset(&new_sig.sa_mask); new_sig.sa_flags = SA_RESTART; - if ((sigaction(SIGINT, &new_sig, &old_sig) < 0) - || (sigaction(SIGTERM, &new_sig, &old_sig) < 0)) { - fprintf(stderr, "Failed to create signal handler: %s", strerror(errno)); + + if (pipe(cancellation_fd) != 0 + || (errno = pthread_create(&cancellation_thread, NULL, cancellation_proc, NULL)) != 0 + || sigaction(SIGINT, &new_sig, &old_sig) != 0 + || sigaction(SIGTERM, &new_sig, &old_sig) != 0) { + fprintf(stderr, "Failed to setup cancellation: %s", strerror(errno)); } } #else -void set_sa_handler(void) +void setup_cancellation(void) { } + #endif #include "opensc-notify-cmdline.h" @@ -244,8 +263,8 @@ main (int argc, char **argv) if ((!cmdline.customized_mode_counter && !cmdline.standard_mode_counter) || cmdline.daemon_mode_counter) { - set_sa_handler(); run_daemon = 1; + setup_cancellation(); notify_daemon(); } else { /* give the notification process some time to spawn */ diff --git a/src/ui/strings.c b/src/ui/strings.c index ea1d3ba650..90dbc0f964 100644 --- a/src/ui/strings.c +++ b/src/ui/strings.c @@ -34,8 +34,12 @@ static const char *get_inserted_text(struct sc_pkcs15_card *p15card, struct sc_a static char text[3*SC_MAX_ATR_SIZE] = {0}; const char prefix[] = "ATR: "; - if (p15card && p15card->card && p15card->card->name) { + if (p15card && p15card->card + && p15card->card->name) { return p15card->card->name; + } else if (p15card && p15card->card + && p15card->card->reader && p15card->card->reader->name) { + return p15card->card->reader->name; } if (!atr) @@ -192,7 +196,7 @@ const char *ui_get_str(struct sc_context *ctx, struct sc_atr *atr, str = "Dieses Fenster wird automatisch geschlossen, wenn die PIN am PIN-Pad eingegeben wurde (Timeout typischerweise nach 30 Sekunden)."; break; case NOTIFY_CARD_INSERTED: - if (p15card) { + if (p15card && p15card->card && p15card->card->name) { str = "Smartcard kann jetzt verwendet werden"; } else { str = "Smartcard erkannt"; @@ -260,7 +264,7 @@ const char *ui_get_str(struct sc_context *ctx, struct sc_atr *atr, str = "This window will be closed automatically after the PIN has been submitted on the PIN pad (timeout typically after 30 seconds)."; break; case NOTIFY_CARD_INSERTED: - if (p15card) { + if (p15card && p15card->card && p15card->card->name) { str = "Smart card is ready to use"; } else { str = "Smart card detected"; From a87c4c68cdc272a65cff0a77b5e48b6b0d921387 Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Fri, 5 Jun 2020 14:57:00 +0200 Subject: [PATCH 1/3] Unbreak wait for events By Jabuk Jelen Fixes https://github.com/OpenSC/OpenSC/issues/2021 --- src/libopensc/reader-pcsc.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index b3da6fc88b..808b75530b 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -1700,12 +1700,6 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re r = SC_ERROR_EVENT_TIMEOUT; } else { sc_reader_t *reader = sc_ctx_get_reader_by_name(ctx, rsp->szReader); - if (reader) { - /* copy the state so we know what to watch out for */ - struct pcsc_private_data *priv = reader->drv_data; - priv->reader_state.dwEventState = state; - priv->reader_state.dwCurrentState = prev_state; - } if ((state & SCARD_STATE_PRESENT) && !(prev_state & SCARD_STATE_PRESENT)) { sc_log(ctx, "card inserted event"); From fb84c16ebadcefcb4dcd68780a1cbe9adb2671bc Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Fri, 5 Jun 2020 15:50:31 +0200 Subject: [PATCH 2/3] pcsc: immediately exit on hotplug events fixes delayed notification for removed readers closes https://github.com/OpenSC/OpenSC/issues/2021 --- src/libopensc/reader-pcsc.c | 4 ++++ src/ui/notify.c | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 808b75530b..56da7816ef 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -1741,6 +1741,10 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re } } + /* if a reader was detected, we need to create a new list of readers */ + if (detected_hotplug) + goto out; + /* Set the timeout if caller wants to time out */ if (timeout == -1) { dwtimeout = INFINITE; diff --git a/src/ui/notify.c b/src/ui/notify.c index 90e7778c10..897ea21ca3 100644 --- a/src/ui/notify.c +++ b/src/ui/notify.c @@ -437,6 +437,7 @@ void sc_notify_id(struct sc_context *ctx, struct sc_atr *atr, #elif defined(ENABLE_NOTIFY) && defined(ENABLE_GIO2) #include +#include "libopensc/log.h" static GApplication *application = NULL; @@ -481,6 +482,14 @@ static void notify_gio(struct sc_context *ctx, } } + if (ctx) { + sc_log(ctx, "%s %s %s %s", + title ? title : "", + text ? text : "", + icon ? icon : "", + group ? group : ""); + } + g_application_send_notification(application, group, notification); if (gicon) { From 00f7f3d87ed3d5d981440e5f53e8520d067a9864 Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Mon, 8 Jun 2020 17:04:49 +0200 Subject: [PATCH 3/3] pkcs11: fixed notifying twice in case of an attached reader before 14e396273 sc_wait_for_event() only notified in case of a new reader, but didn't add it to the internal list of readers. That's why PKCS#11 needed to bail out early in this case (and the application had to call C_WaitForSlotEvent a second time to actually get the related slot). Since sc_wait_for_event() can now handle insertion correctly, we can now immediately check (and reset) the events on the slots. --- src/pkcs11/pkcs11-global.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/pkcs11/pkcs11-global.c b/src/pkcs11/pkcs11-global.c index 671890309f..6985bc21ea 100644 --- a/src/pkcs11/pkcs11-global.c +++ b/src/pkcs11/pkcs11-global.c @@ -730,13 +730,6 @@ CK_RV C_WaitForSlotEvent(CK_FLAGS flags, /* blocking/nonblocking flag */ sc_log(context, "C_WaitForSlotEvent() reader_states:%p", reader_states); sc_pkcs11_unlock(); r = sc_wait_for_event(context, mask, &found, &events, -1, &reader_states); - if (events & SC_EVENT_READER_ATTACHED) { - rv = sc_pkcs11_lock(); - if (rv != CKR_OK) - return rv; - - goto out; - } /* Was C_Finalize called ? */ if (in_finalize == 1) return CKR_CRYPTOKI_NOT_INITIALIZED; From 4cfa4f334d6cbf3f730b5d6b0e5c0daeeffd2da6 Mon Sep 17 00:00:00 2001 From: Zoltan Kelemen Date: Sun, 12 Jul 2020 22:07:13 +0200 Subject: [PATCH] Fix for issue #1999: - Reset context to undefined handle value on error since call may alter output parameter. - Continue to assume -1 as undefined handle value in all PCSC implementations, to keep this fix as small and surgical as possible. --- src/libopensc/reader-pcsc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 56da7816ef..6443d2a9c9 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -1424,7 +1424,7 @@ static int pcsc_detect_readers(sc_context_t *ctx) if ((rv == (LONG)SCARD_E_NO_SERVICE) || (rv == (LONG)SCARD_E_SERVICE_STOPPED)) { gpriv->SCardReleaseContext(gpriv->pcsc_ctx); - gpriv->pcsc_ctx = 0; + gpriv->pcsc_ctx = -1; gpriv->pcsc_wait_ctx = -1; /* reconnecting below may may restart PC/SC service */ rv = SCARD_E_INVALID_HANDLE; @@ -1441,6 +1441,7 @@ static int pcsc_detect_readers(sc_context_t *ctx) rv = gpriv->SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &gpriv->pcsc_ctx); if (rv != SCARD_S_SUCCESS) { + gpriv->pcsc_ctx = -1; PCSC_LOG(ctx, "SCardEstablishContext failed", rv); ret = pcsc_to_opensc_error(rv); goto out; @@ -1451,7 +1452,8 @@ static int pcsc_detect_readers(sc_context_t *ctx) } } while (rv != SCARD_S_SUCCESS); - reader_buf = malloc(sizeof(char) * reader_buf_size); + /* The +2 below is to make sure we have zero terminators, in case we get invalid data */ + reader_buf = calloc(reader_buf_size+2, sizeof(char)); if (!reader_buf) { ret = SC_ERROR_OUT_OF_MEMORY; goto out; @@ -1629,6 +1631,7 @@ static int pcsc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_re if (gpriv->pcsc_wait_ctx == (SCARDCONTEXT)-1) { rv = gpriv->SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &gpriv->pcsc_wait_ctx); if (rv != SCARD_S_SUCCESS) { + gpriv->pcsc_wait_ctx = -1; PCSC_LOG(ctx, "SCardEstablishContext(wait) failed", rv); r = pcsc_to_opensc_error(rv); goto out; From 8c5d4ec47f9c3f48bd5b2d7747030b8ffc39a2c6 Mon Sep 17 00:00:00 2001 From: Frida Flodin Date: Wed, 6 Oct 2021 09:05:48 +0000 Subject: [PATCH 1/4] Fix detect_card_presence return value In opensc.h the documentation states that the function detect_card_presence should return 0 if no card is present, which is reasonable. This was not the case before since more flags could be set even if SC_READER_CARD_PRESENT is not. This was probably missed before since more flags has been added since this function was first written. Signed-off-by: Frida Flodin --- src/libopensc/reader-pcsc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 99887852d7..54d8cf30c7 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -476,7 +476,12 @@ static int pcsc_detect_card_presence(sc_reader_t *reader) rv = refresh_attributes(reader); if (rv != SC_SUCCESS) LOG_FUNC_RETURN(reader->ctx, rv); - LOG_FUNC_RETURN(reader->ctx, reader->flags); + + // Return 0 if the card is not present + if (reader->flags & SC_READER_CARD_PRESENT) + LOG_FUNC_RETURN(reader->ctx, reader->flags); + else + LOG_FUNC_RETURN(reader->ctx, 0); } static int check_forced_protocol(sc_reader_t *reader, DWORD *protocol) From ffb5c82ea3724462a5a23e6b2b34bec30af4eb70 Mon Sep 17 00:00:00 2001 From: Frida Flodin Date: Wed, 6 Oct 2021 09:05:52 +0000 Subject: [PATCH 2/4] Handle when reader is detached on macOS refresh_attributes returns SC_SUCCESS if we can't detect the reader. The same should happen if the reader is unknown/detached. This was found when detaching reader on macOS. Then we don't get SCARD_E_UNKNOWN_READER from SCardGetStatusChange. We notice it later from that the state of the reader is SCARD_STATE_UNKNOWN. This resulted in C_WaitForSlotEvent not noticing that the reader, and thus the card, was removed. Signed-off-by: Frida Flodin --- src/libopensc/reader-pcsc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 54d8cf30c7..40f994a514 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -415,7 +415,8 @@ static int refresh_attributes(sc_reader_t *reader) * XXX: We'll hit it again, as no readers are removed currently. */ reader->flags &= ~(SC_READER_CARD_PRESENT); - return SC_ERROR_READER_DETACHED; + sc_log(reader->ctx, "Reader unknown: %s", sc_strerror(SC_ERROR_READER_DETACHED)); + SC_FUNC_RETURN(reader->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); } reader->flags &= ~(SC_READER_CARD_CHANGED|SC_READER_CARD_INUSE|SC_READER_CARD_EXCLUSIVE); From 20d11ef10abc3728f7eb21c6452e2b373fc4bbb1 Mon Sep 17 00:00:00 2001 From: Frida Flodin Date: Wed, 6 Oct 2021 09:05:56 +0000 Subject: [PATCH 3/4] Fix incorrect use of SC_READER_CARD_CHANGED Looking in opensc.h the flag SC_READER_CARD_CHANGED should be set if the card was exchanged. In other words if a card is present but it is not the same card as before. It looks like SC_READER_CARD_CHANGED was misinterpreted as a flag for when the card was removed and thus that the status has changed. Signed-off-by: Frida Flodin --- src/libopensc/reader-pcsc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 40f994a514..664042a199 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -393,10 +393,7 @@ static int refresh_attributes(sc_reader_t *reader) || rv == (LONG)SCARD_E_NO_READERS_AVAILABLE #endif || rv == (LONG)SCARD_E_SERVICE_STOPPED) { - if (old_flags & SC_READER_CARD_PRESENT) { - reader->flags |= SC_READER_CARD_CHANGED; - } - + reader->flags &= ~(SC_READER_CARD_PRESENT); SC_FUNC_RETURN(reader->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); } @@ -459,8 +456,6 @@ static int refresh_attributes(sc_reader_t *reader) } } else { reader->flags &= ~SC_READER_CARD_PRESENT; - if (old_flags & SC_READER_CARD_PRESENT) - reader->flags |= SC_READER_CARD_CHANGED; } sc_log(reader->ctx, "card %s%s", reader->flags & SC_READER_CARD_PRESENT ? "present" : "absent", From 26bbbe7bb6ab3198ffb50f7dfb9757b3b3d471a1 Mon Sep 17 00:00:00 2001 From: Frida Flodin Date: Wed, 6 Oct 2021 09:05:59 +0000 Subject: [PATCH 4/4] Sanity check detect_card_presence return value The return value from detect_card_presence should be 0 if no card is present. Therefore the flag SC_READER_CARD_PRESENT is not allowed to be 0 if detect_card_presence has non-zero return value. Signed-off-by: Frida Flodin --- src/libopensc/sc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libopensc/sc.c b/src/libopensc/sc.c index 29f6b86895..40b9646fe2 100644 --- a/src/libopensc/sc.c +++ b/src/libopensc/sc.c @@ -337,6 +337,12 @@ int sc_detect_card_presence(sc_reader_t *reader) LOG_FUNC_RETURN(reader->ctx, SC_ERROR_NOT_SUPPORTED); r = reader->ops->detect_card_presence(reader); + + // Check that we get sane return value from backend + // detect_card_presence should return 0 if no card is present. + if (r && !(r & SC_READER_CARD_PRESENT)) + LOG_FUNC_RETURN(reader->ctx, SC_ERROR_INTERNAL); + LOG_FUNC_RETURN(reader->ctx, r); } From 62cf2c496eec26b7bc6a2c55bb3b9b88db462962 Mon Sep 17 00:00:00 2001 From: Veronika Hanulikova Date: Fri, 2 Sep 2022 16:19:26 +0200 Subject: [PATCH] Keep pcsc reader flags when disconnected When the reader is removed, the reader->flags are set to SC_READER_REMOVED. card_detect_all() then frees resources and sets slot->reader to NULL. During this, sc_card_disconnect() is called, setting reader->flags to 0. In a subsequent call to card_detect_all() with the reader still removed, the corresponding slot is reclaimed, and slot->reader set back to the removed reader, but slot->events is overwritten, which causes the C_WaitForSlot() not to recognize event on the slot. --- src/libopensc/reader-pcsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 1efd8a0d31..40bfd293d3 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -672,7 +672,7 @@ static int pcsc_disconnect(sc_reader_t * reader) LONG rv = priv->gpriv->SCardDisconnect(priv->pcsc_card, priv->gpriv->disconnect_action); PCSC_TRACE(reader, "SCardDisconnect returned", rv); } - reader->flags = 0; + reader->flags &= SC_READER_REMOVED; return SC_SUCCESS; } From c2e00e9071952b30ed6d58d9b7670eb3d93ea6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 20 May 2022 14:26:44 +0300 Subject: [PATCH] pkcs11-session: fix C_GetSessionInfo in 'atomic' mode The device is always in logged-out mode with PIN cached, so ignore the logged-in check. Since the token is now guaranteed to be logged-in or have sessions removed, simplify the further checks to match the session state. Fixes: 4bd8cda96604 "pkcs11-session: When we notice logout in lower layers..." --- src/pkcs11/pkcs11-session.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pkcs11/pkcs11-session.c b/src/pkcs11/pkcs11-session.c index 7fb9cb36..e9388183 100644 --- a/src/pkcs11/pkcs11-session.c +++ b/src/pkcs11/pkcs11-session.c @@ -252,7 +252,6 @@ CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_RV rv; struct sc_pkcs11_session *session; struct sc_pkcs11_slot *slot; - int logged_out; if (pInfo == NULL_PTR) return CKR_ARGUMENTS_BAD; @@ -276,16 +275,16 @@ CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, /* the session's handle */ pInfo->ulDeviceError = 0; slot = session->slot; - logged_out = (slot_get_logged_in_state(slot) == SC_PIN_STATE_LOGGED_OUT); - if (logged_out && slot->login_user >= 0) { + if (!sc_pkcs11_conf.atomic && slot->login_user >= 0 && + slot_get_logged_in_state(slot) == SC_PIN_STATE_LOGGED_OUT) { slot->login_user = -1; sc_pkcs11_close_all_sessions(session->slot->id); rv = CKR_SESSION_HANDLE_INVALID; goto out; } - if (slot->login_user == CKU_SO && !logged_out) { + if (slot->login_user == CKU_SO) { pInfo->state = CKS_RW_SO_FUNCTIONS; - } else if ((slot->login_user == CKU_USER && !logged_out) || (!(slot->token_info.flags & CKF_LOGIN_REQUIRED))) { + } else if (slot->login_user == CKU_USER || !(slot->token_info.flags & CKF_LOGIN_REQUIRED)) { pInfo->state = (session->flags & CKF_RW_SESSION) ? CKS_RW_USER_FUNCTIONS : CKS_RO_USER_FUNCTIONS; } else { -- 2.40.1 From 12ac33d6e0f01a334c792b341b7ea27f10ba0b98 Mon Sep 17 00:00:00 2001 From: Veronika Hanulikova Date: Wed, 22 Mar 2023 16:19:07 +0100 Subject: [PATCH 1/6] Add function for getting current card status in PKCS15 layer By using sc_detect_card_presence() function and observing status flags. --- src/pkcs11/framework-pkcs15.c | 29 +++++++++++++++++++++++++++++ src/pkcs11/sc-pkcs11.h | 1 + 2 files changed, 30 insertions(+) diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index 97daefcb47..11ea867023 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -1401,6 +1401,35 @@ int slot_get_logged_in_state(struct sc_pkcs11_slot *slot) return logged_in; } +int slot_get_card_state(struct sc_pkcs11_slot *slot) +{ + struct pkcs15_fw_data *fw_data = NULL; + struct sc_pkcs15_card *p15card = NULL; + int rv = 0; + + if (slot->p11card == NULL) { + goto out; + } + + fw_data = (struct pkcs15_fw_data *) slot->p11card->fws_data[slot->fw_data_idx]; + if (!fw_data) + goto out; + p15card = fw_data->p15_card; + if (!p15card) + goto out; + + if ((rv = sc_detect_card_presence(p15card->card->reader)) <= 0) + goto out; + if (rv & SC_READER_CARD_CHANGED) + return SC_READER_CARD_CHANGED; + else if (rv & SC_READER_REMOVED) + return SC_READER_REMOVED; + else if (rv & SC_READER_CARD_PRESENT) + return SC_READER_CARD_PRESENT; +out: + return 0; +} + struct sc_pkcs15_object * _get_auth_object_by_name(struct sc_pkcs15_card *p15card, char *name) diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h index bc7baa7e74..4a8dac8de6 100644 --- a/src/pkcs11/sc-pkcs11.h +++ b/src/pkcs11/sc-pkcs11.h @@ -413,6 +413,7 @@ CK_RV slot_token_removed(CK_SLOT_ID id); CK_RV slot_allocate(struct sc_pkcs11_slot **, struct sc_pkcs11_card *); CK_RV slot_find_changed(CK_SLOT_ID_PTR idp, int mask); int slot_get_logged_in_state(struct sc_pkcs11_slot *slot); +int slot_get_card_state(struct sc_pkcs11_slot *slot); /* Login tracking functions */ CK_RV restore_login_state(struct sc_pkcs11_slot *slot); From 2dcb0ee396c5283380a76fa1c4518176e832e6c0 Mon Sep 17 00:00:00 2001 From: Veronika Hanulikova Date: Wed, 22 Mar 2023 16:19:25 +0100 Subject: [PATCH 2/6] Differentiate between changed and logged out card in C_GetSessionInfo Do not delete all sessions, when the card was logged out during operation. Instead, check whether the card was changed and by logging out only set correct flag. --- src/pkcs11/pkcs11-session.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/pkcs11/pkcs11-session.c b/src/pkcs11/pkcs11-session.c index e938818376..d32e7a5789 100644 --- a/src/pkcs11/pkcs11-session.c +++ b/src/pkcs11/pkcs11-session.c @@ -253,6 +253,7 @@ CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_RV rv; struct sc_pkcs11_session *session; struct sc_pkcs11_slot *slot; + int card_status = 0, logged_out = 0; if (pInfo == NULL_PTR) return CKR_ARGUMENTS_BAD; @@ -275,16 +276,20 @@ CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, /* the session's handle */ pInfo->ulDeviceError = 0; slot = session->slot; - if (!sc_pkcs11_conf.atomic && slot->login_user >= 0 && - slot_get_logged_in_state(slot) == SC_PIN_STATE_LOGGED_OUT) { + card_status = slot_get_card_state(slot); + if (card_status != SC_READER_CARD_PRESENT) { + /* Card was removed or reinserted, invalidate all sessions */ slot->login_user = -1; sc_pkcs11_close_all_sessions(session->slot->id); rv = CKR_SESSION_HANDLE_INVALID; goto out; } - if (slot->login_user == CKU_SO) { + + /* Check whether the user is logged in the card */ + logged_out = (slot_get_logged_in_state(slot) == SC_PIN_STATE_LOGGED_OUT); + if (slot->login_user == CKU_SO && !logged_out) { pInfo->state = CKS_RW_SO_FUNCTIONS; - } else if (slot->login_user == CKU_USER || !(slot->token_info.flags & CKF_LOGIN_REQUIRED)) { + } else if ((slot->login_user == CKU_USER && !logged_out) || !(slot->token_info.flags & CKF_LOGIN_REQUIRED)) { pInfo->state = (session->flags & CKF_RW_SESSION) ? CKS_RW_USER_FUNCTIONS : CKS_RO_USER_FUNCTIONS; } else { From c528c27616881e6cc3afef2da50193603a572c00 Mon Sep 17 00:00:00 2001 From: Veronika Hanulikova Date: Fri, 14 Apr 2023 14:52:10 +0200 Subject: [PATCH 3/6] Return all flags when checking the card presence --- src/pkcs11/framework-pkcs15.c | 7 +------ src/pkcs11/pkcs11-session.c | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index 11ea867023..e35324c805 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -1420,12 +1420,7 @@ int slot_get_card_state(struct sc_pkcs11_slot *slot) if ((rv = sc_detect_card_presence(p15card->card->reader)) <= 0) goto out; - if (rv & SC_READER_CARD_CHANGED) - return SC_READER_CARD_CHANGED; - else if (rv & SC_READER_REMOVED) - return SC_READER_REMOVED; - else if (rv & SC_READER_CARD_PRESENT) - return SC_READER_CARD_PRESENT; + return rv; out: return 0; } diff --git a/src/pkcs11/pkcs11-session.c b/src/pkcs11/pkcs11-session.c index d32e7a5789..01ce7676c9 100644 --- a/src/pkcs11/pkcs11-session.c +++ b/src/pkcs11/pkcs11-session.c @@ -277,7 +277,7 @@ CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, /* the session's handle */ slot = session->slot; card_status = slot_get_card_state(slot); - if (card_status != SC_READER_CARD_PRESENT) { + if (!(card_status & SC_READER_CARD_PRESENT)) { /* Card was removed or reinserted, invalidate all sessions */ slot->login_user = -1; sc_pkcs11_close_all_sessions(session->slot->id); From 3d21cba957cc6972a1a672e8a508e1e6b5f5bba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Veronika=20Hanul=C3=ADkov=C3=A1?= Date: Tue, 9 May 2023 09:52:51 +0200 Subject: [PATCH 4/6] Remove session when card is changed --- src/pkcs11/pkcs11-session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pkcs11/pkcs11-session.c b/src/pkcs11/pkcs11-session.c index 01ce7676c9..68b6c57b8d 100644 --- a/src/pkcs11/pkcs11-session.c +++ b/src/pkcs11/pkcs11-session.c @@ -277,7 +277,7 @@ CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, /* the session's handle */ slot = session->slot; card_status = slot_get_card_state(slot); - if (!(card_status & SC_READER_CARD_PRESENT)) { + if (!(card_status & SC_READER_CARD_PRESENT) || card_status & SC_READER_CARD_CHANGED) { /* Card was removed or reinserted, invalidate all sessions */ slot->login_user = -1; sc_pkcs11_close_all_sessions(session->slot->id); From ecd845c2f7190afc46f39ebbae0dda7b55019994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Veronika=20Hanul=C3=ADkov=C3=A1?= Date: Tue, 9 May 2023 09:53:20 +0200 Subject: [PATCH 5/6] Fix PCSC handling when reader is removed --- src/libopensc/reader-pcsc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 04d5ac8fdd..8c2f98c9b1 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -364,7 +364,7 @@ static int refresh_attributes(sc_reader_t *reader) if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) return SC_ERROR_NOT_ALLOWED; - if (priv->reader_state.szReader == NULL || reader->ctx->flags & SC_READER_REMOVED) { + if (priv->reader_state.szReader == NULL || reader->flags & SC_READER_REMOVED) { priv->reader_state.szReader = reader->name; priv->reader_state.dwCurrentState = SCARD_STATE_UNAWARE; priv->reader_state.dwEventState = SCARD_STATE_UNAWARE; @@ -394,6 +394,8 @@ static int refresh_attributes(sc_reader_t *reader) #endif || rv == (LONG)SCARD_E_SERVICE_STOPPED) { reader->flags &= ~(SC_READER_CARD_PRESENT); + reader->flags |= SC_READER_REMOVED; + priv->gpriv->removed_reader = reader; SC_FUNC_RETURN(reader->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); } From d04ec3ea3c7cb3b47de28492b4eea5ed1be2cc0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Veronika=20Hanul=C3=ADkov=C3=A1?= Date: Thu, 18 May 2023 14:18:04 +0200 Subject: [PATCH 6/6] Remove unnecessary goto statement --- src/pkcs11/framework-pkcs15.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index e35324c805..9c7ec67fb4 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -1408,21 +1408,19 @@ int slot_get_card_state(struct sc_pkcs11_slot *slot) int rv = 0; if (slot->p11card == NULL) { - goto out; + return 0; } fw_data = (struct pkcs15_fw_data *) slot->p11card->fws_data[slot->fw_data_idx]; if (!fw_data) - goto out; + return 0; p15card = fw_data->p15_card; if (!p15card) - goto out; + return 0; if ((rv = sc_detect_card_presence(p15card->card->reader)) <= 0) - goto out; + return 0; return rv; -out: - return 0; } From 5e79a2a4abdd523cfff19824718bbb0d8ced7320 Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Thu, 9 Apr 2020 16:29:44 +0200 Subject: [PATCH] fixed compiler warning --- src/tools/opensc-notify.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/opensc-notify.c b/src/tools/opensc-notify.c index 87d66c67..b1afc62d 100644 --- a/src/tools/opensc-notify.c +++ b/src/tools/opensc-notify.c @@ -189,7 +189,9 @@ static int cancellation_fd[] = {-1, -1}; void sig_handler(int sig) { run_daemon = 0; - write(cancellation_fd[1], &sig, sizeof sig); + if (-1 == write(cancellation_fd[1], &sig, sizeof sig)) { + fprintf(stderr, "Failed immediate cancellation: %s", strerror(errno)); + } } static void *cancellation_proc(void *arg) -- 2.40.1 From 843779fe6e0f345f483f9ce9c9739913502391eb Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Thu, 23 Apr 2020 08:45:24 +0200 Subject: [PATCH] opensc-notify: respect signal safety Thanks, Marcin. https://github.com/OpenSC/OpenSC/commit/5e79a2a4abdd523cfff19824718bbb0d8ced7320#r38486829 --- src/tools/opensc-notify.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/tools/opensc-notify.c b/src/tools/opensc-notify.c index b1afc62d..75767aba 100644 --- a/src/tools/opensc-notify.c +++ b/src/tools/opensc-notify.c @@ -189,9 +189,7 @@ static int cancellation_fd[] = {-1, -1}; void sig_handler(int sig) { run_daemon = 0; - if (-1 == write(cancellation_fd[1], &sig, sizeof sig)) { - fprintf(stderr, "Failed immediate cancellation: %s", strerror(errno)); - } + (void)write(cancellation_fd[1], &sig, sizeof sig); } static void *cancellation_proc(void *arg) -- 2.40.1 From 7936bdef15c71139a6a6159cabaf9e6101565add Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Wed, 29 Apr 2020 01:25:33 +0200 Subject: [PATCH] resolve unused variable warning on newer gcc --- src/tools/opensc-notify.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/opensc-notify.c b/src/tools/opensc-notify.c index 75767aba..3b61c498 100644 --- a/src/tools/opensc-notify.c +++ b/src/tools/opensc-notify.c @@ -189,7 +189,10 @@ static int cancellation_fd[] = {-1, -1}; void sig_handler(int sig) { run_daemon = 0; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" (void)write(cancellation_fd[1], &sig, sizeof sig); +#pragma GCC diagnostic pop } static void *cancellation_proc(void *arg) -- 2.40.1 From 1202eceeefd5ffab45648d41ed0a3076cac10920 Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Wed, 29 Apr 2020 15:16:31 +0200 Subject: [PATCH] fixed wrong error --- src/tools/opensc-notify.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/opensc-notify.c b/src/tools/opensc-notify.c index 3b61c498..c67212b3 100644 --- a/src/tools/opensc-notify.c +++ b/src/tools/opensc-notify.c @@ -190,7 +190,7 @@ static int cancellation_fd[] = {-1, -1}; void sig_handler(int sig) { run_daemon = 0; #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-result" (void)write(cancellation_fd[1], &sig, sizeof sig); #pragma GCC diagnostic pop } -- 2.40.1