Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3011 lines
79 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. WinSCard
  5. Abstract:
  6. This module supplies the API for the Calais Smartcard Service Manager.
  7. The Calais Service Manager does the work of coordinating the protocols,
  8. readers, drivers, and smartcards on behalf of the application. The
  9. following services are provided as part of a library to simplify access to
  10. the Service Manager. These routines are the documented, exposed APIs.
  11. These routines merely package the requests and forward them to the Calais
  12. Service Manager, allowing the actual implementation of Calais to vary over
  13. time.
  14. At no time does the API library make security decisions. All
  15. security-related functions must be performed by the Service Manager, running
  16. in its own address space, or in the operating system kernel. However, some
  17. utility routines may be implemented in the API library for speed, as long as
  18. they do not involve security decisions.
  19. Author:
  20. Doug Barlow (dbarlow) 10/23/1996
  21. Environment:
  22. Win32, C++ w/ Exceptions
  23. Notes:
  24. ?Notes?
  25. --*/
  26. #define __SUBROUTINE__
  27. #ifndef WIN32_LEAN_AND_MEAN
  28. #define WIN32_LEAN_AND_MEAN
  29. #endif
  30. #include <nt.h>
  31. #include <ntrtl.h>
  32. #include <nturtl.h>
  33. #include <windows.h>
  34. #include <winbase.h>
  35. #include <wtsapi32.h>
  36. #include "client.h"
  37. #include "redirect.h"
  38. #include "winsta.h"
  39. const SCARD_IO_REQUEST
  40. g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, sizeof(SCARD_IO_REQUEST) },
  41. g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, sizeof(SCARD_IO_REQUEST) },
  42. g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, sizeof(SCARD_IO_REQUEST) };
  43. CHandleList
  44. * g_phlContexts = NULL,
  45. * g_phlReaders = NULL;
  46. const WCHAR g_wszBlank[] = L"\000";
  47. HINSTANCE g_hInst;
  48. HANDLE g_hSessionChangeEvent = NULL;
  49. HANDLE g_hSessionChangeCallbackHandle = NULL;
  50. ULONG_PTR g_SessionChangeID = 0;
  51. CRITICAL_SECTION g_RegisterForSessionChangeNoticationsCS;
  52. BOOL g_fRegisteredForSessionChangeNotications = FALSE;
  53. DWORD g_dwTimerCallbacksMade = 0;
  54. DWORD g_dwClientCount = 0;
  55. HANDLE g_hTimerEvent = NULL;
  56. HANDLE g_hWaitTimerEventCallbackHandle = NULL;
  57. CRITICAL_SECTION g_SafeCreateHandleCS;
  58. CRITICAL_SECTION g_SetStartedEventCS;
  59. CRITICAL_SECTION g_RegisterForStoppedEventCS;
  60. CRITICAL_SECTION g_DllMainCS;
  61. HANDLE g_hWaitForStartedCallbackHandle = NULL;
  62. HANDLE g_hUnifiedStartedEvent = NULL;
  63. HANDLE g_hWaitForStoppedCallbackHandle = NULL;
  64. CRITICAL_SECTION g_TermSrvEnabledCS;
  65. BOOL g_fTermSrvEnableChecked = FALSE;
  66. BOOL g_bTermSrvEnabled = FALSE;
  67. BOOL g_fInClientRundown = FALSE;
  68. BOOL g_fInDllMain = FALSE;
  69. BOOL SetStartedEventWhenSCardSubsytemIsStarted(BOOL fUseLocal);
  70. void
  71. PrintDebugString(LPSTR szString, DWORD dwValue)
  72. {
  73. char szOutString[256];
  74. sprintf(szOutString,
  75. "%d.%d> WINSCARD: %s - %lx\n",
  76. GetCurrentProcessId(),
  77. GetCurrentThreadId(),
  78. szString,
  79. dwValue);
  80. //OutputDebugStringA(szOutString);
  81. }
  82. //
  83. ////////////////////////////////////////////////////////////////////////////////
  84. //
  85. // Mark all current held contexts bad
  86. //
  87. WINSCARDAPI void WINAPI
  88. MarkContextsAsBad(BOOL fCancel)
  89. {
  90. try {
  91. g_phlContexts->MarkContentAsBad(fCancel);
  92. g_phlReaders->MarkContentAsBad(FALSE);
  93. }
  94. catch (...)
  95. {
  96. }
  97. }
  98. //
  99. ////////////////////////////////////////////////////////////////////////////////
  100. //
  101. // DllMain
  102. //
  103. BOOL WINAPI
  104. DllMain(
  105. HMODULE hInstDLL,
  106. DWORD fdwReason,
  107. LPVOID lpvReserved)
  108. {
  109. DWORD dw;
  110. BOOL f;
  111. g_fInDllMain = TRUE;
  112. switch (fdwReason)
  113. {
  114. case DLL_PROCESS_ATTACH:
  115. g_hInst = hInstDLL;
  116. try
  117. {
  118. dw = 0;;
  119. InitializeCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
  120. dw++;
  121. InitializeCriticalSection(&g_SafeCreateHandleCS);
  122. dw++;
  123. InitializeCriticalSection(&g_SetStartedEventCS);
  124. dw++;
  125. InitializeCriticalSection(&g_TermSrvEnabledCS);
  126. dw++;
  127. InitializeCriticalSection(&g_RegisterForStoppedEventCS);
  128. dw++;
  129. InitializeCriticalSection(&g_DllMainCS);
  130. }
  131. catch(...)
  132. {
  133. if (dw >= 1)
  134. {
  135. DeleteCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
  136. }
  137. if (dw >= 2)
  138. {
  139. DeleteCriticalSection(&g_SafeCreateHandleCS);
  140. }
  141. if (dw >= 3)
  142. {
  143. DeleteCriticalSection(&g_SetStartedEventCS);
  144. }
  145. if (dw >= 4)
  146. {
  147. DeleteCriticalSection(&g_TermSrvEnabledCS);
  148. }
  149. if (dw >= 5)
  150. {
  151. DeleteCriticalSection(&g_RegisterForStoppedEventCS);
  152. }
  153. g_fInDllMain = FALSE;
  154. return FALSE;
  155. }
  156. g_phlContexts = new CHandleList(CONTEXT_HANDLE_ID);
  157. g_phlReaders = new CHandleList(READER_HANDLE_ID);
  158. if ((NULL == g_phlContexts) ||
  159. (NULL == g_phlReaders) ||
  160. g_phlContexts->InitFailed() ||
  161. g_phlReaders->InitFailed())
  162. {
  163. if (g_phlContexts)
  164. {
  165. delete g_phlContexts;
  166. g_phlContexts = NULL;
  167. }
  168. if (g_phlReaders)
  169. {
  170. delete g_phlReaders;
  171. g_phlReaders = NULL;
  172. }
  173. DeleteCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
  174. DeleteCriticalSection(&g_SafeCreateHandleCS);
  175. DeleteCriticalSection(&g_SetStartedEventCS);
  176. DeleteCriticalSection(&g_TermSrvEnabledCS);
  177. DeleteCriticalSection(&g_RegisterForStoppedEventCS);
  178. DeleteCriticalSection(&g_DllMainCS);
  179. g_fInDllMain = FALSE;
  180. return FALSE;
  181. }
  182. break;
  183. case DLL_PROCESS_DETACH:
  184. //
  185. // Clean up the registered waits if they are still outstanding
  186. //
  187. HANDLE hCallbackToUnregister;
  188. EnterCriticalSection(&g_DllMainCS);
  189. g_fInDllMain = TRUE;
  190. LeaveCriticalSection(&g_DllMainCS);
  191. hCallbackToUnregister = InterlockedExchangePointer(
  192. &g_hWaitTimerEventCallbackHandle,
  193. NULL);
  194. if (hCallbackToUnregister != NULL)
  195. {
  196. UnregisterWaitEx(hCallbackToUnregister, INVALID_HANDLE_VALUE);
  197. }
  198. hCallbackToUnregister = InterlockedExchangePointer(
  199. &g_hSessionChangeCallbackHandle,
  200. NULL);
  201. if (hCallbackToUnregister != NULL)
  202. {
  203. UnregisterWaitEx(hCallbackToUnregister, INVALID_HANDLE_VALUE);
  204. }
  205. hCallbackToUnregister = InterlockedExchangePointer(
  206. &g_hWaitForStoppedCallbackHandle,
  207. NULL);
  208. if (hCallbackToUnregister != NULL)
  209. {
  210. UnregisterWaitEx(hCallbackToUnregister, INVALID_HANDLE_VALUE);
  211. }
  212. hCallbackToUnregister = InterlockedExchangePointer(
  213. &g_hWaitForStartedCallbackHandle,
  214. NULL);
  215. if (hCallbackToUnregister != NULL)
  216. {
  217. UnregisterWaitEx(hCallbackToUnregister, INVALID_HANDLE_VALUE);
  218. }
  219. //
  220. // The third parameter, lpvReserved, passed to DllMain
  221. // is NULL for FreeLibrary and non-NULL for ProcessExit.
  222. // Only clean up for FreeLibrary
  223. //
  224. if (lpvReserved == NULL)
  225. {
  226. if (g_hSessionChangeEvent != NULL)
  227. {
  228. CloseHandle(g_hSessionChangeEvent);
  229. }
  230. if (g_hTimerEvent != NULL)
  231. {
  232. CloseHandle(g_hTimerEvent);
  233. }
  234. //
  235. // Cleanup CritSecs.
  236. //
  237. DeleteCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
  238. DeleteCriticalSection(&g_SafeCreateHandleCS);
  239. DeleteCriticalSection(&g_SetStartedEventCS);
  240. DeleteCriticalSection(&g_TermSrvEnabledCS);
  241. DeleteCriticalSection(&g_RegisterForStoppedEventCS);
  242. DeleteCriticalSection(&g_DllMainCS);
  243. try {
  244. if (g_phlReaders)
  245. {
  246. g_fInClientRundown = TRUE;
  247. CHandle * pReader = g_phlReaders->GetFirst();
  248. while (pReader != NULL)
  249. {
  250. try
  251. {
  252. ((CReaderContext *) pReader)->EndTransaction(SCARD_LEAVE_CARD_FORCE);
  253. }
  254. catch (...){}
  255. pReader = g_phlReaders->GetNext(pReader);
  256. }
  257. delete g_phlReaders;
  258. g_phlReaders = NULL;
  259. }
  260. if (g_phlContexts)
  261. {
  262. delete g_phlContexts;
  263. g_phlContexts = NULL;
  264. }
  265. }
  266. catch (...)
  267. {
  268. }
  269. ReleaseStartedEvent();
  270. ReleaseStoppedEvent();
  271. if (g_hUnifiedStartedEvent != NULL)
  272. {
  273. CloseHandle(g_hUnifiedStartedEvent);
  274. }
  275. }
  276. break;
  277. }
  278. f = RedirDllMain(hInstDLL, fdwReason, lpvReserved);
  279. g_fInDllMain = FALSE;
  280. return(f);
  281. }
  282. //
  283. ////////////////////////////////////////////////////////////////////////////////
  284. //
  285. // SessionChangeCallback
  286. //
  287. VOID CALLBACK
  288. SessionChangeCallback(
  289. PVOID lpParameter,
  290. BOOLEAN TimerOrWaitFired)
  291. {
  292. WTS_CONNECTSTATE_CLASS *pConnectState = NULL;
  293. BOOL fConnected = FALSE;
  294. DWORD dw;
  295. HANDLE hCallbackToUnregister;
  296. EnterCriticalSection(&g_DllMainCS);
  297. if (g_fInDllMain)
  298. {
  299. LeaveCriticalSection(&g_DllMainCS);
  300. return;
  301. }
  302. //
  303. // If we are registered for local smart card stopped callbacks then
  304. // unregister
  305. //
  306. hCallbackToUnregister = InterlockedExchangePointer(
  307. &g_hWaitForStoppedCallbackHandle,
  308. NULL);
  309. if (hCallbackToUnregister != NULL)
  310. {
  311. UnregisterWait(hCallbackToUnregister);
  312. }
  313. //
  314. // Detect whether we are in a connected state or not
  315. //
  316. if (!WTSQuerySessionInformation(
  317. WTS_CURRENT_SERVER_HANDLE,
  318. WTS_CURRENT_SESSION,
  319. WTSConnectState,
  320. (LPTSTR *) &pConnectState,
  321. &dw))
  322. {
  323. //OutputDebugString("WINSCARD: SessionChangeCallback: WTSQuerySessionInformation failed!\n");
  324. LeaveCriticalSection(&g_DllMainCS);
  325. return;
  326. }
  327. fConnected = ( (*pConnectState == WTSActive) ||
  328. (*pConnectState == WTSConnected));
  329. WTSFreeMemory(pConnectState);
  330. //
  331. // If there is an outstanding wait, it may be waiting on the wrong event,
  332. // so cancel the wait here. When there is a connect event the
  333. // SetStartedEventWhenSCardSubsytemIsStarted() API will be called again
  334. // to wait on the correct event
  335. //
  336. hCallbackToUnregister = InterlockedExchangePointer(
  337. &g_hWaitForStartedCallbackHandle,
  338. NULL);
  339. if (hCallbackToUnregister != NULL)
  340. {
  341. UnregisterWait(hCallbackToUnregister);
  342. }
  343. if (!fConnected)
  344. {
  345. //
  346. // Make sure the unified started event isn't set since we
  347. // are now in a disconnected state
  348. //
  349. //OutputDebugString("WINSCARD: SessionChangeCallback: Disconnect\n");
  350. ResetEvent(g_hUnifiedStartedEvent);
  351. //
  352. // Only mark the contexts bad if we're not in a service, because we
  353. // know we're not redirecting if we're in a service.
  354. //
  355. if (FALSE == InAService())
  356. MarkContextsAsBad(TRUE);
  357. }
  358. else
  359. {
  360. //OutputDebugString("WINSCARD: SessionChangeCallback: Reconnect\n");
  361. SetRedirectDisabledValue();
  362. SetStartedEventWhenSCardSubsytemIsStarted(FALSE);
  363. }
  364. LeaveCriticalSection(&g_DllMainCS);
  365. }
  366. //
  367. ////////////////////////////////////////////////////////////////////////////////
  368. //
  369. // TimerCallback
  370. //
  371. VOID CALLBACK
  372. TimerCallback(
  373. PVOID lpParameter,
  374. BOOLEAN TimerOrWaitFired
  375. )
  376. {
  377. HANDLE h = NULL;
  378. BOOL fUnregister = TRUE;
  379. __try
  380. {
  381. EnterCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
  382. }
  383. __except(EXCEPTION_EXECUTE_HANDLER)
  384. {
  385. return;
  386. }
  387. if (g_dwClientCount == 0)
  388. {
  389. LeaveCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
  390. return;
  391. }
  392. //
  393. // The check for !g_fInDllMain is only to reduce the window in which a deadlock
  394. // can occur. The deadlock condition is as follows:
  395. //
  396. // 1) A thread enters winscard's DllMain (the thread in DllMain is of course holding the loader lock)
  397. // 2) TimerCallback gets called
  398. // 3) winscard's DllMain calls UnregisterWaitEx(INVALID_HANDLE_VALUE) for TimerCallback, which will
  399. // block until the TimerCallback callback completes.
  400. // 4) TimerCallback makes the WinStationRegisterNotificationEvent call which may try to load or unload
  401. // a DLL, which of course requires the loader lock.
  402. // 5) WHAMO!!!
  403. //
  404. if (!g_fInDllMain)
  405. {
  406. if (!g_fRegisteredForSessionChangeNotications)
  407. {
  408. if (WinStationRegisterNotificationEvent(
  409. g_hSessionChangeEvent,
  410. &g_SessionChangeID,
  411. NOTIFY_FOR_THIS_SESSION,
  412. WTS_CONSOLE_CONNECT_MASK |
  413. WTS_CONSOLE_DISCONNECT_MASK |
  414. WTS_REMOTE_CONNECT_MASK |
  415. WTS_REMOTE_DISCONNECT_MASK))
  416. {
  417. g_fRegisteredForSessionChangeNotications = TRUE;
  418. }
  419. else if (++g_dwTimerCallbacksMade < 60) // 60 attemps at 10 seconds each will be ten minutes
  420. {
  421. //
  422. // We still haven't succusfully registered for session change notifications and we haven't
  423. // exausted our max retries, so don't unregister the callback yet.
  424. //
  425. fUnregister = FALSE;
  426. }
  427. }
  428. }
  429. else
  430. {
  431. fUnregister = FALSE;
  432. }
  433. if (fUnregister)
  434. {
  435. h = InterlockedExchangePointer(&g_hWaitTimerEventCallbackHandle, NULL);
  436. if (h != NULL)
  437. {
  438. UnregisterWait(h);
  439. }
  440. }
  441. LeaveCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
  442. }
  443. //
  444. ////////////////////////////////////////////////////////////////////////////////
  445. //
  446. // RegisterForSessionChangeNotifications
  447. //
  448. BOOL
  449. RegisterForSessionChangeNotifications()
  450. {
  451. BOOL fRet = TRUE;
  452. //
  453. // Make sure we only register for session change notifications once
  454. //
  455. __try
  456. {
  457. EnterCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
  458. }
  459. __except(EXCEPTION_EXECUTE_HANDLER)
  460. {
  461. return FALSE;
  462. }
  463. g_dwClientCount++;
  464. //
  465. // If the global session change event and callback aren't setup then do that
  466. //
  467. if (g_hSessionChangeEvent == NULL)
  468. {
  469. g_hSessionChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  470. if (g_hSessionChangeEvent == NULL)
  471. {
  472. goto ErrorReturn;
  473. }
  474. if (!RegisterWaitForSingleObject(
  475. &g_hSessionChangeCallbackHandle,
  476. g_hSessionChangeEvent,
  477. SessionChangeCallback,
  478. 0,
  479. INFINITE,
  480. WT_EXECUTEDEFAULT))
  481. {
  482. CloseHandle(g_hSessionChangeEvent);
  483. g_hSessionChangeEvent = NULL;
  484. goto ErrorReturn;
  485. }
  486. }
  487. //
  488. // Register with the WTS subsystem for change notifications
  489. //
  490. if (!g_fRegisteredForSessionChangeNotications)
  491. {
  492. if (WinStationRegisterNotificationEvent(
  493. g_hSessionChangeEvent,
  494. &g_SessionChangeID,
  495. NOTIFY_FOR_THIS_SESSION,
  496. WTS_CONSOLE_CONNECT_MASK |
  497. WTS_CONSOLE_DISCONNECT_MASK |
  498. WTS_REMOTE_CONNECT_MASK |
  499. WTS_REMOTE_DISCONNECT_MASK))
  500. {
  501. g_fRegisteredForSessionChangeNotications = TRUE;
  502. }
  503. else if (g_hWaitTimerEventCallbackHandle == NULL)
  504. {
  505. //OutputDebugString("WINSCARD: RegisterForSessionChangeNotifications - WinStationRegisterNotificationEvent failed!!\n");
  506. //
  507. // Since the WinStationRegisterNotificationEvent call failed, TermSrv probably
  508. // isn't ready, so just register for a callback and try to register again later
  509. //
  510. g_dwTimerCallbacksMade = 0;
  511. if (g_hTimerEvent == NULL)
  512. {
  513. g_hTimerEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  514. }
  515. if (!RegisterWaitForSingleObject(
  516. &g_hWaitTimerEventCallbackHandle,
  517. g_hTimerEvent,
  518. TimerCallback,
  519. 0,
  520. 10000,
  521. WT_EXECUTEDEFAULT))
  522. {
  523. goto ErrorReturn;
  524. }
  525. }
  526. }
  527. Return:
  528. LeaveCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
  529. return fRet;
  530. ErrorReturn:
  531. g_dwClientCount--;
  532. fRet = FALSE;
  533. goto Return;
  534. }
  535. //
  536. ////////////////////////////////////////////////////////////////////////////////
  537. //
  538. // UnRegisterForSessionChangeNotifications
  539. //
  540. BOOL
  541. UnRegisterForSessionChangeNotifications()
  542. {
  543. BOOL fRet = TRUE;
  544. HANDLE h;
  545. //
  546. // Make sure we only unregister if there are no more clients
  547. //
  548. __try
  549. {
  550. EnterCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
  551. }
  552. __except(EXCEPTION_EXECUTE_HANDLER)
  553. {
  554. return FALSE;
  555. }
  556. if (g_dwClientCount == 0)
  557. {
  558. fRet = FALSE;
  559. goto Return;
  560. }
  561. else if (g_dwClientCount == 1)
  562. {
  563. g_dwClientCount = 0;
  564. //
  565. // If the timer callback is going then kill it
  566. //
  567. h = InterlockedExchangePointer(&g_hWaitTimerEventCallbackHandle, NULL);
  568. if (h != NULL)
  569. {
  570. UnregisterWait(h);
  571. }
  572. //
  573. // If we are registered then unregister
  574. //
  575. if (g_fRegisteredForSessionChangeNotications)
  576. {
  577. WinStationUnRegisterNotificationEvent(g_SessionChangeID);
  578. g_SessionChangeID = 0;
  579. }
  580. g_fRegisteredForSessionChangeNotications = FALSE;
  581. }
  582. else
  583. {
  584. g_dwClientCount--;
  585. }
  586. Return:
  587. LeaveCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
  588. return fRet;
  589. }
  590. //
  591. ////////////////////////////////////////////////////////////////////////////////
  592. //
  593. // SetStartedEventAfterTestingConnectedState
  594. //
  595. BOOL
  596. SetStartedEventAfterTestingConnectedState()
  597. {
  598. BOOL fRet = TRUE;
  599. WTS_CONNECTSTATE_CLASS *pConnectState = NULL;
  600. BOOL fConnected = FALSE;
  601. DWORD dw;
  602. BOOL fUnregister = FALSE;
  603. //
  604. // Register for connect/disconnect notifications from the WTS subsystem
  605. //
  606. if (!RegisterForSessionChangeNotifications())
  607. {
  608. //OutputDebugString("WINSCARD: SetStartedEventAfterTestingConnectedState - RegisterForSessionChangeNotifications failed!!\n");
  609. goto ErrorReturn;
  610. }
  611. fUnregister = TRUE;
  612. //
  613. // Detect whether we are in a connected state or not
  614. //
  615. if (!WTSQuerySessionInformation(
  616. WTS_CURRENT_SERVER_HANDLE,
  617. WTS_CURRENT_SESSION,
  618. WTSConnectState,
  619. (LPTSTR *) &pConnectState,
  620. &dw))
  621. {
  622. //OutputDebugString("WINSCARD: SetStartedEventAfterTestingConnectedState - WTSQuerySessionInformation failed!!\n");
  623. //
  624. // Since that failed, TermSrv is probably not started, so just go local
  625. //
  626. if (!SetStartedEventWhenSCardSubsytemIsStarted(TRUE))
  627. {
  628. goto ErrorReturn;
  629. }
  630. goto Return;
  631. }
  632. fConnected = ( (*pConnectState == WTSActive) ||
  633. (*pConnectState == WTSConnected));
  634. WTSFreeMemory(pConnectState);
  635. //
  636. // If we are connected, then call SetStartedEventWhenSCardSubsytemIsStarted
  637. // which will detect whether we are in local or redirect mode and subsequently
  638. // wait on the appropriate smart card subsystem (the local or the remote).
  639. // Otherwise, we are not connected, so do nothing since
  640. // SetStartedEventWhenSCardSubsytemIsStarted will be called once when we get
  641. // a connnected notification from the WTS subsystem
  642. //
  643. if (fConnected)
  644. {
  645. //OutputDebugString("WINSCARD: SetStartedEventAfterTestingConnectedState - Connected!!\n");
  646. if (!SetStartedEventWhenSCardSubsytemIsStarted(FALSE))
  647. {
  648. goto ErrorReturn;
  649. }
  650. }
  651. else
  652. {
  653. //OutputDebugString("WINSCARD: SetStartedEventAfterTestingConnectedState - NOT Connected!!\n");
  654. }
  655. Return:
  656. return fRet;
  657. ErrorReturn:
  658. if (fUnregister)
  659. {
  660. UnRegisterForSessionChangeNotifications();
  661. }
  662. fRet = FALSE;
  663. goto Return;
  664. }
  665. //
  666. ////////////////////////////////////////////////////////////////////////////////
  667. //
  668. // TermSrvEnabled
  669. //
  670. BOOL
  671. TermSrvEnabled()
  672. {
  673. BOOL fRet = TRUE;
  674. SC_HANDLE schSCM = NULL;
  675. SC_HANDLE schService = NULL;
  676. LPQUERY_SERVICE_CONFIG pServiceConfig = NULL;
  677. DWORD cbServiceConfig = 0;
  678. //
  679. // Make sure we only do this once
  680. //
  681. __try
  682. {
  683. EnterCriticalSection(&g_TermSrvEnabledCS);
  684. }
  685. __except(EXCEPTION_EXECUTE_HANDLER)
  686. {
  687. return FALSE;
  688. }
  689. if (g_fTermSrvEnableChecked)
  690. {
  691. goto Return;
  692. }
  693. //
  694. // Open the service control manager
  695. //
  696. schSCM = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
  697. if(schSCM == NULL)
  698. {
  699. //OutputDebugString("WINSCARD: TermSrvEnabled - OpenSCManagerW failed!!\n");
  700. goto Return;
  701. }
  702. //
  703. // open the "Terminal Services" service so we can query it's configuration
  704. //
  705. schService = OpenServiceW(schSCM, L"TermService", SERVICE_QUERY_CONFIG);
  706. if (schService == NULL)
  707. {
  708. //OutputDebugString("WINSCARD: TermSrvEnabled - OpenServiceW failed!!\n");
  709. goto Return;
  710. }
  711. //
  712. // Get and check the services configuration
  713. //
  714. QueryServiceConfig(schService, NULL, 0, &cbServiceConfig);
  715. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  716. {
  717. pServiceConfig = (LPQUERY_SERVICE_CONFIG) HeapAlloc(
  718. GetProcessHeap(),
  719. HEAP_ZERO_MEMORY,
  720. cbServiceConfig);
  721. if (pServiceConfig == NULL)
  722. {
  723. goto Return;
  724. }
  725. if (QueryServiceConfig(schService, pServiceConfig, cbServiceConfig, &cbServiceConfig))
  726. {
  727. if(pServiceConfig->dwStartType == SERVICE_DISABLED)
  728. {
  729. g_fTermSrvEnableChecked = TRUE;
  730. goto Return;
  731. }
  732. }
  733. else
  734. {
  735. //OutputDebugString("WINSCARD: TermSrvEnabled - QueryServiceConfig failed - 2!!\n");
  736. goto Return;
  737. }
  738. }
  739. else
  740. {
  741. //OutputDebugString("WINSCARD: TermSrvEnabled - QueryServiceConfig failed!!\n");
  742. goto Return;
  743. }
  744. g_fTermSrvEnableChecked = TRUE;
  745. g_bTermSrvEnabled = TRUE;
  746. Return:
  747. LeaveCriticalSection(&g_TermSrvEnabledCS);
  748. if (pServiceConfig != NULL)
  749. {
  750. HeapFree(GetProcessHeap(), 0, pServiceConfig);
  751. }
  752. if (schService != NULL)
  753. {
  754. CloseServiceHandle(schService);
  755. }
  756. if (schSCM != NULL)
  757. {
  758. CloseServiceHandle(schSCM);
  759. }
  760. return g_bTermSrvEnabled;
  761. }
  762. //
  763. ////////////////////////////////////////////////////////////////////////////////
  764. //
  765. // SafeCreateEvent
  766. //
  767. BOOL
  768. SafeCreateEvent(
  769. HANDLE *phEvent)
  770. {
  771. BOOL fRet = TRUE;
  772. __try
  773. {
  774. EnterCriticalSection(&g_SafeCreateHandleCS);
  775. }
  776. __except(EXCEPTION_EXECUTE_HANDLER)
  777. {
  778. return (FALSE);
  779. }
  780. if (*phEvent != NULL)
  781. {
  782. goto Return;
  783. }
  784. *phEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  785. if (*phEvent == NULL)
  786. {
  787. fRet = FALSE;
  788. }
  789. Return:
  790. LeaveCriticalSection(&g_SafeCreateHandleCS);
  791. return (fRet);
  792. }
  793. //
  794. ////////////////////////////////////////////////////////////////////////////////
  795. //
  796. // SmartCardSubsystemStoppedCallback and RegisterForStoppedCallback
  797. //
  798. VOID CALLBACK SmartCardSubsystemStoppedCallback(
  799. PVOID lpParameter,
  800. BOOLEAN TimerOrWaitFired
  801. )
  802. {
  803. HANDLE hCallbackToUnregister;
  804. EnterCriticalSection(&g_DllMainCS);
  805. if (g_fInDllMain)
  806. {
  807. LeaveCriticalSection(&g_DllMainCS);
  808. return;
  809. }
  810. //OutputDebugString("WINSCARD: SmartCardSubsystemStoppedCallback - resetting event \n");
  811. ResetEvent(g_hUnifiedStartedEvent);
  812. SetStartedEventWhenSCardSubsytemIsStarted(TRUE);
  813. hCallbackToUnregister = InterlockedExchangePointer(
  814. &g_hWaitForStoppedCallbackHandle,
  815. NULL);
  816. if (hCallbackToUnregister != NULL)
  817. {
  818. UnregisterWait(hCallbackToUnregister);
  819. }
  820. LeaveCriticalSection(&g_DllMainCS);
  821. }
  822. BOOL
  823. RegisterForStoppedCallback()
  824. {
  825. BOOL fRet = TRUE;
  826. BOOL fEnteredCS = FALSE;
  827. HANDLE h = NULL;
  828. h = AccessStoppedEvent();
  829. if (h == NULL)
  830. {
  831. goto ErrorReturn;
  832. }
  833. __try
  834. {
  835. EnterCriticalSection(&g_RegisterForStoppedEventCS);
  836. }
  837. __except(EXCEPTION_EXECUTE_HANDLER)
  838. {
  839. goto ErrorReturn;
  840. }
  841. fEnteredCS = TRUE;
  842. if (g_hWaitForStoppedCallbackHandle != NULL)
  843. {
  844. goto Return;
  845. }
  846. if (!RegisterWaitForSingleObject(
  847. &g_hWaitForStoppedCallbackHandle,
  848. h,
  849. SmartCardSubsystemStoppedCallback,
  850. 0,
  851. INFINITE,
  852. WT_EXECUTEONLYONCE))
  853. {
  854. goto ErrorReturn;
  855. }
  856. Return:
  857. if (fEnteredCS)
  858. {
  859. LeaveCriticalSection(&g_RegisterForStoppedEventCS);
  860. }
  861. return fRet;
  862. ErrorReturn:
  863. fRet = FALSE;
  864. goto Return;
  865. }
  866. //
  867. ////////////////////////////////////////////////////////////////////////////////
  868. //
  869. // SmartCardSubsystemStartedCallback
  870. //
  871. // This callback is fired when the smart card subsystem sets its started event.
  872. // NOTE: Both local and remote scard subsystems being started will fire this
  873. // same callback
  874. //
  875. VOID CALLBACK SmartCardSubsystemStartedCallback(
  876. PVOID lpParameter,
  877. BOOLEAN TimerOrWaitFired
  878. )
  879. {
  880. BOOL fLocal = (lpParameter == (PVOID) 1);
  881. HANDLE hCallbackToUnregister;
  882. EnterCriticalSection(&g_DllMainCS);
  883. if (g_fInDllMain)
  884. {
  885. LeaveCriticalSection(&g_DllMainCS);
  886. return;
  887. }
  888. //OutputDebugString("WINSCARD: SmartCardSubsystemStartedCallback - setting event \n");
  889. SetEvent(g_hUnifiedStartedEvent);
  890. if (fLocal)
  891. {
  892. RegisterForStoppedCallback();
  893. }
  894. hCallbackToUnregister = InterlockedExchangePointer(
  895. &g_hWaitForStartedCallbackHandle,
  896. NULL);
  897. if (hCallbackToUnregister != NULL)
  898. {
  899. UnregisterWait(hCallbackToUnregister);
  900. }
  901. LeaveCriticalSection(&g_DllMainCS);
  902. }
  903. //
  904. ////////////////////////////////////////////////////////////////////////////////
  905. //
  906. // SetStartedEventWhenSCardSubsytemIsStarted
  907. //
  908. BOOL
  909. SetStartedEventWhenSCardSubsytemIsStarted(
  910. BOOL fUseLocal)
  911. {
  912. HANDLE h = NULL;
  913. BOOL fRet = TRUE;
  914. BOOL fEnteredCritSec = FALSE;
  915. BOOL fLocal = FALSE;
  916. //
  917. // If termsrv is enabled and we are in redirect mode then get the
  918. // started event that corresponds to the remoted scard subsystem being
  919. // available, otherwise, get the started event of the local scard
  920. // resource manager
  921. //
  922. if (!fUseLocal && TermSrvEnabled() && InTSRedirectMode())
  923. {
  924. //OutputDebugString("WINSCARD: SetStartedEventWhenSCardSubsytemIsStarted REDIRECT\n");
  925. //
  926. // if redirect is disabled, then just get out
  927. //
  928. if (TS_REDIRECT_DISABLED)
  929. {
  930. goto Return;
  931. }
  932. if (TS_REDIRECT_READY)
  933. {
  934. h = pfnSCardAccessStartedEvent();
  935. }
  936. else
  937. {
  938. goto ErrorReturn;
  939. }
  940. }
  941. else
  942. {
  943. //OutputDebugString("WINSCARD: SetStartedEventWhenSCardSubsytemIsStarted LOCAL\n");
  944. h = AccessStartedEvent();
  945. fLocal = TRUE;
  946. }
  947. if (h == NULL)
  948. {
  949. goto ErrorReturn;
  950. }
  951. //
  952. // If the event is already set, then just set the event returned
  953. // to the caller and return
  954. //
  955. if (WAIT_OBJECT_0 == WaitForSingleObject(h, 0))
  956. {
  957. //OutputDebugString("WINSCARD: SetStartedEventWhenSCardSubsytemIsStarted SETTING EVENT\n");
  958. SetEvent(g_hUnifiedStartedEvent);
  959. if (fLocal)
  960. {
  961. RegisterForStoppedCallback();
  962. }
  963. goto Return;
  964. }
  965. //
  966. // The event wasn't set so we need to register a callback which
  967. // fires when the scard subsystem is started.
  968. //
  969. // Make sure only one callback is registered.
  970. //
  971. __try
  972. {
  973. EnterCriticalSection(&g_SetStartedEventCS);
  974. }
  975. __except(EXCEPTION_EXECUTE_HANDLER)
  976. {
  977. goto ErrorReturn;
  978. }
  979. fEnteredCritSec = TRUE;
  980. //
  981. // There is already a callback registered, so just get out
  982. //
  983. if (g_hWaitForStartedCallbackHandle != NULL)
  984. {
  985. goto Return;
  986. }
  987. //
  988. // Register for the callback. The callback is fired when the smart
  989. // card resource manager event is set (either the remote or the local
  990. // subsystem event, based on whether this is a redirected session or not).
  991. //
  992. if (!RegisterWaitForSingleObject(
  993. &g_hWaitForStartedCallbackHandle,
  994. h,
  995. SmartCardSubsystemStartedCallback,
  996. (fLocal ? ((PVOID) 1) : ((PVOID) 0)), // tell the callback whether this is local or not
  997. INFINITE,
  998. WT_EXECUTEONLYONCE))
  999. {
  1000. goto ErrorReturn;
  1001. }
  1002. Return:
  1003. if (fEnteredCritSec)
  1004. {
  1005. LeaveCriticalSection(&g_SetStartedEventCS);
  1006. }
  1007. return (fRet);
  1008. ErrorReturn:
  1009. fRet = FALSE;
  1010. goto Return;
  1011. }
  1012. //
  1013. ////////////////////////////////////////////////////////////////////////////////
  1014. //
  1015. // Service Manager Access Services
  1016. //
  1017. // The following services are used to manage user and terminal contexts for
  1018. // smartcards.
  1019. //
  1020. /*++
  1021. SCardEstablishContext:
  1022. This service establishes a context within which communication to the Service
  1023. Manager is performed.
  1024. Arguments:
  1025. dwScope supplies the scope under which this context acts. Possible values
  1026. are:
  1027. SCARD_SCOPE_USER - The context is a user context, and any database
  1028. operations are performed within the domain of the user.
  1029. SCARD_SCOPE_TERMINAL - The context is that of the current terminal, and
  1030. any database operations are performed within the domain of that
  1031. terminal. (The calling application must have appropriate access
  1032. permissions for any database actions.)
  1033. SCARD_SCOPE_SYSTEM - The context is the system context, and any database
  1034. operations are performed within the domain of the system. (The
  1035. calling application must have appropriate access permissions for any
  1036. database actions.)
  1037. pvReserved1 is reserved for future use, and must be NULL. [Reserved to
  1038. allow a suitably privileged management application to act on behalf of
  1039. another user.]
  1040. PvReserved2 is reserved for future use, and must be NULL. [Reserved to
  1041. allow a suitably privileged management application to act on behalf of
  1042. another terminal.]
  1043. phContext receives a handle to the established context, to be supplied to
  1044. other routines attempting to do work within the context.
  1045. Return Value:
  1046. A 32-bit value indicating whether or not the service completed successfully.
  1047. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  1048. represents an error condition.
  1049. Author:
  1050. Doug Barlow (dbarlow) 10/23/1996
  1051. --*/
  1052. #undef __SUBROUTINE__
  1053. #define __SUBROUTINE__ DBGT("SCardEstablishContext")
  1054. WINSCARDAPI LONG WINAPI
  1055. SCardEstablishContext(
  1056. IN DWORD dwScope,
  1057. IN LPCVOID pvReserved1,
  1058. IN LPCVOID pvReserved2,
  1059. OUT LPSCARDCONTEXT phContext)
  1060. {
  1061. LONG nReturn = SCARD_S_SUCCESS;
  1062. CSCardUserContext *pCtx = NULL;
  1063. try
  1064. {
  1065. if (NULL != pvReserved1)
  1066. throw (DWORD)SCARD_E_INVALID_VALUE;
  1067. if (NULL != pvReserved2)
  1068. throw (DWORD)SCARD_E_INVALID_VALUE;
  1069. if ((SCARD_SCOPE_USER != dwScope)
  1070. // && (SCARD_SCOPE_TERMINAL != dwScope) // Maybe NT V5+?
  1071. && (SCARD_SCOPE_SYSTEM != dwScope))
  1072. throw (DWORD)SCARD_E_INVALID_VALUE;
  1073. *phContext = 0; // Make sure it's valid.
  1074. pCtx = new CSCardUserContext(dwScope);
  1075. if (NULL == pCtx)
  1076. {
  1077. CalaisWarning(
  1078. __SUBROUTINE__,
  1079. DBGT("Client can't allocate a new context"));
  1080. throw (DWORD)SCARD_E_NO_MEMORY;
  1081. }
  1082. if (pCtx->InitFailed())
  1083. {
  1084. delete pCtx;
  1085. pCtx = NULL;
  1086. return SCARD_E_NO_MEMORY;
  1087. }
  1088. if (!SafeCreateEvent(&g_hUnifiedStartedEvent))
  1089. {
  1090. throw GetLastError();
  1091. }
  1092. //
  1093. // If TermSrv is enabled then register for session change notifications.
  1094. // Don't fail if we can't do this, since it may not be fatal
  1095. //
  1096. if (TermSrvEnabled() && RegisterForSessionChangeNotifications())
  1097. {
  1098. pCtx->fCallUnregister = TRUE;
  1099. }
  1100. else
  1101. {
  1102. pCtx->fCallUnregister = FALSE;
  1103. }
  1104. if (InTSRedirectMode())
  1105. {
  1106. HANDLE hHeap;
  1107. SCARDCONTEXT hContext = NULL;
  1108. HANDLE hEvent = NULL;
  1109. //
  1110. // if redirect is disabled, then just get out
  1111. //
  1112. if (TS_REDIRECT_DISABLED)
  1113. {
  1114. throw (DWORD)SCARD_E_NO_SERVICE;
  1115. }
  1116. hEvent = g_hUnifiedStartedEvent;
  1117. pCtx->AllocateMemory(0);
  1118. hHeap = pCtx->HeapHandle();
  1119. if (NULL == hHeap)
  1120. throw GetLastError();
  1121. if (!TS_REDIRECT_READY)
  1122. {
  1123. throw GetLastError();
  1124. }
  1125. nReturn = pfnSCardEstablishContext(dwScope, (LPCVOID)hHeap, (LPCVOID) hEvent, &hContext);
  1126. //
  1127. // See if there is an indication that the client's scardsvr service was shutdown
  1128. //
  1129. if (SCARD_E_NO_SERVICE == nReturn)
  1130. {
  1131. SetStartedEventAfterTestingConnectedState();
  1132. //OutputDebugString("WINSCARD: SCardEstablishContext: got E_NO_SERVICE!\n");
  1133. }
  1134. if (SCARD_S_SUCCESS != nReturn)
  1135. throw (DWORD)nReturn;
  1136. pCtx->SetRedirContext(hContext);
  1137. }
  1138. else
  1139. {
  1140. pCtx->EstablishContext();
  1141. }
  1142. *phContext = g_phlContexts->Add(pCtx);
  1143. }
  1144. catch (DWORD dwStatus)
  1145. {
  1146. if (NULL != pCtx)
  1147. delete pCtx;
  1148. nReturn = (LONG)dwStatus;
  1149. }
  1150. catch (...)
  1151. {
  1152. if (NULL != pCtx)
  1153. delete pCtx;
  1154. nReturn = SCARD_E_INVALID_PARAMETER;
  1155. }
  1156. return nReturn;
  1157. }
  1158. /*++
  1159. SCardIsValidContext:
  1160. This routine verifies that the context to the Service Manager is intact.
  1161. It is possible that if someone stops the Resource Manager Service, that
  1162. existing handles can be rendered useless, resulting in an
  1163. SCARD_E_SERVICE_STOPPED error. This routine simply tests to see if the
  1164. context is valid by pinging the server. It's used internally to validate
  1165. handles, and appears useful for external tools.
  1166. Arguments:
  1167. hContext supplies the handle to the context previously established via the
  1168. SCardEstablishContext service.
  1169. Return Value:
  1170. A 32-bit value indicating whether or not the service completed successfully.
  1171. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  1172. represents an error condition. Specific interesting error codes are:
  1173. SCARD_E_SERVICE_STOPPED - The Resource Manager Service has been ended.
  1174. SCARD_E_INVALID_HANDLE - The supplied handle isn't valid.
  1175. Author:
  1176. Doug Barlow (dbarlow) 11/2/1998
  1177. --*/
  1178. #undef __SUBROUTINE__
  1179. #define __SUBROUTINE__ DBGT("SCardIsValidContext")
  1180. WINSCARDAPI LONG WINAPI
  1181. SCardIsValidContext(
  1182. IN SCARDCONTEXT hContext)
  1183. {
  1184. LONG nReturn = SCARD_S_SUCCESS;
  1185. try
  1186. {
  1187. CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]);
  1188. SCARDCONTEXT hRedirContext = pCtx->GetRedirContext();
  1189. if (pCtx->IsBad())
  1190. {
  1191. throw (DWORD)SCARD_E_SERVICE_STOPPED;
  1192. }
  1193. if (NULL != hRedirContext) {
  1194. nReturn = pfnSCardIsValidContext(hRedirContext);
  1195. }
  1196. else
  1197. {
  1198. try
  1199. {
  1200. if (!pCtx->IsValidContext())
  1201. throw (DWORD)SCARD_E_SERVICE_STOPPED;
  1202. }
  1203. catch (...)
  1204. {
  1205. SCardReleaseContext(hContext);
  1206. throw;
  1207. }
  1208. }
  1209. }
  1210. catch (DWORD dwStatus)
  1211. {
  1212. nReturn = (LONG)dwStatus;
  1213. }
  1214. catch (...)
  1215. {
  1216. nReturn = SCARD_E_INVALID_PARAMETER;
  1217. }
  1218. return nReturn;
  1219. }
  1220. ////////////////////////////////////////////////////////////////////////////////
  1221. //
  1222. // IsSafeToUnregisterForSessionChangeNotifications
  1223. //
  1224. BOOL IsSafeToUnregisterForSessionChangeNotifications(
  1225. IN SCARDCONTEXT hContext)
  1226. {
  1227. //
  1228. // Check if the loader lock is held by the caller (in which case
  1229. // we may be in the caller's DllMain right now). If the lock is held,
  1230. // it's not safe to make the Unregister RPC call, since that could cause
  1231. // deadlock.
  1232. //
  1233. // IsSafe is TRUE if the current Thread is Not Equal to the lock's owning
  1234. // thread.
  1235. //
  1236. // Note, we tried using RtlIsThreadWithinLoaderCallout here, but that only
  1237. // tells us if we're in PROCESS_ATTACH. It doesn't tell us if we're in
  1238. // any other loader callbacks so it's not sufficient.
  1239. return ( NtCurrentTeb()->ClientId.UniqueThread ) !=
  1240. ( ((PRTL_CRITICAL_SECTION)(NtCurrentPeb()->LoaderLock))->OwningThread );
  1241. }
  1242. /*++
  1243. SCardReleaseContext:
  1244. This routine closes an established context to the Service Manager, and frees
  1245. any resources allocated under that context.
  1246. Arguments:
  1247. hContext supplies the handle to the context previously established via the
  1248. SCardEstablishContext service.
  1249. Return Value:
  1250. A 32-bit value indicating whether or not the service completed successfully.
  1251. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  1252. represents an error condition.
  1253. Author:
  1254. Doug Barlow (dbarlow) 10/23/1996
  1255. --*/
  1256. #undef __SUBROUTINE__
  1257. #define __SUBROUTINE__ DBGT("SCardReleaseContext")
  1258. WINSCARDAPI LONG WINAPI
  1259. SCardReleaseContext(
  1260. IN SCARDCONTEXT hContext)
  1261. {
  1262. LONG nReturn = SCARD_S_SUCCESS;
  1263. CSCardUserContext *pCtx = NULL;
  1264. try
  1265. {
  1266. pCtx = (CSCardUserContext *)g_phlContexts->Close(hContext);
  1267. SCARDCONTEXT hRedirContext = pCtx->GetRedirContext();
  1268. if (pCtx->fCallUnregister)
  1269. {
  1270. if (IsSafeToUnregisterForSessionChangeNotifications(hContext))
  1271. {
  1272. UnRegisterForSessionChangeNotifications();
  1273. }
  1274. }
  1275. if (NULL != hRedirContext)
  1276. {
  1277. if (pCtx->IsBad())
  1278. {
  1279. nReturn = pfnSCardReleaseBadContext(hRedirContext);
  1280. }
  1281. else
  1282. {
  1283. nReturn = pfnSCardReleaseContext(hRedirContext);
  1284. }
  1285. }
  1286. else
  1287. {
  1288. try
  1289. {
  1290. pCtx->Cancel();
  1291. pCtx->ReleaseContext();
  1292. }
  1293. catch (...) {}
  1294. }
  1295. delete pCtx;
  1296. pCtx = NULL;
  1297. }
  1298. catch (DWORD dwStatus)
  1299. {
  1300. nReturn = (LONG)dwStatus;
  1301. }
  1302. catch (...)
  1303. {
  1304. nReturn = SCARD_E_INVALID_PARAMETER;
  1305. }
  1306. return nReturn;
  1307. }
  1308. //
  1309. ////////////////////////////////////////////////////////////////////////////////
  1310. //
  1311. // Service Manager Support Routines
  1312. //
  1313. // The following services are supplied to simplify the use of the Service
  1314. // Manager API.
  1315. //
  1316. /*++
  1317. SCardFreeMemory:
  1318. This routine releases memory that has been returned from the Service Manager
  1319. API via the use of the SCARD_AUTOALLOCATE length designator.
  1320. Arguments:
  1321. hContext - This is the reference value returned from the
  1322. SCardEstablishContext service.
  1323. pvMem - This supplies the memory block to be released.
  1324. Return Value:
  1325. A 32-bit value indicating whether or not the service completed successfully.
  1326. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  1327. represents an error condition.
  1328. Author:
  1329. Doug Barlow (dbarlow) 10/23/1996
  1330. --*/
  1331. #undef __SUBROUTINE__
  1332. #define __SUBROUTINE__ DBGT("SCardFreeMemory")
  1333. WINSCARDAPI LONG WINAPI
  1334. SCardFreeMemory(
  1335. IN SCARDCONTEXT hContext,
  1336. IN LPCVOID pvMem)
  1337. {
  1338. LONG nReturn = SCARD_S_SUCCESS;
  1339. try
  1340. {
  1341. if ((NULL != pvMem) && ((LPVOID)g_wszBlank != pvMem))
  1342. {
  1343. if (NULL == hContext)
  1344. HeapFree(GetProcessHeap(), 0, (LPVOID)pvMem);
  1345. else
  1346. {
  1347. CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]);
  1348. nReturn = (LONG)pCtx->FreeMemory(pvMem);
  1349. }
  1350. }
  1351. }
  1352. catch (DWORD dwStatus)
  1353. {
  1354. nReturn = (LONG)dwStatus;
  1355. }
  1356. catch (...)
  1357. {
  1358. nReturn = SCARD_E_INVALID_PARAMETER;
  1359. }
  1360. return nReturn;
  1361. }
  1362. //
  1363. ////////////////////////////////////////////////////////////////////////////////
  1364. //
  1365. // Reader Services
  1366. //
  1367. // The following services supply means for tracking cards within readers.
  1368. //
  1369. /*++
  1370. SCardCancel:
  1371. This service is used to terminate any and all outstanding actions within the
  1372. context. The caller supplies the context handle under which outstanding
  1373. requests will be canceled. Not all requests are cancelable; only those
  1374. which require waiting for external action by the smartcard or user. Any
  1375. such outstanding action requests will terminate with a status indication
  1376. that the action was canceled. This is especially useful to force
  1377. outstanding SCardGetStatusChange calls to terminate.
  1378. Arguments:
  1379. hContext supplies the handle identifying the Service Manager Context
  1380. established previously via the SCardEstablishContext() service.
  1381. Return Value:
  1382. A 32-bit value indicating whether or not the service completed successfully.
  1383. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  1384. represents an error condition.
  1385. Author:
  1386. Doug Barlow (dbarlow) 10/23/1996
  1387. --*/
  1388. #undef __SUBROUTINE__
  1389. #define __SUBROUTINE__ DBGT("SCardCancel")
  1390. WINSCARDAPI LONG WINAPI
  1391. SCardCancel(
  1392. IN SCARDCONTEXT hContext)
  1393. {
  1394. LONG nReturn = SCARD_S_SUCCESS;
  1395. try
  1396. {
  1397. CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]);
  1398. SCARDCONTEXT hRedirContext = pCtx->GetRedirContext();
  1399. if (pCtx->IsBad())
  1400. {
  1401. throw (DWORD)SCARD_E_SERVICE_STOPPED;
  1402. }
  1403. if (NULL != hRedirContext) {
  1404. return pfnSCardCancel(hRedirContext);
  1405. }
  1406. else
  1407. pCtx->Cancel();
  1408. }
  1409. catch (DWORD dwStatus)
  1410. {
  1411. nReturn = (LONG)dwStatus;
  1412. }
  1413. catch (...)
  1414. {
  1415. nReturn = SCARD_E_INVALID_PARAMETER;
  1416. }
  1417. return nReturn;
  1418. }
  1419. //
  1420. ////////////////////////////////////////////////////////////////////////////////
  1421. //
  1422. // Card/Reader Access Services
  1423. //
  1424. // The following services provide means for establishing communication with
  1425. // the card.
  1426. //
  1427. /*++
  1428. SCardReconnect:
  1429. This service re-establishes an existing connection from the calling
  1430. application to the smartcard. This service is used to move a card handle
  1431. from direct access to general access (see Section 4), or to acknowledge and
  1432. clear an error condition that is preventing further access to the card.
  1433. Arguments:
  1434. hCard - This supplies the reference value obtained from a previous call to
  1435. the SCardConnect or SCardOpenReader service.
  1436. DwShareMode supplies a flag indicating whether or not other applications may
  1437. form connections to this card. Possible values are:
  1438. SCARD_SHARE_SHARED - This application is willing to share this card with
  1439. other applications.
  1440. SCARD_SHARE_EXCLUSIVE - This application is not willing to share this
  1441. card with other applications.
  1442. DwPreferredProtocols supplies a bit mask of acceptable protocols for this
  1443. connection. Possible values, which may be combined via the OR
  1444. operation, are:
  1445. SCARD_PROTOCOL_T0 - T=0 is an acceptable protocol.
  1446. SCARD_PROTOCOL_T1 - T=1 is an acceptable protocol.
  1447. DwInitialization supplies an indication as to the form of initialization
  1448. that should be performed on the card. Possible values are:
  1449. SCARD_LEAVE_CARD - Don't do anything special on reconnect
  1450. SCARD_RESET_CARD - Reset the card (Warm Reset)
  1451. SCARD_UNPOWER_CARD - Power down the card and reset it (Cold Reset)
  1452. pdwActiveProtocol receives a flag indicating the established active
  1453. protocol. Possible values are:
  1454. SCARD_PROTOCOL_T0 - T=0 is the active protocol.
  1455. SCARD_PROTOCOL_T1 - T=1 is the active protocol.
  1456. Return Value:
  1457. A 32-bit value indicating whether or not the service completed successfully.
  1458. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  1459. represents an error condition.
  1460. Author:
  1461. Doug Barlow (dbarlow) 10/23/1996
  1462. --*/
  1463. #undef __SUBROUTINE__
  1464. #define __SUBROUTINE__ DBGT("SCardReconnect")
  1465. WINSCARDAPI LONG WINAPI
  1466. SCardReconnect(
  1467. IN SCARDHANDLE hCard,
  1468. IN DWORD dwShareMode,
  1469. IN DWORD dwPreferredProtocols,
  1470. IN DWORD dwInitialization,
  1471. OUT LPDWORD pdwActiveProtocol)
  1472. {
  1473. LONG nReturn = SCARD_S_SUCCESS;
  1474. try
  1475. {
  1476. CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
  1477. if (pRdr->IsBad())
  1478. {
  1479. throw (DWORD)SCARD_E_SERVICE_STOPPED;
  1480. }
  1481. if (NULL != pRdr->GetRedirCard()) {
  1482. nReturn = pfnSCardReconnect(pRdr->GetRedirCard(), dwShareMode, dwPreferredProtocols, dwInitialization, pdwActiveProtocol);
  1483. }
  1484. else
  1485. {
  1486. pRdr->Reconnect(
  1487. dwShareMode,
  1488. dwPreferredProtocols,
  1489. dwInitialization);
  1490. if (NULL != pdwActiveProtocol)
  1491. *pdwActiveProtocol = pRdr->Protocol();
  1492. }
  1493. }
  1494. catch (DWORD dwStatus)
  1495. {
  1496. nReturn = (LONG)dwStatus;
  1497. }
  1498. catch (...)
  1499. {
  1500. nReturn = SCARD_E_INVALID_PARAMETER;
  1501. }
  1502. return nReturn;
  1503. }
  1504. /*++
  1505. SCardDisconnect:
  1506. This service terminates a previously opened connection between the calling
  1507. application and the smartcard in the target reader.
  1508. Arguments:
  1509. hCard - This supplies the reference value obtained from a previous call to
  1510. the SCardConnect or SCardOpenReader service.
  1511. dwDisposition - Supplies an indication of what should be done with the card
  1512. in the connected reader. Possible values are:
  1513. SCARD_LEAVE_CARD - Don't do anything special on close
  1514. SCARD_RESET_CARD - Reset the card on close
  1515. SCARD_UNPOWER_CARD - Power down the card on close
  1516. SCARD_EJECT_CARD - Eject the card on close
  1517. Return Value:
  1518. A 32-bit value indicating whether or not the service completed successfully.
  1519. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  1520. represents a warning condition. The connection is terminated regardless of
  1521. the return code.
  1522. Author:
  1523. Doug Barlow (dbarlow) 10/23/1996
  1524. --*/
  1525. #undef __SUBROUTINE__
  1526. #define __SUBROUTINE__ DBGT("SCardDisconnect")
  1527. WINSCARDAPI LONG WINAPI
  1528. SCardDisconnect(
  1529. IN SCARDHANDLE hCard,
  1530. IN DWORD dwDisposition)
  1531. {
  1532. CReaderContext *pRdr = NULL;
  1533. LONG nReturn = SCARD_S_SUCCESS;
  1534. try
  1535. {
  1536. pRdr = (CReaderContext *)g_phlReaders->Close(hCard);
  1537. if (NULL != pRdr->GetRedirCard()) {
  1538. nReturn = pfnSCardDisconnect(pRdr->GetRedirCard(), dwDisposition);
  1539. }
  1540. else
  1541. {
  1542. ASSERT(pRdr->Context()->m_hReaderHandle == hCard);
  1543. pRdr->Context()->m_hReaderHandle = NULL;
  1544. nReturn = pRdr->Disconnect(dwDisposition);
  1545. }
  1546. delete pRdr;
  1547. }
  1548. catch (DWORD dwStatus)
  1549. {
  1550. if (NULL != pRdr)
  1551. delete pRdr;
  1552. nReturn = (LONG)dwStatus;
  1553. }
  1554. catch (...)
  1555. {
  1556. if (NULL != pRdr)
  1557. delete pRdr;
  1558. nReturn = SCARD_E_INVALID_PARAMETER;
  1559. }
  1560. return nReturn;
  1561. }
  1562. /*++
  1563. SCardBeginTransaction:
  1564. This service temporarily blocks other applications from accessing the
  1565. smartcard, in order for this application to perform an operation that
  1566. requires multiple interactions.
  1567. Arguments:
  1568. hCard - This supplies the reference value obtained from a previous call to
  1569. the SCardConnect or SCardOpenReader service.
  1570. Return Value:
  1571. A 32-bit value indicating whether or not the service completed successfully.
  1572. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  1573. represents an error condition.
  1574. Author:
  1575. Doug Barlow (dbarlow) 10/23/1996
  1576. --*/
  1577. #undef __SUBROUTINE__
  1578. #define __SUBROUTINE__ DBGT("SCardBeginTransaction")
  1579. WINSCARDAPI LONG WINAPI
  1580. SCardBeginTransaction(
  1581. IN SCARDHANDLE hCard)
  1582. {
  1583. LONG nReturn = SCARD_S_SUCCESS;
  1584. try
  1585. {
  1586. CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
  1587. if (pRdr->IsBad())
  1588. {
  1589. throw (DWORD)SCARD_E_SERVICE_STOPPED;
  1590. }
  1591. if (NULL != pRdr->GetRedirCard()) {
  1592. nReturn = pfnSCardBeginTransaction(pRdr->GetRedirCard());
  1593. }
  1594. else
  1595. pRdr->BeginTransaction();
  1596. }
  1597. catch (DWORD dwStatus)
  1598. {
  1599. nReturn = (LONG)dwStatus;
  1600. }
  1601. catch (...)
  1602. {
  1603. nReturn = SCARD_E_INVALID_PARAMETER;
  1604. }
  1605. return nReturn;
  1606. }
  1607. /*++
  1608. SCardEndTransaction:
  1609. This service completes a previously declared transaction, allowing other
  1610. applications to resume interactions with the card.
  1611. Arguments:
  1612. hCard - This supplies the reference value obtained from a previous call to
  1613. the SCardConnect or SCardOpenReader service.
  1614. dwDisposition - Supplies an indication of what should be done with the card
  1615. in the connected reader. Possible values are:
  1616. SCARD_LEAVE_CARD - Don't do anything special on close
  1617. SCARD_RESET_CARD - Reset the card on close
  1618. SCARD_UNPOWER_CARD - Power down the card on close
  1619. SCARD_EJECT_CARD - Eject the card on close
  1620. Return Value:
  1621. A 32-bit value indicating whether or not the service completed successfully.
  1622. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  1623. represents an error condition.
  1624. Author:
  1625. Doug Barlow (dbarlow) 10/23/1996
  1626. --*/
  1627. #undef __SUBROUTINE__
  1628. #define __SUBROUTINE__ DBGT("SCardEndTransaction")
  1629. WINSCARDAPI LONG WINAPI
  1630. SCardEndTransaction(
  1631. IN SCARDHANDLE hCard,
  1632. IN DWORD dwDisposition)
  1633. {
  1634. LONG nReturn = SCARD_S_SUCCESS;
  1635. try
  1636. {
  1637. CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
  1638. if (pRdr->IsBad())
  1639. {
  1640. throw (DWORD)SCARD_E_SERVICE_STOPPED;
  1641. }
  1642. if (NULL != pRdr->GetRedirCard()) {
  1643. nReturn = pfnSCardEndTransaction(pRdr->GetRedirCard(), dwDisposition);
  1644. }
  1645. else
  1646. pRdr->EndTransaction(dwDisposition);
  1647. }
  1648. catch (DWORD dwStatus)
  1649. {
  1650. nReturn = (LONG)dwStatus;
  1651. }
  1652. catch (...)
  1653. {
  1654. nReturn = SCARD_E_INVALID_PARAMETER;
  1655. }
  1656. return nReturn;
  1657. }
  1658. /*++
  1659. SCardState:
  1660. This routine provides the current state of the reader. It may be used at
  1661. any time following a successful call to SCardConnect or SCardOpenReader, and
  1662. prior to a successful call to SCardDisconnect. It does not effect the state
  1663. of the reader or driver.
  1664. Arguments:
  1665. hCard - This is the reference value returned from the SCardConnect or
  1666. SCardOpenReader service.
  1667. pdwState - This receives the current state of the reader. Upon success, it
  1668. receives one of the following state indicators:
  1669. SCARD_ABSENT - This value implies there is no card in the reader.
  1670. SCARD_PRESENT - This value implies there is a card is present in the
  1671. reader, but that it has not been moved into position for use.
  1672. SCARD_SWALLOWED - This value implies there is a card in the reader in
  1673. position for use. The card is not powered.
  1674. SCARD_POWERED - This value implies there is power is being provided to
  1675. the card, but the Reader Driver is unaware of the mode of the card.
  1676. SCARD_NEGOTIABLEMODE - This value implies the card has been reset and is
  1677. awaiting PTS negotiation.
  1678. SCARD_SPECIFICMODE - This value implies the card has been reset and
  1679. specific communication protocols have been established.
  1680. pdwProtocol - This receives the current protocol, if any. Possible returned
  1681. values are listed below. Other values may be added in the future. The
  1682. returned value is only meaningful if the returned state is
  1683. SCARD_SPECIFICMODE.
  1684. SCARD_PROTOCOL_RAW - The Raw Transfer Protocol is in use.
  1685. SCARD_PROTOCOL_T0 - The ISO 7816/3 T=0 Protocol is in use.
  1686. SCARD_PROTOCOL_T1 - The ISO 7816/3 T=1 Protocol is in use.
  1687. pbAtr - This parameter points to a 32-byte buffer which receives the ATR
  1688. string from the currently inserted card, if available.
  1689. pbcAtrLen - This points to a DWORD which supplies the length of the pbAtr
  1690. buffer, and receives the actual number of bytes in the ATR string.
  1691. Return Value:
  1692. A 32-bit value indicating whether or not the service completed successfully.
  1693. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  1694. represents an error condition.
  1695. Author:
  1696. Doug Barlow (dbarlow) 10/23/1996
  1697. --*/
  1698. #undef __SUBROUTINE__
  1699. #define __SUBROUTINE__ DBGT("SCardState")
  1700. WINSCARDAPI LONG WINAPI
  1701. SCardState(
  1702. IN SCARDHANDLE hCard,
  1703. OUT LPDWORD pdwState,
  1704. OUT LPDWORD pdwProtocol,
  1705. OUT LPBYTE pbAtr,
  1706. IN OUT LPDWORD pcbAtrLen)
  1707. {
  1708. LONG nReturn = SCARD_S_SUCCESS;
  1709. try
  1710. {
  1711. CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
  1712. if (pRdr->IsBad())
  1713. {
  1714. throw (DWORD)SCARD_E_SERVICE_STOPPED;
  1715. }
  1716. if (NULL != pRdr->GetRedirCard()) {
  1717. nReturn = pfnSCardState(pRdr->GetRedirCard(), pdwState, pdwProtocol, pbAtr, pcbAtrLen);
  1718. }
  1719. else
  1720. {
  1721. CBuffer bfAtr, bfRdr;
  1722. DWORD dwLocalState, dwLocalProtocol;
  1723. pRdr->Status(&dwLocalState, &dwLocalProtocol, bfAtr, bfRdr);
  1724. if (NULL != pdwState)
  1725. *pdwState = dwLocalState;
  1726. if (NULL != pdwProtocol)
  1727. *pdwProtocol = dwLocalProtocol;
  1728. if (NULL != pcbAtrLen)
  1729. PlaceResult(pRdr->Context()->Parent(), bfAtr, pbAtr, pcbAtrLen);
  1730. }
  1731. }
  1732. catch (DWORD dwStatus)
  1733. {
  1734. nReturn = (LONG)dwStatus;
  1735. }
  1736. catch (...)
  1737. {
  1738. nReturn = SCARD_E_INVALID_PARAMETER;
  1739. }
  1740. return nReturn;
  1741. }
  1742. /*++
  1743. SCardTransmit:
  1744. This routine sends a service request to the smartcard, and expects to
  1745. receive data back from the card.
  1746. Arguments:
  1747. hCard - This is the reference value returned from the SCardConnect service.
  1748. pioSendPci - This supplies the protocol header structure for the
  1749. instruction. This buffer is in the format of a SCARD_IO_REQUEST
  1750. structure, followed by the specific protocol control information.
  1751. pbSendBuffer - This supplies the actual data to be written to the card in
  1752. conjunction with the command.
  1753. cbSendLength - This supplies the length of the pbSendBuffer parameter, in
  1754. bytes.
  1755. pioRecvPci - This supplies the protocol header structure for the
  1756. instruction, followed by a buffer in which to receive any returned
  1757. protocol control information specific to the protocol in use. This
  1758. parameter may be NULL if no returned PCI is desired.
  1759. pbRecvBuffer - This receives any data returned from the card in conjunction
  1760. with the command.
  1761. pcbRecvLength - This supplies the length of the pbRecvBuffer parameter, in
  1762. bytes, and receives the actual number of bytes received from the
  1763. smartcard. If the buffer length is specified as SCARD_AUTOALLOCATE,
  1764. then pbAttrBuffer is converted to a pointer to a byte pointer, and
  1765. receives the address of a block of memory containing the returned data.
  1766. This block of memory must be deallocated via the SCardFreeMemory()
  1767. service.
  1768. Return Value:
  1769. A 32-bit value indicating whether or not the service completed successfully.
  1770. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  1771. represents an error condition.
  1772. Author:
  1773. Doug Barlow (dbarlow) 2/6/1997
  1774. --*/
  1775. #undef __SUBROUTINE__
  1776. #define __SUBROUTINE__ DBGT("SCardTransmit")
  1777. WINSCARDAPI LONG WINAPI
  1778. SCardTransmit(
  1779. IN SCARDHANDLE hCard,
  1780. IN LPCSCARD_IO_REQUEST pioSendPci,
  1781. IN LPCBYTE pbSendBuffer,
  1782. IN DWORD cbSendLength,
  1783. IN OUT LPSCARD_IO_REQUEST pioRecvPci,
  1784. OUT LPBYTE pbRecvBuffer,
  1785. IN OUT LPDWORD pcbRecvLength)
  1786. {
  1787. LONG nReturn = SCARD_S_SUCCESS;
  1788. try
  1789. {
  1790. CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
  1791. if (pRdr->IsBad())
  1792. {
  1793. throw (DWORD)SCARD_E_SERVICE_STOPPED;
  1794. }
  1795. if (NULL != pRdr->GetRedirCard()) {
  1796. nReturn = pfnSCardTransmit(pRdr->GetRedirCard(), pioSendPci, pbSendBuffer, cbSendLength, pioRecvPci, pbRecvBuffer, pcbRecvLength);
  1797. }
  1798. else
  1799. {
  1800. CBuffer bfData(*pcbRecvLength);
  1801. DWORD dwLen = 0;
  1802. if (NULL != pcbRecvLength)
  1803. {
  1804. if (SCARD_AUTOALLOCATE != *pcbRecvLength)
  1805. dwLen = *pcbRecvLength;
  1806. }
  1807. pRdr->Transmit(
  1808. pioSendPci,
  1809. pbSendBuffer,
  1810. cbSendLength,
  1811. pioRecvPci,
  1812. bfData,
  1813. dwLen);
  1814. PlaceResult(
  1815. pRdr->Context()->Parent(),
  1816. bfData,
  1817. pbRecvBuffer,
  1818. pcbRecvLength);
  1819. }
  1820. }
  1821. catch (DWORD dwStatus)
  1822. {
  1823. nReturn = (LONG)dwStatus;
  1824. }
  1825. catch (...)
  1826. {
  1827. nReturn = SCARD_E_INVALID_PARAMETER;
  1828. }
  1829. return nReturn;
  1830. }
  1831. //
  1832. ////////////////////////////////////////////////////////////////////////////////
  1833. //
  1834. // Reader Control Routines
  1835. //
  1836. // The following services provide for direct, low-level manipulation of the
  1837. // reader by the calling application allowing it control over the
  1838. // attributes of the communications with the card.
  1839. //
  1840. /*++
  1841. SCardControl:
  1842. This routine provides for direct application control of the reader, should
  1843. it be necessary. It may be used at any time following a successful call to
  1844. SCardConnect or SCardOpenReader, and prior to a successful call to
  1845. SCardDisconnect. The effect on the state of the reader is dependent on the
  1846. control code.
  1847. Arguments:
  1848. hCard - This is the reference value returned from the SCardConnect or
  1849. SCardOpenReader service.
  1850. dwControlCode - This supplies the control code for the operation. This value
  1851. identifies the specific operation to be performed.
  1852. pvInBuffer - This supplies a pointer to a buffer that contains the data
  1853. required to perform the operation. This parameter can be NULL if the
  1854. dwControlCode parameter specifies an operation that does not require
  1855. input data.
  1856. cbInBufferSize - This supplies the size, in bytes, of the buffer pointed to
  1857. by pvInBuffer.
  1858. pvOutBuffer - This buffer receives the operation's output data. This
  1859. parameter can be NULL if the dwControlCode parameter specifies an
  1860. operation that does not produce output data.
  1861. cbOutBufferSize - This supplies the size, in bytes, of the buffer pointed to
  1862. by pvOutBuffer.
  1863. pcbBytesReturned - This receives the size, in bytes, of the data stored into
  1864. the buffer pointed to by pvOutBuffer.
  1865. Return Value:
  1866. A 32-bit value indicating whether or not the service completed successfully.
  1867. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  1868. represents an error condition.
  1869. Author:
  1870. Doug Barlow (dbarlow) 10/23/1996
  1871. --*/
  1872. #undef __SUBROUTINE__
  1873. #define __SUBROUTINE__ DBGT("SCardControl")
  1874. WINSCARDAPI LONG WINAPI
  1875. SCardControl(
  1876. IN SCARDHANDLE hCard,
  1877. IN DWORD dwControlCode,
  1878. IN LPCVOID pvInBuffer,
  1879. IN DWORD cbInBufferSize,
  1880. OUT LPVOID pvOutBuffer,
  1881. IN DWORD cbOutBufferSize,
  1882. OUT LPDWORD pcbBytesReturned)
  1883. {
  1884. LONG nReturn = SCARD_S_SUCCESS;
  1885. try
  1886. {
  1887. CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
  1888. if (pRdr->IsBad())
  1889. {
  1890. throw (DWORD)SCARD_E_SERVICE_STOPPED;
  1891. }
  1892. if (NULL != pRdr->GetRedirCard()) {
  1893. nReturn = pfnSCardControl(pRdr->GetRedirCard(), dwControlCode, pvInBuffer, cbInBufferSize, pvOutBuffer, cbOutBufferSize, pcbBytesReturned);
  1894. }
  1895. else
  1896. {
  1897. CBuffer bfResponse(cbOutBufferSize);
  1898. *pcbBytesReturned = cbOutBufferSize;
  1899. pRdr->Control(dwControlCode, pvInBuffer, cbInBufferSize, bfResponse);
  1900. PlaceResult(
  1901. pRdr->Context()->Parent(),
  1902. bfResponse,
  1903. (LPBYTE)pvOutBuffer,
  1904. pcbBytesReturned);
  1905. }
  1906. }
  1907. catch (DWORD dwStatus)
  1908. {
  1909. nReturn = (LONG)dwStatus;
  1910. }
  1911. catch (...)
  1912. {
  1913. nReturn = SCARD_E_INVALID_PARAMETER;
  1914. }
  1915. return nReturn;
  1916. }
  1917. /*++
  1918. SCardGetAttrib:
  1919. This routine gets the current communications attributes for the given
  1920. handle. It does not effect the state of the reader, driver, or card.
  1921. Arguments:
  1922. hCard - This is the reference value returned from the SCardConnect or
  1923. SCardOpenReader service.
  1924. dwAttrId - This supplies the identifier for the attribute to get.
  1925. pbAttr - This buffer receives the attribute corresponding to the attribute
  1926. id supplied in the dwAttrId parameter. If this value is NULL, the
  1927. supplied buffer length in pcbAttrLength is ignored, the length of the
  1928. buffer that would have been returned had this parameter not been null is
  1929. written to pcbAttrLength, and a success code is returned.
  1930. pcbAttrLength - This supplies the length of the pbAttr buffer in bytes, and
  1931. receives the actual length of the received attribute. If the buffer
  1932. length is specified as SCARD_AUTOALLOCATE, then pbAttrBuffer is
  1933. converted to a pointer to a byte pointer, and receives the address of a
  1934. block of memory containing the attribute. This block of memory must be
  1935. deallocated via the SCardFreeMemory() service.
  1936. Return Value:
  1937. A 32-bit value indicating whether or not the service completed successfully.
  1938. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  1939. represents an error condition.
  1940. Note that strings are always returned as ANSI characters, per PC/SC
  1941. standards.
  1942. Author:
  1943. Doug Barlow (dbarlow) 10/23/1996
  1944. --*/
  1945. #undef __SUBROUTINE__
  1946. #define __SUBROUTINE__ DBGT("SCardGetAttrib")
  1947. WINSCARDAPI LONG WINAPI
  1948. SCardGetAttrib(
  1949. IN SCARDHANDLE hCard,
  1950. IN DWORD dwAttrId,
  1951. OUT LPBYTE pbAttr,
  1952. IN OUT LPDWORD pcbAttrLen)
  1953. {
  1954. LONG nReturn = SCARD_S_SUCCESS;
  1955. try
  1956. {
  1957. CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
  1958. if (pRdr->IsBad())
  1959. {
  1960. throw (DWORD)SCARD_E_SERVICE_STOPPED;
  1961. }
  1962. if (NULL != pRdr->GetRedirCard()) {
  1963. nReturn = pfnSCardGetAttrib(pRdr->GetRedirCard(), dwAttrId, pbAttr, pcbAttrLen);
  1964. }
  1965. else
  1966. {
  1967. CBuffer bfAttrib;
  1968. DWORD dwLen = 0;
  1969. if (NULL != pcbAttrLen)
  1970. {
  1971. if (SCARD_AUTOALLOCATE != *pcbAttrLen)
  1972. dwLen = *pcbAttrLen;
  1973. }
  1974. switch (dwAttrId)
  1975. {
  1976. case SCARD_ATTR_DEVICE_FRIENDLY_NAME_A:
  1977. {
  1978. CBuffer bfSysName, bfNames;
  1979. CTextMultistring mtzNames;
  1980. pRdr->GetAttrib(SCARD_ATTR_DEVICE_SYSTEM_NAME, bfSysName, MAX_PATH);
  1981. ListReaderNames(
  1982. pRdr->Context()->Scope(),
  1983. bfSysName,
  1984. bfNames);
  1985. mtzNames = (LPCTSTR)bfNames.Access();
  1986. bfAttrib.Set(
  1987. (LPCBYTE)((LPCSTR)mtzNames),
  1988. (mtzNames.Length()) * sizeof(CHAR));
  1989. break;
  1990. }
  1991. case SCARD_ATTR_DEVICE_FRIENDLY_NAME_W:
  1992. {
  1993. CBuffer bfSysName, bfNames;
  1994. CTextMultistring mtzNames;
  1995. pRdr->GetAttrib(SCARD_ATTR_DEVICE_SYSTEM_NAME, bfSysName, MAX_PATH);
  1996. ListReaderNames(
  1997. pRdr->Context()->Scope(),
  1998. bfSysName,
  1999. bfNames);
  2000. mtzNames = (LPCTSTR)bfNames.Access();
  2001. bfAttrib.Set(
  2002. (LPCBYTE)((LPCWSTR)mtzNames),
  2003. (mtzNames.Length()) * sizeof(WCHAR));
  2004. break;
  2005. }
  2006. case SCARD_ATTR_DEVICE_SYSTEM_NAME_A:
  2007. {
  2008. CBuffer bfSysName;
  2009. CTextString szSysName;
  2010. pRdr->GetAttrib(SCARD_ATTR_DEVICE_SYSTEM_NAME, bfSysName, dwLen);
  2011. szSysName = (LPCTSTR)bfSysName.Access();
  2012. bfAttrib.Set(
  2013. (LPCBYTE)((LPCSTR)szSysName),
  2014. (szSysName.Length() + 1) * sizeof(CHAR));
  2015. break;
  2016. }
  2017. case SCARD_ATTR_DEVICE_SYSTEM_NAME_W:
  2018. {
  2019. CBuffer bfSysName;
  2020. CTextString szSysName;
  2021. pRdr->GetAttrib(SCARD_ATTR_DEVICE_SYSTEM_NAME, bfSysName, dwLen);
  2022. szSysName = (LPCTSTR)bfSysName.Access();
  2023. bfAttrib.Set(
  2024. (LPCBYTE)((LPCWSTR)szSysName),
  2025. (szSysName.Length() + 1) * sizeof(WCHAR));
  2026. break;
  2027. }
  2028. default:
  2029. pRdr->GetAttrib(dwAttrId, bfAttrib, dwLen);
  2030. }
  2031. PlaceResult(pRdr->Context()->Parent(), bfAttrib, pbAttr, pcbAttrLen);
  2032. }
  2033. }
  2034. catch (DWORD dwStatus)
  2035. {
  2036. nReturn = (LONG)dwStatus;
  2037. }
  2038. catch (...)
  2039. {
  2040. nReturn = SCARD_E_INVALID_PARAMETER;
  2041. }
  2042. return nReturn;
  2043. }
  2044. /*++
  2045. SCardSetAttrib:
  2046. This routine sets the current communications attributes for the given
  2047. handle. It does not effect the state of the reader, driver, or card. Not
  2048. all attributes are settable at all times, as many of the attributes are
  2049. directly under control of the transport protocol. These attributes are
  2050. offered only as a suggestion to the reader -- the reader may ignore any
  2051. attributes it feels are inappropriate.
  2052. Arguments:
  2053. hCard - This is the reference value returned from the SCardOpenReader
  2054. service.
  2055. dwAttrId - This supplies the identifier for the attribute to get.
  2056. pbAttr - This buffer supplies the attribute corresponding to the attribute
  2057. id supplied in the dwAttrId parameter.
  2058. cbAttrLength - This supplies the length of the attribute value in pbAttr
  2059. buffer in bytes.
  2060. Return Value:
  2061. A 32-bit value indicating whether or not the service completed successfully.
  2062. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
  2063. represents an error condition.
  2064. Author:
  2065. Doug Barlow (dbarlow) 10/23/1996
  2066. --*/
  2067. #undef __SUBROUTINE__
  2068. #define __SUBROUTINE__ DBGT("SCardSetAttrib")
  2069. WINSCARDAPI LONG WINAPI
  2070. SCardSetAttrib(
  2071. IN SCARDHANDLE hCard,
  2072. IN DWORD dwAttrId,
  2073. IN LPCBYTE pbAttr,
  2074. IN DWORD cbAttrLen)
  2075. {
  2076. LONG nReturn = SCARD_S_SUCCESS;
  2077. try
  2078. {
  2079. CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
  2080. if (pRdr->IsBad())
  2081. {
  2082. throw (DWORD)SCARD_E_SERVICE_STOPPED;
  2083. }
  2084. if (NULL != pRdr->GetRedirCard()) {
  2085. nReturn = pfnSCardSetAttrib(pRdr->GetRedirCard(), dwAttrId, pbAttr, cbAttrLen);
  2086. }
  2087. else
  2088. pRdr->SetAttrib(dwAttrId, pbAttr, cbAttrLen);
  2089. }
  2090. catch (DWORD dwStatus)
  2091. {
  2092. nReturn = (LONG)dwStatus;
  2093. }
  2094. catch (...)
  2095. {
  2096. nReturn = SCARD_E_INVALID_PARAMETER;
  2097. }
  2098. return nReturn;
  2099. }
  2100. //
  2101. ////////////////////////////////////////////////////////////////////////////////
  2102. //
  2103. // SCard Service Information
  2104. //
  2105. // The following services are used to manage the Calais Service itself.
  2106. // These routines are not documented to users, and are not guaranteed
  2107. // to exist in future releases.
  2108. //
  2109. /*++
  2110. SCardAccessStartedEvent:
  2111. This function obtains a local handle to the Calais Resource Manager Start
  2112. event. The handle must be released via the SCardReleaseStartedEvent
  2113. service.
  2114. Arguments:
  2115. None
  2116. Return Value:
  2117. The Handle, or NULL if an error occurs.
  2118. Throws:
  2119. None
  2120. Remarks:
  2121. Programs other than the resource manager should only wait on these flags.
  2122. Author:
  2123. Doug Barlow (dbarlow) 7/1/1998
  2124. --*/
  2125. #undef __SUBROUTINE__
  2126. #define __SUBROUTINE__ DBGT("SCardAccessStartedEvent")
  2127. WINSCARDAPI HANDLE WINAPI
  2128. SCardAccessStartedEvent(
  2129. void)
  2130. {
  2131. HANDLE hRet = NULL;
  2132. //
  2133. // Create the event that is passed back to the caller...
  2134. // if it hasn't already been created
  2135. //
  2136. if (SafeCreateEvent(&g_hUnifiedStartedEvent))
  2137. {
  2138. hRet = g_hUnifiedStartedEvent;
  2139. }
  2140. else
  2141. {
  2142. goto ErrorReturn;
  2143. }
  2144. if (TermSrvEnabled())
  2145. {
  2146. //
  2147. //
  2148. //
  2149. if (!SetStartedEventAfterTestingConnectedState())
  2150. {
  2151. goto ErrorReturn;
  2152. }
  2153. }
  2154. else
  2155. {
  2156. //
  2157. // TermSrv is disabled, so go ahead and call the
  2158. // SetStartedEventWhenSCardSubsytemIsStarted function which will make sure
  2159. // the event which is returned to the caller will be set when the LOCAL
  2160. // smart card subsystem becomes available.
  2161. //
  2162. if (!SetStartedEventWhenSCardSubsytemIsStarted(TRUE))
  2163. {
  2164. goto ErrorReturn;
  2165. }
  2166. }
  2167. Return:
  2168. return (hRet);
  2169. ErrorReturn:
  2170. hRet = NULL;
  2171. goto Return;
  2172. }
  2173. /*++
  2174. SCardAccessNewReaderEvent:
  2175. This function obtains a local handle to the Calais Resource Manager's New
  2176. Reader event. The handle must be released via the
  2177. SCardReleaseNewReaderEvent service.
  2178. Arguments:
  2179. None
  2180. Return Value:
  2181. The Handle, or NULL if an error occurs.
  2182. Throws:
  2183. None
  2184. Remarks:
  2185. Programs other than the resource manager should only wait on these flags.
  2186. Author:
  2187. Doug Barlow (dbarlow) 7/1/1998
  2188. --*/
  2189. #undef __SUBROUTINE__
  2190. #define __SUBROUTINE__ DBGT("SCardAccessNewReaderEvent")
  2191. WINSCARDAPI HANDLE WINAPI
  2192. SCardAccessNewReaderEvent(
  2193. void)
  2194. {
  2195. return AccessNewReaderEvent();
  2196. }
  2197. /*++
  2198. SCardReleaseStartedEvent:
  2199. This function releases a previously accessed handle to the Calais
  2200. Resource Manager Start event. The handle must be obtained via the
  2201. SCardAccessStartedEvent service.
  2202. Arguments:
  2203. None
  2204. Return Value:
  2205. None.
  2206. Throws:
  2207. None
  2208. Remarks:
  2209. Programs other than the resource manager should only wait on these flags.
  2210. Author:
  2211. Doug Barlow (dbarlow) 7/1/1998
  2212. --*/
  2213. #undef __SUBROUTINE__
  2214. #define __SUBROUTINE__ DBGT("SCardReleaseStartedEvent")
  2215. WINSCARDAPI void WINAPI
  2216. SCardReleaseStartedEvent(
  2217. void)
  2218. {
  2219. if (TermSrvEnabled())
  2220. {
  2221. UnRegisterForSessionChangeNotifications();
  2222. }
  2223. }
  2224. /*++
  2225. SCardReleaseNewReaderEvent:
  2226. This function releases a previously accessed handle to the Calais
  2227. Resource Manager New Reader event. The handle must be obtained via the
  2228. SCardAccessNewReaderEvent service.
  2229. Arguments:
  2230. None
  2231. Return Value:
  2232. None.
  2233. Throws:
  2234. None
  2235. Remarks:
  2236. Programs other than the resource manager should only wait on these flags.
  2237. Author:
  2238. Doug Barlow (dbarlow) 7/1/1998
  2239. --*/
  2240. #undef __SUBROUTINE__
  2241. #define __SUBROUTINE__ DBGT("SCardReleaseNewReaderEvent")
  2242. WINSCARDAPI void WINAPI
  2243. SCardReleaseNewReaderEvent(
  2244. void)
  2245. {
  2246. ReleaseNewReaderEvent();
  2247. }
  2248. /*++
  2249. SCardReleaseAllEvents:
  2250. This is a catch-all routine that releases all known special event handles.
  2251. Arguments:
  2252. None
  2253. Return Value:
  2254. None
  2255. Throws:
  2256. None
  2257. Remarks:
  2258. Author:
  2259. Doug Barlow (dbarlow) 7/6/1998
  2260. --*/
  2261. #undef __SUBROUTINE__
  2262. #define __SUBROUTINE__ DBGT("SCardReleaseAllEvents")
  2263. WINSCARDAPI void WINAPI
  2264. SCardReleaseAllEvents(
  2265. void)
  2266. {
  2267. ReleaseAllEvents();
  2268. }
  2269. //
  2270. ///////////////////////////////////////////////////////////////////////////////
  2271. //
  2272. // Utility Routines
  2273. //
  2274. /*++
  2275. PlaceResult:
  2276. This set of routines places the result of an operation into the user's
  2277. output buffer, supporting SCARD_AUTO_ALLOCATE, invalid buffer sizes, etc.
  2278. Arguments:
  2279. pCtx supplies the context under which this operation is being performed.
  2280. bfResult supplies the result to be returned to the user.
  2281. pbOutput receives the result for the user, as a byte stream.
  2282. szOutput receives the result as an ANSI or UNICODE string.
  2283. pcbLength supplies the length of the user's output buffer in bytes, and
  2284. receives how much of it was used.
  2285. pcchLength supplies the length of the user's output buffer in characters,
  2286. and receives how much of it was used.
  2287. Return Value:
  2288. None
  2289. Throws:
  2290. Error conditions are thrown as DWORD status codes.
  2291. Author:
  2292. Doug Barlow (dbarlow) 12/7/1996
  2293. --*/
  2294. #undef __SUBROUTINE__
  2295. #define __SUBROUTINE__ DBGT("PlaceResult")
  2296. void
  2297. PlaceResult(
  2298. CSCardUserContext *pCtx,
  2299. CBuffer &bfResult,
  2300. LPBYTE pbOutput,
  2301. LPDWORD pcbLength)
  2302. {
  2303. LPBYTE pbForUser = NULL;
  2304. LPBYTE pbOutBuff = pbOutput;
  2305. try
  2306. {
  2307. if (NULL == pbOutput)
  2308. *pcbLength = 0;
  2309. switch (*pcbLength)
  2310. {
  2311. case 0: // They just want the length.
  2312. *pcbLength = bfResult.Length();
  2313. break;
  2314. case SCARD_AUTOALLOCATE:
  2315. if (0 < bfResult.Length())
  2316. {
  2317. if (NULL == pCtx)
  2318. {
  2319. pbForUser = (LPBYTE)HeapAlloc(
  2320. GetProcessHeap(),
  2321. HEAP_ZERO_MEMORY,
  2322. bfResult.Length());
  2323. }
  2324. else
  2325. pbForUser = (LPBYTE)pCtx->AllocateMemory(bfResult.Length());
  2326. if (NULL == pbForUser)
  2327. {
  2328. CalaisWarning(
  2329. __SUBROUTINE__,
  2330. DBGT("Client can't get return memory"));
  2331. throw (DWORD)SCARD_E_NO_MEMORY;
  2332. }
  2333. *(LPBYTE *)pbOutput = pbForUser;
  2334. pbOutBuff = pbForUser;
  2335. // Fall through intentionally
  2336. }
  2337. else
  2338. {
  2339. *pcbLength = 0;
  2340. *(LPBYTE *)pbOutput = (LPBYTE)g_wszBlank;
  2341. break; // Do terminate the case now.
  2342. }
  2343. default:
  2344. if (*pcbLength < bfResult.Length())
  2345. {
  2346. *pcbLength = bfResult.Length();
  2347. throw (DWORD)SCARD_E_INSUFFICIENT_BUFFER;
  2348. }
  2349. CopyMemory(pbOutBuff, bfResult.Access(), bfResult.Length());
  2350. *pcbLength = bfResult.Length();
  2351. break;
  2352. }
  2353. }
  2354. catch (...)
  2355. {
  2356. if (NULL != pbForUser)
  2357. {
  2358. if (NULL == pCtx)
  2359. HeapFree(GetProcessHeap(), 0, pbForUser);
  2360. else
  2361. pCtx->FreeMemory(pbForUser);
  2362. }
  2363. throw;
  2364. }
  2365. }
  2366. #include <setupapi.h>
  2367. //
  2368. // On a system that installs a smart card reader for the very first time
  2369. // the smart card subsystem must be started manually, but only this first time.
  2370. // After that, it is started automatically whenever the system boots
  2371. //
  2372. DWORD
  2373. APIENTRY
  2374. ClassInstall32(
  2375. IN DI_FUNCTION dif,
  2376. IN HDEVINFO hdi,
  2377. IN PSP_DEVINFO_DATA pdevData) OPTIONAL
  2378. {
  2379. if (dif == DIF_INSTALLDEVICE)
  2380. {
  2381. StartCalaisService();
  2382. }
  2383. return ERROR_DI_DO_DEFAULT;
  2384. }