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.

1226 lines
25 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 2000
  3. Module Name:
  4. scuisupp
  5. Abstract:
  6. Support for smart card certificate selection UI
  7. Author:
  8. Klaus Schutz
  9. --*/
  10. #include "stdafx.h"
  11. #include <wincrypt.h>
  12. #include <winscard.h>
  13. #include <winwlx.h>
  14. #include <string.h>
  15. #include "calaislb.h"
  16. #include "scuisupp.h"
  17. #include "StatMon.h" // smart card reader status monitor
  18. #include "scevents.h"
  19. #include <mmsystem.h>
  20. typedef struct _READER_DATA
  21. {
  22. CERT_ENUM CertEnum;
  23. LPTSTR pszReaderName;
  24. LPTSTR pszCardName;
  25. LPTSTR pszCSPName;
  26. } READER_DATA, *PREADER_DATA;
  27. typedef struct _THREAD_DATA
  28. {
  29. // handle to heap of this thread
  30. HANDLE hHeap;
  31. // the smart card context we use
  32. SCARDCONTEXT hSCardContext;
  33. // the window we send messages to
  34. HWND hWindow;
  35. // event to signal that the monitor thread can terminate
  36. HANDLE hClose;
  37. // thread handle for the monitor thread
  38. HANDLE hThread;
  39. // number of readers detected
  40. DWORD dwNumReaders;
  41. // messages to be sent to parent
  42. UINT msgReaderArrival;
  43. UINT msgReaderRemoval;
  44. UINT msgSmartCardInsertion;
  45. UINT msgSmartCardRemoval;
  46. UINT msgSmartCardStatus;
  47. UINT msgSmartCardCertAvail;
  48. // reader state array
  49. PSCARD_READERSTATE rgReaders;
  50. // number of removed readers
  51. DWORD dwRemovedReaders;
  52. // pointer array of removed reader data
  53. PREADER_DATA *ppRemovedReaderData;
  54. } THREAD_DATA, *PTHREAD_DATA;
  55. #ifndef TEST
  56. #define SC_DEBUG(a)
  57. #else
  58. #define SC_DEBUG(a) _DebugPrint a
  59. #undef PostMessage
  60. #define PostMessage(a,b,c,d) _PostMessage(a, b, c, d)
  61. #undef RegisterWindowMessage
  62. #define RegisterWindowMessage(a) _RegisterWindowMessage(a)
  63. void
  64. __cdecl
  65. _DebugPrint(
  66. LPCTSTR szFormat,
  67. ...
  68. )
  69. {
  70. TCHAR szBuffer[1024];
  71. va_list ap;
  72. va_start(ap, szFormat);
  73. _vstprintf(szBuffer, szFormat, ap);
  74. OutputDebugString(szBuffer);
  75. _tprintf(szBuffer);
  76. }
  77. #define MAX_MESSAGES 10
  78. static struct {
  79. UINT dwMessage;
  80. LPCTSTR lpMessage;
  81. } Messages[MAX_MESSAGES];
  82. UINT
  83. _RegisterWindowMessage(
  84. LPCTSTR lpString
  85. )
  86. {
  87. for (DWORD dwIndex = 0; dwIndex < MAX_MESSAGES; dwIndex += 1) {
  88. if (Messages[dwIndex].lpMessage == NULL) {
  89. break;
  90. }
  91. if (_tcscmp(lpString, Messages[dwIndex].lpMessage) == 0) {
  92. return Messages[dwIndex].dwMessage;
  93. }
  94. }
  95. Messages[dwIndex].lpMessage = lpString;
  96. Messages[dwIndex].dwMessage = dwIndex;
  97. return dwIndex;
  98. }
  99. LPCTSTR
  100. _GetWindowMessageString(
  101. UINT dwMessage
  102. )
  103. {
  104. for (DWORD dwIndex = 0; dwIndex < MAX_MESSAGES; dwIndex += 1) {
  105. if (Messages[dwIndex].lpMessage == NULL) {
  106. return TEXT("(NOT DEFINED)");
  107. }
  108. if (dwMessage == Messages[dwIndex].dwMessage) {
  109. return Messages[dwIndex].lpMessage;
  110. }
  111. }
  112. return TEXT("(INTERNAL ERROR)");
  113. }
  114. LRESULT
  115. _PostMessage(
  116. HWND hWindow,
  117. UINT Msg,
  118. WPARAM wParam,
  119. LPARAM lParam
  120. )
  121. {
  122. SC_DEBUG((TEXT("Received message %s\n"), _GetWindowMessageString(Msg)));
  123. return 0;
  124. }
  125. #endif
  126. static
  127. LPCTSTR
  128. FirstString(
  129. IN LPCTSTR szMultiString
  130. )
  131. /*++
  132. FirstString:
  133. This routine returns a pointer to the first string in a multistring, or NULL
  134. if there aren't any.
  135. Arguments:
  136. szMultiString - This supplies the address of the current position within a
  137. Multi-string structure.
  138. Return Value:
  139. The address of the first null-terminated string in the structure, or NULL if
  140. there are no strings.
  141. Author:
  142. Doug Barlow (dbarlow) 11/25/1996
  143. --*/
  144. {
  145. LPCTSTR szFirst = NULL;
  146. try
  147. {
  148. if (0 != *szMultiString)
  149. szFirst = szMultiString;
  150. }
  151. catch (...) {}
  152. return szFirst;
  153. }
  154. static
  155. LPCTSTR
  156. NextString(
  157. IN LPCTSTR szMultiString)
  158. /*++
  159. NextString:
  160. In some cases, the Smartcard API returns multiple strings, separated by Null
  161. characters, and terminated by two null characters in a row. This routine
  162. simplifies access to such structures. Given the current string in a
  163. multi-string structure, it returns the next string, or NULL if no other
  164. strings follow the current string.
  165. Arguments:
  166. szMultiString - This supplies the address of the current position within a
  167. Multi-string structure.
  168. Return Value:
  169. The address of the next Null-terminated string in the structure, or NULL if
  170. no more strings follow.
  171. Author:
  172. Doug Barlow (dbarlow) 8/12/1996
  173. --*/
  174. {
  175. LPCTSTR szNext;
  176. try
  177. {
  178. DWORD cchLen = lstrlen(szMultiString);
  179. if (0 == cchLen)
  180. szNext = NULL;
  181. else
  182. {
  183. szNext = szMultiString + cchLen + 1;
  184. if (0 == *szNext)
  185. szNext = NULL;
  186. }
  187. }
  188. catch (...)
  189. {
  190. szNext = NULL;
  191. }
  192. return szNext;
  193. }
  194. static
  195. void
  196. FreeReaderData(
  197. PTHREAD_DATA pThreadData,
  198. PREADER_DATA pReaderData
  199. )
  200. {
  201. if (pThreadData->hSCardContext && pReaderData->pszCardName) {
  202. SCardFreeMemory(pThreadData->hSCardContext, pReaderData->pszCardName);
  203. pReaderData->pszCardName = NULL;
  204. pReaderData->CertEnum.pszCardName = NULL;
  205. }
  206. if (pThreadData->hSCardContext && pReaderData->pszCSPName) {
  207. SCardFreeMemory(pThreadData->hSCardContext, pReaderData->pszCSPName);
  208. pReaderData->pszCSPName = NULL;
  209. }
  210. if (pReaderData->CertEnum.pCertContext) {
  211. CertFreeCertificateContext(pReaderData->CertEnum.pCertContext);
  212. pReaderData->CertEnum.pCertContext = NULL;
  213. }
  214. pReaderData->CertEnum.dwStatus = 0;
  215. }
  216. static
  217. void
  218. UpdateCertificates(
  219. PTHREAD_DATA pThreadData,
  220. PSCARD_READERSTATE pReaderState
  221. )
  222. {
  223. PREADER_DATA pReaderData = (PREADER_DATA) pReaderState->pvUserData;
  224. FreeReaderData(pThreadData, pReaderData);
  225. SC_DEBUG((TEXT("Enumerating certificates on %s...\n"), pReaderState->szReader));
  226. LPTSTR pszContainerName = NULL;
  227. LPTSTR pszDefaultContainerName = NULL;
  228. PBYTE pbCert = NULL;
  229. HCRYPTKEY hKey = NULL;
  230. HCRYPTPROV hCryptProv = NULL;
  231. __try {
  232. pReaderData->CertEnum.dwStatus = SCARD_F_UNKNOWN_ERROR;
  233. // Get the name of the card
  234. DWORD dwAutoAllocate = SCARD_AUTOALLOCATE;
  235. LONG lReturn = SCardListCards(
  236. pThreadData->hSCardContext,
  237. pReaderState->rgbAtr,
  238. NULL,
  239. 0,
  240. (LPTSTR)&pReaderData->pszCardName,
  241. &dwAutoAllocate
  242. );
  243. if (lReturn != SCARD_S_SUCCESS) {
  244. SC_DEBUG((TEXT("Failed to get card name for card in %s\n"), pReaderState->szReader));
  245. pReaderData->CertEnum.dwStatus = lReturn;
  246. __leave;
  247. }
  248. pReaderData->CertEnum.pszCardName = pReaderData->pszCardName;
  249. dwAutoAllocate = SCARD_AUTOALLOCATE;
  250. lReturn = SCardGetCardTypeProviderName(
  251. pThreadData->hSCardContext,
  252. pReaderData->pszCardName,
  253. SCARD_PROVIDER_CSP,
  254. (LPTSTR)&pReaderData->pszCSPName,
  255. &dwAutoAllocate
  256. );
  257. if (lReturn != SCARD_S_SUCCESS) {
  258. SC_DEBUG((TEXT("Failed to get CSP name from %s\n"), pReaderState->szReader));
  259. pReaderData->CertEnum.dwStatus = SCARD_E_UNKNOWN_CARD;
  260. __leave;
  261. }
  262. pszContainerName = (LPTSTR) HeapAlloc(
  263. pThreadData->hHeap,
  264. HEAP_ZERO_MEMORY,
  265. (_tcslen(pReaderState->szReader) + 10) * sizeof(TCHAR)
  266. );
  267. if (pszContainerName == NULL) {
  268. pReaderData->CertEnum.dwStatus = SCARD_E_NO_MEMORY;
  269. __leave;
  270. }
  271. _stprintf(
  272. pszContainerName,
  273. TEXT("\\\\.\\%s\\"),
  274. pReaderState->szReader);
  275. BOOL fSuccess = CryptAcquireContext(
  276. &hCryptProv,
  277. pszContainerName,
  278. pReaderData->pszCSPName,
  279. PROV_RSA_FULL,
  280. CRYPT_SILENT
  281. );
  282. if (fSuccess == FALSE) {
  283. SC_DEBUG((
  284. TEXT("Failed to acquire context on %s (%lx)\n"),
  285. pReaderState->szReader, GetLastError()
  286. ));
  287. pReaderData->CertEnum.dwStatus = GetLastError();
  288. __leave;
  289. }
  290. // Get the default container name, so we can use it
  291. DWORD cbDefaultContainerName;
  292. fSuccess = CryptGetProvParam(
  293. hCryptProv,
  294. PP_CONTAINER,
  295. NULL,
  296. &cbDefaultContainerName,
  297. 0
  298. );
  299. if (!fSuccess) {
  300. SC_DEBUG((TEXT("Failed to get default container name from %s\n"), pReaderState->szReader));
  301. pReaderData->CertEnum.dwStatus = GetLastError();
  302. __leave;
  303. }
  304. pszDefaultContainerName =
  305. (LPTSTR) HeapAlloc(pThreadData->hHeap, HEAP_ZERO_MEMORY, cbDefaultContainerName * sizeof(TCHAR));
  306. if (NULL == pszContainerName) {
  307. pReaderData->CertEnum.dwStatus = SCARD_E_NO_MEMORY;
  308. __leave;
  309. }
  310. fSuccess = CryptGetProvParam(
  311. hCryptProv,
  312. PP_CONTAINER,
  313. (PBYTE)pszDefaultContainerName,
  314. &cbDefaultContainerName,
  315. 0
  316. );
  317. if (!fSuccess) {
  318. pReaderData->CertEnum.dwStatus = GetLastError();
  319. __leave;
  320. }
  321. fSuccess = CryptGetUserKey(
  322. hCryptProv,
  323. AT_KEYEXCHANGE,
  324. &hKey
  325. );
  326. if (fSuccess == FALSE) {
  327. SC_DEBUG((TEXT("Failed to get key from %s\n"), pReaderState->szReader));
  328. pReaderData->CertEnum.dwStatus = GetLastError();
  329. __leave;
  330. }
  331. // get length of certificate
  332. DWORD cbCertLen = 0;
  333. fSuccess = CryptGetKeyParam(
  334. hKey,
  335. KP_CERTIFICATE,
  336. NULL,
  337. &cbCertLen,
  338. 0
  339. );
  340. DWORD dwError = GetLastError();
  341. if (fSuccess == FALSE && dwError != ERROR_MORE_DATA) {
  342. SC_DEBUG((TEXT("Failed to get certificate from %s\n"), pReaderState->szReader));
  343. pReaderData->CertEnum.dwStatus = GetLastError();
  344. __leave;
  345. }
  346. pbCert = (LPBYTE) HeapAlloc(pThreadData->hHeap, HEAP_ZERO_MEMORY, cbCertLen);
  347. if (pbCert == NULL)
  348. {
  349. pReaderData->CertEnum.dwStatus = SCARD_E_NO_MEMORY;
  350. __leave;
  351. }
  352. // read the certificate off the card
  353. fSuccess = CryptGetKeyParam(
  354. hKey,
  355. KP_CERTIFICATE,
  356. pbCert,
  357. &cbCertLen,
  358. 0
  359. );
  360. if (fSuccess == FALSE) {
  361. SC_DEBUG((TEXT("Failed to get certificate from %s\n"), pReaderState->szReader));
  362. pReaderData->CertEnum.dwStatus = GetLastError();
  363. __leave;
  364. }
  365. PCERT_CONTEXT pCertContext = (PCERT_CONTEXT) CertCreateCertificateContext(
  366. X509_ASN_ENCODING,
  367. pbCert,
  368. cbCertLen
  369. );
  370. if (pCertContext == NULL) {
  371. __leave;
  372. }
  373. pReaderData->CertEnum.dwStatus = SCARD_S_SUCCESS;
  374. pReaderData->CertEnum.pCertContext = pCertContext;
  375. SC_DEBUG((TEXT("Found new certificate on %s\n"), pReaderState->szReader));
  376. PostMessage(
  377. pThreadData->hWindow,
  378. pThreadData->msgSmartCardCertAvail,
  379. (WPARAM) &pReaderData->CertEnum,
  380. 0
  381. );
  382. }
  383. __finally {
  384. //
  385. // free all allocated memory
  386. //
  387. if (NULL != pszContainerName)
  388. {
  389. HeapFree(pThreadData->hHeap, 0, pszContainerName);
  390. }
  391. if (NULL != pszDefaultContainerName)
  392. {
  393. HeapFree(pThreadData->hHeap, 0, pszDefaultContainerName);
  394. }
  395. if (NULL != pbCert)
  396. {
  397. HeapFree(pThreadData->hHeap, 0, pbCert);
  398. }
  399. if (NULL != hKey)
  400. {
  401. CryptDestroyKey(hKey);
  402. }
  403. if (NULL != hCryptProv)
  404. {
  405. CryptReleaseContext(hCryptProv, 0);
  406. }
  407. }
  408. }
  409. static
  410. void
  411. StopMonitorReaders(
  412. PTHREAD_DATA pThreadData
  413. )
  414. {
  415. _ASSERT(pThreadData != NULL);
  416. SetEvent(pThreadData->hClose);
  417. if (pThreadData->hSCardContext) {
  418. SCardCancel(pThreadData->hSCardContext);
  419. }
  420. }
  421. static
  422. void
  423. RemoveCard(
  424. PTHREAD_DATA pThreadData,
  425. PREADER_DATA pReaderData
  426. )
  427. {
  428. SC_DEBUG((TEXT("Smart Card removed from %s\n"), pReaderData->CertEnum.pszReaderName));
  429. PostMessage(
  430. pThreadData->hWindow,
  431. pThreadData->msgSmartCardRemoval,
  432. (WPARAM) &pReaderData->CertEnum,
  433. 0
  434. );
  435. }
  436. static
  437. BOOL
  438. AddReader(
  439. PTHREAD_DATA pThreadData,
  440. LPCTSTR pszNewReader
  441. )
  442. {
  443. PSCARD_READERSTATE pScardReaderState =
  444. (PSCARD_READERSTATE) HeapReAlloc(
  445. pThreadData->hHeap,
  446. HEAP_ZERO_MEMORY,
  447. pThreadData->rgReaders,
  448. (pThreadData->dwNumReaders + 1) * (sizeof(SCARD_READERSTATE))
  449. );
  450. if (pScardReaderState == NULL) {
  451. return FALSE;
  452. }
  453. pThreadData->rgReaders = pScardReaderState;
  454. PREADER_DATA pReaderData =
  455. (PREADER_DATA) HeapAlloc(
  456. pThreadData->hHeap,
  457. HEAP_ZERO_MEMORY,
  458. sizeof(READER_DATA)
  459. );
  460. if (pReaderData == NULL) {
  461. return FALSE;
  462. }
  463. pThreadData->rgReaders[pThreadData->dwNumReaders].pvUserData =
  464. pReaderData;
  465. LPTSTR pszReaderName =
  466. (LPTSTR) HeapAlloc(
  467. pThreadData->hHeap,
  468. HEAP_ZERO_MEMORY,
  469. (_tcslen(pszNewReader) + 1) * sizeof(TCHAR)
  470. );
  471. if (pszReaderName == NULL) {
  472. return FALSE;
  473. }
  474. _tcscpy(pszReaderName, pszNewReader);
  475. pReaderData->pszReaderName = pszReaderName;
  476. pThreadData->rgReaders[pThreadData->dwNumReaders].szReader =
  477. pszReaderName;
  478. pThreadData->rgReaders[pThreadData->dwNumReaders].dwCurrentState =
  479. SCARD_STATE_EMPTY;
  480. pReaderData->CertEnum.pszReaderName = (LPTSTR) pszReaderName;
  481. pThreadData->dwNumReaders++;
  482. PostMessage(
  483. pThreadData->hWindow,
  484. pThreadData->msgReaderArrival,
  485. (WPARAM) &pReaderData->CertEnum,
  486. 0
  487. );
  488. return TRUE;
  489. }
  490. static
  491. BOOL
  492. RemoveReader(
  493. PTHREAD_DATA pThreadData,
  494. PSCARD_READERSTATE pReaderState
  495. )
  496. {
  497. PREADER_DATA pReaderData =
  498. (PREADER_DATA) pReaderState->pvUserData;
  499. if (pReaderState->dwCurrentState & SCARD_STATE_PRESENT) {
  500. RemoveCard(
  501. pThreadData,
  502. pReaderData
  503. );
  504. }
  505. SC_DEBUG((TEXT("Reader %s removed\n"), pReaderData->CertEnum.pszReaderName));
  506. PostMessage(
  507. pThreadData->hWindow,
  508. pThreadData->msgReaderRemoval,
  509. (WPARAM) &pReaderData->CertEnum,
  510. 0
  511. );
  512. // build an array of reader data that needs to be deleted on exit
  513. PREADER_DATA *ppRemovedReaderData = NULL;
  514. if (pThreadData->dwRemovedReaders == 0) {
  515. ppRemovedReaderData = (PREADER_DATA *) HeapAlloc(
  516. pThreadData->hHeap,
  517. HEAP_ZERO_MEMORY,
  518. sizeof(PREADER_DATA)
  519. );
  520. } else {
  521. ppRemovedReaderData = (PREADER_DATA *) HeapReAlloc(
  522. pThreadData->hHeap,
  523. HEAP_ZERO_MEMORY,
  524. pThreadData->ppRemovedReaderData,
  525. (pThreadData->dwRemovedReaders + 1) * sizeof(PREADER_DATA)
  526. );
  527. }
  528. if (ppRemovedReaderData == NULL) {
  529. return FALSE;
  530. }
  531. // add the reader data to the list of stuff that needs to be freed on exit
  532. pThreadData->ppRemovedReaderData = ppRemovedReaderData;
  533. pThreadData->ppRemovedReaderData[pThreadData->dwRemovedReaders] = pReaderData;
  534. for (DWORD dwIndex = 1; dwIndex < pThreadData->dwNumReaders; dwIndex += 1) {
  535. if (pReaderState == &pThreadData->rgReaders[dwIndex]) {
  536. // check if the reader we remove is not the last or the only one.
  537. if (pThreadData->dwNumReaders > 1 && dwIndex != pThreadData->dwNumReaders - 1) {
  538. // put the reader from the end of the list into this available slot
  539. pThreadData->rgReaders[dwIndex] =
  540. pThreadData->rgReaders[pThreadData->dwNumReaders - 1];
  541. }
  542. // shrink the reader state array
  543. PSCARD_READERSTATE pReaders = (PSCARD_READERSTATE) HeapReAlloc(
  544. pThreadData->hHeap,
  545. 0,
  546. pThreadData->rgReaders,
  547. (pThreadData->dwNumReaders - 1) * sizeof(SCARD_READERSTATE)
  548. );
  549. if (pReaders == NULL) {
  550. return FALSE;
  551. }
  552. pThreadData->rgReaders = pReaders;
  553. break;
  554. }
  555. }
  556. pThreadData->dwNumReaders -= 1;
  557. pThreadData->dwRemovedReaders += 1;
  558. return TRUE;
  559. }
  560. static
  561. BOOL
  562. RemoveAllReaders(
  563. PTHREAD_DATA pThreadData
  564. )
  565. {
  566. if (pThreadData->rgReaders == NULL) {
  567. return TRUE;
  568. }
  569. // This loop will destroy all the readers starting with the first one
  570. // dwIndex doesn't have to be incremented. pThreadData->dwNumReaders is
  571. // decremented in RemoveReader
  572. for (DWORD dwIndex = 1; dwIndex < pThreadData->dwNumReaders; ) {
  573. if (RemoveReader(
  574. pThreadData,
  575. &pThreadData->rgReaders[dwIndex]
  576. ) == FALSE) {
  577. return FALSE;
  578. }
  579. }
  580. // Remove the PnP pseudo reader
  581. HeapFree(
  582. pThreadData->hHeap,
  583. 0,
  584. pThreadData->rgReaders
  585. );
  586. pThreadData->rgReaders = NULL;
  587. return TRUE;
  588. }
  589. static
  590. DWORD
  591. StartMonitorReaders(
  592. LPVOID pData
  593. )
  594. {
  595. PTHREAD_DATA pThreadData = (PTHREAD_DATA) pData;
  596. LPCTSTR szReaderNameList = NULL;
  597. //
  598. // We use this outer loop to restart in case the
  599. // resource manager was stopped
  600. //
  601. __try {
  602. pThreadData->rgReaders =
  603. (PSCARD_READERSTATE) HeapAlloc(
  604. pThreadData->hHeap,
  605. HEAP_ZERO_MEMORY,
  606. sizeof(SCARD_READERSTATE)
  607. );
  608. if (pThreadData->rgReaders == NULL) {
  609. __leave;
  610. }
  611. pThreadData->rgReaders[0].szReader = SCPNP_NOTIFICATION;
  612. pThreadData->rgReaders[0].dwCurrentState = 0;
  613. pThreadData->dwNumReaders = 1;
  614. while (WaitForSingleObject(pThreadData->hClose, 0) == WAIT_TIMEOUT) {
  615. // Acquire context with resource manager
  616. LONG lReturn = SCardEstablishContext(
  617. SCARD_SCOPE_USER,
  618. NULL,
  619. NULL,
  620. &pThreadData->hSCardContext
  621. );
  622. if (SCARD_S_SUCCESS != lReturn) {
  623. // The prev. call should never fail
  624. // It's better to terminate this thread.
  625. __leave;
  626. }
  627. szReaderNameList = NULL;
  628. DWORD dwAutoAllocate = SCARD_AUTOALLOCATE;
  629. // now list the available readers
  630. lReturn = SCardListReaders(
  631. pThreadData->hSCardContext,
  632. SCARD_DEFAULT_READERS,
  633. (LPTSTR)&szReaderNameList,
  634. &dwAutoAllocate
  635. );
  636. if (SCARD_S_SUCCESS == lReturn)
  637. {
  638. // bugbug - this pointer should not be modified
  639. for (LPCTSTR szReader = FirstString( szReaderNameList );
  640. szReader != NULL;
  641. szReader = NextString(szReader)) {
  642. BOOL fFound = FALSE;
  643. // now check if this reader is already in the reader array
  644. for (DWORD dwIndex = 1; dwIndex < pThreadData->dwNumReaders; dwIndex++) {
  645. if (lstrcmp(
  646. szReader,
  647. pThreadData->rgReaders[dwIndex].szReader
  648. ) == 0) {
  649. fFound = TRUE;
  650. break;
  651. }
  652. }
  653. if (fFound == FALSE) {
  654. if (AddReader(pThreadData, szReader) == FALSE) {
  655. __leave;
  656. }
  657. }
  658. }
  659. }
  660. BOOL fNewReader = FALSE;
  661. // analyze newly inserted cards
  662. while (WaitForSingleObject(pThreadData->hClose, 0) == WAIT_TIMEOUT &&
  663. fNewReader == FALSE) {
  664. lReturn = SCardGetStatusChange(
  665. pThreadData->hSCardContext,
  666. INFINITE,
  667. pThreadData->rgReaders,
  668. pThreadData->dwNumReaders
  669. );
  670. if (SCARD_E_SYSTEM_CANCELLED == lReturn) {
  671. // the smart card system has been stopped
  672. // send notification that all readers are gone
  673. if (RemoveAllReaders(pThreadData) == FALSE) {
  674. __leave;
  675. }
  676. // Wait until it restarted
  677. HANDLE hCalaisStarted = CalaisAccessStartedEvent();
  678. if (hCalaisStarted == NULL) {
  679. // no way to recover. stop cert prop
  680. StopMonitorReaders(pThreadData);
  681. break;
  682. }
  683. HANDLE lHandles[2] = { hCalaisStarted, pThreadData->hClose };
  684. lReturn = WaitForMultipleObjectsEx(
  685. 2,
  686. lHandles,
  687. FALSE,
  688. INFINITE,
  689. FALSE
  690. );
  691. if (lReturn != WAIT_OBJECT_0) {
  692. // We stop if an error occured
  693. StopMonitorReaders(pThreadData);
  694. break;
  695. }
  696. // Otherwise the resource manager has been restarted
  697. break;
  698. }
  699. if (SCARD_S_SUCCESS != lReturn)
  700. {
  701. StopMonitorReaders(pThreadData);
  702. break;
  703. }
  704. // Enumerate the readers and for every card change send a message
  705. for (DWORD dwIndex = 1; dwIndex < pThreadData->dwNumReaders; dwIndex++)
  706. {
  707. // Check if the reader has been removed
  708. if ((pThreadData->rgReaders[dwIndex].dwEventState & SCARD_STATE_UNAVAILABLE)) {
  709. if (RemoveReader(
  710. pThreadData,
  711. &pThreadData->rgReaders[dwIndex]
  712. ) == FALSE) {
  713. __leave;
  714. }
  715. // Continue the loop with the same index
  716. dwIndex--;
  717. continue;
  718. }
  719. // check if this is a card insertion
  720. if ((pThreadData->rgReaders[dwIndex].dwCurrentState & SCARD_STATE_EMPTY) &&
  721. (pThreadData->rgReaders[dwIndex].dwEventState & SCARD_STATE_PRESENT)) {
  722. PREADER_DATA pReaderData =
  723. (PREADER_DATA) pThreadData->rgReaders[dwIndex].pvUserData;
  724. SC_DEBUG((TEXT("Smart Card inserted into %s\n"), pThreadData->rgReaders[dwIndex].szReader));
  725. PostMessage(
  726. pThreadData->hWindow,
  727. pThreadData->msgSmartCardInsertion,
  728. (WPARAM) &pReaderData->CertEnum,
  729. 0
  730. );
  731. // read in all certificates
  732. UpdateCertificates(
  733. pThreadData,
  734. &pThreadData->rgReaders[dwIndex]
  735. );
  736. PostMessage(
  737. pThreadData->hWindow,
  738. pThreadData->msgSmartCardStatus,
  739. (WPARAM) &pReaderData->CertEnum,
  740. 0
  741. );
  742. }
  743. // check if this is a card removal
  744. if ((pThreadData->rgReaders[dwIndex].dwCurrentState & SCARD_STATE_PRESENT) &&
  745. (pThreadData->rgReaders[dwIndex].dwEventState & SCARD_STATE_EMPTY)) {
  746. PREADER_DATA pReaderData = (PREADER_DATA) pThreadData->rgReaders[dwIndex].pvUserData;
  747. RemoveCard(pThreadData, pReaderData);
  748. // we can't update the certificates because it would delete
  749. // some memory data that the caller could reference.
  750. }
  751. // Update the "current state" of this reader
  752. pThreadData->rgReaders[dwIndex].dwCurrentState =
  753. pThreadData->rgReaders[dwIndex].dwEventState;
  754. }
  755. // check if a new reader showed up
  756. if ((pThreadData->dwNumReaders == 1 ||
  757. pThreadData->rgReaders[0].dwCurrentState != 0) &&
  758. pThreadData->rgReaders[0].dwEventState & SCARD_STATE_CHANGED) {
  759. fNewReader = TRUE;
  760. }
  761. pThreadData->rgReaders[0].dwCurrentState =
  762. pThreadData->rgReaders[0].dwEventState;
  763. }
  764. // Clean up
  765. if (NULL != szReaderNameList)
  766. {
  767. SCardFreeMemory(pThreadData->hSCardContext, (PVOID) szReaderNameList);
  768. szReaderNameList = NULL;
  769. }
  770. if (NULL != pThreadData->hSCardContext)
  771. {
  772. SCardReleaseContext(pThreadData->hSCardContext);
  773. pThreadData->hSCardContext = NULL;
  774. }
  775. }
  776. }
  777. __finally {
  778. if (NULL != szReaderNameList)
  779. {
  780. SCardFreeMemory(pThreadData->hSCardContext, (PVOID) szReaderNameList);
  781. }
  782. if (NULL != pThreadData->hSCardContext)
  783. {
  784. SCardReleaseContext(pThreadData->hSCardContext);
  785. pThreadData->hSCardContext = NULL;
  786. }
  787. RemoveAllReaders(pThreadData);
  788. SC_DEBUG((TEXT("Terminating monitor thread\n")));
  789. }
  790. return TRUE;
  791. }
  792. HSCARDUI
  793. WINAPI
  794. SCardUIInit(
  795. HWND hWindow
  796. )
  797. {
  798. PTHREAD_DATA pThreadData =
  799. (PTHREAD_DATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(THREAD_DATA));
  800. BOOL fSuccess = FALSE;
  801. __try {
  802. if (pThreadData == NULL) {
  803. __leave;
  804. }
  805. pThreadData->hHeap = GetProcessHeap();
  806. pThreadData->hWindow = hWindow;
  807. pThreadData->msgReaderArrival =
  808. RegisterWindowMessage(TEXT(SCARDUI_READER_ARRIVAL));
  809. pThreadData->msgReaderRemoval =
  810. RegisterWindowMessage(TEXT(SCARDUI_READER_REMOVAL));
  811. pThreadData->msgSmartCardInsertion =
  812. RegisterWindowMessage(TEXT(SCARDUI_SMART_CARD_INSERTION));
  813. pThreadData->msgSmartCardRemoval =
  814. RegisterWindowMessage(TEXT(SCARDUI_SMART_CARD_REMOVAL));
  815. pThreadData->msgSmartCardStatus =
  816. RegisterWindowMessage(TEXT(SCARDUI_SMART_CARD_STATUS));
  817. pThreadData->msgSmartCardCertAvail =
  818. RegisterWindowMessage(TEXT(SCARDUI_SMART_CARD_CERT_AVAIL));
  819. pThreadData->hClose = CreateEvent(
  820. NULL,
  821. TRUE,
  822. FALSE,
  823. NULL
  824. );
  825. if (pThreadData->hClose == NULL) {
  826. __leave;
  827. }
  828. pThreadData->hThread = CreateThread(
  829. NULL,
  830. 0,
  831. StartMonitorReaders,
  832. (LPVOID) pThreadData,
  833. CREATE_SUSPENDED,
  834. NULL
  835. );
  836. if (pThreadData->hThread == NULL) {
  837. __leave;
  838. }
  839. ResumeThread(pThreadData->hThread);
  840. fSuccess = TRUE;
  841. }
  842. __finally {
  843. if (fSuccess == FALSE) {
  844. if (pThreadData && pThreadData->hClose) {
  845. CloseHandle(pThreadData->hClose);
  846. }
  847. if (pThreadData) {
  848. HeapFree(pThreadData->hHeap, 0, pThreadData);
  849. pThreadData = NULL;
  850. }
  851. }
  852. }
  853. return (HSCARDUI) pThreadData;
  854. }
  855. DWORD
  856. WINAPI
  857. SCardUIExit(
  858. HSCARDUI hSCardUI
  859. )
  860. /*++
  861. Routine Description:
  862. Stops cert. propagation when the user logs out.
  863. Arguments:
  864. lpvParam - Winlogon notification info.
  865. --*/
  866. {
  867. PTHREAD_DATA pThreadData = (PTHREAD_DATA) hSCardUI;
  868. if(NULL != pThreadData->hThread)
  869. {
  870. DWORD dwStatus;
  871. StopMonitorReaders(pThreadData);
  872. dwStatus = WaitForSingleObject(
  873. pThreadData->hThread,
  874. INFINITE
  875. );
  876. _ASSERT(dwStatus == WAIT_OBJECT_0);
  877. CloseHandle(pThreadData->hClose);
  878. // now free all data
  879. for (DWORD dwIndex = 0; dwIndex < pThreadData->dwRemovedReaders; dwIndex++) {
  880. FreeReaderData(
  881. pThreadData,
  882. pThreadData->ppRemovedReaderData[dwIndex]
  883. );
  884. HeapFree(
  885. pThreadData->hHeap,
  886. 0,
  887. pThreadData->ppRemovedReaderData[dwIndex]->pszReaderName
  888. );
  889. HeapFree(
  890. pThreadData->hHeap,
  891. 0,
  892. pThreadData->ppRemovedReaderData[dwIndex]
  893. );
  894. }
  895. HeapFree(pThreadData->hHeap, 0, pThreadData);
  896. }
  897. return ERROR_SUCCESS;
  898. }
  899. #ifdef TEST
  900. #include <conio.h>
  901. __cdecl
  902. main(
  903. int argc,
  904. char ** argv
  905. )
  906. {
  907. HSCARDUI hScardUi;
  908. hScardUi = SCardUIInit(NULL);
  909. while (TRUE) {
  910. _sleep(1000);
  911. if (_kbhit()) {
  912. _getch();
  913. SCardUIExit(hScardUi);
  914. break;
  915. }
  916. }
  917. hScardUi = SCardUIInit(NULL);
  918. while (TRUE) {
  919. _sleep(1000);
  920. if (_kbhit()) {
  921. SCardUIExit(hScardUi);
  922. return 0;
  923. }
  924. }
  925. }
  926. #endif