Skip to content

--reader silently selects the wrong reader when another reader's name is a prefix #109

@HaoChen-Roy

Description

@HaoChen-Roy

Summary

When multiple PC/SC readers are attached and one reader's name is a prefix of another's (e.g. two identical readers appear as ACS ACR1552 1S CL Reader PICC and ACS ACR1552 1S CL Reader PICC 01 on macOS),
passing --reader with the shorter/prefix name silently binds fdsm to the longer-named reader. fdsm prints Using card in <the wrong reader> with no warning.

Environment

  • fdsm: current master (26.01.3-SNAPSHOT); also reproducible on the most recent release JAR
  • OS: macOS 15 (Darwin 25.4.0)
  • JDK: OpenJDK 21
  • Readers: two ACS ACR1552 units attached simultaneously

Reproduction

  1. Attach two identical USB contactless readers. PC/SC assigns one the bare name (ACS ACR1552 1S CL Reader PICC) and the second a suffixed name (ACS ACR1552 1S CL Reader PICC 01).
Available readers:
- ACS ACR1552 1S CL Reader SAM
- ACS ACR1552 1S CL Reader SAM 01
- ACS ACR1552 1S CL Reader PICC
- ACS ACR1552 1S CL Reader PICC 01
  1. Place a card only on the …PICC 01 reader; leave the …PICC reader empty.
  2. Run:
java -jar fdsm.jar --reader "ACS ACR1552 1S CL Reader PICC" --offline --card-info

Expected

fdsm binds exactly to the named reader. Since that reader is empty, it fails fast (e.g. SCARD_E_NO_SMARTCARD).

Actual

Using card in ACS ACR1552 1S CL Reader PICC 01
UID: D65B4C15

fdsm silently falls through to the other reader whose name contains the requested string as a substring, and reads its card.

Root cause

tool/src/main/java/com/fidesmo/fdsm/Main.java, lines 262–273. The loop uses contains() on lowercased names (substring match rather than exact) and has no break, so when multiple readers match, the
last enumerated one wins. No card-presence or tiebreaking logic is applied.

Impact

Silent data-corruption path for anyone running fdsm against a station with more than one reader attached. Per the "FDSM for OEMs" docs, "Once a Batch ID is set it cannot be changed" — so a mis-matched
--reader during a --run <batching> operation writes a wrong, permanent Batch ID to the wrong device.

Proposed fix

Change the match to equalsIgnoreCase (still case-insensitive, but exact) and break on first match:

-        if (t.getName().toLowerCase().contains(reader.toLowerCase())) {
+        if (t.getName().equalsIgnoreCase(reader)) {
             terminal = t;
+            break;
         }

Workaround

Pass a --reader value that is not a prefix of any other reader's name (e.g. "…PICC 01" uniquely matches the second reader). There is no clean workaround for the shorter-named reader in a pair like the
above except physically disconnecting the other reader before each call.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions