FreeRDP/channels/smartcard/client/smartcard_operations.c

2164 lines
54 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>
2014-02-11 07:12:13 +04:00
#include <assert.h>
2011-10-15 19:30:10 +04:00
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/stream.h>
#include <winpr/smartcard.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>
2011-10-15 19:30:10 +04:00
#include "smartcard_main.h"
2011-10-15 19:30:10 +04:00
2014-04-04 08:56:24 +04:00
const char* smartcard_get_ioctl_string(UINT32 ioControlCode)
{
switch (ioControlCode)
{
case SCARD_IOCTL_ESTABLISHCONTEXT:
return "SCARD_IOCTL_ESTABLISHCONTEXT";
case SCARD_IOCTL_RELEASECONTEXT:
return "SCARD_IOCTL_RELEASECONTEXT";
case SCARD_IOCTL_ISVALIDCONTEXT:
return "SCARD_IOCTL_ISVALIDCONTEXT";
case SCARD_IOCTL_LISTREADERGROUPSA:
return "SCARD_IOCTL_LISTREADERGROUPSA";
case SCARD_IOCTL_LISTREADERGROUPSW:
return "SCARD_IOCTL_LISTREADERGROUPSW";
case SCARD_IOCTL_LISTREADERSA:
return "SCARD_IOCTL_LISTREADERSA";
case SCARD_IOCTL_LISTREADERSW:
return "SCARD_IOCTL_LISTREADERSW";
case SCARD_IOCTL_INTRODUCEREADERGROUPA:
return "SCARD_IOCTL_INTRODUCEREADERGROUPA";
case SCARD_IOCTL_INTRODUCEREADERGROUPW:
return "SCARD_IOCTL_INTRODUCEREADERGROUPW";
case SCARD_IOCTL_FORGETREADERGROUPA:
return "SCARD_IOCTL_FORGETREADERGROUPA";
case SCARD_IOCTL_FORGETREADERGROUPW:
return "SCARD_IOCTL_FORGETREADERGROUPW";
case SCARD_IOCTL_INTRODUCEREADERA:
return "SCARD_IOCTL_INTRODUCEREADERA";
case SCARD_IOCTL_INTRODUCEREADERW:
return "SCARD_IOCTL_INTRODUCEREADERW";
case SCARD_IOCTL_FORGETREADERA:
return "SCARD_IOCTL_FORGETREADERA";
case SCARD_IOCTL_FORGETREADERW:
return "SCARD_IOCTL_FORGETREADERW";
case SCARD_IOCTL_ADDREADERTOGROUPA:
return "SCARD_IOCTL_ADDREADERTOGROUPA";
case SCARD_IOCTL_ADDREADERTOGROUPW:
return "SCARD_IOCTL_ADDREADERTOGROUPW";
case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
return "SCARD_IOCTL_REMOVEREADERFROMGROUPA";
case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
return "SCARD_IOCTL_REMOVEREADERFROMGROUPW";
case SCARD_IOCTL_LOCATECARDSA:
return "SCARD_IOCTL_LOCATECARDSA";
case SCARD_IOCTL_LOCATECARDSW:
return "SCARD_IOCTL_LOCATECARDSW";
case SCARD_IOCTL_GETSTATUSCHANGEA:
return "SCARD_IOCTL_GETSTATUSCHANGEA";
case SCARD_IOCTL_GETSTATUSCHANGEW:
return "SCARD_IOCTL_GETSTATUSCHANGEW";
case SCARD_IOCTL_CANCEL:
return "SCARD_IOCTL_CANCEL";
case SCARD_IOCTL_CONNECTA:
return "SCARD_IOCTL_CONNECTA";
case SCARD_IOCTL_CONNECTW:
return "SCARD_IOCTL_CONNECTW";
case SCARD_IOCTL_RECONNECT:
return "SCARD_IOCTL_RECONNECT";
case SCARD_IOCTL_DISCONNECT:
return "SCARD_IOCTL_DISCONNECT";
case SCARD_IOCTL_BEGINTRANSACTION:
return "SCARD_IOCTL_BEGINTRANSACTION";
case SCARD_IOCTL_ENDTRANSACTION:
return "SCARD_IOCTL_ENDTRANSACTION";
case SCARD_IOCTL_STATE:
return "SCARD_IOCTL_STATE";
case SCARD_IOCTL_STATUSA:
return "SCARD_IOCTL_STATUSA";
case SCARD_IOCTL_STATUSW:
return "SCARD_IOCTL_STATUSW";
case SCARD_IOCTL_TRANSMIT:
return "SCARD_IOCTL_TRANSMIT";
case SCARD_IOCTL_CONTROL:
return "SCARD_IOCTL_CONTROL";
case SCARD_IOCTL_GETATTRIB:
return "SCARD_IOCTL_GETATTRIB";
case SCARD_IOCTL_SETATTRIB:
return "SCARD_IOCTL_SETATTRIB";
case SCARD_IOCTL_ACCESSSTARTEDEVENT:
return "SCARD_IOCTL_ACCESSSTARTEDEVENT";
case SCARD_IOCTL_LOCATECARDSBYATRA:
return "SCARD_IOCTL_LOCATECARDSBYATRA";
case SCARD_IOCTL_LOCATECARDSBYATRW:
return "SCARD_IOCTL_LOCATECARDSBYATRW";
case SCARD_IOCTL_READCACHEA:
return "SCARD_IOCTL_READCACHEA";
case SCARD_IOCTL_READCACHEW:
return "SCARD_IOCTL_READCACHEW";
case SCARD_IOCTL_WRITECACHEA:
return "SCARD_IOCTL_WRITECACHEA";
case SCARD_IOCTL_WRITECACHEW:
return "SCARD_IOCTL_WRITECACHEW";
case SCARD_IOCTL_GETTRANSMITCOUNT:
return "SCARD_IOCTL_GETTRANSMITCOUNT";
case SCARD_IOCTL_RELEASESTARTEDEVENT:
return "SCARD_IOCTL_RELEASESTARTEDEVENT";
2014-04-04 08:56:24 +04:00
case SCARD_IOCTL_GETREADERICON:
return "SCARD_IOCTL_GETREADERICON";
case SCARD_IOCTL_GETDEVICETYPEID:
return "SCARD_IOCTL_GETDEVICETYPEID";
default:
return "SCARD_IOCTL_UNKNOWN";
}
return "SCARD_IOCTL_UNKNOWN";
}
static UINT32 handle_Context(SMARTCARD_DEVICE* smartcard, IRP* irp)
{
2014-04-04 08:56:24 +04:00
UINT32 length;
if (Stream_GetRemainingLength(irp->input) < 4)
{
2014-04-04 08:56:24 +04:00
WLog_Print(smartcard->log, WLOG_WARN, "Context is too short: %d",
(int) Stream_GetRemainingLength(irp->input));
return SCARD_F_INTERNAL_ERROR;
}
2014-04-04 08:56:24 +04:00
Stream_Read_UINT32(irp->input, length); /* Length (4 bytes) */
if ((Stream_GetRemainingLength(irp->input) < length) || (!length))
{
2014-04-04 08:56:24 +04:00
WLog_Print(smartcard->log, WLOG_WARN, "Context is too short: Actual: %d, Expected: %d",
(int) Stream_GetRemainingLength(irp->input), length);
return SCARD_F_INTERNAL_ERROR;
}
2014-04-04 08:56:24 +04:00
Stream_Seek(irp->input, length);
if (length > Stream_GetRemainingLength(irp->input))
{
2014-04-04 08:56:24 +04:00
WLog_Print(smartcard->log, WLOG_WARN, "Context is too long: Actual: %d, Expected: %d",
(int) Stream_GetRemainingLength(irp->input), length);
return SCARD_F_INTERNAL_ERROR;
}
return 0;
}
static UINT32 handle_CardHandle(SMARTCARD_DEVICE* smartcard, IRP* irp)
{
UINT32 status;
2014-04-04 08:56:24 +04:00
UINT32 length;
status = handle_Context(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
return status;
if (Stream_GetRemainingLength(irp->input) < 4)
{
2014-04-04 08:56:24 +04:00
WLog_Print(smartcard->log, WLOG_WARN, "CardHandle is too short: %d",
(int) Stream_GetRemainingLength(irp->input));
return SCARD_F_INTERNAL_ERROR;
}
2014-04-04 08:56:24 +04:00
Stream_Read_UINT32(irp->input, length); /* Length (4 bytes) */
if ((Stream_GetRemainingLength(irp->input) < length) || (!length))
{
2014-04-04 08:56:24 +04:00
WLog_Print(smartcard->log, WLOG_WARN, "CardHandle is too short: Actual: %d, Expected: %d",
(int) Stream_GetRemainingLength(irp->input), length);
return SCARD_F_INTERNAL_ERROR;
}
2014-04-04 08:56:24 +04:00
Stream_Seek(irp->input, length); /* Length (4 bytes) */
return 0;
}
static UINT32 handle_RedirContextRef(SMARTCARD_DEVICE* smartcard, IRP* irp, SCARDCONTEXT* hContext)
{
2014-04-04 08:56:24 +04:00
UINT32 length;
if (Stream_GetRemainingLength(irp->input) < 4)
{
2014-04-04 08:56:24 +04:00
WLog_Print(smartcard->log, WLOG_WARN, "RedirContextRef is too short: Actual: %d, Expected: %d\n",
(int) Stream_GetRemainingLength(irp->input), 4);
return SCARD_F_INTERNAL_ERROR;
}
2014-04-04 08:56:24 +04:00
Stream_Read_UINT32(irp->input, length); /* Length (4 bytes) */
if ((length != 4) && (length != 8))
{
2014-04-04 08:56:24 +04:00
WLog_Print(smartcard->log, WLOG_WARN, "RedirContextRef length is not 4 or 8: %d\n", length);
return SCARD_F_INTERNAL_ERROR;
}
if ((Stream_GetRemainingLength(irp->input) < length) || (!length))
2014-04-04 08:56:24 +04:00
{
WLog_Print(smartcard->log, WLOG_WARN, "RedirContextRef is too short: Actual: %d, Expected: %d\n",
(int) Stream_GetRemainingLength(irp->input), length);
return SCARD_F_INTERNAL_ERROR;
}
if (length > 4)
Stream_Read_UINT64(irp->input, *hContext);
else
Stream_Read_UINT32(irp->input, *hContext);
return 0;
}
static UINT32 handle_RedirHandleRef(SMARTCARD_DEVICE* smartcard, IRP* irp, SCARDCONTEXT* hContext, SCARDHANDLE* hHandle)
{
2014-04-04 08:56:24 +04:00
UINT32 length;
UINT32 status;
status = handle_RedirContextRef(smartcard, irp, hContext);
2013-10-24 23:34:14 +04:00
if (status)
return status;
if (Stream_GetRemainingLength(irp->input) < 4)
{
WLog_Print(smartcard->log, WLOG_WARN, "RedirHandleRef is too short: Actual: %d, Expected: %d\n",
(int) Stream_GetRemainingLength(irp->input), 4);
return SCARD_F_INTERNAL_ERROR;
}
Stream_Read_UINT32(irp->input, length); /* Length (4 bytes) */
if ((length != 4) && (length != 8))
{
WLog_Print(smartcard->log, WLOG_WARN, "RedirHandleRef length is not 4 or 8: %d\n", length);
return SCARD_F_INTERNAL_ERROR;
}
if ((Stream_GetRemainingLength(irp->input) < length) || (!length))
{
WLog_Print(smartcard->log, WLOG_WARN, "RedirHandleRef is too short: Actual: %d, Expected: %d\n",
(int) Stream_GetRemainingLength(irp->input), length);
return SCARD_F_INTERNAL_ERROR;
}
if (length > 4)
Stream_Read_UINT64(irp->input, *hHandle);
else
Stream_Read_UINT32(irp->input, *hHandle);
return 0;
}
2014-04-04 01:29:12 +04:00
static BOOL check_reader_is_forwarded(SMARTCARD_DEVICE* smartcard, const char* readerName)
{
BOOL rc = TRUE;
char *name = _strdup(readerName);
char *str, *strpos=NULL, *strstatus=NULL;
long pos, cpos, ret;
/* Extract the name, position and status from the data provided. */
str = strtok(name, " ");
while(str)
{
strpos = strstatus;
strstatus = str;
str = strtok(NULL, " ");
}
2013-09-13 11:47:18 +04:00
if (!strpos)
goto finally;
pos = strtol(strpos, NULL, 10);
2014-04-04 01:29:12 +04:00
if (strpos && strstatus)
{
/* Check, if the name of the reader matches. */
2014-04-04 01:29:12 +04:00
if (smartcard->name && strncmp(smartcard->name, readerName, strlen(smartcard->name)))
rc = FALSE;
/* Check, if the position matches. */
2014-04-04 01:29:12 +04:00
if (smartcard->path)
{
2014-04-04 01:29:12 +04:00
ret = sscanf(smartcard->path, "%ld", &cpos);
if ((1 == ret) && (cpos != pos))
rc = FALSE;
}
}
else
2014-04-04 01:29:12 +04:00
{
DEBUG_WARN("unknown reader format '%s'", readerName);
2014-04-04 01:29:12 +04:00
}
2013-09-13 11:47:18 +04:00
finally:
free(name);
if (!rc)
DEBUG_WARN("reader '%s' not forwarded", readerName);
return rc;
}
2014-04-04 01:29:12 +04:00
static BOOL check_handle_is_forwarded(SMARTCARD_DEVICE* smartcard, SCARDHANDLE hCard, SCARDCONTEXT hContext)
{
BOOL rc = FALSE;
LONG status;
DWORD state = 0, protocol = 0;
DWORD readerLen;
DWORD atrLen = SCARD_ATR_LENGTH;
char* readerName = NULL;
BYTE pbAtr[SCARD_ATR_LENGTH];
readerLen = SCARD_AUTOALLOCATE;
status = SCardStatusA(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
2013-10-24 23:34:14 +04:00
if (status == SCARD_S_SUCCESS)
{
2014-04-04 01:29:12 +04:00
rc = check_reader_is_forwarded(smartcard, readerName);
if (!rc)
DEBUG_WARN("Reader '%s' not forwarded!", readerName);
}
SCardFreeMemory(hContext, readerName);
return rc;
}
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_Pointer(irp->output);
2011-10-15 19:30:10 +04:00
len = strlen(src) + 1;
if (wide)
{
UINT32 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);
2011-10-15 19:30:10 +04:00
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.
*/
UINT32 size = Stream_GetPosition(irp->output) - field_lengths;
2012-10-09 11:26:39 +04:00
UINT32 add = (seed - (size % seed)) % seed;
2011-10-15 19:30:10 +04:00
if (add > 0)
2013-05-09 00:27:21 +04:00
Stream_Zero(irp->output, add);
2011-10-15 19:30:10 +04:00
}
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)
2013-05-09 00:27:21 +04:00
Stream_Zero(irp->output, add);
2011-10-15 19:30:10 +04:00
}
static UINT32 smartcard_output_return(IRP* irp, UINT32 status)
2011-10-15 19:30:10 +04:00
{
2013-05-09 00:27:21 +04:00
Stream_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
{
UINT32 header = (length < 0) ? (0) : ((length > highLimit) ? (highLimit) : (length));
2011-10-15 19:30:10 +04:00
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(irp->output, header);
2011-10-15 19:30:10 +04:00
if (length <= 0)
{
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(irp->output, 0);
2011-10-15 19:30:10 +04:00
}
else
{
if (header < length)
length = header;
2013-05-09 00:09:16 +04:00
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));
2013-05-09 00:09:16 +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
2013-05-09 00:09:16 +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)
{
UINT32 i;
2011-10-15 19:30:10 +04:00
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);
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_EstablishContext(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
UINT32 status;
EstablishContext_Call call;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext = -1;
status = smartcard_unpack_establish_context_call(smartcard, irp->input, &call);
2011-10-15 19:30:10 +04:00
if (status)
return status;
2011-10-15 19:30:10 +04:00
status = SCardEstablishContext(call.dwScope, NULL, NULL, &hContext);
2011-10-15 19:30:10 +04:00
2014-04-04 08:56:24 +04:00
Stream_Write_UINT32(irp->output, 4); /* cbContext (4 bytes) */
Stream_Write_UINT32(irp->output, -1); /* ReferentID (4 bytes) */
2011-10-15 19:30:10 +04:00
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(irp->output, 4);
Stream_Write_UINT32(irp->output, hContext);
2011-10-15 19:30:10 +04:00
/* store hContext in allowed context list */
2014-04-04 01:29:12 +04:00
smartcard->hContext = hContext;
2011-10-15 19:30:10 +04:00
smartcard_output_alignment(irp, 8);
2014-04-04 01:29:12 +04:00
2013-09-13 11:47:18 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_ReleaseContext(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
UINT32 status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext = -1;
status = handle_Context(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
return status;
status = handle_RedirContextRef(smartcard, irp, &hContext);
2013-10-24 23:34:14 +04:00
if (status)
return status;
2011-10-15 19:30:10 +04:00
status = SCardReleaseContext(hContext);
2014-04-04 01:29:12 +04:00
ZeroMemory(&smartcard->hContext, sizeof(smartcard->hContext));
2011-10-15 19:30:10 +04:00
smartcard_output_alignment(irp, 8);
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_IsValidContext(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
UINT32 status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
status = handle_Context(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
return status;
status = handle_RedirContextRef(smartcard, irp, &hContext);
2013-10-24 23:34:14 +04:00
if (status)
return status;
2011-10-15 19:30:10 +04:00
status = SCardIsValidContext(hContext);
2011-10-15 19:30:10 +04:00
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_ListReaders(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL wide)
2011-10-15 19:30:10 +04:00
{
UINT32 status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
DWORD dwReaders;
ListReaders_Call call;
2011-10-15 19:30:10 +04:00
char *readerList = NULL, *walker;
int elemLength, dataLength;
int pos, poslen1, poslen2, allowed_pos;
2011-10-15 19:30:10 +04:00
status = handle_Context(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
goto finish;
status = smartcard_unpack_list_readers_call(smartcard, irp->input, &call);
2014-04-04 08:56:24 +04:00
if (status)
goto finish;
2011-10-15 19:30:10 +04:00
status = handle_RedirContextRef(smartcard, irp, &hContext);
2014-04-04 08:56:24 +04:00
if (status)
goto finish;
2011-10-15 19:30:10 +04:00
dwReaders = SCARD_AUTOALLOCATE;
status = SCardListReadersA(hContext, (LPCSTR) call.mszGroups, (LPSTR) &readerList, &dwReaders);
2011-10-15 19:30:10 +04:00
if (status != SCARD_S_SUCCESS)
2011-10-15 19:30:10 +04:00
{
goto finish;
2011-10-15 19:30:10 +04:00
}
poslen1 = Stream_GetPosition(irp->output);
Stream_Seek_UINT32(irp->output);
2011-10-15 19:30:10 +04:00
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(irp->output, 0x01760650);
2011-10-15 19:30:10 +04:00
poslen2 = Stream_GetPosition(irp->output);
Stream_Seek_UINT32(irp->output);
2011-10-15 19:30:10 +04:00
walker = readerList;
dataLength = 0;
/* Smartcards can be forwarded by position and name. */
allowed_pos = -1;
2014-04-04 01:29:12 +04:00
if (smartcard->path)
{
if (1 != sscanf(smartcard->path, "%d", &allowed_pos))
allowed_pos = -1;
2014-04-04 01:29:12 +04:00
}
pos = 0;
2011-10-15 19:30:10 +04:00
while (1)
{
elemLength = strlen(walker);
if (elemLength == 0)
break;
/* Ignore readers not forwarded. */
if ((allowed_pos < 0) || (pos == allowed_pos))
{
2014-04-04 01:29:12 +04:00
if (!smartcard->name || strstr(walker, smartcard->name))
dataLength += smartcard_output_string(irp, walker, wide);
}
2011-10-15 19:30:10 +04:00
walker += elemLength + 1;
pos ++;
2011-10-15 19:30:10 +04:00
}
dataLength += smartcard_output_string(irp, "\0", wide);
2011-10-15 19:30:10 +04:00
pos = Stream_GetPosition(irp->output);
2011-10-15 19:30:10 +04:00
Stream_SetPosition(irp->output, poslen1);
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(irp->output, dataLength);
Stream_SetPosition(irp->output, poslen2);
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(irp->output, dataLength);
2011-10-15 19:30:10 +04:00
Stream_SetPosition(irp->output, pos);
2011-10-15 19:30:10 +04:00
smartcard_output_repos(irp, dataLength);
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
finish:
if (readerList)
{
SCardFreeMemory(hContext, readerList);
}
2011-10-15 19:30:10 +04:00
if (call.mszGroups)
free(call.mszGroups);
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_GetStatusChange(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL wide)
2011-10-15 19:30:10 +04:00
{
UINT32 i;
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
GetStatusChangeA_Call call;
ReaderStateA* readerState = NULL;
LPSCARD_READERSTATEA rgReaderState = NULL;
LPSCARD_READERSTATEA rgReaderStates = NULL;
2011-10-15 19:30:10 +04:00
status = handle_Context(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
goto finish;
/* Ensure, that the capacity expected is actually available. */
if (Stream_GetRemainingLength(irp->input) < 12)
{
DEBUG_WARN("length violation %d [%d]", 12,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
Stream_Read_UINT32(irp->input, call.dwTimeOut); /* dwTimeOut (4 bytes) */
Stream_Read_UINT32(irp->input, call.cReaders); /* cReaders (4 bytes) */
Stream_Seek_UINT32(irp->input); /* rgReaderStatesNdrPtr (4 bytes) */
2011-10-15 19:30:10 +04:00
/* Get context */
status = handle_RedirContextRef(smartcard, irp, &hContext);
2013-10-24 23:34:14 +04:00
if (status)
goto finish;
2011-10-15 19:30:10 +04:00
/* Skip ReaderStateConformant */
if (Stream_GetRemainingLength(irp->input) < 4)
{
DEBUG_WARN("length violation %d [%d]", 4,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
Stream_Seek(irp->input, 4);
2011-10-15 19:30:10 +04:00
if (call.cReaders > 0)
2011-10-15 19:30:10 +04:00
{
call.rgReaderStates = (ReaderStateA*) calloc(1, call.cReaders * sizeof(ReaderStateA));
for (i = 0; i < call.cReaders; i++)
2011-10-15 19:30:10 +04:00
{
readerState = &call.rgReaderStates[i];
2011-10-15 19:30:10 +04:00
if (Stream_GetRemainingLength(irp->input) < 52 )
{
DEBUG_WARN("length violation %d [%d]", 52,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
Stream_Seek(irp->input, 4);
2011-10-15 19:30:10 +04:00
Stream_Read_UINT32(irp->input, readerState->Common.dwCurrentState); /* dwCurrentState (4 bytes) */
Stream_Read_UINT32(irp->input, readerState->Common.dwEventState); /* dwEventState (4 bytes) */
Stream_Read_UINT32(irp->input, readerState->Common.cbAtr); /* cbAtr (4 bytes) */
Stream_Read(irp->input, readerState->Common.rgbAtr, 32);
Stream_Seek(irp->input, 4);
2011-10-15 19:30:10 +04:00
/* reset high bytes? */
readerState->Common.dwCurrentState &= 0x0000FFFF;
readerState->Common.dwEventState = 0;
2011-10-15 19:30:10 +04:00
}
for (i = 0; i < call.cReaders; i++)
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
readerState = &call.rgReaderStates[i];
if (Stream_GetRemainingLength(irp->input) < 12 )
{
DEBUG_WARN("length violation %d [%d]", 12,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
Stream_Seek(irp->input, 8);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(irp->input, dataLength);
if (Stream_GetRemainingLength(irp->input) < dataLength )
{
DEBUG_WARN("length violation %d [%d]", dataLength,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
smartcard_input_repos(irp, smartcard_input_string(irp,
(char**) &readerState->szReader, dataLength, wide));
2011-10-15 19:30:10 +04:00
if (!readerState->szReader)
2013-08-30 18:30:27 +04:00
{
DEBUG_WARN("cur->szReader=%p", readerState->szReader);
2013-08-30 18:30:27 +04:00
continue;
}
if (strcmp((char*) readerState->szReader, "\\\\?PnP?\\Notification") == 0)
readerState->Common.dwCurrentState |= SCARD_STATE_IGNORE;
2011-10-15 19:30:10 +04:00
}
}
else
{
call.rgReaderStates = NULL;
2011-10-15 19:30:10 +04:00
}
rgReaderStates = (SCARD_READERSTATEA*) calloc(1, call.cReaders * sizeof(SCARD_READERSTATEA));
2011-10-15 19:30:10 +04:00
for (i = 0; i < call.cReaders; i++)
{
rgReaderStates[i].szReader = (LPCSTR) call.rgReaderStates[i].szReader;
rgReaderStates[i].dwCurrentState = call.rgReaderStates[i].Common.dwCurrentState;
rgReaderStates[i].dwEventState = call.rgReaderStates[i].Common.dwEventState;
rgReaderStates[i].cbAtr = call.rgReaderStates[i].Common.cbAtr;
CopyMemory(&(rgReaderStates[i].rgbAtr), &(call.rgReaderStates[i].Common.rgbAtr), 36);
}
status = SCardGetStatusChangeA(hContext, (DWORD) call.dwTimeOut, rgReaderStates, (DWORD) call.cReaders);
Stream_Write_UINT32(irp->output, call.cReaders);
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(irp->output, 0x00084dd8);
Stream_Write_UINT32(irp->output, call.cReaders);
2011-10-15 19:30:10 +04:00
for (i = 0; i < call.cReaders; i++)
2011-10-15 19:30:10 +04:00
{
rgReaderState = &rgReaderStates[i];
2011-10-15 19:30:10 +04:00
Stream_Write_UINT32(irp->output, rgReaderState->dwCurrentState);
Stream_Write_UINT32(irp->output, rgReaderState->dwEventState);
Stream_Write_UINT32(irp->output, rgReaderState->cbAtr);
Stream_Write(irp->output, rgReaderState->rgbAtr, 32);
2013-05-09 00:27:21 +04:00
Stream_Zero(irp->output, 4);
2011-10-15 19:30:10 +04:00
}
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
finish:
if (call.rgReaderStates)
{
for (i = 0; i < call.cReaders; i++)
{
readerState = &call.rgReaderStates[i];
if (readerState->szReader)
free((void*) readerState->szReader);
readerState->szReader = NULL;
}
free(call.rgReaderStates);
free(rgReaderStates);
}
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_Cancel(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
status = handle_Context(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
return status;
status = handle_RedirContextRef(smartcard, irp, &hContext);
2013-10-24 23:34:14 +04:00
if (status)
return status;
2011-10-15 19:30:10 +04:00
status = SCardCancel(hContext);
2011-10-15 19:30:10 +04:00
smartcard_output_alignment(irp, 8);
return status;
2011-10-15 19:30:10 +04:00
}
UINT32 handle_ConnectA(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
SCARDHANDLE hCard;
ConnectA_Call call;
Connect_Return ret;
2011-10-15 19:30:10 +04:00
call.szReader = NULL;
call.Common.Context.pbContext = (BYTE*) &hContext;
2011-10-15 19:30:10 +04:00
status = smartcard_unpack_connect_a_call(smartcard, irp->input, &call);
2013-10-24 23:34:14 +04:00
if (status)
goto finish;
if (!check_reader_is_forwarded(smartcard, (char*) call.szReader))
{
DEBUG_WARN("Reader '%s' not forwarded!", call.szReader);
status = SCARD_E_INVALID_TARGET;
goto finish;
}
status = SCardConnectA(hContext, (char*) call.szReader, (DWORD) call.Common.dwShareMode,
(DWORD) call.Common.dwPreferredProtocols, &hCard, (DWORD*) &ret.dwActiveProtocol);
smartcard->hCard = hCard;
2013-10-24 23:34:14 +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, ret.dwActiveProtocol); /* dwActiveProtocol (4 bytes) */
Stream_Write_UINT32(irp->output, 0x00000004);
Stream_Write_UINT32(irp->output, hCard);
2013-10-24 23:34:14 +04:00
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
finish:
if (call.szReader)
free(call.szReader);
return status;
}
UINT32 handle_ConnectW(SMARTCARD_DEVICE* smartcard, IRP* irp)
{
LONG status;
SCARDCONTEXT hContext;
SCARDHANDLE hCard;
ConnectW_Call call;
Connect_Return ret;
call.szReader = NULL;
call.Common.Context.pbContext = (BYTE*) &hContext;
status = smartcard_unpack_connect_w_call(smartcard, irp->input, &call);
if (status)
goto finish;
status = SCardConnectW(hContext, (WCHAR*) call.szReader, (DWORD) call.Common.dwShareMode,
(DWORD) call.Common.dwPreferredProtocols, &hCard, (DWORD*) &ret.dwActiveProtocol);
2011-10-15 19:30:10 +04:00
2014-04-04 01:29:12 +04:00
smartcard->hCard = hCard;
2011-10-15 19:30:10 +04:00
2013-05-09 00:09:16 +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, ret.dwActiveProtocol); /* dwActiveProtocol (4 bytes) */
2013-05-09 00:09:16 +04:00
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
finish:
if (call.szReader)
free(call.szReader);
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_Reconnect(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
SCARDHANDLE hCard;
Reconnect_Call call;
Reconnect_Return ret;
2011-10-15 19:30:10 +04:00
status = handle_CardHandle(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
return status;
if (Stream_GetRemainingLength(irp->input) < 12)
{
DEBUG_WARN("length violation %d [%d]", 12,
Stream_GetRemainingLength(irp->input));
return SCARD_F_INTERNAL_ERROR;
}
Stream_Read_UINT32(irp->input, call.dwShareMode); /* dwShareMode (4 bytes) */
Stream_Read_UINT32(irp->input, call.dwPreferredProtocols); /* dwPreferredProtocols (4 bytes) */
Stream_Read_UINT32(irp->input, call.dwInitialization); /* dwInitialization (4 bytes) */
2011-10-15 19:30:10 +04:00
status = handle_RedirHandleRef(smartcard, irp, &hContext, &hCard);
2014-04-04 01:29:12 +04:00
if (status)
return status;
2011-10-15 19:30:10 +04:00
2014-04-04 01:29:12 +04:00
if (!check_handle_is_forwarded(smartcard, hCard, hContext))
{
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
return SCARD_E_INVALID_TARGET;
}
status = SCardReconnect(hCard, (DWORD) call.dwShareMode, (DWORD) call.dwPreferredProtocols,
(DWORD) call.dwInitialization, (LPDWORD) &ret.dwActiveProtocol);
2011-10-15 19:30:10 +04:00
Stream_Write_UINT32(irp->output, ret.dwActiveProtocol); /* dwActiveProtocol (4 bytes) */
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_Disconnect(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
SCARDHANDLE hCard;
HCardAndDisposition_Call call;
2011-10-15 19:30:10 +04:00
status = handle_CardHandle(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
return status;
if (Stream_GetRemainingLength(irp->input) < 4)
{
DEBUG_WARN("length violation %d [%d]", 4,
Stream_GetRemainingLength(irp->input));
return SCARD_F_INTERNAL_ERROR;
}
Stream_Read_UINT32(irp->input, call.dwDisposition); /* dwDisposition (4 bytes) */
status = handle_RedirHandleRef(smartcard, irp, &hContext, &hCard);
2013-10-24 23:34:14 +04:00
if (status)
return status;
2011-10-15 19:30:10 +04:00
2014-04-04 01:29:12 +04:00
if (!check_handle_is_forwarded(smartcard, hCard, hContext))
{
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
return SCARD_E_INVALID_TARGET;
}
status = SCardDisconnect(hCard, (DWORD) call.dwDisposition);
2011-10-15 19:30:10 +04:00
2014-04-04 01:29:12 +04:00
ZeroMemory(&smartcard->hCard, sizeof(smartcard->hCard));
2011-10-15 19:30:10 +04:00
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_BeginTransaction(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
SCARDHANDLE hCard;
SCARDCONTEXT hContext;
HCardAndDisposition_Call call;
status = handle_CardHandle(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
return status;
if (Stream_GetRemainingLength(irp->input) < 4)
{
DEBUG_WARN("length violation %d [%d]", 4,
Stream_GetRemainingLength(irp->input));
return SCARD_F_INTERNAL_ERROR;
}
Stream_Read_UINT32(irp->input, call.dwDisposition); /* dwDisposition (4 bytes) */
status = handle_RedirHandleRef(smartcard, irp, &hContext, &hCard);
2013-10-24 23:34:14 +04:00
if (status)
return status;
2014-04-04 01:29:12 +04:00
if (!check_handle_is_forwarded(smartcard, hCard, hContext))
{
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
return SCARD_E_INVALID_TARGET;
}
2011-10-15 19:30:10 +04:00
status = SCardBeginTransaction(hCard);
2011-10-15 19:30:10 +04:00
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_EndTransaction(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
SCARDHANDLE hCard;
SCARDCONTEXT hContext;
HCardAndDisposition_Call call;
2011-10-15 19:30:10 +04:00
status = handle_CardHandle(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
return status;
if (Stream_GetRemainingLength(irp->input) < 4)
{
DEBUG_WARN("length violation %d [%d]", 4,
Stream_GetRemainingLength(irp->input));
return SCARD_F_INTERNAL_ERROR;
}
Stream_Read_UINT32(irp->input, call.dwDisposition); /* dwDisposition (4 bytes) */
2011-10-15 19:30:10 +04:00
status = handle_RedirHandleRef(smartcard, irp, &hContext, &hCard);
2013-10-24 23:34:14 +04:00
if (status)
return status;
2014-04-04 01:29:12 +04:00
if (!check_handle_is_forwarded(smartcard, hCard, hContext))
{
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
return SCARD_E_INVALID_TARGET;
}
2011-10-15 19:30:10 +04:00
status = SCardEndTransaction(hCard, call.dwDisposition);
smartcard_output_alignment(irp, 8);
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_State(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDHANDLE hCard;
SCARDCONTEXT hContext;
State_Call call;
State_Return ret;
2011-10-15 19:30:10 +04:00
DWORD readerLen;
2013-09-13 11:47:18 +04:00
char* readerName = NULL;
BYTE atr[SCARD_ATR_LENGTH];
2011-10-15 19:30:10 +04:00
status = handle_CardHandle(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
goto finish;
if (Stream_GetRemainingLength(irp->input) < 8)
{
DEBUG_WARN("length violation %d [%d]", 8,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
Stream_Read_UINT32(irp->input, call.fpbAtrIsNULL); /* fpbAtrIsNULL (4 bytes) */
Stream_Read_UINT32(irp->input, call.cbAtrLen); /* cbAtrLen (4 bytes) */
status = handle_RedirHandleRef(smartcard, irp, &hContext, &hCard);
2013-10-24 23:34:14 +04:00
if (status)
goto finish;
2011-10-15 19:30:10 +04:00
2014-04-04 01:29:12 +04:00
if (!check_handle_is_forwarded(smartcard, hCard, hContext))
{
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
status = SCARD_E_INVALID_TARGET;
goto finish;
}
2011-10-15 19:30:10 +04:00
readerLen = SCARD_AUTOALLOCATE;
ret.rgAtr = atr;
ret.cbAtrLen = SCARD_ATR_LENGTH;
status = SCardStatusA(hCard, (LPSTR) &readerName, &readerLen,
&ret.dwState, &ret.dwProtocol, ret.rgAtr, &ret.cbAtrLen);
2011-10-15 19:30:10 +04:00
if (status != SCARD_S_SUCCESS)
2011-10-15 19:30:10 +04:00
{
status = smartcard_output_return(irp, status);
goto finish;
2011-10-15 19:30:10 +04:00
}
Stream_Write_UINT32(irp->output, ret.dwState); /* dwState (4 bytes) */
Stream_Write_UINT32(irp->output, ret.dwProtocol); /* dwProtocol (4 bytes) */
Stream_Write_UINT32(irp->output, ret.cbAtrLen); /* cbAtrLen (4 bytes) */
Stream_Write_UINT32(irp->output, 0x00000001); /* rgAtrPointer (4 bytes) */
Stream_Write_UINT32(irp->output, ret.cbAtrLen); /* rgAtrLength (4 bytes) */
Stream_Write(irp->output, ret.rgAtr, ret.cbAtrLen); /* rgAtr */
2011-10-15 19:30:10 +04:00
smartcard_output_repos(irp, ret.cbAtrLen);
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
finish:
if (readerName)
{
SCardFreeMemory(hContext, readerName);
}
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static DWORD handle_Status(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL wide)
2011-10-15 19:30:10 +04:00
{
LONG status;
2011-10-15 19:30:10 +04:00
SCARDHANDLE hCard;
SCARDCONTEXT hContext;
2011-10-15 19:30:10 +04:00
DWORD state, protocol;
DWORD readerLen = 0;
DWORD atrLen = SCARD_ATR_LENGTH;
2013-09-13 11:47:18 +04:00
char* readerName = NULL;
BYTE *pbAtr = NULL;
UINT32 dataLength = 0;
2011-10-15 19:30:10 +04:00
int pos, poslen1, poslen2;
status = handle_CardHandle(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
goto finish;
if (Stream_GetRemainingLength(irp->input) < 12)
{
DEBUG_WARN("length violation %d [%d]", 12,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
2013-10-24 23:34:14 +04:00
Stream_Seek(irp->input, 4);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(irp->input, readerLen);
Stream_Read_UINT32(irp->input, atrLen);
status = handle_RedirHandleRef(smartcard, irp, &hContext, &hCard);
2013-10-24 23:34:14 +04:00
if (status)
goto finish;
2011-10-15 19:30:10 +04:00
2014-04-04 01:29:12 +04:00
if (!check_handle_is_forwarded(smartcard, hCard, hContext))
{
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
status = SCARD_E_INVALID_TARGET;
goto finish;
}
2013-09-13 11:47:18 +04:00
pbAtr = malloc(sizeof(BYTE) * atrLen);
2011-10-15 19:30:10 +04:00
2014-04-04 01:29:12 +04:00
readerLen = SCARD_AUTOALLOCATE;
status = SCardStatusA(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
2011-10-15 19:30:10 +04:00
if (status != SCARD_S_SUCCESS)
2011-10-15 19:30:10 +04:00
{
status = smartcard_output_return(irp, status);
goto finish;
2011-10-15 19:30:10 +04:00
}
poslen1 = Stream_GetPosition(irp->output);
2013-05-09 00:09:16 +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);
Stream_Write(irp->output, pbAtr, atrLen);
2011-10-15 19:30:10 +04:00
if (atrLen < 32)
2013-05-09 00:27:21 +04:00
Stream_Zero(irp->output, 32 - atrLen);
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(irp->output, atrLen);
2011-10-15 19:30:10 +04:00
poslen2 = Stream_GetPosition(irp->output);
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(irp->output, readerLen);
2011-10-15 19:30:10 +04:00
2013-09-13 11:47:18 +04:00
if (readerName)
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_GetPosition(irp->output);
Stream_SetPosition(irp->output, poslen1);
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(irp->output,dataLength);
Stream_SetPosition(irp->output, poslen2);
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(irp->output,dataLength);
Stream_SetPosition(irp->output, pos);
2011-10-15 19:30:10 +04:00
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
finish:
if (readerName)
{
2014-04-04 01:29:12 +04:00
SCardFreeMemory(hContext, readerName);
}
2011-10-15 19:30:10 +04:00
2013-09-13 11:47:18 +04:00
if (pbAtr)
free(pbAtr);
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_Transmit(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
SCARDHANDLE hCard;
SCARDCONTEXT hContext;
UINT32 pioSendPciBufferPtr;
UINT32 ptrSendBuffer;
UINT32 ptrIoRecvPciBuffer;
UINT32 recvBufferIsNULL;
UINT32 linkedLen;
2013-09-13 11:47:18 +04:00
void *tmp;
union
{
SCARD_IO_REQUEST *rq;
UINT32 *u32;
void *v;
} ioSendPci, ioRecvPci;
2013-09-13 11:47:18 +04:00
SCARD_IO_REQUEST *pPioRecvPci = NULL;
2011-10-15 19:30:10 +04:00
DWORD cbSendLength = 0, cbRecvLength = 0;
BYTE *sendBuf = NULL, *recvBuf = NULL;
2011-10-15 19:30:10 +04:00
2013-09-13 11:47:18 +04:00
ioSendPci.v = NULL;
ioRecvPci.v = NULL;
status = handle_CardHandle(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
goto finish;
if (Stream_GetRemainingLength(irp->input) < 32)
{
DEBUG_WARN("length violation %d [%d]", 32,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
2011-10-15 19:30:10 +04:00
ioSendPci.v = malloc(sizeof(SCARD_IO_REQUEST));
ioRecvPci.v = malloc(sizeof(SCARD_IO_REQUEST));
Stream_Read_UINT32(irp->input, ioSendPci.rq->dwProtocol);
Stream_Read_UINT32(irp->input, ioSendPci.rq->cbPciLength);
Stream_Read_UINT32(irp->input, pioSendPciBufferPtr);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(irp->input, cbSendLength);
Stream_Read_UINT32(irp->input, ptrSendBuffer);
Stream_Read_UINT32(irp->input, ptrIoRecvPciBuffer);
Stream_Read_UINT32(irp->input, recvBufferIsNULL);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(irp->input, cbRecvLength);
2011-10-15 19:30:10 +04:00
status = handle_RedirHandleRef(smartcard, irp, &hContext, &hCard);
if (status)
goto finish;
2013-09-23 11:11:23 +04:00
/* Check, if there is data available from the ipSendPci element */
if (pioSendPciBufferPtr)
2011-10-15 19:30:10 +04:00
{
if (Stream_GetRemainingLength(irp->input) < 8)
{
DEBUG_WARN("length violation %d [%d]", 8,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(irp->input, linkedLen);
if (Stream_GetRemainingLength(irp->input) < ioSendPci.rq->cbPciLength)
{
DEBUG_WARN("length violation %d [%d]", ioSendPci.rq->cbPciLength,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
/* For details see 2.2.1.8 SCardIO_Request in MS-RDPESC and
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa379807%28v=vs.85%29.aspx
*/
if (linkedLen < ioSendPci.rq->cbPciLength - sizeof(SCARD_IO_REQUEST))
{
DEBUG_WARN("SCARD_IO_REQUEST with invalid extra byte length %d [%d]",
ioSendPci.rq->cbPciLength - sizeof(SCARD_IO_REQUEST), linkedLen);
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
2013-09-13 11:47:18 +04:00
/* Invalid length received. */
if (!ioSendPci.rq->cbPciLength)
{
if (ioSendPci.v)
free(ioSendPci.v);
ioSendPci.v = NULL;
}
else
{
tmp = realloc(ioSendPci.v, ioSendPci.rq->cbPciLength);
ioSendPci.v = tmp;
Stream_Read(irp->input, &ioSendPci.rq[1], ioSendPci.rq->cbPciLength);
}
2011-10-15 19:30:10 +04:00
}
else
ioSendPci.rq->cbPciLength = sizeof(SCARD_IO_REQUEST);
2011-10-15 19:30:10 +04:00
/* Check, if there is data available from the SendBufferPointer */
if (ptrSendBuffer)
2011-10-15 19:30:10 +04:00
{
if (Stream_GetRemainingLength(irp->input) < 4)
{
DEBUG_WARN("length violation %d [%d]", 4,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(irp->input, linkedLen);
2011-10-15 19:30:10 +04:00
/* Just check for too few bytes, there may be more actual
* data than is used due to padding. */
if (linkedLen < cbSendLength)
{
DEBUG_WARN("SendBuffer invalid byte length %d [%d]",
cbSendLength, linkedLen);
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
if (Stream_GetRemainingLength(irp->input) < cbSendLength)
{
DEBUG_WARN("length violation %d [%d]", cbSendLength,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
sendBuf = malloc(cbSendLength);
Stream_Read(irp->input, sendBuf, cbSendLength);
2011-10-15 19:30:10 +04:00
}
/* Check, if a response is desired. */
if (cbRecvLength && !recvBufferIsNULL)
recvBuf = malloc(cbRecvLength);
else
cbRecvLength = 0;
2011-10-15 19:30:10 +04:00
if (ptrIoRecvPciBuffer)
2011-10-15 19:30:10 +04:00
{
if (Stream_GetRemainingLength(irp->input) < 8)
{
DEBUG_WARN("length violation %d [%d]", 8,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
2011-10-15 19:30:10 +04:00
/* recvPci */
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(irp->input, linkedLen);
Stream_Read_UINT16(irp->input, ioRecvPci.rq->dwProtocol);
Stream_Read_UINT16(irp->input, ioRecvPci.rq->cbPciLength);
2013-09-23 11:11:23 +04:00
/* Just check for too few bytes, there may be more actual
* data than is used due to padding. */
if (linkedLen < ioRecvPci.rq->cbPciLength)
{
DEBUG_WARN("SCARD_IO_REQUEST with invalid extra byte length %d [%d]",
ioRecvPci.rq->cbPciLength - sizeof(SCARD_IO_REQUEST), linkedLen);
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
if (Stream_GetRemainingLength(irp->input) < ioRecvPci.rq->cbPciLength)
{
DEBUG_WARN("length violation %d [%d]", ioRecvPci.rq->cbPciLength,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
/* Read data, see
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa379807%28v=vs.85%29.aspx
*/
if (!ioRecvPci.rq->cbPciLength)
{
if (ioRecvPci.v)
free(ioRecvPci.v);
ioRecvPci.v = NULL;
}
else
{
tmp = realloc(ioRecvPci.v, ioRecvPci.rq->cbPciLength);
ioRecvPci.v = tmp;
Stream_Read(irp->input, &ioRecvPci.rq[1], ioRecvPci.rq->cbPciLength);
}
pPioRecvPci = ioRecvPci.rq;
2011-10-15 19:30:10 +04:00
}
else
2014-04-04 01:29:12 +04:00
{
2011-10-15 19:30:10 +04:00
pPioRecvPci = NULL;
2014-04-04 01:29:12 +04:00
}
2011-10-15 19:30:10 +04:00
2014-04-04 01:29:12 +04:00
if (!check_handle_is_forwarded(smartcard, hCard, hContext))
{
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
status = SCARD_E_INVALID_TARGET;
goto finish;
}
status = SCardTransmit(hCard, ioSendPci.rq, 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
{
2014-04-04 01:29:12 +04:00
2011-10-15 19:30:10 +04:00
}
else
{
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(irp->output, 0); /* pioRecvPci 0x00; */
2011-10-15 19:30:10 +04:00
2013-08-30 18:30:27 +04:00
if (recvBuf)
{
smartcard_output_buffer_start(irp, cbRecvLength); /* start of recvBuf output */
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
finish:
2013-08-30 18:30:27 +04:00
if (sendBuf)
free(sendBuf);
if (recvBuf)
free(recvBuf);
if (ioSendPci.v)
free(ioSendPci.v);
if (ioRecvPci.v)
free(ioRecvPci.v);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_Control(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
UINT32 length;
2011-10-15 19:30:10 +04:00
SCARDCONTEXT hContext;
SCARDHANDLE hCard;
2012-10-09 11:26:39 +04:00
UINT32 controlFunction;
Control_Call call;
Control_Return ret;
UINT32 pvInBufferPointer;
2011-10-15 19:30:10 +04:00
status = handle_CardHandle(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
goto finish;
if (Stream_GetRemainingLength(irp->input) < 20)
{
DEBUG_WARN("length violation %d [%d]", 20,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
call.pvInBuffer = NULL;
Stream_Read_UINT32(irp->input, call.dwControlCode); /* dwControlCode (4 bytes) */
Stream_Read_UINT32(irp->input, call.cbInBufferSize); /* cbInBufferSize (4 bytes) */
Stream_Read_UINT32(irp->input, pvInBufferPointer); /* pvInBufferPointer (4 bytes) */
Stream_Read_UINT32(irp->input, call.fpvOutBufferIsNULL); /* fpvOutBufferIsNULL (4 bytes) */
Stream_Read_UINT32(irp->input, call.cbOutBufferSize); /* cbOutBufferSize (4 bytes) */
status = handle_RedirHandleRef(smartcard, irp, &hContext, &hCard);
2013-10-24 23:34:14 +04:00
if (status)
goto finish;
2011-10-15 19:30:10 +04:00
/* Translate Windows SCARD_CTL_CODE's to corresponding local code */
if (DEVICE_TYPE_FROM_CTL_CODE(call.dwControlCode) == FILE_DEVICE_SMARTCARD)
{
controlFunction = FUNCTION_FROM_CTL_CODE(call.dwControlCode);
call.dwControlCode = SCARD_CTL_CODE(controlFunction);
}
2013-10-24 23:34:14 +04:00
if (pvInBufferPointer)
2011-10-15 19:30:10 +04:00
{
/* Get the size of the linked data. */
if (Stream_GetRemainingLength(irp->input) < 4)
{
DEBUG_WARN("length violation %d [%d]", 4,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
Stream_Read_UINT32(irp->input, length); /* Length (4 bytes) */
2011-10-15 19:30:10 +04:00
/* Check, if there is actually enough data... */
if (Stream_GetRemainingLength(irp->input) < length)
{
DEBUG_WARN("length violation %d [%d]", length,
Stream_GetRemainingLength(irp->input));
status = SCARD_F_INTERNAL_ERROR;
goto finish;
}
call.pvInBuffer = malloc(length);
call.cbInBufferSize = length;
Stream_Read(irp->input, call.pvInBuffer, length);
2011-10-15 19:30:10 +04:00
}
ret.cbOutBufferSize = call.cbOutBufferSize;
ret.pvOutBuffer = malloc(call.cbOutBufferSize);
2014-04-04 01:29:12 +04:00
if (!check_handle_is_forwarded(smartcard, hCard, hContext))
{
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
status = SCARD_E_INVALID_TARGET;
goto finish;
}
status = SCardControl(hCard, (DWORD) call.dwControlCode,
call.pvInBuffer, (DWORD) call.cbInBufferSize,
ret.pvOutBuffer, (DWORD) call.cbOutBufferSize, &ret.cbOutBufferSize);
2011-10-15 19:30:10 +04:00
Stream_Write_UINT32(irp->output, (UINT32) ret.cbOutBufferSize); /* cbOutBufferSize (4 bytes) */
Stream_Write_UINT32(irp->output, 0x00000004); /* pvOutBufferPointer (4 bytes) */
Stream_Write_UINT32(irp->output, ret.cbOutBufferSize); /* pvOutBufferLength (4 bytes) */
2011-10-15 19:30:10 +04:00
if (ret.cbOutBufferSize > 0)
2011-10-15 19:30:10 +04:00
{
Stream_Write(irp->output, ret.pvOutBuffer, ret.cbOutBufferSize); /* pvOutBuffer */
smartcard_output_repos(irp, ret.cbOutBufferSize);
2011-10-15 19:30:10 +04:00
}
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
finish:
if (call.pvInBuffer)
free(call.pvInBuffer);
if (ret.pvOutBuffer)
free(ret.pvOutBuffer);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_GetAttrib(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
LONG status;
DWORD cbAttrLen;
2011-10-15 19:30:10 +04:00
SCARDHANDLE hCard;
SCARDCONTEXT hContext;
GetAttrib_Call call;
GetAttrib_Return ret;
2011-10-15 19:30:10 +04:00
status = handle_CardHandle(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
return status;
if (Stream_GetRemainingLength(irp->input) < 12)
{
DEBUG_WARN("length violation %d [%d]", 12,
Stream_GetRemainingLength(irp->input));
return SCARD_F_INTERNAL_ERROR;
}
Stream_Read_UINT32(irp->input, call.dwAttrId); /* dwAttrId (4 bytes) */
Stream_Read_UINT32(irp->input, call.fpbAttrIsNULL); /* fpbAttrIsNULL (4 bytes) */
Stream_Read_UINT32(irp->input, call.cbAttrLen); /* cbAttrLen (4 bytes) */
status = handle_RedirHandleRef(smartcard, irp, &hContext, &hCard);
2013-10-24 23:34:14 +04:00
if (status)
return status;
2011-10-15 19:30:10 +04:00
2014-04-04 01:29:12 +04:00
if (!check_handle_is_forwarded(smartcard, hCard, hContext))
{
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
return SCARD_E_INVALID_TARGET;
}
ret.pbAttr = NULL;
cbAttrLen = (call.cbAttrLen == 0) ? 0 : SCARD_AUTOALLOCATE;
status = SCardGetAttrib(hCard, call.dwAttrId, (cbAttrLen == 0) ? NULL : (BYTE*) &ret.pbAttr, &cbAttrLen);
if (status != SCARD_S_SUCCESS)
{
cbAttrLen = (call.cbAttrLen == 0) ? 0 : SCARD_AUTOALLOCATE;
}
2011-10-15 19:30:10 +04:00
if (call.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,
(cbAttrLen == 0) ? NULL : (BYTE*) &ret.pbAttr, &cbAttrLen);
if (status != SCARD_S_SUCCESS)
{
cbAttrLen = (call.cbAttrLen == 0) ? 0 : SCARD_AUTOALLOCATE;
}
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
if (call.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,
(cbAttrLen == 0) ? NULL : (BYTE*) &ret.pbAttr, &cbAttrLen);
if (status != SCARD_S_SUCCESS)
{
cbAttrLen = (call.cbAttrLen == 0) ? 0 : SCARD_AUTOALLOCATE;
}
2011-10-15 19:30:10 +04:00
}
if ((cbAttrLen > call.cbAttrLen) && (ret.pbAttr != NULL))
2011-10-15 19:30:10 +04:00
{
status = SCARD_E_INSUFFICIENT_BUFFER;
2011-10-15 19:30:10 +04:00
}
call.cbAttrLen = cbAttrLen;
2011-10-15 19:30:10 +04:00
if (status != SCARD_S_SUCCESS)
2011-10-15 19:30:10 +04:00
{
status = smartcard_output_return(irp, status);
goto finish;
2011-10-15 19:30:10 +04:00
}
else
{
ret.cbAttrLen = call.cbAttrLen;
2011-10-15 19:30:10 +04:00
Stream_Write_UINT32(irp->output, ret.cbAttrLen); /* cbAttrLen (4 bytes) */
Stream_Write_UINT32(irp->output, 0x00000200); /* pbAttrPointer (4 bytes) */
Stream_Write_UINT32(irp->output, ret.cbAttrLen); /* pbAttrLength (4 bytes) */
if (!ret.pbAttr)
Stream_Zero(irp->output, ret.cbAttrLen); /* pbAttr */
2011-10-15 19:30:10 +04:00
else
Stream_Write(irp->output, ret.pbAttr, ret.cbAttrLen); /* pbAttr */
smartcard_output_repos(irp, ret.cbAttrLen);
/* align to multiple of 4 */
2013-05-09 00:09:16 +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
finish:
SCardFreeMemory(hContext, ret.pbAttr);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_AccessStartedEvent(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
if (Stream_GetRemainingLength(irp->input) < 4)
{
2013-10-24 23:34:14 +04:00
DEBUG_WARN("length violation %d [%d]", 4, Stream_GetRemainingLength(irp->input));
return SCARD_F_INTERNAL_ERROR;
}
2013-10-24 23:34:14 +04:00
Stream_Seek(irp->input, 4); /* Unused (4 bytes) */
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
return SCARD_S_SUCCESS;
}
2014-04-04 01:29:12 +04:00
static UINT32 handle_LocateCardsByATR(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL wide)
2011-10-15 19:30:10 +04:00
{
LONG status;
UINT32 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_READERSTATEA* cur = NULL;
SCARD_READERSTATEA* rsCur = NULL;
SCARD_READERSTATEA* readerStates = NULL;
2014-04-04 01:29:12 +04:00
SCARD_ATRMASK* curAtr = NULL;
SCARD_ATRMASK* pAtrMasks = NULL;
2011-10-15 19:30:10 +04:00
status = handle_Context(smartcard, irp);
2013-10-24 23:34:14 +04:00
if (status)
return status;
if (Stream_GetRemainingLength(irp->input) < 4)
{
DEBUG_WARN("length violation %d [%d]", 4,
Stream_GetRemainingLength(irp->input));
return SCARD_F_INTERNAL_ERROR;
}
Stream_Seek(irp->input, 4);
status = handle_RedirContextRef(smartcard, irp, &hContext);
2013-10-24 23:34:14 +04:00
if (status)
return status;
Stream_Seek(irp->input, 44);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(irp->input, hContext);
Stream_Read_UINT32(irp->input, atrMaskCount);
2011-10-15 19:30:10 +04:00
pAtrMasks = calloc(atrMaskCount, sizeof(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++)
{
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(irp->input, pAtrMasks[i].cbAtr);
Stream_Read(irp->input, pAtrMasks[i].rgbAtr, 36);
Stream_Read(irp->input, pAtrMasks[i].rgbMask, 36);
2011-10-15 19:30:10 +04:00
}
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(irp->input, readerCount);
2011-10-15 19:30:10 +04:00
readerStates = calloc(readerCount, sizeof(SCARD_READERSTATE));
2011-10-15 19:30:10 +04:00
for (i = 0; i < readerCount; i++)
{
cur = &readerStates[i];
Stream_Seek(irp->input, 4);
2011-10-15 19:30:10 +04:00
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(irp->input, cur->dwCurrentState);
Stream_Read_UINT32(irp->input, cur->dwEventState);
Stream_Read_UINT32(irp->input, cur->cbAtr);
Stream_Read(irp->input, cur->rgbAtr, 32);
2011-10-15 19:30:10 +04:00
Stream_Seek(irp->input, 4);
2011-10-15 19:30:10 +04:00
/* reset high bytes? */
cur->dwCurrentState &= 0x0000FFFF;
cur->dwEventState &= 0x0000FFFF;
cur->dwEventState = 0;
}
for (i = 0; i < readerCount; i++)
{
2012-10-09 11:26:39 +04:00
UINT32 dataLength;
2011-10-15 19:30:10 +04:00
cur = &readerStates[i];
Stream_Seek(irp->input, 8);
2013-05-09 00:09:16 +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
2013-08-30 18:30:27 +04:00
if (!cur->szReader)
{
DEBUG_WARN("cur->szReader=%p", cur->szReader);
continue;
}
2011-10-15 19:30:10 +04:00
if (strcmp(cur->szReader, "\\\\?PnP?\\Notification") == 0)
cur->dwCurrentState |= SCARD_STATE_IGNORE;
}
status = SCardGetStatusChangeA(hContext, 0x00000001, readerStates, readerCount);
2014-04-04 01:29:12 +04:00
if (status != SCARD_S_SUCCESS)
2011-10-15 19:30:10 +04:00
{
status = smartcard_output_return(irp, status);
goto finish;
2011-10-15 19:30:10 +04:00
}
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 |= SCARD_STATE_ATRMATCH;
2011-10-15 19:30:10 +04:00
}
}
}
2013-05-09 00:09:16 +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, cur = readerStates; i < readerCount; i++, cur++)
2011-10-15 19:30:10 +04:00
{
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(irp->output, cur->dwCurrentState);
Stream_Write_UINT32(irp->output, cur->dwEventState);
Stream_Write_UINT32(irp->output, cur->cbAtr);
Stream_Write(irp->output, cur->rgbAtr, 32);
2011-10-15 19:30:10 +04:00
2013-05-09 00:27:21 +04:00
Stream_Zero(irp->output, 4);
2011-10-15 19:30:10 +04:00
}
smartcard_output_alignment(irp, 8);
2011-10-15 19:30:10 +04:00
finish:
for (i = 0, cur = readerStates; i < readerCount; i++, cur++)
{
if (cur->szReader)
free((void*) cur->szReader);
cur->szReader = NULL;
}
if (readerStates)
free(readerStates);
if (pAtrMasks)
free(pAtrMasks);
2011-10-15 19:30:10 +04:00
return status;
2011-10-15 19:30:10 +04:00
}
2014-04-04 01:29:12 +04:00
void smartcard_device_control(SMARTCARD_DEVICE* smartcard, IRP* irp)
2011-10-15 19:30:10 +04:00
{
2012-10-09 11:26:39 +04:00
UINT32 result;
UINT32 status;
UINT32 ioControlCode;
2014-04-04 08:56:24 +04:00
UINT32 outputBufferLength;
UINT32 inputBufferLength;
UINT32 objectBufferLength;
/* Device Control Request */
if (Stream_GetRemainingLength(irp->input) < 32)
{
WLog_Print(smartcard->log, WLOG_WARN, "Device Control Request is too short: %d",
(int) Stream_GetRemainingLength(irp->input));
return;
}
2011-10-15 19:30:10 +04:00
2014-04-04 08:56:24 +04:00
Stream_Read_UINT32(irp->input, outputBufferLength); /* OutputBufferLength (4 bytes) */
Stream_Read_UINT32(irp->input, inputBufferLength); /* InputBufferLength (4 bytes) */
Stream_Read_UINT32(irp->input, ioControlCode); /* IoControlCode (4 bytes) */
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
2011-10-15 19:30:10 +04:00
if (Stream_Length(irp->input) != (Stream_GetPosition(irp->input) + inputBufferLength))
{
WLog_Print(smartcard->log, WLOG_WARN,
"InputBufferLength mismatch: Actual: %d Expected: %d\n",
Stream_Length(irp->input), Stream_GetPosition(irp->input) + inputBufferLength);
return;
}
WLog_Print(smartcard->log, WLOG_WARN, "ioControlCode: %s (0x%08X)",
smartcard_get_ioctl_string(ioControlCode), ioControlCode);
if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) &&
(ioControlCode != SCARD_IOCTL_RELEASESTARTEDEVENT))
{
status = smartcard_unpack_common_type_header(smartcard, irp->input);
if (status)
return;
status = smartcard_unpack_private_type_header(smartcard, irp->input);
if (status)
return;
}
/**
* [MS-RDPESC] 3.2.5.1: Sending Outgoing Messages:
* the output buffer length SHOULD be set to 2048
*
* Since it's a SHOULD and not a MUST, we don't care
* about it, but we still reserve at least 2048 bytes.
*/
2013-05-02 02:15:55 +04:00
Stream_EnsureRemainingCapacity(irp->output, 2048);
2011-10-15 19:30:10 +04:00
/* Device Control Response */
Stream_Seek_UINT32(irp->output); /* OutputBufferLength (4 bytes) */
2011-10-15 19:30:10 +04:00
Stream_Seek(irp->output, SMARTCARD_COMMON_TYPE_HEADER_LENGTH); /* CommonTypeHeader (8 bytes) */
Stream_Seek(irp->output, SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH); /* PrivateTypeHeader (8 bytes) */
2011-10-15 19:30:10 +04:00
Stream_Seek_UINT32(irp->output); /* Result (4 bytes) */
2011-10-15 19:30:10 +04:00
switch (ioControlCode)
2011-10-15 19:30:10 +04:00
{
case SCARD_IOCTL_ESTABLISHCONTEXT:
2014-04-04 01:29:12 +04:00
result = handle_EstablishContext(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_RELEASECONTEXT:
result = handle_ReleaseContext(smartcard, irp);
break;
case SCARD_IOCTL_ISVALIDCONTEXT:
2014-04-04 01:29:12 +04:00
result = handle_IsValidContext(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_LISTREADERGROUPSA:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_LISTREADERGROUPSW:
result = SCARD_F_INTERNAL_ERROR;
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_LISTREADERSA:
2014-04-04 01:29:12 +04:00
result = handle_ListReaders(smartcard, irp, 0);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_LISTREADERSW:
2014-04-04 01:29:12 +04:00
result = handle_ListReaders(smartcard, irp, 1);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_INTRODUCEREADERGROUPA:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_INTRODUCEREADERGROUPW:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_FORGETREADERGROUPA:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_FORGETREADERGROUPW:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_INTRODUCEREADERA:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_INTRODUCEREADERW:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_FORGETREADERA:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_FORGETREADERW:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_ADDREADERTOGROUPA:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_ADDREADERTOGROUPW:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_LOCATECARDSA:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_LOCATECARDSW:
2011-10-15 19:30:10 +04:00
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_GETSTATUSCHANGEA:
2014-04-04 01:29:12 +04:00
result = handle_GetStatusChange(smartcard, irp, 0);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_GETSTATUSCHANGEW:
2014-04-04 01:29:12 +04:00
result = handle_GetStatusChange(smartcard, irp, 1);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_CANCEL:
2014-04-04 01:29:12 +04:00
result = handle_Cancel(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_CONNECTA:
result = handle_ConnectA(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_CONNECTW:
result = handle_ConnectW(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_RECONNECT:
2014-04-04 01:29:12 +04:00
result = handle_Reconnect(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_DISCONNECT:
2014-04-04 01:29:12 +04:00
result = handle_Disconnect(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_BEGINTRANSACTION:
2014-04-04 01:29:12 +04:00
result = handle_BeginTransaction(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_ENDTRANSACTION:
2014-04-04 01:29:12 +04:00
result = handle_EndTransaction(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_STATE:
2014-04-04 01:29:12 +04:00
result = handle_State(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_STATUSA:
2014-04-04 01:29:12 +04:00
result = handle_Status(smartcard, irp, 0);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_STATUSW:
2014-04-04 01:29:12 +04:00
result = handle_Status(smartcard, irp, 1);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_TRANSMIT:
2014-04-04 01:29:12 +04:00
result = handle_Transmit(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_CONTROL:
2014-04-04 01:29:12 +04:00
result = handle_Control(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_GETATTRIB:
2014-04-04 01:29:12 +04:00
result = handle_GetAttrib(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_SETATTRIB:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_ACCESSSTARTEDEVENT:
2014-04-04 01:29:12 +04:00
result = handle_AccessStartedEvent(smartcard, irp);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_LOCATECARDSBYATRA:
2014-04-04 01:29:12 +04:00
result = handle_LocateCardsByATR(smartcard, irp, 0);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_LOCATECARDSBYATRW:
2014-04-04 01:29:12 +04:00
result = handle_LocateCardsByATR(smartcard, irp, 1);
2011-10-15 19:30:10 +04:00
break;
case SCARD_IOCTL_READCACHEA:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_READCACHEW:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_WRITECACHEA:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_WRITECACHEW:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_GETTRANSMITCOUNT:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_RELEASESTARTEDEVENT:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_GETREADERICON:
result = SCARD_F_INTERNAL_ERROR;
break;
case SCARD_IOCTL_GETDEVICETYPEID:
result = SCARD_F_INTERNAL_ERROR;
break;
2011-10-15 19:30:10 +04:00
default:
2014-04-04 08:56:24 +04:00
result = STATUS_UNSUCCESSFUL;
2011-10-15 19:30:10 +04:00
break;
}
if ((result != SCARD_S_SUCCESS) && (result != SCARD_E_TIMEOUT))
{
WLog_Print(smartcard->log, WLOG_WARN,
"IRP failure: ioControlCode: %s (0x%08X), status: %s (0x%08X)",
smartcard_get_ioctl_string(ioControlCode), ioControlCode,
SCardGetErrorString(result), result);
}
2011-10-15 19:30:10 +04:00
Stream_SealLength(irp->output);
outputBufferLength = Stream_Length(irp->output) - RDPDR_DEVICE_IO_RESPONSE_LENGTH - 4;
objectBufferLength = outputBufferLength - RDPDR_DEVICE_IO_RESPONSE_LENGTH;
Stream_SetPosition(irp->output, RDPDR_DEVICE_IO_RESPONSE_LENGTH);
2011-10-15 19:30:10 +04:00
/* Device Control Response */
Stream_Write_UINT32(irp->output, outputBufferLength); /* OutputBufferLength (4 bytes) */
2011-10-15 19:30:10 +04:00
smartcard_pack_common_type_header(smartcard, irp->output); /* CommonTypeHeader (8 bytes) */
smartcard_pack_private_type_header(smartcard, irp->output, objectBufferLength); /* PrivateTypeHeader (8 bytes) */
2011-10-15 19:30:10 +04:00
Stream_Write_UINT32(irp->output, result); /* Result (4 bytes) */
2011-10-15 19:30:10 +04:00
Stream_SetPosition(irp->output, Stream_Length(irp->output));
2011-10-15 19:30:10 +04:00
irp->IoStatus = 0;
irp->Complete(irp);
}