1/* 2 * Copyright (c) 2000-2007 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * winscard_clnt.c 26 * SmartCardServices 27 */ 28 29/* 30 * MUSCLE SmartCard Development ( http://www.linuxnet.com ) 31 * 32 * Copyright (C) 1999-2004 33 * David Corcoran <corcoran@linuxnet.com> 34 * Damien Sauveron <damien.sauveron@labri.fr> 35 * Ludovic Rousseau <ludovic.rousseau@free.fr> 36 * 37 * $Id: winscard_clnt.c 123 2010-03-27 10:50:42Z ludovic.rousseau@gmail.com $ 38 */ 39 40/** 41 * @file 42 * @brief This handles smartcard reader communications and 43 * forwarding requests over message queues. 44 * 45 * Here is exposed the API for client applications. 46 */ 47 48#include <assert.h> 49#include "config.h" 50#include <stdlib.h> 51#include <string.h> 52#include <sys/types.h> 53#include <fcntl.h> 54#include <unistd.h> 55#include <sys/un.h> 56#include <errno.h> 57#include <sys/socket.h> 58#include <sys/ioctl.h> 59#include <sys/_endian.h> 60 61#include "wintypes.h" 62#include "pcsclite.h" 63#include "pcscexport.h" 64#include "winscard.h" 65#include "debug.h" 66#include "thread_generic.h" 67 68#include "readerfactory.h" 69#include "eventhandler.h" 70#include "sys_generic.h" 71#include "winscard_msg.h" 72#include "readerstate.h" 73 74#include <security_utilities/debugging.h> 75 76/** used for backward compatibility */ 77#define SCARD_PROTOCOL_ANY_OLD 0x1000 78 79#ifndef min 80#define min(a,b) (((a) < (b)) ? (a) : (b)) 81#endif 82 83#define PROFILE_START 84#define PROFILE_END 85 86/** 87 * Represents an Application Context Channel. 88 * A channel belongs to an Application Context (\c _psContextMap). 89 */ 90struct _psChannelMap 91{ 92 SCARDHANDLE hCard; 93 LPSTR readerName; 94}; 95 96typedef struct _psChannelMap CHANNEL_MAP, *PCHANNEL_MAP; 97 98/** 99 * @brief Represents the an Application Context on the Client side. 100 * 101 * An Application Context contains Channels (\c _psChannelMap). 102 */ 103static struct _psContextMap 104{ 105 DWORD dwClientID; /** Client Connection ID */ 106 SCARDCONTEXT hContext; /** Application Context ID */ 107 DWORD contextBlockStatus; 108 PCSCLITE_MUTEX_T mMutex; /** Mutex for this context */ 109 CHANNEL_MAP psChannelMap[PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS]; 110} psContextMap[PCSCLITE_MAX_APPLICATION_CONTEXTS]; 111 112/** 113 * Make sure the initialization code is executed only once. 114 */ 115static short isExecuted = 0; 116 117/** 118 * Memory mapped address used to read status information about the readers. 119 * Each element in the vector \ref readerStates makes references to a part of 120 * the memory mapped. 121 */ 122static int mapAddr = 0; 123 124/** 125 * Ensure that some functions be accessed in thread-safe mode. 126 * These function's names finishes with "TH". 127 */ 128static PCSCLITE_MUTEX clientMutex = PTHREAD_MUTEX_INITIALIZER; 129 130/** 131 * Pointers to a memory mapped area used to read status information about the 132 * readers. 133 * Each element in the vector \ref readerStates makes references to a part of 134 * the memory mapped \ref mapAddr. 135 */ 136static PREADER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]; 137 138PCSC_API SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, 8 }; 139PCSC_API SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, 8 }; 140PCSC_API SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, 8 }; 141 142 143static LONG SCardAddContext(SCARDCONTEXT, DWORD); 144static LONG SCardGetContextIndice(SCARDCONTEXT); 145static LONG SCardGetContextIndiceTH(SCARDCONTEXT); 146static LONG SCardRemoveContext(SCARDCONTEXT); 147 148static LONG SCardAddHandle(SCARDHANDLE, DWORD, LPSTR); 149static LONG SCardGetIndicesFromHandle(SCARDHANDLE, PDWORD, PDWORD); 150static LONG SCardGetIndicesFromHandleTH(SCARDHANDLE, PDWORD, PDWORD); 151static LONG SCardRemoveHandle(SCARDHANDLE); 152 153static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId, 154 LPBYTE pbAttr, LPDWORD pcbAttrLen); 155 156static LONG SCardCheckDaemonAvailability(void); 157static int SCardInitializeOnce(); 158 159static int SHMClientCommunicationTimeout(); 160 161/* 162 * Thread safety functions 163 */ 164inline static LONG SCardLockThread(void); 165inline static LONG SCardUnlockThread(void); 166 167static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT); 168 169/** 170 * @brief Creates an Application Context to the PC/SC Resource Manager. 171 172 * This must be the first function called in a PC/SC application. 173 * This is a thread-safe wrapper to the function SCardEstablishContextTH(). 174 * 175 * @param[in] dwScope Scope of the establishment. 176 * This can either be a local or remote connection. 177 * <ul> 178 * <li>\ref SCARD_SCOPE_USER - Not used. 179 * <li>\ref SCARD_SCOPE_TERMINAL - Not used. 180 * <li>\ref SCARD_SCOPE_GLOBAL - Not used. 181 * <li>\ref SCARD_SCOPE_SYSTEM - Services on the local machine. 182 * </ul> 183 * @param[in] pvReserved1 Reserved for future use. Can be used for remote connection. 184 * @param[in] pvReserved2 Reserved for future use. 185 * @param[out] phContext Returned Application Context. 186 * 187 * @return Connection status. 188 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 189 * @retval SCARD_E_NO_SERVICE The server is not runing (\ref SCARD_E_NO_SERVICE) 190 * @retval SCARD_E_INVALID_VALUE Invalid scope type passed (\ref SCARD_E_INVALID_VALUE ) 191 * @retval SCARD_E_INVALID_PARAMETER phContext is null (\ref SCARD_E_INVALID_PARAMETER) 192 * 193 * @test 194 * @code 195 * SCARDCONTEXT hContext; 196 * LONG rv; 197 * ... 198 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 199 * @endcode 200 */ 201LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, 202 LPCVOID pvReserved2, LPSCARDCONTEXT phContext) 203{ 204 LONG rv; 205 206 PROFILE_START 207 208 SCardLockThread(); 209 rv = SCardEstablishContextTH(dwScope, pvReserved1, 210 pvReserved2, phContext); 211 SCardUnlockThread(); 212 213 PROFILE_END 214 215 return rv; 216} 217 218/** 219 * @brief Creates a communication context to the PC/SC Resource 220 * Manager. 221 * 222 * This function shuld not be called directly. Instead, the thread-safe 223 * function SCardEstablishContext() should be called. 224 * 225 * @param[in] dwScope Scope of the establishment. 226 * This can either be a local or remote connection. 227 * <ul> 228 * <li>\ref SCARD_SCOPE_USER - Not used. 229 * <li>\ref SCARD_SCOPE_TERMINAL - Not used. 230 * <li>\ref SCARD_SCOPE_GLOBAL - Not used. 231 * <li>\ref SCARD_SCOPE_SYSTEM - Services on the local machine. 232 * </ul> 233 * @param[in] pvReserved1 Reserved for future use. Can be used for remote connection. 234 * @param[in] pvReserved2 Reserved for future use. 235 * @param[out] phContext Returned reference to this connection. 236 * 237 * @return Connection status. 238 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 239 * @retval SCARD_E_NO_SERVICE The server is not runing (\ref SCARD_E_NO_SERVICE) 240 * @retval SCARD_E_INVALID_PARAMETER phContext is null. (\ref SCARD_E_INVALID_PARAMETER) 241 * @retval SCARD_E_INVALID_VALUE Invalid scope type passed (\ref SCARD_E_INVALID_VALUE) 242 */ 243static LONG SCardEstablishContextTH(DWORD dwScope, LPCVOID pvReserved1, 244 LPCVOID pvReserved2, LPSCARDCONTEXT phContext) 245{ 246 LONG rv; 247 establish_struct scEstablishStruct; 248 sharedSegmentMsg msgStruct; 249 DWORD dwClientID = 0; 250 251 if (phContext == NULL) 252 return SCARD_E_INVALID_PARAMETER; 253 else 254 *phContext = 0; 255 256 /* Check if the server is running */ 257 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 258 return SCARD_E_NO_SERVICE; 259 260 /* 261 * Do this only once: 262 * - Initialize debug of need. 263 * - Set up the memory mapped structures for reader states. 264 * - Allocate each reader structure. 265 * - Initialize context struct. 266 */ 267 if (isExecuted == 0) 268 { 269 SCardInitializeOnce(); 270 isExecuted = 1; 271 } 272 273 /* Establishes a connection to the server */ 274 if (SHMClientSetupSession(&dwClientID) != 0) 275 { 276 SYS_CloseFile(mapAddr); 277 return SCARD_E_NO_SERVICE; 278 } 279 280 { /* exchange client/server protocol versions */ 281 sharedSegmentMsg msgStruct; 282 version_struct *veStr = (version_struct *)&msgStruct.data; 283 veStr->major = PROTOCOL_VERSION_MAJOR; 284 veStr->minor = PROTOCOL_VERSION_MINOR; 285 htonlVersionStruct(veStr); 286 287 if (-1 == WrapSHMWrite(CMD_VERSION, dwClientID, sizeof(version_struct), SHMClientCommunicationTimeout(), veStr)) 288 return SCARD_E_NO_SERVICE; 289 290 /* 291 * Read a message from the server 292 */ 293 if (-1 == SHMClientReadMessage(&msgStruct, dwClientID, sizeof(version_struct), SHMClientCommunicationTimeout())) 294 { 295 Log1(PCSC_LOG_ERROR, "Your pcscd is too old and does not support CMD_VERSION"); 296 return SCARD_F_COMM_ERROR; 297 } 298 299 ntohlVersionStruct(veStr); 300 Log3(PCSC_LOG_ERROR, "Server is protocol version %d:%d", 301 veStr->major, veStr->minor); 302 303 if (veStr->rv != SCARD_S_SUCCESS) 304 return veStr->rv; 305 } 306 307 if (dwScope != SCARD_SCOPE_USER && dwScope != SCARD_SCOPE_TERMINAL && 308 dwScope != SCARD_SCOPE_SYSTEM && dwScope != SCARD_SCOPE_GLOBAL) 309 { 310 return SCARD_E_INVALID_VALUE; 311 } 312 313 /* 314 * Try to establish an Application Context with the server 315 */ 316 scEstablishStruct.dwScope = dwScope; 317 scEstablishStruct.phContext = 0; 318 scEstablishStruct.rv = 0; 319 320 htonlEstablishStruct(&scEstablishStruct); 321 rv = WrapSHMWrite(SCARD_ESTABLISH_CONTEXT, dwClientID, 322 sizeof(scEstablishStruct), PCSCLITE_MCLIENT_ATTEMPTS, 323 (void *) &scEstablishStruct); 324 325 if (rv == -1) 326 return SCARD_E_NO_SERVICE; 327 328 /* 329 * Read the response from the server 330 */ 331 rv = SHMClientReadMessage(&msgStruct, dwClientID, sizeof(establish_struct), SHMClientCommunicationTimeout()); 332 333 if (rv == -1) 334 return SCARD_F_COMM_ERROR; 335 336 memcpy(&scEstablishStruct, &msgStruct.data, sizeof(scEstablishStruct)); 337 ntohlEstablishStruct(&scEstablishStruct); 338 339 if (scEstablishStruct.rv != SCARD_S_SUCCESS) 340 return scEstablishStruct.rv; 341 342 *phContext = scEstablishStruct.phContext; 343 344 /* 345 * Allocate the new hContext - if allocator full return an error 346 */ 347 rv = SCardAddContext(*phContext, dwClientID); 348 349 return rv; 350} 351 352/** 353 * @brief This function destroys a communication context to the PC/SC Resource 354 * Manager. This must be the last function called in a PC/SC application. 355 * 356 * @param[in] hContext Connection context to be closed. 357 * 358 * @return Connection status. 359 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 360 * 361 * @test 362 * @code 363 * SCARDCONTEXT hContext; 364 * LONG rv; 365 * ... 366 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 367 * rv = SCardReleaseContext(hContext); 368 * @endcode 369 */ 370LONG SCardReleaseContext(SCARDCONTEXT hContext) 371{ 372 LONG rv; 373 release_struct scReleaseStruct; 374 sharedSegmentMsg msgStruct; 375 LONG dwContextIndex; 376 377 PROFILE_START 378 379 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 380 return SCARD_E_NO_SERVICE; 381 382 /* 383 * Make sure this context has been opened 384 */ 385 dwContextIndex = SCardGetContextIndice(hContext); 386 if (dwContextIndex == -1) 387 return SCARD_E_INVALID_HANDLE; 388 389 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 390 391 scReleaseStruct.hContext = hContext; 392 scReleaseStruct.rv = 0; 393 htonlReleaseStruct(&scReleaseStruct); 394 395 rv = WrapSHMWrite(SCARD_RELEASE_CONTEXT, psContextMap[dwContextIndex].dwClientID, 396 sizeof(scReleaseStruct), 397 PCSCLITE_MCLIENT_ATTEMPTS, (void *) &scReleaseStruct); 398 399 if (rv == -1) 400 { 401 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 402 return SCARD_E_NO_SERVICE; 403 } 404 405 /* 406 * Read a message from the server 407 */ 408 rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(release_struct), SHMClientCommunicationTimeout()); 409 memcpy(&scReleaseStruct, &msgStruct.data, sizeof(scReleaseStruct)); 410 ntohlReleaseStruct(&scReleaseStruct); 411 412 if (rv == -1) 413 { 414 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 415 return SCARD_F_COMM_ERROR; 416 } 417 418 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 419 420 /* 421 * Remove the local context from the stack 422 */ 423 SCardLockThread(); 424 SCardRemoveContext(hContext); 425 SCardUnlockThread(); 426 427 PROFILE_END 428 429 return scReleaseStruct.rv; 430} 431 432/** 433 * @deprecated 434 * This function is not in Microsoft(R) WinSCard API and is deprecated 435 * in pcsc-lite API. 436 * The function does not do anything except returning \ref SCARD_S_SUCCESS. 437 * 438 * @param[in] hContext Connection context to the PC/SC Resource Manager. 439 * @param[in] dwTimeout New timeout value. 440 * 441 * @return Error code. 442 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 443 */ 444LONG SCardSetTimeout(SCARDCONTEXT hContext, DWORD dwTimeout) 445{ 446 /* 447 * Deprecated 448 */ 449 450 return SCARD_S_SUCCESS; 451} 452 453/** 454 * This function establishes a connection to the friendly name of the reader 455 * specified in szReader. The first connection will power up and perform a 456 * reset on the card. 457 * 458 * @param[in] hContext Connection context to the PC/SC Resource Manager. 459 * @param[in] szReader Reader name to connect to. 460 * @param[in] dwShareMode Mode of connection type: exclusive or shared. 461 * <ul> 462 * <li>\ref SCARD_SHARE_SHARED - This application will allow others to share 463 * the reader. 464 * <li>\ref SCARD_SHARE_EXCLUSIVE - This application will NOT allow others to 465 * share the reader. 466 * <li>\ref SCARD_SHARE_DIRECT - Direct control of the reader, even without a 467 * card. \ref SCARD_SHARE_DIRECT can be used before using SCardControl() to 468 * send control commands to the reader even if a card is not present in the 469 * reader. 470 * </ul> 471 * @param[in] dwPreferredProtocols Desired protocol use. 472 * <ul> 473 * <li>\ref SCARD_PROTOCOL_T0 - Use the T=0 protocol. 474 * <li>\ref SCARD_PROTOCOL_T1 - Use the T=1 protocol. 475 * <li>\ref SCARD_PROTOCOL_RAW - Use with memory type cards. 476 * </ul> 477 * dwPreferredProtocols is a bit mask of acceptable protocols for the 478 * connection. You can use (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1) if you 479 * do not have a preferred protocol. 480 * @param[out] phCard Handle to this connection. 481 * @param[out] pdwActiveProtocol Established protocol to this connection. 482 * 483 * @return Error code. 484 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 485 * @retval SCARD_E_INVALID_HANDLE Invalid hContext handle (\ref SCARD_E_INVALID_HANDLE) 486 * @retval SCARD_E_INVALID_VALUE Invalid sharing mode, requested protocol, or reader name (\ref SCARD_E_INVALID_VALUE) 487 * @retval SCARD_E_NOT_READY Could not allocate the desired port (\ref SCARD_E_NOT_READY) 488 * @retval SCARD_E_READER_UNAVAILABLE Could not power up the reader or card (\ref SCARD_E_READER_UNAVAILABLE) 489 * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION) 490 * @retval SCARD_E_UNSUPPORTED_FEATURE Protocol not supported (\ref SCARD_E_UNSUPPORTED_FEATURE) 491 * 492 * @test 493 * @code 494 * SCARDCONTEXT hContext; 495 * SCARDHANDLE hCard; 496 * DWORD dwActiveProtocol; 497 * LONG rv; 498 * ... 499 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 500 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol); 501 * @endcode 502 */ 503LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, 504 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, 505 LPDWORD pdwActiveProtocol) 506{ 507 LONG rv; 508 connect_struct scConnectStruct = {0,}; 509 sharedSegmentMsg msgStruct = {0,}; 510 LONG dwContextIndex; 511 512 PROFILE_START 513 514 /* 515 * Check for NULL parameters 516 */ 517 if (phCard == NULL || pdwActiveProtocol == NULL) 518 return SCARD_E_INVALID_PARAMETER; 519 else 520 *phCard = 0; 521 522 if (szReader == NULL) 523 return SCARD_E_UNKNOWN_READER; 524 525 /* 526 * Check for uninitialized strings 527 */ 528 if (strlen(szReader) > MAX_READERNAME) 529 return SCARD_E_INVALID_VALUE; 530 531 if (!(dwPreferredProtocols & SCARD_PROTOCOL_T0) && 532 !(dwPreferredProtocols & SCARD_PROTOCOL_T1) && 533 !(dwPreferredProtocols & SCARD_PROTOCOL_RAW) && 534 !(dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD)) 535 { 536 return SCARD_E_INVALID_VALUE; 537 } 538 539 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 540 return SCARD_E_NO_SERVICE; 541 542 /* 543 * Make sure this context has been opened 544 */ 545 dwContextIndex = SCardGetContextIndice(hContext); 546 if (dwContextIndex == -1) 547 return SCARD_E_INVALID_HANDLE; 548 549 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 550 551 strncpy(scConnectStruct.szReader, szReader, MAX_READERNAME); 552 553 scConnectStruct.hContext = hContext; 554 scConnectStruct.dwShareMode = dwShareMode; 555 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols; 556 scConnectStruct.phCard = *phCard; 557 scConnectStruct.pdwActiveProtocol = *pdwActiveProtocol; 558 htonlConnectStruct(&scConnectStruct); 559 560 rv = WrapSHMWrite(SCARD_CONNECT, psContextMap[dwContextIndex].dwClientID, 561 sizeof(scConnectStruct), 562 SHMClientCommunicationTimeout(), (void *) &scConnectStruct); 563 564 if (rv == -1) 565 { 566 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 567 return SCARD_E_NO_SERVICE; 568 } 569 570 /* 571 * Read a message from the server 572 */ 573 rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(connect_struct), SHMClientCommunicationTimeout()); 574 575 memcpy(&scConnectStruct, &msgStruct.data, sizeof(scConnectStruct)); 576 ntohlConnectStruct(&scConnectStruct); 577 578 if (rv == -1) 579 { 580 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 581 return SCARD_F_COMM_ERROR; 582 } 583 584 *phCard = scConnectStruct.phCard; 585 *pdwActiveProtocol = scConnectStruct.pdwActiveProtocol; 586 587 if (scConnectStruct.rv == SCARD_S_SUCCESS) 588 { 589 /* 590 * Keep track of the handle locally 591 */ 592 rv = SCardAddHandle(*phCard, dwContextIndex, (LPSTR) szReader); 593 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 594 595 PROFILE_END 596 597 return rv; 598 } 599 600 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 601 602 PROFILE_END 603 604 return scConnectStruct.rv; 605} 606 607/** 608 * @brief This function reestablishes a connection to a reader that was previously 609 * connected to using SCardConnect(). 610 * 611 * In a multi application environment it is possible for an application to reset 612 * the card in shared mode. When this occurs any other application trying to 613 * access certain commands will be returned the value SCARD_W_RESET_CARD. When 614 * this occurs SCardReconnect() must be called in order to acknowledge that 615 * the card was reset and allow it to change it's state accordingly. 616 * 617 * @param[in] hCard Handle to a previous call to connect. 618 * @param[in] dwShareMode Mode of connection type: exclusive/shared. 619 * <ul> 620 * <li>\ref SCARD_SHARE_SHARED - This application will allow others to share 621 * the reader. 622 * <li>\ref SCARD_SHARE_EXCLUSIVE - This application will NOT allow others to 623 * share the reader. 624 * </ul> 625 * @param[in] dwPreferredProtocols Desired protocol use. 626 * <ul> 627 * <li>\ref SCARD_PROTOCOL_T0 - Use the T=0 protocol. 628 * <li>\ref SCARD_PROTOCOL_T1 - Use the T=1 protocol. 629 * <li>\ref SCARD_PROTOCOL_RAW - Use with memory type cards. 630 * </ul> 631 * \p dwPreferredProtocols is a bit mask of acceptable protocols for 632 * the connection. You can use (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1) 633 * if you do not have a preferred protocol. 634 * @param[in] dwInitialization Desired action taken on the card/reader. 635 * <ul> 636 * <li>\ref SCARD_LEAVE_CARD - Do nothing. 637 * <li>\ref SCARD_RESET_CARD - Reset the card (warm reset). 638 * <li>\ref SCARD_UNPOWER_CARD - Unpower the card (cold reset). 639 * <li>\ref SCARD_EJECT_CARD - Eject the card. 640 * </ul> 641 * @param[out] pdwActiveProtocol Established protocol to this connection. 642 * 643 * @return Error code. 644 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 645 * @retval SCARD_E_INVALID_HANDLE Invalid \p hCard handle (\ref SCARD_E_INVALID_HANDLE) 646 * @retval SCARD_E_NOT_READY Could not allocate the desired port (\ref SCARD_E_NOT_READY) 647 * @retval SCARD_E_INVALID_VALUE Invalid sharing mode, requested protocol, or reader name (\ref SCARD_E_INVALID_VALUE) 648 * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE) 649 * @retval SCARD_E_UNSUPPORTED_FEATURE Protocol not supported (\ref SCARD_E_UNSUPPORTED_FEATURE) 650 * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION) 651 * 652 * @test 653 * @code 654 * SCARDCONTEXT hContext; 655 * SCARDHANDLE hCard; 656 * DWORD dwActiveProtocol, dwSendLength, dwRecvLength; 657 * LONG rv; 658 * BYTE pbRecvBuffer[10]; 659 * BYTE pbSendBuffer[] = {0xC0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00}; 660 * ... 661 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 662 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol); 663 * ... 664 * dwSendLength = sizeof(pbSendBuffer); 665 * dwRecvLength = sizeof(pbRecvBuffer); 666 * rv = SCardTransmit(hCard, SCARD_PCI_T0, pbSendBuffer, dwSendLength, &pioRecvPci, pbRecvBuffer, &dwRecvLength); 667 * / * Card has been reset by another application * / 668 * if (rv == SCARD_W_RESET_CARD) 669 * { 670 * rv = SCardReconnect(hCard, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, SCARD_RESET_CARD, &dwActiveProtocol); 671 * } 672 * @endcode 673 */ 674LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, 675 DWORD dwPreferredProtocols, DWORD dwInitialization, 676 LPDWORD pdwActiveProtocol) 677{ 678 LONG rv; 679 reconnect_struct scReconnectStruct; 680 sharedSegmentMsg msgStruct; 681 int i; 682 DWORD dwContextIndex, dwChannelIndex; 683 684 PROFILE_START 685 686 if (dwInitialization != SCARD_LEAVE_CARD && 687 dwInitialization != SCARD_RESET_CARD && 688 dwInitialization != SCARD_UNPOWER_CARD && 689 dwInitialization != SCARD_EJECT_CARD) 690 { 691 return SCARD_E_INVALID_VALUE; 692 } 693 694 if (!(dwPreferredProtocols & SCARD_PROTOCOL_T0) && 695 !(dwPreferredProtocols & SCARD_PROTOCOL_T1) && 696 !(dwPreferredProtocols & SCARD_PROTOCOL_RAW) && 697 !(dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD)) 698 { 699 return SCARD_E_INVALID_VALUE; 700 } 701 702 if (pdwActiveProtocol == NULL) 703 return SCARD_E_INVALID_PARAMETER; 704 705 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 706 return SCARD_E_NO_SERVICE; 707 708 /* 709 * Make sure this handle has been opened 710 */ 711 rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex); 712 713 if (rv == -1) 714 return SCARD_E_INVALID_HANDLE; 715 716 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 717 718 719 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 720 { 721 char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName; 722 /* by default r == NULL */ 723 if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r)) 724 break; 725 } 726 727 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 728 { 729 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 730 return SCARD_E_READER_UNAVAILABLE; 731 } 732 733 scReconnectStruct.hCard = hCard; 734 scReconnectStruct.dwShareMode = dwShareMode; 735 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols; 736 scReconnectStruct.dwInitialization = dwInitialization; 737 scReconnectStruct.pdwActiveProtocol = *pdwActiveProtocol; 738 htonlReconnectStruct(&scReconnectStruct); 739 740 rv = WrapSHMWrite(SCARD_RECONNECT, psContextMap[dwContextIndex].dwClientID, 741 sizeof(scReconnectStruct), 742 SHMClientCommunicationTimeout(), (void *) &scReconnectStruct); 743 744 if (rv == -1) 745 { 746 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 747 return SCARD_E_NO_SERVICE; 748 } 749 750 /* 751 * Read a message from the server 752 */ 753 rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(reconnect_struct), SHMClientCommunicationTimeout()); 754 755 memcpy(&scReconnectStruct, &msgStruct.data, sizeof(scReconnectStruct)); 756 ntohlReconnectStruct(&scReconnectStruct); 757 758 if (rv == -1) 759 { 760 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 761 return SCARD_F_COMM_ERROR; 762 } 763 764 *pdwActiveProtocol = scReconnectStruct.pdwActiveProtocol; 765 766 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 767 768 PROFILE_END 769 770 return scReconnectStruct.rv; 771} 772 773/** 774 * This function terminates a connection to the connection made through 775 * SCardConnect(). dwDisposition can have the following values: 776 * 777 * @param[in] hCard Connection made from SCardConnect. 778 * @param[in] dwDisposition Reader function to execute. 779 * <ul> 780 * <li>\ref SCARD_LEAVE_CARD - Do nothing. 781 * <li>\ref SCARD_RESET_CARD - Reset the card (warm reset). 782 * <li>\ref SCARD_UNPOWER_CARD - Unpower the card (cold reset). 783 * <li>\ref SCARD_EJECT_CARD - Eject the card. 784 * </ul> 785 * 786 * @return Error code. 787 * @retval SCARD_S_SUCCESS Successful(\ref SCARD_S_SUCCESS) 788 * @retval SCARD_E_INVALID_HANDLE Invalid \p hCard handle (\ref SCARD_E_INVALID_HANDLE) 789 * @retval SCARD_E_INVALID_VALUE - Invalid \p dwDisposition (\ref SCARD_E_INVALID_VALUE) 790 * 791 * @test 792 * @code 793 * SCARDCONTEXT hContext; 794 * SCARDHANDLE hCard; 795 * DWORD dwActiveProtocol; 796 * LONG rv; 797 * ... 798 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 799 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol); 800 * rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD); 801 * @endcode 802 */ 803LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition) 804{ 805 LONG rv; 806 disconnect_struct scDisconnectStruct; 807 sharedSegmentMsg msgStruct; 808 DWORD dwContextIndex, dwChannelIndex; 809 810 PROFILE_START 811 812 if (dwDisposition != SCARD_LEAVE_CARD && 813 dwDisposition != SCARD_RESET_CARD && 814 dwDisposition != SCARD_UNPOWER_CARD && 815 dwDisposition != SCARD_EJECT_CARD) 816 { 817 return SCARD_E_INVALID_VALUE; 818 } 819 820 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 821 return SCARD_E_NO_SERVICE; 822 823 /* 824 * Make sure this handle has been opened 825 */ 826 rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex); 827 828 if (rv == -1) 829 return SCARD_E_INVALID_HANDLE; 830 831 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 832 833 scDisconnectStruct.hCard = hCard; 834 scDisconnectStruct.dwDisposition = dwDisposition; 835 htonlDisconnectStruct(&scDisconnectStruct); 836 837 rv = WrapSHMWrite(SCARD_DISCONNECT, psContextMap[dwContextIndex].dwClientID, 838 sizeof(scDisconnectStruct), 839 SHMClientCommunicationTimeout(), (void *) &scDisconnectStruct); 840 841 if (rv == -1) 842 { 843 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 844 return SCARD_E_NO_SERVICE; 845 } 846 847 /* 848 * Read a message from the server 849 */ 850 rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(disconnect_struct), SHMClientCommunicationTimeout()); 851 852 memcpy(&scDisconnectStruct, &msgStruct.data, sizeof(scDisconnectStruct)); 853 ntohlDisconnectStruct(&scDisconnectStruct); 854 855 if (rv == -1) 856 { 857 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 858 return SCARD_F_COMM_ERROR; 859 } 860 861 SCardRemoveHandle(hCard); 862 863 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 864 865 PROFILE_END 866 867 return scDisconnectStruct.rv; 868} 869 870/** 871 * @brief This function establishes a temporary exclusive access mode for 872 * doing a series of commands or transaction. 873 * 874 * You might want to use this when you are selecting a few files and then 875 * writing a large file so you can make sure that another application will 876 * not change the current file. If another application has a lock on this 877 * reader or this application is in \ref SCARD_SHARE_EXCLUSIVE there will be no 878 * action taken. 879 * 880 * @param[in] hCard Connection made from SCardConnect. 881 * 882 * @return Error code. 883 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 884 * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE) 885 * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION) 886 * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE) 887 * 888 * @test 889 * @code 890 * SCARDCONTEXT hContext; 891 * SCARDHANDLE hCard; 892 * DWORD dwActiveProtocol; 893 * LONG rv; 894 * ... 895 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 896 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol); 897 * rv = SCardBeginTransaction(hCard); 898 * ... 899 * / * Do some transmit commands * / 900 * @endcode 901 */ 902LONG SCardBeginTransaction(SCARDHANDLE hCard) 903{ 904 905 LONG rv; 906 begin_struct txBeginStruct = {0,}, rxBeginStruct = {0,}; 907 int i; 908 sharedSegmentMsg msgStruct = {0,}; 909 DWORD dwContextIndex, dwChannelIndex; 910 911 PROFILE_START 912 913 secdebug("pcscd", "SCardBeginTransaction: initial request: hCard: 0x%08X", hCard); 914 915 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 916 return SCARD_E_NO_SERVICE; 917 918 /* 919 * Make sure this handle has been opened 920 */ 921 rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex); 922 923 if (rv == -1) 924 return SCARD_E_INVALID_HANDLE; 925 926 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 927 928 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 929 { 930 char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName; 931 932 /* by default r == NULL */ 933 if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r)) 934 break; 935 } 936 937 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 938 { 939 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 940 return SCARD_E_READER_UNAVAILABLE; 941 } 942 943 txBeginStruct.hCard = hCard; 944 htonlBeginStruct(&txBeginStruct); 945 946 /* 947 * Query the server every so often until the sharing violation ends 948 * and then hold the lock for yourself. 949 */ 950 951 do 952 { 953 rv = WrapSHMWrite(SCARD_BEGIN_TRANSACTION, psContextMap[dwContextIndex].dwClientID, 954 sizeof(txBeginStruct), 955 SHMClientCommunicationTimeout(), (void *) &txBeginStruct); 956 957 if (rv == -1) 958 { 959 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 960 return SCARD_E_NO_SERVICE; 961 } 962 963 /* 964 * Read a message from the server 965 */ 966 rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(begin_struct), SHMClientCommunicationTimeout()); 967 memcpy(&rxBeginStruct, &msgStruct.data, sizeof(rxBeginStruct)); 968 ntohlBeginStruct(&rxBeginStruct); 969 970 if (rv == -1) 971 { 972 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 973 return SCARD_F_COMM_ERROR; 974 } 975 976 } 977 while (rxBeginStruct.rv == SCARD_E_SHARING_VIOLATION); 978 979 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 980 981 PROFILE_END 982 secdebug("pcscd", "SCardBeginTransaction: hCard: 0x%08X, returning: 0x%08X", rxBeginStruct.hCard, rxBeginStruct.rv); 983 984 return rxBeginStruct.rv; 985} 986 987/** 988 * @brief This function ends a previously begun transaction. 989 * 990 * The calling application must be the owner of the previously begun 991 * transaction or an error will occur. 992 * 993 * @param[in] hCard Connection made from SCardConnect. 994 * @param[in] dwDisposition Action to be taken on the reader. 995 * The disposition action is not currently used in this release. 996 * <ul> 997 * <li>\ref SCARD_LEAVE_CARD - Do nothing. 998 * <li>\ref SCARD_RESET_CARD - Reset the card. 999 * <li>\ref SCARD_UNPOWER_CARD - Unpower the card. 1000 * <li>\ref SCARD_EJECT_CARD - Eject the card. 1001 * </ul> 1002 * 1003 * @return Error code. 1004 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 1005 * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE) 1006 * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION) 1007 * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE) 1008 * 1009 * @test 1010 * @code 1011 * SCARDCONTEXT hContext; 1012 * SCARDHANDLE hCard; 1013 * DWORD dwActiveProtocol; 1014 * LONG rv; 1015 * ... 1016 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 1017 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol); 1018 * rv = SCardBeginTransaction(hCard); 1019 * ... 1020 * / * Do some transmit commands * / 1021 * ... 1022 * rv = SCardEndTransaction(hCard, SCARD_LEAVE_CARD); 1023 * @endcode 1024 */ 1025LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition) 1026{ 1027 LONG rv; 1028 end_struct scEndStruct; 1029 sharedSegmentMsg msgStruct; 1030 int randnum, i; 1031 DWORD dwContextIndex, dwChannelIndex; 1032 1033 PROFILE_START 1034 1035 secdebug("pcscd", "SCardEndTransaction: initial request: hCard: 0x%08X, dwDisposition: 0x%04X", 1036 hCard, dwDisposition); 1037 /* 1038 * Zero out everything 1039 */ 1040 randnum = 0; 1041 1042 if (dwDisposition != SCARD_LEAVE_CARD && 1043 dwDisposition != SCARD_RESET_CARD && 1044 dwDisposition != SCARD_UNPOWER_CARD && 1045 dwDisposition != SCARD_EJECT_CARD) 1046 { 1047 return SCARD_E_INVALID_VALUE; 1048 } 1049 1050 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 1051 return SCARD_E_NO_SERVICE; 1052 1053 /* 1054 * Make sure this handle has been opened 1055 */ 1056 rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex); 1057 1058 if (rv == -1) 1059 return SCARD_E_INVALID_HANDLE; 1060 1061 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 1062 1063 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 1064 { 1065 char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName; 1066 1067 /* by default r == NULL */ 1068 if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r)) 1069 break; 1070 } 1071 1072 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 1073 { 1074 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1075 return SCARD_E_READER_UNAVAILABLE; 1076 } 1077 1078 scEndStruct.hCard = hCard; 1079 scEndStruct.dwDisposition = dwDisposition; 1080 htonlEndStruct(&scEndStruct); 1081 1082 rv = WrapSHMWrite(SCARD_END_TRANSACTION, psContextMap[dwContextIndex].dwClientID, 1083 sizeof(scEndStruct), 1084 SHMClientCommunicationTimeout(), (void *) &scEndStruct); 1085 secdebug("pcscd", "SCardEndTransaction: WrapSHMWrite result: 0x%08X", rv); 1086 1087 if (rv == -1) 1088 { 1089 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1090 return SCARD_E_NO_SERVICE; 1091 } 1092 1093 /* 1094 * Read a message from the server 1095 */ 1096 rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(end_struct), SHMClientCommunicationTimeout()); 1097 secdebug("pcscd", "SCardEndTransaction: SHMClientRead result: 0x%08X", rv); 1098 1099 memcpy(&scEndStruct, &msgStruct.data, sizeof(scEndStruct)); 1100 ntohlEndStruct(&scEndStruct); 1101 1102 if (rv == -1) 1103 { 1104 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1105 return SCARD_F_COMM_ERROR; 1106 } 1107 1108 /* 1109 * This helps prevent starvation 1110 */ 1111 randnum = SYS_Random(randnum, 1000.0, 10000.0); 1112 SYS_USleep(randnum); 1113 1114 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1115 1116 PROFILE_END 1117 1118 secdebug("pcscd", "SCardEndTransaction: returning: 0x%08X", scEndStruct.rv); 1119 return scEndStruct.rv; 1120} 1121 1122/** 1123 * @deprecated 1124 * This function is not in Microsoft(R) WinSCard API and is deprecated 1125 * in pcsc-lite API. 1126 */ 1127LONG SCardCancelTransaction(SCARDHANDLE hCard) 1128{ 1129 LONG rv; 1130 cancel_struct scCancelStruct; 1131 sharedSegmentMsg msgStruct; 1132 int i; 1133 DWORD dwContextIndex, dwChannelIndex; 1134 1135 PROFILE_START 1136 1137 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 1138 return SCARD_E_NO_SERVICE; 1139 1140 /* 1141 * Make sure this handle has been opened 1142 */ 1143 rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex); 1144 1145 if (rv == -1) 1146 return SCARD_E_INVALID_HANDLE; 1147 1148 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 1149 1150 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 1151 { 1152 char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName; 1153 1154 /* by default r == NULL */ 1155 if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r)) 1156 break; 1157 } 1158 1159 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 1160 { 1161 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1162 return SCARD_E_READER_UNAVAILABLE; 1163 } 1164 1165 scCancelStruct.hCard = hCard; 1166 htonlCancelStruct(&scCancelStruct); 1167 1168 rv = WrapSHMWrite(SCARD_CANCEL_TRANSACTION, psContextMap[dwContextIndex].dwClientID, 1169 sizeof(scCancelStruct), 1170 SHMClientCommunicationTimeout(), (void *) &scCancelStruct); 1171 1172 if (rv == -1) 1173 { 1174 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1175 return SCARD_E_NO_SERVICE; 1176 } 1177 1178 /* 1179 * Read a message from the server 1180 */ 1181 rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(cancel_struct), SHMClientCommunicationTimeout()); 1182 1183 memcpy(&scCancelStruct, &msgStruct.data, sizeof(scCancelStruct)); 1184 ntohlCancelStruct(&scCancelStruct); 1185 1186 if (rv == -1) 1187 { 1188 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1189 return SCARD_F_COMM_ERROR; 1190 } 1191 1192 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1193 1194 PROFILE_END 1195 1196 return scCancelStruct.rv; 1197} 1198 1199/** 1200 * @brief This function returns the current status of the reader connected to by hCard. 1201 * 1202 * It's friendly name will be stored in szReaderName. pcchReaderLen will be 1203 * the size of the allocated buffer for szReaderName, while pcbAtrLen will 1204 * be the size of the allocated buffer for pbAtr. If either of these is too 1205 * small, the function will return with \ref SCARD_E_INSUFFICIENT_BUFFER and the 1206 * necessary size in pcchReaderLen and pcbAtrLen. The current state, and 1207 * protocol will be stored in pdwState and pdwProtocol respectively. 1208 * 1209 * @param[in] hCard Connection made from SCardConnect. 1210 * @param mszReaderNames [inout] Friendly name of this reader. 1211 * @param pcchReaderLen [inout] Size of the szReaderName multistring. 1212 * @param[out] pdwState Current state of this reader. pdwState 1213 * is a DWORD possibly OR'd with the following values: 1214 * <ul> 1215 * <li>\ref SCARD_ABSENT - There is no card in the reader. 1216 * <li>\ref SCARD_PRESENT - There is a card in the reader, but it has not 1217 * been moved into position for use. 1218 * <li>\ref SCARD_SWALLOWED - There is a card in the reader in position for 1219 * use. The card is not powered. 1220 * <li>\ref SCARD_POWERED - Power is being provided to the card, but the 1221 * reader driver is unaware of the mode of the card. 1222 * <li>\ref SCARD_NEGOTIABLE - The card has been reset and is awaiting PTS 1223 * negotiation. 1224 * <li>\ref SCARD_SPECIFIC - The card has been reset and specific 1225 * communication protocols have been established. 1226 * </ul> 1227 * @param[out] pdwProtocol Current protocol of this reader. 1228 * <ul> 1229 * <li>\ref SCARD_PROTOCOL_T0 Use the T=0 protocol. 1230 * <li>\ref SCARD_PROTOCOL_T1 Use the T=1 protocol. 1231 * </ul> 1232 * @param[out] pbAtr Current ATR of a card in this reader. 1233 * @param[out] pcbAtrLen Length of ATR. 1234 * 1235 * @return Error code. 1236 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 1237 * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE) 1238 * @retval SCARD_E_INSUFFICIENT_BUFFER Not enough allocated memory for szReaderName or for pbAtr (\ref SCARD_E_INSUFFICIENT_BUFFER) 1239 * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE) 1240 * 1241 * @test 1242 * @code 1243 * SCARDCONTEXT hContext; 1244 * SCARDHANDLE hCard; 1245 * DWORD dwActiveProtocol; 1246 * DWORD dwState, dwProtocol, dwAtrLen, dwReaderLen; 1247 * BYTE pbAtr[MAX_ATR_SIZE]; 1248 * ... 1249 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 1250 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol); 1251 * ... 1252 * dwAtrLen = sizeof(pbAtr); 1253 * rv=SCardStatus(hCard, NULL, &dwReaderLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen); 1254 * @endcode 1255 */ 1256LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderNames, 1257 LPDWORD pcchReaderLen, LPDWORD pdwState, 1258 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen) 1259{ 1260 DWORD dwReaderLen, atrOutputBufferSize; 1261 LONG rv; 1262 int i; 1263 status_struct scStatusStruct; 1264 sharedSegmentMsg msgStruct; 1265 DWORD dwContextIndex, dwChannelIndex; 1266 char *r; 1267 1268 PROFILE_START 1269 1270 /* 1271 * Check for NULL parameters 1272 */ 1273 1274 if (pcchReaderLen == NULL || pcbAtrLen == NULL) 1275 return SCARD_E_INVALID_PARAMETER; 1276 1277 /* length passed from caller */ 1278 dwReaderLen = *pcchReaderLen; 1279 atrOutputBufferSize = *pcbAtrLen; 1280 1281 /* default output values */ 1282 if (pdwState) 1283 *pdwState = 0; 1284 1285 if (pdwProtocol) 1286 *pdwProtocol = 0; 1287 1288 *pcchReaderLen = 0; 1289 *pcbAtrLen = 0; 1290 1291 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 1292 return SCARD_E_NO_SERVICE; 1293 1294 /* 1295 * Make sure this handle has been opened 1296 */ 1297 rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex); 1298 1299 if (rv == -1) 1300 return SCARD_E_INVALID_HANDLE; 1301 1302 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 1303 1304 r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName; 1305 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 1306 { 1307 /* by default r == NULL */ 1308 if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r)) 1309 break; 1310 } 1311 1312 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 1313 { 1314 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1315 return SCARD_E_READER_UNAVAILABLE; 1316 } 1317 1318 /* initialise the structure */ 1319 memset(&scStatusStruct, 0, sizeof(scStatusStruct)); 1320 scStatusStruct.hCard = hCard; 1321 1322 /* those sizes need to be initialised */ 1323 scStatusStruct.pcchReaderLen = sizeof(scStatusStruct.mszReaderNames); 1324 scStatusStruct.pcbAtrLen = sizeof(scStatusStruct.pbAtr); 1325 htonlStatusStruct(&scStatusStruct); 1326 1327 rv = WrapSHMWrite(SCARD_STATUS, psContextMap[dwContextIndex].dwClientID, 1328 sizeof(scStatusStruct), 1329 SHMClientCommunicationTimeout(), (void *) &scStatusStruct); 1330 1331 if (rv == -1) 1332 { 1333 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1334 return SCARD_E_NO_SERVICE; 1335 } 1336 1337 /* 1338 * Read a message from the server 1339 */ 1340 rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(status_struct), SHMClientCommunicationTimeout()); 1341 1342 memcpy(&scStatusStruct, &msgStruct.data, sizeof(scStatusStruct)); 1343 ntohlStatusStruct(&scStatusStruct); 1344 1345 if (rv == -1) 1346 { 1347 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1348 return SCARD_F_COMM_ERROR; 1349 } 1350 1351 rv = scStatusStruct.rv; 1352 if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER) 1353 { 1354 /* 1355 * An event must have occurred 1356 */ 1357 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1358 return rv; 1359 } 1360 1361 /* 1362 * Now continue with the client side SCardStatus 1363 */ 1364 1365 *pcchReaderLen = strlen(psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName) + 1; 1366 *pcbAtrLen = SharedReaderState_CardAtrLength(readerStates[i]); 1367 1368 if (pdwState) 1369 *pdwState = SharedReaderState_State(readerStates[i]); 1370 1371 if (pdwProtocol) 1372 *pdwProtocol = SharedReaderState_Protocol(readerStates[i]); 1373 1374 /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */ 1375 if (mszReaderNames) 1376 { 1377 if (*pcchReaderLen > dwReaderLen) 1378 rv = SCARD_E_INSUFFICIENT_BUFFER; 1379 1380 strncpy(mszReaderNames, 1381 psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName, 1382 dwReaderLen); 1383 } 1384 1385 if (pbAtr) 1386 { 1387 if (*pcbAtrLen > atrOutputBufferSize) 1388 rv = SCARD_E_INSUFFICIENT_BUFFER; 1389 1390 memcpy(pbAtr, SharedReaderState_CardAtr(readerStates[i]), 1391 min(*pcbAtrLen, atrOutputBufferSize)); 1392 } 1393 1394 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1395 1396 PROFILE_END 1397 1398 return rv; 1399} 1400 1401/** 1402 * @brief This function receives a structure or list of structures containing 1403 * reader names. It then blocks for a change in state to occur on any of the 1404 * OR'd values contained in dwCurrentState for a maximum blocking time of 1405 * dwTimeout or forever if INFINITE is used. 1406 * 1407 * The new event state will be contained in dwEventState. A status change might 1408 * be a card insertion or removal event, a change in ATR, etc. 1409 * 1410 * This function will block for reader availability if cReaders is equal to 1411 * zero and rgReaderStates is NULL. 1412 * 1413 * @code 1414 * typedef struct { 1415 * LPCSTR szReader; // Reader name 1416 * LPVOID pvUserData; // User defined data 1417 * DWORD dwCurrentState; // Current state of reader 1418 * DWORD dwEventState; // Reader state after a state change 1419 * DWORD cbAtr; // ATR Length, usually MAX_ATR_SIZE 1420 * BYTE rgbAtr[MAX_ATR_SIZE]; // ATR Value 1421 * } SCARD_READERSTATE; 1422 * ... 1423 * typedef SCARD_READERSTATE *PSCARD_READERSTATE, **LPSCARD_READERSTATE; 1424 * ... 1425 * @endcode 1426 * 1427 * Value of dwCurrentState and dwEventState: 1428 * <ul> 1429 * <li>\ref SCARD_STATE_UNAWARE The application is unaware of the current 1430 * state, and would like to know. The use of this value results in an 1431 * immediate return from state transition monitoring services. This is 1432 * represented by all bits set to zero. 1433 * <li>\ref SCARD_STATE_IGNORE This reader should be ignored 1434 * <li>\ref SCARD_STATE_CHANGED There is a difference between the state believed 1435 * by the application, and the state known by the resource manager. 1436 * When this bit is set, the application may assume a significant state 1437 * change has occurred on this reader. 1438 * <li>\ref SCARD_STATE_UNKNOWN The given reader name is not recognized by the 1439 * resource manager. If this bit is set, then \ref SCARD_STATE_CHANGED and 1440 * \ref SCARD_STATE_IGNORE will also be set 1441 * <li>\ref SCARD_STATE_UNAVAILABLE The actual state of this reader is not 1442 * available. If this bit is set, then all the following bits are clear. 1443 * <li>\ref SCARD_STATE_EMPTY There is no card in the reader. If this bit is set, 1444 * all the following bits will be clear 1445 * <li>\ref SCARD_STATE_PRESENT There is a card in the reader 1446 * <li>\ref SCARD_STATE_ATRMATCH There is a card in the reader with an ATR 1447 * matching one of the target cards. If this bit is set, 1448 * \ref SCARD_STATE_PRESENT will also be set. This bit is only returned on 1449 * the SCardLocateCards() function. 1450 * <li>\ref SCARD_STATE_EXCLUSIVE The card in the reader is allocated for 1451 * exclusive use by another application. If this bit is set, 1452 * \ref SCARD_STATE_PRESENT will also be set. 1453 * <li>\ref SCARD_STATE_INUSE The card in the reader is in use by one or more 1454 * other applications, but may be connected to in shared mode. If this 1455 * bit is set, \ref SCARD_STATE_PRESENT will also be set. 1456 * <li>\ref SCARD_STATE_MUTE There is an unresponsive card in the reader. 1457 * </ul> 1458 * 1459 * @param[in] hContext Connection context to the PC/SC Resource Manager. 1460 * @param[in] dwTimeout Maximum waiting time (in miliseconds) for status 1461 * change, zero (or INFINITE) for infinite. 1462 * @param rgReaderStates [inout] Structures of readers with current states. 1463 * @param[in] cReaders Number of structures. 1464 * 1465 * @return Error code. 1466 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 1467 * @retval SCARD_E_INVALID_VALUE Invalid States, reader name, etc (\ref SCARD_E_INVALID_VALUE) 1468 * @retval SCARD_E_INVALID_HANDLE Invalid hContext handle (\ref SCARD_E_INVALID_HANDLE) 1469 * @retval SCARD_E_READER_UNAVAILABLE The reader is unavailable (\ref SCARD_E_READER_UNAVAILABLE) 1470 * 1471 * @test 1472 * @code 1473 * SCARDCONTEXT hContext; 1474 * SCARD_READERSTATE_A rgReaderStates[1]; 1475 * LONG rv; 1476 * ... 1477 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 1478 * ... 1479 * rgReaderStates[0].szReader = "Reader X"; 1480 * rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE; 1481 * ... 1482 * rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 1); 1483 * printf("reader state: 0x%04X\n", rgReaderStates[0].dwEventState); 1484 * @endcode 1485 */ 1486LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, 1487 LPSCARD_READERSTATE_A rgReaderStates, DWORD cReaders) 1488{ 1489 PSCARD_READERSTATE_A currReader; 1490 PREADER_STATE rContext; 1491 DWORD dwTime = 0; 1492 DWORD dwState; 1493 DWORD dwBreakFlag = 0; 1494 int j; 1495 LONG dwContextIndex; 1496 int currentReaderCount = 0; 1497 1498 PROFILE_START 1499 1500 if (rgReaderStates == NULL && cReaders > 0) 1501 return SCARD_E_INVALID_PARAMETER; 1502 1503 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 1504 return SCARD_E_NO_SERVICE; 1505 1506 /* 1507 * Make sure this context has been opened 1508 */ 1509 1510 dwContextIndex = SCardGetContextIndice(hContext); 1511 if (dwContextIndex == -1) 1512 return SCARD_E_INVALID_HANDLE; 1513 1514 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 1515 1516 /* 1517 * Application is waiting for a reader - return the first available 1518 * reader 1519 */ 1520 1521 if (cReaders == 0) 1522 { 1523 while (1) 1524 { 1525 int i; 1526 1527 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 1528 { 1529 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1530 return SCARD_E_NO_SERVICE; 1531 } 1532 1533 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 1534 { 1535 if (SharedReaderState_ReaderID(readerStates[i]) != 0) 1536 { 1537 /* 1538 * Reader was found 1539 */ 1540 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1541 1542 PROFILE_END 1543 1544 return SCARD_S_SUCCESS; 1545 } 1546 } 1547 1548 if (dwTimeout == 0) 1549 { 1550 /* 1551 * return immediately - no reader available 1552 */ 1553 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1554 return SCARD_E_READER_UNAVAILABLE; 1555 } 1556 1557 SYS_USleep(PCSCLITE_STATUS_WAIT); 1558 1559 if (dwTimeout != INFINITE) 1560 { 1561 dwTime += PCSCLITE_STATUS_WAIT; 1562 1563 if (dwTime >= (dwTimeout * 1000)) 1564 { 1565 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1566 1567 PROFILE_END 1568 1569 return SCARD_E_TIMEOUT; 1570 } 1571 } 1572 } 1573 } 1574 else 1575 if (cReaders >= PCSCLITE_MAX_READERS_CONTEXTS) 1576 { 1577 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1578 return SCARD_E_INVALID_VALUE; 1579 } 1580 1581 /* 1582 * Check the integrity of the reader states structures 1583 */ 1584 1585 for (j = 0; j < cReaders; j++) 1586 { 1587 currReader = &rgReaderStates[j]; 1588 1589 if (currReader->szReader == NULL) 1590 { 1591 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1592 return SCARD_E_INVALID_VALUE; 1593 } 1594 } 1595 1596 /* 1597 * End of search for readers 1598 */ 1599 1600 /* 1601 * Clear the event state for all readers 1602 */ 1603 for (j = 0; j < cReaders; j++) 1604 { 1605 currReader = &rgReaderStates[j]; 1606 currReader->dwEventState = 0; 1607 } 1608 1609 /* 1610 * Now is where we start our event checking loop 1611 */ 1612 1613 Log1(PCSC_LOG_DEBUG, "Event Loop Start"); 1614 1615 psContextMap[dwContextIndex].contextBlockStatus = BLOCK_STATUS_BLOCKING; 1616 1617 /* Get the initial reader count on the system */ 1618 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++) 1619 if (SharedReaderState_ReaderID(readerStates[j]) != 0) 1620 currentReaderCount++; 1621 1622 j = 0; 1623 1624 do 1625 { 1626 int newReaderCount = 0; 1627 char ReaderCountChanged = 0; 1628 1629 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 1630 { 1631 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1632 1633 PROFILE_END 1634 1635 return SCARD_E_NO_SERVICE; 1636 } 1637 1638 if (j == 0) 1639 { 1640 int i; 1641 1642 for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 1643 if (SharedReaderState_ReaderID(readerStates[i]) != 0) 1644 newReaderCount++; 1645 1646 if (newReaderCount != currentReaderCount) 1647 { 1648 Log1(PCSC_LOG_INFO, "Reader list changed"); 1649 ReaderCountChanged = 1; 1650 currentReaderCount = newReaderCount; 1651 } 1652 } 1653 currReader = &rgReaderStates[j]; 1654 1655 /************ Look for IGNORED readers ****************************/ 1656 1657 if (currReader->dwCurrentState & SCARD_STATE_IGNORE) 1658 currReader->dwEventState = SCARD_STATE_IGNORE; 1659 else 1660 { 1661 LPSTR lpcReaderName; 1662 int i; 1663 1664 /************ Looks for correct readernames *********************/ 1665 1666 lpcReaderName = (char *) currReader->szReader; 1667 1668 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 1669 { 1670 if (SharedReaderState_ReaderNameIsEqual(readerStates[i], lpcReaderName)) 1671 break; 1672 } 1673 1674 /* 1675 * The requested reader name is not recognized 1676 */ 1677 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 1678 { 1679 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN) 1680 currReader->dwEventState = SCARD_STATE_UNKNOWN; 1681 else 1682 { 1683 currReader->dwEventState = 1684 SCARD_STATE_UNKNOWN | SCARD_STATE_CHANGED; 1685 /* 1686 * Spec says use SCARD_STATE_IGNORE but a removed USB 1687 * reader with eventState fed into currentState will 1688 * be ignored forever 1689 */ 1690 dwBreakFlag = 1; 1691 } 1692 } 1693 else 1694 { 1695 1696 /* 1697 * The reader has come back after being away 1698 */ 1699 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN) 1700 { 1701 currReader->dwEventState |= SCARD_STATE_CHANGED; 1702 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN; 1703 dwBreakFlag = 1; 1704 } 1705 1706 /*****************************************************************/ 1707 1708 /* 1709 * Set the reader status structure 1710 */ 1711 rContext = readerStates[i]; 1712 1713 /* 1714 * Now we check all the Reader States 1715 */ 1716 dwState = SharedReaderState_State(rContext); 1717 1718 /*********** Check if the reader is in the correct state ********/ 1719 if (dwState & SCARD_UNKNOWN) 1720 { 1721 /* 1722 * App thinks reader is in bad state and it is 1723 */ 1724 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE) 1725 currReader->dwEventState = SCARD_STATE_UNAVAILABLE; 1726 else 1727 { 1728 /* 1729 * App thinks reader is in good state and it is 1730 * not 1731 */ 1732 currReader->dwEventState = SCARD_STATE_CHANGED | 1733 SCARD_STATE_UNAVAILABLE; 1734 dwBreakFlag = 1; 1735 } 1736 } 1737 else 1738 { 1739 /* 1740 * App thinks reader in bad state but it is not 1741 */ 1742 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE) 1743 { 1744 currReader->dwEventState &= 1745 ~SCARD_STATE_UNAVAILABLE; 1746 currReader->dwEventState |= SCARD_STATE_CHANGED; 1747 dwBreakFlag = 1; 1748 } 1749 } 1750 1751 /********** Check for card presence in the reader **************/ 1752 1753 if (dwState & SCARD_PRESENT) 1754 { 1755 /* card present but not yet powered up */ 1756 if (0 == SharedReaderState_CardAtrLength(rContext)) 1757 /* Allow the status thread to convey information */ 1758 SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10); 1759 1760 currReader->cbAtr = SharedReaderState_CardAtrLength(rContext); 1761 memcpy(currReader->rgbAtr, SharedReaderState_CardAtr(rContext), 1762 currReader->cbAtr); 1763 } 1764 else 1765 currReader->cbAtr = 0; 1766 1767 /* 1768 * Card is now absent 1769 */ 1770 if (dwState & SCARD_ABSENT) 1771 { 1772 currReader->dwEventState |= SCARD_STATE_EMPTY; 1773 currReader->dwEventState &= ~SCARD_STATE_PRESENT; 1774 currReader->dwEventState &= ~SCARD_STATE_UNAWARE; 1775 currReader->dwEventState &= ~SCARD_STATE_IGNORE; 1776 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN; 1777 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE; 1778 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH; 1779 currReader->dwEventState &= ~SCARD_STATE_MUTE; 1780 currReader->dwEventState &= ~SCARD_STATE_INUSE; 1781 1782 /* 1783 * After present the rest are assumed 1784 */ 1785 if (currReader->dwCurrentState & SCARD_STATE_PRESENT 1786 || currReader->dwCurrentState & SCARD_STATE_ATRMATCH 1787 || currReader->dwCurrentState & SCARD_STATE_EXCLUSIVE 1788 || currReader->dwCurrentState & SCARD_STATE_INUSE) 1789 { 1790 currReader->dwEventState |= SCARD_STATE_CHANGED; 1791 dwBreakFlag = 1; 1792 } 1793 1794 /* 1795 * Card is now present 1796 */ 1797 } else if (dwState & SCARD_PRESENT) 1798 { 1799 currReader->dwEventState |= SCARD_STATE_PRESENT; 1800 currReader->dwEventState &= ~SCARD_STATE_EMPTY; 1801 currReader->dwEventState &= ~SCARD_STATE_UNAWARE; 1802 currReader->dwEventState &= ~SCARD_STATE_IGNORE; 1803 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN; 1804 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE; 1805 currReader->dwEventState &= ~SCARD_STATE_MUTE; 1806 1807 if (currReader->dwCurrentState & SCARD_STATE_EMPTY) 1808 { 1809 currReader->dwEventState |= SCARD_STATE_CHANGED; 1810 dwBreakFlag = 1; 1811 } 1812 1813 if (dwState & SCARD_SWALLOWED) 1814 { 1815 if (currReader->dwCurrentState & SCARD_STATE_MUTE) 1816 currReader->dwEventState |= SCARD_STATE_MUTE; 1817 else 1818 { 1819 currReader->dwEventState |= SCARD_STATE_MUTE; 1820 if (currReader->dwCurrentState 1821 != SCARD_STATE_UNAWARE) 1822 currReader->dwEventState |= SCARD_STATE_CHANGED; 1823 dwBreakFlag = 1; 1824 } 1825 } 1826 else 1827 { 1828 /* 1829 * App thinks card is mute but it is not 1830 */ 1831 if (currReader->dwCurrentState & SCARD_STATE_MUTE) 1832 { 1833 currReader->dwEventState |= 1834 SCARD_STATE_CHANGED; 1835 dwBreakFlag = 1; 1836 } 1837 } 1838 } 1839 1840 /* 1841 * Now figure out sharing modes 1842 */ 1843 DWORD sharing = SharedReaderState_Sharing(rContext); 1844 if (sharing == -1) 1845 { 1846 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE; 1847 currReader->dwEventState &= ~SCARD_STATE_INUSE; 1848 if (currReader->dwCurrentState & SCARD_STATE_INUSE) 1849 { 1850 currReader->dwEventState |= SCARD_STATE_CHANGED; 1851 dwBreakFlag = 1; 1852 } 1853 } 1854 else if (sharing >= 1) 1855 { 1856 /* 1857 * A card must be inserted for it to be INUSE 1858 */ 1859 if (dwState & SCARD_PRESENT) 1860 { 1861 currReader->dwEventState |= SCARD_STATE_INUSE; 1862 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE; 1863 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE) 1864 { 1865 currReader->dwEventState |= SCARD_STATE_CHANGED; 1866 dwBreakFlag = 1; 1867 } 1868 } 1869 } 1870 else if (sharing == 0) 1871 { 1872 currReader->dwEventState &= ~SCARD_STATE_INUSE; 1873 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE; 1874 1875 if (currReader->dwCurrentState & SCARD_STATE_INUSE) 1876 { 1877 currReader->dwEventState |= SCARD_STATE_CHANGED; 1878 dwBreakFlag = 1; 1879 } 1880 else if (currReader-> dwCurrentState 1881 & SCARD_STATE_EXCLUSIVE) 1882 { 1883 currReader->dwEventState |= SCARD_STATE_CHANGED; 1884 dwBreakFlag = 1; 1885 } 1886 } 1887 1888 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE) 1889 { 1890 /* 1891 * Break out of the while .. loop and return status 1892 * once all the status's for all readers is met 1893 */ 1894 currReader->dwEventState |= SCARD_STATE_CHANGED; 1895 dwBreakFlag = 1; 1896 } 1897 1898 } /* End of SCARD_STATE_UNKNOWN */ 1899 1900 } /* End of SCARD_STATE_IGNORE */ 1901 1902 /* 1903 * Counter and resetter 1904 */ 1905 j = j + 1; 1906 if (j == cReaders) 1907 { 1908 if (!dwBreakFlag) 1909 { 1910 /* break if the reader count changed, 1911 * so that the calling application can update 1912 * the reader list 1913 */ 1914 if (ReaderCountChanged) 1915 break; 1916 } 1917 j = 0; 1918 } 1919 1920 /* 1921 * Declare all the break conditions 1922 */ 1923 1924 if (psContextMap[dwContextIndex].contextBlockStatus 1925 == BLOCK_STATUS_RESUME) 1926 break; 1927 1928 /* 1929 * Break if UNAWARE is set and all readers have been checked 1930 */ 1931 if ((dwBreakFlag == 1) && (j == 0)) 1932 break; 1933 1934 /* 1935 * Timeout has occurred and all readers checked 1936 */ 1937 if ((dwTimeout == 0) && (j == 0)) 1938 break; 1939 1940 if (dwTimeout != INFINITE && dwTimeout != 0) 1941 { 1942 /* 1943 * If time is greater than timeout and all readers have been 1944 * checked 1945 */ 1946 if ((dwTime >= (dwTimeout * 1000)) && (j == 0)) 1947 { 1948 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1949 return SCARD_E_TIMEOUT; 1950 } 1951 } 1952 1953 /* 1954 * Only sleep once for each cycle of reader checks. 1955 */ 1956 if (j == 0) 1957 { 1958 SYS_USleep(PCSCLITE_STATUS_WAIT); 1959 dwTime += PCSCLITE_STATUS_WAIT; 1960 } 1961 } 1962 while (1); 1963 1964 Log1(PCSC_LOG_DEBUG, "Event Loop End"); 1965 1966 if (psContextMap[dwContextIndex].contextBlockStatus == 1967 BLOCK_STATUS_RESUME) 1968 { 1969 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1970 return SCARD_E_CANCELLED; 1971 } 1972 1973 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 1974 1975 PROFILE_END 1976 1977 return SCARD_S_SUCCESS; 1978} 1979 1980#undef SCardControl 1981 1982LONG SCardControl(SCARDHANDLE hCard, const void *pbSendBuffer, 1983 DWORD cbSendLength, void *pbRecvBuffer, LPDWORD pcbRecvLength) 1984{ 1985 1986 SCARD_IO_REQUEST pioSendPci, pioRecvPci; 1987 1988 pioSendPci.dwProtocol = SCARD_PROTOCOL_RAW; 1989 pioRecvPci.dwProtocol = SCARD_PROTOCOL_RAW; 1990 1991 return SCardTransmit(hCard, &pioSendPci, pbSendBuffer, cbSendLength, 1992 &pioRecvPci, pbRecvBuffer, pcbRecvLength); 1993} 1994 1995/** 1996 * @brief This function sends a command directly to the IFD Handler to be 1997 * processed by the reader. 1998 * 1999 * This is useful for creating client side reader drivers for functions like 2000 * PIN pads, biometrics, or other extensions to the normal smart card reader 2001 * that are not normally handled by PC/SC. 2002 * 2003 * @note the API of this function changed. In pcsc-lite 1.2.0 and before the 2004 * API was not Windows(R) PC/SC compatible. This has been corrected. 2005 * 2006 * @param[in] hCard Connection made from SCardConnect. 2007 * @param[in] dwControlCode Control code for the operation.\n 2008 * <a href="http://pcsclite.alioth.debian.org/pcsc-lite/node26.html#Some_SCardControl_commands"> 2009 * Click here</a> for a list of supported commands by some drivers. 2010 * @param[in] pbSendBuffer Command to send to the reader. 2011 * @param[in] cbSendLength Length of the command. 2012 * @param[out] pbRecvBuffer Response from the reader. 2013 * @param[in] cbRecvLength Length of the response buffer. 2014 * @param[out] lpBytesReturned Length of the response. 2015 * 2016 * @return Error code. 2017 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 2018 * @retval SCARD_E_NOT_TRANSACTED Data exchange not successful (\ref SCARD_E_NOT_TRANSACTED) 2019 * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE) 2020 * @retval SCARD_E_INVALID_VALUE Invalid value was presented (\ref SCARD_E_INVALID_VALUE) 2021 * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed(\ref SCARD_E_READER_UNAVAILABLE) 2022 * @retval SCARD_W_RESET_CARD The card has been reset by another application (\ref SCARD_W_RESET_CARD) 2023 * @retval SCARD_W_REMOVED_CARD The card has been removed from the reader(\ref SCARD_W_REMOVED_CARD) 2024 * 2025 * @test 2026 * @code 2027 * LONG rv; 2028 * SCARDCONTEXT hContext; 2029 * SCARDHANDLE hCard; 2030 * DWORD dwActiveProtocol, dwSendLength, dwRecvLength; 2031 * BYTE pbRecvBuffer[10]; 2032 * BYTE pbSendBuffer[] = { 0x06, 0x00, 0x0A, 0x01, 0x01, 0x10 0x00 }; 2033 * ... 2034 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 2035 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_RAW &hCard, &dwActiveProtocol); 2036 * dwSendLength = sizeof(pbSendBuffer); 2037 * dwRecvLength = sizeof(pbRecvBuffer); 2038 * rv = SCardControl(hCard, 0x42000001, pbSendBuffer, dwSendLength, pbRecvBuffer, sizeof(pbRecvBuffer), &dwRecvLength); 2039 * @endcode 2040 */ 2041int32_t SCardControl132(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, 2042 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, 2043 LPDWORD lpBytesReturned) 2044{ 2045 // Real implementation to be provided as part of: 2046 // <rdar://problem/4711576> Support the new SCardControl function 2047 // 2048 2049 LONG rv; 2050 control_struct scControlStruct; 2051 sharedSegmentMsg msgStruct; 2052 int i; 2053 DWORD dwContextIndex, dwChannelIndex; 2054 2055 PROFILE_START 2056 2057 /* 0 bytes received by default */ 2058 if (NULL != lpBytesReturned) 2059 *lpBytesReturned = 0; 2060 2061 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 2062 return SCARD_E_NO_SERVICE; 2063 2064 /* 2065 * Make sure this handle has been opened 2066 */ 2067 rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex); 2068 2069 if (rv == -1) 2070 return SCARD_E_INVALID_HANDLE; 2071 2072 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 2073 2074 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 2075 { 2076 char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName; 2077 2078 /* by default r == NULL */ 2079 if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r)) 2080 break; 2081 } 2082 2083 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 2084 { 2085 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2086 return SCARD_E_READER_UNAVAILABLE; 2087 } 2088 2089 if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED) 2090 || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED)) 2091 { 2092 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2093 return SCARD_E_INSUFFICIENT_BUFFER; 2094 } 2095 2096 if ((cbSendLength > MAX_BUFFER_SIZE) || (cbRecvLength > MAX_BUFFER_SIZE)) 2097 { 2098 /* extended control */ 2099 unsigned char buffer[sizeof(sharedSegmentMsg) + MAX_BUFFER_SIZE_EXTENDED]; 2100 control_struct_extended *scControlStructExtended = (control_struct_extended *)buffer; 2101 sharedSegmentMsg *pmsgStruct = (psharedSegmentMsg)buffer; 2102 2103 scControlStructExtended->hCard = hCard; 2104 scControlStructExtended->dwControlCode = dwControlCode; 2105 scControlStructExtended->cbSendLength = cbSendLength; 2106 scControlStructExtended->cbRecvLength = cbRecvLength; 2107 scControlStructExtended->size = sizeof(*scControlStructExtended) + cbSendLength; 2108 memcpy(scControlStructExtended->data, pbSendBuffer, cbSendLength); 2109 2110 size_t csesize = scControlStructExtended->size; // remember it from before byte swap 2111 htonlControlStructExtended(scControlStructExtended); 2112 rv = WrapSHMWrite(SCARD_CONTROL_EXTENDED, 2113 psContextMap[dwContextIndex].dwClientID, 2114 csesize, 2115 SHMClientCommunicationTimeout(), buffer); 2116 2117 if (rv == -1) 2118 { 2119 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2120 return SCARD_E_NO_SERVICE; 2121 } 2122 2123 /* 2124 * Read a message from the server 2125 */ 2126 /* read the first block */ 2127 rv = SHMClientReadMessage(pmsgStruct, psContextMap[dwContextIndex].dwClientID, 0, SHMClientCommunicationTimeout()); 2128 if (rv == -1) 2129 { 2130 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2131 return SCARD_F_COMM_ERROR; 2132 } 2133 2134 /* we receive a sharedSegmentMsg and not a control_struct_extended */ 2135 scControlStructExtended = (control_struct_extended *)&(pmsgStruct -> data); 2136 ntohlControlStructExtended(scControlStructExtended); 2137 2138 /* a second block is present */ 2139 if (scControlStructExtended->size > PCSCLITE_MAX_MESSAGE_SIZE) 2140 { 2141 rv = SHMMessageReceive(buffer + sizeof(sharedSegmentMsg), 2142 scControlStructExtended->size-PCSCLITE_MAX_MESSAGE_SIZE, 2143 psContextMap[dwContextIndex].dwClientID, 2144 SHMClientCommunicationTimeout()); 2145 if (rv == -1) 2146 { 2147 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2148 return SCARD_F_COMM_ERROR; 2149 } 2150 } 2151 2152 if (scControlStructExtended -> rv == SCARD_S_SUCCESS) 2153 { 2154 /* 2155 * Copy and zero it so any secret information is not leaked 2156 */ 2157 memcpy(pbRecvBuffer, scControlStructExtended -> data, 2158 scControlStructExtended -> pdwBytesReturned); 2159 memset(scControlStructExtended -> data, 0x00, 2160 scControlStructExtended -> pdwBytesReturned); 2161 } 2162 2163 if (NULL != lpBytesReturned) 2164 *lpBytesReturned = scControlStructExtended -> pdwBytesReturned; 2165 2166 rv = scControlStructExtended -> rv; 2167 } 2168 else 2169 { 2170 scControlStruct.hCard = hCard; 2171 scControlStruct.dwControlCode = dwControlCode; 2172 scControlStruct.cbSendLength = cbSendLength; 2173 scControlStruct.cbRecvLength = cbRecvLength; 2174 memcpy(scControlStruct.pbSendBuffer, pbSendBuffer, cbSendLength); 2175 htonlControlStruct(&scControlStruct); 2176 2177 rv = WrapSHMWrite(SCARD_CONTROL, psContextMap[dwContextIndex].dwClientID, 2178 sizeof(scControlStruct), SHMClientCommunicationTimeout(), &scControlStruct); 2179 2180 if (rv == -1) 2181 { 2182 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2183 return SCARD_E_NO_SERVICE; 2184 } 2185 2186 /* 2187 * Read a message from the server 2188 */ 2189 rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(control_struct), SHMClientCommunicationTimeout()); 2190 2191 if (rv == -1) 2192 { 2193 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2194 return SCARD_F_COMM_ERROR; 2195 } 2196 2197 memcpy(&scControlStruct, &msgStruct.data, sizeof(scControlStruct)); 2198 ntohlControlStruct(&scControlStruct); 2199 2200 if (NULL != lpBytesReturned) 2201 *lpBytesReturned = scControlStruct.dwBytesReturned; 2202 2203 if (scControlStruct.rv == SCARD_S_SUCCESS) 2204 { 2205 /* 2206 * Copy and zero it so any secret information is not leaked 2207 */ 2208 memcpy(pbRecvBuffer, scControlStruct.pbRecvBuffer, 2209 scControlStruct.cbRecvLength); 2210 memset(scControlStruct.pbRecvBuffer, 0x00, 2211 sizeof(scControlStruct.pbRecvBuffer)); 2212 } 2213 2214 rv = scControlStruct.rv; 2215 } 2216 2217 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2218 2219 PROFILE_END 2220 2221 return rv; 2222} 2223 2224/** 2225 * This function get an attribute from the IFD Handler. The list of possible 2226 * attributes is available in the file \c pcsclite.h. 2227 * 2228 * @param[in] hCard Connection made from SCardConnect(). 2229 * @param[in] dwAttrId Identifier for the attribute to get. 2230 * <ul> 2231 * <li>\ref SCARD_ATTR_ASYNC_PROTOCOL_TYPES 2232 * <li>\ref SCARD_ATTR_ATR_STRING 2233 * <li>\ref SCARD_ATTR_CHANNEL_ID 2234 * <li>\ref SCARD_ATTR_CHARACTERISTICS 2235 * <li>\ref SCARD_ATTR_CURRENT_BWT 2236 * <li>\ref SCARD_ATTR_CURRENT_CLK 2237 * <li>\ref SCARD_ATTR_CURRENT_CWT 2238 * <li>\ref SCARD_ATTR_CURRENT_D 2239 * <li>\ref SCARD_ATTR_CURRENT_EBC_ENCODING 2240 * <li>\ref SCARD_ATTR_CURRENT_F 2241 * <li>\ref SCARD_ATTR_CURRENT_IFSC 2242 * <li>\ref SCARD_ATTR_CURRENT_IFSD 2243 * <li>\ref SCARD_ATTR_CURRENT_IO_STATE 2244 * <li>\ref SCARD_ATTR_CURRENT_N 2245 * <li>\ref SCARD_ATTR_CURRENT_PROTOCOL_TYPE 2246 * <li>\ref SCARD_ATTR_CURRENT_W 2247 * <li>\ref SCARD_ATTR_DEFAULT_CLK 2248 * <li>\ref SCARD_ATTR_DEFAULT_DATA_RATE 2249 * <li>\ref SCARD_ATTR_DEVICE_FRIENDLY_NAME_A 2250 * <li>\ref SCARD_ATTR_DEVICE_FRIENDLY_NAME_W 2251 * <li>\ref SCARD_ATTR_DEVICE_IN_USE 2252 * <li>\ref SCARD_ATTR_DEVICE_SYSTEM_NAME_A 2253 * <li>\ref SCARD_ATTR_DEVICE_SYSTEM_NAME_W 2254 * <li>\ref SCARD_ATTR_DEVICE_UNIT 2255 * <li>\ref SCARD_ATTR_ESC_AUTHREQUEST 2256 * <li>\ref SCARD_ATTR_ESC_CANCEL 2257 * <li>\ref SCARD_ATTR_ESC_RESET 2258 * <li>\ref SCARD_ATTR_EXTENDED_BWT 2259 * <li>\ref SCARD_ATTR_ICC_INTERFACE_STATUS 2260 * <li>\ref SCARD_ATTR_ICC_PRESENCE 2261 * <li>\ref SCARD_ATTR_ICC_TYPE_PER_ATR 2262 * <li>\ref SCARD_ATTR_MAX_CLK 2263 * <li>\ref SCARD_ATTR_MAX_DATA_RATE 2264 * <li>\ref SCARD_ATTR_MAX_IFSD 2265 * <li>\ref SCARD_ATTR_MAXINPUT 2266 * <li>\ref SCARD_ATTR_POWER_MGMT_SUPPORT 2267 * <li>\ref SCARD_ATTR_SUPRESS_T1_IFS_REQUEST 2268 * <li>\ref SCARD_ATTR_SYNC_PROTOCOL_TYPES 2269 * <li>\ref SCARD_ATTR_USER_AUTH_INPUT_DEVICE 2270 * <li>\ref SCARD_ATTR_USER_TO_CARD_AUTH_DEVICE 2271 * <li>\ref SCARD_ATTR_VENDOR_IFD_SERIAL_NO 2272 * <li>\ref SCARD_ATTR_VENDOR_IFD_TYPE 2273 * <li>\ref SCARD_ATTR_VENDOR_IFD_VERSION 2274 * <li>\ref SCARD_ATTR_VENDOR_NAME 2275 * </ul> 2276 * 2277 * Not all the dwAttrId values listed above may be implemented in the IFD 2278 * Handler you are using. And some dwAttrId values not listed here may be 2279 * implemented. 2280 * 2281 * @param[out] pbAttr Pointer to a buffer that receives the attribute. 2282 * @param pcbAttrLen [inout] Length of the \p pbAttr buffer in bytes. 2283 * 2284 * @return Error code. 2285 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 2286 * @retval SCARD_E_NOT_TRANSACTED Data exchange not successful (\ref SCARD_E_NOT_TRANSACTED) 2287 * @retval SCARD_E_INSUFFICIENT_BUFFER Reader buffer not large enough (\ref SCARD_E_INSUFFICIENT_BUFFER) 2288 * 2289 * @test 2290 * @code 2291 * LONG rv; 2292 * SCARDCONTEXT hContext; 2293 * SCARDHANDLE hCard; 2294 * DWORD dwActiveProtocol; 2295 * unsigned char pbAtr[MAX_ATR_SIZE]; 2296 * DWORD dwAtrLen; 2297 * ... 2298 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 2299 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, 2300 * SCARD_PROTOCOL_RAW &hCard, &dwActiveProtocol); 2301 * rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, pbAtr, &dwAtrLen); 2302 * @endcode 2303 */ 2304 2305int32_t SCardGetAttrib(SCARDHANDLE hCard, uint32_t dwAttrId, uint8_t * pbAttr, 2306 uint32_t * pcbAttrLen) 2307{ 2308 PROFILE_START 2309 2310 if (NULL == pcbAttrLen) 2311 return SCARD_E_INVALID_PARAMETER; 2312 2313 /* if only get the length */ 2314 if (NULL == pbAttr) 2315 /* this variable may not be set by the caller. use a reasonable size */ 2316 *pcbAttrLen = MAX_BUFFER_SIZE; 2317 2318 PROFILE_END 2319 2320 return SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, pbAttr, 2321 pcbAttrLen); 2322} 2323 2324/** 2325 * @brief This function set an attribute of the IFD Handler. 2326 * 2327 * The list of attributes you can set is dependent on the IFD Handler you are 2328 * using. 2329 * 2330 * @param[in] hCard Connection made from SCardConnect(). 2331 * @param[in] dwAttrId Identifier for the attribute to set. 2332 * @param[in] pbAttr Pointer to a buffer that receives the attribute. 2333 * @param[in] cbAttrLen Length of the \p pbAttr buffer in bytes. 2334 * 2335 * @return Error code 2336 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 2337 * @retval SCARD_E_NOT_TRANSACTED Data exchange not successful (\ref SCARD_E_NOT_TRANSACTED) 2338 * 2339 * @test 2340 * @code 2341 * LONG rv; 2342 * SCARDCONTEXT hContext; 2343 * SCARDHANDLE hCard; 2344 * DWORD dwActiveProtocol; 2345 * unsigned char pbAtr[MAX_ATR_SIZE]; 2346 * DWORD dwAtrLen; 2347 * ... 2348 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 2349 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, 2350 * SCARD_PROTOCOL_RAW &hCard, &dwActiveProtocol); 2351 * rv = SCardSetAttrib(hCard, 0x42000001, "\x12\x34\x56", 3); 2352 * @endcode 2353 */ 2354 2355int32_t SCardSetAttrib(SCARDHANDLE hCard, uint32_t dwAttrId, const uint8_t *pbAttr, 2356 uint32_t cbAttrLen) 2357{ 2358 PROFILE_START 2359 2360 if (NULL == pbAttr || 0 == cbAttrLen) 2361 return SCARD_E_INVALID_PARAMETER; 2362 2363 PROFILE_END 2364 2365 return SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr, 2366 &cbAttrLen); 2367} 2368 2369static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId, 2370 LPBYTE pbAttr, LPDWORD pcbAttrLen) 2371{ 2372 PROFILE_START 2373 2374 LONG rv; 2375 getset_struct scGetSetStruct; 2376 sharedSegmentMsg msgStruct; 2377 int i; 2378 DWORD dwContextIndex, dwChannelIndex; 2379 2380 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 2381 return SCARD_E_NO_SERVICE; 2382 2383 /* 2384 * Make sure this handle has been opened 2385 */ 2386 rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex); 2387 2388 if (rv == -1) 2389 return SCARD_E_INVALID_HANDLE; 2390 2391 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 2392 2393 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 2394 { 2395 char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName; 2396 2397 /* by default r == NULL */ 2398 if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r)) 2399 break; 2400 } 2401 2402 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 2403 { 2404 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2405 return SCARD_E_READER_UNAVAILABLE; 2406 } 2407 2408 if (*pcbAttrLen > MAX_BUFFER_SIZE) 2409 { 2410 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2411 return SCARD_E_INSUFFICIENT_BUFFER; 2412 } 2413 2414 scGetSetStruct.hCard = hCard; 2415 scGetSetStruct.dwAttrId = dwAttrId; 2416 scGetSetStruct.cbAttrLen = *pcbAttrLen; 2417 scGetSetStruct.rv = SCARD_E_NO_SERVICE; 2418 if (SCARD_SET_ATTRIB == command) 2419 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen); 2420 2421 ntohlGetSetStruct(&scGetSetStruct); 2422 rv = WrapSHMWrite(command, 2423 psContextMap[dwContextIndex].dwClientID, sizeof(scGetSetStruct), 2424 SHMClientCommunicationTimeout(), &scGetSetStruct); 2425 2426 if (rv == -1) 2427 { 2428 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2429 return SCARD_E_NO_SERVICE; 2430 } 2431 2432 /* 2433 * Read a message from the server 2434 */ 2435 rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(getset_struct), SHMClientCommunicationTimeout()); 2436 2437 if (rv == -1) 2438 { 2439 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2440 return SCARD_F_COMM_ERROR; 2441 } 2442 2443 memcpy(&scGetSetStruct, &msgStruct.data, sizeof(scGetSetStruct)); 2444 ntohlGetSetStruct(&scGetSetStruct); 2445 2446 if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command)) 2447 { 2448 /* 2449 * Copy and zero it so any secret information is not leaked 2450 */ 2451 if (*pcbAttrLen < scGetSetStruct.cbAttrLen) 2452 { 2453 scGetSetStruct.cbAttrLen = *pcbAttrLen; 2454 scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER; 2455 } 2456 else 2457 *pcbAttrLen = scGetSetStruct.cbAttrLen; 2458 2459 if (pbAttr) 2460 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen); 2461 2462 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr)); 2463 } 2464 2465 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2466 2467 PROFILE_END 2468 2469 return scGetSetStruct.rv; 2470} 2471 2472/** 2473 * @brief This function sends an APDU to the smart card contained in the reader 2474 * connected to by SCardConnect(). 2475 * 2476 * The card responds from the APDU and stores this response in pbRecvBuffer 2477 * and it's length in SpcbRecvLength. 2478 * SSendPci and SRecvPci are structures containing the following: 2479 * @code 2480 * typedef struct { 2481 * DWORD dwProtocol; // SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1 2482 * DWORD cbPciLength; // Length of this structure - not used 2483 * } SCARD_IO_REQUEST; 2484 * @endcode 2485 * 2486 * @param[in] hCard Connection made from SCardConnect(). 2487 * @param pioSendPci [inout] Structure of protocol information. 2488 * <ul> 2489 * <li>\ref SCARD_PCI_T0 - Pre-defined T=0 PCI structure. 2490 * <li>\ref SCARD_PCI_T1 - Pre-defined T=1 PCI structure. 2491 * </ul> 2492 * @param[in] pbSendBuffer APDU to send to the card. 2493 * @param[in] cbSendLength Length of the APDU. 2494 * @param pioRecvPci [inout] Structure of protocol information. 2495 * @param[out] pbRecvBuffer Response from the card. 2496 * @param pcbRecvLength [inout] Length of the response. 2497 * 2498 * @return Error code. 2499 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 2500 * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE) 2501 * @retval SCARD_E_NOT_TRANSACTED APDU exchange not successful (\ref SCARD_E_NOT_TRANSACTED) 2502 * @retval SCARD_E_PROTO_MISMATCH Connect protocol is different than desired (\ref SCARD_E_PROTO_MISMATCH) 2503 * @retval SCARD_E_INVALID_VALUE Invalid Protocol, reader name, etc (\ref SCARD_E_INVALID_VALUE) 2504 * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE) 2505 * @retval SCARD_W_RESET_CARD The card has been reset by another application (\ref SCARD_W_RESET_CARD) 2506 * @retval SCARD_W_REMOVED_CARD The card has been removed from the reader (\ref SCARD_W_REMOVED_CARD) 2507 * 2508 * @test 2509 * @code 2510 * LONG rv; 2511 * SCARDCONTEXT hContext; 2512 * SCARDHANDLE hCard; 2513 * DWORD dwActiveProtocol, dwSendLength, dwRecvLength; 2514 * SCARD_IO_REQUEST pioRecvPci; 2515 * BYTE pbRecvBuffer[10]; 2516 * BYTE pbSendBuffer[] = { 0xC0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00 }; 2517 * ... 2518 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 2519 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol); 2520 * dwSendLength = sizeof(pbSendBuffer); 2521 * dwRecvLength = sizeof(pbRecvBuffer); 2522 * rv = SCardTransmit(hCard, SCARD_PCI_T0, pbSendBuffer, dwSendLength, &pioRecvPci, pbRecvBuffer, &dwRecvLength); 2523 * @endcode 2524 */ 2525#include <syslog.h> 2526LONG SCardTransmit(SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci, 2527 LPCBYTE pbSendBuffer, DWORD cbSendLength, 2528 LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer, 2529 LPDWORD pcbRecvLength) 2530{ 2531 LONG rv; 2532 int i; 2533 DWORD dwContextIndex, dwChannelIndex; 2534 2535 PROFILE_START 2536 2537 if (pbSendBuffer == NULL || pbRecvBuffer == NULL || 2538 pcbRecvLength == NULL || pioSendPci == NULL) 2539 return SCARD_E_INVALID_PARAMETER; 2540 2541 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 2542 return SCARD_E_NO_SERVICE; 2543 2544 /* 2545 * Make sure this handle has been opened 2546 */ 2547 rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex); 2548 2549 if (rv == -1) 2550 { 2551 *pcbRecvLength = 0; 2552 return SCARD_E_INVALID_HANDLE; 2553 } 2554 2555 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 2556 2557 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 2558 { 2559 char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName; 2560 2561 /* by default r == NULL */ 2562 if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r)) 2563 break; 2564 } 2565 2566 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 2567 { 2568 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2569 return SCARD_E_READER_UNAVAILABLE; 2570 } 2571 2572 if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED) 2573 || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED)) 2574 { 2575 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2576 return SCARD_E_INSUFFICIENT_BUFFER; 2577 } 2578 2579 if ((cbSendLength > MAX_BUFFER_SIZE) || (*pcbRecvLength > MAX_BUFFER_SIZE)) 2580 { 2581 /* extended APDU */ 2582 unsigned char buffer[sizeof(sharedSegmentMsg) + MAX_BUFFER_SIZE_EXTENDED]; 2583 const sharedSegmentMsg *pmsgStruct = (psharedSegmentMsg)buffer; 2584 transmit_struct_extended *scTransmitStructExtended = (transmit_struct_extended *)buffer; 2585 2586 scTransmitStructExtended->hCard = hCard; 2587 scTransmitStructExtended->cbSendLength = cbSendLength; 2588 scTransmitStructExtended->pcbRecvLength = *pcbRecvLength; 2589 scTransmitStructExtended->size = sizeof(*scTransmitStructExtended) + cbSendLength; 2590 scTransmitStructExtended->pioSendPciProtocol = pioSendPci->dwProtocol; 2591 scTransmitStructExtended->pioSendPciLength = pioSendPci->cbPciLength; 2592 memcpy(scTransmitStructExtended->data, pbSendBuffer, cbSendLength); 2593 secdebug("pcscd", "Extended APDU: initial request: hCard: 0x%08X, cbSendLength: %d", 2594 hCard, cbSendLength); 2595 secdebug("pcscd", " pcbRecvLength: %d", *pcbRecvLength); 2596 2597 if (pioRecvPci) 2598 { 2599 scTransmitStructExtended->pioRecvPciProtocol = pioRecvPci->dwProtocol; 2600 scTransmitStructExtended->pioRecvPciLength = pioRecvPci->cbPciLength; 2601 } 2602 else 2603 scTransmitStructExtended->pioRecvPciProtocol = SCARD_PROTOCOL_ANY; 2604 2605 size_t tsesize = scTransmitStructExtended->size; // remember it before we byte swap 2606 LogXxd(PCSC_LOG_INFO, "Extended APDU: sending: ", pbSendBuffer, cbSendLength); 2607 htonlTransmitStructExtended(scTransmitStructExtended); 2608 rv = WrapSHMWrite(SCARD_TRANSMIT_EXTENDED, 2609 psContextMap[dwContextIndex].dwClientID, 2610 tsesize, 2611 SHMClientCommunicationTimeout(), buffer); 2612 secdebug("pcscd", "Extended APDU: WrapSHMWrite result: %d [0x%08X]", rv, rv); 2613 2614 if (rv == -1) 2615 { 2616 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2617 return SCARD_E_NO_SERVICE; 2618 } 2619 2620 /* 2621 * Read a message from the server 2622 */ 2623 rv = SHMClientReadMessage((psharedSegmentMsg)buffer, psContextMap[dwContextIndex].dwClientID, 0, SHMClientCommunicationTimeout()); 2624 if (rv == -1) 2625 { 2626 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2627 return SCARD_F_COMM_ERROR; 2628 } 2629 2630 /* we receive a sharedSegmentMsg and not a transmit_struct_extended */ 2631 scTransmitStructExtended = (transmit_struct_extended *)pmsgStruct->data; 2632 ntohlTransmitStructExtended(scTransmitStructExtended); 2633 secdebug("pcscd", "Extended APDU: reply received: hCard: 0x%08X, cbSendLength: %d", 2634 hCard, cbSendLength); 2635 secdebug("pcscd", " reply received: pcbRecvLength: %d, size: %llu", 2636 scTransmitStructExtended->pcbRecvLength, scTransmitStructExtended->size); 2637 secdebug("pcscd", " reply received: rv %d [0x%08X]", 2638 scTransmitStructExtended -> rv, scTransmitStructExtended -> rv); 2639 LogXxd(PCSC_LOG_INFO, "Extended APDU: received: ", scTransmitStructExtended->data, scTransmitStructExtended->pcbRecvLength); 2640 2641 /* a second block is present */ 2642 if (scTransmitStructExtended->size > PCSCLITE_MAX_MESSAGE_SIZE) 2643 { 2644 rv = SHMMessageReceive(buffer + sizeof(sharedSegmentMsg), 2645 scTransmitStructExtended->size-PCSCLITE_MAX_MESSAGE_SIZE, 2646 psContextMap[dwContextIndex].dwClientID, 2647 SHMClientCommunicationTimeout()); 2648 if (rv == -1) 2649 { 2650 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2651 return SCARD_F_COMM_ERROR; 2652 } 2653 // we don't fix up byte order here since this is in the data portion 2654 } 2655 2656 if (scTransmitStructExtended -> rv == SCARD_S_SUCCESS) 2657 { 2658 /* 2659 * Copy and zero it so any secret information is not leaked 2660 */ 2661 memcpy(pbRecvBuffer, scTransmitStructExtended -> data, 2662 scTransmitStructExtended -> pcbRecvLength); 2663 memset(scTransmitStructExtended -> data, 0x00, 2664 scTransmitStructExtended -> pcbRecvLength); 2665 2666 if (pioRecvPci) 2667 { 2668 pioRecvPci->dwProtocol = scTransmitStructExtended->pioRecvPciProtocol; 2669 pioRecvPci->cbPciLength = scTransmitStructExtended->pioRecvPciLength; 2670 } 2671 } 2672 2673 *pcbRecvLength = scTransmitStructExtended -> pcbRecvLength; 2674 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2675 2676 rv = scTransmitStructExtended -> rv; 2677 } 2678 else 2679 { 2680 /* short APDU */ 2681 transmit_struct scTransmitStruct; 2682 sharedSegmentMsg msgStruct; 2683 2684 scTransmitStruct.hCard = hCard; 2685 scTransmitStruct.cbSendLength = cbSendLength; 2686 scTransmitStruct.pcbRecvLength = *pcbRecvLength; 2687 scTransmitStruct.pioSendPciProtocol = pioSendPci->dwProtocol; 2688 scTransmitStruct.pioSendPciLength = pioSendPci->cbPciLength; 2689 memcpy(scTransmitStruct.pbSendBuffer, pbSendBuffer, cbSendLength); 2690 2691 if (pioRecvPci) 2692 { 2693 scTransmitStruct.pioRecvPciProtocol = pioRecvPci->dwProtocol; 2694 scTransmitStruct.pioRecvPciLength = pioRecvPci->cbPciLength; 2695 } 2696 else 2697 scTransmitStruct.pioRecvPciProtocol = SCARD_PROTOCOL_ANY; 2698 2699 htonlTransmitStruct(&scTransmitStruct); 2700 rv = WrapSHMWrite(SCARD_TRANSMIT, 2701 psContextMap[dwContextIndex].dwClientID, sizeof(scTransmitStruct), 2702 SHMClientCommunicationTimeout(), (void *) &scTransmitStruct); 2703 2704 if (rv == -1) 2705 { 2706 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2707 return SCARD_E_NO_SERVICE; 2708 } 2709 2710 /* 2711 * Read a message from the server 2712 */ 2713 rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(transmit_struct), SHMClientCommunicationTimeout()); 2714 2715 memcpy(&scTransmitStruct, &msgStruct.data, sizeof(scTransmitStruct)); 2716 ntohlTransmitStruct(&scTransmitStruct); 2717 2718 if (rv == -1) 2719 { 2720 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2721 return SCARD_F_COMM_ERROR; 2722 } 2723 2724 /* 2725 * Zero it and free it so any secret information cannot be leaked 2726 */ 2727 memset(scTransmitStruct.pbSendBuffer, 0x00, cbSendLength); 2728 2729 if (scTransmitStruct.rv == SCARD_S_SUCCESS) 2730 { 2731 /* 2732 * Copy and zero it so any secret information is not leaked 2733 */ 2734 memcpy(pbRecvBuffer, scTransmitStruct.pbRecvBuffer, 2735 scTransmitStruct.pcbRecvLength); 2736 memset(scTransmitStruct.pbRecvBuffer, 0x00, 2737 scTransmitStruct.pcbRecvLength); 2738 2739 if (pioRecvPci) 2740 { 2741 pioRecvPci->dwProtocol = scTransmitStruct.pioRecvPciProtocol; 2742 pioRecvPci->cbPciLength = scTransmitStruct.pioRecvPciLength; 2743 } 2744 } 2745 2746 *pcbRecvLength = scTransmitStruct.pcbRecvLength; 2747 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2748 2749 rv = scTransmitStruct.rv; 2750 } 2751 2752 PROFILE_END 2753 2754 return rv; 2755} 2756 2757/** 2758 * This function returns a list of currently available readers on the system. 2759 * \p mszReaders is a pointer to a character string that is allocated by the application. 2760 * If the application sends mszGroups and mszReaders as NULL then this function will 2761 * return the size of the buffer needed to allocate in pcchReaders. 2762 * 2763 * @param[in] hContext Connection context to the PC/SC Resource Manager. 2764 * @param[in] mszGroups List of groups to list readers (not used). 2765 * @param[out] mszReaders Multi-string with list of readers. 2766 * @param pcchReaders [inout] Size of multi-string buffer including NULL's. 2767 * 2768 * @return Connection status. 2769 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 2770 * @retval SCARD_E_INVALID_HANDLE Invalid Scope Handle (\ref SCARD_E_INVALID_HANDLE) 2771 * @retval SCARD_E_INSUFFICIENT_BUFFER Reader buffer not large enough (\ref SCARD_E_INSUFFICIENT_BUFFER) 2772 * 2773 * @test 2774 * @code 2775 * SCARDCONTEXT hContext; 2776 * LPSTR mszReaders; 2777 * DWORD dwReaders; 2778 * LONG rv; 2779 * ... 2780 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 2781 * rv = SCardListReaders(hContext, NULL, NULL, &dwReaders); 2782 * mszReaders = malloc(sizeof(char)*dwReaders); 2783 * rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders); 2784 * @endcode 2785 */ 2786LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, 2787 LPSTR mszReaders, LPDWORD pcchReaders) 2788{ 2789 DWORD dwReadersLen; 2790 int i, lastChrPtr; 2791 LONG dwContextIndex; 2792 2793 PROFILE_START 2794 2795 /* 2796 * Check for NULL parameters 2797 */ 2798 if (pcchReaders == NULL) 2799 return SCARD_E_INVALID_PARAMETER; 2800 2801 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 2802 return SCARD_E_NO_SERVICE; 2803 2804 /* 2805 * Make sure this context has been opened 2806 */ 2807 dwContextIndex = SCardGetContextIndice(hContext); 2808 if (dwContextIndex == -1) 2809 return SCARD_E_INVALID_HANDLE; 2810 2811 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 2812 2813 dwReadersLen = 0; 2814 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 2815 if (SharedReaderState_ReaderID(readerStates[i]) != 0) 2816 dwReadersLen += strlen(SharedReaderState_ReaderName(readerStates[i])) + 1; 2817 2818 /* for the last NULL byte */ 2819 dwReadersLen += 1; 2820 2821 if ((mszReaders == NULL) /* text array not allocated */ 2822 || (*pcchReaders == 0)) /* size == 0 */ 2823 { 2824 *pcchReaders = dwReadersLen; 2825 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2826 return SCARD_S_SUCCESS; 2827 } 2828 2829 if (*pcchReaders < dwReadersLen) 2830 { 2831 *pcchReaders = dwReadersLen; 2832 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2833 return SCARD_E_INSUFFICIENT_BUFFER; 2834 } 2835 2836 lastChrPtr = 0; 2837 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 2838 { 2839 if (SharedReaderState_ReaderID(readerStates[i]) != 0) 2840 { 2841 /* 2842 * Build the multi-string 2843 */ 2844 strcpy(&mszReaders[lastChrPtr], SharedReaderState_ReaderName(readerStates[i])); 2845 lastChrPtr += strlen(SharedReaderState_ReaderName(readerStates[i]))+1; 2846 } 2847 } 2848 mszReaders[lastChrPtr] = '\0'; /* Add the last null */ 2849 2850 *pcchReaders = dwReadersLen; 2851 2852 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2853 2854 PROFILE_END 2855 2856 return SCARD_S_SUCCESS; 2857} 2858 2859/** 2860 * @brief This function returns a list of currently available reader groups on the system. 2861 * \p mszGroups is a pointer to a character string that is allocated by the 2862 * application. If the application sends mszGroups as NULL then this function 2863 * will return the size of the buffer needed to allocate in pcchGroups. 2864 * 2865 * The group names is a multi-string and separated by a nul character ('\\0') and ended by 2866 * a double nul character. "SCard$DefaultReaders\\0Group 2\\0\\0". 2867 * 2868 * @param[in] hContext Connection context to the PC/SC Resource Manager. 2869 * @param[out] mszGroups List of groups to list readers. 2870 * @param pcchGroups [inout] Size of multi-string buffer including NULL's. 2871 * 2872 * @return Error code. 2873 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 2874 * @retval SCARD_E_INVALID_HANDLE Invalid Scope Handle (\ref SCARD_E_INVALID_HANDLE) 2875 * @retval SCARD_E_INSUFFICIENT_BUFFER Reader buffer not large enough (\ref SCARD_E_INSUFFICIENT_BUFFER) 2876 * 2877 * @test 2878 * @code 2879 * SCARDCONTEXT hContext; 2880 * LPSTR mszGroups; 2881 * DWORD dwGroups; 2882 * LONG rv; 2883 * ... 2884 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 2885 * rv = SCardListReaderGroups(hContext, NULL, &dwGroups); 2886 * mszGroups = malloc(sizeof(char)*dwGroups); 2887 * rv = SCardListReaderGroups(hContext, mszGroups, &dwGroups); 2888 * @endcode 2889 */ 2890LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, 2891 LPDWORD pcchGroups) 2892{ 2893 LONG rv = SCARD_S_SUCCESS; 2894 LONG dwContextIndex; 2895 2896 PROFILE_START 2897 2898 const char ReaderGroup[] = "SCard$DefaultReaders"; 2899 const int dwGroups = strlen(ReaderGroup) + 2; 2900 2901 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 2902 return SCARD_E_NO_SERVICE; 2903 2904 /* 2905 * Make sure this context has been opened 2906 */ 2907 dwContextIndex = SCardGetContextIndice(hContext); 2908 if (dwContextIndex == -1) 2909 return SCARD_E_INVALID_HANDLE; 2910 2911 SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 2912 2913 if (mszGroups) 2914 { 2915 2916 if (*pcchGroups < dwGroups) 2917 rv = SCARD_E_INSUFFICIENT_BUFFER; 2918 else 2919 { 2920 memset(mszGroups, 0, dwGroups); 2921 memcpy(mszGroups, ReaderGroup, strlen(ReaderGroup)); 2922 } 2923 } 2924 2925 *pcchGroups = dwGroups; 2926 2927 SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2928 2929 PROFILE_END 2930 2931 return rv; 2932} 2933 2934/** 2935 * This function cancels all pending blocking requests on the 2936 * SCardGetStatusChange() function. 2937 * 2938 * @param[in] hContext Connection context to the PC/SC Resource Manager. 2939 * 2940 * @return Error code. 2941 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 2942 * @retval SCARD_E_INVALID_HANDLE Invalid \p hContext handle (\ref SCARD_E_INVALID_HANDLE) 2943 * 2944 * @test 2945 * @code 2946 * SCARDCONTEXT hContext; 2947 * DWORD cReaders; 2948 * SCARD_READERSTATE rgReaderStates; 2949 * LONG rv; 2950 * ... 2951 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 2952 * rgReaderStates.szReader = strdup("Reader X"); 2953 * rgReaderStates.dwCurrentState = SCARD_STATE_EMPTY; 2954 * ... 2955 * / * Spawn off thread for following function * / 2956 * ... 2957 * rv = SCardGetStatusChange(hContext, 0, rgReaderStates, cReaders); 2958 * rv = SCardCancel(hContext); 2959 * @endcode 2960 */ 2961LONG SCardCancel(SCARDCONTEXT hContext) 2962{ 2963 LONG dwContextIndex; 2964 2965 PROFILE_START 2966 2967 dwContextIndex = SCardGetContextIndice(hContext); 2968 2969 if (dwContextIndex == -1) 2970 return SCARD_E_INVALID_HANDLE; 2971 2972 /* 2973 * Set the block status for this Context so blocking calls will 2974 * complete 2975 */ 2976 psContextMap[dwContextIndex].contextBlockStatus = BLOCK_STATUS_RESUME; 2977 2978 PROFILE_END 2979 2980 return SCARD_S_SUCCESS; 2981} 2982 2983/** 2984 * @brief check if a \ref SCARDCONTEXT is valid. 2985 * 2986 * Call this function to determine whether a smart card context handle is still 2987 * valid. After a smart card context handle has been set by \ref 2988 * SCardEstablishContext, it may become not valid if the resource manager 2989 * service has been shut down. 2990 * 2991 * @param[in] hContext Connection context to the PC/SC Resource Manager. 2992 * 2993 * @return Error code. 2994 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) 2995 * @retval SCARD_E_INVALID_HANDLE Invalid Handle (\ref SCARD_E_INVALID_HANDLE) 2996 * 2997 * @test 2998 * @code 2999 * SCARDCONTEXT hContext; 3000 * LONG rv; 3001 * ... 3002 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 3003 * rv = SCardIsValidContext(hContext); 3004 * @endcode 3005 */ 3006LONG SCardIsValidContext(SCARDCONTEXT hContext) 3007{ 3008 LONG rv; 3009 LONG dwContextIndex; 3010 3011 PROFILE_START 3012 3013 rv = SCARD_S_SUCCESS; 3014 3015 /* 3016 * Make sure this context has been opened 3017 */ 3018 dwContextIndex = SCardGetContextIndice(hContext); 3019 if (dwContextIndex == -1) 3020 rv = SCARD_E_INVALID_HANDLE; 3021 3022 PROFILE_END 3023 3024 return rv; 3025} 3026 3027/** 3028 * Functions for managing instances of SCardEstablishContext These functions 3029 * keep track of Context handles and associate the blocking 3030 * variable contextBlockStatus to an hContext 3031 */ 3032 3033/** 3034 * @brief Adds an Application Context to the vector \c psContextMap. 3035 * 3036 * @param[in] hContext Application Context ID. 3037 * @param[in] dwClientID Client connection ID. 3038 * 3039 * @return Error code. 3040 * @retval SCARD_S_SUCCESS Success (\ref SCARD_S_SUCCESS) 3041 * @retval SCARD_E_NO_MEMORY There is no free slot to store \p hContext (\ref SCARD_E_NO_MEMORY) 3042 */ 3043static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID) 3044{ 3045 int i; 3046 3047 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) 3048 { 3049 if (psContextMap[i].hContext == 0) 3050 { 3051 psContextMap[i].hContext = hContext; 3052 psContextMap[i].dwClientID = dwClientID; 3053 psContextMap[i].contextBlockStatus = BLOCK_STATUS_RESUME; 3054 psContextMap[i].mMutex = malloc(sizeof(PCSCLITE_MUTEX)); 3055 SYS_MutexInit(psContextMap[i].mMutex); 3056 return SCARD_S_SUCCESS; 3057 } 3058 } 3059 3060 return SCARD_E_NO_MEMORY; 3061} 3062 3063/** 3064 * @brief Get the index from the Application Context vector \c psContextMap 3065 * for the passed context. 3066 * 3067 * This function is a thread-safe wrapper to the function 3068 * SCardGetContextIndiceTH(). 3069 * 3070 * @param[in] hContext Application Context whose index will be find. 3071 * 3072 * @return Index corresponding to the Application Context or -1 if it is 3073 * not found. 3074 */ 3075static LONG SCardGetContextIndice(SCARDCONTEXT hContext) 3076{ 3077 LONG rv; 3078 3079 SCardLockThread(); 3080 rv = SCardGetContextIndiceTH(hContext); 3081 SCardUnlockThread(); 3082 3083 return rv; 3084} 3085 3086/** 3087 * @brief Get the index from the Application Context vector \c psContextMap 3088 * for the passed context. 3089 * 3090 * This functions is not thread-safe and should not be called. Instead, call 3091 * the function SCardGetContextIndice(). 3092 * 3093 * @param[in] hContext Application Context whose index will be find. 3094 * 3095 * @return Index corresponding to the Application Context or -1 if it is 3096 * not found. 3097 */ 3098static LONG SCardGetContextIndiceTH(SCARDCONTEXT hContext) 3099{ 3100 int i; 3101 3102 if (hContext == 0) 3103 return -1; 3104 3105 /* 3106 * Find this context and return its spot in the array 3107 */ 3108 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) 3109 if (hContext == psContextMap[i].hContext) 3110 return i; 3111 3112 return -1; 3113} 3114 3115/** 3116 * @brief Removes an Application Context from a control vector. 3117 * 3118 * @param[in] hContext Application Context to be removed. 3119 * 3120 * @return Error code. 3121 * @retval SCARD_S_SUCCESS Success (\ref SCARD_S_SUCCESS) 3122 * @retval SCARD_E_INVALID_HANDLE The context \p hContext was not found (\ref SCARD_E_INVALID_HANDLE) 3123 */ 3124static LONG SCardRemoveContext(SCARDCONTEXT hContext) 3125{ 3126 LONG retIndice; 3127 3128 retIndice = SCardGetContextIndiceTH(hContext); 3129 3130 if (retIndice == -1) 3131 return SCARD_E_INVALID_HANDLE; 3132 else 3133 { 3134 int i; 3135 3136 psContextMap[retIndice].hContext = 0; 3137 SHMClientCloseSession(psContextMap[retIndice].dwClientID); 3138 psContextMap[retIndice].dwClientID = 0; 3139 free(psContextMap[retIndice].mMutex); 3140 psContextMap[retIndice].mMutex = NULL; 3141 psContextMap[retIndice].contextBlockStatus = BLOCK_STATUS_RESUME; 3142 3143 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++) 3144 { 3145 /* 3146 * Reset the \c hCard structs to zero 3147 */ 3148 psContextMap[retIndice].psChannelMap[i].hCard = 0; 3149 free(psContextMap[retIndice].psChannelMap[i].readerName); 3150 psContextMap[retIndice].psChannelMap[i].readerName = NULL; 3151 } 3152 3153 return SCARD_S_SUCCESS; 3154 } 3155} 3156 3157/* 3158 * Functions for managing hCard values returned from SCardConnect. 3159 */ 3160 3161static LONG SCardAddHandle(SCARDHANDLE hCard, DWORD dwContextIndex, 3162 LPSTR readerName) 3163{ 3164 int i; 3165 3166 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++) 3167 { 3168 if (psContextMap[dwContextIndex].psChannelMap[i].hCard == 0) 3169 { 3170 psContextMap[dwContextIndex].psChannelMap[i].hCard = hCard; 3171 psContextMap[dwContextIndex].psChannelMap[i].readerName = strdup(readerName); 3172 return SCARD_S_SUCCESS; 3173 } 3174 } 3175 3176 return SCARD_E_NO_MEMORY; 3177} 3178 3179static LONG SCardRemoveHandle(SCARDHANDLE hCard) 3180{ 3181 DWORD dwContextIndice, dwChannelIndice; 3182 LONG rv; 3183 3184 rv = SCardGetIndicesFromHandle(hCard, &dwContextIndice, &dwChannelIndice); 3185 3186 if (rv == -1) 3187 return SCARD_E_INVALID_HANDLE; 3188 else 3189 { 3190 psContextMap[dwContextIndice].psChannelMap[dwChannelIndice].hCard = 0; 3191 free(psContextMap[dwContextIndice].psChannelMap[dwChannelIndice].readerName); 3192 psContextMap[dwContextIndice].psChannelMap[dwChannelIndice].readerName = NULL; 3193 return SCARD_S_SUCCESS; 3194 } 3195} 3196 3197static LONG SCardGetIndicesFromHandle(SCARDHANDLE hCard, PDWORD pdwContextIndice, PDWORD pdwChannelIndice) 3198{ 3199 LONG rv; 3200 3201 if (0 == hCard) 3202 return -1; 3203 3204 SCardLockThread(); 3205 rv = SCardGetIndicesFromHandleTH(hCard, pdwContextIndice, pdwChannelIndice); 3206 SCardUnlockThread(); 3207 3208 return rv; 3209} 3210 3211static LONG SCardGetIndicesFromHandleTH(SCARDHANDLE hCard, PDWORD pdwContextIndice, PDWORD pdwChannelIndice) 3212{ 3213 int i; 3214 3215 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) 3216 { 3217 if (psContextMap[i].hContext != 0) 3218 { 3219 int j; 3220 3221 for (j = 0; j < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; j++) 3222 { 3223 if (psContextMap[i].psChannelMap[j].hCard == hCard) 3224 { 3225 *pdwContextIndice = i; 3226 *pdwChannelIndice = j; 3227 return SCARD_S_SUCCESS; 3228 } 3229 } 3230 3231 } 3232 } 3233 3234 return -1; 3235} 3236 3237/** 3238 * @brief This function locks a mutex so another thread must wait to use this 3239 * function. 3240 * 3241 * Wrapper to the function SYS_MutexLock(). 3242 */ 3243inline static LONG SCardLockThread(void) 3244{ 3245 return SYS_MutexLock(&clientMutex); 3246} 3247 3248/** 3249 * @brief This function unlocks a mutex so another thread may use the client. 3250 * 3251 * Wrapper to the function SYS_MutexUnLock(). 3252 */ 3253inline static LONG SCardUnlockThread(void) 3254{ 3255 return SYS_MutexUnLock(&clientMutex); 3256} 3257 3258/** 3259 * @brief Checks if the Server is running. 3260 * 3261 * @return Error code. 3262 * @retval SCARD_S_SUCCESS Server is running (\ref SCARD_S_SUCCESS) 3263 * @retval SCARD_E_NO_SERVICE Server is not running (\ref SCARD_E_NO_SERVICE) 3264 */ 3265static LONG SCardCheckDaemonAvailability(void) 3266{ 3267 LONG rv; 3268 struct stat statBuffer; 3269 3270 rv = SYS_Stat(PCSCLITE_PUBSHM_FILE, &statBuffer); 3271 3272 if (rv != 0) 3273 { 3274 Log1(PCSC_LOG_ERROR, "PCSC Not Running"); 3275 return SCARD_E_NO_SERVICE; 3276 } 3277 3278 return SCARD_S_SUCCESS; 3279} 3280 3281/** 3282 * free resources allocated by the library 3283 * You _shall_ call this function if you use dlopen/dlclose to load/unload the 3284 * library. Otherwise you will exhaust the ressources available. 3285 */ 3286#ifdef __SUNPRO_C 3287#pragma fini (SCardUnload) 3288#endif 3289 3290void DESTRUCTOR SCardUnload(void) 3291{ 3292 int i; 3293 3294 if (!isExecuted) 3295 return; 3296 3297 /* unmap public shared file from memory */ 3298 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++) 3299 { 3300 if (readerStates[i] != NULL) 3301 { 3302 SYS_PublicMemoryUnmap(readerStates[i], sizeof(READER_STATE)); 3303 readerStates[i] = NULL; 3304 } 3305 } 3306 3307 SYS_CloseFile(mapAddr); 3308 isExecuted = 0; 3309} 3310 3311static int SCardInitializeOnce() 3312{ 3313 int pageSize; 3314 int i; 3315 3316 /* 3317 * Do any system initilization here 3318 */ 3319 SYS_Initialize(); 3320 3321 /* 3322 * Set up the memory mapped reader stats structures 3323 */ 3324 mapAddr = SYS_OpenFile(PCSCLITE_PUBSHM_FILE, O_RDONLY, 0); 3325 if (mapAddr < 0) 3326 { 3327 Log2(PCSC_LOG_ERROR, "Cannot open public shared file: %s", 3328 PCSCLITE_PUBSHM_FILE); 3329 return SCARD_E_NO_SERVICE; 3330 } 3331 3332 pageSize = SYS_GetPageSize(); 3333 3334 /* 3335 * Allocate each reader structure in the memory map 3336 */ 3337 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 3338 { 3339 readerStates[i] = 3340 (PREADER_STATE)SYS_PublicMemoryMap(sizeof(READER_STATE), 3341 mapAddr, (i * pageSize)); 3342 if (readerStates[i] == NULL) 3343 { 3344 Log1(PCSC_LOG_ERROR, "Cannot public memory map"); 3345 SYS_CloseFile(mapAddr); /* Close the memory map file */ 3346 return SCARD_F_INTERNAL_ERROR; 3347 } 3348 } 3349 3350 /* 3351 * Initializes the application contexts and all channels for each one 3352 */ 3353 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) 3354 { 3355 int j; 3356 3357 /* 3358 * Initially set the context struct to zero 3359 */ 3360 psContextMap[i].dwClientID = 0; 3361 psContextMap[i].hContext = 0; 3362 psContextMap[i].contextBlockStatus = BLOCK_STATUS_RESUME; 3363 psContextMap[i].mMutex = NULL; 3364 3365 for (j = 0; j < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; j++) 3366 { 3367 /* 3368 * Initially set the hcard structs to zero 3369 */ 3370 psContextMap[i].psChannelMap[j].hCard = 0; 3371 psContextMap[i].psChannelMap[j].readerName = NULL; 3372 } 3373 } 3374 3375 /* 3376 * Is there a free slot for this connection ? 3377 */ 3378 3379 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) 3380 { 3381 if (psContextMap[i].dwClientID == 0) 3382 break; 3383 } 3384 3385 if (i == PCSCLITE_MAX_APPLICATION_CONTEXTS) 3386 { 3387 return SCARD_E_NO_MEMORY; 3388 } 3389 3390 return SCARD_S_SUCCESS; 3391} 3392 3393static int SHMClientCommunicationTimeout() 3394{ 3395 /* 3396 This is a param to e.g. SHMClientReadMessage, and is a timeout in milliseconds. 3397 The constant PCSCLITE_SERVER_ATTEMPTS is very poorly named; it is a time value 3398 in milliseconds, not the number of attempts. Some values to use: 3399 5 default if PCSCLITE_ENHANCED_MESSAGING not defined 3400 200 if PCSCLITE_ENHANCED_MESSAGING is defined 3401 12000 might be a good value to set while debugging 3402 */ 3403 3404 static int baseTimeout = 12000;//PCSCLITE_CLIENT_ATTEMPTS; 3405 volatile int timeOut = baseTimeout; 3406 3407 return timeOut; 3408} 3409