Windows PC/SC and SCARD_E_SERVICE_STOPPED (part 2)

In a previous blog article " Windows PC/SC and SCARD_E_SERVICE_STOPPED " I presented a problem on Windows when the last reader is disconnected.

After a discussion on the pcsclite-muscle mailing list I got nice feedback.Thanks.

Diego de Felice gave a reference to a Microsoft documentation from 2016 "What's New in Smart Cards"

Smart Card Service start and stop behavior

Smart card reader detection logic has been added so that the Smart Card Service runs only when appropriate. On Windows Server 2012 and Windows 8, the Smart Card Service (scardsvr) automatically starts when the user connects a smart card reader and automatically stops when a user removes a smart card reader and no other smart card reader is connected to the computer. On startup, the Smart Card Service automatically starts if a reader was previously connected to the computer but a reader is not currently connected to the system. If no smart card readers are connected to the computer, the service will automatically shut down one minute after the last API call into the Smart Card Service. If a reader was never previously connected to the computer, the service will not start automatically.

So the (strange) behavior is documented by Microsoft.

Stephan Brunner then gave a solution: establish a new context.


Source code

I wanted to test the hack proposed by Stephan.

#! /usr/bin/env python3

from smartcard.scard import *
from smartcard.pcsc.PCSCExceptions import *
import time

hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER)
if hresult != SCARD_S_SUCCESS:
    raise EstablishContextException(hresult)

i = 0
while True:
    hresult, readers = SCardListReaders(hcontext, [])
    exc = BaseSCardException(message="", hresult=hresult)
    print('(%d) %s:' % (i, str(exc)), readers)
    if not hresult in [SCARD_S_SUCCESS, SCARD_E_NO_READERS_AVAILABLE]:
        hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER)
        if hresult != SCARD_S_SUCCESS:
            raise EstablishContextException(hresult)

    time.sleep(1)
    i += 1

Output

(base) C:\Users\ludovic\Documents>python SCardListReaders.py
(0) : Impossible de trouver un lecteur de carte ŕ puce.  (0x8010002E): []
(1) : Impossible de trouver un lecteur de carte ŕ puce.  (0x8010002E): []
(2) : Impossible de trouver un lecteur de carte ŕ puce.  (0x8010002E): []
(3) : Impossible de trouver un lecteur de carte ŕ puce.  (0x8010002E): []
(4) : L’opération a réussi.  (0x00000000): ['Generic EMV Smartcard Reader 0']
(5) : L’opération a réussi.  (0x00000000): ['Generic EMV Smartcard Reader 0']
(6) : L’opération a réussi.  (0x00000000): ['Generic EMV Smartcard Reader 0']
(7) : L’opération a réussi.  (0x00000000): ['Generic EMV Smartcard Reader 0']
(8) : L’opération a réussi.  (0x00000000): ['Generic EMV Smartcard Reader 0']
(9) : Le gestionnaire de ressources des cartes ŕ puce s’est arręté.  (0x8010001E): []
(10) : Impossible de trouver un lecteur de carte ŕ puce.  (0x8010002E): []
(11) : Impossible de trouver un lecteur de carte ŕ puce.  (0x8010002E): []
(12) : Impossible de trouver un lecteur de carte ŕ puce.  (0x8010002E): []
(13) : L’opération a réussi.  (0x00000000): ['Generic EMV Smartcard Reader 0']
(14) : L’opération a réussi.  (0x00000000): ['Generic EMV Smartcard Reader 0']
(15) : L’opération a réussi.  (0x00000000): ['Generic EMV Smartcard Reader 0']
(16) : L’opération a réussi.  (0x00000000): ['Generic EMV Smartcard Reader 0']
(17) : Le gestionnaire de ressources des cartes ŕ puce s’est arręté.  (0x8010001E): []
(18) : Impossible de trouver un lecteur de carte ŕ puce.  (0x8010002E): []
(19) : Impossible de trouver un lecteur de carte ŕ puce.  (0x8010002E): []

Description

Step 0, I start the script with no smart card reader connected. So SCardListReaders() returns the expected 0x8010002E which is SCARD_E_NO_READERS_AVAILABLE.

Step 4, Then I connect a smart card reader.

Step 9, Then I disconnect the smart card reader and SCardListReaders() returns the unexpected error 0x8010001E i.e. SCARD_E_SERVICE_STOPPED.

The program then calls SCardEstablishContext() again, with success, and continue.

Step 10, The next call to CardListReaders() returns the expected 0x8010002E. So I guess the PC/SC resource manager has been  re-started. 

Step 13, Connecting a new smart card reader works fine and the reader is detected.

Step 17, I disconnect the reader and I get again the SCARD_E_SERVICE_STOPPED error.

Without the hack

If the code does not establish a new context then CardListReaders() will return SCARD_E_SERVICE_STOPPED for ever. And if I connect a new reader it is not detected.

I think this behavior explains the bug reported in CardRequest waitforcard ATR can't see reconnected readers on Windows (regression) #123.


Conclusion

Ignoring SCARD_E_SERVICE_STOPPED, as I did in commit 5b43ef5, is not a correct solution. I have to work on a better solution (just for Windows).