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.

1187 lines
34 KiB

  1. #include <windows.h>
  2. #include <wincrypt.h>
  3. #pragma warning(push)
  4. #pragma warning(disable:4201)
  5. // Disable error C4201 in public header
  6. // nonstandard extension used : nameless struct/union
  7. #include <winscard.h>
  8. #pragma warning(pop)
  9. #include "basecsp.h"
  10. #include "datacach.h"
  11. #include "cardmod.h"
  12. #include "debug.h"
  13. //
  14. // Debugging Macros
  15. //
  16. #define LOG_BEGIN_FUNCTION(x) \
  17. { DebugLog((DEB_TRACE_FINDCARD, "%s: Entering\n", #x)); }
  18. #define LOG_END_FUNCTION(x, y) \
  19. { DebugLog((DEB_TRACE_FINDCARD, "%s: Leaving, status: 0x%x\n", #x, y)); }
  20. //
  21. // Function: FindCardMakeCardHandles
  22. //
  23. // Purpose: Based on reader name information in the CARD_MATCH_DATA
  24. // structure, build and return an SCARD_CONTEXT and SCARD_HANDLE
  25. // for the target card.
  26. //
  27. // Note, the wszMatchedReader, dwShareMode, and dwPreferredProtocols fields
  28. // of the CARD_MATCH_DATA structure must be initialized by the caller.
  29. //
  30. DWORD FindCardMakeCardHandles(
  31. IN PCARD_MATCH_DATA pCardMatchData,
  32. OUT SCARDCONTEXT *pSCardContext,
  33. OUT SCARDHANDLE *pSCardHandle)
  34. {
  35. DWORD dwSts = ERROR_SUCCESS;
  36. DWORD dwActiveProtocol = 0;
  37. *pSCardContext = 0;
  38. *pSCardHandle = 0;
  39. dwSts = SCardEstablishContext(
  40. SCARD_SCOPE_USER,
  41. NULL,
  42. NULL,
  43. pSCardContext);
  44. if (ERROR_SUCCESS != dwSts)
  45. goto Ret;
  46. dwSts = SCardConnectW(
  47. *pSCardContext,
  48. pCardMatchData->wszMatchedReader,
  49. pCardMatchData->dwShareMode,
  50. pCardMatchData->dwPreferredProtocols,
  51. pSCardHandle,
  52. &dwActiveProtocol);
  53. Ret:
  54. if (ERROR_SUCCESS != dwSts)
  55. {
  56. if (*pSCardHandle)
  57. {
  58. SCardDisconnect(*pSCardHandle, SCARD_LEAVE_CARD);
  59. *pSCardHandle = 0;
  60. }
  61. if (*pSCardContext)
  62. {
  63. SCardReleaseContext(*pSCardContext);
  64. *pSCardContext = 0;
  65. }
  66. }
  67. return dwSts;
  68. }
  69. //
  70. // Function: CardStateCacheFindAddItem
  71. //
  72. // Purpose: Lookup the card specified in the CARD_MATCH_DATA structure
  73. // in the CSP's cache of CARD_STATE items. If the card is found
  74. // in the cache, set the CARD_MATCH_DATA to point to the cached
  75. // item.
  76. //
  77. // If the matching card is not found cached, add it to the cache.
  78. //
  79. // If this function Succeeds, the returned CARD_STATE structure
  80. // has its own valid card context and card handle.
  81. //
  82. DWORD CardStateCacheFindAddItem(
  83. IN PCARD_MATCH_DATA pCardMatchData)
  84. {
  85. DWORD dwSts = ERROR_SUCCESS;
  86. BOOL fInCspCS = FALSE;
  87. DATA_BLOB dbKeys;
  88. DATA_BLOB dbCardState;
  89. PCARD_STATE pCardState = pCardMatchData->pCardState;
  90. BOOL fMakeNewCardHandle = FALSE;
  91. BOOL fInCardStateCS = FALSE;
  92. memset(&dbKeys, 0, sizeof(dbKeys));
  93. memset(&dbCardState, 0, sizeof(dbCardState));
  94. DsysAssert(0 != pCardState->pCardData->hScard);
  95. DsysAssert(0 != pCardState->pCardData->hSCardCtx);
  96. DsysAssert(0 != pCardMatchData->hSCard);
  97. DsysAssert(0 != pCardMatchData->hSCardCtx);
  98. // Now going to search the CSP_STATE for a cached entry for the current
  99. // card. Grab the critical section protecting the cache.
  100. dwSts = CspEnterCriticalSection(
  101. &pCardMatchData->pCspState->cs);
  102. if (ERROR_SUCCESS != dwSts)
  103. goto Ret;
  104. fInCspCS = TRUE;
  105. // Lookup a cache entry via card serial number
  106. dbKeys.pbData = (PBYTE) pCardMatchData->pCardState->wszSerialNumber;
  107. dbKeys.cbData =
  108. wcslen(pCardMatchData->pCardState->wszSerialNumber) * sizeof(
  109. pCardMatchData->pCardState->wszSerialNumber[0]);
  110. dwSts = CacheGetItem(
  111. pCardMatchData->pCspState->hCache,
  112. &dbKeys,
  113. 1, &dbCardState);
  114. if (ERROR_NOT_FOUND != dwSts &&
  115. ERROR_SUCCESS != dwSts)
  116. // some unexpected error has occurred
  117. goto Ret;
  118. if (ERROR_NOT_FOUND == dwSts)
  119. {
  120. // This is a new card that has not been cached yet. Add it
  121. // to the cache.
  122. //
  123. // Since we're not using an already-cached card, and we expect
  124. // that this card object was just passed to us new, we know
  125. // that we need to create a new card handle for it.
  126. //
  127. dbCardState.cbData = sizeof(CARD_STATE);
  128. dbCardState.pbData = (PBYTE) pCardState;
  129. dwSts = CacheAddItem(
  130. pCardMatchData->pCspState->hCache,
  131. &dbKeys,
  132. 1, &dbCardState);
  133. dbCardState.pbData = NULL;
  134. if (ERROR_SUCCESS != dwSts)
  135. goto Ret;
  136. DsysAssert(TRUE == fInCspCS);
  137. // We're done mucking with the cache list, so let it go.
  138. CspLeaveCriticalSection(&pCardMatchData->pCspState->cs);
  139. fInCspCS = FALSE;
  140. }
  141. else
  142. {
  143. DsysAssert(TRUE == fInCspCS);
  144. // We're now done with the cache list in this case.
  145. CspLeaveCriticalSection(&pCardMatchData->pCspState->cs);
  146. fInCspCS = FALSE;
  147. //
  148. // The current card has already been cached. Free the local copy of
  149. // the CSP_STATE struct and use the cached one instead.
  150. //
  151. // We can't hold the critsec on the current CardState, and keep its
  152. // associated card's transaction, while waiting for the critsec of
  153. // another CardState. That could deadlock.
  154. //
  155. if (pCardMatchData->fTransacted)
  156. {
  157. dwSts = CspEndTransaction(pCardState);
  158. if (ERROR_SUCCESS != dwSts)
  159. goto Ret;
  160. pCardMatchData->fTransacted = FALSE;
  161. }
  162. // Can't let the SCARDCONTEXT be released, because the scarddlg
  163. // routines will still be expecting to use it.
  164. pCardState->pCardData->hSCardCtx = 0;
  165. DeleteCardState(pCardState);
  166. CspFreeH(pCardState);
  167. pCardMatchData->pCardState = (PCARD_STATE) dbCardState.pbData;
  168. // Update the local pointer for convenience.
  169. pCardState = (PCARD_STATE) dbCardState.pbData;
  170. // Don't want this pointer freed out from under us since we're going
  171. // to use this struct.
  172. dbCardState.pbData = NULL;
  173. //
  174. // Now we need to verify that the handles cached with this card
  175. // structure are still valid. Check now. If the handles
  176. // aren't valid anymore, we'll reconnect to this card below.
  177. //
  178. // We want to ensure that each card object has it's own handles.
  179. //
  180. // Since the card state objects are shared, we need to take the
  181. // critical section of the target object before we can examine its
  182. // handles.
  183. //
  184. dwSts = CspEnterCriticalSection(&pCardState->cs);
  185. if (ERROR_SUCCESS != dwSts)
  186. goto Ret;
  187. else
  188. fInCardStateCS = TRUE;
  189. if (pCardMatchData->hSCardCtx == pCardState->pCardData->hSCardCtx)
  190. dwSts = ValidateCardHandle(pCardState, FALSE, NULL);
  191. else
  192. dwSts = ValidateCardHandle(pCardState, TRUE, NULL);
  193. if (ERROR_SUCCESS != dwSts)
  194. fMakeNewCardHandle = TRUE;
  195. }
  196. if (fMakeNewCardHandle)
  197. {
  198. if (FALSE == fInCardStateCS)
  199. {
  200. dwSts = CspEnterCriticalSection(&pCardState->cs);
  201. if (ERROR_SUCCESS != dwSts)
  202. goto Ret;
  203. else
  204. fInCardStateCS = TRUE;
  205. }
  206. dwSts = FindCardMakeCardHandles(
  207. pCardMatchData,
  208. &pCardState->pCardData->hSCardCtx,
  209. &pCardState->pCardData->hScard);
  210. }
  211. Ret:
  212. if (fInCardStateCS)
  213. CspLeaveCriticalSection(&pCardState->cs);
  214. if (fInCspCS)
  215. CspLeaveCriticalSection(
  216. &pCardMatchData->pCspState->cs);
  217. if (dbCardState.pbData)
  218. CspFreeH(dbCardState.pbData);
  219. return dwSts;
  220. }
  221. //
  222. // Function: GetCardSerialNumber
  223. //
  224. // Purpose: Attempt to read the serial number of the card
  225. // specified in pCardMatchData.
  226. //
  227. // Assumes that a transaction is not currently held on the target
  228. // card by the caller.
  229. //
  230. DWORD GetCardSerialNumber(
  231. IN OUT PCARD_MATCH_DATA pCardMatchData)
  232. {
  233. PFN_CARD_ACQUIRE_CONTEXT pfnCardAcquireContext = NULL;
  234. DWORD cch = 0;
  235. WCHAR rgwsz[MAX_PATH];
  236. DWORD dwSts = ERROR_SUCCESS;
  237. PCARD_STATE pCardState = NULL;
  238. PCARD_DATA pCardData = NULL;
  239. DATA_BLOB DataBlob;
  240. DWORD dwState = 0;
  241. DWORD dwProtocol = 0;
  242. LPWSTR mszReaders = NULL;
  243. LOG_BEGIN_FUNCTION(GetCardSerialNumber);
  244. memset(&DataBlob, 0, sizeof(DataBlob));
  245. //
  246. // Determine how to talk to the card by looking
  247. // for the appropriate Card Specific Module in the Calais
  248. // database.
  249. //
  250. cch = sizeof(rgwsz) / sizeof(rgwsz[0]);
  251. dwSts = SCardGetCardTypeProviderNameW(
  252. pCardMatchData->hSCardCtx,
  253. pCardMatchData->wszMatchedCard,
  254. SCARD_PROVIDER_CARD_MODULE,
  255. rgwsz,
  256. &cch);
  257. if (ERROR_SUCCESS != dwSts)
  258. goto Ret;
  259. pCardState = (PCARD_STATE) CspAllocH(sizeof(CARD_STATE));
  260. LOG_CHECK_ALLOC(pCardState);
  261. pCardState->dwVersion = CARD_STATE_CURRENT_VERSION;
  262. dwSts = InitializeCardState(pCardState);
  263. if (ERROR_SUCCESS != dwSts)
  264. goto Ret;
  265. pCardState->hCardModule = LoadLibraryW(rgwsz);
  266. if (0 == pCardState->hCardModule)
  267. {
  268. dwSts = GetLastError();
  269. goto Ret;
  270. }
  271. pfnCardAcquireContext =
  272. (PFN_CARD_ACQUIRE_CONTEXT) GetProcAddress(
  273. pCardState->hCardModule,
  274. "CardAcquireContext");
  275. if (NULL == pfnCardAcquireContext)
  276. {
  277. dwSts = GetLastError();
  278. goto Ret;
  279. }
  280. pCardData = (PCARD_DATA) CspAllocH(sizeof(CARD_DATA));
  281. LOG_CHECK_ALLOC(pCardData);
  282. dwSts = InitializeCardData(pCardData);
  283. if (ERROR_SUCCESS != dwSts)
  284. goto Ret;
  285. //
  286. // We need to temporarily copy the current card handle into the
  287. // CARD_DATA structure, so we can make some calls into the card
  288. // module. We may keep these handles in some cases.
  289. //
  290. pCardData->hScard = pCardMatchData->hSCard;
  291. pCardData->hSCardCtx = pCardMatchData->hSCardCtx;
  292. pCardData->pwszCardName = (LPWSTR) CspAllocH(
  293. (1 + wcslen(pCardMatchData->wszMatchedCard)) * sizeof(WCHAR));
  294. LOG_CHECK_ALLOC(pCardData->pwszCardName);
  295. wcscpy(
  296. pCardData->pwszCardName,
  297. pCardMatchData->wszMatchedCard);
  298. pCardData->cbAtr = cbATR_BUFFER;
  299. pCardData->pbAtr = (PBYTE) CspAllocH(cbATR_BUFFER);
  300. LOG_CHECK_ALLOC(pCardData->pbAtr);
  301. //
  302. // Use SCardStatus to get the ATR of the card we're trying
  303. // to talk to.
  304. //
  305. cch = SCARD_AUTOALLOCATE;
  306. dwSts = SCardStatusW(
  307. pCardData->hScard,
  308. (LPWSTR) &mszReaders,
  309. &cch,
  310. &dwState,
  311. &dwProtocol,
  312. pCardData->pbAtr,
  313. &pCardData->cbAtr);
  314. switch (dwSts)
  315. {
  316. case SCARD_W_RESET_CARD:
  317. // The card managed to get reset already. Try to reconnect.
  318. dwSts = SCardReconnect(
  319. pCardData->hScard,
  320. pCardMatchData->dwShareMode,
  321. pCardMatchData->dwPreferredProtocols,
  322. SCARD_LEAVE_CARD,
  323. &dwProtocol);
  324. if (ERROR_SUCCESS != dwSts)
  325. goto Ret;
  326. break;
  327. case ERROR_SUCCESS:
  328. break;
  329. default:
  330. goto Ret;
  331. }
  332. //
  333. // Now acquire a card module context for this card.
  334. //
  335. dwSts = pfnCardAcquireContext(pCardData, 0);
  336. if (ERROR_SUCCESS != dwSts)
  337. goto Ret;
  338. pCardState->pCardData = pCardData;
  339. pCardData = NULL;
  340. //
  341. // Now that we have both the CARD_STATE and CARD_DATA structures,
  342. // we can setup the caching contexts to be used by the CSP and to
  343. // be exposed to the card module.
  344. //
  345. dwSts = InitializeCspCaching(pCardState);
  346. if (ERROR_SUCCESS != dwSts)
  347. goto Ret;
  348. dwSts = CspBeginTransaction(pCardState);
  349. if (ERROR_SUCCESS != dwSts)
  350. goto Ret;
  351. pCardMatchData->fTransacted = TRUE;
  352. //
  353. // Get the serial number for this card
  354. //
  355. dwSts = CspReadFile(
  356. pCardState,
  357. wszCARD_IDENTIFIER_FILE_FULL_PATH,
  358. 0,
  359. &DataBlob.pbData,
  360. &DataBlob.cbData);
  361. if (ERROR_SUCCESS != dwSts)
  362. {
  363. CspEndTransaction(pCardState);
  364. pCardMatchData->fTransacted = FALSE;
  365. goto Ret;
  366. }
  367. memcpy(
  368. pCardState->wszSerialNumber,
  369. DataBlob.pbData,
  370. DataBlob.cbData);
  371. pCardState->pfnCardAcquireContext = pfnCardAcquireContext;
  372. pCardMatchData->pCardState = pCardState;
  373. pCardState = NULL;
  374. Ret:
  375. // If we're not in a transaction, assume the current handles will be
  376. // cleaned up by the caller
  377. /*
  378. if (NULL != pCardMatchData->pCardState &&
  379. NULL != pCardMatchData->pCardState->pCardData &&
  380. FALSE == pCardMatchData->fTransacted)
  381. {
  382. pCardMatchData->pCardState->pCardData->hScard = 0;
  383. pCardMatchData->pCardState->pCardData->hSCardCtx = 0;
  384. }
  385. */
  386. if (DataBlob.pbData)
  387. CspFreeH(DataBlob.pbData);
  388. if (pCardState)
  389. {
  390. DeleteCardState(pCardState);
  391. CspFreeH(pCardState);
  392. }
  393. if (pCardData)
  394. {
  395. CleanupCardData(pCardData);
  396. CspFreeH(pCardData);
  397. }
  398. if (mszReaders)
  399. SCardFreeMemory(pCardMatchData->hSCardCtx, mszReaders);
  400. LOG_END_FUNCTION(GetCardSerialNumber, dwSts);
  401. return dwSts;
  402. }
  403. //
  404. // Function: FindCardConnectProc
  405. //
  406. // Purpose: This function is called by SCardUIDlgSelectCard to
  407. // connect to candidate cards. This is a wrapper for
  408. // SCardConnectW, useful because the reader name and card
  409. // name are copied into the PCARD_MATCH_DATA structure for
  410. // reference by FindCardCheckProc, below.
  411. //
  412. SCARDHANDLE WINAPI FindCardConnectProc(
  413. IN SCARDCONTEXT hSCardCtx,
  414. IN LPWSTR wszReader,
  415. IN LPWSTR wszCard,
  416. IN OUT PVOID pvCardMatchData)
  417. {
  418. SCARDHANDLE hSCard = 0;
  419. DWORD dwSts = ERROR_SUCCESS;
  420. PCARD_MATCH_DATA pCardMatchData = (PCARD_MATCH_DATA) pvCardMatchData;
  421. DsysAssert(FALSE == pCardMatchData->fTransacted);
  422. dwSts = SCardConnectW(
  423. hSCardCtx,
  424. wszReader,
  425. pCardMatchData->dwShareMode,
  426. pCardMatchData->dwPreferredProtocols,
  427. &hSCard,
  428. &pCardMatchData->dwActiveProtocol);
  429. if (ERROR_SUCCESS != dwSts)
  430. {
  431. SetLastError(dwSts);
  432. return 0;
  433. }
  434. wcsncpy(
  435. pCardMatchData->wszMatchedCard,
  436. wszCard,
  437. pCardMatchData->cchMatchedCard);
  438. wcsncpy(
  439. pCardMatchData->wszMatchedReader,
  440. wszReader,
  441. pCardMatchData->cchMatchedReader);
  442. return hSCard;
  443. }
  444. //
  445. // Function: FindCardDisconnectProc
  446. //
  447. // Purpose: Called by SCardUIDlgSelectCard, this is a wrapper
  448. // for SCardDisconnect. Some cleanup is also done in the
  449. // provided CARD_MATCH_DATA structure to indicate that no
  450. // card handle is currently active.
  451. //
  452. void WINAPI FindCardDisconnectProc(
  453. IN SCARDCONTEXT hSCardCtx,
  454. IN SCARDHANDLE hSCard,
  455. IN PVOID pvCardMatchData)
  456. {
  457. DWORD dwSts = ERROR_SUCCESS;
  458. PCARD_MATCH_DATA pCardMatchData = (PCARD_MATCH_DATA) pvCardMatchData;
  459. UNREFERENCED_PARAMETER(hSCardCtx);
  460. DsysAssert(FALSE == pCardMatchData->fTransacted);
  461. //
  462. // Get rid of the matching card and reader information.
  463. //
  464. memset(
  465. pCardMatchData->wszMatchedCard,
  466. 0,
  467. pCardMatchData->cchMatchedCard * sizeof(pCardMatchData->wszMatchedCard[0]));
  468. memset(
  469. pCardMatchData->wszMatchedReader,
  470. 0,
  471. pCardMatchData->cchMatchedReader * sizeof(pCardMatchData->wszMatchedReader[0]));
  472. pCardMatchData->hSCard = 0;
  473. // If there is a matched card currently, we may be about to disconnect its
  474. // card handle. If so, set that handle value to zero.
  475. if (NULL != pCardMatchData->pCardState)
  476. {
  477. dwSts = CspEnterCriticalSection(
  478. &pCardMatchData->pCardState->cs);
  479. if (ERROR_SUCCESS != dwSts)
  480. {
  481. SetLastError(dwSts);
  482. return;
  483. }
  484. if (hSCard == pCardMatchData->pCardState->pCardData->hScard)
  485. pCardMatchData->pCardState->pCardData->hScard = 0;
  486. CspLeaveCriticalSection(
  487. &pCardMatchData->pCardState->cs);
  488. }
  489. dwSts = SCardDisconnect(hSCard, SCARD_LEAVE_CARD);
  490. if (ERROR_SUCCESS != dwSts)
  491. {
  492. SetLastError(dwSts);
  493. return;
  494. }
  495. }
  496. //
  497. // Function: FindCardMatchUserParamaters
  498. //
  499. // Purpose: Check the card specified in the CARD_MATCH_DATA structure against
  500. // the user parameters specified in CryptAcquireContext.
  501. //
  502. // Assumes that the caller does not hold a transaction on the
  503. // target card.
  504. //
  505. // If the card match is successful, the transaction will still be held
  506. // when the function returns. The caller must release it.
  507. //
  508. DWORD WINAPI FindCardMatchUserParameters(
  509. IN PCARD_MATCH_DATA pCardMatchData)
  510. {
  511. DWORD dwSts = ERROR_SUCCESS;
  512. CARD_FREE_SPACE_INFO CardFreeSpaceInfo;
  513. DATA_BLOB DataBlob;
  514. PCARD_STATE pCardState = pCardMatchData->pCardState;
  515. CONTAINER_MAP_RECORD ContainerRecord;
  516. BYTE cContainers = 0;
  517. LOG_BEGIN_FUNCTION(FindCardMatchUserParameters);
  518. memset(&CardFreeSpaceInfo, 0, sizeof(CardFreeSpaceInfo));
  519. memset(&DataBlob, 0, sizeof(DataBlob));
  520. memset(&ContainerRecord, 0, sizeof(ContainerRecord));
  521. //
  522. // Now start checking this card for matching
  523. // information.
  524. //
  525. if (CRYPT_NEWKEYSET & pCardMatchData->dwCtxFlags)
  526. {
  527. if (FALSE == pCardMatchData->fTransacted)
  528. {
  529. dwSts = CspBeginTransaction(pCardState);
  530. if (ERROR_SUCCESS != dwSts)
  531. goto Ret;
  532. pCardMatchData->fTransacted = TRUE;
  533. }
  534. //
  535. // The user wants to create a new keyset. Will that
  536. // be possible on this card?
  537. //
  538. dwSts = CspQueryFreeSpace(
  539. pCardState,
  540. 0,
  541. &CardFreeSpaceInfo);
  542. if (ERROR_SUCCESS != dwSts)
  543. goto Ret;
  544. // Determine how many valid containers are already present on this card
  545. dwSts = ContainerMapEnumContainers(
  546. pCardState, &cContainers, NULL);
  547. if (ERROR_SUCCESS != dwSts)
  548. goto Ret;
  549. if (cContainers >= CardFreeSpaceInfo.dwMaxKeyContainers)
  550. {
  551. // No space for an additional container exists on
  552. // this card.
  553. dwSts = (DWORD) NTE_TOKEN_KEYSET_STORAGE_FULL;
  554. goto Ret;
  555. }
  556. // If a container name was specified, make sure that container name
  557. // doesn't already exist on this card.
  558. if (NULL != pCardMatchData->pwszContainerName)
  559. {
  560. wcscpy(ContainerRecord.wszGuid, pCardMatchData->pwszContainerName);
  561. dwSts = ContainerMapFindContainer(
  562. pCardState, &ContainerRecord, NULL);
  563. switch (dwSts)
  564. {
  565. case ERROR_SUCCESS:
  566. // If that call succeeded, then the specified container
  567. // already exists, so this card can't be used.
  568. dwSts = (DWORD) NTE_EXISTS;
  569. break;
  570. case NTE_BAD_KEYSET:
  571. // In this case, we're successful because the keyset
  572. // wasn't found.
  573. dwSts = ERROR_SUCCESS;
  574. break;
  575. default:
  576. goto Ret;
  577. }
  578. }
  579. else
  580. {
  581. // Otherwise, the caller is attempting to create a new default
  582. // container, using a random Guid. Nothing else to do at this time.
  583. }
  584. }
  585. else if (CRYPT_VERIFYCONTEXT & pCardMatchData->dwCtxFlags)
  586. {
  587. //
  588. // Caller is requesting VERIFYCONTEXT only. We don't need to check
  589. // for a specific container, we we're done.
  590. //
  591. }
  592. else
  593. {
  594. if (FALSE == pCardMatchData->fTransacted)
  595. {
  596. dwSts = CspBeginTransaction(pCardState);
  597. if (ERROR_SUCCESS != dwSts)
  598. goto Ret;
  599. pCardMatchData->fTransacted = TRUE;
  600. }
  601. //
  602. // The user wants to open an existing keyset.
  603. //
  604. if (pCardMatchData->pwszContainerName)
  605. {
  606. wcscpy(ContainerRecord.wszGuid, pCardMatchData->pwszContainerName);
  607. dwSts = ContainerMapFindContainer(
  608. pCardState,
  609. &ContainerRecord,
  610. &pCardMatchData->bContainerIndex);
  611. if (ERROR_SUCCESS != dwSts)
  612. {
  613. dwSts = (DWORD) SCARD_E_NO_KEY_CONTAINER;
  614. goto Ret;
  615. }
  616. }
  617. else
  618. {
  619. // User wants to open an existing default container.
  620. dwSts = ContainerMapGetDefaultContainer(
  621. pCardState,
  622. &ContainerRecord,
  623. &pCardMatchData->bContainerIndex);
  624. if (ERROR_SUCCESS != dwSts)
  625. {
  626. dwSts = (DWORD) SCARD_E_NO_KEY_CONTAINER;
  627. goto Ret;
  628. }
  629. // Hang onto the default container name - it will be needed in
  630. // the User Context.
  631. pCardMatchData->pwszContainerName = (LPWSTR) CspAllocH(
  632. (wcslen(ContainerRecord.wszGuid) + 1) * sizeof(WCHAR));
  633. LOG_CHECK_ALLOC(pCardMatchData->pwszContainerName);
  634. wcscpy(
  635. pCardMatchData->pwszContainerName,
  636. ContainerRecord.wszGuid);
  637. pCardMatchData->fFreeContainerName = TRUE;
  638. }
  639. }
  640. Ret:
  641. if (ERROR_SUCCESS != dwSts && TRUE == pCardMatchData->fTransacted)
  642. {
  643. CspEndTransaction(pCardMatchData->pCardState);
  644. pCardMatchData->fTransacted = FALSE;
  645. }
  646. if (DataBlob.pbData)
  647. CspFreeH(DataBlob.pbData);
  648. LOG_END_FUNCTION(FindCardMatchUserParameters, dwSts);
  649. return dwSts;
  650. }
  651. //
  652. // Function: FindCardCheckProc
  653. //
  654. // Purpose: Called by SCardUIDlgSelectCard to check candidate cards.
  655. //
  656. BOOL WINAPI FindCardCheckProc(
  657. IN SCARDCONTEXT hSCardCtx,
  658. IN SCARDHANDLE hSCard,
  659. IN PVOID pvCardMatchData)
  660. {
  661. DWORD dwSts = ERROR_SUCCESS;
  662. PCARD_MATCH_DATA pCardMatchData = (PCARD_MATCH_DATA) pvCardMatchData;
  663. BOOL fCardMatches = FALSE;
  664. UNREFERENCED_PARAMETER(hSCardCtx);
  665. LOG_BEGIN_FUNCTION(FindCardCheckProc);
  666. pCardMatchData->hSCard = hSCard;
  667. pCardMatchData->dwError = ERROR_SUCCESS;
  668. //
  669. // Read the serial number from the card
  670. //
  671. dwSts = GetCardSerialNumber(
  672. pCardMatchData);
  673. if (ERROR_SUCCESS != dwSts)
  674. goto Ret;
  675. //
  676. // Lookup the serial number in our cached list
  677. // of cards
  678. //
  679. dwSts = CardStateCacheFindAddItem(
  680. pCardMatchData);
  681. if (ERROR_SUCCESS != dwSts)
  682. goto Ret;
  683. if (CARD_MATCH_TYPE_SERIAL_NUMBER ==
  684. pCardMatchData->dwMatchType)
  685. {
  686. // We're working on a "by Serial Number" match, so compare
  687. // the requested serial number to that of the card being
  688. // examined. If they match, the search ends successfully.
  689. // If they don't, we know this is the wrong card.
  690. if (0 == wcscmp(
  691. pCardMatchData->pwszSerialNumber,
  692. pCardMatchData->pCardState->wszSerialNumber))
  693. {
  694. fCardMatches = TRUE;
  695. }
  696. }
  697. else
  698. {
  699. // We're not searching by serial number, so we'll make some sort
  700. // of container-based decision for matching a card.
  701. dwSts = FindCardMatchUserParameters(
  702. pCardMatchData);
  703. if (ERROR_SUCCESS == dwSts ||
  704. (NTE_TOKEN_KEYSET_STORAGE_FULL == dwSts &&
  705. SC_DLG_NO_UI != pCardMatchData->dwUIFlags))
  706. {
  707. //
  708. // If the user picked this card explicitly from the UI, but
  709. // the card is full, report a successful match to scarddlg.
  710. // This allows the CSP to return an appropriate error code
  711. // to allow enrollment to restart by re-using an existing key,
  712. // rather than trying to create a new one.
  713. //
  714. fCardMatches = TRUE;
  715. }
  716. }
  717. Ret:
  718. pCardMatchData->hSCard = 0;
  719. if (pCardMatchData->fTransacted)
  720. {
  721. CspEndTransaction(pCardMatchData->pCardState);
  722. pCardMatchData->fTransacted = FALSE;
  723. }
  724. if (TRUE == fCardMatches)
  725. {
  726. pCardMatchData->pUIMatchedCardState = pCardMatchData->pCardState;
  727. }
  728. else
  729. {
  730. pCardMatchData->pCardState = NULL;
  731. pCardMatchData->dwError = dwSts;
  732. }
  733. LOG_END_FUNCTION(FindCardCheckProc, dwSts);
  734. return fCardMatches;
  735. }
  736. //
  737. // Function: FindCardCached
  738. //
  739. // Purpose: Attempt to find a matching card using only cached
  740. // data.
  741. //
  742. DWORD FindCardCached(
  743. IN OUT PCARD_MATCH_DATA pCardMatchData)
  744. {
  745. PCARD_STATE pCardState = NULL;
  746. DWORD dwSts = ERROR_SUCCESS;
  747. PDATA_BLOB pdb = NULL;
  748. DWORD cItems = 0;
  749. BOOL fCardStatusChanged = FALSE;
  750. LOG_BEGIN_FUNCTION(FindCardCached);
  751. dwSts = CspEnterCriticalSection(
  752. &pCardMatchData->pCspState->cs);
  753. if (ERROR_SUCCESS != dwSts)
  754. goto Ret;
  755. dwSts = CacheEnumItems(
  756. pCardMatchData->pCspState->hCache,
  757. &pdb,
  758. &cItems);
  759. CspLeaveCriticalSection(
  760. &pCardMatchData->pCspState->cs);
  761. if (ERROR_SUCCESS != dwSts)
  762. goto Ret;
  763. while (cItems--)
  764. {
  765. pCardState = (PCARD_STATE) pdb[cItems].pbData;
  766. pCardMatchData->pCardState = pCardState;
  767. // Make sure the handle for this cached card is still valid. If
  768. // the handle isn't valid, skip this card for the cached search.
  769. dwSts = CspEnterCriticalSection(&pCardState->cs);
  770. if (ERROR_SUCCESS != dwSts)
  771. goto Ret;
  772. dwSts = ValidateCardHandle(pCardState, TRUE, &fCardStatusChanged);
  773. if ((ERROR_SUCCESS != dwSts ||
  774. TRUE == fCardStatusChanged) &&
  775. NULL != pCardState->hPinCache)
  776. {
  777. // Flush the pin cache for this card. Not checking error code
  778. // since we'll keep processing, anyway.
  779. CspRemoveCachedPin(pCardState, wszCARD_USER_USER);
  780. }
  781. CspLeaveCriticalSection(&pCardState->cs);
  782. if (ERROR_SUCCESS == dwSts)
  783. {
  784. dwSts = FindCardMatchUserParameters(
  785. pCardMatchData);
  786. if (ERROR_SUCCESS == dwSts)
  787. break;
  788. else
  789. pCardMatchData->pCardState = NULL;
  790. }
  791. }
  792. CacheFreeEnumItems(pdb);
  793. Ret:
  794. if (TRUE == pCardMatchData->fTransacted)
  795. {
  796. CspEndTransaction(pCardMatchData->pCardState);
  797. pCardMatchData->fTransacted = FALSE;
  798. }
  799. LOG_END_FUNCTION(FindCardCached, dwSts);
  800. return dwSts;
  801. }
  802. //
  803. // Function: FindCard
  804. //
  805. // Purpose: Primary internal routine for matching a suitable card
  806. // based on these factors:
  807. //
  808. // a) Cards that are supportable by this CSP.
  809. // b) Cards that meet the user supplied criteria from
  810. // CryptAcquireContext.
  811. //
  812. DWORD FindCard(
  813. IN OUT PCARD_MATCH_DATA pCardMatchData)
  814. {
  815. DWORD dwSts = ERROR_SUCCESS;
  816. OPENCARDNAME_EXW ocnx;
  817. OPENCARD_SEARCH_CRITERIAW ocsc;
  818. LOG_BEGIN_FUNCTION(FindCard);
  819. if (CARD_MATCH_TYPE_READER_AND_CONTAINER ==
  820. pCardMatchData->dwMatchType)
  821. {
  822. //
  823. // Only look for a cached card if the search type is
  824. // by Reader and Container.
  825. //
  826. // The reason for this is: if we already know the serial number
  827. // of the card we're looking for, then we must have already had a
  828. // valid card previously. Assume that we'll have to go through
  829. // the Resource Manager to locate such a card, because the card
  830. // handle became invalid and reconnect failed (the card was withdrawn
  831. // and possibly inserted in a different reader).
  832. //
  833. dwSts = FindCardCached(pCardMatchData);
  834. if (ERROR_SUCCESS == dwSts &&
  835. NULL != pCardMatchData->pCardState)
  836. {
  837. //
  838. // Found a cached card, so we're done.
  839. //
  840. goto Ret;
  841. }
  842. }
  843. //
  844. // No cached card was found, or this is a "by Serial Number" search,
  845. // so continue the search via
  846. // the smart card subsystem.
  847. //
  848. dwSts = SCardEstablishContext(
  849. SCARD_SCOPE_USER, NULL, NULL, &pCardMatchData->hSCardCtx);
  850. if (ERROR_SUCCESS != dwSts)
  851. goto Ret;
  852. memset(&ocnx, 0, sizeof(ocnx));
  853. memset(&ocsc, 0, sizeof(ocsc));
  854. ocsc.dwStructSize = sizeof(ocsc);
  855. ocsc.lpfnCheck = FindCardCheckProc;
  856. ocsc.lpfnConnect = FindCardConnectProc;
  857. ocsc.lpfnDisconnect = FindCardDisconnectProc;
  858. ocsc.dwShareMode = pCardMatchData->dwShareMode;
  859. ocsc.dwPreferredProtocols = pCardMatchData->dwPreferredProtocols;
  860. ocsc.pvUserData = (PVOID) pCardMatchData;
  861. ocnx.dwStructSize = sizeof(ocnx);
  862. ocnx.pvUserData = (PVOID) pCardMatchData;
  863. ocnx.hSCardContext = pCardMatchData->hSCardCtx;
  864. ocnx.pOpenCardSearchCriteria = &ocsc;
  865. ocnx.lpstrCard = pCardMatchData->wszMatchedCard;
  866. ocnx.nMaxCard = pCardMatchData->cchMatchedCard;
  867. ocnx.lpstrRdr = pCardMatchData->wszMatchedReader;
  868. ocnx.nMaxRdr = pCardMatchData->cchMatchedReader;
  869. ocnx.lpfnConnect = FindCardConnectProc;
  870. ocnx.dwShareMode = pCardMatchData->dwShareMode;
  871. ocnx.dwPreferredProtocols = pCardMatchData->dwPreferredProtocols;
  872. //
  873. // The first attempt at finding a matching card should be done
  874. // "silently." We want to control whether card selection UI is
  875. // displayed, depending on whether a card is currently in the
  876. // reader, and depending on the context flags.
  877. //
  878. ocnx.dwFlags = SC_DLG_NO_UI;
  879. pCardMatchData->dwUIFlags = ocnx.dwFlags;
  880. dwSts = SCardUIDlgSelectCardW(&ocnx);
  881. switch (dwSts)
  882. {
  883. case ERROR_SUCCESS:
  884. break; // Success, we're done.
  885. case SCARD_E_CANCELLED:
  886. if (NTE_TOKEN_KEYSET_STORAGE_FULL == pCardMatchData->dwError)
  887. {
  888. dwSts = (DWORD) NTE_TOKEN_KEYSET_STORAGE_FULL;
  889. break;
  890. }
  891. if ( (CRYPT_SILENT & pCardMatchData->dwCtxFlags) ||
  892. (CRYPT_VERIFYCONTEXT & pCardMatchData->dwCtxFlags))
  893. {
  894. //
  895. // We couldn't show UI, and the caller specified a key container
  896. // (or simply asked for the default) that we couldn't find. Apps
  897. // such as enrollment station expect that we return NTE_BAD_KEYSET
  898. // in this scenario.
  899. //
  900. if (SCARD_E_NO_KEY_CONTAINER == pCardMatchData->dwError)
  901. {
  902. dwSts = (DWORD) NTE_BAD_KEYSET;
  903. break;
  904. }
  905. dwSts = (DWORD) SCARD_E_NO_SMARTCARD;
  906. break;
  907. }
  908. // Allow UI and try again.
  909. ocnx.dwFlags = 0;
  910. pCardMatchData->dwUIFlags = ocnx.dwFlags;
  911. dwSts = SCardUIDlgSelectCardW(&ocnx);
  912. //
  913. // If scarddlg thinks the match was successful, but the matched card
  914. // is actually full, then report that error. This is done so that the
  915. // user can manually select a "full" card in the UI, and
  916. // certificate enrollment can proceed by re-using the existing key.
  917. //
  918. if (ERROR_SUCCESS == dwSts &&
  919. NTE_TOKEN_KEYSET_STORAGE_FULL == pCardMatchData->dwError)
  920. {
  921. dwSts = (DWORD) NTE_TOKEN_KEYSET_STORAGE_FULL;
  922. break;
  923. }
  924. break;
  925. default:
  926. break; // Return error to caller.
  927. }
  928. if (ERROR_SUCCESS == dwSts)
  929. {
  930. // Make sure scarddlg didn't fail unexpectedly
  931. if (0 == ocnx.hCardHandle)
  932. {
  933. dwSts = SCARD_E_NO_SMARTCARD;
  934. goto Ret;
  935. }
  936. DsysAssert(NULL != pCardMatchData->pUIMatchedCardState);
  937. pCardMatchData->pCardState = pCardMatchData->pUIMatchedCardState;
  938. dwSts = CspEnterCriticalSection(
  939. &pCardMatchData->pCardState->cs);
  940. if (ERROR_SUCCESS != dwSts)
  941. goto Ret;
  942. if (0 == pCardMatchData->pCardState->pCardData->hScard)
  943. {
  944. pCardMatchData->pCardState->pCardData->hScard = ocnx.hCardHandle;
  945. ocnx.hCardHandle = 0;
  946. pCardMatchData->pCardState->pCardData->hSCardCtx =
  947. pCardMatchData->hSCardCtx;
  948. pCardMatchData->hSCardCtx = 0;
  949. }
  950. CspLeaveCriticalSection(
  951. &pCardMatchData->pCardState->cs);
  952. ocnx.hCardHandle = 0;
  953. }
  954. Ret:
  955. DsysAssert(FALSE == pCardMatchData->fTransacted);
  956. DsysAssert(0 == pCardMatchData->hSCard);
  957. if (0 != ocnx.hCardHandle)
  958. SCardDisconnect(ocnx.hCardHandle, SCARD_LEAVE_CARD);
  959. if (0 != pCardMatchData->hSCardCtx && ERROR_SUCCESS != dwSts)
  960. SCardReleaseContext(pCardMatchData->hSCardCtx);
  961. LOG_END_FUNCTION(FindCard, dwSts);
  962. return dwSts;
  963. }