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.

2884 lines
66 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. Context
  5. Abstract:
  6. This module implements the CSCardUserContext and CSCardSubcontext classes.
  7. These classes are responsible for establishing and maintaining the
  8. connection to the Calais Server application, and for tracking the context
  9. under which related operations are performed.
  10. Author:
  11. Doug Barlow (dbarlow) 11/21/1996
  12. Environment:
  13. Win32, C++ w/ Excpetions
  14. Notes:
  15. ?Notes?
  16. --*/
  17. #define __SUBROUTINE__
  18. #ifndef WIN32_LEAN_AND_MEAN
  19. #define WIN32_LEAN_AND_MEAN
  20. #endif
  21. #include <windows.h>
  22. #include "client.h"
  23. #ifdef DBG
  24. #include <stdio.h>
  25. #endif
  26. //
  27. //==============================================================================
  28. //
  29. // CSCardUserContext
  30. //
  31. /*++
  32. CSCardUserContext:
  33. This is the default constructor for the user context.
  34. Arguments:
  35. None
  36. Return Value:
  37. None
  38. Throws:
  39. None
  40. Remarks:
  41. ?Remarks?
  42. Author:
  43. Doug Barlow (dbarlow) 4/22/1999
  44. --*/
  45. #undef __SUBROUTINE__
  46. #define __SUBROUTINE__ DBGT("CSCardUserContext::CSCardUserContext")
  47. CSCardUserContext::CSCardUserContext(
  48. IN DWORD dwScope)
  49. : m_csUsrCtxLock(CSID_USER_CONTEXT),
  50. m_hContextHeap(DBGT("User Context Heap Handle")),
  51. m_rgpSubContexts()
  52. {
  53. m_dwScope = dwScope;
  54. m_hRedirContext = NULL;
  55. }
  56. /*++
  57. CSCardUserContext::~CSCardUserContext:
  58. This is the destructor for a User Context.
  59. Arguments:
  60. None
  61. Return Value:
  62. None
  63. Throws:
  64. None
  65. Remarks:
  66. ?Remarks?
  67. Author:
  68. Doug Barlow (dbarlow) 4/22/1999
  69. --*/
  70. #undef __SUBROUTINE__
  71. #define __SUBROUTINE__ DBGT("CSCardUserContext::~CSCardUserContext")
  72. CSCardUserContext::~CSCardUserContext()
  73. {
  74. DWORD dwIndex;
  75. CSCardSubcontext *pSubCtx;
  76. LockSection(&m_csUsrCtxLock, DBGT("Destructing User Level Context"));
  77. for (dwIndex = m_rgpSubContexts.Count(); 0 < dwIndex;)
  78. {
  79. {
  80. pSubCtx = m_rgpSubContexts[--dwIndex];
  81. if (NULL != pSubCtx)
  82. m_rgpSubContexts.Set(dwIndex, NULL);
  83. }
  84. if (NULL != pSubCtx)
  85. delete pSubCtx;
  86. }
  87. m_rgpSubContexts.Empty();
  88. if (m_hContextHeap.IsValid())
  89. HeapDestroy(m_hContextHeap.Relinquish());
  90. }
  91. /*++
  92. EstablishContext:
  93. This method establishes the context by connecting to the Calais Server
  94. application.
  95. Arguments:
  96. dwScope supplies an indication of the scope of the context. Possible values
  97. are:
  98. SCARD_SCOPE_USER - The context is a user context, and any database
  99. operations are performed within the domain of the user.
  100. SCARD_SCOPE_TERMINAL - The context is that of the current terminal, and
  101. any database operations are performed within the domain of that
  102. terminal. (The calling application must have appropriate access
  103. permissions for any database actions.)
  104. SCARD_SCOPE_SYSTEM - The context is the system context, and any database
  105. operations are performed within the domain of the system. (The
  106. calling application must have appropriate access permissions for any
  107. database actions.)
  108. Return Value:
  109. None
  110. Throws:
  111. Error conditions are thrown as DWORD status codes.
  112. Author:
  113. Doug Barlow (dbarlow) 11/21/1996
  114. --*/
  115. #undef __SUBROUTINE__
  116. #define __SUBROUTINE__ DBGT("CSCardUserContext::EstablishContext")
  117. void
  118. CSCardUserContext::EstablishContext(
  119. void)
  120. {
  121. //
  122. // Make sure we can access the server.
  123. //
  124. CSCardSubcontext *pSubCtx = AcquireSubcontext();
  125. ASSERT(NULL != pSubCtx);
  126. if (NULL == pSubCtx)
  127. throw (DWORD)SCARD_E_NO_MEMORY;
  128. pSubCtx->ReleaseSubcontext();
  129. }
  130. /*++
  131. ReleaseContext:
  132. This method requests the ReleaseContext service on behalf of the client.
  133. Arguments:
  134. None
  135. Return Value:
  136. None
  137. Throws:
  138. Errors are thrown as DWORD status codes.
  139. Author:
  140. Doug Barlow (dbarlow) 12/6/1996
  141. --*/
  142. #undef __SUBROUTINE__
  143. #define __SUBROUTINE__ DBGT("CSCardUserContext::ReleaseContext")
  144. void
  145. CSCardUserContext::ReleaseContext(
  146. void)
  147. {
  148. DWORD dwIndex;
  149. CSCardSubcontext *pSubCtx;
  150. LockSection(&m_csUsrCtxLock, DBGT("Releasing subcontexts"));
  151. for (dwIndex = m_rgpSubContexts.Count(); 0 < dwIndex;)
  152. {
  153. pSubCtx = m_rgpSubContexts[--dwIndex];
  154. if (NULL != pSubCtx)
  155. {
  156. m_rgpSubContexts.Set(dwIndex, NULL);
  157. if (NULL != pSubCtx->m_hReaderHandle)
  158. {
  159. try
  160. {
  161. g_phlReaders->Close(pSubCtx->m_hReaderHandle);
  162. }
  163. catch (...) {}
  164. }
  165. try
  166. {
  167. pSubCtx->ReleaseContext();
  168. }
  169. catch (...) {}
  170. delete pSubCtx;
  171. }
  172. }
  173. }
  174. /*++
  175. ClosePipes:
  176. This method closes the pipes to SCardSvr.
  177. Arguments:
  178. None
  179. Return Value:
  180. None
  181. Throws:
  182. Errors are thrown as DWORD status codes.
  183. Author:
  184. Sermet Iskin (SermetI) 1/3/2001
  185. --*/
  186. #undef __SUBROUTINE__
  187. #define __SUBROUTINE__ DBGT("CSCardUserContext::ClosePipes")
  188. void
  189. CSCardUserContext::ClosePipes(
  190. void)
  191. {
  192. DWORD dwIndex;
  193. CSCardSubcontext *pSubCtx;
  194. LockSection(&m_csUsrCtxLock, DBGT("Closing pipes"));
  195. for (dwIndex = m_rgpSubContexts.Count(); 0 < dwIndex;)
  196. {
  197. pSubCtx = m_rgpSubContexts[--dwIndex];
  198. if (NULL != pSubCtx)
  199. {
  200. try
  201. {
  202. pSubCtx->ClosePipe();
  203. }
  204. catch (...) {}
  205. }
  206. }
  207. }
  208. /*++
  209. AllocateMemory:
  210. Allocate memory for the user through this user context.
  211. Arguments:
  212. cbLength supplies the length of the buffer to be allocated, in bytes.
  213. Return Value:
  214. The address of the allocated buffer, or NULL if an error occurred.
  215. Throws:
  216. None
  217. Remarks:
  218. ?Remarks?
  219. Author:
  220. Doug Barlow (dbarlow) 4/21/1999
  221. --*/
  222. #undef __SUBROUTINE__
  223. #define __SUBROUTINE__ DBGT("CSCardUserContext::AllocateMemory")
  224. LPVOID
  225. CSCardUserContext::AllocateMemory(
  226. DWORD cbLength)
  227. {
  228. LockSection(&m_csUsrCtxLock, DBGT("Locking memory heap"));
  229. if (!m_hContextHeap.IsValid())
  230. {
  231. m_hContextHeap = HeapCreate(0, 0, 0);
  232. if (!m_hContextHeap.IsValid())
  233. {
  234. CalaisWarning(
  235. __SUBROUTINE__,
  236. DBGT("Failed to create context heap: "),
  237. m_hContextHeap.GetLastError());
  238. goto ErrorExit;
  239. }
  240. }
  241. if (cbLength)
  242. {
  243. return HeapAlloc(
  244. m_hContextHeap,
  245. HEAP_ZERO_MEMORY,
  246. cbLength);
  247. }
  248. ErrorExit:
  249. return NULL;
  250. }
  251. /*++
  252. FreeMemory:
  253. Free memory for the user through this user context.
  254. Arguments:
  255. pvBuffer supplies the address of the previously allocated buffer.
  256. Return Value:
  257. None.
  258. Throws:
  259. None
  260. Remarks:
  261. ?Remarks?
  262. Author:
  263. Doug Barlow (dbarlow) 4/21/1999
  264. --*/
  265. #undef __SUBROUTINE__
  266. #define __SUBROUTINE__ DBGT("CSCardUserContext::FreeMemory")
  267. DWORD
  268. CSCardUserContext::FreeMemory(
  269. LPCVOID pvBuffer)
  270. {
  271. BOOL fSts;
  272. LockSection(&m_csUsrCtxLock, DBGT("Freeing heap memory"));
  273. ASSERT(m_hContextHeap.IsValid());
  274. fSts = HeapFree(m_hContextHeap, 0, (LPVOID)pvBuffer);
  275. return fSts ? ERROR_SUCCESS : GetLastError();
  276. }
  277. /*++
  278. AcquireSubcontext:
  279. A User Context manages one or more underlying subcontexts. Subcontexts
  280. exist to facilitate multiple operations simoultaneously. This method
  281. obtains a subcontext for temporary use.
  282. Arguments:
  283. None
  284. Return Value:
  285. The address of the newly created subcontext object.
  286. Throws:
  287. Errors are thrown as DWORD status codes.
  288. Remarks:
  289. Subcontexts are managed by the main context, so when the main context is
  290. closed, all the subcontexts are closed too.
  291. Author:
  292. Doug Barlow (dbarlow) 9/4/1998
  293. --*/
  294. #undef __SUBROUTINE__
  295. #define __SUBROUTINE__ DBGT("CSCardUserContext::AcquireSubcontext")
  296. CSCardSubcontext *
  297. CSCardUserContext::AcquireSubcontext(
  298. BOOL fAndAllocate)
  299. {
  300. CSCardSubcontext *pSubCtx = NULL;
  301. LockSection(&m_csUsrCtxLock, DBGT("Acquiring a subcontext"));
  302. try
  303. {
  304. DWORD dwIndex;
  305. //
  306. // See if we've got an unused subcontext laying around.
  307. //
  308. for (dwIndex = m_rgpSubContexts.Count(); 0 < dwIndex;)
  309. {
  310. pSubCtx = m_rgpSubContexts[--dwIndex];
  311. if (NULL != pSubCtx)
  312. {
  313. LockSection2(&pSubCtx->m_csSubCtxLock, DBGT("Reusing subcontext"));
  314. if (fAndAllocate)
  315. {
  316. if (CSCardSubcontext::Idle == pSubCtx->m_nInUse)
  317. {
  318. ASSERT(pSubCtx->m_hCancelEvent.IsValid());
  319. pSubCtx->Allocate();
  320. pSubCtx->SetBusy();
  321. break;
  322. }
  323. }
  324. else
  325. {
  326. if (CSCardSubcontext::Busy > pSubCtx->m_nInUse)
  327. {
  328. ASSERT(pSubCtx->m_hCancelEvent.IsValid());
  329. pSubCtx->SetBusy();
  330. break;
  331. }
  332. }
  333. pSubCtx = NULL;
  334. }
  335. }
  336. //
  337. // If not, make a new one.
  338. //
  339. if (NULL == pSubCtx)
  340. {
  341. pSubCtx = new CSCardSubcontext;
  342. if (NULL == pSubCtx)
  343. {
  344. CalaisWarning(
  345. __SUBROUTINE__,
  346. DBGT("Client can't allocate a new subcontext"));
  347. return NULL; // SCARD_E_NO_MEMORY;
  348. }
  349. if (pSubCtx->InitFailed())
  350. {
  351. delete pSubCtx;
  352. pSubCtx = NULL;
  353. return NULL; // SCARD_E_NO_MEMORY;
  354. }
  355. if (fAndAllocate)
  356. pSubCtx->Allocate();
  357. pSubCtx->SetBusy();
  358. pSubCtx->EstablishContext(m_dwScope);
  359. m_rgpSubContexts.Add(pSubCtx);
  360. pSubCtx->m_pParentCtx = this;
  361. }
  362. //
  363. // Make sure the cancel event is clear.
  364. //
  365. ASSERT(pSubCtx->m_hCancelEvent.IsValid());
  366. if (!ResetEvent(pSubCtx->m_hCancelEvent))
  367. {
  368. DWORD dwErr = GetLastError();
  369. CalaisWarning(
  370. __SUBROUTINE__,
  371. DBGT("Subcontext Allocate Failed to clear cancel event: %1"),
  372. dwErr);
  373. }
  374. //
  375. // All done. Return to caller.
  376. //
  377. ASSERT(pSubCtx->m_pParentCtx == this);
  378. }
  379. catch (...)
  380. {
  381. if (NULL != pSubCtx)
  382. {
  383. if (NULL == pSubCtx->m_pParentCtx)
  384. delete pSubCtx;
  385. else
  386. {
  387. if (fAndAllocate)
  388. pSubCtx->Deallocate();
  389. pSubCtx->ReleaseSubcontext();
  390. }
  391. }
  392. throw;
  393. }
  394. return pSubCtx;
  395. }
  396. /*++
  397. IsValidContext:
  398. This method requests the ReleaseContext service on behalf of the client.
  399. Arguments:
  400. None
  401. Return Value:
  402. None
  403. Throws:
  404. If the call cannot be completed, a DWORD status code is thrown.
  405. Remarks:
  406. If the context is determined to not be valid, it is automatically released.
  407. Author:
  408. Doug Barlow (dbarlow) 11/2/1998
  409. --*/
  410. #undef __SUBROUTINE__
  411. #define __SUBROUTINE__ DBGT("CSCardUserContext::IsValidContext")
  412. BOOL
  413. CSCardUserContext::IsValidContext(
  414. void)
  415. {
  416. DWORD dwIndex;
  417. BOOL fIsValid = TRUE;
  418. CSCardSubcontext *pSubCtx;
  419. LockSection(&m_csUsrCtxLock, DBGT("Valid context check"));
  420. for (dwIndex = m_rgpSubContexts.Count(); 0 < dwIndex;)
  421. {
  422. pSubCtx = m_rgpSubContexts[--dwIndex];
  423. if (NULL != pSubCtx)
  424. {
  425. CSCardSubcontext::State nState;
  426. {
  427. LockSection2(
  428. &pSubCtx->m_csSubCtxLock,
  429. DBGT("IsValidContext Checking validity state"));
  430. nState = pSubCtx->m_nInUse;
  431. }
  432. switch (nState)
  433. {
  434. case CSCardSubcontext::Idle:
  435. case CSCardSubcontext::Allocated:
  436. try
  437. {
  438. CSubctxLock ctxLock(pSubCtx);
  439. pSubCtx->IsValidContext();
  440. fIsValid = TRUE;
  441. }
  442. catch (...)
  443. {
  444. m_rgpSubContexts.Set(dwIndex, NULL);
  445. delete pSubCtx;
  446. fIsValid = FALSE;
  447. }
  448. break;
  449. case CSCardSubcontext::Busy:
  450. // Don't bother it.
  451. break;
  452. default:
  453. CalaisWarning(
  454. __SUBROUTINE__,
  455. DBGT("Subcontext state is invalid"));
  456. throw (DWORD)SCARD_F_INTERNAL_ERROR;
  457. }
  458. }
  459. }
  460. return fIsValid;
  461. }
  462. /*++
  463. LocateCards:
  464. This method requests the LocateCards service on behalf of the client.
  465. Arguments:
  466. mszReaders supplies the names of readers to look in, as a multistring.
  467. mszCards supplies the names of the cards to search for, as a multi-string.
  468. rgReaderStates supplies an array of SCARD_READERSTATE structures controlling
  469. the search, and receives the result. Reader names are taken from the
  470. mszReaders parameter, not from here.
  471. cReaders supplies the number of elements in the rgReaderStates array.
  472. Return Value:
  473. None
  474. Throws:
  475. Errors are thrown as DWORD status codes.
  476. Author:
  477. Doug Barlow (dbarlow) 12/6/1996
  478. --*/
  479. #undef __SUBROUTINE__
  480. #define __SUBROUTINE__ DBGT("CSCardUserContext::LocateCards")
  481. void
  482. CSCardUserContext::LocateCards(
  483. IN LPCTSTR mszReaders,
  484. IN LPSCARD_ATRMASK rgAtrMasks,
  485. IN DWORD cAtrs,
  486. IN OUT LPSCARD_READERSTATE rgReaderStates,
  487. IN DWORD cReaders)
  488. {
  489. CSCardSubcontext *pSubCtx = NULL;
  490. try
  491. {
  492. pSubCtx = AcquireSubcontext();
  493. if (NULL == pSubCtx)
  494. throw (DWORD)SCARD_E_NO_MEMORY;
  495. pSubCtx->LocateCards(
  496. mszReaders,
  497. rgAtrMasks,
  498. cAtrs,
  499. rgReaderStates,
  500. cReaders);
  501. pSubCtx->ReleaseSubcontext();
  502. }
  503. catch (...)
  504. {
  505. if (NULL != pSubCtx)
  506. pSubCtx->ReleaseSubcontext();
  507. throw;
  508. }
  509. }
  510. /*++
  511. GetStatusChange:
  512. This method requests the GetStatusChange service on behalf of the client.
  513. Arguments:
  514. rgReaderStates supplies an array of SCARD_READERSTATE structures controlling
  515. the search, and receives the result.
  516. cReaders supplies the number of elements in the rgReaderStates array.
  517. Return Value:
  518. None
  519. Remarks:
  520. We don't have to clean up the cancel event, since this is a one-time usage
  521. of this sub-context. Typically, if the subcontext were to be continued
  522. to be used, we'd have to make sure the cancel event got cleared eventually.
  523. Throws:
  524. Errors are thrown as DWORD status codes.
  525. Author:
  526. Doug Barlow (dbarlow) 12/6/1996
  527. --*/
  528. #undef __SUBROUTINE__
  529. #define __SUBROUTINE__ DBGT("CSCardUserContext::GetStatusChange")
  530. void
  531. CSCardUserContext::GetStatusChange(
  532. IN LPCTSTR mszReaders,
  533. IN OUT LPSCARD_READERSTATE rgReaderStates,
  534. IN DWORD cReaders,
  535. IN DWORD dwTimeout)
  536. {
  537. CSCardSubcontext *pSubCtx = NULL;
  538. try
  539. {
  540. pSubCtx = AcquireSubcontext(TRUE);
  541. if (NULL == pSubCtx)
  542. throw (DWORD) SCARD_E_NO_MEMORY;
  543. pSubCtx->GetStatusChange(
  544. mszReaders,
  545. rgReaderStates,
  546. cReaders,
  547. dwTimeout);
  548. pSubCtx->Deallocate();
  549. pSubCtx->ReleaseSubcontext();
  550. }
  551. catch (DWORD dwStatus)
  552. {
  553. DWORD dwError;
  554. dwError = dwStatus;
  555. if (NULL != pSubCtx)
  556. {
  557. pSubCtx->Deallocate();
  558. pSubCtx->ReleaseSubcontext();
  559. }
  560. // Catch & convert the Cancel I threw myself
  561. if ((SCARD_E_CANCELLED == dwError) && (IsBad()))
  562. {
  563. dwError = SCARD_E_SYSTEM_CANCELLED;
  564. }
  565. throw dwError;
  566. }
  567. catch (...)
  568. {
  569. if (NULL != pSubCtx)
  570. {
  571. pSubCtx->Deallocate();
  572. pSubCtx->ReleaseSubcontext();
  573. }
  574. throw;
  575. }
  576. }
  577. /*++
  578. Cancel:
  579. This method requests the Cancel service on behalf of the client.
  580. Arguments:
  581. None
  582. Return Value:
  583. None
  584. Throws:
  585. Errors are thrown as DWORD status codes.
  586. Author:
  587. Doug Barlow (dbarlow) 12/6/1996
  588. --*/
  589. #undef __SUBROUTINE__
  590. #define __SUBROUTINE__ DBGT("CSCardUserContext::Cancel")
  591. void
  592. CSCardUserContext::Cancel(
  593. void)
  594. {
  595. DWORD dwIndex;
  596. CSCardSubcontext *pSubCtx;
  597. LockSection(&m_csUsrCtxLock, DBGT("Cancelling outstanding operations"));
  598. for (dwIndex = m_rgpSubContexts.Count(); 0 < dwIndex;)
  599. {
  600. pSubCtx = m_rgpSubContexts[--dwIndex];
  601. if (NULL != pSubCtx)
  602. pSubCtx->Cancel();
  603. }
  604. }
  605. /*++
  606. StripInactiveReaders:
  607. This routine scans the supplied list of readers, and shortens it to exclude
  608. any readers that aren't currently active.
  609. Arguments:
  610. bfReaders supplies a list of readers by friendly name. This list is pruned
  611. to remove all names that refer to inactive readers.
  612. Return Value:
  613. None
  614. Throws:
  615. Errors are thrown as DWORD status codes.
  616. Remarks:
  617. All the listed readers must be introduced. This routine does not filter
  618. undefined readers.
  619. Author:
  620. Doug Barlow (dbarlow) 5/7/1998
  621. --*/
  622. #undef __SUBROUTINE__
  623. #define __SUBROUTINE__ DBGT("CSCardUserContext::StripInactiveReaders")
  624. void
  625. CSCardUserContext::StripInactiveReaders(
  626. IN OUT CBuffer &bfReaders)
  627. {
  628. CSCardSubcontext *pSubCtx = NULL;
  629. try
  630. {
  631. pSubCtx = AcquireSubcontext();
  632. if (NULL == pSubCtx)
  633. throw (DWORD) SCARD_E_NO_MEMORY;
  634. pSubCtx->StripInactiveReaders(bfReaders);
  635. pSubCtx->ReleaseSubcontext();
  636. }
  637. catch (...)
  638. {
  639. if (NULL != pSubCtx)
  640. pSubCtx->ReleaseSubcontext();
  641. throw;
  642. }
  643. }
  644. //
  645. //==============================================================================
  646. //
  647. // CSCardSubcontext
  648. //
  649. /*++
  650. CONSTRUCTOR and DESTRUCTOR:
  651. These are the simple constructor and destructor for the CSCardSubcontext
  652. class.
  653. Arguments:
  654. None
  655. Return Value:
  656. None
  657. Throws:
  658. None
  659. Remarks:
  660. ?Remarks?
  661. Author:
  662. Doug Barlow (dbarlow) 9/8/1998
  663. --*/
  664. #undef __SUBROUTINE__
  665. #define __SUBROUTINE__ DBGT("CSCardSubcontext::CSCardSubcontext")
  666. CSCardSubcontext::CSCardSubcontext(void)
  667. : m_csSubCtxLock(CSID_SUBCONTEXT),
  668. m_hBusy(DBGT("Subcontext busy mutex")),
  669. m_hCancelEvent(DBGT("Subcontext cancel event"))
  670. {
  671. DWORD dwSts;
  672. m_hReaderHandle = NULL;
  673. m_pParentCtx = NULL;
  674. m_pChannel = NULL;
  675. m_nInUse = Idle;
  676. m_nLastState = Invalid;
  677. m_hBusy = CreateEvent(NULL, TRUE, TRUE, NULL);
  678. if (!m_hBusy.IsValid())
  679. {
  680. dwSts = m_hBusy.GetLastError();
  681. CalaisWarning(
  682. __SUBROUTINE__,
  683. DBGT("Failed to create busy event flag: %1"),
  684. dwSts);
  685. throw dwSts;
  686. }
  687. CSecurityDescriptor acl;
  688. acl.InitializeFromProcessToken();
  689. acl.AllowOwner(
  690. EVENT_ALL_ACCESS);
  691. acl.Allow(
  692. &acl.SID_LocalService,
  693. EVENT_ALL_ACCESS);
  694. m_hCancelEvent = CreateEvent(acl, TRUE, FALSE, NULL);
  695. if (!m_hCancelEvent.IsValid())
  696. {
  697. dwSts = m_hCancelEvent.GetLastError();
  698. CalaisWarning(
  699. __SUBROUTINE__,
  700. DBGT("Card context cannot create cancel event: %1"),
  701. dwSts);
  702. throw dwSts;
  703. }
  704. }
  705. #undef __SUBROUTINE__
  706. #define __SUBROUTINE__ DBGT("CSCardSubcontext::~CSCardSubcontext")
  707. CSCardSubcontext::~CSCardSubcontext()
  708. {
  709. if (NULL != m_pChannel)
  710. delete m_pChannel;
  711. if (m_hBusy.IsValid())
  712. m_hBusy.Close();
  713. if (m_hCancelEvent.IsValid())
  714. m_hCancelEvent.Close();
  715. }
  716. /*++
  717. Allocate:
  718. This method raises the state of the subcontext to 'Allocated'. This means
  719. it is in use as an SCARDHANDLE.
  720. Arguments:
  721. None
  722. Return Value:
  723. None
  724. Throws:
  725. Errors are thrown as DWORD status codes
  726. Remarks:
  727. ?Remarks?
  728. Author:
  729. Doug Barlow (dbarlow) 4/23/1999
  730. --*/
  731. #undef __SUBROUTINE__
  732. #define __SUBROUTINE__ DBGT("CSCardSubcontext::Allocate")
  733. void
  734. CSCardSubcontext::Allocate(
  735. void)
  736. {
  737. LockSection(&m_csSubCtxLock, DBGT("Mark subcontext as allocated"));
  738. ASSERT(Idle == m_nInUse);
  739. ASSERT(Invalid == m_nLastState);
  740. m_nInUse = Allocated;
  741. }
  742. /*++
  743. Deallocate:
  744. This method releases the subcontext from the allocated state.
  745. If the device is still busy, it sets things up to be deallocated
  746. when it is released.
  747. Arguments:
  748. None
  749. Return Value:
  750. None
  751. Throws:
  752. Errors are thrown as DWORD status codes.
  753. Remarks:
  754. ?Remarks?
  755. Author:
  756. Doug Barlow (dbarlow) 4/23/1999
  757. --*/
  758. #undef __SUBROUTINE__
  759. #define __SUBROUTINE__ DBGT("CSCardSubcontext::Deallocate")
  760. void
  761. CSCardSubcontext::Deallocate(
  762. void)
  763. {
  764. LockSection(&m_csSubCtxLock, DBGT("Deallocate subcontext"));
  765. switch (m_nInUse)
  766. {
  767. case Idle:
  768. ASSERT(FALSE); // Why are we here?
  769. break;
  770. case Allocated:
  771. m_nInUse = Idle;
  772. m_nLastState = Invalid;
  773. break;
  774. case Busy:
  775. ASSERT(Allocated == m_nLastState);
  776. m_nLastState = Idle;
  777. break;
  778. default:
  779. CalaisWarning(
  780. __SUBROUTINE__,
  781. DBGT("Subcontext deallocation state corruption detected."));
  782. throw (DWORD)SCARD_F_INTERNAL_ERROR;
  783. }
  784. }
  785. /*++
  786. SetBusy:
  787. This method marks the subcontext as busy.
  788. Arguments:
  789. None
  790. Return Value:
  791. None
  792. Throws:
  793. None (It tries to limp along)
  794. Remarks:
  795. ?Remarks?
  796. Author:
  797. Doug Barlow (dbarlow) 11/10/1998
  798. --*/
  799. #undef __SUBROUTINE__
  800. #define __SUBROUTINE__ DBGT("CSCardSubcontext::SetBusy")
  801. void
  802. CSCardSubcontext::SetBusy(
  803. void)
  804. {
  805. LockSection(&m_csSubCtxLock, DBGT("Mark subcontext busy"));
  806. ASSERT(Busy != m_nInUse);
  807. ASSERT(Invalid == m_nLastState);
  808. ASSERT(m_hBusy.IsValid());
  809. m_nLastState = m_nInUse;
  810. m_nInUse = Busy;
  811. ASSERT(m_nLastState < m_nInUse);
  812. ASSERT(Invalid != m_nLastState);
  813. if (!ResetEvent(m_hBusy))
  814. CalaisWarning(
  815. __SUBROUTINE__,
  816. DBGT("Failed to mark context busy: %1"),
  817. GetLastError());
  818. }
  819. /*++
  820. SendRequest:
  821. This method sends the given Communications Object to the server application.
  822. Arguments:
  823. pCom supplies the Communications Object to be sent.
  824. Return Value:
  825. None
  826. Throws:
  827. None
  828. Author:
  829. Doug Barlow (dbarlow) 12/16/1996
  830. --*/
  831. #undef __SUBROUTINE__
  832. #define __SUBROUTINE__ DBGT("CSCardSubcontext::SendRequest")
  833. void
  834. CSCardSubcontext::SendRequest(
  835. CComObject *pCom)
  836. {
  837. ASSERT(Busy == m_nInUse);
  838. try
  839. {
  840. DWORD dwSts = pCom->Send(m_pChannel);
  841. if (ERROR_SUCCESS != dwSts)
  842. throw dwSts;
  843. }
  844. catch (DWORD dwErr)
  845. {
  846. switch (dwErr)
  847. {
  848. case ERROR_NO_DATA:
  849. case ERROR_PIPE_NOT_CONNECTED:
  850. case ERROR_BAD_PIPE:
  851. case ERROR_BROKEN_PIPE:
  852. throw (DWORD)SCARD_E_SERVICE_STOPPED;
  853. break;
  854. default:
  855. throw;
  856. }
  857. }
  858. }
  859. //
  860. // Attempts to restore the impersonation token of the current thread.
  861. // Assumes that failure to restore the impersonation token is catastrophic.
  862. //
  863. // If this function is called, we assume we're currently running as Local
  864. // System and attempting to restore our impersonation token. That shouldn't
  865. // fail, but if it does, something is really wrong and we must not continue
  866. // to execute code in this state.
  867. //
  868. void MySetThreadToken(HANDLE hThreadToken)
  869. {
  870. if (FALSE == SetThreadToken(NULL, hThreadToken))
  871. {
  872. ASSERT(FALSE);
  873. TerminateThread(GetCurrentThread(), 0);
  874. }
  875. }
  876. /*++
  877. EstablishContext:
  878. This method establishes the context by connecting to the Calais Server
  879. application.
  880. Arguments:
  881. dwScope supplies an indication of the scope of the context. Possible values
  882. are:
  883. SCARD_SCOPE_USER - The context is a user context, and any database
  884. operations are performed within the domain of the user.
  885. SCARD_SCOPE_TERMINAL - The context is that of the current terminal, and
  886. any database operations are performed within the domain of that
  887. terminal. (The calling application must have appropriate access
  888. permissions for any database actions.)
  889. SCARD_SCOPE_SYSTEM - The context is the system context, and any database
  890. operations are performed within the domain of the system. (The
  891. calling application must have appropriate access permissions for any
  892. database actions.)
  893. Return Value:
  894. None
  895. Throws:
  896. Error conditions are thrown as DWORD status codes.
  897. Author:
  898. Doug Barlow (dbarlow) 11/21/1996
  899. --*/
  900. #undef __SUBROUTINE__
  901. #define __SUBROUTINE__ DBGT("CSCardSubcontext::EstablishContext")
  902. void
  903. CSCardSubcontext::EstablishContext(
  904. IN DWORD dwScope)
  905. {
  906. CComChannel *pCom = NULL;
  907. DWORD dwVersion = CALAIS_COMM_CURRENT;
  908. HANDLE hThreadToken = NULL;
  909. try
  910. {
  911. CComInitiator comInit;
  912. ComEstablishContext comEstablishContext;
  913. ComEstablishContext::CObjEstablishContext_request *pReq;
  914. ComEstablishContext::CObjEstablishContext_response *pRsp;
  915. DWORD dwSts;
  916. HANDLE hServerCancelEvent = NULL;
  917. ASSERT(Busy == m_nInUse);
  918. pCom = comInit.Initiate(
  919. CalaisString(CALSTR_COMMPIPENAME),
  920. &dwVersion);
  921. ASSERT(dwVersion == CALAIS_COMM_CURRENT);
  922. pReq = comEstablishContext.InitRequest(0);
  923. pReq->dwProcId = GetCurrentProcessId();
  924. pReq->hptrCancelEvent = (HANDLE_PTR) m_hCancelEvent.Value();
  925. comEstablishContext.Send(pCom);
  926. comEstablishContext.InitResponse(0);
  927. pRsp = comEstablishContext.Receive(pCom);
  928. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  929. throw pRsp->dwStatus;
  930. hServerCancelEvent = (HANDLE) pRsp->hptrCancelEvent;
  931. if (NULL != hServerCancelEvent)
  932. {
  933. CHandleObject hTargetProc(DBGT("Target Process in EstablishContext"));
  934. HANDLE h = NULL;
  935. BOOL fSts = FALSE;
  936. //
  937. // The Resource Manager doesn't have access to our Cancel event.
  938. // It's proposed an event to use instead. Switch over.
  939. //
  940. // Get the process handle for scardsvr. We require Duplicate
  941. // Handle rights.
  942. //
  943. // Assume that the only reason scardsvr would have sent back a new
  944. // event handle is that we're impersonating a lesser account that
  945. // doesn't own the current process. That account will likely not
  946. // have the appropriate rights to scardsvr either, so we need to
  947. // revert to self before doing the following work.
  948. //
  949. if (FALSE == OpenThreadToken(
  950. GetCurrentThread(), MAXIMUM_ALLOWED, TRUE, &hThreadToken))
  951. throw GetLastError();
  952. if (FALSE == RevertToSelf())
  953. throw GetLastError();
  954. hTargetProc = OpenProcess(
  955. PROCESS_DUP_HANDLE | EVENT_ALL_ACCESS,
  956. FALSE, // handle inheritance flag
  957. pRsp->dwProcId); // process identifier
  958. if (!hTargetProc.IsValid())
  959. throw GetLastError();
  960. fSts = DuplicateHandle(
  961. hTargetProc, // handle to process
  962. hServerCancelEvent,
  963. GetCurrentProcess(),// handle to process to duplicate to
  964. &h, // pointer to duplicate handle
  965. EVENT_ALL_ACCESS, // access for duplicate handle
  966. FALSE, // handle inheritance flag
  967. 0); // optional actions
  968. if (!fSts)
  969. {
  970. dwSts = GetLastError();
  971. CalaisWarning(
  972. __SUBROUTINE__,
  973. DBGT("EstablishContext could not dup offered cancel event: %1"),
  974. dwSts);
  975. ASSERT(NULL == h);
  976. throw dwSts;
  977. }
  978. // Restore the impersonation token
  979. MySetThreadToken(hThreadToken);
  980. CloseHandle(hThreadToken);
  981. hThreadToken = NULL;
  982. ASSERT(m_hCancelEvent.IsValid());
  983. m_hCancelEvent.Close();
  984. m_hCancelEvent = h;
  985. }
  986. m_pChannel = pCom;
  987. }
  988. catch (...)
  989. {
  990. if (NULL != hThreadToken)
  991. {
  992. MySetThreadToken(hThreadToken);
  993. CloseHandle(hThreadToken);
  994. }
  995. if (NULL != pCom)
  996. delete pCom;
  997. throw;
  998. }
  999. }
  1000. /*++
  1001. ReleaseSubcontext:
  1002. This method releases the subcontext for use by other requests.
  1003. Arguments:
  1004. None
  1005. Return Value:
  1006. None
  1007. Throws:
  1008. Errors are thrown as DWORD status codes
  1009. Remarks:
  1010. ?Remarks?
  1011. Author:
  1012. Doug Barlow (dbarlow) 4/22/1999
  1013. --*/
  1014. #undef __SUBROUTINE__
  1015. #define __SUBROUTINE__ DBGT("CSCardSubcontext::ReleaseSubcontext")
  1016. void
  1017. CSCardSubcontext::ReleaseSubcontext(
  1018. void)
  1019. {
  1020. LockSection(&m_csSubCtxLock, DBGT("Mark subcontext available"));
  1021. // Check to see if winscard.dll is currently being unloaded. If
  1022. // so, skip the asserts.
  1023. if (FALSE == g_fInClientRundown)
  1024. {
  1025. ASSERT(Idle != m_nInUse);
  1026. ASSERT(Busy != m_nLastState);
  1027. ASSERT(Invalid != m_nLastState);
  1028. ASSERT(m_nInUse > m_nLastState);
  1029. ASSERT(m_hBusy.IsValid());
  1030. }
  1031. m_nInUse = m_nLastState;
  1032. if (FALSE == g_fInClientRundown)
  1033. {
  1034. ASSERT(Busy != m_nInUse);
  1035. }
  1036. m_nLastState = Invalid;
  1037. if (!SetEvent(m_hBusy))
  1038. CalaisWarning(
  1039. __SUBROUTINE__,
  1040. DBGT("Failed to mark context Available: %1"),
  1041. GetLastError());
  1042. }
  1043. /*++
  1044. ReleaseContext:
  1045. This method requests the ReleaseContext service on behalf of the client.
  1046. Arguments:
  1047. None
  1048. Return Value:
  1049. None
  1050. Throws:
  1051. Errors are thrown as DWORD status codes.
  1052. Author:
  1053. Doug Barlow (dbarlow) 12/6/1996
  1054. --*/
  1055. #undef __SUBROUTINE__
  1056. #define __SUBROUTINE__ DBGT("CSCardSubcontext::ReleaseContext")
  1057. void
  1058. CSCardSubcontext::ReleaseContext(
  1059. void)
  1060. {
  1061. ComReleaseContext comRel;
  1062. ComReleaseContext::CObjReleaseContext_request *pReq;
  1063. ComReleaseContext::CObjReleaseContext_response *pRsp;
  1064. if (WaitForSingleObject(m_hBusy, 0) != WAIT_TIMEOUT) // Subcontext not busy
  1065. {
  1066. CSubctxLock csCtxLock(this);
  1067. pReq = comRel.InitRequest(0);
  1068. SendRequest(&comRel);
  1069. comRel.InitResponse(0);
  1070. pRsp = comRel.Receive(m_pChannel);
  1071. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  1072. throw pRsp->dwStatus;
  1073. }
  1074. }
  1075. /*++
  1076. ClosePipe:
  1077. This method closes the pipe to SCardSvr.
  1078. Arguments:
  1079. None
  1080. Return Value:
  1081. None
  1082. Throws:
  1083. Errors are thrown as DWORD status codes.
  1084. Author:
  1085. Sermet Iskin (SermetI) 1/4/2001
  1086. --*/
  1087. #undef __SUBROUTINE__
  1088. #define __SUBROUTINE__ DBGT("CSCardSubcontext::ClosePipe")
  1089. void
  1090. CSCardSubcontext::ClosePipe(
  1091. void)
  1092. {
  1093. if (WaitForSingleObject(m_hBusy, 0) != WAIT_TIMEOUT) // Subcontext not busy
  1094. {
  1095. CSubctxLock csCtxLock(this);
  1096. m_pChannel->ClosePipe() ;
  1097. }
  1098. }
  1099. /*++
  1100. WaitForAvailable:
  1101. This method waits for a given connection to go not busy, then locks it.
  1102. Arguments:
  1103. None
  1104. Return Value:
  1105. None
  1106. Throws:
  1107. Errors are thrown as DWORD status codes
  1108. Remarks:
  1109. ?Remarks?
  1110. Author:
  1111. Doug Barlow (dbarlow) 4/22/1999
  1112. --*/
  1113. #undef __SUBROUTINE__
  1114. #define __SUBROUTINE__ DBGT("CSCardSubcontext::WaitForAvailable")
  1115. void
  1116. CSCardSubcontext::WaitForAvailable(
  1117. void)
  1118. {
  1119. DWORD dwSts;
  1120. BOOL fNotDone = TRUE;
  1121. ASSERT(m_hBusy.IsValid());
  1122. while (fNotDone)
  1123. {
  1124. {
  1125. LockSection(&m_csSubCtxLock, DBGT("Checking availability"));
  1126. switch (m_nInUse)
  1127. {
  1128. case Idle:
  1129. ASSERT(Invalid == m_nLastState);
  1130. // Fall through intentionally
  1131. case Allocated:
  1132. ASSERT(Allocated != m_nLastState);
  1133. SetBusy();
  1134. fNotDone = FALSE;
  1135. continue;
  1136. break;
  1137. case Busy:
  1138. ASSERT(Busy > m_nLastState);
  1139. ASSERT(Invalid != m_nLastState);
  1140. break;
  1141. default:
  1142. CalaisWarning(
  1143. __SUBROUTINE__,
  1144. DBGT("Subcontext availability state is corrupted."));
  1145. throw (DWORD)SCARD_F_INTERNAL_ERROR;
  1146. }
  1147. }
  1148. dwSts = WaitForSingleObject(m_hBusy, CALAIS_LOCK_TIMEOUT);
  1149. switch (dwSts)
  1150. {
  1151. case WAIT_ABANDONED:
  1152. CalaisWarning(
  1153. __SUBROUTINE__,
  1154. DBGT("Wait for context busy received wait abandoned."));
  1155. break;
  1156. case WAIT_OBJECT_0:
  1157. break;
  1158. case WAIT_TIMEOUT:
  1159. CalaisWarning(
  1160. __SUBROUTINE__,
  1161. DBGT("Wait for context busy timed out."),
  1162. GetLastError());
  1163. break;
  1164. case WAIT_FAILED:
  1165. CalaisWarning(
  1166. __SUBROUTINE__,
  1167. DBGT("Wait for context busy failed: %1"),
  1168. GetLastError());
  1169. break;
  1170. default:
  1171. CalaisWarning(
  1172. __SUBROUTINE__,
  1173. DBGT("Wait for context busy received invalid return: %1"),
  1174. GetLastError());
  1175. }
  1176. }
  1177. }
  1178. /*++
  1179. IsValidContext:
  1180. This method requests the ReleaseContext service on behalf of the client.
  1181. Arguments:
  1182. None
  1183. Return Value:
  1184. None
  1185. Throws:
  1186. If the call cannot be completed, a DWORD status code is thrown.
  1187. Remarks:
  1188. If the context is determined to not be valid, it is automatically released.
  1189. Author:
  1190. Doug Barlow (dbarlow) 11/2/1998
  1191. --*/
  1192. #undef __SUBROUTINE__
  1193. #define __SUBROUTINE__ DBGT("CSCardSubcontext::IsValidContext")
  1194. void
  1195. CSCardSubcontext::IsValidContext(
  1196. void)
  1197. {
  1198. ComIsValidContext comObj;
  1199. ComIsValidContext::CObjIsValidContext_request *pReq;
  1200. ComIsValidContext::CObjIsValidContext_response *pRsp;
  1201. pReq = comObj.InitRequest(0);
  1202. SendRequest(&comObj);
  1203. comObj.InitResponse(0);
  1204. pRsp = comObj.Receive(m_pChannel);
  1205. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  1206. throw pRsp->dwStatus;
  1207. }
  1208. /*++
  1209. LocateCards:
  1210. This method requests the LocateCards service on behalf of the client.
  1211. Arguments:
  1212. mszReaders supplies the names of readers to look in, as a multistring.
  1213. mszCards supplies the names of the cards to search for, as a multi-string.
  1214. rgReaderStates supplies an array of SCARD_READERSTATE structures controlling
  1215. the search, and receives the result. Reader names are taken from the
  1216. mszReaders parameter, not from here.
  1217. cReaders supplies the number of elements in the rgReaderStates array.
  1218. Return Value:
  1219. None
  1220. Throws:
  1221. Errors are thrown as DWORD status codes.
  1222. Author:
  1223. Doug Barlow (dbarlow) 12/6/1996
  1224. --*/
  1225. #undef __SUBROUTINE__
  1226. #define __SUBROUTINE__ DBGT("CSCardSubcontext::LocateCards")
  1227. void
  1228. CSCardSubcontext::LocateCards(
  1229. IN LPCTSTR mszReaders,
  1230. IN LPSCARD_ATRMASK rgAtrMasks,
  1231. IN DWORD cAtrs,
  1232. IN OUT LPSCARD_READERSTATE rgReaderStates,
  1233. IN DWORD cReaders)
  1234. {
  1235. ComLocateCards comObj;
  1236. ComLocateCards::CObjLocateCards_request *pReq;
  1237. ComLocateCards::CObjLocateCards_response *pRsp;
  1238. CBuffer bfReaders;
  1239. CBuffer bfStatus;
  1240. CBuffer bfAtrs;
  1241. CBuffer bfMasks;
  1242. CBuffer bfXlate1(36); // Rough guess of name & ATR lengths
  1243. LPDWORD rgdwStatus;
  1244. DWORD dwIndex, dwChkLen;
  1245. BYTE cbAtrLen;
  1246. DWORD dwAtrLen;
  1247. LPCBYTE pbAtr;
  1248. LPCTSTR szReader;
  1249. if (0 == cReaders)
  1250. return;
  1251. if (0 == *mszReaders)
  1252. throw (DWORD)SCARD_E_UNKNOWN_READER;
  1253. bfStatus.Resize(sizeof(DWORD) * cReaders);
  1254. rgdwStatus = (LPDWORD)bfStatus.Access();
  1255. //
  1256. // List the smartcard ATRs and masks we're interested in.
  1257. //
  1258. for (dwIndex = 0;
  1259. dwIndex < cAtrs;
  1260. dwIndex++)
  1261. {
  1262. bfAtrs.Presize(bfAtrs.Length() + rgAtrMasks[dwIndex].cbAtr + 1, TRUE);
  1263. bfMasks.Presize(bfMasks.Length() + rgAtrMasks[dwIndex].cbAtr + 1, TRUE);
  1264. ASSERT(33 >= rgAtrMasks[dwIndex].cbAtr); // Biggest an ATR can be.
  1265. cbAtrLen = (BYTE)rgAtrMasks[dwIndex].cbAtr;
  1266. bfAtrs.Append(&cbAtrLen, 1);
  1267. bfAtrs.Append(rgAtrMasks[dwIndex].rgbAtr, cbAtrLen);
  1268. bfMasks.Append(&cbAtrLen, 1);
  1269. bfMasks.Append(rgAtrMasks[dwIndex].rgbMask, cbAtrLen);
  1270. }
  1271. //
  1272. // List the reader devices we're interested in.
  1273. //
  1274. for (szReader = FirstString(mszReaders), dwIndex = 0;
  1275. NULL != szReader;
  1276. szReader = NextString(szReader), dwIndex += 1)
  1277. {
  1278. ASSERT(cReaders > dwIndex);
  1279. BOOL fSts = GetReaderInfo(
  1280. Scope(),
  1281. szReader,
  1282. NULL,
  1283. &bfXlate1);
  1284. if (!fSts)
  1285. throw (DWORD)SCARD_E_UNKNOWN_READER;
  1286. bfReaders.Append(
  1287. bfXlate1.Access(),
  1288. bfXlate1.Length());
  1289. rgdwStatus[dwIndex] = rgReaderStates[dwIndex].dwCurrentState;
  1290. }
  1291. ASSERT(cReaders == dwIndex);
  1292. bfReaders.Append((LPCBYTE)TEXT("\000"), sizeof(TCHAR));
  1293. //
  1294. // Put it all into the request.
  1295. //
  1296. pReq = comObj.InitRequest(
  1297. bfAtrs.Length() + bfMasks.Length() + bfReaders.Length()
  1298. + bfStatus.Length() + 4 * sizeof(DWORD));
  1299. pReq = (ComLocateCards::CObjLocateCards_request *)comObj.Append(
  1300. pReq->dscAtrs, bfAtrs.Access(), bfAtrs.Length());
  1301. pReq = (ComLocateCards::CObjLocateCards_request *)comObj.Append(
  1302. pReq->dscAtrMasks, bfMasks.Access(), bfMasks.Length());
  1303. pReq = (ComLocateCards::CObjLocateCards_request *)comObj.Append(
  1304. pReq->dscReaders, bfReaders.Access(), bfReaders.Length());
  1305. pReq = (ComLocateCards::CObjLocateCards_request *)comObj.Append(
  1306. pReq->dscReaderStates, bfStatus.Access(), bfStatus.Length());
  1307. //
  1308. // Send in the request.
  1309. //
  1310. SendRequest(&comObj);
  1311. comObj.InitResponse(cReaders * sizeof(DWORD));
  1312. pRsp = comObj.Receive(m_pChannel);
  1313. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  1314. throw pRsp->dwStatus;
  1315. //
  1316. // Parse the response.
  1317. //
  1318. rgdwStatus = (LPDWORD)comObj.Parse(pRsp->dscReaderStates, &dwChkLen);
  1319. if (dwChkLen != cReaders * sizeof(DWORD))
  1320. {
  1321. CalaisWarning(
  1322. __SUBROUTINE__,
  1323. DBGT("Client locate cards array size mismatch"));
  1324. throw (DWORD)SCARD_F_COMM_ERROR;
  1325. }
  1326. pbAtr = (LPCBYTE)comObj.Parse(pRsp->dscAtrs, &dwChkLen);
  1327. for (dwIndex = 0; dwIndex < cReaders; dwIndex += 1)
  1328. {
  1329. rgReaderStates[dwIndex].dwEventState = rgdwStatus[dwIndex];
  1330. dwAtrLen = *pbAtr++;
  1331. ASSERT(33 >= dwAtrLen);
  1332. if (dwAtrLen >= dwChkLen)
  1333. {
  1334. CalaisWarning(
  1335. __SUBROUTINE__,
  1336. DBGT("Client locate cards ATR size mismatch"));
  1337. throw (DWORD)SCARD_F_COMM_ERROR;
  1338. }
  1339. ZeroMemory(
  1340. rgReaderStates[dwIndex].rgbAtr,
  1341. sizeof(SCARD_READERSTATE) - FIELD_OFFSET(SCARD_READERSTATE, rgbAtr));
  1342. CopyMemory(rgReaderStates[dwIndex].rgbAtr, pbAtr, dwAtrLen);
  1343. rgReaderStates[dwIndex].cbAtr = dwAtrLen;
  1344. dwChkLen -= dwAtrLen + 1;
  1345. pbAtr += dwAtrLen;
  1346. }
  1347. }
  1348. /*++
  1349. GetStatusChange:
  1350. This method requests the GetStatusChange service on behalf of the client.
  1351. Arguments:
  1352. rgReaderStates supplies an array of SCARD_READERSTATE structures controlling
  1353. the search, and receives the result.
  1354. cReaders supplies the number of elements in the rgReaderStates array.
  1355. Return Value:
  1356. None
  1357. Remarks:
  1358. We don't have to clean up the cancel event, since this is a one-time usage
  1359. of this sub-context. Typically, if the subcontext were to be continued
  1360. to be used, we'd have to make sure the cancel event got cleared eventually.
  1361. Throws:
  1362. Errors are thrown as DWORD status codes.
  1363. Author:
  1364. Doug Barlow (dbarlow) 12/6/1996
  1365. --*/
  1366. #undef __SUBROUTINE__
  1367. #define __SUBROUTINE__ DBGT("CSCardSubcontext::GetStatusChange")
  1368. void
  1369. CSCardSubcontext::GetStatusChange(
  1370. IN LPCTSTR mszReaders,
  1371. IN OUT LPSCARD_READERSTATE rgReaderStates,
  1372. IN DWORD cReaders,
  1373. IN DWORD dwTimeout)
  1374. {
  1375. ComGetStatusChange comObj;
  1376. ComGetStatusChange::CObjGetStatusChange_request *pReq;
  1377. ComGetStatusChange::CObjGetStatusChange_response *pRsp;
  1378. CBuffer bfReaders;
  1379. CBuffer bfStatus;
  1380. LPDWORD rgdwStatus;
  1381. CBuffer bfXlate(16); // Rough guess of device name length
  1382. DWORD dwIndex, dwChkLen;
  1383. BOOL fSts;
  1384. LPCBYTE pbAtr;
  1385. DWORD dwAtrLen;
  1386. LPCTSTR szReader;
  1387. if (0 == cReaders)
  1388. return;
  1389. bfStatus.Resize(sizeof(DWORD) * cReaders);
  1390. rgdwStatus = (LPDWORD)bfStatus.Access();
  1391. if (0 == *mszReaders)
  1392. throw (DWORD)SCARD_E_UNKNOWN_READER;
  1393. //
  1394. // List the reader devices we're interested in.
  1395. //
  1396. for (szReader = FirstString(mszReaders), dwIndex = 0;
  1397. NULL != szReader;
  1398. szReader = NextString(szReader), dwIndex += 1)
  1399. {
  1400. ASSERT(cReaders > dwIndex);
  1401. fSts = GetReaderInfo(
  1402. Scope(),
  1403. szReader,
  1404. NULL,
  1405. &bfXlate);
  1406. if (fSts)
  1407. {
  1408. bfReaders.Append(
  1409. bfXlate.Access(),
  1410. bfXlate.Length());
  1411. }
  1412. else if (0 == _tcsncicmp(
  1413. CalaisString(CALSTR_SPECIALREADERHEADER),
  1414. szReader,
  1415. _tcslen(CalaisString(CALSTR_SPECIALREADERHEADER))))
  1416. {
  1417. bfReaders.Append(
  1418. (LPCBYTE)szReader,
  1419. (_tcslen(szReader) + 1) * sizeof(TCHAR));
  1420. }
  1421. else
  1422. throw (DWORD)SCARD_E_UNKNOWN_READER;
  1423. rgdwStatus[dwIndex] = rgReaderStates[dwIndex].dwCurrentState;
  1424. }
  1425. ASSERT(cReaders == dwIndex);
  1426. bfReaders.Append((LPCBYTE)TEXT("\000"), sizeof(TCHAR));
  1427. //
  1428. // Put it all into the request.
  1429. //
  1430. pReq = comObj.InitRequest(
  1431. bfReaders.Length() + bfStatus.Length()
  1432. + 2 * sizeof(DWORD));
  1433. pReq->dwTimeout = dwTimeout;
  1434. pReq = (ComGetStatusChange::CObjGetStatusChange_request *)
  1435. comObj.Append(
  1436. pReq->dscReaders,
  1437. bfReaders.Access(),
  1438. bfReaders.Length());
  1439. pReq = (ComGetStatusChange::CObjGetStatusChange_request *)
  1440. comObj.Append(
  1441. pReq->dscReaderStates,
  1442. bfStatus.Access(),
  1443. bfStatus.Length());
  1444. SendRequest(&comObj);
  1445. comObj.InitResponse(cReaders * sizeof(DWORD));
  1446. pRsp = comObj.Receive(m_pChannel);
  1447. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  1448. throw pRsp->dwStatus;
  1449. rgdwStatus = (LPDWORD)comObj.Parse(pRsp->dscReaderStates, &dwChkLen);
  1450. if (dwChkLen != cReaders * sizeof(DWORD))
  1451. {
  1452. CalaisWarning(
  1453. __SUBROUTINE__,
  1454. DBGT("Client locate cards array size mismatch"));
  1455. throw (DWORD)SCARD_F_COMM_ERROR;
  1456. }
  1457. pbAtr = (LPCBYTE)comObj.Parse(pRsp->dscAtrs, &dwChkLen);
  1458. for (dwIndex = 0; dwIndex < cReaders; dwIndex += 1)
  1459. {
  1460. rgReaderStates[dwIndex].dwEventState = rgdwStatus[dwIndex];
  1461. dwAtrLen = *pbAtr++;
  1462. ASSERT(33 >= dwAtrLen);
  1463. if (dwAtrLen >= dwChkLen)
  1464. {
  1465. CalaisWarning(
  1466. __SUBROUTINE__,
  1467. DBGT("Client locate cards ATR size mismatch"));
  1468. throw (DWORD)SCARD_F_COMM_ERROR;
  1469. }
  1470. ZeroMemory(
  1471. rgReaderStates[dwIndex].rgbAtr,
  1472. sizeof(SCARD_READERSTATE) - FIELD_OFFSET(SCARD_READERSTATE, rgbAtr));
  1473. CopyMemory(rgReaderStates[dwIndex].rgbAtr, pbAtr, dwAtrLen);
  1474. rgReaderStates[dwIndex].cbAtr = dwAtrLen;
  1475. dwChkLen -= dwAtrLen + 1;
  1476. pbAtr += dwAtrLen;
  1477. }
  1478. }
  1479. /*++
  1480. Cancel:
  1481. This method requests the Cancel service on behalf of the client.
  1482. Arguments:
  1483. None
  1484. Return Value:
  1485. None
  1486. Throws:
  1487. Errors are thrown as DWORD status codes.
  1488. Author:
  1489. Doug Barlow (dbarlow) 12/6/1996
  1490. --*/
  1491. #undef __SUBROUTINE__
  1492. #define __SUBROUTINE__ DBGT("CSCardSubcontext::Cancel")
  1493. void
  1494. CSCardSubcontext::Cancel(
  1495. void)
  1496. {
  1497. ASSERT(m_hCancelEvent.IsValid());
  1498. if (!SetEvent(m_hCancelEvent))
  1499. CalaisWarning(
  1500. __SUBROUTINE__,
  1501. DBGT("Cancel request Failed to set context cancel event: %1"),
  1502. GetLastError());
  1503. }
  1504. /*++
  1505. StripInactiveReaders:
  1506. This routine scans the supplied list of readers, and shortens it to exclude
  1507. any readers that aren't currently active.
  1508. Arguments:
  1509. bfReaders supplies a list of readers by friendly name. This list is pruned
  1510. to remove all names that refer to inactive readers.
  1511. Return Value:
  1512. None
  1513. Throws:
  1514. Errors are thrown as DWORD status codes.
  1515. Remarks:
  1516. All the listed readers must be introduced. This routine does not filter
  1517. undefined readers.
  1518. Author:
  1519. Doug Barlow (dbarlow) 5/7/1998
  1520. --*/
  1521. #undef __SUBROUTINE__
  1522. #define __SUBROUTINE__ DBGT("CSCardSubcontext::StripInactiveReaders")
  1523. void
  1524. CSCardSubcontext::StripInactiveReaders(
  1525. IN OUT CBuffer &bfReaders)
  1526. {
  1527. ComListReaders comObj;
  1528. ComListReaders::CObjListReaders_request *pReq;
  1529. ComListReaders::CObjListReaders_response *pRsp;
  1530. CBuffer bfDeviceName, bfDevices;
  1531. LPCTSTR szReader;
  1532. BOOL fSts;
  1533. LPBOOL pfDeviceActive;
  1534. DWORD dwReaderCount;
  1535. //
  1536. // Build the corresponding list of device names.
  1537. //
  1538. if (0 == *(LPCTSTR)bfReaders.Access())
  1539. throw (DWORD)SCARD_E_NO_READERS_AVAILABLE;
  1540. for (szReader = FirstString((LPCTSTR)bfReaders.Access());
  1541. NULL != szReader;
  1542. szReader = NextString(szReader))
  1543. {
  1544. fSts = GetReaderInfo(Scope(), szReader, NULL, &bfDeviceName);
  1545. if (!fSts)
  1546. throw (DWORD)SCARD_E_UNKNOWN_READER;
  1547. MStrAdd(bfDevices, (LPCTSTR)bfDeviceName.Access());
  1548. }
  1549. //
  1550. // Ask the resource manager which ones are active.
  1551. //
  1552. pReq = comObj.InitRequest(bfDevices.Length());
  1553. pReq = (ComListReaders::CObjListReaders_request *)comObj.Append(
  1554. pReq->dscReaders, bfDevices.Access(), bfDevices.Length());
  1555. SendRequest(&comObj);
  1556. comObj.InitResponse(0);
  1557. pRsp = comObj.Receive(m_pChannel);
  1558. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  1559. throw pRsp->dwStatus;
  1560. pfDeviceActive = (LPBOOL)comObj.Parse(pRsp->dscReaders, &dwReaderCount);
  1561. dwReaderCount /= sizeof(BOOL);
  1562. ASSERT(dwReaderCount == MStringCount((LPCTSTR)bfReaders.Access()));
  1563. //
  1564. // Filter the inactive ones out of the original set.
  1565. //
  1566. bfDevices.Reset();
  1567. for (szReader = FirstString((LPCTSTR)bfReaders.Access());
  1568. NULL != szReader;
  1569. szReader = NextString(szReader))
  1570. {
  1571. if (*pfDeviceActive++)
  1572. MStrAdd(bfDevices, szReader);
  1573. }
  1574. //
  1575. // Replace the original buffer.
  1576. //
  1577. bfReaders = bfDevices;
  1578. }
  1579. //
  1580. //==============================================================================
  1581. //
  1582. // CReaderContext
  1583. //
  1584. #define INVALID_SCARDHANDLE_VALUE (INTERCHANGEHANDLE)(-1)
  1585. /*++
  1586. CReaderContext:
  1587. ~CReaderContext:
  1588. These are the constructor and destructor for a client reader context object.
  1589. Arguments:
  1590. None
  1591. Return Value:
  1592. None
  1593. Throws:
  1594. None
  1595. Author:
  1596. Doug Barlow (dbarlow) 12/7/1996
  1597. --*/
  1598. #undef __SUBROUTINE__
  1599. #define __SUBROUTINE__ DBGT("CReaderContext::CReaderContext")
  1600. CReaderContext::CReaderContext(
  1601. void)
  1602. {
  1603. m_dwActiveProtocol = SCARD_PROTOCOL_UNDEFINED;
  1604. m_pCtx = NULL;
  1605. m_hCard = (INTERCHANGEHANDLE)INVALID_SCARDHANDLE_VALUE;
  1606. m_hRedirCard = NULL;
  1607. }
  1608. #undef __SUBROUTINE__
  1609. #define __SUBROUTINE__ DBGT("CReaderContext::~CReaderContext")
  1610. CReaderContext::~CReaderContext()
  1611. {
  1612. try
  1613. {
  1614. if (NULL != m_pCtx)
  1615. {
  1616. Context()->Deallocate();
  1617. Context()->ReleaseSubcontext();
  1618. m_pCtx = NULL;
  1619. }
  1620. }
  1621. catch (...) {}
  1622. }
  1623. /*++
  1624. Connect:
  1625. This method requests the Connect service on behalf of the client.
  1626. Arguments:
  1627. pCtx supplies the Context under which the reader is opened.
  1628. szReaderName supplies the name of the reader to connect to.
  1629. dwShareMode supplies the form of sharing to be invoked.
  1630. dwPreferredProtocols supplies the acceptable protocols.
  1631. Return Value:
  1632. None
  1633. Throws:
  1634. Errors are thrown as DWORD status codes.
  1635. Author:
  1636. Doug Barlow (dbarlow) 12/6/1996
  1637. --*/
  1638. #undef __SUBROUTINE__
  1639. #define __SUBROUTINE__ DBGT("CReaderContext::Connect")
  1640. void
  1641. CReaderContext::Connect(
  1642. CSCardSubcontext *pCtx,
  1643. LPCTSTR szReaderName,
  1644. DWORD dwShareMode,
  1645. DWORD dwPreferredProtocols)
  1646. {
  1647. ComConnect comObj;
  1648. ComConnect::CObjConnect_request *pReq;
  1649. ComConnect::CObjConnect_response *pRsp;
  1650. BOOL fSts;
  1651. CBuffer bfDevice;
  1652. ASSERT(SCARD_PROTOCOL_UNDEFINED == m_dwActiveProtocol);
  1653. ASSERT(NULL == m_pCtx);
  1654. if (0 == *szReaderName)
  1655. throw (DWORD)SCARD_E_UNKNOWN_READER;
  1656. fSts = GetReaderInfo(
  1657. pCtx->Scope(),
  1658. szReaderName,
  1659. NULL,
  1660. &bfDevice);
  1661. if (!fSts)
  1662. throw (DWORD)SCARD_E_UNKNOWN_READER;
  1663. pReq = comObj.InitRequest(bfDevice.Length() + sizeof(DWORD));
  1664. pReq->dwShareMode = dwShareMode;
  1665. pReq->dwPreferredProtocols = dwPreferredProtocols;
  1666. pReq = (ComConnect::CObjConnect_request *)comObj.Append(
  1667. pReq->dscReader, bfDevice.Access(), bfDevice.Length());
  1668. pCtx->SendRequest(&comObj);
  1669. comObj.InitResponse(0);
  1670. pRsp = comObj.Receive(pCtx->m_pChannel);
  1671. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  1672. throw pRsp->dwStatus;
  1673. m_hCard = pRsp->hCard;
  1674. m_dwActiveProtocol = pRsp->dwActiveProtocol;
  1675. m_pCtx = pCtx;
  1676. }
  1677. /*++
  1678. Reconnect:
  1679. This method requests the Reconnect service on behalf of the client.
  1680. Arguments:
  1681. dwShareMode supplies the form of sharing to be invoked.
  1682. dwPreferredProtocols supplies the acceptable protocols.
  1683. dwInitialization supplies the card initialization required.
  1684. Return Value:
  1685. None
  1686. Throws:
  1687. Errors are thrown as DWORD status codes.
  1688. Author:
  1689. Doug Barlow (dbarlow) 12/6/1996
  1690. --*/
  1691. #undef __SUBROUTINE__
  1692. #define __SUBROUTINE__ DBGT("CReaderContext::Reconnect")
  1693. void
  1694. CReaderContext::Reconnect(
  1695. DWORD dwShareMode,
  1696. DWORD dwPreferredProtocols,
  1697. DWORD dwInitialization)
  1698. {
  1699. ComReconnect comObj;
  1700. ComReconnect::CObjReconnect_request *pReq;
  1701. ComReconnect::CObjReconnect_response *pRsp;
  1702. CSubctxLock ctxLock(Context());
  1703. pReq = comObj.InitRequest(0);
  1704. pReq->hCard = m_hCard;
  1705. pReq->dwShareMode = dwShareMode;
  1706. pReq->dwPreferredProtocols = dwPreferredProtocols;
  1707. pReq->dwInitialization = dwInitialization;
  1708. Context()->SendRequest(&comObj);
  1709. comObj.InitResponse(0);
  1710. pRsp = comObj.Receive(Context()->m_pChannel);
  1711. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  1712. throw pRsp->dwStatus;
  1713. m_dwActiveProtocol = pRsp->dwActiveProtocol;
  1714. }
  1715. /*++
  1716. Disconnect:
  1717. This method requests the Disconnect service on behalf of the client.
  1718. Arguments:
  1719. dwDisposition - Supplies an indication of what should be done with the card
  1720. in the connected reader.
  1721. Return Value:
  1722. None
  1723. Throws:
  1724. Errors are thrown as DWORD status codes.
  1725. Author:
  1726. Doug Barlow (dbarlow) 12/6/1996
  1727. --*/
  1728. #undef __SUBROUTINE__
  1729. #define __SUBROUTINE__ DBGT("CReaderContext::Disconnect")
  1730. LONG
  1731. CReaderContext::Disconnect(
  1732. DWORD dwDisposition)
  1733. {
  1734. ComDisconnect comObj;
  1735. ComDisconnect::CObjDisconnect_request *pReq;
  1736. ComDisconnect::CObjDisconnect_response *pRsp = NULL;
  1737. CSubctxLock ctxLock(Context());
  1738. try
  1739. {
  1740. pReq = comObj.InitRequest(0);
  1741. pReq->hCard = m_hCard;
  1742. pReq->dwDisposition = dwDisposition;
  1743. Context()->SendRequest(&comObj);
  1744. comObj.InitResponse(0);
  1745. pRsp = comObj.Receive(Context()->m_pChannel);
  1746. }
  1747. catch (...) {}
  1748. if (NULL != m_pCtx)
  1749. {
  1750. Context()->Deallocate();
  1751. m_pCtx = NULL;
  1752. }
  1753. m_dwActiveProtocol = SCARD_PROTOCOL_UNDEFINED;
  1754. m_hCard = INVALID_SCARDHANDLE_VALUE;
  1755. return (NULL != pRsp) ? pRsp->dwStatus : SCARD_E_SERVICE_STOPPED;
  1756. }
  1757. /*++
  1758. BeginTransaction:
  1759. This method requests the BeginTransaction service on behalf of the client.
  1760. Arguments:
  1761. None
  1762. Return Value:
  1763. None
  1764. Throws:
  1765. Errors are thrown as DWORD status codes.
  1766. Author:
  1767. Doug Barlow (dbarlow) 12/6/1996
  1768. --*/
  1769. #undef __SUBROUTINE__
  1770. #define __SUBROUTINE__ DBGT("CReaderContext::BeginTransaction")
  1771. void
  1772. CReaderContext::BeginTransaction(
  1773. void)
  1774. {
  1775. ComBeginTransaction comObj;
  1776. ComBeginTransaction::CObjBeginTransaction_request *pReq;
  1777. ComBeginTransaction::CObjBeginTransaction_response *pRsp;
  1778. CSubctxLock ctxLock(Context());
  1779. pReq = comObj.InitRequest(0);
  1780. pReq->hCard = m_hCard;
  1781. Context()->SendRequest(&comObj);
  1782. comObj.InitResponse(0);
  1783. pRsp = comObj.Receive(Context()->m_pChannel);
  1784. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  1785. throw pRsp->dwStatus;
  1786. }
  1787. /*++
  1788. EndTransaction:
  1789. This method requests the EndTransaction service on behalf of the client.
  1790. Arguments:
  1791. dwDisposition supplies the disposition of the card.
  1792. Return Value:
  1793. None
  1794. Throws:
  1795. Errors are thrown as DWORD status codes.
  1796. Author:
  1797. Doug Barlow (dbarlow) 12/6/1996
  1798. --*/
  1799. #undef __SUBROUTINE__
  1800. #define __SUBROUTINE__ DBGT("CReaderContext::EndTransaction")
  1801. void
  1802. CReaderContext::EndTransaction(
  1803. DWORD dwDisposition)
  1804. {
  1805. DWORD dw;
  1806. if (dwDisposition == SCARD_LEAVE_CARD_FORCE)
  1807. {
  1808. if (INVALID_SCARDHANDLE_VALUE == m_hCard)
  1809. {
  1810. return;
  1811. }
  1812. dw = SCARD_LEAVE_CARD;
  1813. }
  1814. else
  1815. {
  1816. dw = dwDisposition;
  1817. }
  1818. ComEndTransaction comObj;
  1819. ComEndTransaction::CObjEndTransaction_request *pReq;
  1820. ComEndTransaction::CObjEndTransaction_response *pRsp;
  1821. CSubctxLock ctxLock(Context());
  1822. pReq = comObj.InitRequest(0);
  1823. pReq->hCard = m_hCard;
  1824. pReq->dwDisposition = dw;
  1825. Context()->SendRequest(&comObj);
  1826. comObj.InitResponse(0);
  1827. pRsp = comObj.Receive(Context()->m_pChannel);
  1828. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  1829. throw pRsp->dwStatus;
  1830. }
  1831. /*++
  1832. Status:
  1833. This method requests the Status service on behalf of the client.
  1834. Arguments:
  1835. pdwState - This receives the current state of the reader. Upon success, it
  1836. receives one of the following state indicators:
  1837. SCARD_ABSENT - This value implies there is no card in the reader.
  1838. SCARD_PRESENT - This value implies there is a card is present in the
  1839. reader, but that it has not been moved into position for use.
  1840. SCARD_SWALLOWED - This value implies there is a card in the reader in
  1841. position for use. The card is not powered.
  1842. SCARD_POWERED - This value implies there is power is being provided to
  1843. the card, but the Reader Driver is unaware of the mode of the card.
  1844. SCARD_NEGOTIABLEMODE - This value implies the card has been reset and is
  1845. awaiting PTS negotiation.
  1846. SCARD_SPECIFICMODE - This value implies the card has been reset and
  1847. specific communication protocols have been established.
  1848. pdwProtocol - This receives the current protocol, if any. Possible returned
  1849. values are listed below. Other values may be added in the future. The
  1850. returned value is only meaningful if the returned state is
  1851. SCARD_SPECIFICMODE.
  1852. SCARD_PROTOCOL_RAW - The Raw Transfer Protocol is in use.
  1853. SCARD_PROTOCOL_T0 - The ISO 7816/3 T=0 Protocol is in use.
  1854. SCARD_PROTOCOL_T1 - The ISO 7816/3 T=1 Protocol is in use.
  1855. bfAtr - This receives the current ATR, if any.
  1856. bfReaderNames - This receives the list of friendly names assigned to the
  1857. connected reader, as a MultiString.
  1858. Return Value:
  1859. None
  1860. Throws:
  1861. Errors are thrown as DWORD status codes.
  1862. Author:
  1863. Doug Barlow (dbarlow) 11/14/1997
  1864. --*/
  1865. #undef __SUBROUTINE__
  1866. #define __SUBROUTINE__ DBGT("CReaderContext::Status")
  1867. void
  1868. CReaderContext::Status(
  1869. OUT LPDWORD pdwState,
  1870. OUT LPDWORD pdwProtocol,
  1871. OUT CBuffer &bfAtr,
  1872. OUT CBuffer &bfReaderNames)
  1873. {
  1874. ComStatus comObj;
  1875. ComStatus::CObjStatus_request *pReq;
  1876. ComStatus::CObjStatus_response *pRsp;
  1877. CBuffer bfSysName;
  1878. LPCBYTE pbAtr;
  1879. DWORD cbAtr;
  1880. LPCTSTR szSysName;
  1881. CSubctxLock ctxLock(Context());
  1882. pReq = comObj.InitRequest(0);
  1883. pReq->hCard = m_hCard;
  1884. Context()->SendRequest(&comObj);
  1885. comObj.InitResponse(0);
  1886. pRsp = comObj.Receive(Context()->m_pChannel);
  1887. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  1888. throw pRsp->dwStatus;
  1889. *pdwState = pRsp->dwState;
  1890. *pdwProtocol = pRsp->dwProtocol;
  1891. pbAtr = (LPCBYTE)comObj.Parse(pRsp->dscAtr, &cbAtr);
  1892. szSysName = (LPCTSTR)comObj.Parse(pRsp->dscSysName);
  1893. bfAtr.Set(pbAtr, cbAtr);
  1894. ListReaderNames(
  1895. Context()->Scope(),
  1896. szSysName,
  1897. bfReaderNames);
  1898. }
  1899. /*++
  1900. Transmit:
  1901. This method requests the Transmit service on behalf of the client.
  1902. Arguments:
  1903. pioSendPci - This supplies the protocol header structure for the
  1904. instruction.
  1905. pbSendBuffer - This supplies the actual data to be written to the card in
  1906. conjunction with the command.
  1907. cbSendLength - This supplies the length of the pbDataBuffer parameter, in
  1908. bytes.
  1909. pioRecvPci - This receives the return protocol header structure from the
  1910. instruction.
  1911. bfRecvData - This receives any data returned from the card in conjunction
  1912. with the command.
  1913. cbProposedLength - This supplies a maximum length for the received data.
  1914. If this value is zero, then the server uses the default max length.
  1915. Return Value:
  1916. None
  1917. Throws:
  1918. Errors are thrown as DWORD status codes.
  1919. Author:
  1920. Doug Barlow (dbarlow) 12/6/1996
  1921. --*/
  1922. #undef __SUBROUTINE__
  1923. #define __SUBROUTINE__ DBGT("CReaderContext::Transmit")
  1924. void
  1925. CReaderContext::Transmit(
  1926. IN LPCSCARD_IO_REQUEST pioSendPci,
  1927. IN LPCBYTE pbSendBuffer,
  1928. IN DWORD cbSendLength,
  1929. OUT LPSCARD_IO_REQUEST pioRecvPci,
  1930. OUT CBuffer &bfRecvData,
  1931. IN DWORD cbProposedLength)
  1932. {
  1933. static const SCARD_IO_REQUEST ioNullPci = { 0, sizeof(SCARD_IO_REQUEST) };
  1934. ComTransmit comObj;
  1935. ComTransmit::CObjTransmit_request *pReq;
  1936. ComTransmit::CObjTransmit_response *pRsp;
  1937. LPSCARD_IO_REQUEST pioIoreq;
  1938. DWORD cbIoreq, cbData;
  1939. LPCBYTE pbData;
  1940. CSubctxLock ctxLock(Context());
  1941. if (NULL == pioSendPci)
  1942. pioSendPci = &ioNullPci;
  1943. pReq = comObj.InitRequest(pioSendPci->cbPciLength + cbSendLength
  1944. + 2 * sizeof(DWORD)
  1945. + 2 * sizeof(DWORD));
  1946. pReq->hCard = m_hCard;
  1947. pReq->dwPciLength = (NULL == pioRecvPci)
  1948. ? sizeof(SCARD_IO_REQUEST)
  1949. : pioRecvPci->cbPciLength;
  1950. pReq->dwRecvLength = cbProposedLength;
  1951. pReq = (ComTransmit::CObjTransmit_request *)comObj.Append(
  1952. pReq->dscSendPci,
  1953. (LPCBYTE)pioSendPci,
  1954. pioSendPci->cbPciLength);
  1955. pReq = (ComTransmit::CObjTransmit_request *)comObj.Append(
  1956. pReq->dscSendBuffer,
  1957. pbSendBuffer,
  1958. cbSendLength);
  1959. Context()->SendRequest(&comObj);
  1960. comObj.InitResponse(pReq->dwPciLength + pReq->dwRecvLength
  1961. + 2 * sizeof(DWORD));
  1962. pRsp = comObj.Receive(Context()->m_pChannel);
  1963. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  1964. throw pRsp->dwStatus;
  1965. pioIoreq = (LPSCARD_IO_REQUEST)comObj.Parse(pRsp->dscRecvPci, &cbIoreq);
  1966. ASSERT(cbIoreq == pioIoreq->cbPciLength);
  1967. if (NULL != pioRecvPci)
  1968. {
  1969. if (cbIoreq > pioRecvPci->cbPciLength)
  1970. throw (DWORD)SCARD_E_PCI_TOO_SMALL;
  1971. CopyMemory(pioRecvPci, pioIoreq, cbIoreq);
  1972. }
  1973. pbData = (LPCBYTE)comObj.Parse(pRsp->dscRecvBuffer, &cbData);
  1974. bfRecvData.Set(pbData, cbData);
  1975. }
  1976. /*++
  1977. Control:
  1978. This method requests the Control service on behalf of the client.
  1979. Arguments:
  1980. dwControlCode - This supplies the control code for the operation. This value
  1981. identifies the specific operation to be performed.
  1982. pvInBuffer - This supplies a pointer to a buffer that contains the data
  1983. required to perform the operation. This parameter can be NULL if the
  1984. dwControlCode parameter specifies an operation that does not require
  1985. input data.
  1986. cbInBufferSize - This supplies the size, in bytes, of the buffer pointed to
  1987. by pvInBuffer.
  1988. bfOutBuffer - This buffer receives the operation's output data.
  1989. Return Value:
  1990. None
  1991. Throws:
  1992. Errors are thrown as DWORD status codes.
  1993. Author:
  1994. Doug Barlow (dbarlow) 12/6/1996
  1995. --*/
  1996. #undef __SUBROUTINE__
  1997. #define __SUBROUTINE__ DBGT("CReaderContext::Control")
  1998. void
  1999. CReaderContext::Control(
  2000. IN DWORD dwControlCode,
  2001. IN LPCVOID pvInBuffer,
  2002. IN DWORD cbInBufferSize,
  2003. OUT CBuffer &bfOutBuffer)
  2004. {
  2005. ComControl comObj;
  2006. ComControl::CObjControl_request *pReq;
  2007. ComControl::CObjControl_response *pRsp;
  2008. LPCBYTE pbData;
  2009. DWORD cbData;
  2010. CSubctxLock ctxLock(Context());
  2011. pReq = comObj.InitRequest(cbInBufferSize + sizeof(DWORD));
  2012. pReq->hCard = m_hCard;
  2013. pReq->dwControlCode = dwControlCode;
  2014. pReq->dwOutLength = bfOutBuffer.Space();
  2015. pReq = (ComControl::CObjControl_request *)
  2016. comObj.Append(pReq->dscInBuffer, (LPCBYTE)pvInBuffer, cbInBufferSize);
  2017. Context()->SendRequest(&comObj);
  2018. comObj.InitResponse(0);
  2019. pRsp = comObj.Receive(Context()->m_pChannel);
  2020. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  2021. throw pRsp->dwStatus;
  2022. pbData = (LPCBYTE)comObj.Parse(pRsp->dscOutBuffer, &cbData);
  2023. bfOutBuffer.Set(pbData, cbData);
  2024. }
  2025. /*++
  2026. GetAttrib:
  2027. This method requests the GetAttrib service on behalf of the client.
  2028. Arguments:
  2029. dwAttrId - This supplies the identifier for the attribute to get.
  2030. bfAttr - This buffer receives the attribute corresponding to the attribute
  2031. id supplied in the dwAttrId parameter.
  2032. cbProposedLength - This supplies a maximum length for the received data.
  2033. If this value is zero, then the server uses the default max length.
  2034. Return Value:
  2035. None
  2036. Throws:
  2037. Errors are thrown as DWORD status codes.
  2038. Author:
  2039. Doug Barlow (dbarlow) 12/6/1996
  2040. --*/
  2041. #undef __SUBROUTINE__
  2042. #define __SUBROUTINE__ DBGT("CReaderContext::GetAttrib")
  2043. void
  2044. CReaderContext::GetAttrib(
  2045. IN DWORD dwAttrId,
  2046. OUT CBuffer &bfAttr,
  2047. DWORD cbProposedLen)
  2048. {
  2049. ComGetAttrib comObj;
  2050. ComGetAttrib::CObjGetAttrib_request *pReq;
  2051. ComGetAttrib::CObjGetAttrib_response *pRsp;
  2052. LPCBYTE pbData;
  2053. DWORD cbData;
  2054. CSubctxLock ctxLock(Context());
  2055. pReq = comObj.InitRequest(0);
  2056. pReq->hCard = m_hCard;
  2057. pReq->dwAttrId = dwAttrId;
  2058. pReq->dwOutLength = cbProposedLen;
  2059. Context()->SendRequest(&comObj);
  2060. comObj.InitResponse(0);
  2061. pRsp = comObj.Receive(Context()->m_pChannel);
  2062. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  2063. throw pRsp->dwStatus;
  2064. pbData = (LPCBYTE)comObj.Parse(pRsp->dscAttr, &cbData);
  2065. bfAttr.Set(pbData, cbData);
  2066. }
  2067. /*++
  2068. SetAttrib:
  2069. This method requests the SetAttrib service on behalf of the client.
  2070. Arguments:
  2071. dwAttrId - This supplies the identifier for the attribute to get.
  2072. pbAttr - This buffer supplies the attribute corresponding to the attribute
  2073. id supplied in the dwAttrId parameter.
  2074. cbAttrLength - This supplies the length of the attribute value in pbAttr
  2075. buffer in bytes.
  2076. Return Value:
  2077. None
  2078. Throws:
  2079. Errors are thrown as DWORD status codes.
  2080. Author:
  2081. Doug Barlow (dbarlow) 12/6/1996
  2082. --*/
  2083. #undef __SUBROUTINE__
  2084. #define __SUBROUTINE__ DBGT("CReaderContext::SetAttrib")
  2085. void
  2086. CReaderContext::SetAttrib(
  2087. IN DWORD dwAttrId,
  2088. IN LPCBYTE pbAttr,
  2089. IN DWORD cbAttrLen)
  2090. {
  2091. ComSetAttrib comObj;
  2092. ComSetAttrib::CObjSetAttrib_request *pReq;
  2093. ComSetAttrib::CObjSetAttrib_response *pRsp;
  2094. CSubctxLock ctxLock(Context());
  2095. pReq = comObj.InitRequest(0);
  2096. pReq->hCard = m_hCard;
  2097. pReq->dwAttrId = dwAttrId;
  2098. pReq = (ComSetAttrib::CObjSetAttrib_request *)
  2099. comObj.Append(pReq->dscAttr, pbAttr, cbAttrLen);
  2100. Context()->SendRequest(&comObj);
  2101. comObj.InitResponse(0);
  2102. pRsp = comObj.Receive(Context()->m_pChannel);
  2103. if (SCARD_S_SUCCESS != pRsp->dwStatus)
  2104. throw pRsp->dwStatus;
  2105. }