Source code of Windows XP (NT5)
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.

887 lines
18 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: ifdrdr.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include <stdarg.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <conio.h>
  14. #include <afx.h>
  15. #include <afxtempl.h>
  16. #include <winioctl.h>
  17. #include <winsmcrd.h>
  18. #include "ifdtest.h"
  19. ULONG CReaderList::m_uRefCount;
  20. ULONG CReaderList::m_uNumReaders;
  21. CReaderList **CReaderList::m_pList;
  22. static CString l_CEmpty("");
  23. void
  24. DumpData(
  25. PCHAR in_pchCaption,
  26. ULONG in_uIndent,
  27. PBYTE in_pbData,
  28. ULONG in_uLength)
  29. {
  30. ULONG l_uIndex, l_uLine, l_uCol;
  31. printf("%s\n%*s%04x: ", in_pchCaption, in_uIndent, "", 0);
  32. for (l_uLine = 0, l_uIndex = 0;
  33. l_uLine < ((in_uLength - 1) / 8) + 1;
  34. l_uLine++) {
  35. for (l_uCol = 0, l_uIndex = l_uLine * 8;
  36. l_uCol < 8; l_uCol++,
  37. l_uIndex++) {
  38. printf(
  39. l_uIndex < in_uLength ? "%02x " : " ",
  40. in_pbData[l_uIndex]
  41. );
  42. }
  43. putchar(' ');
  44. for (l_uCol = 0, l_uIndex = l_uLine * 8;
  45. l_uCol < 8; l_uCol++,
  46. l_uIndex++) {
  47. printf(
  48. l_uIndex < in_uLength ? "%c" : " ",
  49. isprint(in_pbData[l_uIndex]) ? in_pbData[l_uIndex] : '.'
  50. );
  51. }
  52. putchar('\n');
  53. if (l_uIndex < in_uLength) {
  54. printf("%*s%04x: ", in_uIndent, "", l_uIndex + 1);
  55. }
  56. }
  57. }
  58. CReaderList::CReaderList(
  59. CString &in_CDeviceName,
  60. CString &in_CPnPType,
  61. CString &in_CVendorName,
  62. CString &in_CIfdType
  63. )
  64. {
  65. m_CDeviceName += in_CDeviceName;
  66. m_CPnPType += in_CPnPType;
  67. m_CVendorName += in_CVendorName;
  68. m_CIfdType += in_CIfdType;
  69. }
  70. CString &
  71. CReaderList::GetDeviceName(
  72. ULONG in_uIndex
  73. )
  74. /*++
  75. Routine Description:
  76. Retrieves the device name of a reader
  77. Arguments:
  78. in_uIndex - index to reader list
  79. Return Value:
  80. The device name that can be used to open the reader
  81. --*/
  82. {
  83. if (in_uIndex >= m_uNumReaders) {
  84. return l_CEmpty;
  85. }
  86. return m_pList[in_uIndex]->m_CDeviceName;
  87. }
  88. CString &
  89. CReaderList::GetIfdType(
  90. ULONG in_uIndex
  91. )
  92. {
  93. if (in_uIndex >= m_uNumReaders) {
  94. return l_CEmpty;
  95. }
  96. return m_pList[in_uIndex]->m_CIfdType;
  97. }
  98. CString &
  99. CReaderList::GetPnPType(
  100. ULONG in_uIndex
  101. )
  102. {
  103. if (in_uIndex >= m_uNumReaders) {
  104. return l_CEmpty;
  105. }
  106. return m_pList[in_uIndex]->m_CPnPType;
  107. }
  108. CString &
  109. CReaderList::GetVendorName(
  110. ULONG in_uIndex
  111. )
  112. {
  113. if (in_uIndex >= m_uNumReaders) {
  114. return l_CEmpty;
  115. }
  116. return m_pList[in_uIndex]->m_CVendorName;
  117. }
  118. void
  119. CReaderList::AddDevice(
  120. CString in_CDeviceName,
  121. CString in_CPnPType
  122. )
  123. /*++
  124. Routine Description:
  125. This functions tries to open the reader device supplied by
  126. in_pchDeviceName. If the device exists it adds it to the list
  127. of installed readers
  128. Arguments:
  129. in_pchDeviceName - reader device name
  130. in_pchPnPType - type of reader (wdm-pnp, nt, win9x)
  131. --*/
  132. {
  133. CReader l_CReader;
  134. if (l_CReader.Open(in_CDeviceName)) {
  135. if (l_CReader.GetVendorName().IsEmpty()) {
  136. LogMessage(
  137. "VendorName of reader device %s is NULL",
  138. (LPCSTR) in_CDeviceName
  139. );
  140. } else if (l_CReader.GetIfdType().IsEmpty()) {
  141. LogMessage(
  142. "IfdType of reader device %s is NULL",
  143. (LPCSTR) in_CDeviceName
  144. );
  145. } else {
  146. CReaderList *l_CReaderList = new CReaderList(
  147. in_CDeviceName,
  148. in_CPnPType,
  149. l_CReader.GetVendorName(),
  150. l_CReader.GetIfdType()
  151. );
  152. // extend the device list array by one
  153. CReaderList **l_pList =
  154. new CReaderList *[m_uNumReaders + 1];
  155. if (m_pList) {
  156. // copy old list of readers to new list of readers
  157. memcpy(
  158. l_pList,
  159. m_pList,
  160. m_uNumReaders * sizeof(CReaderList *)
  161. );
  162. delete m_pList;
  163. }
  164. m_pList = l_pList;
  165. m_pList[m_uNumReaders++] = l_CReaderList;
  166. }
  167. l_CReader.Close();
  168. }
  169. }
  170. CReaderList::CReaderList()
  171. /*++
  172. Routine Description:
  173. Constructor for CReaderList.
  174. Builds a list of currently installed and running smart card readers.
  175. It first tries to find all WDM PnP drivers. These should be registered
  176. in the registry under the class guid for smart card readers.
  177. Then it looks for all 'old style' reader names like \\.\SCReaderN
  178. And then it looks for all Windows 9x VxD style readers, which are
  179. registered in the registry through smclib.vxd
  180. --*/
  181. {
  182. HKEY l_hKey;
  183. ULONG l_uIndex;
  184. m_uCurrentReader = (ULONG) -1;
  185. if (m_uRefCount++ != 0) {
  186. return;
  187. }
  188. // look up all WDM PnP smart card readers
  189. if (RegOpenKey(
  190. HKEY_LOCAL_MACHINE,
  191. "System\\CurrentControlSet\\Control\\DeviceClasses\\{50DD5230-BA8A-11D1-BF5D-0000F805F530}",
  192. &l_hKey) == ERROR_SUCCESS) {
  193. ULONG l_uStatus, l_uIndex;
  194. for (l_uIndex = 0; ;l_uIndex++) {
  195. HKEY l_hDeviceTypeKey;
  196. UCHAR l_rgchDeviceTypeKey[128];
  197. ULONG l_uDeviceTypeInstance = 0;
  198. // look up 'device type subkey'
  199. l_uStatus = RegEnumKey(
  200. l_hKey,
  201. l_uIndex,
  202. (PCHAR) l_rgchDeviceTypeKey,
  203. sizeof(l_rgchDeviceTypeKey)
  204. );
  205. if (l_uStatus != ERROR_SUCCESS) {
  206. // no smart card device types found
  207. break;
  208. }
  209. // open the found 'device type subkey'
  210. l_uStatus = RegOpenKey(
  211. l_hKey,
  212. (PCHAR) l_rgchDeviceTypeKey,
  213. &l_hDeviceTypeKey
  214. );
  215. if (l_uStatus != ERROR_SUCCESS) {
  216. continue;
  217. }
  218. for (l_uDeviceTypeInstance = 0; ; l_uDeviceTypeInstance++) {
  219. DWORD l_dwKeyType;
  220. HKEY l_hDeviceTypeInstanceKey;
  221. UCHAR l_rgchDeviceName[128];
  222. UCHAR l_rgchDeviceTypeInstanceKey[128];
  223. ULONG l_uDeviceNameLen = sizeof(l_rgchDeviceName);
  224. // look up device instance subkey
  225. l_uStatus = RegEnumKey(
  226. l_hDeviceTypeKey,
  227. l_uDeviceTypeInstance,
  228. (PCHAR) l_rgchDeviceTypeInstanceKey,
  229. sizeof(l_rgchDeviceTypeInstanceKey)
  230. );
  231. if (l_uStatus != ERROR_SUCCESS) {
  232. // no instance of the smart card reader type found
  233. break;
  234. }
  235. // open the found 'device type instance subkey'
  236. l_uStatus = RegOpenKey(
  237. l_hDeviceTypeKey,
  238. (PCHAR) l_rgchDeviceTypeInstanceKey,
  239. &l_hDeviceTypeInstanceKey
  240. );
  241. if (l_uStatus != ERROR_SUCCESS) {
  242. continue;
  243. }
  244. // get the name of the device
  245. if (RegQueryValueEx(
  246. l_hDeviceTypeInstanceKey,
  247. "SymbolicLink",
  248. NULL,
  249. &l_dwKeyType,
  250. l_rgchDeviceName,
  251. &l_uDeviceNameLen) == ERROR_SUCCESS) {
  252. AddDevice(l_rgchDeviceName, READER_TYPE_WDM);
  253. }
  254. }
  255. }
  256. }
  257. // Now look up all non PnP readers
  258. for (l_uIndex = 0; l_uIndex < MAXIMUM_SMARTCARD_READERS; l_uIndex++) {
  259. UCHAR l_rgchDeviceName[128];
  260. sprintf(
  261. (PCHAR) l_rgchDeviceName,
  262. "\\\\.\\SCReader%d",
  263. l_uIndex
  264. );
  265. AddDevice(l_rgchDeviceName, READER_TYPE_NT);
  266. }
  267. // Add all Windows95 type readers to the list
  268. if (RegOpenKey(
  269. HKEY_LOCAL_MACHINE,
  270. "System\\CurrentControlSet\\Services\\VxD\\Smclib\\Devices",
  271. &l_hKey) == ERROR_SUCCESS) {
  272. ULONG l_uIndex;
  273. for (l_uIndex = 0; l_uIndex < MAXIMUM_SMARTCARD_READERS; l_uIndex++) {
  274. UCHAR l_rgchDeviceName[128], l_rgchValueName[128];
  275. DWORD l_dwValueType;
  276. ULONG l_uDeviceNameLen = sizeof(l_rgchDeviceName);
  277. ULONG l_uValueNameLen = sizeof(l_rgchValueName);
  278. if (RegEnumValue(
  279. l_hKey,
  280. l_uIndex,
  281. (PCHAR) l_rgchValueName,
  282. &l_uValueNameLen,
  283. NULL,
  284. &l_dwValueType,
  285. (PUCHAR) l_rgchDeviceName,
  286. &l_uDeviceNameLen) == ERROR_SUCCESS) {
  287. AddDevice(CString("\\\\.\\") + l_rgchDeviceName, READER_TYPE_VXD);
  288. }
  289. }
  290. }
  291. }
  292. CReaderList::~CReaderList()
  293. {
  294. ULONG l_uIndex;
  295. if (--m_uRefCount != 0) {
  296. return;
  297. }
  298. for (l_uIndex = 0; l_uIndex < m_uNumReaders; l_uIndex++) {
  299. delete m_pList[l_uIndex];
  300. }
  301. if (m_pList) {
  302. delete m_pList;
  303. }
  304. }
  305. // ****************************************************************************
  306. // CReader methods
  307. // ****************************************************************************
  308. CReader::CReader(
  309. void
  310. )
  311. {
  312. m_uReplyBufferSize = sizeof(m_rgbReplyBuffer);
  313. m_Ovr.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  314. ResetEvent(m_Ovr.hEvent);
  315. m_OvrWait.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  316. ResetEvent(m_OvrWait.hEvent);
  317. m_ScardIoRequest.dwProtocol = 0;
  318. m_ScardIoRequest.cbPciLength = sizeof(m_ScardIoRequest);
  319. m_fDump = FALSE;
  320. }
  321. void
  322. CReader::Close(
  323. void
  324. )
  325. {
  326. #ifndef SIMULATE
  327. CloseHandle(m_hReader);
  328. #endif
  329. }
  330. CString &
  331. CReader::GetIfdType(
  332. void
  333. )
  334. {
  335. ULONG l_uAttr = SCARD_ATTR_VENDOR_IFD_TYPE;
  336. #ifdef SIMULATE
  337. m_CIfdType = "DEBUG IfdType";
  338. #endif
  339. if (m_CIfdType.IsEmpty()) {
  340. BOOL l_bResult = DeviceIoControl(
  341. m_hReader,
  342. IOCTL_SMARTCARD_GET_ATTRIBUTE,
  343. (void *) &l_uAttr,
  344. sizeof(ULONG),
  345. m_rgbReplyBuffer,
  346. sizeof(m_rgbReplyBuffer),
  347. &m_uReplyLength,
  348. &m_Ovr
  349. );
  350. if (l_bResult) {
  351. m_rgbReplyBuffer[m_uReplyLength] = '\0';
  352. m_CIfdType = m_rgbReplyBuffer;
  353. }
  354. }
  355. return m_CIfdType;
  356. }
  357. LONG
  358. CReader::GetState(
  359. PULONG out_puState
  360. )
  361. {
  362. SetLastError(0);
  363. BOOL l_bResult = DeviceIoControl(
  364. m_hReader,
  365. IOCTL_SMARTCARD_GET_STATE,
  366. NULL,
  367. 0,
  368. (void *) out_puState,
  369. sizeof(ULONG),
  370. &m_uReplyLength,
  371. &m_Ovr
  372. );
  373. return GetLastError();
  374. }
  375. CString &
  376. CReader::GetVendorName(
  377. void
  378. )
  379. {
  380. ULONG l_uAttr = SCARD_ATTR_VENDOR_NAME;
  381. #ifdef SIMULATE
  382. m_CVendorName = "DEBUG Vendor";
  383. #endif
  384. if (m_CVendorName.IsEmpty()) {
  385. BOOL l_bResult = DeviceIoControl(
  386. m_hReader,
  387. IOCTL_SMARTCARD_GET_ATTRIBUTE,
  388. (void *) &l_uAttr,
  389. sizeof(ULONG),
  390. m_rgbReplyBuffer,
  391. sizeof(m_rgbReplyBuffer),
  392. &m_uReplyLength,
  393. &m_Ovr
  394. );
  395. if (l_bResult) {
  396. m_rgbReplyBuffer[m_uReplyLength] = '\0';
  397. m_CVendorName = m_rgbReplyBuffer;
  398. }
  399. }
  400. return m_CVendorName;
  401. }
  402. ULONG
  403. CReader::GetDeviceUnit(
  404. void
  405. )
  406. {
  407. ULONG l_uAttr = SCARD_ATTR_DEVICE_UNIT;
  408. BOOL l_bResult = DeviceIoControl(
  409. m_hReader,
  410. IOCTL_SMARTCARD_GET_ATTRIBUTE,
  411. (void *) &l_uAttr,
  412. sizeof(ULONG),
  413. m_rgbReplyBuffer,
  414. sizeof(m_rgbReplyBuffer),
  415. &m_uReplyLength,
  416. &m_Ovr
  417. );
  418. return (ULONG) *m_rgbReplyBuffer;
  419. }
  420. BOOL
  421. CReader::Open(
  422. void
  423. )
  424. {
  425. if (m_CDeviceName.IsEmpty()) {
  426. return FALSE;
  427. }
  428. // Try to open the reader.
  429. m_hReader = CreateFile(
  430. (LPCSTR) m_CDeviceName,
  431. GENERIC_READ | GENERIC_WRITE,
  432. 0,
  433. NULL,
  434. OPEN_EXISTING,
  435. FILE_FLAG_OVERLAPPED,
  436. NULL
  437. );
  438. if (m_hReader == INVALID_HANDLE_VALUE ) {
  439. return FALSE;
  440. }
  441. return TRUE;
  442. }
  443. BOOL
  444. CReader::Open(
  445. CString & in_CDeviceName
  446. )
  447. {
  448. // save the reader name
  449. m_CDeviceName += in_CDeviceName;
  450. #ifdef SIMULATE
  451. return TRUE;
  452. #endif
  453. return Open();
  454. }
  455. LONG
  456. CReader::PowerCard(
  457. ULONG in_uMinorIoControl
  458. )
  459. /*++
  460. Routine Description:
  461. Cold resets the current card and sets the ATR
  462. of the card in the reader class.
  463. Return Value:
  464. Returns the result of the DeviceIoControl call
  465. --*/
  466. {
  467. BOOL l_bResult;
  468. ULONG l_uReplyLength;
  469. CHAR l_rgbAtr[SCARD_ATR_LENGTH];
  470. SetLastError(0);
  471. l_bResult = DeviceIoControl (
  472. m_hReader,
  473. IOCTL_SMARTCARD_POWER,
  474. &in_uMinorIoControl,
  475. sizeof(in_uMinorIoControl),
  476. l_rgbAtr,
  477. sizeof(l_rgbAtr),
  478. &l_uReplyLength,
  479. &m_Ovr
  480. );
  481. if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
  482. SetLastError(0);
  483. l_bResult = GetOverlappedResult(
  484. m_hReader,
  485. &m_Ovr,
  486. &l_uReplyLength,
  487. TRUE
  488. );
  489. }
  490. if (GetLastError() == ERROR_SUCCESS) {
  491. SetAtr((PBYTE) l_rgbAtr, l_uReplyLength);
  492. }
  493. return GetLastError();
  494. }
  495. LONG
  496. CReader::SetProtocol(
  497. const ULONG in_uProtocol
  498. )
  499. {
  500. BOOL l_bResult;
  501. m_ScardIoRequest.dwProtocol = in_uProtocol;
  502. m_ScardIoRequest.cbPciLength = sizeof(SCARD_IO_REQUEST);
  503. SetLastError(0);
  504. l_bResult = DeviceIoControl (
  505. m_hReader,
  506. IOCTL_SMARTCARD_SET_PROTOCOL,
  507. (void *) &in_uProtocol,
  508. sizeof(ULONG),
  509. m_rgbReplyBuffer,
  510. sizeof(m_rgbReplyBuffer),
  511. &m_uReplyLength,
  512. &m_Ovr
  513. );
  514. if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
  515. SetLastError(0);
  516. l_bResult = GetOverlappedResult(
  517. m_hReader,
  518. &m_Ovr,
  519. &m_uReplyLength,
  520. TRUE
  521. );
  522. }
  523. return GetLastError();
  524. }
  525. LONG
  526. CReader::Transmit(
  527. PUCHAR in_pchApdu,
  528. ULONG in_uApduLength,
  529. PUCHAR *out_pchReply,
  530. PULONG out_puReplyLength
  531. )
  532. /*++
  533. Routine Description:
  534. Transmits an apdu using the currently connected reader
  535. Arguments:
  536. in_pchApdu - the apdu to send
  537. in_uApduLength - the length of the apdu
  538. out_pchReply - result returned from the reader/card
  539. out_puReplyLength - pointer to store number of bytes returned
  540. Return Value:
  541. The nt-status code returned by the reader
  542. --*/
  543. {
  544. BOOL l_bResult;
  545. ULONG l_uBufferLength = m_ScardIoRequest.cbPciLength + in_uApduLength;
  546. PUCHAR l_pchBuffer = new UCHAR [l_uBufferLength];
  547. // Copy io-request header to request buffer
  548. memcpy(
  549. l_pchBuffer,
  550. &m_ScardIoRequest,
  551. m_ScardIoRequest.cbPciLength
  552. );
  553. // copy io-request header to reply buffer
  554. memcpy(
  555. m_rgbReplyBuffer,
  556. &m_ScardIoRequest,
  557. m_ScardIoRequest.cbPciLength
  558. );
  559. // append apdu to buffer
  560. memcpy(
  561. l_pchBuffer + m_ScardIoRequest.cbPciLength,
  562. in_pchApdu,
  563. in_uApduLength
  564. );
  565. if (m_fDump) {
  566. DumpData(
  567. "\n RequestData:",
  568. 3,
  569. l_pchBuffer,
  570. l_uBufferLength
  571. );
  572. }
  573. SetLastError(0);
  574. // send the request to the card
  575. l_bResult = DeviceIoControl (
  576. m_hReader,
  577. IOCTL_SMARTCARD_TRANSMIT,
  578. l_pchBuffer,
  579. l_uBufferLength,
  580. m_rgbReplyBuffer,
  581. m_uReplyBufferSize,
  582. &m_uReplyLength,
  583. &m_Ovr
  584. );
  585. if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
  586. // wait for result
  587. SetLastError(0);
  588. l_bResult = GetOverlappedResult(
  589. m_hReader,
  590. &m_Ovr,
  591. &m_uReplyLength,
  592. TRUE
  593. );
  594. }
  595. if (m_fDump) {
  596. printf(" IOCTL returned %lxh\n", GetLastError());
  597. if (l_bResult) {
  598. DumpData(
  599. " ReplyData:",
  600. 3,
  601. m_rgbReplyBuffer,
  602. m_uReplyLength
  603. );
  604. }
  605. printf("%*s", 53, "");
  606. }
  607. *out_pchReply = (PUCHAR) m_rgbReplyBuffer + m_ScardIoRequest.cbPciLength;
  608. *out_puReplyLength = m_uReplyLength - m_ScardIoRequest.cbPciLength;
  609. delete l_pchBuffer;
  610. return GetLastError();
  611. }
  612. LONG
  613. CReader::VendorIoctl(
  614. CString &o_Answer
  615. )
  616. {
  617. BOOL l_bResult = DeviceIoControl(
  618. m_hReader,
  619. CTL_CODE(FILE_DEVICE_SMARTCARD, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS),
  620. NULL,
  621. NULL,
  622. m_rgbReplyBuffer,
  623. sizeof(m_rgbReplyBuffer),
  624. &m_uReplyLength,
  625. &m_Ovr
  626. );
  627. if (l_bResult) {
  628. m_rgbReplyBuffer[m_uReplyLength] = '\0';
  629. o_Answer = CString(m_rgbReplyBuffer);
  630. }
  631. return GetLastError();
  632. }
  633. LONG
  634. CReader::WaitForCard(
  635. const ULONG in_uWaitFor
  636. )
  637. {
  638. BOOL l_bResult;
  639. ULONG l_uReplyLength;
  640. SetLastError(0);
  641. l_bResult = DeviceIoControl (
  642. m_hReader,
  643. in_uWaitFor,
  644. NULL,
  645. 0,
  646. NULL,
  647. 0,
  648. &l_uReplyLength,
  649. &m_Ovr
  650. );
  651. if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
  652. SetLastError(0);
  653. l_bResult = GetOverlappedResult(
  654. m_hReader,
  655. &m_Ovr,
  656. &l_uReplyLength,
  657. TRUE
  658. );
  659. }
  660. return GetLastError();
  661. }
  662. LONG
  663. CReader::StartWaitForCard(
  664. const ULONG in_uWaitFor
  665. )
  666. {
  667. BOOL l_bResult;
  668. ULONG l_uReplyLength;
  669. ResetEvent(m_OvrWait.hEvent);
  670. l_bResult = DeviceIoControl (
  671. m_hReader,
  672. in_uWaitFor,
  673. NULL,
  674. 0,
  675. NULL,
  676. 0,
  677. &l_uReplyLength,
  678. &m_OvrWait
  679. );
  680. return GetLastError();
  681. }
  682. LONG
  683. CReader::FinishWaitForCard(
  684. const BOOL in_bWait
  685. )
  686. {
  687. BOOL l_bResult;
  688. ULONG l_uReplyLength;
  689. SetLastError(0);
  690. l_bResult = GetOverlappedResult(
  691. m_hReader,
  692. &m_OvrWait,
  693. &l_uReplyLength,
  694. in_bWait
  695. );
  696. return GetLastError();
  697. }