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: I58b71f9562e152e7ed21b55d7b876bba481b01f8changes/11/20811/2
parent
4f5c79d627
commit
753c8aa87a
|
@ -108,6 +108,9 @@ bankd expects a CSV file `bankd_pcsc_slots.csv` in the current working directory
|
|||
|
||||
This CSV file specifies the mapping between the string names of the PCSC
|
||||
readers and the RSPRO bandk/slot numbers. The format is as follows:
|
||||
* first column: bankd number
|
||||
* second column: slot number within bankd
|
||||
* third column: extended POSIX regular expression matching the slot
|
||||
|
||||
.Example: CSV file mapping bankd slots 0..4 to an ACS ACR33U-A1 reader slots
|
||||
----
|
||||
|
@ -128,4 +131,24 @@ Scanning present readers...
|
|||
----
|
||||
|
||||
In this example, there's only a single PC/SC reader available, and it has a string of
|
||||
"Alcor Micro AU9560 00 00" which needs to be copy-pasted into the CSV file.
|
||||
"Alcor Micro AU9560 00 00" which needs to be used in the CSV file.
|
||||
|
||||
NOTE:: If the reader name contains any special characters, they might need to be escaped according
|
||||
to the extended POSIX regular expression syntax. See `man 7 regex` for a reference.
|
||||
|
||||
.Example: CSV file mapping bankd slots 0..7 to a sysmoOCTSIM:
|
||||
----
|
||||
"1","0","sysmocom sysmoOCTSIM \[CCID\] \(ab19180f3335355320202034463a15ff\) [0-9]{2} 00"
|
||||
"1","1","sysmocom sysmoOCTSIM \[CCID\] \(ab19180f3335355320202034463a15ff\) [0-9]{2} 01"
|
||||
"1","2","sysmocom sysmoOCTSIM \[CCID\] \(ab19180f3335355320202034463a15ff\) [0-9]{2} 02"
|
||||
"1","3","sysmocom sysmoOCTSIM \[CCID\] \(ab19180f3335355320202034463a15ff\) [0-9]{2} 03"
|
||||
"1","4","sysmocom sysmoOCTSIM \[CCID\] \(ab19180f3335355320202034463a15ff\) [0-9]{2} 04"
|
||||
"1","5","sysmocom sysmoOCTSIM \[CCID\] \(ab19180f3335355320202034463a15ff\) [0-9]{2} 05"
|
||||
"1","6","sysmocom sysmoOCTSIM \[CCID\] \(ab19180f3335355320202034463a15ff\) [0-9]{2} 06"
|
||||
"1","7","sysmocom sysmoOCTSIM \[CCID\] \(ab19180f3335355320202034463a15ff\) [0-9]{2} 07"
|
||||
----
|
||||
|
||||
In the above example, the +\[CCID\]+ and the +\(serialnumber\)+ both had to be escaped.
|
||||
|
||||
The +[0-9]\{2\}+ construct exists to perform wildcard matching, no matter which particular two-digit number
|
||||
pcscd decides to use.
|
||||
|
|
|
@ -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 @@ struct pcsc_slot_name {
|
|||
/* 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 @@ static void cb1(void *s, size_t len, void *data)
|
|||
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 @@ static void cb2(int c, void *data)
|
|||
{
|
||||
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 @@ const char *bankd_pcsc_get_slot_name(struct bankd *bankd, const struct bank_slot
|
|||
|
||||
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 @@ const char *bankd_pcsc_get_slot_name(struct bankd *bankd, const struct bank_slot
|
|||
#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 @@ end:
|
|||
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 @@ static int pcsc_open_card(struct bankd_worker *worker)
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue