FreeRDP/channels/smartcard/client/smartcard_operations.c

1556 lines
39 KiB
C
Raw Normal View History

/**
2012-10-09 05:00:07 +04:00
* FreeRDP: A Remote Desktop Protocol Implementation
* Smartcard Device Service Virtual Channel
*
* Copyright (C) Alexi Volkov <alexi@myrealbox.com> 2006
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Anthony Tong <atong@trustedcs.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
2011-10-15 19:30:10 +04:00
#include "config.h"
#endif
2011-10-15 19:30:10 +04:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <strings.h>
#include <pthread.h>
2012-10-02 17:57:32 +04:00
#include <semaphore.h>
2011-10-15 19:30:10 +04:00
2012-10-02 17:57:32 +04:00
#define BOOL PCSC_BOOL
2011-10-15 19:30:10 +04:00
#include <PCSC/pcsclite.h>
#include <PCSC/reader.h>
#include <PCSC/winscard.h>
2012-10-02 17:57:32 +04:00
#undef BOOL
2011-10-15 19:30:10 +04:00
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/stream.h>
2013-03-22 01:58:18 +04:00
#include <freerdp/freerdp.h>
2012-10-09 05:00:07 +04:00
#include <freerdp/channels/rdpdr.h>
2013-03-22 01:58:18 +04:00
#include <freerdp/utils/svc_plugin.h>
2011-10-15 19:30:10 +04:00
#include "smartcard_main.h"
2011-10-15 19:30:10 +04:00
/* [MS-RDPESC] 3.1.4 */
2012-10-09 05:00:07 +04:00
#define SCARD_IOCTL_ESTABLISH_CONTEXT 0x00090014 /* EstablishContext */
#define SCARD_IOCTL_RELEASE_CONTEXT 0x00090018 /* ReleaseContext */
#define SCARD_IOCTL_IS_VALID_CONTEXT 0x0009001C /* IsValidContext */
#define SCARD_IOCTL_LIST_READER_GROUPS 0x00090020 /* ListReaderGroups */
#define SCARD_IOCTL_LIST_READERS 0x00090028 /* ListReadersA */
#define SCARD_IOCTL_INTRODUCE_READER_GROUP 0x00090050 /* IntroduceReaderGroup */
#define SCARD_IOCTL_FORGET_READER_GROUP 0x00090058 /* ForgetReader */
#define SCARD_IOCTL_INTRODUCE_READER 0x00090060 /* IntroduceReader */
#define SCARD_IOCTL_FORGET_READER 0x00090068 /* IntroduceReader */
#define SCARD_IOCTL_ADD_READER_TO_GROUP 0x00090070 /* AddReaderToGroup */
#define SCARD_IOCTL_REMOVE_READER_FROM_GROUP 0x00090078 /* RemoveReaderFromGroup */
#define SCARD_IOCTL_GET_STATUS_CHANGE 0x000900A0 /* GetStatusChangeA */
#define SCARD_IOCTL_CANCEL 0x000900A8 /* Cancel */
#define SCARD_IOCTL_CONNECT 0x000900AC /* ConnectA */
#define SCARD_IOCTL_RECONNECT 0x000900B4 /* Reconnect */
#define SCARD_IOCTL_DISCONNECT 0x000900B8 /* Disconnect */
#define SCARD_IOCTL_BEGIN_TRANSACTION 0x000900BC /* BeginTransaction */
#define SCARD_IOCTL_END_TRANSACTION 0x000900C0 /* EndTransaction */
#define SCARD_IOCTL_STATE 0x000900C4 /* State */
#define SCARD_IOCTL_STATUS 0x000900C8 /* StatusA */
#define SCARD_IOCTL_TRANSMIT 0x000900D0 /* Transmit */
#define SCARD_IOCTL_CONTROL 0x000900D4 /* Control */
#define SCARD_IOCTL_GETATTRIB 0x000900D8 /* GetAttrib */
#define SCARD_IOCTL_SETATTRIB 0x000900DC /* SetAttrib */
#define SCARD_IOCTL_ACCESS_STARTED_EVENT 0x000900E0 /* SCardAccessStartedEvent */
#define SCARD_IOCTL_LOCATE_CARDS_BY_ATR 0x000900E8 /* LocateCardsByATR */
#define SCARD_INPUT_LINKED 0xFFFFFFFF
2011-10-15 19:30:10 +04:00
/* Decode Win CTL_CODE values */
2012-10-09 05:00:07 +04:00
#define WIN_CTL_FUNCTION(ctl_code) ((ctl_code & 0x3FFC) >> 2)
#define WIN_CTL_DEVICE_TYPE(ctl_code) (ctl_code >> 16)
2012-10-09 05:00:07 +04:00
#define WIN_FILE_DEVICE_SMARTCARD 0x00000031
static UINT32 smartcard_output_string(IRP* irp, char* src, BOOL wide)
2011-10-15 19:30:10 +04:00
{
BYTE* p;
2012-10-09 11:26:39 +04:00
UINT32 len;
2011-10-15 19:30:10 +04:00
p = stream_get_tail(irp->output);
len = strlen(src) + 1;
if (wide)
{
int i;
2011-10-15 19:30:10 +04:00
for (i = 0; i < len; i++ )
{
p[2 * i] = src[i] < 0 ? '?' : src[i];
p[2 * i + 1] = '\0';
}
len *= 2;
}
else
{
memcpy(p, src, len);
}
stream_seek(irp->output, len);
return len;
}
static void smartcard_output_alignment(IRP* irp, UINT32 seed)
2011-10-15 19:30:10 +04:00
{
2012-10-09 11:26:39 +04:00
const UINT32 field_lengths = 20;/* Remove the lengths of the fields
* RDPDR_HEADER, DeviceID,
* CompletionID, and IoStatus
* of Section 2.2.1.5.5 of MS-RDPEFS.
*/
2012-10-09 11:26:39 +04:00
UINT32 size = stream_get_length(irp->output) - field_lengths;
UINT32 add = (seed - (size % seed)) % seed;
2011-10-15 19:30:10 +04:00
if (add > 0)
stream_write_zero(irp->output, add);
}
static void smartcard_output_repos(IRP* irp, UINT32 written)
2011-10-15 19:30:10 +04:00
{
2012-10-09 11:26:39 +04:00
UINT32 add = (4 - (written % 4)) % 4;
2011-10-15 19:30:10 +04:00
if (add > 0)
stream_write_zero(irp->output, add);
}
static UINT32 smartcard_output_return(IRP* irp, UINT32 status)
2011-10-15 19:30:10 +04:00
{
stream_write_zero(irp->output, 256);
return status;
2011-10-15 19:30:10 +04:00
}
static void smartcard_output_buffer_limit(IRP* irp, char* buffer, unsigned int length, unsigned int highLimit)
2011-10-15 19:30:10 +04:00
{
int header = (length < 0) ? (0) : ((length > highLimit) ? (highLimit) : (length));
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, header);
2011-10-15 19:30:10 +04:00
if (length <= 0)
{
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, 0);
2011-10-15 19:30:10 +04:00
}
else
{
if (header < length)
length = header;
stream_write(irp->output, buffer, length);
smartcard_output_repos(irp, length);
2011-10-15 19:30:10 +04:00
}
}
static void smartcard_output_buffer(IRP* irp, char* buffer, unsigned int length)
2011-10-15 19:30:10 +04:00
{
smartcard_output_buffer_limit(irp, buffer, length, 0x7FFFFFFF);
2011-10-15 19:30:10 +04:00
}
static void smartcard_output_buffer_start_limit(IRP* irp, int length, int highLimit)
2011-10-15 19:30:10 +04:00
{
int header = (length < 0) ? (0) : ((length > highLimit) ? (highLimit) : (length));
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, header);
stream_write_UINT32(irp->output, 0x00000001); /* Magic DWORD - any non zero */
2011-10-15 19:30:10 +04:00
}
static void smartcard_output_buffer_start(IRP* irp, int length)
2011-10-15 19:30:10 +04:00
{
smartcard_output_buffer_start_limit(irp, length, 0x7FFFFFFF);
2011-10-15 19:30:10 +04:00
}
static UINT32 smartcard_input_string(IRP* irp, char** dest, UINT32 dataLength, BOOL wide)
2011-10-15 19:30:10 +04:00
{
2012-10-09 05:00:07 +04:00
char* buffer;
2011-10-15 19:30:10 +04:00
int bufferSize;
bufferSize = wide ? (2 * dataLength) : dataLength;
buffer = malloc(bufferSize + 2); /* reserve 2 bytes for the '\0' */
2011-10-15 19:30:10 +04:00
stream_read(irp->input, buffer, bufferSize);
2012-10-09 05:00:07 +04:00
2011-10-15 19:30:10 +04:00
if (wide)
{
int i;
for (i = 0; i < dataLength; i++)
{
if ((buffer[2 * i] < 0) || (buffer[2 * i + 1] != 0))
buffer[i] = '?';
else
buffer[i] = buffer[2 * i];
}
}
buffer[dataLength] = '\0';
*dest = buffer;
return bufferSize;
}
static void smartcard_input_repos(IRP* irp, UINT32 read)
2011-10-15 19:30:10 +04:00
{
2012-10-09 11:26:39 +04:00
UINT32 add = 4 - (read % 4);
2011-10-15 19:30:10 +04:00
if (add < 4 && add > 0)
stream_seek(irp->input, add);
}
static void smartcard_input_reader_name(IRP* irp, char** dest, BOOL wide)
2011-10-15 19:30:10 +04:00
{
2012-10-09 11:26:39 +04:00
UINT32 dataLength;
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 8);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, dataLength);
2011-10-15 19:30:10 +04:00
DEBUG_SCARD("datalength %d", dataLength);
smartcard_input_repos(irp, smartcard_input_string(irp, dest, dataLength, wide));
2011-10-15 19:30:10 +04:00
}
static void smartcard_input_skip_linked(IRP* irp)
2011-10-15 19:30:10 +04:00
{
2012-10-09 11:26:39 +04:00
UINT32 len;
stream_read_UINT32(irp->input, len);
2011-10-15 19:30:10 +04:00
if (len > 0)
{
stream_seek(irp->input, len);
smartcard_input_repos(irp, len);
2011-10-15 19:30:10 +04:00
}
}
static UINT32 smartcard_map_state(UINT32 state)
2011-10-15 19:30:10 +04:00
{
/* is this mapping still needed? */
2011-10-15 19:30:10 +04:00
if (state & SCARD_SPECIFIC)
state = 0x00000006;
else if (state & SCARD_NEGOTIABLE)
state = 0x00000006;
2011-10-15 19:30:10 +04:00
else if (state & SCARD_POWERED)
state = 0x00000004;
else if (state & SCARD_SWALLOWED)
state = 0x00000003;
else if (state & SCARD_PRESENT)
state = 0x00000002;
else if (state & SCARD_ABSENT)
state = 0x00000001;
else
state = 0x00000000;
return state;
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_EstablishContext(IRP* irp)
2011-10-15 19:30:10 +04:00
{
UINT32 len;
UINT32 status;
2012-10-09 11:26:39 +04:00
UINT32 scope;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext = -1;
stream_seek(irp->input, 8);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, len);
2011-10-15 19:30:10 +04:00
if (len != 8)
return SCARD_F_INTERNAL_ERROR;
2012-10-09 11:26:39 +04:00
stream_seek_UINT32(irp->input);
stream_read_UINT32(irp->input, scope);
2011-10-15 19:30:10 +04:00
status = SCardEstablishContext(scope, NULL, NULL, &hContext);
2011-10-15 19:30:10 +04:00
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, 4); // cbContext
stream_write_UINT32(irp->output, -1); // ReferentID
2011-10-15 19:30:10 +04:00
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, 4);
stream_write_UINT32(irp->output, hContext);
2011-10-15 19:30:10 +04:00
/* TODO: store hContext in allowed context list */
2011-10-15 19:30:10 +04:00
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
return SCARD_S_SUCCESS;
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_ReleaseContext(IRP* irp)
2011-10-15 19:30:10 +04:00
{
UINT32 len, status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext = -1;
stream_seek(irp->input, 8);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, len);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x10);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hContext);
2011-10-15 19:30:10 +04:00
status = SCardReleaseContext(hContext);
if (status)
DEBUG_SCARD("%s (0x%08x)", pcsc_stringify_error(status), (unsigned) status);
2011-10-15 19:30:10 +04:00
else
DEBUG_SCARD("success 0x%08lx", hContext);
smartcard_output_alignment(irp, 8);
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_IsValidContext(IRP* irp)
2011-10-15 19:30:10 +04:00
{
UINT32 status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
stream_seek(irp->input, 0x1C);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hContext);
2011-10-15 19:30:10 +04:00
status = SCardIsValidContext(hContext);
2011-10-15 19:30:10 +04:00
if (status)
DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(status), (unsigned) status);
2011-10-15 19:30:10 +04:00
else
DEBUG_SCARD("Success context: 0x%08x", (unsigned) hContext);
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_ListReaders(IRP* irp, BOOL wide)
2011-10-15 19:30:10 +04:00
{
UINT32 len, status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
DWORD dwReaders;
char *readerList = NULL, *walker;
int elemLength, dataLength;
int pos, poslen1, poslen2;
stream_seek(irp->input, 8);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, len);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x1c);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, len);
2011-10-15 19:30:10 +04:00
if (len != 4)
return SCARD_F_INTERNAL_ERROR;
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hContext);
2011-10-15 19:30:10 +04:00
/* ignore rest of [MS-RDPESC] 2.2.2.4 ListReaders_Call */
status = SCARD_S_SUCCESS;
2011-10-15 19:30:10 +04:00
#ifdef SCARD_AUTOALLOCATE
dwReaders = SCARD_AUTOALLOCATE;
status = SCardListReaders(hContext, NULL, (LPSTR) &readerList, &dwReaders);
2011-10-15 19:30:10 +04:00
#else
status = SCardListReaders(hContext, NULL, NULL, &dwReaders);
2011-10-15 19:30:10 +04:00
readerList = malloc(dwReaders);
status = SCardListReaders(hContext, NULL, readerList, &dwReaders);
2011-10-15 19:30:10 +04:00
#endif
if (status != SCARD_S_SUCCESS)
2011-10-15 19:30:10 +04:00
{
DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(status), (unsigned) status);
return status;
2011-10-15 19:30:10 +04:00
}
/* DEBUG_SCARD("Success 0x%08x %d %d", (unsigned) hContext, (unsigned) cchReaders, (int) strlen(readerList));*/
2011-10-15 19:30:10 +04:00
poslen1 = stream_get_pos(irp->output);
2012-10-09 11:26:39 +04:00
stream_seek_UINT32(irp->output);
2011-10-15 19:30:10 +04:00
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, 0x01760650);
2011-10-15 19:30:10 +04:00
poslen2 = stream_get_pos(irp->output);
2012-10-09 11:26:39 +04:00
stream_seek_UINT32(irp->output);
2011-10-15 19:30:10 +04:00
walker = readerList;
dataLength = 0;
2011-10-15 19:30:10 +04:00
while (1)
{
elemLength = strlen(walker);
if (elemLength == 0)
break;
dataLength += smartcard_output_string(irp, walker, wide);
2011-10-15 19:30:10 +04:00
walker += elemLength + 1;
elemLength = strlen(walker);
}
dataLength += smartcard_output_string(irp, "\0", wide);
2011-10-15 19:30:10 +04:00
pos = stream_get_pos(irp->output);
stream_set_pos(irp->output, poslen1);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, dataLength);
2011-10-15 19:30:10 +04:00
stream_set_pos(irp->output, poslen2);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, dataLength);
2011-10-15 19:30:10 +04:00
stream_set_pos(irp->output, pos);
smartcard_output_repos(irp, dataLength);
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
#ifdef SCARD_AUTOALLOCATE
SCardFreeMemory(hContext, readerList);
#else
free(readerList);
2011-10-15 19:30:10 +04:00
#endif
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_GetStatusChange(IRP* irp, BOOL wide)
2011-10-15 19:30:10 +04:00
{
int i;
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
DWORD dwTimeout = 0;
DWORD readerCount = 0;
SCARD_READERSTATE *readerStates, *cur;
stream_seek(irp->input, 0x18);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, dwTimeout);
stream_read_UINT32(irp->input, readerCount);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 8);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hContext);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 4);
DEBUG_SCARD("context: 0x%08x, timeout: 0x%08x, count: %d",
(unsigned) hContext, (unsigned) dwTimeout, (int) readerCount);
2011-10-15 19:30:10 +04:00
if (readerCount > 0)
{
readerStates = malloc(readerCount * sizeof(SCARD_READERSTATE));
ZeroMemory(readerStates, readerCount * sizeof(SCARD_READERSTATE));
2011-10-15 19:30:10 +04:00
if (!readerStates)
return smartcard_output_return(irp, SCARD_E_NO_MEMORY);
2011-10-15 19:30:10 +04:00
for (i = 0; i < readerCount; i++)
{
cur = &readerStates[i];
stream_seek(irp->input, 4);
/*
* TODO: on-wire is little endian; need to either
* convert to host endian or fix the headers to
* request the order we want
*/
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, cur->dwCurrentState);
stream_read_UINT32(irp->input, cur->dwEventState);
stream_read_UINT32(irp->input, cur->cbAtr);
2011-10-15 19:30:10 +04:00
stream_read(irp->input, cur->rgbAtr, 32);
stream_seek(irp->input, 4);
/* reset high bytes? */
cur->dwCurrentState &= 0x0000FFFF;
cur->dwEventState = 0;
}
for (i = 0; i < readerCount; i++)
{
cur = &readerStates[i];
2012-10-09 11:26:39 +04:00
UINT32 dataLength;
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 8);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, dataLength);
smartcard_input_repos(irp, smartcard_input_string(irp, (char **) &cur->szReader, dataLength, wide));
2011-10-15 19:30:10 +04:00
DEBUG_SCARD(" \"%s\"", cur->szReader ? cur->szReader : "NULL");
DEBUG_SCARD(" user: 0x%08x, state: 0x%08x, event: 0x%08x",
(unsigned) cur->pvUserData, (unsigned) cur->dwCurrentState,
(unsigned) cur->dwEventState);
if (strcmp(cur->szReader, "\\\\?PnP?\\Notification") == 0)
cur->dwCurrentState |= SCARD_STATE_IGNORE;
}
}
else
{
readerStates = NULL;
}
status = SCardGetStatusChange(hContext, (DWORD) dwTimeout, readerStates, (DWORD) readerCount);
2011-10-15 19:30:10 +04:00
if (status != SCARD_S_SUCCESS)
DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(status), (unsigned) status);
2011-10-15 19:30:10 +04:00
else
DEBUG_SCARD("Success");
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, readerCount);
stream_write_UINT32(irp->output, 0x00084dd8);
stream_write_UINT32(irp->output, readerCount);
2011-10-15 19:30:10 +04:00
for (i = 0; i < readerCount; i++)
{
cur = &readerStates[i];
DEBUG_SCARD(" \"%s\"", cur->szReader ? cur->szReader : "NULL");
DEBUG_SCARD(" user: 0x%08x, state: 0x%08x, event: 0x%08x",
2011-10-15 19:30:10 +04:00
(unsigned) cur->pvUserData, (unsigned) cur->dwCurrentState,
(unsigned) cur->dwEventState);
/* TODO: do byte conversions if necessary */
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, cur->dwCurrentState);
stream_write_UINT32(irp->output, cur->dwEventState);
stream_write_UINT32(irp->output, cur->cbAtr);
2011-10-15 19:30:10 +04:00
stream_write(irp->output, cur->rgbAtr, 32);
stream_write_zero(irp->output, 4);
free((void *)cur->szReader);
2011-10-15 19:30:10 +04:00
}
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
free(readerStates);
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_Cancel(IRP *irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
stream_seek(irp->input, 0x1C);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hContext);
2011-10-15 19:30:10 +04:00
status = SCardCancel(hContext);
2011-10-15 19:30:10 +04:00
if (status != SCARD_S_SUCCESS)
DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(status), (unsigned) status);
2011-10-15 19:30:10 +04:00
else
DEBUG_SCARD("Success context: 0x%08x %s", (unsigned) hContext, pcsc_stringify_error(status));
2011-10-15 19:30:10 +04:00
smartcard_output_alignment(irp, 8);
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_Connect(IRP* irp, BOOL wide)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
char* readerName = NULL;
2011-10-15 19:30:10 +04:00
DWORD dwShareMode = 0;
DWORD dwPreferredProtocol = 0;
DWORD dwActiveProtocol = 0;
SCARDHANDLE hCard;
stream_seek(irp->input, 0x1c);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, dwShareMode);
stream_read_UINT32(irp->input, dwPreferredProtocol);
2011-10-15 19:30:10 +04:00
smartcard_input_reader_name(irp, &readerName, wide);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 4);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hContext);
2011-10-15 19:30:10 +04:00
DEBUG_SCARD("(context: 0x%08x, share: 0x%08x, proto: 0x%08x, reader: \"%s\")",
(unsigned) hContext, (unsigned) dwShareMode,
(unsigned) dwPreferredProtocol, readerName ? readerName : "NULL");
status = SCardConnect(hContext, readerName, (DWORD) dwShareMode,
2011-10-15 19:30:10 +04:00
(DWORD) dwPreferredProtocol, &hCard, (DWORD *) &dwActiveProtocol);
if (status != SCARD_S_SUCCESS)
DEBUG_SCARD("Failure: %s 0x%08x", pcsc_stringify_error(status), (unsigned) status);
2011-10-15 19:30:10 +04:00
else
DEBUG_SCARD("Success 0x%08x", (unsigned) hCard);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, 0x00000000);
stream_write_UINT32(irp->output, 0x00000000);
stream_write_UINT32(irp->output, 0x00000004);
stream_write_UINT32(irp->output, 0x016Cff34);
stream_write_UINT32(irp->output, dwActiveProtocol);
stream_write_UINT32(irp->output, 0x00000004);
stream_write_UINT32(irp->output, hCard);
2011-10-15 19:30:10 +04:00
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
free(readerName);
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_Reconnect(IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
SCARDHANDLE hCard;
DWORD dwShareMode = 0;
DWORD dwPreferredProtocol = 0;
DWORD dwInitialization = 0;
DWORD dwActiveProtocol = 0;
stream_seek(irp->input, 0x20);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, dwShareMode);
stream_read_UINT32(irp->input, dwPreferredProtocol);
stream_read_UINT32(irp->input, dwInitialization);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x4);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hContext);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x4);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hCard);
2011-10-15 19:30:10 +04:00
DEBUG_SCARD("(context: 0x%08x, hcard: 0x%08x, share: 0x%08x, proto: 0x%08x, init: 0x%08x)",
(unsigned) hContext, (unsigned) hCard,
(unsigned) dwShareMode, (unsigned) dwPreferredProtocol, (unsigned) dwInitialization);
status = SCardReconnect(hCard, (DWORD) dwShareMode, (DWORD) dwPreferredProtocol,
2011-10-15 19:30:10 +04:00
(DWORD) dwInitialization, (LPDWORD) &dwActiveProtocol);
if (status != SCARD_S_SUCCESS)
DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(status), (unsigned) status);
2011-10-15 19:30:10 +04:00
else
DEBUG_SCARD("Success (proto: 0x%08x)", (unsigned) dwActiveProtocol);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, dwActiveProtocol);
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_Disconnect(IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
SCARDHANDLE hCard;
DWORD dwDisposition = 0;
stream_seek(irp->input, 0x20);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, dwDisposition);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 4);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hContext);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 4);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hCard);
2011-10-15 19:30:10 +04:00
DEBUG_SCARD("(context: 0x%08x, hcard: 0x%08x, disposition: 0x%08x)",
(unsigned) hContext, (unsigned) hCard, (unsigned) dwDisposition);
status = SCardDisconnect(hCard, (DWORD) dwDisposition);
2011-10-15 19:30:10 +04:00
if (status != SCARD_S_SUCCESS)
DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(status), (unsigned) status);
2011-10-15 19:30:10 +04:00
else
DEBUG_SCARD("Success");
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_BeginTransaction(IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hCard;
stream_seek(irp->input, 0x30);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hCard);
2011-10-15 19:30:10 +04:00
status = SCardBeginTransaction(hCard);
2011-10-15 19:30:10 +04:00
if (status != SCARD_S_SUCCESS)
DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(status), (unsigned) status);
2011-10-15 19:30:10 +04:00
else
DEBUG_SCARD("Success hcard: 0x%08x", (unsigned) hCard);
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_EndTransaction(IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hCard;
DWORD dwDisposition = 0;
stream_seek(irp->input, 0x20);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, dwDisposition);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x0C);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hCard);
2011-10-15 19:30:10 +04:00
status = SCardEndTransaction(hCard, dwDisposition);
if (status != SCARD_S_SUCCESS)
DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(status), (unsigned) status);
2011-10-15 19:30:10 +04:00
else
DEBUG_SCARD("Success hcard: 0x%08x", (unsigned) hCard);
smartcard_output_alignment(irp, 8);
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_State(IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDHANDLE hCard;
DWORD state = 0, protocol = 0;
DWORD readerLen;
DWORD atrLen = MAX_ATR_SIZE;
char* readerName;
2011-10-15 19:30:10 +04:00
BYTE pbAtr[MAX_ATR_SIZE];
#ifdef WITH_DEBUG_SCARD
int i;
#endif
stream_seek(irp->input, 0x24);
2012-10-09 11:26:39 +04:00
stream_seek_UINT32(irp->input); /* atrLen */
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x0c);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hCard);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x04);
#ifdef SCARD_AUTOALLOCATE
readerLen = SCARD_AUTOALLOCATE;
status = SCardStatus(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
2011-10-15 19:30:10 +04:00
#else
readerLen = 256;
readerName = malloc(readerLen);
2011-10-15 19:30:10 +04:00
status = SCardStatus(hCard, (LPSTR) readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
2011-10-15 19:30:10 +04:00
#endif
if (status != SCARD_S_SUCCESS)
2011-10-15 19:30:10 +04:00
{
DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(status), (unsigned) status);
return smartcard_output_return(irp, status);
2011-10-15 19:30:10 +04:00
}
DEBUG_SCARD("Success (hcard: 0x%08x len: %d state: 0x%08x, proto: 0x%08x)",
(unsigned) hCard, (int) atrLen, (unsigned) state, (unsigned) protocol);
#ifdef WITH_DEBUG_SCARD
printf(" ATR: ");
for (i = 0; i < atrLen; i++)
printf("%02x%c", pbAtr[i], (i == atrLen - 1) ? ' ' : ':');
printf("\n");
#endif
state = smartcard_map_state(state);
2011-10-15 19:30:10 +04:00
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, state);
stream_write_UINT32(irp->output, protocol);
stream_write_UINT32(irp->output, atrLen);
stream_write_UINT32(irp->output, 0x00000001);
stream_write_UINT32(irp->output, atrLen);
2011-10-15 19:30:10 +04:00
stream_write(irp->output, pbAtr, atrLen);
smartcard_output_repos(irp, atrLen);
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
#ifdef SCARD_AUTOALLOCATE
free(readerName);
2011-10-15 19:30:10 +04:00
#else
free(readerName);
2011-10-15 19:30:10 +04:00
#endif
return status;
2011-10-15 19:30:10 +04:00
}
static DWORD handle_Status(IRP *irp, BOOL wide)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDHANDLE hCard;
DWORD state, protocol;
DWORD readerLen = 0;
DWORD atrLen = 0;
char* readerName;
2011-10-15 19:30:10 +04:00
BYTE pbAtr[MAX_ATR_SIZE];
2012-10-09 11:26:39 +04:00
UINT32 dataLength;
2011-10-15 19:30:10 +04:00
int pos, poslen1, poslen2;
#ifdef WITH_DEBUG_SCARD
int i;
#endif
stream_seek(irp->input, 0x24);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, readerLen);
stream_read_UINT32(irp->input, atrLen);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x0c);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hCard);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x4);
atrLen = MAX_ATR_SIZE;
#ifdef SCARD_AUTOALLOCATE
readerLen = SCARD_AUTOALLOCATE;
status = SCardStatus(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
2011-10-15 19:30:10 +04:00
#else
readerLen = 256;
readerName = malloc(readerLen);
2011-10-15 19:30:10 +04:00
status = SCardStatus(hCard, (LPSTR) readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
2011-10-15 19:30:10 +04:00
#endif
if (status != SCARD_S_SUCCESS)
2011-10-15 19:30:10 +04:00
{
DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(status), (unsigned) status);
return smartcard_output_return(irp, status);
2011-10-15 19:30:10 +04:00
}
DEBUG_SCARD("Success (state: 0x%08x, proto: 0x%08x)", (unsigned) state, (unsigned) protocol);
DEBUG_SCARD(" Reader: \"%s\"", readerName ? readerName : "NULL");
#ifdef WITH_DEBUG_SCARD
printf(" ATR: ");
for (i = 0; i < atrLen; i++)
printf("%02x%c", pbAtr[i], (i == atrLen - 1) ? ' ' : ':');
printf("\n");
#endif
state = smartcard_map_state(state);
2011-10-15 19:30:10 +04:00
poslen1 = stream_get_pos(irp->output);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, readerLen);
stream_write_UINT32(irp->output, 0x00020000);
stream_write_UINT32(irp->output, state);
stream_write_UINT32(irp->output, protocol);
2011-10-15 19:30:10 +04:00
stream_write(irp->output, pbAtr, atrLen);
if (atrLen < 32)
stream_write_zero(irp->output, 32 - atrLen);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, atrLen);
2011-10-15 19:30:10 +04:00
poslen2 = stream_get_pos(irp->output);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, readerLen);
2011-10-15 19:30:10 +04:00
dataLength = smartcard_output_string(irp, readerName, wide);
dataLength += smartcard_output_string(irp, "\0", wide);
smartcard_output_repos(irp, dataLength);
2011-10-15 19:30:10 +04:00
pos = stream_get_pos(irp->output);
stream_set_pos(irp->output, poslen1);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output,dataLength);
2011-10-15 19:30:10 +04:00
stream_set_pos(irp->output, poslen2);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output,dataLength);
2011-10-15 19:30:10 +04:00
stream_set_pos(irp->output, pos);
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
#ifdef SCARD_AUTOALLOCATE
/* SCardFreeMemory(NULL, readerName); */
2011-10-15 19:30:10 +04:00
free(readerName);
#else
free(readerName);
2011-10-15 19:30:10 +04:00
#endif
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_Transmit(IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hCard;
2012-10-09 11:26:39 +04:00
UINT32 map[7], linkedLen;
2011-10-15 19:30:10 +04:00
SCARD_IO_REQUEST pioSendPci, pioRecvPci, *pPioRecvPci;
DWORD cbSendLength = 0, cbRecvLength = 0;
BYTE *sendBuf = NULL, *recvBuf = NULL;
stream_seek(irp->input, 0x14);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, map[0]);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x4);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, map[1]);
2011-10-15 19:30:10 +04:00
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, pioSendPci.dwProtocol);
stream_read_UINT32(irp->input, pioSendPci.cbPciLength);
2011-10-15 19:30:10 +04:00
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, map[2]);
stream_read_UINT32(irp->input, cbSendLength);
stream_read_UINT32(irp->input, map[3]);
stream_read_UINT32(irp->input, map[4]);
stream_read_UINT32(irp->input, map[5]);
stream_read_UINT32(irp->input, cbRecvLength);
2011-10-15 19:30:10 +04:00
if (map[0] & SCARD_INPUT_LINKED)
smartcard_input_skip_linked(irp);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 4);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hCard);
2011-10-15 19:30:10 +04:00
if (map[2] & SCARD_INPUT_LINKED)
{
/* sendPci */
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, linkedLen);
2011-10-15 19:30:10 +04:00
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, pioSendPci.dwProtocol);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, linkedLen - 4);
smartcard_input_repos(irp, linkedLen);
2011-10-15 19:30:10 +04:00
}
pioSendPci.cbPciLength = sizeof(SCARD_IO_REQUEST);
if (map[3] & SCARD_INPUT_LINKED)
{
/* send buffer */
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, linkedLen);
2011-10-15 19:30:10 +04:00
sendBuf = malloc(linkedLen);
2011-10-15 19:30:10 +04:00
stream_read(irp->input, sendBuf, linkedLen);
smartcard_input_repos(irp, linkedLen);
2011-10-15 19:30:10 +04:00
}
if (cbRecvLength)
recvBuf = malloc(cbRecvLength);
2011-10-15 19:30:10 +04:00
if (map[4] & SCARD_INPUT_LINKED)
{
/* recvPci */
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, linkedLen);
2011-10-15 19:30:10 +04:00
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, pioRecvPci.dwProtocol);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, linkedLen - 4);
smartcard_input_repos(irp, linkedLen);
2011-10-15 19:30:10 +04:00
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, map[6]);
2011-10-15 19:30:10 +04:00
if (map[6] & SCARD_INPUT_LINKED)
{
/* not sure what this is */
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, linkedLen);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, linkedLen);
smartcard_input_repos(irp, linkedLen);
2011-10-15 19:30:10 +04:00
}
pioRecvPci.cbPciLength = sizeof(SCARD_IO_REQUEST);
pPioRecvPci = &pioRecvPci;
}
else
{
pPioRecvPci = NULL;
}
pPioRecvPci = NULL;
DEBUG_SCARD("SCardTransmit(hcard: 0x%08lx, send: %d bytes, recv: %d bytes)",
(long unsigned) hCard, (int) cbSendLength, (int) cbRecvLength);
status = SCardTransmit(hCard, &pioSendPci, sendBuf, cbSendLength,
2011-10-15 19:30:10 +04:00
pPioRecvPci, recvBuf, &cbRecvLength);
if (status != SCARD_S_SUCCESS)
2011-10-15 19:30:10 +04:00
{
DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(status), (unsigned) status);
2011-10-15 19:30:10 +04:00
}
else
{
DEBUG_SCARD("Success (%d bytes)", (int) cbRecvLength);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, 0); /* pioRecvPci 0x00; */
2011-10-15 19:30:10 +04:00
smartcard_output_buffer_start(irp, cbRecvLength); /* start of recvBuf output */
2011-10-15 19:30:10 +04:00
smartcard_output_buffer(irp, (char*) recvBuf, cbRecvLength);
2011-10-15 19:30:10 +04:00
}
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
free(sendBuf);
free(recvBuf);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_Control(IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
SCARDHANDLE hCard;
2012-10-09 11:26:39 +04:00
UINT32 map[3];
UINT32 controlCode;
UINT32 controlFunction;
BYTE* recvBuffer = NULL;
BYTE* sendBuffer = NULL;
2012-10-09 11:26:39 +04:00
UINT32 recvLength;
2011-10-15 19:30:10 +04:00
DWORD nBytesReturned;
DWORD outBufferSize;
stream_seek(irp->input, 0x14);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, map[0]);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x4);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, map[1]);
stream_read_UINT32(irp->input, controlCode);
stream_read_UINT32(irp->input, recvLength);
stream_read_UINT32(irp->input, map[2]);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x4);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, outBufferSize);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x4);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hContext);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x4);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hCard);
2011-10-15 19:30:10 +04:00
/* Translate Windows SCARD_CTL_CODE's to corresponding local code */
if (WIN_CTL_DEVICE_TYPE(controlCode) == WIN_FILE_DEVICE_SMARTCARD)
{
controlFunction = WIN_CTL_FUNCTION(controlCode);
controlCode = SCARD_CTL_CODE(controlFunction);
}
DEBUG_SCARD("controlCode: 0x%08x", (unsigned) controlCode);
2011-10-15 19:30:10 +04:00
if (map[2] & SCARD_INPUT_LINKED)
{
/* read real input size */
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, recvLength);
2011-10-15 19:30:10 +04:00
recvBuffer = malloc(recvLength);
2011-10-15 19:30:10 +04:00
if (!recvBuffer)
return smartcard_output_return(irp, SCARD_E_NO_MEMORY);
2011-10-15 19:30:10 +04:00
stream_read(irp->input, recvBuffer, recvLength);
}
nBytesReturned = outBufferSize;
sendBuffer = malloc(outBufferSize);
2011-10-15 19:30:10 +04:00
if (!sendBuffer)
return smartcard_output_return(irp, SCARD_E_NO_MEMORY);
2011-10-15 19:30:10 +04:00
status = SCardControl(hCard, (DWORD) controlCode, recvBuffer, (DWORD) recvLength,
2011-10-15 19:30:10 +04:00
sendBuffer, (DWORD) outBufferSize, &nBytesReturned);
if (status != SCARD_S_SUCCESS)
DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(status), (unsigned) status);
2011-10-15 19:30:10 +04:00
else
DEBUG_SCARD("Success (out: %u bytes)", (unsigned) nBytesReturned);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, (UINT32) nBytesReturned);
stream_write_UINT32(irp->output, 0x00000004);
stream_write_UINT32(irp->output, nBytesReturned);
2011-10-15 19:30:10 +04:00
if (nBytesReturned > 0)
{
stream_write(irp->output, sendBuffer, nBytesReturned);
smartcard_output_repos(irp, nBytesReturned);
2011-10-15 19:30:10 +04:00
}
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
free(recvBuffer);
free(sendBuffer);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_GetAttrib(IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDHANDLE hCard;
DWORD dwAttrId = 0;
DWORD dwAttrLen = 0;
2011-10-15 19:30:10 +04:00
DWORD attrLen = 0;
BYTE* pbAttr = NULL;
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x20);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, dwAttrId);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x4);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, dwAttrLen);
stream_seek(irp->input, 0xC);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hCard);
2011-10-15 19:30:10 +04:00
DEBUG_SCARD("hcard: 0x%08x, attrib: 0x%08x (%d bytes)",
2011-10-15 19:30:10 +04:00
(unsigned) hCard, (unsigned) dwAttrId, (int) dwAttrLen);
#ifdef SCARD_AUTOALLOCATE
if (dwAttrLen == 0)
2011-10-15 19:30:10 +04:00
{
attrLen = 0;
}
else
{
attrLen = SCARD_AUTOALLOCATE;
}
#endif
status = SCardGetAttrib(hCard, dwAttrId, attrLen == 0 ? NULL : (BYTE*) &pbAttr, &attrLen);
if (status != SCARD_S_SUCCESS)
{
#ifdef SCARD_AUTOALLOCATE
if (dwAttrLen == 0)
attrLen = 0;
else
attrLen = SCARD_AUTOALLOCATE;
#endif
}
2011-10-15 19:30:10 +04:00
if (dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_A && status == SCARD_E_UNSUPPORTED_FEATURE)
2011-10-15 19:30:10 +04:00
{
status = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_W,
attrLen == 0 ? NULL : (BYTE*) &pbAttr, &attrLen);
if (status != SCARD_S_SUCCESS)
{
#ifdef SCARD_AUTOALLOCATE
if (dwAttrLen == 0)
attrLen = 0;
else
attrLen = SCARD_AUTOALLOCATE;
#endif
}
2011-10-15 19:30:10 +04:00
}
if (dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_W && status == SCARD_E_UNSUPPORTED_FEATURE)
2011-10-15 19:30:10 +04:00
{
status = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_A,
attrLen == 0 ? NULL : (BYTE*) &pbAttr, &attrLen);
if (status != SCARD_S_SUCCESS)
{
#ifdef SCARD_AUTOALLOCATE
if (dwAttrLen == 0)
attrLen = 0;
else
attrLen = SCARD_AUTOALLOCATE;
#endif
}
2011-10-15 19:30:10 +04:00
}
if (attrLen > dwAttrLen && pbAttr != NULL)
2011-10-15 19:30:10 +04:00
{
status = SCARD_E_INSUFFICIENT_BUFFER;
2011-10-15 19:30:10 +04:00
}
dwAttrLen = attrLen;
if (status != SCARD_S_SUCCESS)
2011-10-15 19:30:10 +04:00
{
DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(status), (unsigned int) status);
2011-10-15 19:30:10 +04:00
free(pbAttr);
return smartcard_output_return(irp, status);
2011-10-15 19:30:10 +04:00
}
else
{
DEBUG_SCARD("Success (%d bytes)", (int) dwAttrLen);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, dwAttrLen);
stream_write_UINT32(irp->output, 0x00000200);
stream_write_UINT32(irp->output, dwAttrLen);
2011-10-15 19:30:10 +04:00
if (!pbAttr)
{
stream_write_zero(irp->output, dwAttrLen);
}
else
{
stream_write(irp->output, pbAttr, dwAttrLen);
}
smartcard_output_repos(irp, dwAttrLen);
/* align to multiple of 4 */
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, 0);
2011-10-15 19:30:10 +04:00
}
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
free(pbAttr);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2012-10-09 11:26:39 +04:00
static UINT32 handle_AccessStartedEvent(IRP* irp)
2011-10-15 19:30:10 +04:00
{
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
return SCARD_S_SUCCESS;
}
void scard_error(SMARTCARD_DEVICE* scard, IRP* irp, UINT32 ntstatus)
2011-10-15 19:30:10 +04:00
{
/* [MS-RDPESC] 3.1.4.4 */
2011-10-15 19:30:10 +04:00
printf("scard processing error %x\n", ntstatus);
stream_set_pos(irp->output, 0); /* CHECKME */
2011-10-15 19:30:10 +04:00
irp->IoStatus = ntstatus;
irp->Complete(irp);
}
/* http://msdn.microsoft.com/en-gb/library/ms938473.aspx */
typedef struct _SERVER_SCARD_ATRMASK
{
2012-10-09 11:26:39 +04:00
UINT32 cbAtr;
BYTE rgbAtr[36];
BYTE rgbMask[36];
2011-10-15 19:30:10 +04:00
}
SERVER_SCARD_ATRMASK;
2012-10-09 11:26:39 +04:00
static UINT32 handle_LocateCardsByATR(IRP* irp, BOOL wide)
2011-10-15 19:30:10 +04:00
{
LONG status;
int i, j, k;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
2012-10-09 11:26:39 +04:00
UINT32 atrMaskCount = 0;
UINT32 readerCount = 0;
SCARD_READERSTATE* cur = NULL;
SCARD_READERSTATE* rsCur = NULL;
SCARD_READERSTATE* readerStates = NULL;
SERVER_SCARD_ATRMASK* curAtr = NULL;
SERVER_SCARD_ATRMASK* pAtrMasks = NULL;
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 0x2C);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, hContext);
stream_read_UINT32(irp->input, atrMaskCount);
2011-10-15 19:30:10 +04:00
pAtrMasks = malloc(atrMaskCount * sizeof(SERVER_SCARD_ATRMASK));
2011-10-15 19:30:10 +04:00
if (!pAtrMasks)
return smartcard_output_return(irp, SCARD_E_NO_MEMORY);
2011-10-15 19:30:10 +04:00
for (i = 0; i < atrMaskCount; i++)
{
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, pAtrMasks[i].cbAtr);
2011-10-15 19:30:10 +04:00
stream_read(irp->input, pAtrMasks[i].rgbAtr, 36);
stream_read(irp->input, pAtrMasks[i].rgbMask, 36);
}
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, readerCount);
2011-10-15 19:30:10 +04:00
readerStates = malloc(readerCount * sizeof(SCARD_READERSTATE));
ZeroMemory(readerStates, readerCount * sizeof(SCARD_READERSTATE));
2011-10-15 19:30:10 +04:00
if (!readerStates)
return smartcard_output_return(irp, SCARD_E_NO_MEMORY);
2011-10-15 19:30:10 +04:00
for (i = 0; i < readerCount; i++)
{
cur = &readerStates[i];
stream_seek(irp->input, 4);
/*
* TODO: on-wire is little endian; need to either
* convert to host endian or fix the headers to
* request the order we want
*/
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, cur->dwCurrentState);
stream_read_UINT32(irp->input, cur->dwEventState);
stream_read_UINT32(irp->input, cur->cbAtr);
2011-10-15 19:30:10 +04:00
stream_read(irp->input, cur->rgbAtr, 32);
stream_seek(irp->input, 4);
/* reset high bytes? */
cur->dwCurrentState &= 0x0000FFFF;
cur->dwEventState &= 0x0000FFFF;
cur->dwEventState = 0;
}
for (i = 0; i < readerCount; i++)
{
cur = &readerStates[i];
2012-10-09 11:26:39 +04:00
UINT32 dataLength;
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 8);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, dataLength);
smartcard_input_repos(irp, smartcard_input_string(irp, (char **) &cur->szReader, dataLength, wide));
2011-10-15 19:30:10 +04:00
DEBUG_SCARD(" \"%s\"", cur->szReader ? cur->szReader : "NULL");
DEBUG_SCARD(" user: 0x%08x, state: 0x%08x, event: 0x%08x",
(unsigned) cur->pvUserData, (unsigned) cur->dwCurrentState,
(unsigned) cur->dwEventState);
if (strcmp(cur->szReader, "\\\\?PnP?\\Notification") == 0)
cur->dwCurrentState |= SCARD_STATE_IGNORE;
}
status = SCardGetStatusChange(hContext, 0x00000001, readerStates, readerCount);
if (status != SCARD_S_SUCCESS)
2011-10-15 19:30:10 +04:00
{
DEBUG_SCARD("Failure: %s (0x%08x)",
pcsc_stringify_error(status), (unsigned) status);
2011-10-15 19:30:10 +04:00
return smartcard_output_return(irp, status);
2011-10-15 19:30:10 +04:00
}
DEBUG_SCARD("Success");
for (i = 0, curAtr = pAtrMasks; i < atrMaskCount; i++, curAtr++)
{
for (j = 0, rsCur = readerStates; j < readerCount; j++, rsCur++)
{
BOOL equal = 1;
2011-10-15 19:30:10 +04:00
for (k = 0; k < cur->cbAtr; k++)
{
if ((curAtr->rgbAtr[k] & curAtr->rgbMask[k]) !=
(rsCur->rgbAtr[k] & curAtr->rgbMask[k]))
{
equal = 0;
break;
}
}
if (equal)
{
rsCur->dwEventState |= 0x00000040; /* SCARD_STATE_ATRMATCH 0x00000040 */
}
}
}
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, readerCount);
stream_write_UINT32(irp->output, 0x00084dd8);
stream_write_UINT32(irp->output, readerCount);
2011-10-15 19:30:10 +04:00
for (i = 0, rsCur = readerStates; i < readerCount; i++, rsCur++)
{
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, cur->dwCurrentState);
stream_write_UINT32(irp->output, cur->dwEventState);
stream_write_UINT32(irp->output, cur->cbAtr);
2011-10-15 19:30:10 +04:00
stream_write(irp->output, cur->rgbAtr, 32);
stream_write_zero(irp->output, 4);
free((void*) cur->szReader);
2011-10-15 19:30:10 +04:00
}
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
free(readerStates);
return status;
2011-10-15 19:30:10 +04:00
}
BOOL smartcard_async_op(IRP* irp)
2011-10-15 19:30:10 +04:00
{
2012-10-09 11:26:39 +04:00
UINT32 ioctl_code;
2011-10-15 19:30:10 +04:00
/* peek ahead */
stream_seek(irp->input, 8);
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, ioctl_code);
2011-10-15 19:30:10 +04:00
stream_rewind(irp->input, 12);
switch (ioctl_code)
{
/* non-blocking events */
case SCARD_IOCTL_ACCESS_STARTED_EVENT:
case SCARD_IOCTL_ESTABLISH_CONTEXT:
case SCARD_IOCTL_RELEASE_CONTEXT:
case SCARD_IOCTL_IS_VALID_CONTEXT:
return FALSE;
2011-10-15 19:30:10 +04:00
break;
/* async events */
case SCARD_IOCTL_GET_STATUS_CHANGE:
case SCARD_IOCTL_GET_STATUS_CHANGE + 4:
case SCARD_IOCTL_TRANSMIT:
case SCARD_IOCTL_STATUS:
case SCARD_IOCTL_STATUS + 4:
return TRUE;
2011-10-15 19:30:10 +04:00
break;
default:
break;
}
/* default to async */
return TRUE;
2011-10-15 19:30:10 +04:00
}
void smartcard_device_control(SMARTCARD_DEVICE* scard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
2012-10-09 11:26:39 +04:00
UINT32 pos;
UINT32 result;
UINT32 result_pos;
UINT32 output_len;
UINT32 input_len;
UINT32 ioctl_code;
UINT32 stream_len;
UINT32 irp_result_pos;
UINT32 output_len_pos;
const UINT32 header_lengths = 16;
/* MS-RPCE, Sections 2.2.6.1 and 2.2.6.2. */
2011-10-15 19:30:10 +04:00
2012-10-09 11:26:39 +04:00
stream_read_UINT32(irp->input, output_len);
stream_read_UINT32(irp->input, input_len);
stream_read_UINT32(irp->input, ioctl_code);
2011-10-15 19:30:10 +04:00
stream_seek(irp->input, 20); /* padding */
// stream_seek(irp->input, 4); /* TODO: parse len, le, v1 */
// stream_seek(irp->input, 4); /* 0xcccccccc */
// stream_seek(irp->input, 4); /* rpce len */
/* [MS-RDPESC] 3.2.5.1 Sending Outgoing Messages */
stream_extend(irp->output, 2048);
irp_result_pos = stream_get_pos(irp->output);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, 0x00000000); /* MS-RDPEFS
* OutputBufferLength
* will be updated
* later in this
* function.
*/
2011-10-15 19:30:10 +04:00
/* [MS-RPCE] 2.2.6.1 */
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, 0x00081001); /* len 8, LE, v1 */
stream_write_UINT32(irp->output, 0xcccccccc); /* filler */
2011-10-15 19:30:10 +04:00
output_len_pos = stream_get_pos(irp->output);
stream_seek(irp->output, 4); /* size */
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, 0x0); /* filler */
2011-10-15 19:30:10 +04:00
result_pos = stream_get_pos(irp->output);
stream_seek(irp->output, 4); /* result */
/* body */
switch (ioctl_code)
{
case SCARD_IOCTL_ESTABLISH_CONTEXT:
result = handle_EstablishContext(irp);
break;
case SCARD_IOCTL_IS_VALID_CONTEXT:
result = handle_IsValidContext(irp);
break;
case SCARD_IOCTL_RELEASE_CONTEXT:
result = handle_ReleaseContext(irp);
break;
case SCARD_IOCTL_LIST_READERS:
result = handle_ListReaders(irp, 0);
break;
case SCARD_IOCTL_LIST_READERS + 4:
result = handle_ListReaders(irp, 1);
break;
case SCARD_IOCTL_LIST_READER_GROUPS:
case SCARD_IOCTL_LIST_READER_GROUPS + 4:
/* typically not used unless list_readers fail */
2011-10-15 19:30:10 +04:00
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_GET_STATUS_CHANGE:
result = handle_GetStatusChange(irp, 0);
break;
case SCARD_IOCTL_GET_STATUS_CHANGE + 4:
result = handle_GetStatusChange(irp, 1);
break;
case SCARD_IOCTL_CANCEL:
result = handle_Cancel(irp);
break;
case SCARD_IOCTL_CONNECT:
result = handle_Connect(irp, 0);
break;
case SCARD_IOCTL_CONNECT + 4:
result = handle_Connect(irp, 1);
break;
case SCARD_IOCTL_RECONNECT:
result = handle_Reconnect(irp);
break;
case SCARD_IOCTL_DISCONNECT:
result = handle_Disconnect(irp);
break;
case SCARD_IOCTL_BEGIN_TRANSACTION:
result = handle_BeginTransaction(irp);
break;
case SCARD_IOCTL_END_TRANSACTION:
result = handle_EndTransaction(irp);
break;
case SCARD_IOCTL_STATE:
result = handle_State(irp);
break;
case SCARD_IOCTL_STATUS:
result = handle_Status(irp, 0);
break;
case SCARD_IOCTL_STATUS + 4:
result = handle_Status(irp, 1);
break;
case SCARD_IOCTL_TRANSMIT:
result = handle_Transmit(irp);
break;
case SCARD_IOCTL_CONTROL:
result = handle_Control(irp);
break;
case SCARD_IOCTL_GETATTRIB:
result = handle_GetAttrib(irp);
break;
case SCARD_IOCTL_ACCESS_STARTED_EVENT:
result = handle_AccessStartedEvent(irp);
break;
case SCARD_IOCTL_LOCATE_CARDS_BY_ATR:
result = handle_LocateCardsByATR(irp, 0);
break;
case SCARD_IOCTL_LOCATE_CARDS_BY_ATR + 4:
result = handle_LocateCardsByATR(irp, 1);
break;
default:
result = 0xc0000001;
printf("scard unknown ioctl 0x%x\n", ioctl_code);
break;
}
/* look for NTSTATUS errors */
if ((result & 0xc0000000) == 0xc0000000)
return scard_error(scard, irp, result);
/* per Ludovic Rousseau, map different usage of this particular
* error code between pcsc-lite & windows */
if (result == 0x8010001F)
result = 0x80100022;
/* handle response packet */
pos = stream_get_pos(irp->output);
stream_len = pos - irp_result_pos - 4; /* Value of OutputBufferLength */
stream_set_pos(irp->output, irp_result_pos);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, stream_len);
2011-10-15 19:30:10 +04:00
stream_set_pos(irp->output, output_len_pos);
/* Remove the effect of the MS-RPCE Common Type Header and Private
* Header (Sections 2.2.6.1 and 2.2.6.2).
*/
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, stream_len - header_lengths);
2011-10-15 19:30:10 +04:00
stream_set_pos(irp->output, result_pos);
2012-10-09 11:26:39 +04:00
stream_write_UINT32(irp->output, result);
2011-10-15 19:30:10 +04:00
stream_set_pos(irp->output, pos);
#ifdef WITH_DEBUG_SCARD
winpr_HexDump(stream_get_data(irp->output), stream_get_length(irp->output));
2011-10-15 19:30:10 +04:00
#endif
irp->IoStatus = 0;
irp->Complete(irp);
}