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.

580 lines
15 KiB

  1. #include <windows.h>
  2. #include <winscard.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <guiddef.h>
  7. #include "basecsp.h"
  8. #include "pincache.h"
  9. #include "helpers.h"
  10. extern HINSTANCE ghInstance;
  11. PCARD_DATA pCardData = NULL;
  12. SCARDCONTEXT hSCardContext = 0;
  13. // global array to hold the provider name
  14. WCHAR gszProvider[MAX_PATH];
  15. #ifdef DBG
  16. #define ERROUT(x) ShowError(x)
  17. #else
  18. #define ERROUT(x)
  19. #endif
  20. void ShowError(DWORD dwErr)
  21. {
  22. WCHAR sz[200];
  23. swprintf(sz,L"Returned status %x\n",dwErr);
  24. OutputDebugString(sz);
  25. }
  26. void DoConvertWideStringToLowerCase(WCHAR *pwsz)
  27. {
  28. WCHAR c;
  29. if (NULL == pwsz) return;
  30. while (NULL != (c = *pwsz))
  31. {
  32. *pwsz++= towlower(c);
  33. }
  34. }
  35. // Accept an input buffer containing text, and convert it to binary
  36. // The binary buffer is allocated new and must be freed by the caller
  37. //
  38. // The incoming data consists of hex digits and spaces. Hex digits are
  39. // assembled into bytes as pairs, with the first digit becoming the
  40. // most significant nybble. Spaces in input are discarded with no effect
  41. // so that "12 34 5" becomes 0x12 0x34 0x5, as soes "1 2 3 4 5."
  42. DWORD DoConvertBufferToBinary(BYTE *pIn, DWORD dwcbIn,
  43. BYTE **pOut, DWORD *dwcbOut)
  44. {
  45. WCHAR szTemp[10];
  46. WCHAR *pInput = (WCHAR *) pIn;
  47. BYTE *pAlloc = NULL;
  48. BYTE *pOutput = NULL;
  49. DWORD dwOut = 0;
  50. DWORD dwRet = -1;
  51. BOOL fInabyte = FALSE;
  52. BOOL fErr = FALSE;
  53. BYTE b;
  54. BYTE b2;
  55. WCHAR c;
  56. // Bag it if no data or output ptrs obviously invalid
  57. if ((NULL == pIn) || (dwcbIn == 0)) goto Ret;
  58. if ((NULL == pOut) || (NULL == dwcbOut)) goto Ret;
  59. // count input characters
  60. int iLen = wcslen(pInput);
  61. if (iLen == 0) goto Ret;
  62. // guaranteed to contain the output
  63. pAlloc = (BYTE *)CspAllocH((iLen / 2) + 2);
  64. pOutput = pAlloc;
  65. for (int i = 0;i<iLen;i++)
  66. {
  67. c = pInput[i];
  68. if (c == 0) break;
  69. // skip over whitespace in the input
  70. c = towupper(c);
  71. if (c <= L' ')
  72. {
  73. fInabyte = FALSE;
  74. continue;
  75. }
  76. if (!fInabyte)
  77. {
  78. b = 0;
  79. }
  80. b2 = 0;
  81. // error on not legal hex character
  82. if ( ((c < L'0') || (c > L'F')) ||
  83. ((c > L'9') && (c < L'A')) )
  84. {
  85. dwRet = -1;
  86. *pOut = 0;
  87. *dwcbOut = 0;
  88. if (pAlloc) CspFreeH(pAlloc);
  89. goto Ret;
  90. }
  91. else if (c <= L'9')
  92. b2 = c - L'0';
  93. else
  94. b2 = c - L'A' + 10;
  95. if (fInabyte)
  96. {
  97. b = (b << 4) + b2;
  98. fInabyte = FALSE;
  99. dwOut += 1;
  100. *pOutput++ = b;
  101. }
  102. else
  103. {
  104. b = b2;
  105. fInabyte = TRUE;
  106. }
  107. }
  108. // Permit writing an unpaired terminating hex character to the tail of the binary as a 0x byte.
  109. if (fInabyte)
  110. {
  111. fInabyte = FALSE;
  112. dwOut += 1;
  113. *pOutput++ = b;
  114. }
  115. dwRet = 0;
  116. *pOut = pAlloc;
  117. *dwcbOut = dwOut;
  118. Ret:
  119. ERROUT(dwRet);
  120. return dwRet;
  121. }
  122. DWORD DoConvertBinaryToBuffer(BYTE *pIn, DWORD dwcbIn,
  123. BYTE **pOut, DWORD *dwcbOut)
  124. {
  125. WCHAR *pAlloc = NULL;
  126. WCHAR *pOutput = NULL;
  127. DWORD dwOut = 0;
  128. DWORD dwRet = -1;
  129. BOOL fErr = FALSE;
  130. BYTE b;
  131. // Bag it if no data or output ptrs obviously invalid
  132. if ((NULL == pIn) || (dwcbIn == 0)) goto Ret;
  133. if ((NULL == pOut) || (NULL == dwcbOut)) goto Ret;
  134. pAlloc = (WCHAR *)CspAllocH(((dwcbIn * 3) + 1) * sizeof(WCHAR));
  135. if (NULL == pAlloc) goto Ret;
  136. pOutput = pAlloc;
  137. for (DWORD i = 0 ; i<dwcbIn ; i++)
  138. {
  139. b = pIn[i];
  140. b &= 0xf0;
  141. b = b>> 4;
  142. b += L'0';
  143. if (b > L'9') b += 7;
  144. *pOutput++ = b;
  145. b = pIn[i];
  146. b &= 0x0f;
  147. b += L'0';
  148. if (b > L'9') b += 7;
  149. *pOutput++ = b;
  150. dwOut += 2;
  151. // a space every 4 characters
  152. if ((i > 0) && (((i+1) % 2) == 0)) *pOutput++ = L' ';
  153. }
  154. *pOutput = 0;
  155. dwRet = 0;
  156. *pOut = (BYTE *) pAlloc;
  157. *dwcbOut = (pOutput - pAlloc -1) * sizeof(WCHAR);
  158. Ret:
  159. ERROUT(dwRet);
  160. return dwRet;
  161. }
  162. //
  163. // Find any card present in an attached reader using "minimal" scarddlg UI
  164. //
  165. DWORD GetCardHandleViaUI(
  166. IN SCARDCONTEXT hSCardContext,
  167. OUT SCARDHANDLE *phSCardHandle,
  168. IN DWORD cchMatchedCard,
  169. OUT LPWSTR wszMatchedCard,
  170. IN DWORD cchMatchedReader,
  171. OUT LPWSTR wszMatchedReader)
  172. {
  173. OPENCARDNAME_EXW ocnx;
  174. DWORD dwSts = ERROR_SUCCESS;
  175. memset(&ocnx, 0, sizeof(ocnx));
  176. ocnx.dwStructSize = sizeof(ocnx);
  177. ocnx.hSCardContext = hSCardContext;
  178. ocnx.lpstrCard = wszMatchedCard;
  179. ocnx.nMaxCard = cchMatchedCard;
  180. ocnx.lpstrRdr = wszMatchedReader;
  181. ocnx.nMaxRdr = cchMatchedReader;
  182. ocnx.dwShareMode = SCARD_SHARE_SHARED;
  183. ocnx.dwPreferredProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
  184. ocnx.dwFlags = SC_DLG_MINIMAL_UI;
  185. dwSts = SCardUIDlgSelectCardW(&ocnx);
  186. *phSCardHandle = ocnx.hCardHandle;
  187. return dwSts;
  188. }
  189. // Acquire a context for the target smart card
  190. DWORD DoAcquireCardContext(void)
  191. {
  192. DWORD dwSts = ERROR_SUCCESS;
  193. PFN_CARD_ACQUIRE_CONTEXT pfnCardAcquireContext = NULL;
  194. SCARDHANDLE hSCardHandle = 0;
  195. LPWSTR mszReaders = NULL;
  196. DWORD cchReaders = SCARD_AUTOALLOCATE;
  197. LPWSTR mszCards = NULL;
  198. DWORD cchCards = SCARD_AUTOALLOCATE;
  199. DWORD dwActiveProtocol = 0;
  200. DWORD dwState = 0;
  201. BYTE rgbAtr [32];
  202. DWORD cbAtr = sizeof(rgbAtr);
  203. LPWSTR pszProvider = NULL;
  204. DWORD cchProvider = SCARD_AUTOALLOCATE;
  205. HMODULE hMod = 0;
  206. WCHAR wszMatchedCard[MAX_PATH];
  207. WCHAR wszMatchedReader[MAX_PATH];
  208. HMODULE hThis = (HMODULE) ghInstance; // this executable
  209. memset(rgbAtr, 0, sizeof(rgbAtr));
  210. //
  211. // Initialization
  212. //
  213. dwSts = SCardEstablishContext(
  214. SCARD_SCOPE_USER, NULL, NULL, &hSCardContext);
  215. if (FAILED(dwSts))
  216. goto Ret;
  217. dwSts = GetCardHandleViaUI(
  218. hSCardContext,
  219. &hSCardHandle,
  220. MAX_PATH,
  221. wszMatchedCard,
  222. MAX_PATH,
  223. wszMatchedReader);
  224. if (FAILED(dwSts))
  225. goto Ret;
  226. mszReaders = NULL;
  227. cchReaders = SCARD_AUTOALLOCATE;
  228. dwSts = SCardStatusW(
  229. hSCardHandle,
  230. (LPWSTR) (&mszReaders),
  231. &cchReaders,
  232. &dwState,
  233. &dwActiveProtocol,
  234. rgbAtr,
  235. &cbAtr);
  236. if (FAILED(dwSts))
  237. goto Ret;
  238. dwSts = SCardListCardsW(
  239. hSCardContext,
  240. rgbAtr,
  241. NULL,
  242. 0,
  243. (LPWSTR) (&mszCards),
  244. &cchCards);
  245. if (FAILED(dwSts))
  246. goto Ret;
  247. dwSts = SCardGetCardTypeProviderNameW(
  248. hSCardContext,
  249. mszCards,
  250. SCARD_PROVIDER_CARD_MODULE,
  251. (LPWSTR) (&pszProvider),
  252. &cchProvider);
  253. if (FAILED(dwSts))
  254. goto Ret;
  255. // Load the card module for the selected card
  256. // acquire context and trade initializations
  257. hMod = LoadLibraryW(pszProvider);
  258. if (INVALID_HANDLE_VALUE == hMod)
  259. {
  260. dwSts = GetLastError();
  261. goto Ret;
  262. }
  263. // This fails for an unsupported card type (no card module)
  264. pfnCardAcquireContext =
  265. (PFN_CARD_ACQUIRE_CONTEXT) GetProcAddress(
  266. hMod,
  267. "CardAcquireContext");
  268. if (NULL == pfnCardAcquireContext)
  269. {
  270. dwSts = GetLastError();
  271. goto Ret;
  272. }
  273. pCardData = (PCARD_DATA) CspAllocH(sizeof(CARD_DATA));
  274. if (NULL == pCardData)
  275. {
  276. dwSts = ERROR_NOT_ENOUGH_MEMORY;
  277. goto Ret;
  278. }
  279. memset(pCardData,0,sizeof(CARD_DATA));
  280. pCardData->pbAtr = rgbAtr;
  281. pCardData->cbAtr = cbAtr;
  282. pCardData->pwszCardName = mszCards;
  283. pCardData->dwVersion = CARD_DATA_CURRENT_VERSION;
  284. pCardData->pfnCspAlloc = CspAllocH;
  285. pCardData->pfnCspReAlloc = CspReAllocH;
  286. pCardData->pfnCspFree = CspFreeH;
  287. pCardData->pfnCspCacheAddFile = CspCacheAddFile;
  288. pCardData->pfnCspCacheDeleteFile = CspCacheDeleteFile;
  289. pCardData->pfnCspCacheLookupFile = CspCacheLookupFile;
  290. pCardData->hScard = hSCardHandle;
  291. hSCardHandle = 0;
  292. // First, connect to the card
  293. dwSts = pfnCardAcquireContext(pCardData, 0);
  294. Ret:
  295. if (FAILED(dwSts))
  296. {
  297. CspFreeH(pCardData);
  298. }
  299. ERROUT(dwSts);
  300. return dwSts;
  301. }
  302. void DoLeaveCardContext(void)
  303. {
  304. if (pCardData)
  305. {
  306. if (pCardData->hScard)
  307. SCardDisconnect(pCardData->hScard,SCARD_RESET_CARD);
  308. CspFreeH(pCardData);
  309. }
  310. if (hSCardContext)
  311. SCardReleaseContext(hSCardContext);
  312. }
  313. // Get the CardID, returned in a new allocation as an SZ string. It must be freed by the
  314. // user. Is returned NULL on error.
  315. DWORD DoGetCardId(
  316. WCHAR **pSz)
  317. {
  318. DWORD dwSts = ERROR_SUCCESS;
  319. WCHAR *pString = NULL;
  320. GUID *pGuid;
  321. DWORD ccGuid = 0;
  322. dwSts = pCardData->pfnCardReadFile(pCardData,
  323. wszCARD_IDENTIFIER_FILE_FULL_PATH,
  324. 0,
  325. (PBYTE *) &pGuid,
  326. &ccGuid);
  327. if (ERROR_SUCCESS != dwSts)
  328. goto Ret;
  329. pString = (WCHAR *) CspAllocH(40 * sizeof(WCHAR));
  330. if (pString == NULL)
  331. {
  332. *pSz = NULL;
  333. dwSts = -1;
  334. goto Ret;
  335. }
  336. DWORD ccSz = 40;
  337. _snwprintf(pString, ccSz,L"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
  338. // first copy...
  339. pGuid->Data1, pGuid->Data2, pGuid->Data3,
  340. pGuid->Data4[0], pGuid->Data4[1], pGuid->Data4[2], pGuid->Data4[3],
  341. pGuid->Data4[4], pGuid->Data4[5], pGuid->Data4[6], pGuid->Data4[7]);
  342. *pSz = pString;
  343. Ret:
  344. return dwSts;
  345. }
  346. // Get a challenge buffer from the card. Render it as upper case BASE 64, and return it as a
  347. // string to the caller
  348. /*
  349. DWORD WINAPI CardChangePin(
  350. IN CARD_DATA *pCardData,
  351. IN LPWSTR pwszUserId,
  352. IN BYTE *pbCurrentAuthenticator,
  353. IN DWORD dwcbCurrentAuthenticator,
  354. IN BYTE *pbNewAuthenticator,
  355. IN DWORD dwcbNewAuthenticator,
  356. IN DWORD dwcRetryCount,
  357. IN DWORD dwFlags,
  358. OUT OPTIONAL DWORD *pdwcAttemptsRemaining
  359. );
  360. */
  361. DWORD DoInvalidatePinCache(
  362. void)
  363. {
  364. DWORD dwSts = ERROR_SUCCESS;
  365. DATA_BLOB dbCacheFile;
  366. CARD_CACHE_FILE_FORMAT *pCache = NULL;
  367. memset(&dbCacheFile, 0, sizeof(dbCacheFile));
  368. dwSts = pCardData->pfnCardReadFile(
  369. pCardData,
  370. wszCACHE_FILE_FULL_PATH,
  371. 0,
  372. &dbCacheFile.pbData,
  373. &dbCacheFile.cbData);
  374. if (ERROR_SUCCESS != dwSts)
  375. goto Ret;
  376. if (sizeof(CARD_CACHE_FILE_FORMAT) != dbCacheFile.cbData)
  377. {
  378. dwSts = ERROR_BAD_LENGTH;
  379. goto Ret;
  380. }
  381. // We have the cache file contents at dbCacheFile.pbData
  382. // Update the PinsFreshness value, and write it back
  383. pCache = (CARD_CACHE_FILE_FORMAT *) dbCacheFile.pbData;
  384. BYTE bPinFreshness = pCache->bPinsFreshness;
  385. pCache->bPinsFreshness = bPinFreshness + 1;
  386. dwSts = pCardData->pfnCardWriteFile(
  387. pCardData,
  388. wszCACHE_FILE_FULL_PATH,
  389. 0,
  390. dbCacheFile.pbData,
  391. dbCacheFile.cbData);
  392. if (ERROR_SUCCESS != dwSts)
  393. goto Ret;
  394. Ret:
  395. if (dbCacheFile.pbData)
  396. CspFreeH(dbCacheFile.pbData);
  397. return dwSts;
  398. }
  399. DWORD DoChangePin(WCHAR *pOldPin, WCHAR *pNewPin)
  400. {
  401. char AnsiOldPin[64];
  402. char AnsiNewPin[64];
  403. WCHAR szName[] = wszCARD_USER_USER;
  404. //DoConvertWideStringToLowerCase(szName);
  405. // change WCHAR PINs to ANSI
  406. WideCharToMultiByte(GetConsoleOutputCP(),
  407. 0,
  408. (WCHAR *) pOldPin,
  409. -1,
  410. AnsiOldPin,
  411. 64,
  412. NULL,
  413. NULL);
  414. WideCharToMultiByte(GetConsoleOutputCP(),
  415. 0,
  416. (WCHAR *) pNewPin,
  417. -1,
  418. AnsiNewPin,
  419. 64,
  420. NULL,
  421. NULL);
  422. DWORD dwcbOldPin = strlen(AnsiOldPin);
  423. DWORD dwcbNewPin = strlen( AnsiNewPin);
  424. if (dwcbOldPin == 0) return -1;
  425. DWORD dwSts = pCardData->pfnCardChangeAuthenticator(pCardData, szName,
  426. (BYTE *)AnsiOldPin, dwcbOldPin,
  427. (BYTE *)AnsiNewPin, dwcbNewPin,
  428. 0,
  429. NULL);
  430. ERROUT(dwSts);
  431. if (0 == dwSts) DoInvalidatePinCache();
  432. return dwSts;
  433. }
  434. // Get a challenge buffer from the card. Render it as upper case BASE 64, and return it as a
  435. // string to the caller
  436. DWORD DoGetChallenge(BYTE **pChallenge, DWORD *dwcbChallenge)
  437. {
  438. DWORD dwSts = pCardData->pfnCardGetChallenge(pCardData, pChallenge,dwcbChallenge);
  439. if (FAILED(dwSts))
  440. {
  441. dwcbChallenge = 0;
  442. return dwSts;
  443. }
  444. ERROUT(dwSts);
  445. return dwSts;
  446. }
  447. // Perform the PIN unblock, calling down to the card module, and assuming challenge-response
  448. // administrative authentication.
  449. //
  450. // The admin auth data is coming in as a case-unknown string from the user. Convert to binary,
  451. // and pass the converted blob to pfnCardUnblockPin
  452. DWORD DoCardUnblock(BYTE *pAuthData, DWORD dwcbAuthData,
  453. BYTE *pPinData, DWORD dwcbPinData)
  454. {
  455. WCHAR szName[] = wszCARD_USER_USER;
  456. //DoConvertWideStringToLowerCase(szName);
  457. // Convert the incoming buffer
  458. DWORD dwRet = pCardData->pfnCardUnblockPin(
  459. pCardData,
  460. szName,
  461. pAuthData,
  462. dwcbAuthData,
  463. pPinData,
  464. dwcbPinData,
  465. 0,
  466. CARD_UNBLOCK_PIN_CHALLENGE_RESPONSE);
  467. // this call should be unnecessary, as the unblock should deauth the admin
  468. // I can't reset the card from the card module interface, so I'll ask the user to remove
  469. // his card from the reader if deauth fails. In the real thing, I'll reset the card.
  470. pCardData->pfnCardDeauthenticate(
  471. pCardData,
  472. wszCARD_USER_USER,0);
  473. // Deallocate the buffer for the converted response
  474. ERROUT(dwRet);
  475. if (0 == dwRet) DoInvalidatePinCache();
  476. return dwRet;
  477. }