bankd: regex matching of reader names
So far, bankd did a 1:1 string match of the CSV file line against
the reader name. As pcsc-lite reader names unfortunately tend to
change at times, we introduce matching by regular expressions in
this patch.
Change-Id: I58b71f9562e152e7ed21b55d7b876bba481b01f8
diff --git a/src/bankd/bankd_pcsc.c b/src/bankd/bankd_pcsc.c
index f6e3683..e0b349c 100644
--- a/src/bankd/bankd_pcsc.c
+++ b/src/bankd/bankd_pcsc.c
@@ -1,4 +1,4 @@
-/* (C) 2018-2019 by Harald Welte <laforge@gnumonks.org>
+/* (C) 2018-2020 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@@ -26,6 +26,8 @@
#include <osmocom/core/utils.h>
#include <csv.h>
+#include <regex.h>
+#include <errno.h>
#include "bankd.h"
@@ -34,9 +36,19 @@
/* RSPRO bank slot number */
struct bank_slot slot;
/* String name of the reader in PC/SC world */
- const char *name;
+ const char *name_regex;
};
+/* return a talloc-allocated string containing human-readable POSIX regex error */
+static char *get_regerror(void *ctx, int errcode, regex_t *compiled)
+{
+ size_t len = regerror(errcode, compiled, NULL, 0);
+ char *buffer = talloc_size(ctx, len);
+ OSMO_ASSERT(buffer);
+ regerror(errcode, compiled, buffer, len);
+ return buffer;
+}
+
enum parser_state_name {
ST_NONE,
ST_BANK_NR,
@@ -76,7 +88,7 @@
break;
case ST_PCSC_NAME:
OSMO_ASSERT(ps->cur);
- ps->cur->name = talloc_strdup(ps->cur, field);
+ ps->cur->name_regex = talloc_strdup(ps->cur, field);
break;
default:
OSMO_ASSERT(0);
@@ -87,9 +99,23 @@
{
struct parser_state *ps = data;
struct pcsc_slot_name *sn = ps->cur;
+ regex_t compiled_name;
+ int rc;
- printf("PC/SC slot name: %u/%u -> '%s'\n", sn->slot.bank_id, sn->slot.slot_nr, sn->name);
- llist_add_tail(&sn->list, &ps->bankd->pcsc_slot_names);
+ printf("PC/SC slot name: %u/%u -> regex '%s'\n", sn->slot.bank_id, sn->slot.slot_nr, sn->name_regex);
+
+ memset(&compiled_name, 0, sizeof(compiled_name));
+
+ rc = regcomp(&compiled_name, sn->name_regex, REG_EXTENDED);
+ if (rc != 0) {
+ char *errmsg = get_regerror(sn, rc, &compiled_name);
+ fprintf(stderr, "Error compiling regex '%s': %s - Ignoring\n", sn->name_regex, errmsg);
+ talloc_free(errmsg);
+ talloc_free(sn);
+ } else {
+ llist_add_tail(&sn->list, &ps->bankd->pcsc_slot_names);
+ }
+ regfree(&compiled_name);
ps->state = ST_BANK_NR;
ps->cur = NULL;
@@ -134,7 +160,7 @@
llist_for_each_entry(cur, &bankd->pcsc_slot_names, list) {
if (bank_slot_equals(&cur->slot, slot))
- return cur->name;
+ return cur->name_regex;
}
return NULL;
}
@@ -144,9 +170,12 @@
#include <winscard.h>
#include <pcsclite.h>
+#define LOGW_PCSC_ERROR(w, rv, text) \
+ LOGW((w), text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv)
+
#define PCSC_ERROR(w, rv, text) \
if (rv != SCARD_S_SUCCESS) { \
- LOGW((w), text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv); \
+ LOGW_PCSC_ERROR(w, rv, text); \
goto end; \
} else { \
LOGW((w), ": OK\n"); \
@@ -170,6 +199,57 @@
return rc;
}
+
+static int pcsc_connect_slot_regex(struct bankd_worker *worker)
+{
+ DWORD dwReaders = SCARD_AUTOALLOCATE;
+ LPSTR mszReaders = NULL;
+ regex_t compiled_name;
+ int result = -1;
+ LONG rc;
+ char *p;
+
+ LOGW(worker, "Attempting to find card/slot using regex '%s'\n", worker->reader.name);
+
+ rc = regcomp(&compiled_name, worker->reader.name, REG_EXTENDED);
+ if (rc != 0) {
+ LOGW(worker, "Error compiling RegEx over name '%s'\n", worker->reader.name);
+ return -EINVAL;
+ }
+
+ rc = SCardListReaders(worker->reader.pcsc.hContext, NULL, (LPSTR)&mszReaders, &dwReaders);
+ if (rc != SCARD_S_SUCCESS) {
+ LOGW_PCSC_ERROR(worker, rc, "SCardListReaders");
+ goto out_regfree;
+ }
+
+ p = mszReaders;
+ while (*p) {
+ DWORD dwActiveProtocol;
+ int r = regexec(&compiled_name, p, 0, NULL, 0);
+ if (r == 0) {
+ LOGW(worker, "Attempting to open card/slot '%s'\n", p);
+ rc = SCardConnect(worker->reader.pcsc.hContext, p, SCARD_SHARE_SHARED,
+ SCARD_PROTOCOL_T0, &worker->reader.pcsc.hCard,
+ &dwActiveProtocol);
+ if (rc == SCARD_S_SUCCESS)
+ result = 0;
+ else
+ LOGW_PCSC_ERROR(worker, rc, "SCardConnect");
+ break;
+ }
+ p += strlen(p) + 1;
+ }
+
+ SCardFreeMemory(worker->reader.pcsc.hContext, mszReaders);
+
+out_regfree:
+ regfree(&compiled_name);
+
+ return result;
+}
+
+
static int pcsc_open_card(struct bankd_worker *worker)
{
long rc;
@@ -182,14 +262,13 @@
}
if (!worker->reader.pcsc.hCard) {
- LOGW(worker, "Attempting to open card/slot '%s'\n", worker->reader.name);
- DWORD dwActiveProtocol;
- rc = SCardConnect(worker->reader.pcsc.hContext, worker->reader.name, SCARD_SHARE_SHARED,
- SCARD_PROTOCOL_T0, &worker->reader.pcsc.hCard, &dwActiveProtocol);
- PCSC_ERROR(worker, rc, "SCardConnect")
+ rc = pcsc_connect_slot_regex(worker);
+ if (rc != 0)
+ goto end;
}
rc = pcsc_get_atr(worker);
+
end:
return rc;
}