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.

562 lines
14 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1998 - 1999
  3. Module Name:
  4. scenum.cpp
  5. Abstract:
  6. This module provides the implementation of the smart card helper functions
  7. provided to Xiaohung Su for use in the Smart Card Enrollment Station.
  8. Author:
  9. Doug Barlow (dbarlow) 11/12/1998
  10. Notes:
  11. Most of these routines use a "context handle", defined as LPVOID. The
  12. proper usage of these routines is to declare a context variable in your
  13. code, and assign it the value 'NULL'. For example,
  14. LPVOID pvScEnlistHandle = NULL;
  15. These routines will use this pointer to establish internal working
  16. structures. It's actual value will change between calls, but the value can
  17. be ignored by the caller.
  18. These routines assume a Windows 2000 platform.
  19. --*/
  20. #include <windows.h>
  21. #include <wincrypt.h>
  22. #include <winscard.h>
  23. #include "scenum.h"
  24. typedef struct {
  25. SCARDCONTEXT hCtx;
  26. LPWSTR mszReaders;
  27. DWORD dwEnumIndex;
  28. DWORD dwActiveReaderCount;
  29. DWORD dwReaderCount;
  30. LPSCARD_READERSTATEW rgReaderStates;
  31. } scEnlistContext;
  32. /*++
  33. CountReaders:
  34. This routine returns the number of active smart card readers currently
  35. installed in the system.
  36. Arguments:
  37. pvHandle supplies the context handle, if any. If it is not NULL, then an
  38. existing context is assumed and used. Otherwise, a temporary internal
  39. context is created for use just within this routine.
  40. Return Value:
  41. The actual number of readers currently installed in the system.
  42. Remarks:
  43. If an error occurs, this routine returns zero. The actual error code will
  44. be available via GetLastError.
  45. Author:
  46. Doug Barlow (dbarlow) 11/12/1998
  47. --*/
  48. DWORD
  49. CountReaders(
  50. IN LPVOID pvHandle)
  51. {
  52. DWORD dwCount = 0;
  53. DWORD dwErr = ERROR_SUCCESS;
  54. SCARDCONTEXT hCtx = NULL;
  55. LPWSTR mszReaders = NULL;
  56. LPWSTR szRdr;
  57. DWORD cchReaders;
  58. scEnlistContext *pscCtx = (scEnlistContext *)pvHandle;
  59. //
  60. // See if we can take a shortcut.
  61. //
  62. if (NULL != pscCtx)
  63. {
  64. if (0 == pscCtx->dwReaderCount)
  65. SetLastError(ERROR_SUCCESS);
  66. return pscCtx->dwReaderCount;
  67. }
  68. //
  69. // We have to do things the hard way.
  70. // Create a temporary context.
  71. //
  72. dwErr = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hCtx);
  73. if (SCARD_S_SUCCESS != dwErr)
  74. goto ErrorExit;
  75. //
  76. // Get a list of active readers, and count them.
  77. //
  78. cchReaders = SCARD_AUTOALLOCATE;
  79. dwErr = SCardListReadersW(hCtx, NULL, (LPWSTR)&mszReaders, &cchReaders);
  80. if (SCARD_S_SUCCESS != dwErr)
  81. goto ErrorExit;
  82. for (szRdr = mszReaders; 0 != *szRdr; szRdr += lstrlenW(szRdr) + 1)
  83. dwCount += 1;
  84. dwErr = SCardFreeMemory(hCtx, mszReaders);
  85. mszReaders = NULL;
  86. if (SCARD_S_SUCCESS != dwErr)
  87. goto ErrorExit;
  88. //
  89. // Eliminate our temporary context.
  90. //
  91. dwErr = SCardReleaseContext(hCtx);
  92. hCtx = NULL;
  93. if (SCARD_S_SUCCESS != dwErr)
  94. goto ErrorExit;
  95. //
  96. // Inform the caller of our findings.
  97. //
  98. if (0 == dwCount)
  99. SetLastError(ERROR_SUCCESS);
  100. return dwCount;
  101. //
  102. // An error has occurred. Clean up, and return.
  103. //
  104. ErrorExit:
  105. if (NULL != mszReaders)
  106. SCardFreeMemory(hCtx, mszReaders);
  107. if ((NULL == pvHandle) && (NULL != hCtx))
  108. SCardReleaseContext(hCtx);
  109. SetLastError(dwErr);
  110. return 0;
  111. }
  112. /*++
  113. ScanReaders:
  114. This function scans active readers in preparation for future
  115. EnumInsertedCards calls. It does not block for changes, but just takes a
  116. snapshot of the existing environment.
  117. Arguments:
  118. ppvHandle supplies a pointer to an LPVOID to be used by this and associated
  119. routines to maintain an internal context.
  120. Return Value:
  121. The number of readers with cards inserted, or zero if an error occurs. When
  122. an error occurs, the actual error code can be obtained from GetLastError.
  123. Remarks:
  124. Prior to the first call to this service, the value of the LPVOID pointed to
  125. by ppvHandle should be set to NULL. When all processing is complete, call
  126. the EndReaderScan service to clean up the internal working space and reset
  127. the value to NULL.
  128. Author:
  129. Doug Barlow (dbarlow) 11/12/1998
  130. --*/
  131. DWORD
  132. ScanReaders(
  133. IN OUT LPVOID *ppvHandle)
  134. {
  135. DWORD dwCount = 0;
  136. DWORD dwErr = SCARD_S_SUCCESS;
  137. LPWSTR szRdr;
  138. DWORD cchReaders, cRdrs, dwIndex;
  139. scEnlistContext *pscCtx = *(scEnlistContext **)ppvHandle;
  140. if (NULL == pscCtx)
  141. {
  142. //
  143. // Create the context structure.
  144. //
  145. pscCtx = (scEnlistContext *)LocalAlloc(LPTR, sizeof(scEnlistContext));
  146. if (NULL == pscCtx)
  147. {
  148. dwErr = SCARD_E_NO_MEMORY;
  149. goto ErrorExit;
  150. }
  151. ZeroMemory(pscCtx, sizeof(scEnlistContext));
  152. dwErr = SCardEstablishContext(
  153. SCARD_SCOPE_USER,
  154. NULL,
  155. NULL,
  156. &pscCtx->hCtx);
  157. if (SCARD_S_SUCCESS != dwErr)
  158. goto ErrorExit;
  159. }
  160. //
  161. // Get a list and a count of the readers.
  162. //
  163. if (NULL != pscCtx->mszReaders)
  164. {
  165. dwErr = SCardFreeMemory(pscCtx->hCtx, pscCtx->mszReaders);
  166. pscCtx->mszReaders = NULL;
  167. if (dwErr != SCARD_S_SUCCESS)
  168. goto ErrorExit;
  169. }
  170. cchReaders = SCARD_AUTOALLOCATE;
  171. dwErr = SCardListReadersW(
  172. pscCtx->hCtx,
  173. NULL,
  174. (LPWSTR)&pscCtx->mszReaders,
  175. &cchReaders);
  176. if (SCARD_S_SUCCESS != dwErr)
  177. goto ErrorExit;
  178. cRdrs = 0;
  179. for (szRdr = pscCtx->mszReaders; 0 != *szRdr; szRdr += lstrlenW(szRdr) + 1)
  180. cRdrs += 1;
  181. //
  182. // Enlarge the reader state array if necessary.
  183. //
  184. if (cRdrs > pscCtx->dwReaderCount)
  185. {
  186. if (NULL != pscCtx->rgReaderStates)
  187. {
  188. LocalFree(pscCtx->rgReaderStates);
  189. pscCtx->dwReaderCount = 0;
  190. }
  191. pscCtx->rgReaderStates =
  192. (LPSCARD_READERSTATEW)LocalAlloc(
  193. LPTR,
  194. cRdrs * sizeof(SCARD_READERSTATEW));
  195. if (NULL == pscCtx->rgReaderStates)
  196. {
  197. dwErr = SCARD_E_NO_MEMORY;
  198. goto ErrorExit;
  199. }
  200. pscCtx->dwReaderCount = cRdrs;
  201. }
  202. ZeroMemory(pscCtx->rgReaderStates, cRdrs * sizeof(SCARD_READERSTATEW));
  203. pscCtx->dwActiveReaderCount = cRdrs;
  204. //
  205. // Fill in the state array.
  206. //
  207. cRdrs = 0;
  208. for (szRdr = pscCtx->mszReaders; 0 != *szRdr; szRdr += lstrlenW(szRdr) + 1)
  209. {
  210. pscCtx->rgReaderStates[cRdrs].szReader = szRdr;
  211. pscCtx->rgReaderStates[cRdrs].dwCurrentState = SCARD_STATE_UNAWARE;
  212. cRdrs += 1;
  213. }
  214. dwErr = SCardGetStatusChangeW(
  215. pscCtx->hCtx,
  216. 0,
  217. pscCtx->rgReaderStates,
  218. cRdrs);
  219. if (SCARD_S_SUCCESS != dwErr)
  220. goto ErrorExit;
  221. //
  222. // We're all set for EnumInsertedCard calls.
  223. // Count the number of readers with cards, and return.
  224. //
  225. for (dwIndex = 0; dwIndex < cRdrs; dwIndex += 1)
  226. {
  227. if (0 != (
  228. SCARD_STATE_PRESENT
  229. & pscCtx->rgReaderStates[dwIndex].dwEventState))
  230. dwCount += 1;
  231. }
  232. pscCtx->dwEnumIndex = 0;
  233. *ppvHandle = pscCtx;
  234. if (0 == dwCount)
  235. SetLastError(SCARD_S_SUCCESS);
  236. return dwCount;
  237. //
  238. // An error has occurred. Clean up to the last known good state.
  239. //
  240. ErrorExit:
  241. if ((NULL == *ppvHandle) && (NULL != pscCtx))
  242. {
  243. if (NULL != pscCtx->mszReaders)
  244. {
  245. SCardFreeMemory(pscCtx->hCtx, pscCtx->mszReaders);
  246. pscCtx->mszReaders = NULL;
  247. }
  248. if (NULL != pscCtx->hCtx)
  249. SCardReleaseContext(pscCtx->hCtx);
  250. if (NULL != pscCtx->rgReaderStates)
  251. LocalFree(pscCtx->rgReaderStates);
  252. LocalFree(pscCtx);
  253. }
  254. return 0;
  255. }
  256. /*++
  257. EnumInsertedCards:
  258. This routine is designed to be called repeatedly after first calling the
  259. ScanReaders service. It will repeatedly return information about cards
  260. available for use against CryptoAPI, until all cards have been returned.
  261. Arguments:
  262. pvHandle supplies the context handle in use.
  263. szCryptoProvider is a buffer to receive the name of the Cryptographic
  264. Service Provider associated with the card in the reader.
  265. cchCryptoProvider supplies the length of the szCryptoProvider buffer, in
  266. characters. If this length is not sufficient to hold the name of the
  267. provider, the routine returns FALSE, and GetLastError will return
  268. SCARD_E_INSUFFICIENT_BUFFER.
  269. pdwProviderType receives the type of the smart card provider (this will be
  270. PROV_RSA_FULL for all known smart card CSPs).
  271. pszReaderName receives a pointer to the name of the reader being returned.
  272. Return Value:
  273. TRUE - The output variables have been set to the next available card.
  274. FALSE - There are no more cards to be returned, or some other error has
  275. occurred, per the value available from GetLastError.
  276. Remarks:
  277. The list of cards can be reset using the ScanReaders service.
  278. Author:
  279. Doug Barlow (dbarlow) 11/12/1998
  280. --*/
  281. BOOL
  282. EnumInsertedCards(
  283. IN LPVOID pvHandle,
  284. OUT LPWSTR szCryptoProvider,
  285. IN DWORD cchCryptoProvider,
  286. OUT LPDWORD pdwProviderType,
  287. OUT LPCWSTR *pszReaderName)
  288. {
  289. DWORD dwIndex;
  290. DWORD dwSts;
  291. LPWSTR mszCards = NULL;
  292. DWORD dwLength;
  293. scEnlistContext *pscCtx = (scEnlistContext *)pvHandle;
  294. //
  295. // Run through the remaining readers and see what's left to report.
  296. //
  297. for (dwIndex = pscCtx->dwEnumIndex;
  298. dwIndex < pscCtx->dwActiveReaderCount;
  299. dwIndex += 1)
  300. {
  301. if ( (0 != ( SCARD_STATE_PRESENT
  302. & pscCtx->rgReaderStates[dwIndex].dwEventState))
  303. && (0 == ( SCARD_STATE_MUTE
  304. & pscCtx->rgReaderStates[dwIndex].dwEventState)))
  305. {
  306. //
  307. // This card is active. Try to map it to a CSP.
  308. //
  309. dwLength = SCARD_AUTOALLOCATE;
  310. dwSts = SCardListCardsW(
  311. pscCtx->hCtx,
  312. pscCtx->rgReaderStates[dwIndex].rgbAtr,
  313. NULL,
  314. 0,
  315. (LPWSTR)&mszCards,
  316. &dwLength);
  317. if (SCARD_S_SUCCESS != dwSts)
  318. {
  319. //
  320. // Probably an unregistered card type. Keep looking.
  321. //
  322. goto NextCard;
  323. }
  324. //
  325. // We just use the first returned card name. We don't
  326. // have a mechanism to declare, "same card, next provider"
  327. // yet. Since there are no cards that have this problem
  328. // that we know of, we'll limp along for now.
  329. //
  330. //
  331. // Map the card name to a CSP.
  332. //
  333. dwLength = cchCryptoProvider;
  334. dwSts = SCardGetCardTypeProviderNameW(
  335. pscCtx->hCtx,
  336. mszCards,
  337. SCARD_PROVIDER_CSP,
  338. szCryptoProvider,
  339. &dwLength);
  340. if (SCARD_S_SUCCESS != dwSts)
  341. {
  342. //
  343. // Probably no mapping. Keep looking.
  344. //
  345. goto NextCard;
  346. }
  347. //
  348. // At this point, we've found a card and mapped it to it's
  349. // CSP Name.
  350. //
  351. //
  352. // It would be nice to map the CSP Name to a CSP Type.
  353. // For now, they're all PROV_RSA_FULL.
  354. //
  355. *pdwProviderType = PROV_RSA_FULL;
  356. //
  357. // Return what we know to the caller, saving state for the
  358. // next time through.
  359. //
  360. SCardFreeMemory(pscCtx->hCtx, mszCards);
  361. mszCards = NULL;
  362. pscCtx->dwEnumIndex = dwIndex + 1;
  363. *pszReaderName = pscCtx->rgReaderStates[dwIndex].szReader;
  364. return TRUE;
  365. }
  366. //
  367. // The current card was rejected. Do any clean up, and move on to
  368. // the next card.
  369. //
  370. NextCard:
  371. if (NULL != mszCards)
  372. {
  373. SCardFreeMemory(pscCtx->hCtx, mszCards);
  374. mszCards = NULL;
  375. }
  376. }
  377. //
  378. // We fell out the bottom of the loop. This means we didn't find any
  379. // more readers with cards inserted. Report that we're done for this
  380. // scan.
  381. //
  382. pscCtx->dwEnumIndex = pscCtx->dwActiveReaderCount;
  383. SetLastError(SCARD_S_SUCCESS);
  384. return FALSE;
  385. }
  386. /*++
  387. EndReaderScan:
  388. This routine is used to clean up internal memory used by other services
  389. in this module.
  390. Arguments:
  391. ppvHandle supplies a pointer to an LPVOID being used by this and associated
  392. routines to maintain an internal context. Associated memory will be
  393. freed, and the value reset to NULL.
  394. Return Value:
  395. None
  396. Remarks:
  397. ?Remarks?
  398. Author:
  399. Doug Barlow (dbarlow) 11/12/1998
  400. --*/
  401. void
  402. EndReaderScan(
  403. LPVOID *ppvHandle)
  404. {
  405. scEnlistContext *pscCtx = *(scEnlistContext **)ppvHandle;
  406. if (NULL != pscCtx)
  407. {
  408. if (NULL != pscCtx->mszReaders)
  409. {
  410. SCardFreeMemory(pscCtx->hCtx, pscCtx->mszReaders);
  411. pscCtx->mszReaders = NULL;
  412. }
  413. if (NULL != pscCtx->hCtx)
  414. SCardReleaseContext(pscCtx->hCtx);
  415. if (NULL != pscCtx->rgReaderStates)
  416. LocalFree(pscCtx->rgReaderStates);
  417. LocalFree(pscCtx);
  418. *ppvHandle = NULL;
  419. }
  420. }