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.

690 lines
16 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. ResMgrSt
  5. Abstract:
  6. This file contains the implementation of threads that monitor
  7. the status of the smart card resource manager, and notify the
  8. application when that state has changed via callbacks.
  9. Author:
  10. Amanda Matlosz 03/18/1998
  11. Environment:
  12. Win32, C++ w/Exceptions, MFC
  13. Revision History:
  14. 5/28/98 AMatlosz Previously, this thread just watched for the RM to move
  15. from a 'down' state to an 'up' state. Now it keeps on
  16. eye on the state to make up for the fact that the other
  17. two threads who previously monitored status must shut
  18. themselves down if the RM is up but there are no readers
  19. available.
  20. 10/28/98 AMatlosz Added thread to watch for new readers.
  21. Notes:
  22. --*/
  23. /////////////////////////////////////////////////////////////////////////////
  24. //
  25. // Includes
  26. //
  27. #include "stdafx.h"
  28. #include <winsvc.h>
  29. #include <winscard.h>
  30. #include <calaislb.h>
  31. #include <scEvents.h>
  32. #include "SCAlert.h"
  33. #include "ResMgrSt.h"
  34. #include "miscdef.h"
  35. ////////////////////////////////////////////////////////////////////////////
  36. //
  37. // Globals
  38. //
  39. #ifdef _DEBUG
  40. #define new DEBUG_NEW
  41. #undef THIS_FILE
  42. static char THIS_FILE[] = __FILE__;
  43. #endif
  44. /////////////////////////////////////////////////////////////////////////////////////
  45. //
  46. // CResMgrStatusThrd
  47. //
  48. IMPLEMENT_DYNCREATE(CResMgrStatusThrd, CWinThread)
  49. /*++
  50. InitInstance
  51. Must override init instance to do the loop
  52. Arguments:
  53. Return Value:
  54. TRUE on build start message loop. FALSE otherwise
  55. Notes:
  56. This thread uses two callbacks to inform the caller of its status:
  57. WM_SCARD_RESMGR_STATUS -- WPARAM is bool indicating RM status: true == up
  58. WM_SCARD_RESMGR_EXIT -- indicates thread has been shut down or is shutting
  59. down.
  60. --*/
  61. BOOL CResMgrStatusThrd::InitInstance(void)
  62. {
  63. SC_HANDLE schService = NULL;
  64. SC_HANDLE schSCManager = NULL;
  65. SERVICE_STATUS ssStatus; // current status of the service
  66. DWORD dwSts;
  67. DWORD dwReturn = ERROR_SUCCESS;
  68. //
  69. // Take a short break, then ping the service manager to see if the resource
  70. // manager is running. If not, wait a long time for it to start. Repeat
  71. // until the thread has been asked to die.
  72. //
  73. BOOL fContinue = TRUE;
  74. while (fContinue)
  75. {
  76. try
  77. {
  78. if (NULL == schSCManager)
  79. {
  80. schSCManager = OpenSCManager(
  81. NULL, // machine (NULL == local)
  82. NULL, // database (NULL == default)
  83. SC_MANAGER_CONNECT); // access required
  84. if (NULL == schSCManager)
  85. throw (DWORD)GetLastError();
  86. }
  87. if (NULL == schService)
  88. {
  89. schService = OpenService(
  90. schSCManager,
  91. TEXT("SCardSvr"),
  92. SERVICE_QUERY_STATUS);
  93. if (NULL == schService)
  94. throw (DWORD)GetLastError();
  95. }
  96. if (!QueryServiceStatus(schService, &ssStatus))
  97. throw (DWORD)GetLastError();
  98. switch (ssStatus.dwCurrentState)
  99. {
  100. case SERVICE_CONTINUE_PENDING:
  101. case SERVICE_PAUSE_PENDING:
  102. case SERVICE_PAUSED:
  103. continue;
  104. break;
  105. case SERVICE_START_PENDING:
  106. case SERVICE_STOP_PENDING:
  107. case SERVICE_STOPPED:
  108. dwReturn = SCARD_E_NO_SERVICE;
  109. break;
  110. case SERVICE_RUNNING:
  111. dwReturn = SCARD_S_SUCCESS;
  112. break;
  113. default:
  114. throw (DWORD)SCARD_F_INTERNAL_ERROR;
  115. }
  116. }
  117. catch (DWORD dwErr)
  118. {
  119. _ASSERTE(FALSE); // For debugging.
  120. if (NULL != schService)
  121. {
  122. CloseServiceHandle(schService);
  123. schService = NULL;
  124. }
  125. if (NULL != schSCManager)
  126. {
  127. CloseServiceHandle(schSCManager);
  128. schSCManager = NULL;
  129. }
  130. dwReturn = dwErr;
  131. }
  132. catch (...)
  133. {
  134. _ASSERTE(FALSE); // For debugging.
  135. if (NULL != schService)
  136. {
  137. CloseServiceHandle(schService);
  138. schService = NULL;
  139. }
  140. if (NULL != schSCManager)
  141. {
  142. CloseServiceHandle(schSCManager);
  143. schSCManager = NULL;
  144. }
  145. dwReturn = ERROR_INVALID_PARAMETER;
  146. }
  147. if (SCARD_S_SUCCESS == dwReturn)
  148. {
  149. // say it's UP!
  150. ::PostMessage(m_hCallbackWnd,
  151. WM_SCARD_RESMGR_STATUS,
  152. TRUE,
  153. 0);
  154. }
  155. else
  156. {
  157. // say it's DOWN!
  158. ::PostMessage(m_hCallbackWnd,
  159. WM_SCARD_RESMGR_STATUS,
  160. FALSE,
  161. 0);
  162. }
  163. //
  164. // Wait for ~30 seconds, continuing on Start or timeout
  165. // and stopping immediately if the stop event is signaled
  166. //
  167. HANDLE rgHandle[2];
  168. int nHandle = 2;
  169. rgHandle[0] = CalaisAccessStartedEvent();
  170. rgHandle[1] = m_hKillThrd;
  171. dwSts = WaitForMultipleObjects(
  172. nHandle,
  173. rgHandle,
  174. FALSE,
  175. 300000);
  176. if (WAIT_OBJECT_0 != dwSts && WAIT_TIMEOUT != dwSts)
  177. {
  178. fContinue = FALSE;
  179. }
  180. CalaisReleaseStartedEvent();
  181. }
  182. //
  183. // Clean up & let our caller know that we're shutting down.
  184. //
  185. if (NULL != schService)
  186. {
  187. CloseServiceHandle(schService);
  188. schService = NULL;
  189. }
  190. if (NULL != schSCManager)
  191. {
  192. CloseServiceHandle(schSCManager);
  193. schSCManager = NULL;
  194. }
  195. CalaisReleaseStartedEvent();
  196. if (NULL != m_hCallbackWnd)
  197. {
  198. ::PostMessage(m_hCallbackWnd,
  199. WM_SCARD_RESMGR_EXIT,
  200. 0, 0);
  201. }
  202. AfxEndThread(0);
  203. return TRUE; // to make compiler happy
  204. }
  205. /////////////////////////////////////////////////////////////////////////////////////
  206. //
  207. // CRemovalOptionsThrd
  208. //
  209. IMPLEMENT_DYNCREATE(CRemovalOptionsThrd, CWinThread)
  210. /*++
  211. InitInstance
  212. Must override init instance to do the loop
  213. Arguments:
  214. Return Value:
  215. TRUE on build start message loop. FALSE otherwise
  216. Notes:
  217. This thread uses one message to inform the caller of a change in
  218. the user's removal options:
  219. WM_SCARD_REMOPT_CHNG -- re-query smart card removal options
  220. --*/
  221. BOOL CRemovalOptionsThrd::InitInstance(void)
  222. {
  223. DWORD dwSts = WAIT_FAILED;
  224. LONG lResult = ERROR_SUCCESS;
  225. BOOL fContinue = TRUE;
  226. int nHandle = 2;
  227. HANDLE rgHandle[2] = {NULL, NULL};
  228. rgHandle[1] = m_hKillThrd;
  229. HKEY hKey = NULL;
  230. while (fContinue)
  231. {
  232. // open regkey
  233. lResult = RegOpenKeyEx(
  234. HKEY_LOCAL_MACHINE,
  235. szScRemoveOptionKey,
  236. 0,
  237. KEY_ALL_ACCESS,
  238. &hKey);
  239. if (ERROR_SUCCESS != lResult)
  240. {
  241. goto ErrorExit;
  242. }
  243. // reset/create event
  244. if (NULL != rgHandle[0])
  245. {
  246. if (!ResetEvent(rgHandle[0]))
  247. {
  248. CloseHandle(rgHandle[0]);
  249. rgHandle[0] = NULL;
  250. }
  251. }
  252. if (NULL == rgHandle[0])
  253. {
  254. rgHandle[0] = CreateEvent(
  255. NULL,
  256. TRUE, // must call ResetEvent() to set non-signaled
  257. FALSE, // not signaled when it starts
  258. NULL);
  259. if (NULL == rgHandle[0])
  260. {
  261. // give up!
  262. goto ErrorExit;
  263. }
  264. }
  265. lResult = RegNotifyChangeKeyValue(
  266. hKey,
  267. TRUE,
  268. REG_NOTIFY_CHANGE_LAST_SET,
  269. rgHandle[0],
  270. TRUE);
  271. if (ERROR_SUCCESS != lResult)
  272. {
  273. goto ErrorExit;
  274. }
  275. dwSts = WaitForMultipleObjects(
  276. nHandle,
  277. rgHandle,
  278. FALSE,
  279. INFINITE);
  280. if (WAIT_OBJECT_0 == dwSts)
  281. {
  282. // announce the change
  283. ::PostMessage(m_hCallbackWnd,
  284. WM_SCARD_REMOPT_CHNG,
  285. 0, 0);
  286. }
  287. else if (WAIT_OBJECT_0+1 == dwSts || WAIT_FAILED == dwSts)
  288. {
  289. // Time for thread to quit
  290. fContinue = FALSE;
  291. }
  292. else
  293. {
  294. _ASSERTE(WAIT_TIMEOUT == dwSts);
  295. }
  296. }
  297. //
  298. // Clean up & let our caller know that we're shutting down.
  299. //
  300. ErrorExit:
  301. if (NULL != hKey)
  302. {
  303. RegCloseKey(hKey);
  304. }
  305. if (NULL != rgHandle[0])
  306. {
  307. CloseHandle(rgHandle[0]);
  308. }
  309. if (NULL != m_hCallbackWnd)
  310. {
  311. // announce thread's exit
  312. ::PostMessage(m_hCallbackWnd,
  313. WM_SCARD_REMOPT_EXIT,
  314. 0, 0);
  315. }
  316. AfxEndThread(0);
  317. return TRUE; // to make compiler happy
  318. }
  319. /////////////////////////////////////////////////////////////////////////////////////
  320. //
  321. // CNewReaderThrd
  322. //
  323. IMPLEMENT_DYNCREATE(CNewReaderThrd, CWinThread)
  324. /*++
  325. InitInstance
  326. Must override init instance to do the loop
  327. Arguments:
  328. Return Value:
  329. TRUE on build start message loop. FALSE otherwise
  330. Notes:
  331. This thread uses one callback to inform the caller of an addition to
  332. the active reader list.
  333. WM_SCARD_NEWREADER -- indicates that Calais reports a reader just added
  334. --*/
  335. BOOL CNewReaderThrd::InitInstance(void)
  336. {
  337. if (NULL == m_hCallbackWnd)
  338. {
  339. _ASSERTE(FALSE);
  340. return TRUE; // for compiler
  341. }
  342. DWORD dwSts = 0;
  343. BOOL fContinue = TRUE;
  344. while (fContinue)
  345. {
  346. HANDLE rgHandle[2];
  347. int nHandle = 2;
  348. rgHandle[0] = CalaisAccessNewReaderEvent();
  349. rgHandle[1] = m_hKillThrd;
  350. dwSts = WaitForMultipleObjects(
  351. nHandle,
  352. rgHandle,
  353. FALSE,
  354. 300000);
  355. if (WAIT_OBJECT_0 == dwSts)
  356. {
  357. // a new reader event happened! Fire off the notice
  358. ::PostMessage(m_hCallbackWnd,
  359. WM_SCARD_NEWREADER,
  360. TRUE,
  361. 0);
  362. }
  363. else if (WAIT_OBJECT_0+1 == dwSts || WAIT_FAILED == dwSts)
  364. {
  365. // Time for thread to quit
  366. fContinue = FALSE;
  367. }
  368. else
  369. {
  370. _ASSERTE(WAIT_TIMEOUT == dwSts);
  371. }
  372. CalaisReleaseNewReaderEvent();
  373. }
  374. if (NULL != m_hCallbackWnd)
  375. {
  376. ::PostMessage(m_hCallbackWnd,
  377. WM_SCARD_NEWREADER_EXIT,
  378. 0, 0);
  379. }
  380. AfxEndThread(0);
  381. return TRUE; // to make compiler happy
  382. }
  383. /////////////////////////////////////////////////////////////////////////////////////
  384. //
  385. // CCardStatusThrd
  386. //
  387. IMPLEMENT_DYNCREATE(CCardStatusThrd, CWinThread)
  388. /*++
  389. InitInstance
  390. Must override init instance to do the loop
  391. Arguments:
  392. Return Value:
  393. TRUE on build start message loop. FALSE otherwise
  394. Notes:
  395. This thread uses one callback to inform the caller of a change in
  396. smart card status -- a card is available, no cards are available,
  397. or a card has been idle for >30 seconds.
  398. WM_SCARD_CARDSTATUS -- indicates a new card status
  399. WM_SCARD_CARDSTATUS_EXIT -- indicates imminent thread death.
  400. --*/
  401. BOOL CCardStatusThrd::InitInstance(void)
  402. {
  403. LONG lResult = SCardEstablishContext(SCARD_SCOPE_USER,NULL,NULL,&m_hCtx);
  404. if (SCARD_S_SUCCESS != lResult)
  405. {
  406. CString str;
  407. str.Format(_T("CCardStatusThrd:: SCardEstablishContext returned 0x%x."), lResult);
  408. }
  409. BOOL fContinue = TRUE;
  410. LPTSTR szReaders = NULL;
  411. LPCTSTR pchReader = NULL;
  412. DWORD dwReadersLen = SCARD_AUTOALLOCATE;
  413. SCARD_READERSTATE rgReaderStates[MAXIMUM_SMARTCARD_READERS];
  414. int nIndex = 0, nCnReaders = 0;
  415. BOOL fLogonLock = (NULL != m_pstrLogonReader && !m_pstrLogonReader->IsEmpty());
  416. lResult = SCardListReaders(
  417. m_hCtx,
  418. SCARD_ALL_READERS,
  419. (LPTSTR)&szReaders,
  420. &dwReadersLen
  421. );
  422. if(SCARD_S_SUCCESS != lResult ||
  423. (0 == dwReadersLen || NULL == szReaders || 0 == *szReaders) )
  424. {
  425. fContinue = FALSE;
  426. }
  427. if (fContinue)
  428. {
  429. // use the list of readers to build a readerstate array
  430. for (nIndex = 0, pchReader = szReaders;
  431. nIndex < MAXIMUM_SMARTCARD_READERS && 0 != *pchReader;
  432. nIndex++)
  433. {
  434. rgReaderStates[nIndex].szReader = pchReader;
  435. rgReaderStates[nIndex].dwCurrentState = SCARD_STATE_UNAWARE;
  436. pchReader += lstrlen(pchReader)+1;
  437. }
  438. nCnReaders = nIndex;
  439. }
  440. while (fContinue)
  441. {
  442. UINT uState = (UINT)k_State_NoCard;
  443. lResult = SCardGetStatusChange(
  444. m_hCtx,
  445. 10000, // IN DWORD dwTimeout (10 seconds)
  446. rgReaderStates, // IN OUT LPSCARD_READERSTATE
  447. nCnReaders // IN DWORD cReaders
  448. );
  449. // IF return is success, determine if there are any cards inserted
  450. // if YES, send a messge to notfywnd saying "card in"
  451. // if NO, send a message to notfywnd saying "no card"
  452. if (SCARD_S_SUCCESS == lResult)
  453. {
  454. // Determine if
  455. // (a) any card is present in the system and
  456. // (b) if each idle card has ceased to be idle or present
  457. BOOL fIdle = FALSE;
  458. for(nIndex=0; nIndex < nCnReaders; nIndex++)
  459. {
  460. if (rgReaderStates[nIndex].dwEventState & SCARD_STATE_PRESENT)
  461. {
  462. uState = (UINT)k_State_CardAvailable;
  463. }
  464. if (k_State_CardIdle == (UINT_PTR)(rgReaderStates[nIndex].pvUserData))
  465. {
  466. if ( !(rgReaderStates[nIndex].dwEventState & SCARD_STATE_PRESENT) ||
  467. (rgReaderStates[nIndex].dwEventState & SCARD_STATE_INUSE) )
  468. {
  469. rgReaderStates[nIndex].pvUserData = NULL;
  470. }
  471. else
  472. {
  473. fIdle = TRUE;
  474. }
  475. }
  476. rgReaderStates[nIndex].dwCurrentState = rgReaderStates[nIndex].dwEventState;
  477. }
  478. if (fIdle) uState = k_State_CardIdle;
  479. }
  480. // IF return indicates timeout, determine if any cards are idle.
  481. else if (SCARD_E_TIMEOUT == lResult)
  482. {
  483. BOOL fIdle = FALSE;
  484. // is there an idle card?
  485. for(nIndex=0; nIndex < nCnReaders; nIndex++)
  486. {
  487. if (rgReaderStates[nIndex].dwEventState & SCARD_STATE_PRESENT)
  488. {
  489. uState = k_State_CardAvailable;
  490. if (!(rgReaderStates[nIndex].dwEventState & SCARD_STATE_INUSE))
  491. {
  492. // card used for logon & logoff or lock is not considered idle
  493. if (!fLogonLock ||
  494. 0 != m_pstrLogonReader->Compare(rgReaderStates[nIndex].szReader))
  495. {
  496. rgReaderStates[nIndex].pvUserData = ULongToPtr(k_State_CardIdle);
  497. fIdle = TRUE;
  498. }
  499. }
  500. rgReaderStates[nIndex].dwCurrentState = rgReaderStates[nIndex].dwEventState;
  501. }
  502. }
  503. // there's an overdue idle card! Fire off the notification.
  504. if (fIdle) uState = k_State_CardIdle;
  505. }
  506. else
  507. {
  508. fContinue = FALSE;
  509. }
  510. // update list of readers w/idle cards
  511. m_csLock.Lock();
  512. {
  513. m_paIdleList->RemoveAll();
  514. for(nIndex=0; nIndex < nCnReaders; nIndex++)
  515. {
  516. if (k_State_CardIdle == (UINT_PTR)rgReaderStates[nIndex].pvUserData)
  517. {
  518. m_paIdleList->Add(rgReaderStates[nIndex].szReader);
  519. }
  520. }
  521. }
  522. m_csLock.Unlock();
  523. // inform caller
  524. if (NULL != m_hCallbackWnd)
  525. {
  526. ::PostMessage(m_hCallbackWnd,
  527. WM_SCARD_CARDSTATUS,
  528. uState,
  529. 0);
  530. }
  531. }
  532. if (NULL != m_hCallbackWnd)
  533. {
  534. ::PostMessage(m_hCallbackWnd,
  535. WM_SCARD_CARDSTATUS_EXIT,
  536. 0, 0);
  537. }
  538. AfxEndThread(0);
  539. return TRUE; // to make compiler happy
  540. }
  541. void CCardStatusThrd::CopyIdleList(CStringArray* paStr)
  542. {
  543. if (NULL == paStr)
  544. {
  545. return;
  546. }
  547. m_csLock.Lock();
  548. {
  549. paStr->Copy(*m_paIdleList);
  550. }
  551. m_csLock.Unlock();
  552. }