#299 rdesktop with smartcard

open
nobody
5
2014-09-19
2009-04-21
rahulkr
No

i have installed rdesktop 1.6 which has smart card option in linux OS.i plugin the usb smart card reader
and started pcscd deamon then i invoke the rdesktop with scard option the rdesktop recognized the
smart card which is inserted in the smart card reader.But problem is when i unplug the smart card and plug it again (while rdesktop still running) then rdesktop does not recognized the smart card.
Please help me.I have no clue what is happening but this procedure work perfectly with windows

Discussion

  • You haven't done anything wrong. There is a bug in rdesktop. The set of users using both rdesktop and smart cards is growing but still small; the subset of those users who can hack on the smartcard support is even smaller. So bugs in this area are not fixed very quickly.

    The workaround is to set your terminal server to not log people off as soon as they disconnect. Then when you remove the smartcard (for whatever reason), you can disconnect without logging out of Windows by closing the rdesktop client, and restart rdesktop with the smart card inserted, to reconnect to the terminal server. Then you'll start your Windows session where you left it off, with the smartcard working.

     
  • Is there any patch ready for this problem?

     
  • rahulkr
    rahulkr
    2009-04-23

    Is there any patch for this ?

     
  • there is some code in the scard.c which enables the "hotplug" feature, it's disabled, but when i enabled i was able to hotplug the card in the reader, i'm just not sure if it is buggy...

     
  • I whish to add some extra information.

    We had the same problem and we have discovered an interaction with MS Active Directory. When the windows machine on which we want to connect is outside any domain, redirection and insert/eject events works perfectly. When the machine is added to the domain, we have the same problem.

    The problem occurs with out-of-the box policies on Windows 2003 and Windows 2008 server with the default policies. And I have found no policy directly inpacting RDP in these default policies. So, up-to-now I have no extra-idea or workaround.

     
  • Uncommenting the block of code managing the hotplug allow the smart-card to works perfectly with a MS Windows that is not inside a MS domain.

    I start trying to debug with a MS Windows machine inside a domain and found that the problem come from a deadlock in thread_function. The smart-card thread is locked on pthread_cond_wait without being waked up. The problem is not reproducible with MSTSC.EXE on MS Windows. Certainly a bug somewhere in rdesktop but why AD integration has an impact on rdesktop? Didn't understand up to now.

     
  • As said in an other post on this mailing list, the upgrade of pcsclite help. I have updated pcsc-lite to version 1.5.4 (the latest one) and now the hotplug works with AD but for a limited numbers of times...

    The problems seems to be on the pcscd side.

     
  • I continue my search. The update of pcsc-lite avoid a segmentation fault and seems to be a little more stable but sometime (inpredictable...).

    I'm looking now at the filesystem virtual channel used from smartcard messages transmission. Is it possible that ad problems (and the deadlock in scard.c) come from there? The filesystem virtual channel is implemented in rdpdr.c (the channel is called rdpdr).

     
  • rahulkr
    rahulkr
    2009-07-01

    Actually real problem i had with aladdin etoken 72 pro java - smartcard.I was able to solve the plugin-plugout issue by controlling the behaviour of the thread i.e with help of udev rules.But it is not consistent.I added some code in the TS_SCARDGETCHANGE() function to work this issue but it is not perfect.Now u says that this virtual channel has a problem.What is this virtual channel?How communication happen on this channel?.Because I explore various files related to rdesktop but fail to get the problem source.

     
  • See patch 2815251 - http://sourceforge.net/tracker/?func=detail&aid=2815251&group_id=24366&atid=381349

    This patch may help you. I made it so that I could diff smart card debug output between working and non-working rdesktop builds. It may apply against 1.6.0 - but I made it against the CVS HEAD. There are multiple rdesktop threads calling the pcsc-lite API, and I think this is part of the problem (and the reason that it doesn't always work or fail the same way). The changed debug output that this patch produces may make this more clear to you.

    The Microsoft RDP documentation may help you with your virtual channel queries; I have been assured by the core developers that it is legally safe for the project if you use this documentation. Virtual channels are handled by rdpdr.c; I have not investigated the connections between that and scard.c.

    Thanks for your work on this problem. It's also a problem for me, but it seems you are getting farther than I have, and that you have more time to spend on it than I do.

     
  • rahulkr
    rahulkr
    2009-07-02

    Thanks for the patch.I will look in to it.Currently i am not working on this.if i get time i really like to work this.

     
  • I have 2 logs made with a svn version rdesktop patched with patch 2815251.

    With a machine not joined to a domain:

    SCARD: SCardAccessStartedEvent()
    SCARD: SCardAccessStartedEvent()
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00110012
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00110012
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00120022
    SCARD: ctx b: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00120022
    SCARD: ctx b: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00000022, event: 0x00000022, current state: 0x00120022
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00120022, event: 0x00140022
    SCARD: ctx b: SCardConnect(share: 0x00000002, proto: 0x00000003, reader: "ACS ACR38U 00 00")
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00120122
    SCARD: hcard A: SCardTransmit(send: 5 bytes, recv: 30 bytes)
    SCARD: -> Success (30 bytes)
    SCARD: hcard A: SCardTransmit(send: 9 bytes, recv: 2 bytes)
    SCARD: -> Success (2 bytes)
    SCARD: hcard A: SCardTransmit(send: 5 bytes, recv: 246 bytes)
    SCARD: -> Success (2 bytes)
    SCARD: hcard A: SCardTransmit(send: 5 bytes, recv: 246 bytes)
    SCARD: -> Success (39 bytes)
    SCARD: hcard A: SCardTransmit(send: 9 bytes, recv: 2 bytes)
    SCARD: -> Success (2 bytes)
    SCARD: hcard A: SCardTransmit(send: 11 bytes, recv: 2 bytes)
    SCARD: -> Success (2 bytes)
    SCARD: hcard A: SCardTransmit(send: 5 bytes, recv: 246 bytes)
    SCARD: -> Success (2 bytes)
    SCARD: hcard A: SCardTransmit(send: 5 bytes, recv: 246 bytes)
    SCARD: -> Success (43 bytes)
    SCARD: hcard A: SCardTransmit(send: 11 bytes, recv: 2 bytes)
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00120122
    SCARD: -> Success (2 bytes)
    SCARD: hcard A: SCardTransmit(send: 5 bytes, recv: 18 bytes)
    SCARD: -> Success (18 bytes)
    SCARD: ctx b: hcard A: SCardDisconnect(disposition: 0x00000000)
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00120022
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00120022
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00120022
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00120022
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00120022
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00120022
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00120022
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00130012
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00130012
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00130012
    SCARD: ctx a: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00130012

    With a machine joined to a domain:

    SCARD: SCardAccessStartedEvent()
    SCARD: ctx a: SCardGetStatusChange(timeout: 0xffffffff, count: 2)
    SCARD: ctx a: "\\?PnP?\Notification" user: (nil), state: 0x00000001, event: 0x00000000, current state: 0x00000000
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000010, event: 0x00000000, current state: 0x00000010
    SCARD: SCardAccessStartedEvent()
    SCARD: ctx b: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x000f0012
    SCARD: ctx b: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x000f0012
    SCARD: ctx b: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x000f0012
    SCARD: ctx b: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x000f0012
    SCARD: ctx b: SCardGetStatusChange(timeout: 0x00000000, count: 1)
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x00000000, current state: 0x00000000
    SCARD: ctx b: "ACS ACR38U 00 00" user: (nil), state: 0x00000000, event: 0x000f0012
    SCARD: ctx a: "\\?PnP?\Notification" user: (nil), state: 0x00000000, event: 0x00000001
    SCARD: ctx a: "ACS ACR38U 00 00" user: (nil), state: 0x00000010, event: 0x00100022

     
  • The pcsc-lite winscard_clnt.c mentions:

    /**
    * @brief Creates an Application Context to the PC/SC Resource Manager.
    *
    * This must be the first WinSCard function called in a PC/SC application.
    * Each thread of an application shall use its own SCARDCONTEXT.

    The rdesktop client uses worker threads to handle scard requests (it reuses or spawns new threads if non are available). This violates the 1 SCARDCONTEXT per thread restriction. Unfortunately it's not certain this is really the issue and it is a rather big change.

    NOTE: I got it to work for machines joined to a domain by forcing the first SCardGetStatusChange() call to use a timeout of 1 (normally it's INFINITE). Not quite sure why it works though.

    ie. add something like this to the top of SCardGetStatusChange() in scard.c :

    static int _count=0;

    if (_count == 0) {
    dwTimeout=1;
    _count++;
    }

     
  • Karl Vogel
    Karl Vogel
    2009-08-19

    The issue seems to be caused by winlogon.exe - When the computer is joined to a domain, it issues extra smart card calls. The first call is SCardAccessStartedEvent() to check if the service is up. This should return a HANDLE which the clients wait on.
    If the SCardAccessStartedEvent() is delayed.. so that a normal smart card apps makes API calls before the SCardAccessStartedEvent() from winlogon.exe is done, it locks up the service.

    It was found that returning an error from SCardAccessStartedEvent() somehow makes everything work. It's unclear why this is, it might speed up / skip some initialization in winlogon.exe causing everything to work.

    By patching rdesktop like:
    Index: scard.c
    ===================================================================
    --- scard.c (revision 1505)
    +++ scard.c (working copy)
    @@ -2162,7 +2162,7 @@
    {
    DEBUG_SCARD(("SCARD: SCardAccessStartedEvent()\n"));
    out_uint8s(out, 8);
    - return SCARD_S_SUCCESS;
    + return SCARD_E_INVALID_HANDLE;
    }

    ====

    I got it to work for me.

    I was also able to create a test app that shows the difference between rdesktop and the windows terminal services client. Starting this test app on rdesktop makes it wait until the timeout on the Wait event, whereas on a windows terminal services client, it immediately returns.

    #include <windows.h>

    typedef HANDLE (*FNPTR)(void);
    int main(int argc, char *argv[])
    {
    FNPTR SCardAccessStartedEvent;
    HANDLE x;
    HRESULT dwRet;
    HINSTANCE hLibrary= LoadLibrary("winscard.dll");
    if (hLibrary == NULL) {
    printf("LoadLib failed\n");
    exit(1);
    }

    SCardAccessStartedEvent= \(FNPTR\)GetProcAddress\(hLibrary, "SCardAccessStartedEvent"\);
    if \(SCardAccessStartedEvent == NULL\) \{
        printf\("Proc error\n"\);
        exit\(1\);
    \}
    
    x= SCardAccessStartedEvent\(\); 
    printf\("SCardAccessStartedEvent return: %x \(%d\)\n", x, x\);
    dwRet= WaitForSingleObject\(x, 50000\);
    printf\("Wait return: %x \(%d\)\n", dwRet, dwRet\);
    
    FreeLibrary\(hLibrary\);
    return 0;
    

    }

    For now, I haven't been able to find why it acts differently. There isn't any extra IOCTL calls happening for that call on the terminal services client.

     
  • kvogel's patch does not work for me against a w2k8r2 machine joined to a domain. In fact, it kills smartcard redirection entirely.

    The dwTimeout workaround works better, but there is a lot of freezing of the session when it initially connects, presumably due to an increase in calls to the smartcard reader. I have not enabled debugging yet to probe further. It is unclear to me, also, why the timeout in the first context when joined to a domain is 0xfffffff, while all other timeouts are 0x000000.

     
  • Hai! I am also facing the same problem, " A running rdesktop session not recognizing smartcard once unplugged". I am also using rdesktop 1.6 on centos 5.3 and trying to connect with aladdin etoken 72 pro java - smartcard. I did not tried kvogel's patch till now, but will try for sure. I am looking for a new/related patches regarding this problem as its been a year and I hope someone has found a stable patch for this, please give details if you know any?

     
  • jorge infante
    jorge infante
    2014-01-08

    Hi!
    I'm trying to use the smartcard support of rdesktop to use the smartcard in a browser in the remote session. I don't like to use the smartcard to authenticate the rdp session. Only to use as a external device to session (like a diskette or another usb device). Is it posible? I'm working in the compile packages step, but, I don't know if it is posible. Can you tell me about it?

    TIA
    jorge infante
    rosario - santa fe
    argentina