opensc/SOURCES/opensc-0.20.0-reader-remova...

2174 lines
76 KiB
Diff

From 31d8c2dfd14ed01b430def2f46cc718ef4b595fc Mon Sep 17 00:00:00 2001
From: Frank Morgner <frankmorgner@gmail.com>
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; i<list_size(&virtual_slots); i++) {
- slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
- slot->flags &= ~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; i<list_size(&virtual_slots); i++) {
- slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
- slot->id = (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 <frankmorgner@gmail.com>
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 <deengert@gmail.com>
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; j<list_size(&virtual_slots); j++) {
+ slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, j);
+ if (slot->reader == 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; j<list_size(&virtual_slots); j++) {
+ slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, j);
+ if (slot->reader == 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 <frankmorgner@gmail.com>
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; j<list_size(&virtual_slots); j++) {
- slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, j);
- if (slot->reader == 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; j<list_size(&virtual_slots); j++) {
- slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, j);
- if (slot->reader == 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 <frankmorgner@gmail.com>
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 <frankmorgner@gmail.com>
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; i<list_size(&virtual_slots); i++) {
slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
/* the list of available slots contains:
- * - if present, virtual hotplug slot;
- * - without token(s), one empty slot per reader;
+ * - without token(s), at least one empty slot per reader;
* - any slot with token;
* - any slot that has already been seen;
*/
@@ -550,7 +549,7 @@ CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
sc_log(context, "C_GetSlotInfo(0x%lx)", slotID);
if (sc_pkcs11_conf.init_sloppy) {
- /* Most likely virtual_slots only contains the hotplug slot and has not
+ /* Most likely virtual_slots is empty and has not
* been initialized because the caller has *not* called C_GetSlotList
* before C_GetSlotInfo, as required by PKCS#11. Initialize
* virtual_slots to make things work and hope the caller knows what
diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c
index 2fb495d295..bf91b6bc57 100644
--- a/src/pkcs11/slot.c
+++ b/src/pkcs11/slot.c
@@ -37,15 +37,26 @@ static struct sc_pkcs11_framework_ops *frameworks[] = {
NULL
};
-static struct sc_pkcs11_slot * reader_get_slot(sc_reader_t *reader)
+static struct sc_pkcs11_slot * reader_reclaim_slot(sc_reader_t *reader)
{
unsigned int i;
+ CK_UTF8CHAR slotDescription[64];
+ CK_UTF8CHAR manufacturerID[32];
+
+ strcpy_bp(slotDescription, reader->name, 64);
+ strcpy_bp(manufacturerID, reader->vendor, 32);
/* Locate a slot related to the reader */
for (i = 0; i<list_size(&virtual_slots); i++) {
sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
if (slot->reader == 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; i<list_size(&virtual_slots); i++) {
+ sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
+ if (slot->reader == 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; i<list_size(&virtual_slots); i++) {
+ sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
+ if (slot->reader == 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 <frankmorgner@gmail.com>
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 <frankmorgner@gmail.com>
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 <errno.h>
+#include <pthread.h>
#include <signal.h>
+#include <unistd.h>
+
+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 <frankmorgner@gmail.com>
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 <frankmorgner@gmail.com>
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 <gio/gio.h>
+#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 <frankmorgner@gmail.com>
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 <zoltan.kelemen@saabgroup.com>
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 <frifl@cendio.se>
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 <frifl@cendio.se>
---
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 <frifl@cendio.se>
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 <frifl@cendio.se>
---
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 <frifl@cendio.se>
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 <frifl@cendio.se>
---
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 <frifl@cendio.se>
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 <frifl@cendio.se>
---
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 <vhanulik@redhat.com>
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?= <timo.teras@iki.fi>
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 <xhanulik@fi.muni.cz>
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 <xhanulik@fi.muni.cz>
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 <xhanulik@fi.muni.cz>
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?= <vhanulik@redhat.com>
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?= <vhanulik@redhat.com>
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?= <vhanulik@redhat.com>
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 <frankmorgner@gmail.com>
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 <frankmorgner@gmail.com>
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 <frankmorgner@gmail.com>
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 <frankmorgner@gmail.com>
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
From 295f399304644e6b0acde267ac410d0aae4a1aee Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Fri, 24 Apr 2020 10:18:03 +0200
Subject: [PATCH] reader-pcsc: Avoid use after free (CID 355473)
---
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 34dc821bf..b3da6fc88 100644
--- a/src/libopensc/reader-pcsc.c
+++ b/src/libopensc/reader-pcsc.c
@@ -2550,10 +2550,10 @@ int pcsc_use_reader(sc_context_t *ctx, void * pcsc_context_handle, void * pcsc_c
priv->pcsc_card = card_handle;
detect_protocol(reader, card_handle);
detect_reader_features(reader, card_handle);
+ gpriv->attached_reader = reader;
} else {
_sc_delete_reader(ctx, reader);
}
- gpriv->attached_reader = reader;
}
out:
--
2.41.0
From ca01aa7a8edc8280a5ceadebb472c2e3c198d8c2 Mon Sep 17 00:00:00 2001
From: Peter Popovec <popovec.peter@gmail.com>
Date: Thu, 20 Jan 2022 12:26:19 +0100
Subject: [PATCH] Coverity Scan fix, CID 374840: Null pointer dereferences
(REVERSE_INULL)
modified: src/pkcs11/slot.c
---
src/pkcs11/slot.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c
index ea8a3ac2a..86cb3b884 100644
--- a/src/pkcs11/slot.c
+++ b/src/pkcs11/slot.c
@@ -69,15 +69,17 @@ static struct sc_pkcs11_slot * reader_reclaim_slot(sc_reader_t *reader)
CK_UTF8CHAR slotDescription[64];
CK_UTF8CHAR manufacturerID[32];
+ if (reader == NULL)
+ return NULL;
strcpy_bp(slotDescription, reader->name, 64);
strcpy_bp(manufacturerID, reader->vendor, 32);
/* Locate a slot related to the reader */
for (i = 0; i<list_size(&virtual_slots); i++) {
sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
if (slot->reader == reader)
return slot;
- if (slot->reader == NULL && reader != NULL
+ if (slot->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
--
2.41.0