From 0809f300b775307e580d40dcd2329cb158133a1a Mon Sep 17 00:00:00 2001 From: str4d Date: Sun, 12 Feb 2023 17:22:05 +0000 Subject: [PATCH] Return errors from `YubiKey::open_by_serial` that indicate a key may exist (#477) * Return errors from `YubiKey::open_by_serial` that indicate a key may exist The only such error at the moment is `pcsc::Error::SharingViolation`, which indicates a transient failure to access a specific reader that could have been the one we needed (and so a future retry might succeed). Closes iqlusioninc/yubikey.rs#458. * Avoid resetting unused devices in YubiKey::open_by_serial We only connect to readers so that we can determine their serial. We now try to ensure that the order in which we connect to them doesn't have an effect on their state after we are done. --- src/yubikey.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/yubikey.rs b/src/yubikey.rs index 39ef400..6a699e3 100644 --- a/src/yubikey.rs +++ b/src/yubikey.rs @@ -205,19 +205,40 @@ impl YubiKey { pub fn open_by_serial(serial: Serial) -> Result { let mut readers = Context::open()?; + let mut open_error = None; + for reader in readers.iter()? { let yubikey = match reader.open() { Ok(yk) => yk, - Err(_) => continue, + Err(e) => { + // Save the first error we see that indicates we might have been able + // to find a matching YubiKey. + if open_error.is_none() { + if let Error::PcscError { + inner: Some(pcsc::Error::SharingViolation), + } = e + { + open_error = Some(e); + } + } + continue; + } }; if serial == yubikey.serial() { return Ok(yubikey); + } else { + // We didn't want this YubiKey; don't reset it. + let _ = yubikey.disconnect(pcsc::Disposition::LeaveCard); } } - error!("no YubiKey detected with serial: {}", serial); - Err(Error::NotFound) + Err(if let Some(e) = open_error { + e + } else { + error!("no YubiKey detected with serial: {}", serial); + Error::NotFound + }) } /// Reconnect to a YubiKey.