1#![allow(deprecated)]
102#![allow(clippy::bad_bit_mask)]
103
104use std::ffi::{CStr, CString};
105use std::mem::{forget, transmute};
106use std::ops::Deref;
107use std::os::raw::c_char;
108use std::ptr::{null, null_mut};
109use std::sync::Arc;
110
111use bitflags::bitflags;
112pub use pcsc_sys as ffi;
113
114use ffi::{DWORD, LONG};
115
116const DUMMY_LONG: LONG = -1;
119const DUMMY_DWORD: DWORD = 0xdead_beef;
120
121bitflags! {
126 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
129 pub struct State: DWORD {
130 const UNAWARE = ffi::SCARD_STATE_UNAWARE;
131 const IGNORE = ffi::SCARD_STATE_IGNORE;
132 const CHANGED = ffi::SCARD_STATE_CHANGED;
133 const UNKNOWN = ffi::SCARD_STATE_UNKNOWN;
134 const UNAVAILABLE = ffi::SCARD_STATE_UNAVAILABLE;
135 const EMPTY = ffi::SCARD_STATE_EMPTY;
136 const PRESENT = ffi::SCARD_STATE_PRESENT;
137 const ATRMATCH = ffi::SCARD_STATE_ATRMATCH;
138 const EXCLUSIVE = ffi::SCARD_STATE_EXCLUSIVE;
139 const INUSE = ffi::SCARD_STATE_INUSE;
140 const MUTE = ffi::SCARD_STATE_MUTE;
141 const UNPOWERED = ffi::SCARD_STATE_UNPOWERED;
142 }
143}
144
145impl State {
147 #[deprecated = "use the safe `from_bits_retain` method instead"]
148 pub unsafe fn from_bits_unchecked(bits: DWORD) -> Self {
149 Self::from_bits_retain(bits)
150 }
151}
152
153bitflags! {
154 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
163 pub struct Status: DWORD {
164 const UNKNOWN = {
165 #[cfg(not(target_os = "windows"))] { ffi::SCARD_UNKNOWN }
166 #[cfg(target_os = "windows")] { 0x0001 }
167 };
168 const ABSENT = {
169 #[cfg(not(target_os = "windows"))] { ffi::SCARD_ABSENT }
170 #[cfg(target_os = "windows")] { 0x0002 }
171 };
172 const PRESENT = {
173 #[cfg(not(target_os = "windows"))] { ffi::SCARD_PRESENT }
174 #[cfg(target_os = "windows")] { 0x0004 }
175 };
176 const SWALLOWED = {
177 #[cfg(not(target_os = "windows"))] { ffi::SCARD_SWALLOWED }
178 #[cfg(target_os = "windows")] { 0x0008 }
179 };
180 const POWERED = {
181 #[cfg(not(target_os = "windows"))] { ffi::SCARD_POWERED }
182 #[cfg(target_os = "windows")] { 0x0010 }
183 };
184 const NEGOTIABLE = {
185 #[cfg(not(target_os = "windows"))] { ffi::SCARD_NEGOTIABLE }
186 #[cfg(target_os = "windows")] { 0x0020 }
187 };
188 const SPECIFIC = {
189 #[cfg(not(target_os = "windows"))] { ffi::SCARD_SPECIFIC }
190 #[cfg(target_os = "windows")] { 0x0040 }
191 };
192 }
193}
194
195impl Status {
196 fn from_raw(raw_status: DWORD) -> Self {
197 #[cfg(target_os = "windows")]
198 match raw_status {
199 ffi::SCARD_UNKNOWN => Status::UNKNOWN,
200 ffi::SCARD_ABSENT => Status::ABSENT,
201 ffi::SCARD_PRESENT => Status::PRESENT,
202 ffi::SCARD_SWALLOWED => Status::SWALLOWED,
203 ffi::SCARD_POWERED => Status::POWERED,
204 ffi::SCARD_NEGOTIABLE => Status::NEGOTIABLE,
205 ffi::SCARD_SPECIFIC => Status::SPECIFIC,
206 _ => Status::empty(),
207 }
208
209 #[cfg(not(target_os = "windows"))]
210 Status::from_bits_truncate(raw_status)
211 }
212
213 #[deprecated = "use the safe `from_bits_retain` method instead"]
215 pub unsafe fn from_bits_unchecked(bits: DWORD) -> Self {
216 Self::from_bits_retain(bits)
217 }
218}
219
220#[repr(u32)]
222#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
223pub enum ShareMode {
224 Exclusive = ffi::SCARD_SHARE_EXCLUSIVE as u32,
225 Shared = ffi::SCARD_SHARE_SHARED as u32,
226 Direct = ffi::SCARD_SHARE_DIRECT as u32,
227}
228
229impl ShareMode {
230 fn into_raw(self) -> DWORD {
231 DWORD::from(self as u32)
232 }
233}
234
235#[repr(u32)]
237#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
238pub enum Protocol {
239 T0 = ffi::SCARD_PROTOCOL_T0 as u32,
240 T1 = ffi::SCARD_PROTOCOL_T1 as u32,
241 RAW = ffi::SCARD_PROTOCOL_RAW as u32,
242}
243
244impl Protocol {
245 fn from_raw(raw: DWORD) -> Option<Protocol> {
246 match raw {
247 ffi::SCARD_PROTOCOL_UNDEFINED => None,
248 ffi::SCARD_PROTOCOL_T0 => Some(Protocol::T0),
249 ffi::SCARD_PROTOCOL_T1 => Some(Protocol::T1),
250 ffi::SCARD_PROTOCOL_RAW => Some(Protocol::RAW),
251 _ => panic!("impossible protocol: {:#x}", raw),
254 }
255 }
256}
257
258bitflags! {
259 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
262 pub struct Protocols: DWORD {
263 const UNDEFINED = ffi::SCARD_PROTOCOL_UNDEFINED;
264 const T0 = ffi::SCARD_PROTOCOL_T0;
265 const T1 = ffi::SCARD_PROTOCOL_T1;
266 const RAW = ffi::SCARD_PROTOCOL_RAW;
267 const ANY = ffi::SCARD_PROTOCOL_ANY;
268 }
269}
270
271impl Protocols {
273 #[deprecated = "use the safe `from_bits_retain` method instead"]
274 pub unsafe fn from_bits_unchecked(bits: DWORD) -> Self {
275 Self::from_bits_retain(bits)
276 }
277}
278
279#[repr(u32)]
281#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
282pub enum Disposition {
283 LeaveCard = ffi::SCARD_LEAVE_CARD as u32,
284 ResetCard = ffi::SCARD_RESET_CARD as u32,
285 UnpowerCard = ffi::SCARD_UNPOWER_CARD as u32,
286 EjectCard = ffi::SCARD_EJECT_CARD as u32,
287}
288
289impl Disposition {
290 fn into_raw(self) -> DWORD {
291 DWORD::from(self as u32)
292 }
293}
294
295#[repr(u32)]
302#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
303pub enum Error {
304 InternalError = ffi::SCARD_F_INTERNAL_ERROR as u32,
306 Cancelled = ffi::SCARD_E_CANCELLED as u32,
307 InvalidHandle = ffi::SCARD_E_INVALID_HANDLE as u32,
308 InvalidParameter = ffi::SCARD_E_INVALID_PARAMETER as u32,
309 InvalidTarget = ffi::SCARD_E_INVALID_TARGET as u32,
310 NoMemory = ffi::SCARD_E_NO_MEMORY as u32,
311 WaitedTooLong = ffi::SCARD_F_WAITED_TOO_LONG as u32,
312 InsufficientBuffer = ffi::SCARD_E_INSUFFICIENT_BUFFER as u32,
313 UnknownReader = ffi::SCARD_E_UNKNOWN_READER as u32,
314 Timeout = ffi::SCARD_E_TIMEOUT as u32,
315 SharingViolation = ffi::SCARD_E_SHARING_VIOLATION as u32,
316 NoSmartcard = ffi::SCARD_E_NO_SMARTCARD as u32,
317 UnknownCard = ffi::SCARD_E_UNKNOWN_CARD as u32,
318 CantDispose = ffi::SCARD_E_CANT_DISPOSE as u32,
319 ProtoMismatch = ffi::SCARD_E_PROTO_MISMATCH as u32,
320 NotReady = ffi::SCARD_E_NOT_READY as u32,
321 InvalidValue = ffi::SCARD_E_INVALID_VALUE as u32,
322 SystemCancelled = ffi::SCARD_E_SYSTEM_CANCELLED as u32,
323 CommError = ffi::SCARD_F_COMM_ERROR as u32,
324 UnknownError = ffi::SCARD_F_UNKNOWN_ERROR as u32,
325 InvalidAtr = ffi::SCARD_E_INVALID_ATR as u32,
326 NotTransacted = ffi::SCARD_E_NOT_TRANSACTED as u32,
327 ReaderUnavailable = ffi::SCARD_E_READER_UNAVAILABLE as u32,
328 Shutdown = ffi::SCARD_P_SHUTDOWN as u32,
329 PciTooSmall = ffi::SCARD_E_PCI_TOO_SMALL as u32,
330 ReaderUnsupported = ffi::SCARD_E_READER_UNSUPPORTED as u32,
331 DuplicateReader = ffi::SCARD_E_DUPLICATE_READER as u32,
332 CardUnsupported = ffi::SCARD_E_CARD_UNSUPPORTED as u32,
333 NoService = ffi::SCARD_E_NO_SERVICE as u32,
334 ServiceStopped = ffi::SCARD_E_SERVICE_STOPPED as u32,
335 #[cfg(target_os = "windows")]
336 Unexpected = ffi::SCARD_E_UNEXPECTED as u32,
337 IccInstallation = ffi::SCARD_E_ICC_INSTALLATION as u32,
338 IccCreateorder = ffi::SCARD_E_ICC_CREATEORDER as u32,
339 UnsupportedFeature = ffi::SCARD_E_UNSUPPORTED_FEATURE as u32,
340 DirNotFound = ffi::SCARD_E_DIR_NOT_FOUND as u32,
341 FileNotFound = ffi::SCARD_E_FILE_NOT_FOUND as u32,
342 NoDir = ffi::SCARD_E_NO_DIR as u32,
343 NoFile = ffi::SCARD_E_NO_FILE as u32,
344 NoAccess = ffi::SCARD_E_NO_ACCESS as u32,
345 WriteTooMany = ffi::SCARD_E_WRITE_TOO_MANY as u32,
346 BadSeek = ffi::SCARD_E_BAD_SEEK as u32,
347 InvalidChv = ffi::SCARD_E_INVALID_CHV as u32,
348 UnknownResMng = ffi::SCARD_E_UNKNOWN_RES_MNG as u32,
349 NoSuchCertificate = ffi::SCARD_E_NO_SUCH_CERTIFICATE as u32,
350 CertificateUnavailable = ffi::SCARD_E_CERTIFICATE_UNAVAILABLE as u32,
351 NoReadersAvailable = ffi::SCARD_E_NO_READERS_AVAILABLE as u32,
352 CommDataLost = ffi::SCARD_E_COMM_DATA_LOST as u32,
353 NoKeyContainer = ffi::SCARD_E_NO_KEY_CONTAINER as u32,
354 ServerTooBusy = ffi::SCARD_E_SERVER_TOO_BUSY as u32,
355 UnsupportedCard = ffi::SCARD_W_UNSUPPORTED_CARD as u32,
359 UnresponsiveCard = ffi::SCARD_W_UNRESPONSIVE_CARD as u32,
360 UnpoweredCard = ffi::SCARD_W_UNPOWERED_CARD as u32,
361 ResetCard = ffi::SCARD_W_RESET_CARD as u32,
362 RemovedCard = ffi::SCARD_W_REMOVED_CARD as u32,
363
364 SecurityViolation = ffi::SCARD_W_SECURITY_VIOLATION as u32,
365 WrongChv = ffi::SCARD_W_WRONG_CHV as u32,
366 ChvBlocked = ffi::SCARD_W_CHV_BLOCKED as u32,
367 Eof = ffi::SCARD_W_EOF as u32,
368 CancelledByUser = ffi::SCARD_W_CANCELLED_BY_USER as u32,
369 CardNotAuthenticated = ffi::SCARD_W_CARD_NOT_AUTHENTICATED as u32,
370
371 CacheItemNotFound = ffi::SCARD_W_CACHE_ITEM_NOT_FOUND as u32,
372 CacheItemStale = ffi::SCARD_W_CACHE_ITEM_STALE as u32,
373 CacheItemTooBig = ffi::SCARD_W_CACHE_ITEM_TOO_BIG as u32,
374 }
376
377impl Error {
378 #[allow(clippy::manual_range_contains)]
379 fn from_raw(raw: LONG) -> Error {
380 unsafe {
381 if ffi::SCARD_F_INTERNAL_ERROR <= raw && raw <= ffi::SCARD_E_SERVER_TOO_BUSY
383 || ffi::SCARD_W_UNSUPPORTED_CARD <= raw && raw <= ffi::SCARD_W_CACHE_ITEM_TOO_BIG
384 {
385 transmute::<u32, Error>(raw as u32)
386 } else {
387 if cfg!(debug_assertions) {
388 panic!("unknown PCSC error code: {:#x}", raw);
389 }
390 Error::UnknownError
393 }
394 }
395 }
396
397 fn into_raw(self) -> LONG {
398 self as u32 as LONG
400 }
401}
402
403impl std::error::Error for Error {
404 fn description(&self) -> &str {
405 match *self {
407 Error::InternalError => "An internal consistency check failed",
408 Error::Cancelled => "The action was cancelled by an SCardCancel request",
409 Error::InvalidHandle => "The supplied handle was invalid",
410 Error::InvalidParameter => "One or more of the supplied parameters could not be properly interpreted",
411 Error::InvalidTarget => "Registry startup information is missing or invalid",
412 Error::NoMemory => "Not enough memory available to complete this command",
413 Error::WaitedTooLong => "An internal consistency timer has expired",
414 Error::InsufficientBuffer => "The data buffer to receive returned data is too small for the returned data",
415 Error::UnknownReader => "The specified reader name is not recognized",
416 Error::Timeout => "The user-specified timeout value has expired",
417 Error::SharingViolation => "The smart card cannot be accessed because of other connections outstanding",
418 Error::NoSmartcard => "The operation requires a Smart Card, but no Smart Card is currently in the device",
419 Error::UnknownCard => "The specified smart card name is not recognized",
420 Error::CantDispose => "The system could not dispose of the media in the requested manner",
421 Error::ProtoMismatch => {
422 "The requested protocols are incompatible with the protocol currently in use with the smart card"
423 }
424 Error::NotReady => "The reader or smart card is not ready to accept commands",
425 Error::InvalidValue => "One or more of the supplied parameters values could not be properly interpreted",
426 Error::SystemCancelled => "The action was cancelled by the system, presumably to log off or shut down",
427 Error::CommError => "An internal communications error has been detected",
428 Error::UnknownError => "An internal error has been detected, but the source is unknown",
429 Error::InvalidAtr => "An ATR obtained from the registry is not a valid ATR string",
430 Error::NotTransacted => "An attempt was made to end a non-existent transaction",
431 Error::ReaderUnavailable => "The specified reader is not currently available for use",
432 Error::Shutdown => "The operation has been aborted to allow the server application to exit",
433 Error::PciTooSmall => "The PCI Receive buffer was too small",
434 Error::ReaderUnsupported => "The reader driver does not meet minimal requirements for support",
435 Error::DuplicateReader => "The reader driver did not produce a unique reader name",
436 Error::CardUnsupported => "The smart card does not meet minimal requirements for support",
437 Error::NoService => "The Smart card resource manager is not running",
438 Error::ServiceStopped => "The Smart card resource manager has shut down",
439 #[cfg(target_os = "windows")]
440 Error::Unexpected => "An unexpected card error has occurred",
441 Error::UnsupportedFeature => "This smart card does not support the requested feature",
442 Error::IccInstallation => "No primary provider can be found for the smart card",
443 Error::IccCreateorder => "The requested order of object creation is not supported",
444 Error::DirNotFound => "The identified directory does not exist in the smart card",
445 Error::FileNotFound => "The identified file does not exist in the smart card",
446 Error::NoDir => "The supplied path does not represent a smart card directory",
447 Error::NoFile => "The supplied path does not represent a smart card file",
448 Error::NoAccess => "Access is denied to this file",
449 Error::WriteTooMany => "The smart card does not have enough memory to store the information",
450 Error::BadSeek => "There was an error trying to set the smart card file object pointer",
451 Error::InvalidChv => "The supplied PIN is incorrect",
452 Error::UnknownResMng => "An unrecognized error code was returned from a layered component",
453 Error::NoSuchCertificate => "The requested certificate does not exist",
454 Error::CertificateUnavailable => "The requested certificate could not be obtained",
455 Error::NoReadersAvailable => "Cannot find a smart card reader",
456 Error::CommDataLost => "A communications error with the smart card has been detected. Retry the operation",
457 Error::NoKeyContainer => "The requested key container does not exist on the smart card",
458 Error::ServerTooBusy => "The smart card resource manager is too busy to complete this operation",
459 Error::UnsupportedCard => {
460 "The reader cannot communicate with the card, due to ATR string configuration conflicts"
461 }
462 Error::UnresponsiveCard => "The smart card is not responding to a reset",
463 Error::UnpoweredCard => {
464 "Power has been removed from the smart card, so that further communication is not possible"
465 }
466 Error::ResetCard => "The smart card has been reset, so any shared state information is invalid",
467 Error::RemovedCard => "The smart card has been removed, so further communication is not possible",
468 Error::SecurityViolation => "Access was denied because of a security violation",
469 Error::WrongChv => "The card cannot be accessed because the wrong PIN was presented",
470 Error::ChvBlocked => {
471 "The card cannot be accessed because the maximum number of PIN entry attempts has been reached"
472 }
473 Error::Eof => "The end of the smart card file has been reached",
474 Error::CancelledByUser => r#"The user pressed "Cancel" on a Smart Card Selection Dialog"#,
475 Error::CardNotAuthenticated => "No PIN was presented to the smart card",
476 Error::CacheItemNotFound => "The requested item could not be found in the cache",
477 Error::CacheItemStale => "The requested cache item is too old and was deleted from the cache",
478 Error::CacheItemTooBig => "The new cache item exceeds the maximum per-item size defined for the cache",
479 }
480 }
481}
482
483impl std::fmt::Display for Error {
484 fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
485 f.write_str(std::error::Error::description(self))
486 }
487}
488
489macro_rules! try_pcsc {
490 ($e:expr) => {
491 match $e {
492 ffi::SCARD_S_SUCCESS => (),
493 err => return Err(Error::from_raw(err)),
494 }
495 };
496}
497
498#[repr(u32)]
500#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
501pub enum Scope {
502 User = ffi::SCARD_SCOPE_USER as u32,
503 Terminal = ffi::SCARD_SCOPE_TERMINAL as u32,
504 System = ffi::SCARD_SCOPE_SYSTEM as u32,
505 Global = ffi::SCARD_SCOPE_GLOBAL as u32,
506}
507
508impl Scope {
509 fn into_raw(self) -> DWORD {
510 DWORD::from(self as u32)
511 }
512}
513
514#[repr(u32)]
516#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
517pub enum AttributeClass {
518 VendorInfo = ffi::SCARD_CLASS_VENDOR_INFO as u32,
519 Communications = ffi::SCARD_CLASS_COMMUNICATIONS as u32,
520 Protocol = ffi::SCARD_CLASS_PROTOCOL as u32,
521 PowerMgmt = ffi::SCARD_CLASS_POWER_MGMT as u32,
522 Security = ffi::SCARD_CLASS_SECURITY as u32,
523 Mechanical = ffi::SCARD_CLASS_MECHANICAL as u32,
524 VendorDefined = ffi::SCARD_CLASS_VENDOR_DEFINED as u32,
525 IfdProtocol = ffi::SCARD_CLASS_IFD_PROTOCOL as u32,
526 IccState = ffi::SCARD_CLASS_ICC_STATE as u32,
527 System = ffi::SCARD_CLASS_SYSTEM as u32,
528}
529
530#[repr(u32)]
532#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
533pub enum Attribute {
534 VendorName = ffi::SCARD_ATTR_VENDOR_NAME as u32,
535 VendorIfdType = ffi::SCARD_ATTR_VENDOR_IFD_TYPE as u32,
536 VendorIfdVersion = ffi::SCARD_ATTR_VENDOR_IFD_VERSION as u32,
537 VendorIfdSerialNo = ffi::SCARD_ATTR_VENDOR_IFD_SERIAL_NO as u32,
538 ChannelId = ffi::SCARD_ATTR_CHANNEL_ID as u32,
539 AsyncProtocolTypes = ffi::SCARD_ATTR_ASYNC_PROTOCOL_TYPES as u32,
540 DefaultClk = ffi::SCARD_ATTR_DEFAULT_CLK as u32,
541 MaxClk = ffi::SCARD_ATTR_MAX_CLK as u32,
542 DefaultDataRate = ffi::SCARD_ATTR_DEFAULT_DATA_RATE as u32,
543 MaxDataRate = ffi::SCARD_ATTR_MAX_DATA_RATE as u32,
544 MaxIfsd = ffi::SCARD_ATTR_MAX_IFSD as u32,
545 SyncProtocolTypes = ffi::SCARD_ATTR_SYNC_PROTOCOL_TYPES as u32,
546 PowerMgmtSupport = ffi::SCARD_ATTR_POWER_MGMT_SUPPORT as u32,
547 UserToCardAuthDevice = ffi::SCARD_ATTR_USER_TO_CARD_AUTH_DEVICE as u32,
548 UserAuthInputDevice = ffi::SCARD_ATTR_USER_AUTH_INPUT_DEVICE as u32,
549 Characteristics = ffi::SCARD_ATTR_CHARACTERISTICS as u32,
550
551 CurrentProtocolType = ffi::SCARD_ATTR_CURRENT_PROTOCOL_TYPE as u32,
552 CurrentClk = ffi::SCARD_ATTR_CURRENT_CLK as u32,
553 CurrentF = ffi::SCARD_ATTR_CURRENT_F as u32,
554 CurrentD = ffi::SCARD_ATTR_CURRENT_D as u32,
555 CurrentN = ffi::SCARD_ATTR_CURRENT_N as u32,
556 CurrentW = ffi::SCARD_ATTR_CURRENT_W as u32,
557 CurrentIfsc = ffi::SCARD_ATTR_CURRENT_IFSC as u32,
558 CurrentIfsd = ffi::SCARD_ATTR_CURRENT_IFSD as u32,
559 CurrentBwt = ffi::SCARD_ATTR_CURRENT_BWT as u32,
560 CurrentCwt = ffi::SCARD_ATTR_CURRENT_CWT as u32,
561 CurrentEbcEncoding = ffi::SCARD_ATTR_CURRENT_EBC_ENCODING as u32,
562 ExtendedBwt = ffi::SCARD_ATTR_EXTENDED_BWT as u32,
563
564 IccPresence = ffi::SCARD_ATTR_ICC_PRESENCE as u32,
565 IccInterfaceStatus = ffi::SCARD_ATTR_ICC_INTERFACE_STATUS as u32,
566 CurrentIoState = ffi::SCARD_ATTR_CURRENT_IO_STATE as u32,
567 AtrString = ffi::SCARD_ATTR_ATR_STRING as u32,
568 IccTypePerAtr = ffi::SCARD_ATTR_ICC_TYPE_PER_ATR as u32,
569
570 EscReset = ffi::SCARD_ATTR_ESC_RESET as u32,
571 EscCancel = ffi::SCARD_ATTR_ESC_CANCEL as u32,
572 EscAuthrequest = ffi::SCARD_ATTR_ESC_AUTHREQUEST as u32,
573 Maxinput = ffi::SCARD_ATTR_MAXINPUT as u32,
574
575 DeviceUnit = ffi::SCARD_ATTR_DEVICE_UNIT as u32,
576 DeviceInUse = ffi::SCARD_ATTR_DEVICE_IN_USE as u32,
577 DeviceFriendlyName = ffi::SCARD_ATTR_DEVICE_FRIENDLY_NAME as u32,
578 DeviceSystemName = ffi::SCARD_ATTR_DEVICE_SYSTEM_NAME as u32,
579 SupressT1IfsRequest = ffi::SCARD_ATTR_SUPRESS_T1_IFS_REQUEST as u32,
580}
581
582impl Attribute {
583 fn into_raw(self) -> DWORD {
584 DWORD::from(self as u32)
585 }
586}
587
588pub const MAX_ATR_SIZE: usize = ffi::MAX_ATR_SIZE;
590pub const MAX_BUFFER_SIZE: usize = ffi::MAX_BUFFER_SIZE;
592pub const MAX_BUFFER_SIZE_EXTENDED: usize = ffi::MAX_BUFFER_SIZE_EXTENDED;
594
595#[allow(non_snake_case)]
602pub fn PNP_NOTIFICATION() -> &'static CStr {
604 CStr::from_bytes_with_nul(b"\\\\?PnP?\\Notification\0").unwrap()
606}
607
608pub const fn ctl_code(code: DWORD) -> DWORD {
615 ffi::SCARD_CTL_CODE(code)
616}
617
618#[repr(C)]
625pub struct ReaderState {
626 inner: ffi::SCARD_READERSTATE,
628}
629
630fn get_protocol_pci(protocol: Protocol) -> &'static ffi::SCARD_IO_REQUEST {
634 unsafe {
635 match protocol {
636 Protocol::T0 => &ffi::g_rgSCardT0Pci,
637 Protocol::T1 => &ffi::g_rgSCardT1Pci,
638 Protocol::RAW => &ffi::g_rgSCardRawPci,
639 }
640 }
641}
642
643struct ContextInner {
644 handle: ffi::SCARDCONTEXT,
645}
646
647pub struct Context {
651 inner: Arc<ContextInner>,
652}
653
654pub struct Card {
658 _context: Context,
660 handle: ffi::SCARDHANDLE,
661 active_protocol: Option<Protocol>,
662}
663
664pub struct Transaction<'tx> {
675 card: &'tx mut Card,
676}
677
678#[derive(Clone, Debug)]
684pub struct ReaderNames<'buf> {
685 buf: &'buf [u8],
686 pos: usize,
687}
688
689impl<'buf> Iterator for ReaderNames<'buf> {
690 type Item = &'buf CStr;
691
692 fn next(&mut self) -> Option<&'buf CStr> {
693 match self.buf[self.pos..].iter().position(|&c| c == 0) {
694 None | Some(0) => None,
695 Some(len) => {
696 let old_pos = self.pos;
697 self.pos += len + 1;
698 Some(CStr::from_bytes_with_nul(&self.buf[old_pos..self.pos]).unwrap())
700 }
701 }
702 }
703}
704
705impl Context {
706 pub fn establish(scope: Scope) -> Result<Context, Error> {
714 unsafe {
715 let mut handle: ffi::SCARDCONTEXT = DUMMY_LONG as ffi::SCARDCONTEXT;
716
717 try_pcsc!(ffi::SCardEstablishContext(
718 scope.into_raw(),
719 null(),
720 null(),
721 &mut handle,
722 ));
723
724 Ok(Context {
725 inner: Arc::new(ContextInner { handle }),
726 })
727 }
728 }
729
730 pub fn release(self) -> Result<(), (Context, Error)> {
750 match Arc::try_unwrap(self.inner) {
751 Ok(inner) => {
752 unsafe {
753 let err = ffi::SCardReleaseContext(inner.handle);
754 if err != ffi::SCARD_S_SUCCESS {
755 let context = Context { inner: Arc::new(inner) };
756 return Err((context, Error::from_raw(err)));
757 }
758
759 forget(inner);
761
762 Ok(())
763 }
764 }
765 Err(arc_inner) => {
766 let context = Context { inner: arc_inner };
767 Err((context, Error::CantDispose))
768 }
769 }
770 }
771
772 pub fn is_valid(&self) -> Result<(), Error> {
780 unsafe {
781 try_pcsc!(ffi::SCardIsValidContext(self.inner.handle,));
782
783 Ok(())
784 }
785 }
786
787 pub fn cancel(&self) -> Result<(), Error> {
796 unsafe {
797 try_pcsc!(ffi::SCardCancel(self.inner.handle,));
798
799 Ok(())
800 }
801 }
802
803 pub fn list_readers<'buf>(&self, buffer: &'buf mut [u8]) -> Result<ReaderNames<'buf>, Error> {
820 unsafe {
821 assert!(buffer.len() <= std::u32::MAX as usize);
822 let mut buflen = buffer.len() as DWORD;
823 let bufptr = if buflen == 0 {
828 null_mut()
829 } else {
830 let ptr = buffer.as_mut_ptr() as *mut c_char;
831 assert!(!ptr.is_null());
832 ptr
833 };
834
835 let err = ffi::SCardListReaders(self.inner.handle, null(), bufptr, &mut buflen);
836 if err == Error::NoReadersAvailable.into_raw() {
837 return Ok(ReaderNames { buf: b"\0", pos: 0 });
838 }
839 if err != ffi::SCARD_S_SUCCESS {
840 return Err(Error::from_raw(err));
841 }
842 if bufptr.is_null() {
843 return Err(Error::InsufficientBuffer);
844 }
845
846 Ok(ReaderNames {
847 buf: &buffer[..buflen as usize],
848 pos: 0,
849 })
850 }
851 }
852
853 pub fn list_readers_len(&self) -> Result<usize, Error> {
860 unsafe {
861 let mut buflen = DUMMY_DWORD;
862
863 let err = ffi::SCardListReaders(self.inner.handle, null(), null_mut(), &mut buflen);
864 if err == Error::NoReadersAvailable.into_raw() {
865 return Ok(0);
866 }
867 if err != ffi::SCARD_S_SUCCESS {
868 return Err(Error::from_raw(err));
869 }
870
871 Ok(buflen as usize)
872 }
873 }
874
875 pub fn list_readers_owned(&self) -> Result<Vec<CString>, Error> {
884 let len = self.list_readers_len()?;
885 if len == 0 {
886 return Ok(vec![]);
887 }
888 let mut buffer = vec![0u8; len];
889 Ok(self.list_readers(&mut buffer)?.map(ToOwned::to_owned).collect())
890 }
891
892 pub fn connect(&self, reader: &CStr, share_mode: ShareMode, preferred_protocols: Protocols) -> Result<Card, Error> {
901 unsafe {
902 let mut handle: ffi::SCARDHANDLE = DUMMY_LONG as ffi::SCARDHANDLE;
903 let mut raw_active_protocol: DWORD = DUMMY_DWORD;
904
905 try_pcsc!(ffi::SCardConnect(
906 self.inner.handle,
907 reader.as_ptr(),
908 share_mode.into_raw(),
909 preferred_protocols.bits(),
910 &mut handle,
911 &mut raw_active_protocol,
912 ));
913
914 let active_protocol = Protocol::from_raw(raw_active_protocol);
915
916 Ok(Card {
917 _context: self.clone(),
918 handle,
919 active_protocol,
920 })
921 }
922 }
923
924 pub fn get_status_change<D>(&self, timeout: D, readers: &mut [ReaderState]) -> Result<(), Error>
943 where
944 D: Into<Option<std::time::Duration>>,
945 {
946 let timeout_ms = match timeout.into() {
947 Some(duration) => {
948 let timeout_ms_u64 = duration
949 .as_secs()
950 .saturating_mul(1000)
951 .saturating_add(u64::from(duration.subsec_nanos()) / 1_000_000);
952 std::cmp::min(ffi::INFINITE, timeout_ms_u64 as DWORD)
953 }
954 None => ffi::INFINITE,
955 };
956
957 unsafe {
958 assert!(readers.len() <= std::u32::MAX as usize);
959
960 try_pcsc!(ffi::SCardGetStatusChange(
961 self.inner.handle,
962 timeout_ms,
963 readers.as_mut_ptr() as *mut ffi::SCARD_READERSTATE,
964 readers.len() as DWORD,
965 ));
966
967 Ok(())
968 }
969 }
970}
971
972impl Drop for ContextInner {
973 fn drop(&mut self) {
974 unsafe {
975 let _err = ffi::SCardReleaseContext(self.handle);
978 }
979 }
980}
981
982impl Clone for Context {
983 fn clone(&self) -> Self {
989 Context {
990 inner: Arc::clone(&self.inner),
991 }
992 }
993}
994
995unsafe impl Send for Context {}
996unsafe impl Sync for Context {}
997
998impl ReaderState {
999 pub fn new<T: Into<CString>>(name: T, current_state: State) -> ReaderState {
1002 ReaderState {
1003 inner: ffi::SCARD_READERSTATE {
1004 szReader: name.into().into_raw(),
1005 pvUserData: null_mut(),
1007 dwCurrentState: current_state.bits(),
1008 dwEventState: State::UNAWARE.bits(),
1009 cbAtr: 0,
1010 rgbAtr: [0; ffi::ATR_BUFFER_SIZE],
1011 },
1012 }
1013 }
1014
1015 pub fn name(&self) -> &CStr {
1017 unsafe { CStr::from_ptr(self.inner.szReader) }
1020 }
1021
1022 pub fn atr(&self) -> &[u8] {
1024 &self.inner.rgbAtr[0..self.inner.cbAtr as usize]
1025 }
1026
1027 pub fn current_state(&self) -> State {
1029 State::from_bits_truncate(self.inner.dwCurrentState)
1030 }
1031
1032 pub fn event_state(&self) -> State {
1034 State::from_bits_truncate(self.inner.dwEventState)
1035 }
1036
1037 pub fn event_count(&self) -> u32 {
1043 ((self.inner.dwEventState & 0xFFFF_0000) >> 16) as u32
1044 }
1045
1046 pub fn sync_current_state(&mut self) {
1048 self.inner.dwCurrentState = self.inner.dwEventState;
1052 }
1053}
1054
1055impl Drop for ReaderState {
1056 fn drop(&mut self) {
1057 unsafe { drop(CString::from_raw(self.inner.szReader as *mut c_char)) };
1059 }
1060}
1061
1062unsafe impl Send for ReaderState {}
1063unsafe impl Sync for ReaderState {}
1064
1065#[derive(Clone, Debug)]
1067pub struct CardStatus<'names_buf, 'atr_buf> {
1068 reader_names: ReaderNames<'names_buf>,
1069 state: DWORD,
1070 protocol: Option<Protocol>,
1071 atr: &'atr_buf [u8],
1072}
1073
1074impl<'names_buf, 'atr_buf> CardStatus<'names_buf, 'atr_buf> {
1075 pub fn reader_names(&self) -> ReaderNames<'names_buf> {
1077 self.reader_names.clone()
1078 }
1079
1080 pub fn status(&self) -> Status {
1082 Status::from_raw(self.state)
1083 }
1084
1085 pub fn protocol2(&self) -> Option<Protocol> {
1093 self.protocol
1094 }
1095
1096 pub fn protocol(&self) -> Protocol {
1106 self.protocol
1107 .expect("pcsc::CardStatus::protocol() does not support direct connections; use protocol2() instead")
1108 }
1109
1110 pub fn atr(&self) -> &'atr_buf [u8] {
1112 self.atr
1113 }
1114}
1115
1116#[derive(Clone, Debug)]
1120pub struct CardStatusOwned {
1121 reader_names: Vec<CString>,
1122 state: DWORD,
1123 protocol: Option<Protocol>,
1124 atr: Vec<u8>,
1125}
1126
1127impl CardStatusOwned {
1128 pub fn reader_names(&self) -> &[CString] {
1130 &self.reader_names
1131 }
1132
1133 pub fn status(&self) -> Status {
1135 Status::from_raw(self.state)
1136 }
1137
1138 pub fn protocol2(&self) -> Option<Protocol> {
1146 self.protocol
1147 }
1148
1149 pub fn protocol(&self) -> Protocol {
1159 self.protocol
1160 .expect("pcsc::CardStatus::protocol() does not support direct connections; use protocol2() instead")
1161 }
1162
1163 pub fn atr(&self) -> &[u8] {
1165 &self.atr
1166 }
1167}
1168
1169impl Card {
1170 pub fn transaction(&mut self) -> Result<Transaction, Error> {
1181 unsafe {
1182 try_pcsc!(ffi::SCardBeginTransaction(self.handle,));
1183
1184 Ok(Transaction { card: self })
1185 }
1186 }
1187
1188 pub fn transaction2(&mut self) -> Result<Transaction, (&mut Self, Error)> {
1207 unsafe {
1208 let err = ffi::SCardBeginTransaction(self.handle);
1209 if err != ffi::SCARD_S_SUCCESS {
1210 return Err((self, Error::from_raw(err)));
1211 }
1212
1213 Ok(Transaction { card: self })
1214 }
1215 }
1216
1217 pub fn reconnect(
1224 &mut self,
1225 share_mode: ShareMode,
1226 preferred_protocols: Protocols,
1227 initialization: Disposition,
1228 ) -> Result<(), Error> {
1229 unsafe {
1230 let mut raw_active_protocol: DWORD = DUMMY_DWORD;
1231
1232 try_pcsc!(ffi::SCardReconnect(
1233 self.handle,
1234 share_mode.into_raw(),
1235 preferred_protocols.bits(),
1236 initialization.into_raw(),
1237 &mut raw_active_protocol,
1238 ));
1239
1240 self.active_protocol = Protocol::from_raw(raw_active_protocol);
1241
1242 Ok(())
1243 }
1244 }
1245
1246 pub fn disconnect(mut self, disposition: Disposition) -> Result<(), (Card, Error)> {
1262 unsafe {
1263 let err = ffi::SCardDisconnect(self.handle, disposition.into_raw());
1264 if err != ffi::SCARD_S_SUCCESS {
1265 return Err((self, Error::from_raw(err)));
1266 }
1267
1268 std::ptr::drop_in_place(&mut self._context);
1270 forget(self);
1271
1272 Ok(())
1273 }
1274 }
1275
1276 #[deprecated(since = "2.3.0", note = "Use status2() or status2_owned() instead.")]
1292 pub fn status(&self) -> Result<(Status, Protocol), Error> {
1293 unsafe {
1294 let mut raw_status: DWORD = DUMMY_DWORD;
1295 let mut raw_protocol: DWORD = DUMMY_DWORD;
1296
1297 try_pcsc!(ffi::SCardStatus(
1298 self.handle,
1299 null_mut(),
1300 null_mut(),
1301 &mut raw_status,
1302 &mut raw_protocol,
1303 null_mut(),
1304 null_mut(),
1305 ));
1306
1307 let status = Status::from_raw(raw_status);
1308
1309 let protocol = Protocol::from_raw(raw_protocol)
1310 .expect("pcsc::Card::status() does not support direct connections; use status2() instead");
1311
1312 Ok((status, protocol))
1313 }
1314 }
1315
1316 pub fn status2<'names_buf, 'atr_buf>(
1336 &self,
1337 names_buffer: &'names_buf mut [u8],
1338 atr_buffer: &'atr_buf mut [u8],
1339 ) -> Result<CardStatus<'names_buf, 'atr_buf>, Error> {
1340 unsafe {
1341 assert!(names_buffer.len() <= std::u32::MAX as usize);
1342 let mut names_len: DWORD = names_buffer.len() as DWORD;
1343 let mut raw_state: DWORD = DUMMY_DWORD;
1344 let mut raw_protocol: DWORD = DUMMY_DWORD;
1345 assert!(atr_buffer.len() <= std::u32::MAX as usize);
1346 let mut atr_len: DWORD = atr_buffer.len() as DWORD;
1347
1348 try_pcsc!(ffi::SCardStatus(
1349 self.handle,
1350 names_buffer.as_mut_ptr() as *mut c_char,
1351 &mut names_len,
1352 &mut raw_state,
1353 &mut raw_protocol,
1354 atr_buffer.as_mut_ptr(),
1355 &mut atr_len,
1356 ));
1357
1358 Ok(CardStatus {
1359 reader_names: ReaderNames {
1360 buf: &names_buffer[..names_len as usize],
1361 pos: 0,
1362 },
1363 state: raw_state,
1364 protocol: Protocol::from_raw(raw_protocol),
1365 atr: &atr_buffer[0..atr_len as usize],
1366 })
1367 }
1368 }
1369
1370 pub fn status2_len(&self) -> Result<(usize, usize), Error> {
1378 unsafe {
1379 let mut names_len: DWORD = DUMMY_DWORD;
1380 let mut raw_state: DWORD = DUMMY_DWORD;
1381 let mut raw_protocol: DWORD = DUMMY_DWORD;
1382 let mut atr_len: DWORD = DUMMY_DWORD;
1383
1384 try_pcsc!(ffi::SCardStatus(
1385 self.handle,
1386 null_mut(),
1387 &mut names_len,
1388 &mut raw_state,
1389 &mut raw_protocol,
1390 null_mut(),
1391 &mut atr_len,
1392 ));
1393
1394 Ok((names_len as usize, atr_len as usize))
1395 }
1396 }
1397
1398 pub fn status2_owned(&self) -> Result<CardStatusOwned, Error> {
1407 let (names_len, atr_len) = self.status2_len()?;
1408 let mut names_buffer = vec![0u8; names_len];
1409 let mut atr_buffer = vec![0u8; atr_len];
1410
1411 let (reader_names, state, protocol, atr_len) = {
1412 let card_status = self.status2(&mut names_buffer, &mut atr_buffer)?;
1413 let reader_names = card_status.reader_names.map(ToOwned::to_owned).collect();
1414 (
1415 reader_names,
1416 card_status.state,
1417 card_status.protocol,
1418 card_status.atr.len(),
1419 )
1420 };
1421
1422 atr_buffer.truncate(atr_len);
1423
1424 Ok(CardStatusOwned {
1425 reader_names,
1426 state,
1427 protocol,
1428 atr: atr_buffer,
1429 })
1430 }
1431
1432 pub fn get_attribute<'buf>(&self, attribute: Attribute, buffer: &'buf mut [u8]) -> Result<&'buf [u8], Error> {
1448 unsafe {
1449 assert!(buffer.len() <= std::u32::MAX as usize);
1450 let mut attribute_len = buffer.len() as DWORD;
1451 let bufptr = if attribute_len == 0 {
1456 null_mut()
1457 } else {
1458 let ptr = buffer.as_mut_ptr();
1459 assert!(!ptr.is_null());
1460 ptr
1461 };
1462
1463 try_pcsc!(ffi::SCardGetAttrib(
1464 self.handle,
1465 attribute.into_raw(),
1466 buffer.as_mut_ptr(),
1467 &mut attribute_len,
1468 ));
1469 if bufptr.is_null() && attribute_len > 0 {
1470 return Err(Error::InsufficientBuffer);
1471 }
1472
1473 Ok(&buffer[0..attribute_len as usize])
1474 }
1475 }
1476
1477 pub fn get_attribute_len(&self, attribute: Attribute) -> Result<usize, Error> {
1484 unsafe {
1485 let mut attribute_len = DUMMY_DWORD;
1486
1487 try_pcsc!(ffi::SCardGetAttrib(
1488 self.handle,
1489 attribute.into_raw(),
1490 null_mut(),
1491 &mut attribute_len,
1492 ));
1493
1494 Ok(attribute_len as usize)
1495 }
1496 }
1497
1498 pub fn get_attribute_owned(&self, attribute: Attribute) -> Result<Vec<u8>, Error> {
1507 let len = self.get_attribute_len(attribute)?;
1508 if len == 0 {
1509 return Ok(vec![]);
1510 }
1511 let mut buf = vec![0u8; len];
1512 let n = self.get_attribute(attribute, &mut buf)?.len();
1513 buf.truncate(n);
1514 Ok(buf)
1515 }
1516
1517 pub fn set_attribute(&self, attribute: Attribute, attribute_data: &[u8]) -> Result<(), Error> {
1524 unsafe {
1525 assert!(attribute_data.len() <= std::u32::MAX as usize);
1526
1527 try_pcsc!(ffi::SCardSetAttrib(
1528 self.handle,
1529 attribute.into_raw(),
1530 attribute_data.as_ptr(),
1531 attribute_data.len() as DWORD,
1532 ));
1533
1534 Ok(())
1535 }
1536 }
1537
1538 pub fn transmit<'buf>(&self, send_buffer: &[u8], receive_buffer: &'buf mut [u8]) -> Result<&'buf [u8], Error> {
1554 self.transmit2(send_buffer, receive_buffer).map_err(|(err, _)| err)
1555 }
1556
1557 pub fn transmit2<'buf>(
1587 &self,
1588 send_buffer: &[u8],
1589 receive_buffer: &'buf mut [u8],
1590 ) -> Result<&'buf [u8], (Error, usize)> {
1591 let active_protocol = self
1592 .active_protocol
1593 .expect("pcsc::Card::transmit() does not work with direct connections");
1594 let send_pci = get_protocol_pci(active_protocol);
1595 let recv_pci = null_mut();
1596 assert!(receive_buffer.len() <= std::u32::MAX as usize);
1597 let mut receive_len = receive_buffer.len() as DWORD;
1598
1599 unsafe {
1600 assert!(send_buffer.len() <= std::u32::MAX as usize);
1601
1602 let r = ffi::SCardTransmit(
1603 self.handle,
1604 send_pci,
1605 send_buffer.as_ptr(),
1606 send_buffer.len() as DWORD,
1607 recv_pci,
1608 receive_buffer.as_mut_ptr(),
1609 &mut receive_len,
1610 );
1611
1612 match r {
1613 ffi::SCARD_S_SUCCESS => (),
1614 err => return Err((Error::from_raw(err), receive_len as usize)),
1615 }
1616
1617 Ok(&receive_buffer[0..receive_len as usize])
1618 }
1619 }
1620
1621 pub fn control<'buf>(
1640 &self,
1641 control_code: DWORD,
1644 send_buffer: &[u8],
1645 receive_buffer: &'buf mut [u8],
1646 ) -> Result<&'buf [u8], Error> {
1647 let mut receive_len: DWORD = DUMMY_DWORD;
1648
1649 unsafe {
1650 assert!(send_buffer.len() <= std::u32::MAX as usize);
1651 assert!(receive_buffer.len() <= std::u32::MAX as usize);
1652
1653 try_pcsc!(ffi::SCardControl(
1654 self.handle,
1655 control_code,
1656 send_buffer.as_ptr(),
1657 send_buffer.len() as DWORD,
1658 receive_buffer.as_mut_ptr(),
1659 receive_buffer.len() as DWORD,
1660 &mut receive_len,
1661 ));
1662
1663 Ok(&receive_buffer[0..receive_len as usize])
1664 }
1665 }
1666}
1667
1668impl Drop for Card {
1669 fn drop(&mut self) {
1670 unsafe {
1671 let _err = ffi::SCardDisconnect(self.handle, Disposition::ResetCard.into_raw());
1677 }
1678 }
1679}
1680
1681unsafe impl Send for Card {}
1682unsafe impl Sync for Card {}
1683
1684impl<'tx> Transaction<'tx> {
1685 pub fn end(self, disposition: Disposition) -> Result<(), (Transaction<'tx>, Error)> {
1703 unsafe {
1704 let err = ffi::SCardEndTransaction(self.card.handle, disposition.into_raw());
1705 if err != 0 {
1706 return Err((self, Error::from_raw(err)));
1707 }
1708
1709 forget(self);
1711
1712 Ok(())
1713 }
1714 }
1715
1716 pub fn reconnect(
1723 &mut self,
1724 share_mode: ShareMode,
1725 preferred_protocols: Protocols,
1726 initialization: Disposition,
1727 ) -> Result<(), Error> {
1728 self.card.reconnect(share_mode, preferred_protocols, initialization)
1729 }
1730}
1731
1732impl<'tx> Drop for Transaction<'tx> {
1733 fn drop(&mut self) {
1734 unsafe {
1735 let _err = ffi::SCardEndTransaction(self.card.handle, Disposition::LeaveCard.into_raw());
1741 }
1742 }
1743}
1744
1745impl<'tx> Deref for Transaction<'tx> {
1746 type Target = Card;
1747
1748 fn deref(&self) -> &Card {
1749 self.card
1750 }
1751}