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.

1278 lines
35 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1999 - 1999
  3. Module Name:
  4. PropCert
  5. Abstract:
  6. This module initiates smart card cert propagation to 'My' store.
  7. It is loaded and started by winlogon through an entry in the registry.
  8. Author:
  9. Klaus Schutz
  10. --*/
  11. #include "stdafx.h"
  12. #include <wincrypt.h>
  13. #include <winscard.h>
  14. #include <winwlx.h>
  15. #include "calaislb.h"
  16. #include "scrdcert.h" // smart card cert store
  17. #include "certprop.h"
  18. #include "StatMon.h" // smart card reader status monitor
  19. #include "scevents.h"
  20. #include <mmsystem.h>
  21. #ifndef SCARD_PROVIDER_CSP
  22. #define SCARD_PROVIDER_CSP 2
  23. #endif
  24. #define REG_KEY "Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify\\ScCertProp"
  25. static THREADDATA l_ThreadData;
  26. #ifdef _DEBUG
  27. #define new DEBUG_NEW
  28. #undef THIS_FILE
  29. static char THIS_FILE[] = __FILE__;
  30. #endif
  31. #if defined(DBG) || defined(DEBUG)
  32. BOOL Debug = TRUE;
  33. #define DebugPrint(a) _DebugPrint a
  34. void
  35. __cdecl
  36. _DebugPrint(
  37. LPCTSTR szFormat,
  38. ...
  39. )
  40. {
  41. if (Debug) {
  42. TCHAR szBuffer[512];
  43. va_list ap;
  44. va_start(ap, szFormat);
  45. _vstprintf(szBuffer, szFormat, ap);
  46. OutputDebugString(szBuffer);
  47. }
  48. }
  49. #else
  50. #define DebugPrint(a)
  51. #endif
  52. LPCTSTR
  53. FirstString(
  54. IN LPCTSTR szMultiString
  55. )
  56. /*++
  57. FirstString:
  58. This routine returns a pointer to the first string in a multistring, or NULL
  59. if there aren't any.
  60. Arguments:
  61. szMultiString - This supplies the address of the current position within a
  62. Multi-string structure.
  63. Return Value:
  64. The address of the first null-terminated string in the structure, or NULL if
  65. there are no strings.
  66. Author:
  67. Doug Barlow (dbarlow) 11/25/1996
  68. --*/
  69. {
  70. LPCTSTR szFirst = NULL;
  71. try
  72. {
  73. if (0 != *szMultiString)
  74. szFirst = szMultiString;
  75. }
  76. catch (...) {}
  77. return szFirst;
  78. }
  79. LPCTSTR
  80. NextString(
  81. IN LPCTSTR szMultiString)
  82. /*++
  83. NextString:
  84. In some cases, the Smartcard API returns multiple strings, separated by Null
  85. characters, and terminated by two null characters in a row. This routine
  86. simplifies access to such structures. Given the current string in a
  87. multi-string structure, it returns the next string, or NULL if no other
  88. strings follow the current string.
  89. Arguments:
  90. szMultiString - This supplies the address of the current position within a
  91. Multi-string structure.
  92. Return Value:
  93. The address of the next Null-terminated string in the structure, or NULL if
  94. no more strings follow.
  95. Author:
  96. Doug Barlow (dbarlow) 8/12/1996
  97. --*/
  98. {
  99. LPCTSTR szNext;
  100. try
  101. {
  102. DWORD cchLen = lstrlen(szMultiString);
  103. if (0 == cchLen)
  104. szNext = NULL;
  105. else
  106. {
  107. szNext = szMultiString + cchLen + 1;
  108. if (0 == *szNext)
  109. szNext = NULL;
  110. }
  111. }
  112. catch (...)
  113. {
  114. szNext = NULL;
  115. }
  116. return szNext;
  117. }
  118. /*++
  119. MoveToUnicodeString:
  120. This routine moves the internal string representation to a UNICODE output
  121. buffer.
  122. Arguments:
  123. szDst receives the output string. It must be sufficiently large enough to
  124. handle the string. If this parameter is NULL, then the number of
  125. characters required to hold the result is returned.
  126. szSrc supplies the input string.
  127. cchLength supplies the length of the input string, with or without trailing
  128. nulls. A -1 value implies the length should be computed based on a
  129. trailing null.
  130. Return Value:
  131. The length of the resultant string, in characters, including the trailing
  132. null.
  133. Throws:
  134. Errors as DWORD status codes.
  135. Author:
  136. Doug Barlow (dbarlow) 2/14/1997
  137. --*/
  138. DWORD
  139. MoveToUnicodeString(
  140. LPWSTR szDst,
  141. LPCTSTR szSrc,
  142. DWORD cchLength)
  143. {
  144. if ((DWORD)(-1) == cchLength)
  145. cchLength = lstrlen(szSrc);
  146. else
  147. {
  148. while ((0 < cchLength) && (0 == szSrc[cchLength - 1]))
  149. cchLength -= 1;
  150. }
  151. #ifndef UNICODE
  152. if (0 == *szSrc)
  153. cchLength = 1;
  154. else if (NULL == szDst)
  155. {
  156. cchLength =
  157. MultiByteToWideChar(
  158. GetACP(),
  159. MB_PRECOMPOSED | MB_USEGLYPHCHARS,
  160. szSrc,
  161. cchLength,
  162. NULL,
  163. 0);
  164. if (0 == cchLength)
  165. throw GetLastError();
  166. cchLength += 1;
  167. }
  168. else
  169. {
  170. cchLength =
  171. MultiByteToWideChar(
  172. GetACP(),
  173. MB_PRECOMPOSED | MB_USEGLYPHCHARS,
  174. szSrc,
  175. cchLength,
  176. szDst,
  177. cchLength);
  178. if (0 == cchLength)
  179. throw GetLastError();
  180. szDst[cchLength++] = 0;
  181. }
  182. #else
  183. cchLength += 1;
  184. if (NULL != szDst)
  185. CopyMemory(szDst, szSrc, cchLength * sizeof(TCHAR));
  186. #endif
  187. return cchLength;
  188. }
  189. void
  190. StopMonitorReaders(
  191. THREADDATA *ThreadData
  192. )
  193. {
  194. DWORD dwRet;
  195. _ASSERT(ThreadData != NULL);
  196. SetEvent(ThreadData->hClose);
  197. if (ThreadData->hSCardContext) {
  198. SCardCancel(ThreadData->hSCardContext);
  199. }
  200. }
  201. DWORD
  202. WINAPI
  203. StartMonitorReaders(
  204. LPVOID lpParameter
  205. )
  206. {
  207. LPCTSTR szCardHandled = "KS";
  208. LPCTSTR newPnPReader = SCPNP_NOTIFICATION;
  209. THREADDATA *ThreadData = (THREADDATA *) lpParameter;
  210. HANDLE hCalaisStarted = NULL;
  211. HANDLE lHandles[2];
  212. //
  213. // We use this outer loop to restart in case the
  214. // resource manager was stopped
  215. //
  216. while (WaitForSingleObject(ThreadData->hClose, 0) == WAIT_TIMEOUT) {
  217. // Acquire context with resource manager
  218. LONG lReturn = SCardEstablishContext(
  219. SCARD_SCOPE_SYSTEM,
  220. NULL,
  221. NULL,
  222. &ThreadData->hSCardContext
  223. );
  224. if (SCARD_S_SUCCESS != lReturn) {
  225. if (SCARD_E_NO_SERVICE == lReturn) {
  226. // SCRM not started yet. Give it a chance
  227. hCalaisStarted = CalaisAccessStartedEvent();
  228. if (hCalaisStarted == NULL) {
  229. // no way to recover
  230. break;
  231. }
  232. lHandles[0] = hCalaisStarted;
  233. lHandles[1] = ThreadData->hClose;
  234. lReturn = WaitForMultipleObjectsEx(
  235. 2,
  236. lHandles,
  237. FALSE,
  238. 120 * 1000, // only couple minutes
  239. FALSE
  240. );
  241. if (lReturn != WAIT_OBJECT_0) {
  242. // We stop if an error occured or if the user logs out
  243. break;
  244. }
  245. // Otherwise the resource manager has started
  246. DebugPrint(("ScCertProp: Smart card resource manager started\n"));
  247. continue;
  248. }
  249. // The prev. call should never fail
  250. // It's better to termninate this thread.
  251. break;
  252. }
  253. LPCTSTR szReaderName = NULL;
  254. DWORD dwAutoAllocate = SCARD_AUTOALLOCATE;
  255. // now list the available readers
  256. lReturn = SCardListReaders(
  257. ThreadData->hSCardContext,
  258. SCARD_DEFAULT_READERS,
  259. (LPTSTR)&szReaderName,
  260. &dwAutoAllocate
  261. );
  262. SCARD_READERSTATE rgReaders[MAXIMUM_SMARTCARD_READERS + 1];
  263. // First, make sure the array is totally zeroed.
  264. ZeroMemory((LPVOID) rgReaders, sizeof(rgReaders));
  265. // add the 'new pnp reader has arrived' reader
  266. rgReaders[0].szReader = newPnPReader;
  267. rgReaders[0].dwCurrentState = 0;
  268. DWORD dwNumReaders = 1;
  269. // And build a bare-bones readerstatearray IFF there are any readers
  270. if (SCARD_S_SUCCESS == lReturn)
  271. {
  272. szReaderName = FirstString( szReaderName );
  273. while (NULL != szReaderName &&
  274. dwNumReaders < MAXIMUM_SMARTCARD_READERS + 1) {
  275. DebugPrint(
  276. ("ScCertProp: Found reader: '%s'\n",
  277. szReaderName)
  278. );
  279. rgReaders[dwNumReaders].szReader = (LPCTSTR) szReaderName;
  280. rgReaders[dwNumReaders].dwCurrentState = SCARD_STATE_EMPTY;
  281. szReaderName = NextString(szReaderName);
  282. dwNumReaders++;
  283. }
  284. }
  285. if (SCARD_S_SUCCESS != lReturn) {
  286. DebugPrint(("ScCertProp: No readers found. Waiting for new reader arrival...\n"));
  287. //
  288. // We now will call SCardGetStatusChange which
  289. // will return upon new reader arrival
  290. //
  291. }
  292. BOOL fNewReader = FALSE;
  293. // analyze newly inserted cards and prop certs as necessary
  294. while (WaitForSingleObject(ThreadData->hClose, 0) == WAIT_TIMEOUT &&
  295. fNewReader == FALSE) {
  296. //
  297. // Wait for a change in the system status before continuing; quit if an error occurred
  298. //
  299. lReturn = SCardGetStatusChange(
  300. ThreadData->hSCardContext,
  301. INFINITE,
  302. rgReaders,
  303. dwNumReaders
  304. );
  305. #ifdef DEBUG_VERBOSE
  306. DebugPrint(
  307. ("ScCertProp: SCardGetStatusChange returned %lx\n",
  308. lReturn)
  309. );
  310. #endif
  311. if (SCARD_E_SYSTEM_CANCELLED == lReturn) {
  312. DebugPrint(("ScCertProp: Smart card resource manager stopped\n"));
  313. // Clean up
  314. if (NULL != szReaderName)
  315. {
  316. SCardFreeMemory(ThreadData->hSCardContext, (PVOID)szReaderName);
  317. szReaderName = NULL;
  318. }
  319. if (NULL != ThreadData->hSCardContext)
  320. {
  321. SCardReleaseContext(ThreadData->hSCardContext);
  322. ThreadData->hSCardContext = NULL;
  323. }
  324. //
  325. // The resource manager has been stopped.
  326. // Wait until it restarted or until the user logs out
  327. //
  328. hCalaisStarted = CalaisAccessStartedEvent();
  329. if (hCalaisStarted == NULL) {
  330. // no way to recover. stop cert prop
  331. StopMonitorReaders(ThreadData);
  332. break;
  333. }
  334. lHandles[0] = hCalaisStarted;
  335. lHandles[1] = ThreadData->hClose;
  336. lReturn = WaitForMultipleObjectsEx(
  337. 2,
  338. lHandles,
  339. FALSE,
  340. INFINITE,
  341. FALSE
  342. );
  343. if (lReturn != WAIT_OBJECT_0) {
  344. // We stop if an error occured or if the user logs out
  345. StopMonitorReaders(ThreadData);
  346. break;
  347. }
  348. // Otherwise the resource manager has been restarted
  349. DebugPrint(("ScCertProp: Smart card resource manager re-started\n"));
  350. break;
  351. }
  352. if (SCARD_S_SUCCESS != lReturn)
  353. {
  354. if (SCARD_E_CANCELLED != lReturn)
  355. StopMonitorReaders(ThreadData);
  356. break;
  357. }
  358. #ifdef DEBUG_VERBOSE
  359. DebugPrint(
  360. ("ScCertProp: Reader(PnP) state %lx/%lx\n",
  361. rgReaders[0].dwCurrentState,
  362. rgReaders[0].dwEventState)
  363. );
  364. #endif
  365. // check if a new reader showed up
  366. if ((dwNumReaders == 1 || rgReaders[0].dwCurrentState != 0) &&
  367. rgReaders[0].dwEventState & SCARD_STATE_CHANGED) {
  368. DebugPrint(("ScCertProp: New reader reported...\n"));
  369. fNewReader = TRUE;
  370. break;
  371. }
  372. rgReaders[0].dwCurrentState = rgReaders[0].dwEventState;
  373. //
  374. // Enumerate the readers and for every recognized card that's been
  375. // inserted and has an associated CSP, get a cert (if there is one)
  376. // off the default container and prop it to the 'My' store
  377. //
  378. for (DWORD dwIndex = 1; dwIndex < dwNumReaders; dwIndex++)
  379. {
  380. #ifdef DEBUG_VERBOSE
  381. DebugPrint(
  382. ("ScCertProp: Reader(%s) state %lx/%lx\n",
  383. rgReaders[dwIndex].szReader,
  384. rgReaders[dwIndex].dwCurrentState,
  385. rgReaders[dwIndex].dwEventState)
  386. );
  387. #endif
  388. if ((rgReaders[dwIndex].dwCurrentState & SCARD_STATE_EMPTY) &&
  389. (rgReaders[dwIndex].dwEventState & SCARD_STATE_PRESENT)) {
  390. // play sound for card insertion
  391. PlaySound(
  392. TEXT("SmartcardInsertion"),
  393. NULL,
  394. SND_ASYNC | SND_ALIAS | SND_NODEFAULT
  395. );
  396. }
  397. if ((rgReaders[dwIndex].dwCurrentState & SCARD_STATE_PRESENT) &&
  398. (rgReaders[dwIndex].dwEventState & SCARD_STATE_EMPTY)) {
  399. // play sound for card removal
  400. PlaySound(
  401. TEXT("SmartcardRemoval"),
  402. NULL,
  403. SND_ASYNC | SND_ALIAS | SND_NODEFAULT
  404. );
  405. }
  406. if ((rgReaders[dwIndex].dwCurrentState & SCARD_STATE_EMPTY) &&
  407. (rgReaders[dwIndex].dwEventState & SCARD_STATE_PRESENT) &&
  408. (rgReaders[dwIndex].dwEventState & SCARD_STATE_CHANGED) &&
  409. (rgReaders[dwIndex].pvUserData != (PVOID) szCardHandled))
  410. {
  411. // Get the name of the card
  412. LPCSTR szCardName = NULL;
  413. dwAutoAllocate = SCARD_AUTOALLOCATE;
  414. lReturn = SCardListCards(
  415. ThreadData->hSCardContext,
  416. rgReaders[dwIndex].rgbAtr,
  417. NULL,
  418. 0,
  419. (LPTSTR)&szCardName,
  420. &dwAutoAllocate
  421. );
  422. LPCSTR szCSPName = NULL;
  423. if (SCARD_S_SUCCESS == lReturn)
  424. {
  425. dwAutoAllocate = SCARD_AUTOALLOCATE;
  426. lReturn = SCardGetCardTypeProviderName(
  427. ThreadData->hSCardContext,
  428. szCardName,
  429. SCARD_PROVIDER_CSP,
  430. (LPTSTR)&szCSPName,
  431. &dwAutoAllocate
  432. );
  433. }
  434. DebugPrint(
  435. ("ScCertProp: Smart Card '%s' inserted into reader '%s'\n",
  436. (strlen(szCardName) ? szCardName : "<Unknown>"),
  437. rgReaders[dwIndex].szReader)
  438. );
  439. if (SCARD_S_SUCCESS == lReturn)
  440. {
  441. PPROPDATA PropData = (PPROPDATA) LocalAlloc(LPTR, sizeof(PROPDATA));
  442. if (PropData) {
  443. _tcscpy(PropData->szReader, rgReaders[dwIndex].szReader);
  444. _tcscpy(PropData->szCardName, szCardName);
  445. _tcscpy(PropData->szCSPName, szCSPName);
  446. PropData->hUserToken = ThreadData->hUserToken;
  447. //
  448. // Create a thread to propagate this cert.
  449. // The thread is responsible to free PropData
  450. //
  451. HANDLE hThread = CreateThread(
  452. NULL,
  453. 0,
  454. PropagateCertificates,
  455. (LPVOID) PropData,
  456. 0,
  457. NULL
  458. );
  459. if (hThread == NULL) {
  460. LocalFree(PropData);
  461. }
  462. else {
  463. CloseHandle(hThread);
  464. }
  465. }
  466. }
  467. //
  468. // Clean up
  469. //
  470. if (NULL != szCSPName)
  471. {
  472. SCardFreeMemory(ThreadData->hSCardContext, (PVOID)szCSPName);
  473. szCSPName = NULL;
  474. }
  475. if (NULL != szCardName)
  476. {
  477. SCardFreeMemory(ThreadData->hSCardContext, (PVOID)szCardName);
  478. szCardName = NULL;
  479. }
  480. // Record that we're done with this card
  481. rgReaders[dwIndex].pvUserData = (PVOID) szCardHandled;
  482. }
  483. else
  484. {
  485. // there's no card to handle in this reader; reset pvUserData
  486. rgReaders[dwIndex].pvUserData = NULL;
  487. }
  488. // Update the "current state" of this reader
  489. rgReaders[dwIndex].dwCurrentState = rgReaders[dwIndex].dwEventState;
  490. }
  491. }
  492. // Clean up
  493. if (NULL != szReaderName)
  494. {
  495. SCardFreeMemory(ThreadData->hSCardContext, (PVOID)szReaderName);
  496. szReaderName = NULL;
  497. }
  498. if (NULL != ThreadData->hSCardContext)
  499. {
  500. SCardReleaseContext(ThreadData->hSCardContext);
  501. ThreadData->hSCardContext = NULL;
  502. }
  503. }
  504. return TRUE;
  505. }
  506. DWORD
  507. WINAPI
  508. PropagateCertificates(
  509. LPVOID lpParameter
  510. )
  511. /*++
  512. Routine Description:
  513. This function propagates the cert of a card.
  514. It runs as a seperate thread
  515. --*/
  516. {
  517. PPROPDATA PropData = (PPROPDATA) lpParameter;
  518. BOOL fSts = FALSE;
  519. long lErr = 0;
  520. DWORD dwIndex = 0;
  521. DWORD cbContainerName = 0;
  522. LPSTR szContainerName = NULL;
  523. LPWSTR lpwszContainerName = NULL;
  524. LPWSTR lpwszCSPName = NULL;
  525. LPWSTR lpwszCardName = NULL;
  526. LPSTR lpszContainerName = NULL;
  527. DWORD dwCertLen = 0;
  528. LPBYTE pbCert = NULL;
  529. CRYPT_KEY_PROV_INFO keyProvInfo;
  530. HCERTSTORE hCertStore = NULL;
  531. HCRYPTKEY hKey = NULL;
  532. HCRYPTPROV hCryptProv = NULL;
  533. LPCTSTR szCSPName = PropData->szCSPName;
  534. LPCTSTR szCardName = PropData->szCardName;
  535. static const DWORD rgdwKeys[] = { AT_KEYEXCHANGE , AT_SIGNATURE };
  536. static const DWORD cdwKeys = sizeof(rgdwKeys) / sizeof(DWORD);
  537. #if defined(DBG) || defined(DEBUG)
  538. time_t start = time(NULL);
  539. #endif
  540. lpszContainerName = (LPSTR) LocalAlloc(
  541. LPTR,
  542. strlen(PropData->szReader) + 10
  543. );
  544. if (lpszContainerName == NULL) {
  545. lErr = NTE_NO_MEMORY;
  546. goto ErrorExit;
  547. }
  548. sprintf(lpszContainerName, "\\\\.\\%s\\", PropData->szReader);
  549. fSts = CryptAcquireContext(
  550. &hCryptProv,
  551. lpszContainerName,
  552. PropData->szCSPName,
  553. PROV_RSA_FULL,
  554. CRYPT_SILENT
  555. );
  556. DebugPrint(
  557. ("ScCertProp(%s): CryptAcquireContext took %ld seconds to return %lx\n",
  558. PropData->szCardName,
  559. (time(NULL) - start),
  560. GetLastError())
  561. );
  562. LocalFree(lpszContainerName);
  563. if (fSts == FALSE) {
  564. lErr = GetLastError();
  565. goto ErrorExit;
  566. }
  567. // the following struct is always empty, for I_CryptAddSmartCardCertToStore
  568. CRYPT_DATA_BLOB scCryptData;
  569. memset(&scCryptData, 0, sizeof(CRYPT_DATA_BLOB));
  570. //
  571. // Get the default container name, so we can use it
  572. //
  573. fSts = CryptGetProvParam(
  574. hCryptProv,
  575. PP_CONTAINER,
  576. NULL,
  577. &cbContainerName,
  578. 0
  579. );
  580. if (!fSts)
  581. {
  582. lErr = GetLastError();
  583. goto ErrorExit;
  584. }
  585. szContainerName = (LPSTR) LocalAlloc(LPTR, cbContainerName);
  586. if (NULL == szContainerName)
  587. {
  588. lErr = NTE_NO_MEMORY;
  589. goto ErrorExit;
  590. }
  591. fSts = CryptGetProvParam(
  592. hCryptProv,
  593. PP_CONTAINER,
  594. (PBYTE)szContainerName,
  595. &cbContainerName,
  596. 0
  597. );
  598. if (!fSts)
  599. {
  600. lErr = GetLastError();
  601. goto ErrorExit;
  602. }
  603. //
  604. // Prepare the key prov info that's generic to all keysets
  605. //
  606. lpwszContainerName = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (lstrlen(szContainerName) + 1));
  607. lpwszCSPName = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (lstrlen(szCSPName) + 1));
  608. lpwszCardName = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (lstrlen(szCardName) + 1));
  609. if ((NULL == lpwszCSPName) || (NULL == lpwszCardName) || (NULL == lpwszContainerName))
  610. {
  611. lErr = NTE_NO_MEMORY;
  612. goto ErrorExit;
  613. }
  614. MoveToUnicodeString(lpwszContainerName, szContainerName, lstrlen(szContainerName) + 1);
  615. MoveToUnicodeString(lpwszCSPName, szCSPName, lstrlen(szCSPName) + 1);
  616. MoveToUnicodeString(lpwszCardName, szCardName, lstrlen(szCardName) + 1);
  617. memset(&keyProvInfo, 0, sizeof(CRYPT_KEY_PROV_INFO));
  618. keyProvInfo.pwszContainerName = lpwszContainerName;
  619. keyProvInfo.pwszProvName = lpwszCSPName;
  620. keyProvInfo.dwProvType = PROV_RSA_FULL;
  621. keyProvInfo.dwFlags = 0;
  622. keyProvInfo.cProvParam = 0;
  623. keyProvInfo.rgProvParam = NULL;
  624. //
  625. // For each keyset in this container, get the cert and make
  626. // a cert context, then prop the cert to the My store
  627. //
  628. for (dwIndex = 0; dwIndex < cdwKeys; dwIndex += 1)
  629. {
  630. try
  631. {
  632. //
  633. // Note which key we're working with and get the key handle.
  634. //
  635. keyProvInfo.dwKeySpec = rgdwKeys[dwIndex];
  636. fSts = CryptGetUserKey(
  637. hCryptProv,
  638. rgdwKeys[dwIndex],
  639. &hKey
  640. );
  641. if (!fSts)
  642. {
  643. lErr = GetLastError();
  644. if (NTE_NO_KEY != lErr)
  645. {
  646. throw lErr;
  647. }
  648. }
  649. //
  650. // Upload the certificate & prep CertData blob
  651. //
  652. if (fSts)
  653. {
  654. fSts = CryptGetKeyParam(
  655. hKey,
  656. KP_CERTIFICATE,
  657. NULL,
  658. &dwCertLen,
  659. 0
  660. );
  661. if (!fSts)
  662. {
  663. lErr = GetLastError();
  664. if (ERROR_MORE_DATA == lErr)
  665. {
  666. // There's a certificate -- this means SUCCESS!
  667. fSts = TRUE;
  668. }
  669. //
  670. // otherwise, there may be a key but no cert
  671. // this just means that there's nothing to do.
  672. //
  673. }
  674. }
  675. if (!fSts) {
  676. DebugPrint(
  677. ("ScCertProp(%s): No %s certificate on card\n",
  678. PropData->szCardName,
  679. (dwIndex == 0 ? "key exchange" : "signature"))
  680. );
  681. }
  682. if (fSts)
  683. {
  684. pbCert = (LPBYTE) LocalAlloc(LPTR, dwCertLen);
  685. if (NULL == pbCert)
  686. {
  687. throw ERROR_OUTOFMEMORY;
  688. }
  689. fSts = CryptGetKeyParam(
  690. hKey,
  691. KP_CERTIFICATE,
  692. pbCert,
  693. &dwCertLen,
  694. 0
  695. );
  696. if (!fSts)
  697. {
  698. throw (long) GetLastError();
  699. }
  700. }
  701. if (fSts)
  702. {
  703. CRYPT_DATA_BLOB cdbCertData;
  704. cdbCertData.cbData = dwCertLen;
  705. cdbCertData.pbData = pbCert;
  706. if (PropData->hUserToken && !ImpersonateLoggedOnUser( PropData->hUserToken )) {
  707. DebugPrint(("ScCertProp: ImpersonateLoggedOnUser failed\n"));
  708. throw (long) GetLastError();
  709. }
  710. try
  711. {
  712. //
  713. // Open the MyStore -- and add the cert if it's not there
  714. //
  715. hCertStore = CertOpenStore(
  716. CERT_STORE_PROV_SYSTEM_W, // "My store"
  717. 0, // not applicable
  718. hCryptProv,
  719. CERT_STORE_NO_CRYPT_RELEASE_FLAG |
  720. CERT_SYSTEM_STORE_CURRENT_USER,
  721. L"MY"
  722. );
  723. if (NULL == hCertStore)
  724. {
  725. throw((long)GetLastError());
  726. }
  727. // is the cert already there?
  728. SMART_CARD_CERT_FIND_DATA sccfd;
  729. memset(&sccfd, 0, sizeof(SMART_CARD_CERT_FIND_DATA));
  730. sccfd.cbSize = sizeof(SMART_CARD_CERT_FIND_DATA);
  731. sccfd.pwszProvider = keyProvInfo.pwszProvName;
  732. sccfd.dwProviderType = keyProvInfo.dwProvType;
  733. sccfd.pwszContainer = keyProvInfo.pwszContainerName;
  734. sccfd.dwKeySpec = keyProvInfo.dwKeySpec;
  735. PCCERT_CONTEXT pCCtx = NULL;
  736. pCCtx = I_CryptFindSmartCardCertInStore (
  737. hCertStore,
  738. pCCtx,
  739. &sccfd,
  740. NULL
  741. );
  742. BOOL fSame = FALSE;
  743. if (pCCtx != NULL)
  744. {
  745. if ((pCCtx->cbCertEncoded == dwCertLen) &&
  746. (memcmp(pCCtx->pbCertEncoded, pbCert, dwCertLen) == 0))
  747. {
  748. fSame = TRUE;
  749. }
  750. CertFreeCertificateContext(pCCtx);
  751. pCCtx = NULL;
  752. DebugPrint(
  753. ("ScCertProp(%s): %s certificate already in store\n",
  754. PropData->szCardName,
  755. (dwIndex == 0 ? "Key exchange" : "Signature"))
  756. );
  757. fSts = TRUE;
  758. }
  759. if (!fSame)
  760. {
  761. // this by default does "replace existing"
  762. fSts = I_CryptAddSmartCardCertToStore(
  763. hCertStore,
  764. &cdbCertData,
  765. NULL,
  766. &scCryptData,
  767. &keyProvInfo
  768. );
  769. DebugPrint(
  770. ("ScCertProp(%s): %s certificate %s propagated\n",
  771. PropData->szCardName,
  772. (dwIndex == 0 ? "Key exchange" : "Signature"),
  773. (fSts ? "successfully" : "NOT"))
  774. );
  775. }
  776. if (NULL != hCertStore)
  777. {
  778. CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
  779. hCertStore = NULL;
  780. }
  781. if (!fSts)
  782. {
  783. throw((long) GetLastError());
  784. }
  785. RevertToSelf();
  786. }
  787. catch(...)
  788. {
  789. RevertToSelf();
  790. throw;
  791. }
  792. }
  793. }
  794. catch (...)
  795. {
  796. }
  797. // clean up each time around...
  798. if (NULL != hKey)
  799. {
  800. CryptDestroyKey(hKey);
  801. hKey = NULL;
  802. }
  803. if (NULL != pbCert)
  804. {
  805. LocalFree(pbCert);
  806. pbCert = NULL;
  807. dwCertLen = 0;
  808. }
  809. }
  810. ErrorExit:
  811. if (NULL != szContainerName)
  812. {
  813. LocalFree(szContainerName);
  814. }
  815. if (NULL != lpwszContainerName)
  816. {
  817. LocalFree(lpwszContainerName);
  818. }
  819. if (NULL != lpwszCSPName)
  820. {
  821. LocalFree(lpwszCSPName);
  822. }
  823. if (NULL != lpwszCardName)
  824. {
  825. LocalFree(lpwszCardName);
  826. }
  827. if (NULL != pbCert)
  828. {
  829. LocalFree(pbCert);
  830. }
  831. if (NULL != hKey)
  832. {
  833. CryptDestroyKey(hKey);
  834. }
  835. if (NULL != hCryptProv)
  836. {
  837. CryptReleaseContext(hCryptProv, 0);
  838. }
  839. DebugPrint(
  840. ("ScCertProp(%s): Certificate propagation took %ld seconds\n",
  841. PropData->szCardName,
  842. (time(NULL) - start))
  843. );
  844. LocalFree(PropData);
  845. return ERROR_SUCCESS;
  846. }
  847. DWORD WINAPI
  848. SCardStartCertProp(
  849. LPVOID lpvParam
  850. )
  851. /*++
  852. Routine Description:
  853. Starts cert. propagation after the user logged on.
  854. --*/
  855. {
  856. PWLX_NOTIFICATION_INFO User = (PWLX_NOTIFICATION_INFO) lpvParam;
  857. HKEY hKey;
  858. DWORD fEnabled = TRUE;
  859. //
  860. // First check if cert. prop. is enabled.
  861. //
  862. if (RegOpenKey(
  863. HKEY_LOCAL_MACHINE,
  864. REG_KEY,
  865. &hKey) == ERROR_SUCCESS) {
  866. ULONG uBufferLen = sizeof(fEnabled);
  867. DWORD dwKeyType;
  868. RegQueryValueEx(
  869. hKey,
  870. "Enabled",
  871. NULL,
  872. &dwKeyType,
  873. (PUCHAR) &fEnabled,
  874. &uBufferLen);
  875. RegCloseKey(hKey);
  876. }
  877. if (FALSE == fEnabled) {
  878. DebugPrint(("ScCertProp: Smart card certificate propagation is disabled\n"));
  879. return ERROR_SUCCESS;
  880. }
  881. __try {
  882. if(User) {
  883. l_ThreadData.hUserToken = User->hToken;
  884. }
  885. l_ThreadData.hClose = CreateEvent(
  886. NULL,
  887. TRUE,
  888. FALSE,
  889. NULL
  890. );
  891. if (l_ThreadData.hClose == NULL) {
  892. __leave;
  893. }
  894. l_ThreadData.hThread = CreateThread(
  895. NULL,
  896. 0,
  897. StartMonitorReaders,
  898. (LPVOID) &l_ThreadData,
  899. CREATE_SUSPENDED,
  900. NULL
  901. );
  902. if (l_ThreadData.hThread == NULL) {
  903. CloseHandle(l_ThreadData.hClose);
  904. __leave;
  905. }
  906. l_ThreadData.fSuspended = FALSE; // was initially suspended, not anymore
  907. ResumeThread(l_ThreadData.hThread);
  908. DebugPrint(("ScCertProp: Smart card certificate propagation started\n"));
  909. }
  910. __finally {
  911. }
  912. return ERROR_SUCCESS;
  913. }
  914. DWORD WINAPI
  915. SCardStopCertProp(
  916. LPVOID lpvParam
  917. )
  918. /*++
  919. Routine Description:
  920. Stops cert. propagation when the user logs out.
  921. Arguments:
  922. lpvParam - Winlogon notification info.
  923. --*/
  924. {
  925. UNREFERENCED_PARAMETER(lpvParam);
  926. if(NULL != l_ThreadData.hThread)
  927. {
  928. DWORD dwStatus;
  929. // If the user that unlocks the workstation is different from the one
  930. // that locked it, Logoff occurs without an Unlock, thus the thread is
  931. // still suspended. This should take care of it.
  932. if (l_ThreadData.fSuspended)
  933. {
  934. ResumeThread(l_ThreadData.hThread);
  935. l_ThreadData.fSuspended = FALSE;
  936. }
  937. StopMonitorReaders(&l_ThreadData);
  938. dwStatus = WaitForSingleObject(
  939. l_ThreadData.hThread,
  940. INFINITE
  941. );
  942. _ASSERT(dwStatus == WAIT_OBJECT_0);
  943. CloseHandle(l_ThreadData.hClose);
  944. l_ThreadData.hClose = NULL;
  945. CloseHandle(l_ThreadData.hThread);
  946. l_ThreadData.hThread = NULL;
  947. DebugPrint(("ScCertProp: Smart card certificate propagation stopped\n"));
  948. }
  949. return ERROR_SUCCESS;
  950. }
  951. DWORD WINAPI
  952. SCardSuspendCertProp(
  953. LPVOID lpvParam
  954. )
  955. /*++
  956. Routine Description:
  957. Suspens cert. propagation when the workstation will be locked
  958. Arguments:
  959. lpvParam - Winlogon notification info.
  960. --*/
  961. {
  962. UNREFERENCED_PARAMETER(lpvParam);
  963. // The suspended flag should take care of the following scenario:
  964. // Winlogon generates lock notification each time the locked dialog appears
  965. // (vs. only once when the wks is locked) and the thread would get suspended
  966. // amny times. This happens when the screen saver is kicking on & off while
  967. // the wks is locked (Bug 105852)
  968. if ((NULL != l_ThreadData.hThread) && (!l_ThreadData.fSuspended)){
  969. SuspendThread(l_ThreadData.hThread);
  970. l_ThreadData.fSuspended = TRUE;
  971. DebugPrint(("ScCertProp: Smart card certificate propagation suspended\n"));
  972. }
  973. return ERROR_SUCCESS;
  974. }
  975. DWORD WINAPI
  976. SCardResumeCertProp(
  977. LPVOID lpvParam
  978. )
  979. /*++
  980. Routine Description:
  981. Resumes cert. propagation after unlocking the workstation
  982. Arguments:
  983. lpvParam - Winlogon notification info.
  984. --*/
  985. {
  986. UNREFERENCED_PARAMETER(lpvParam);
  987. if (NULL != l_ThreadData.hThread) {
  988. ResumeThread(l_ThreadData.hThread);
  989. l_ThreadData.fSuspended = FALSE;
  990. DebugPrint(("ScCertProp: Smart card certificate propagation resumed\n"));
  991. }
  992. return ERROR_SUCCESS;
  993. }
  994. DWORD WINAPI
  995. SCardEnableCertProp(
  996. BOOL On
  997. )
  998. /*++
  999. Routine Description:
  1000. Allows cert. propagation to be turned off/on
  1001. Arguments:
  1002. On - TRUE turn on, else off
  1003. --*/
  1004. {
  1005. HKEY l_hKey;
  1006. LONG l_lResult;
  1007. if ((l_lResult = RegOpenKey(
  1008. HKEY_LOCAL_MACHINE,
  1009. REG_KEY,
  1010. &l_hKey)) == ERROR_SUCCESS) {
  1011. l_lResult = RegSetValueEx(
  1012. l_hKey,
  1013. "Enabled",
  1014. 0,
  1015. REG_DWORD,
  1016. (PUCHAR) &On,
  1017. sizeof(DWORD)
  1018. );
  1019. RegCloseKey(l_hKey);
  1020. }
  1021. return l_lResult;
  1022. }
  1023. #ifdef test
  1024. __cdecl
  1025. main(
  1026. int argc,
  1027. char ** argv
  1028. )
  1029. {
  1030. EnableScCertProp(TRUE);
  1031. StartScCertProp(NULL);
  1032. getchar();
  1033. StopScCertProp(&l_ThreadData);
  1034. return 0;
  1035. }
  1036. #endif