2012-08-15 01:09:01 +04:00
|
|
|
/**
|
2012-10-09 05:00:07 +04:00
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
2012-08-15 01:09:01 +04:00
|
|
|
* 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"
|
2012-08-15 01:09:01 +04:00
|
|
|
#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
|
|
|
|
2012-11-20 08:49:08 +04:00
|
|
|
#include <winpr/crt.h>
|
2012-12-14 08:54:54 +04:00
|
|
|
#include <winpr/print.h>
|
2013-03-22 00:45:25 +04:00
|
|
|
#include <winpr/stream.h>
|
2014-04-03 23:27:55 +04:00
|
|
|
#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
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
#include "smartcard_main.h"
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
static UINT32 handle_CommonTypeHeader(SMARTCARD_DEVICE* smartcard, IRP* irp)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
UINT8 version;
|
|
|
|
UINT8 endianess;
|
|
|
|
UINT16 header_length;
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 8)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 8,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process CommonTypeHeader */
|
|
|
|
Stream_Read_UINT8(irp->input, version);
|
|
|
|
Stream_Read_UINT8(irp->input, endianess);
|
|
|
|
Stream_Read_UINT16(irp->input, header_length);
|
|
|
|
Stream_Seek(irp->input, 4);
|
|
|
|
|
|
|
|
if (0x01 != version)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("unsupported header version %d", version);
|
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
if (0x10 != endianess)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("unsupported endianess %d", endianess);
|
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
if (0x08 != header_length)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("unsupported header length %d", header_length);
|
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
static UINT32 handle_PrivateTypeHeader(SMARTCARD_DEVICE* smartcard, IRP* irp)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
UINT32 len;
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 8)
|
|
|
|
{
|
2013-09-12 15:53:15 +04:00
|
|
|
DEBUG_WARN("length violation %d [%d]", 8,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 14:18:35 +04:00
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process PrivateTypeHeader */
|
|
|
|
Stream_Read_UINT32(irp->input, len);
|
|
|
|
Stream_Seek_UINT32(irp->input);
|
|
|
|
|
|
|
|
/* Assure the remaining length is as expected. */
|
|
|
|
if (len < Stream_GetRemainingLength(irp->input))
|
|
|
|
{
|
|
|
|
DEBUG_WARN("missing payload %d [%d]",
|
|
|
|
len, Stream_GetRemainingLength(irp->input));
|
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
static UINT32 handle_Context(SMARTCARD_DEVICE* smartcard, IRP* irp, int *redirect)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
UINT32 len;
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 4)
|
|
|
|
{
|
2013-09-12 15:53:15 +04:00
|
|
|
DEBUG_WARN("length violation %d [%d]", 4,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 14:18:35 +04:00
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process PrivateTypeHeader */
|
|
|
|
Stream_Read_UINT32(irp->input, len);
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < len)
|
|
|
|
{
|
2013-09-12 15:53:15 +04:00
|
|
|
DEBUG_WARN("length violation %d [%d]", len,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 14:18:35 +04:00
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
Stream_Seek(irp->input, len);
|
2013-09-30 16:49:19 +04:00
|
|
|
if (!len)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("Context handle is NULL, using from cache.");
|
|
|
|
*redirect |= 0x01;
|
|
|
|
}
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
if (len > Stream_GetRemainingLength(irp->input))
|
|
|
|
{
|
2013-09-12 15:53:15 +04:00
|
|
|
DEBUG_WARN("length violation %d [%d]", len,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 14:18:35 +04:00
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
static UINT32 handle_CardHandle(SMARTCARD_DEVICE* smartcard, IRP* irp, int* redirect)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
UINT32 status;
|
|
|
|
UINT32 len;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_Context(smartcard, irp, redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +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, len);
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < len)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", len,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
Stream_Seek(irp->input, len);
|
|
|
|
|
2013-09-30 16:49:19 +04:00
|
|
|
if (!len)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("Card handle is NULL, using from cache.");
|
|
|
|
*redirect |= 0x02;
|
|
|
|
}
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
static UINT32 handle_RedirContextRef(SMARTCARD_DEVICE* smartcard, IRP* irp,
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect, SCARDCONTEXT* hContext)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
UINT32 len;
|
|
|
|
|
2013-09-30 16:49:19 +04:00
|
|
|
/* No context provided, use stored. */
|
|
|
|
if (redirect & 0x01)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("No context provided, using stored context.");
|
2014-04-04 01:29:12 +04:00
|
|
|
*hContext = smartcard->hContext;
|
2013-09-30 16:49:19 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
/* Extract context handle. */
|
|
|
|
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, len);
|
2013-09-30 16:49:19 +04:00
|
|
|
if (len > Stream_GetRemainingLength(irp->input))
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
DEBUG_WARN("length violation %d [%d]", len,
|
2013-09-12 14:18:35 +04:00
|
|
|
Stream_GetRemainingLength(irp->input));
|
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
2013-10-24 23:34:14 +04:00
|
|
|
ZeroMemory(hContext, sizeof(SCARDCONTEXT));
|
2013-09-30 16:49:19 +04:00
|
|
|
Stream_Read(irp->input, hContext, len);
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
static UINT32 handle_RedirHandleRef(SMARTCARD_DEVICE* smartcard, IRP* irp,
|
|
|
|
int redirect, SCARDCONTEXT* hContext, SCARDHANDLE* hHandle)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
UINT32 len, status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirContextRef(smartcard, irp, redirect, hContext);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2013-09-30 16:49:19 +04:00
|
|
|
/* Use stored card handle. */
|
|
|
|
if (redirect & 0x02)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("No card handle provided, using stored handle.");
|
2014-04-04 01:29:12 +04:00
|
|
|
*hHandle = smartcard->hCard;
|
2013-09-30 16:49:19 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
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, len);
|
|
|
|
if (len != 4)
|
|
|
|
{
|
2013-09-12 15:53:15 +04:00
|
|
|
DEBUG_WARN("length violation %d [%d]", len, 4);
|
2013-09-12 14:18:35 +04:00
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < len)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", len,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
2013-10-24 23:34:14 +04:00
|
|
|
ZeroMemory(hHandle, sizeof(SCARDHANDLE));
|
2013-09-12 14:18:35 +04:00
|
|
|
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)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
BOOL rc = TRUE;
|
|
|
|
char *name = _strdup(readerName);
|
|
|
|
char *str, *strpos=NULL, *strstatus=NULL;
|
2013-09-30 15:29:40 +04:00
|
|
|
long pos, cpos, ret;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
pos = strtol(strpos, NULL, 10);
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
if (strpos && strstatus)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
/* 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)))
|
2013-09-12 14:18:35 +04:00
|
|
|
rc = FALSE;
|
|
|
|
|
|
|
|
/* Check, if the position matches. */
|
2014-04-04 01:29:12 +04:00
|
|
|
if (smartcard->path)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
2014-04-04 01:29:12 +04:00
|
|
|
ret = sscanf(smartcard->path, "%ld", &cpos);
|
2013-09-12 14:18:35 +04:00
|
|
|
if ((1 == ret) && (cpos != pos))
|
|
|
|
rc = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2014-04-04 01:29:12 +04:00
|
|
|
{
|
2013-09-12 14:18:35 +04:00
|
|
|
DEBUG_WARN("unknown reader format '%s'", readerName);
|
2014-04-04 01:29:12 +04:00
|
|
|
}
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2013-09-13 11:47:18 +04:00
|
|
|
finally:
|
2013-09-12 14:18:35 +04:00
|
|
|
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)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
BOOL rc = FALSE;
|
|
|
|
LONG status;
|
|
|
|
DWORD state = 0, protocol = 0;
|
|
|
|
DWORD readerLen;
|
2014-04-03 23:27:55 +04:00
|
|
|
DWORD atrLen = SCARD_ATR_LENGTH;
|
2013-09-12 14:18:35 +04:00
|
|
|
char* readerName = NULL;
|
2014-04-03 23:27:55 +04:00
|
|
|
BYTE pbAtr[SCARD_ATR_LENGTH];
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
readerLen = SCARD_AUTOALLOCATE;
|
|
|
|
|
|
|
|
status = SCardStatus(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status == SCARD_S_SUCCESS)
|
|
|
|
{
|
2014-04-04 01:29:12 +04:00
|
|
|
rc = check_reader_is_forwarded(smartcard, readerName);
|
2013-09-12 14:18:35 +04:00
|
|
|
if (!rc)
|
|
|
|
DEBUG_WARN("Reader '%s' not forwarded!", readerName);
|
|
|
|
}
|
|
|
|
|
|
|
|
SCardFreeMemory(hContext, readerName);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2011-11-23 04:22:17 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
static UINT32 smartcard_output_string(IRP* irp, char* src, BOOL wide)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2012-10-09 11:01:37 +04:00
|
|
|
BYTE* p;
|
2012-10-09 11:26:39 +04:00
|
|
|
UINT32 len;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
p = Stream_Pointer(irp->output);
|
2011-10-15 19:30:10 +04:00
|
|
|
len = strlen(src) + 1;
|
|
|
|
|
|
|
|
if (wide)
|
|
|
|
{
|
|
|
|
int i;
|
2011-11-22 05:46:58 +04:00
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->output, len);
|
2011-10-15 19:30:10 +04:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
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
|
2012-08-02 02:05:45 +04:00
|
|
|
* RDPDR_HEADER, DeviceID,
|
|
|
|
* CompletionID, and IoStatus
|
|
|
|
* of Section 2.2.1.5.5 of MS-RDPEFS.
|
|
|
|
*/
|
2013-04-30 06:35:15 +04:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +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
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +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);
|
2012-11-21 20:56:40 +04:00
|
|
|
return status;
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +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));
|
|
|
|
|
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
|
|
|
|
{
|
2013-08-30 18:30:27 +04:00
|
|
|
assert(NULL != buffer);
|
2011-10-15 19:30:10 +04:00
|
|
|
if (header < length)
|
|
|
|
length = header;
|
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write(irp->output, buffer, length);
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_repos(irp, length);
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
static void smartcard_output_buffer(IRP* irp, char* buffer, unsigned int length)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_buffer_limit(irp, buffer, length, 0x7FFFFFFF);
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +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
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
static void smartcard_output_buffer_start(IRP* irp, int length)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_buffer_start_limit(irp, length, 0x7FFFFFFF);
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +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;
|
2012-10-09 07:21:26 +04:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
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)
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->input, add);
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
static UINT32 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
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
assert(irp);
|
|
|
|
assert(dest);
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 12)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 12,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->input, 8);
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, dataLength);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (Stream_GetRemainingLength(irp->input) < dataLength)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", dataLength,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_input_repos(irp, smartcard_input_string(irp, dest, dataLength, wide));
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
return 0;
|
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
|
|
|
{
|
2012-11-21 20:56:40 +04:00
|
|
|
UINT32 status;
|
2012-10-09 11:26:39 +04:00
|
|
|
UINT32 scope;
|
2011-10-15 19:30:10 +04:00
|
|
|
SCARDCONTEXT hContext = -1;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
2011-11-22 05:46:58 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
/* Ensure, that the capacity expected is actually available. */
|
2013-09-12 15:53:15 +04:00
|
|
|
if (Stream_GetRemainingLength(irp->input) < 4)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
2013-09-12 15:53:15 +04:00
|
|
|
DEBUG_WARN("length violation %d [%d]", 4,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2011-10-15 19:30:10 +04:00
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
/* Read the scope from the stream. */
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, scope);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardEstablishContext(scope, NULL, NULL, &hContext);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(irp->output, 4); // cbContext
|
|
|
|
Stream_Write_UINT32(irp->output, -1); // ReferentID
|
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
|
|
|
|
2013-09-30 15:29:40 +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
|
|
|
|
2012-11-21 20:56:40 +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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2013-09-12 14:18:35 +04:00
|
|
|
UINT32 status;
|
2011-10-15 19:30:10 +04:00
|
|
|
SCARDCONTEXT hContext = -1;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_Context(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirContextRef(smartcard, irp, redirect, &hContext);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +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
|
|
|
|
2012-11-21 20:56:40 +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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2012-11-21 20:56:40 +04:00
|
|
|
UINT32 status;
|
2011-10-15 19:30:10 +04:00
|
|
|
SCARDCONTEXT hContext;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_Context(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirContextRef(smartcard, irp, redirect, &hContext);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardIsValidContext(hContext);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2013-09-12 14:18:35 +04:00
|
|
|
UINT32 status;
|
2011-10-15 19:30:10 +04:00
|
|
|
SCARDCONTEXT hContext;
|
|
|
|
DWORD dwReaders;
|
2013-09-30 15:29:40 +04:00
|
|
|
UINT32 cBytes;
|
|
|
|
INT32 fmszReadersIsNULL;
|
|
|
|
UINT32 cchReaders;
|
|
|
|
LPTSTR mszGroups = NULL;
|
2011-10-15 19:30:10 +04:00
|
|
|
char *readerList = NULL, *walker;
|
|
|
|
int elemLength, dataLength;
|
2013-09-12 14:18:35 +04:00
|
|
|
int pos, poslen1, poslen2, allowed_pos;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_Context(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2013-09-30 15:29:40 +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;
|
|
|
|
}
|
|
|
|
Stream_Read_UINT32(irp->input, cBytes);
|
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
/* Ensure, that the capacity expected is actually available. */
|
2013-09-30 15:29:40 +04:00
|
|
|
if (Stream_GetRemainingLength(irp->input) < cBytes)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
2013-09-30 15:29:40 +04:00
|
|
|
DEBUG_WARN("length violation %d [%d]", cBytes,
|
2013-09-12 15:53:15 +04:00
|
|
|
Stream_GetRemainingLength(irp->input));
|
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
2013-09-30 15:29:40 +04:00
|
|
|
if (cBytes)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
2013-09-30 15:29:40 +04:00
|
|
|
mszGroups = malloc(cBytes);
|
|
|
|
Stream_Read(irp->input, mszGroups, cBytes);
|
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-30 15:29:40 +04:00
|
|
|
if (Stream_GetRemainingLength(irp->input) < 4)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 4,
|
2013-09-12 15:53:15 +04:00
|
|
|
Stream_GetRemainingLength(irp->input));
|
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
2013-09-30 15:29:40 +04:00
|
|
|
Stream_Read_UINT32(irp->input, fmszReadersIsNULL);
|
|
|
|
|
|
|
|
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, cchReaders);
|
2013-09-30 16:49:19 +04:00
|
|
|
|
|
|
|
Stream_Seek(irp->input, 4);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
/* Read RedirScardcontextRef */
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirContextRef(smartcard, irp, redirect, &hContext);
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
|
|
|
/* ignore rest of [MS-RDPESC] 2.2.2.4 ListReaders_Call */
|
|
|
|
|
|
|
|
dwReaders = SCARD_AUTOALLOCATE;
|
2013-09-30 15:29:40 +04:00
|
|
|
status = SCardListReaders(hContext, mszGroups, (LPSTR) &readerList, &dwReaders);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
if (status != SCARD_S_SUCCESS)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
|
2013-04-30 06:35:15 +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
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
poslen2 = Stream_GetPosition(irp->output);
|
|
|
|
Stream_Seek_UINT32(irp->output);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
|
|
|
walker = readerList;
|
|
|
|
dataLength = 0;
|
2011-11-22 05:46:58 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
/* 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))
|
2013-09-12 14:18:35 +04:00
|
|
|
allowed_pos = -1;
|
2014-04-04 01:29:12 +04:00
|
|
|
}
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
pos = 0;
|
2011-10-15 19:30:10 +04:00
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
elemLength = strlen(walker);
|
|
|
|
if (elemLength == 0)
|
|
|
|
break;
|
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
/* 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))
|
2013-09-12 14:18:35 +04:00
|
|
|
dataLength += smartcard_output_string(irp, walker, wide);
|
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
walker += elemLength + 1;
|
2013-09-12 14:18:35 +04:00
|
|
|
pos ++;
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
dataLength += smartcard_output_string(irp, "\0", wide);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
pos = Stream_GetPosition(irp->output);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_SetPosition(irp->output, poslen1);
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(irp->output, dataLength);
|
2013-04-30 06:35:15 +04:00
|
|
|
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
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_SetPosition(irp->output, pos);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_repos(irp, dataLength);
|
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
finish:
|
|
|
|
if (readerList)
|
|
|
|
{
|
|
|
|
SCardFreeMemory(hContext, readerList);
|
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-30 15:29:40 +04:00
|
|
|
if (mszGroups)
|
|
|
|
free(mszGroups);
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
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
|
|
|
{
|
2012-11-21 20:56:40 +04:00
|
|
|
int i;
|
|
|
|
LONG status;
|
2014-04-04 01:29:12 +04:00
|
|
|
int redirect = 0;
|
2011-10-15 19:30:10 +04:00
|
|
|
SCARDCONTEXT hContext;
|
|
|
|
DWORD dwTimeout = 0;
|
|
|
|
DWORD readerCount = 0;
|
2013-09-12 15:53:15 +04:00
|
|
|
SCARD_READERSTATE *readerStates = NULL, *cur;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_Context(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
/* Ensure, that the capacity expected is actually available. */
|
2013-09-12 15:53:15 +04:00
|
|
|
if (Stream_GetRemainingLength(irp->input) < 12)
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
2013-09-12 15:53:15 +04:00
|
|
|
DEBUG_WARN("length violation %d [%d]", 12,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2014-04-03 23:27:55 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, dwTimeout);
|
|
|
|
Stream_Read_UINT32(irp->input, readerCount);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
/* Skip reader state */
|
|
|
|
Stream_Seek(irp->input, 4);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
/* Get context */
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirContextRef(smartcard, irp, redirect, &hContext);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
/* Skip ReaderStateConformant */
|
2013-09-12 15:53:15 +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-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->input, 4);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
|
|
|
if (readerCount > 0)
|
|
|
|
{
|
2012-11-20 08:49:08 +04:00
|
|
|
readerStates = malloc(readerCount * sizeof(SCARD_READERSTATE));
|
|
|
|
ZeroMemory(readerStates, readerCount * sizeof(SCARD_READERSTATE));
|
|
|
|
|
2011-10-15 19:30:10 +04:00
|
|
|
for (i = 0; i < readerCount; i++)
|
|
|
|
{
|
|
|
|
cur = &readerStates[i];
|
|
|
|
|
2013-09-12 15:53:15 +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;
|
|
|
|
}
|
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->input, 4);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: on-wire is little endian; need to either
|
|
|
|
* convert to host endian or fix the headers to
|
|
|
|
* request the order we want
|
|
|
|
*/
|
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
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->input, 4);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
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-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->input, 8);
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, dataLength);
|
2013-09-12 15:53:15 +04:00
|
|
|
|
|
|
|
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 **) &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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
readerStates = NULL;
|
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardGetStatusChange(hContext, (DWORD) dwTimeout, readerStates, (DWORD) readerCount);
|
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; i < readerCount; i++)
|
|
|
|
{
|
|
|
|
cur = &readerStates[i];
|
|
|
|
|
|
|
|
/* TODO: do byte conversions if necessary */
|
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
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
finish:
|
|
|
|
if (readerStates)
|
2013-10-01 15:09:52 +04:00
|
|
|
{
|
|
|
|
for (i = 0; i < readerCount; i++)
|
|
|
|
{
|
|
|
|
cur = &readerStates[i];
|
|
|
|
|
|
|
|
if (cur->szReader)
|
2014-04-03 23:27:55 +04:00
|
|
|
free((void*) cur->szReader);
|
2013-10-01 15:09:52 +04:00
|
|
|
cur->szReader = NULL;
|
|
|
|
}
|
2013-09-12 15:53:15 +04:00
|
|
|
free(readerStates);
|
2013-10-01 15:09:52 +04:00
|
|
|
}
|
2013-09-12 15:53:15 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2012-11-21 20:56:40 +04:00
|
|
|
LONG status;
|
2011-10-15 19:30:10 +04:00
|
|
|
SCARDCONTEXT hContext;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_Context(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirContextRef(smartcard, irp, redirect, &hContext);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardCancel(hContext);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-11-22 05:46:58 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
return status;
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
static UINT32 handle_Connect(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL wide)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2012-11-21 20:56:40 +04:00
|
|
|
LONG status;
|
2011-10-15 19:30:10 +04:00
|
|
|
SCARDCONTEXT hContext;
|
2012-11-21 20:56:40 +04:00
|
|
|
char* readerName = NULL;
|
2011-10-15 19:30:10 +04:00
|
|
|
DWORD dwShareMode = 0;
|
|
|
|
DWORD dwPreferredProtocol = 0;
|
|
|
|
DWORD dwActiveProtocol = 0;
|
|
|
|
SCARDHANDLE hCard;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
/* Skip ptrReader */
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 4)
|
|
|
|
{
|
2014-04-04 01:29:12 +04:00
|
|
|
DEBUG_WARN("Length violation %d [%d]", 4,
|
2013-09-12 14:18:35 +04:00
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->input, 4);
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
/* Read common data */
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_Context(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 8)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("Length violadion %d [%d]", 8,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
Stream_Read_UINT32(irp->input, dwShareMode);
|
|
|
|
Stream_Read_UINT32(irp->input, dwPreferredProtocol);
|
|
|
|
|
|
|
|
status = smartcard_input_reader_name(irp, &readerName, wide);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirContextRef(smartcard, irp, redirect, &hContext);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
if (!check_reader_is_forwarded(smartcard, readerName))
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("Reader '%s' not forwarded!", readerName);
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_E_INVALID_TARGET;
|
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardConnect(hContext, readerName, (DWORD) dwShareMode,
|
2011-10-15 19:30:10 +04:00
|
|
|
(DWORD) dwPreferredProtocol, &hCard, (DWORD *) &dwActiveProtocol);
|
|
|
|
|
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, dwActiveProtocol);
|
|
|
|
Stream_Write_UINT32(irp->output, 0x00000004);
|
|
|
|
Stream_Write_UINT32(irp->output, hCard);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
finish:
|
|
|
|
if (readerName)
|
|
|
|
free(readerName);
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2012-11-21 20:56:40 +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;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CardHandle(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 12)
|
2013-09-12 15:53:15 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 12,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 14:18:35 +04:00
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
2013-09-12 15:53:15 +04:00
|
|
|
}
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2013-05-09 00:09:16 +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
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirHandleRef(smartcard, irp, redirect, &hContext, &hCard);
|
|
|
|
|
2013-09-12 14:18:35 +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))
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
|
|
|
|
return SCARD_E_INVALID_TARGET;
|
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardReconnect(hCard, (DWORD) dwShareMode, (DWORD) dwPreferredProtocol,
|
2014-04-04 01:29:12 +04:00
|
|
|
(DWORD) dwInitialization, (LPDWORD) &dwActiveProtocol);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(irp->output, dwActiveProtocol);
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2012-11-21 20:56:40 +04:00
|
|
|
LONG status;
|
2011-10-15 19:30:10 +04:00
|
|
|
SCARDCONTEXT hContext;
|
|
|
|
SCARDHANDLE hCard;
|
|
|
|
DWORD dwDisposition = 0;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CardHandle(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 4)
|
2013-09-12 15:53:15 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 4,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 14:18:35 +04:00
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
2013-09-12 15:53:15 +04:00
|
|
|
}
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, dwDisposition);
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirHandleRef(smartcard, irp, redirect, &hContext, &hCard);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +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))
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
|
|
|
|
return SCARD_E_INVALID_TARGET;
|
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardDisconnect(hCard, (DWORD) 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
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2012-11-21 20:56:40 +04:00
|
|
|
LONG status;
|
2013-09-12 14:18:35 +04:00
|
|
|
SCARDHANDLE hCard;
|
|
|
|
SCARDCONTEXT hContext;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CardHandle(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 4)
|
2013-09-12 15:53:15 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 4,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 14:18:35 +04:00
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
2013-09-12 15:53:15 +04:00
|
|
|
}
|
2013-09-12 14:18:35 +04:00
|
|
|
Stream_Seek(irp->input, 4);
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirHandleRef(smartcard, irp, redirect, &hContext, &hCard);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
if (!check_handle_is_forwarded(smartcard, hCard, hContext))
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
|
|
|
|
return SCARD_E_INVALID_TARGET;
|
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardBeginTransaction(hCard);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2012-11-21 20:56:40 +04:00
|
|
|
LONG status;
|
2013-09-12 14:18:35 +04:00
|
|
|
SCARDHANDLE hCard;
|
|
|
|
SCARDCONTEXT hContext;
|
2011-10-15 19:30:10 +04:00
|
|
|
DWORD dwDisposition = 0;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CardHandle(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 4)
|
2013-09-12 15:53:15 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 4,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 14:18:35 +04:00
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
2013-09-12 15:53:15 +04:00
|
|
|
}
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, dwDisposition);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirHandleRef(smartcard, irp, redirect, &hContext, &hCard);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
if (!check_handle_is_forwarded(smartcard, hCard, hContext))
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
|
|
|
|
return SCARD_E_INVALID_TARGET;
|
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardEndTransaction(hCard, dwDisposition);
|
2011-11-22 05:46:58 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-11-22 05:46:58 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2012-11-21 20:56:40 +04:00
|
|
|
LONG status;
|
2011-10-15 19:30:10 +04:00
|
|
|
SCARDHANDLE hCard;
|
2013-09-12 14:18:35 +04:00
|
|
|
SCARDCONTEXT hContext;
|
2011-10-15 19:30:10 +04:00
|
|
|
DWORD state = 0, protocol = 0;
|
|
|
|
DWORD readerLen;
|
2014-04-03 23:27:55 +04:00
|
|
|
DWORD atrLen = SCARD_ATR_LENGTH;
|
2013-09-13 11:47:18 +04:00
|
|
|
char* readerName = NULL;
|
2014-04-03 23:27:55 +04:00
|
|
|
BYTE pbAtr[SCARD_ATR_LENGTH];
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CardHandle(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 8)
|
2013-09-12 15:53:15 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 8,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
|
|
|
}
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
Stream_Seek(irp->input, 4);
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek_UINT32(irp->input); /* atrLen */
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirHandleRef(smartcard, irp, redirect, &hContext, &hCard);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
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))
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_E_INVALID_TARGET;
|
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
|
|
|
|
readerLen = SCARD_AUTOALLOCATE;
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardStatus(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
if (status != SCARD_S_SUCCESS)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2013-09-12 15:53:15 +04:00
|
|
|
status = smartcard_output_return(irp, status);
|
|
|
|
goto finish;
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
|
2013-05-09 00:09:16 +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);
|
|
|
|
Stream_Write(irp->output, pbAtr, atrLen);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_repos(irp, atrLen);
|
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
finish:
|
|
|
|
if (readerName)
|
|
|
|
{
|
|
|
|
SCardFreeMemory(hContext, readerName);
|
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2012-11-21 20:56:40 +04:00
|
|
|
LONG status;
|
2011-10-15 19:30:10 +04:00
|
|
|
SCARDHANDLE hCard;
|
2013-09-12 14:18:35 +04:00
|
|
|
SCARDCONTEXT hContext;
|
2011-10-15 19:30:10 +04:00
|
|
|
DWORD state, protocol;
|
|
|
|
DWORD readerLen = 0;
|
2014-04-03 23:27:55 +04:00
|
|
|
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;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CardHandle(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 12)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 12,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +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);
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirHandleRef(smartcard, irp, redirect, &hContext, &hCard);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
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))
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_E_INVALID_TARGET;
|
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
|
|
|
|
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;
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardStatus(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
if (status != SCARD_S_SUCCESS)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2013-09-12 15:53:15 +04:00
|
|
|
status = smartcard_output_return(irp, status);
|
|
|
|
goto finish;
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
|
2013-04-30 06:35:15 +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
|
|
|
|
2013-04-30 06:35:15 +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);
|
2012-11-21 20:56:40 +04:00
|
|
|
dataLength += smartcard_output_string(irp, "\0", wide);
|
|
|
|
smartcard_output_repos(irp, dataLength);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-04-30 06:35:15 +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);
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_SetPosition(irp->output, poslen2);
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(irp->output,dataLength);
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_SetPosition(irp->output, pos);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
finish:
|
|
|
|
if (readerName)
|
|
|
|
{
|
2014-04-04 01:29:12 +04:00
|
|
|
SCardFreeMemory(hContext, readerName);
|
2013-09-12 15:53:15 +04:00
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-13 11:47:18 +04:00
|
|
|
if (pbAtr)
|
|
|
|
free(pbAtr);
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2012-11-21 20:56:40 +04:00
|
|
|
LONG status;
|
2013-09-12 14:18:35 +04:00
|
|
|
SCARDHANDLE hCard;
|
|
|
|
SCARDCONTEXT hContext;
|
2013-09-12 15:53:15 +04:00
|
|
|
UINT32 pioSendPciBufferPtr;
|
|
|
|
UINT32 ptrSendBuffer;
|
|
|
|
UINT32 ptrIoRecvPciBuffer;
|
|
|
|
UINT32 recvBufferIsNULL;
|
|
|
|
UINT32 linkedLen;
|
2013-09-13 11:47:18 +04:00
|
|
|
void *tmp;
|
2013-09-12 17:50:12 +04:00
|
|
|
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;
|
2013-09-12 16:10:44 +04:00
|
|
|
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;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CardHandle(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 32)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 32,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 17:50:12 +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);
|
2013-09-12 15:53:15 +04:00
|
|
|
Stream_Read_UINT32(irp->input, pioSendPciBufferPtr);
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, cbSendLength);
|
2013-09-12 15:53:15 +04:00
|
|
|
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
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirHandleRef(smartcard, irp, redirect, &hContext, &hCard);
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-23 11:11:23 +04:00
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
/* Check, if there is data available from the ipSendPci element */
|
|
|
|
if (pioSendPciBufferPtr)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2013-09-12 14:30:46 +04:00
|
|
|
if (Stream_GetRemainingLength(irp->input) < 8)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 8,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
2013-09-12 14:30:46 +04:00
|
|
|
}
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, linkedLen);
|
2013-09-12 14:30:46 +04:00
|
|
|
|
2013-09-24 11:23:43 +04:00
|
|
|
if (Stream_GetRemainingLength(irp->input) < ioSendPci.rq->cbPciLength)
|
2013-09-12 14:30:46 +04:00
|
|
|
{
|
2013-09-24 11:23:43 +04:00
|
|
|
DEBUG_WARN("length violation %d [%d]", ioSendPci.rq->cbPciLength,
|
2013-09-12 14:30:46 +04:00
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
2013-09-12 14:30:46 +04:00
|
|
|
}
|
2013-09-12 17:50:12 +04:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
*/
|
2013-09-24 11:23:43 +04:00
|
|
|
if (linkedLen < ioSendPci.rq->cbPciLength - sizeof(SCARD_IO_REQUEST))
|
2013-09-12 16:10:44 +04:00
|
|
|
{
|
2013-09-12 17:50:12 +04:00
|
|
|
DEBUG_WARN("SCARD_IO_REQUEST with invalid extra byte length %d [%d]",
|
|
|
|
ioSendPci.rq->cbPciLength - sizeof(SCARD_IO_REQUEST), linkedLen);
|
2013-09-12 16:10:44 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
|
|
|
}
|
2013-09-13 11:47:18 +04:00
|
|
|
|
2013-10-01 16:41:59 +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
|
|
|
}
|
2013-09-12 15:53:15 +04:00
|
|
|
else
|
2013-09-12 17:50:12 +04:00
|
|
|
ioSendPci.rq->cbPciLength = sizeof(SCARD_IO_REQUEST);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
/* Check, if there is data available from the SendBufferPointer */
|
|
|
|
if (ptrSendBuffer)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2013-09-12 14:30:46 +04:00
|
|
|
if (Stream_GetRemainingLength(irp->input) < 4)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 4,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
2013-09-12 14:30:46 +04:00
|
|
|
}
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, linkedLen);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-24 11:23:43 +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)
|
2013-09-12 14:30:46 +04:00
|
|
|
{
|
2013-09-24 11:23:43 +04:00
|
|
|
DEBUG_WARN("length violation %d [%d]", cbSendLength,
|
2013-09-12 14:30:46 +04:00
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
2013-09-12 14:30:46 +04:00
|
|
|
}
|
2013-09-24 11:23:43 +04:00
|
|
|
sendBuf = malloc(cbSendLength);
|
|
|
|
Stream_Read(irp->input, sendBuf, cbSendLength);
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
/* Check, if a response is desired. */
|
|
|
|
if (cbRecvLength && !recvBufferIsNULL)
|
2012-10-09 07:21:26 +04:00
|
|
|
recvBuf = malloc(cbRecvLength);
|
2013-09-12 15:53:15 +04:00
|
|
|
else
|
|
|
|
cbRecvLength = 0;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
if (ptrIoRecvPciBuffer)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2013-09-12 14:30:46 +04:00
|
|
|
if (Stream_GetRemainingLength(irp->input) < 8)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 8,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
2013-09-12 14:30:46 +04:00
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
/* recvPci */
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, linkedLen);
|
2013-09-12 17:50:12 +04:00
|
|
|
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. */
|
2013-10-02 18:48:54 +04:00
|
|
|
if (linkedLen < ioRecvPci.rq->cbPciLength)
|
2013-09-12 17:50:12 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("SCARD_IO_REQUEST with invalid extra byte length %d [%d]",
|
2013-10-02 18:48:54 +04:00
|
|
|
ioRecvPci.rq->cbPciLength - sizeof(SCARD_IO_REQUEST), linkedLen);
|
2013-09-12 17:50:12 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
|
|
|
}
|
2013-09-12 14:30:46 +04:00
|
|
|
|
2013-09-24 11:23:43 +04:00
|
|
|
if (Stream_GetRemainingLength(irp->input) < ioRecvPci.rq->cbPciLength)
|
2013-09-12 14:30:46 +04:00
|
|
|
{
|
2013-09-24 11:23:43 +04:00
|
|
|
DEBUG_WARN("length violation %d [%d]", ioRecvPci.rq->cbPciLength,
|
2013-09-12 14:30:46 +04:00
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
2013-09-12 14:30:46 +04:00
|
|
|
}
|
|
|
|
|
2013-09-12 17:50:12 +04:00
|
|
|
/* Read data, see
|
|
|
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa379807%28v=vs.85%29.aspx
|
|
|
|
*/
|
2013-10-01 16:41:59 +04:00
|
|
|
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);
|
|
|
|
}
|
2013-09-12 17:50:12 +04:00
|
|
|
|
|
|
|
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))
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_E_INVALID_TARGET;
|
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
|
|
|
|
2013-09-12 17:50:12 +04:00
|
|
|
status = SCardTransmit(hCard, ioSendPci.rq, sendBuf, cbSendLength,
|
2011-10-15 19:30:10 +04:00
|
|
|
pPioRecvPci, recvBuf, &cbRecvLength);
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
finish:
|
2013-08-30 18:30:27 +04:00
|
|
|
if (sendBuf)
|
|
|
|
free(sendBuf);
|
|
|
|
if (recvBuf)
|
|
|
|
free(recvBuf);
|
2013-09-12 17:50:12 +04:00
|
|
|
if (ioSendPci.v)
|
|
|
|
free(ioSendPci.v);
|
|
|
|
if (ioRecvPci.v)
|
|
|
|
free(ioRecvPci.v);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2012-11-21 20:56:40 +04:00
|
|
|
LONG status;
|
2011-10-15 19:30:10 +04:00
|
|
|
SCARDCONTEXT hContext;
|
|
|
|
SCARDHANDLE hCard;
|
2013-09-12 15:53:15 +04:00
|
|
|
UINT32 pvInBuffer, fpvOutBufferIsNULL;
|
2012-10-09 11:26:39 +04:00
|
|
|
UINT32 controlCode;
|
|
|
|
UINT32 controlFunction;
|
2012-11-21 20:56:40 +04:00
|
|
|
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;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CardHandle(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < 20)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", 20,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, controlCode);
|
|
|
|
Stream_Read_UINT32(irp->input, recvLength);
|
2013-09-12 15:53:15 +04:00
|
|
|
Stream_Read_UINT32(irp->input, pvInBuffer);
|
|
|
|
Stream_Read_UINT32(irp->input, fpvOutBufferIsNULL);
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, outBufferSize);
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirHandleRef(smartcard, irp, redirect, &hContext, &hCard);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
2013-09-12 15:53:15 +04:00
|
|
|
goto finish;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2011-11-23 04:22:17 +04:00
|
|
|
/* Translate Windows SCARD_CTL_CODE's to corresponding local code */
|
2014-04-04 01:29:12 +04:00
|
|
|
if (DEVICE_TYPE_FROM_CTL_CODE(controlCode) == FILE_DEVICE_SMARTCARD)
|
2011-11-23 04:22:17 +04:00
|
|
|
{
|
2014-04-04 01:29:12 +04:00
|
|
|
controlFunction = FUNCTION_FROM_CTL_CODE(controlCode);
|
2011-11-23 04:22:17 +04:00
|
|
|
controlCode = SCARD_CTL_CODE(controlFunction);
|
|
|
|
}
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
if (pvInBuffer)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2013-09-12 15:53:15 +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;
|
|
|
|
}
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, recvLength);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
/* Check, if there is actually enough data... */
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < recvLength)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("length violation %d [%d]", recvLength,
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
|
|
|
status = SCARD_F_INTERNAL_ERROR;
|
|
|
|
goto finish;
|
|
|
|
}
|
2012-10-09 07:21:26 +04:00
|
|
|
recvBuffer = malloc(recvLength);
|
2011-11-22 05:46:58 +04:00
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read(irp->input, recvBuffer, recvLength);
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nBytesReturned = outBufferSize;
|
2012-10-09 07:21:26 +04:00
|
|
|
sendBuffer = malloc(outBufferSize);
|
2011-11-22 05:46:58 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
if (!check_handle_is_forwarded(smartcard, hCard, hContext))
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
|
2013-09-12 15:53:15 +04:00
|
|
|
status = SCARD_E_INVALID_TARGET;
|
|
|
|
goto finish;
|
2013-09-12 14:18:35 +04:00
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardControl(hCard, (DWORD) controlCode, recvBuffer, (DWORD) recvLength,
|
2011-10-15 19:30:10 +04:00
|
|
|
sendBuffer, (DWORD) outBufferSize, &nBytesReturned);
|
|
|
|
|
2013-05-09 00:09:16 +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)
|
|
|
|
{
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write(irp->output, sendBuffer, nBytesReturned);
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_repos(irp, nBytesReturned);
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 15:53:15 +04:00
|
|
|
finish:
|
|
|
|
if (recvBuffer)
|
|
|
|
free(recvBuffer);
|
|
|
|
if (sendBuffer)
|
|
|
|
free(sendBuffer);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2012-11-21 20:56:40 +04:00
|
|
|
LONG status;
|
2011-10-15 19:30:10 +04:00
|
|
|
SCARDHANDLE hCard;
|
2013-09-12 14:18:35 +04:00
|
|
|
SCARDCONTEXT hContext;
|
2012-11-21 20:56:40 +04:00
|
|
|
DWORD dwAttrId = 0;
|
|
|
|
DWORD dwAttrLen = 0;
|
2011-10-15 19:30:10 +04:00
|
|
|
DWORD attrLen = 0;
|
2012-10-09 11:01:37 +04:00
|
|
|
BYTE* pbAttr = NULL;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CardHandle(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +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;
|
|
|
|
}
|
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, dwAttrId);
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->input, 0x4);
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, dwAttrLen);
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirHandleRef(smartcard, irp, redirect, &hContext, &hCard);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +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))
|
2013-09-12 14:18:35 +04:00
|
|
|
{
|
|
|
|
DEBUG_WARN("invalid handle %p [%p]", hCard, hContext);
|
|
|
|
return SCARD_E_INVALID_TARGET;
|
|
|
|
}
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
attrLen = (dwAttrLen == 0) ? 0 : SCARD_AUTOALLOCATE;
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardGetAttrib(hCard, dwAttrId, attrLen == 0 ? NULL : (BYTE*) &pbAttr, &attrLen);
|
|
|
|
|
|
|
|
if (status != SCARD_S_SUCCESS)
|
|
|
|
{
|
2014-04-04 01:29:12 +04:00
|
|
|
attrLen = (dwAttrLen == 0) ? 0 : SCARD_AUTOALLOCATE;
|
2011-12-22 23:23:08 +04:00
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
if (dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_A && status == SCARD_E_UNSUPPORTED_FEATURE)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_W,
|
2012-10-09 11:01:37 +04:00
|
|
|
attrLen == 0 ? NULL : (BYTE*) &pbAttr, &attrLen);
|
2012-11-21 20:56:40 +04:00
|
|
|
|
|
|
|
if (status != SCARD_S_SUCCESS)
|
|
|
|
{
|
2014-04-04 01:29:12 +04:00
|
|
|
attrLen = (dwAttrLen == 0) ? 0 : SCARD_AUTOALLOCATE;
|
2011-12-22 23:23:08 +04:00
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
2014-04-04 01:29:12 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
if (dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_W && status == SCARD_E_UNSUPPORTED_FEATURE)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_A,
|
2012-10-09 11:01:37 +04:00
|
|
|
attrLen == 0 ? NULL : (BYTE*) &pbAttr, &attrLen);
|
2012-11-21 20:56:40 +04:00
|
|
|
|
|
|
|
if (status != SCARD_S_SUCCESS)
|
|
|
|
{
|
2014-04-04 01:29:12 +04:00
|
|
|
attrLen = (dwAttrLen == 0) ? 0 : SCARD_AUTOALLOCATE;
|
2011-12-22 23:23:08 +04:00
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
2012-11-21 20:56:40 +04:00
|
|
|
if (attrLen > dwAttrLen && pbAttr != NULL)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCARD_E_INSUFFICIENT_BUFFER;
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
dwAttrLen = attrLen;
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
if (status != SCARD_S_SUCCESS)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2013-10-01 15:09:52 +04:00
|
|
|
status = smartcard_output_return(irp, status);
|
|
|
|
goto finish;
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-05-09 00:09:16 +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)
|
|
|
|
{
|
2013-05-09 00:27:21 +04:00
|
|
|
Stream_Zero(irp->output, dwAttrLen);
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write(irp->output, pbAttr, dwAttrLen);
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_repos(irp, dwAttrLen);
|
2011-11-22 05:46:58 +04:00
|
|
|
/* 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
|
|
|
}
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-10-01 15:09:52 +04:00
|
|
|
finish:
|
2013-09-12 14:18:35 +04:00
|
|
|
SCardFreeMemory(hContext, pbAttr);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2012-11-21 20:56:40 +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
|
|
|
{
|
2013-09-12 14:18:35 +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));
|
2013-09-12 14:18:35 +04:00
|
|
|
return SCARD_F_INTERNAL_ERROR;
|
|
|
|
}
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
Stream_Seek(irp->input, 4);
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2013-09-12 14:18:35 +04:00
|
|
|
|
2011-10-15 19:30:10 +04:00
|
|
|
return SCARD_S_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
void scard_error(SMARTCARD_DEVICE* smartcard, IRP* irp, UINT32 ntstatus)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2011-11-22 05:46:58 +04:00
|
|
|
/* [MS-RDPESC] 3.1.4.4 */
|
2013-09-12 14:18:35 +04:00
|
|
|
DEBUG_WARN("scard processing error %x", ntstatus);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_SetPosition(irp->output, 0); /* CHECKME */
|
2011-10-15 19:30:10 +04:00
|
|
|
irp->IoStatus = ntstatus;
|
|
|
|
irp->Complete(irp);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2013-09-30 16:49:19 +04:00
|
|
|
int redirect = 0;
|
2012-11-21 20:56:40 +04:00
|
|
|
LONG status;
|
2011-11-22 05:46:58 +04:00
|
|
|
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;
|
2011-11-22 05:46:58 +04:00
|
|
|
SCARD_READERSTATE* cur = NULL;
|
|
|
|
SCARD_READERSTATE* rsCur = NULL;
|
|
|
|
SCARD_READERSTATE* 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
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_CommonTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_PrivateTypeHeader(smartcard, irp);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_Context(smartcard, irp, &redirect);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +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);
|
2014-04-04 01:29:12 +04:00
|
|
|
status = handle_RedirContextRef(smartcard, irp, redirect, &hContext);
|
2013-10-24 23:34:14 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->input, 0x2C);
|
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
|
|
|
|
2014-04-04 01:29:12 +04:00
|
|
|
pAtrMasks = malloc(atrMaskCount * sizeof(SCARD_ATRMASK));
|
2011-11-22 05:46:58 +04:00
|
|
|
|
2011-10-15 19:30:10 +04:00
|
|
|
if (!pAtrMasks)
|
2012-11-21 20:56:40 +04:00
|
|
|
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
|
|
|
|
2012-11-20 08:49:08 +04:00
|
|
|
readerStates = malloc(readerCount * sizeof(SCARD_READERSTATE));
|
|
|
|
ZeroMemory(readerStates, readerCount * sizeof(SCARD_READERSTATE));
|
2011-11-22 05:46:58 +04:00
|
|
|
|
2011-10-15 19:30:10 +04:00
|
|
|
for (i = 0; i < readerCount; i++)
|
|
|
|
{
|
|
|
|
cur = &readerStates[i];
|
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->input, 4);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: on-wire is little endian; need to either
|
|
|
|
* convert to host endian or fix the headers to
|
|
|
|
* request the order we want
|
|
|
|
*/
|
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
|
|
|
|
2013-04-30 06:35:15 +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++)
|
|
|
|
{
|
|
|
|
cur = &readerStates[i];
|
2012-10-09 11:26:39 +04:00
|
|
|
UINT32 dataLength;
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->input, 8);
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, dataLength);
|
2012-11-21 20:56:40 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
status = SCardGetStatusChange(hContext, 0x00000001, readerStates, readerCount);
|
2014-04-04 01:29:12 +04:00
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
if (status != SCARD_S_SUCCESS)
|
2011-10-15 19:30:10 +04:00
|
|
|
{
|
2013-10-01 15:09:52 +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++)
|
|
|
|
{
|
2012-10-09 10:38:39 +04:00
|
|
|
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 */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2013-08-30 16:19:50 +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
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
smartcard_output_alignment(irp, 8);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-10-01 15:09:52 +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
|
|
|
|
2012-11-21 20:56:40 +04:00
|
|
|
return status;
|
2011-10-15 19:30:10 +04:00
|
|
|
}
|
|
|
|
|
2012-11-21 20:56:40 +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 */
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->input, 8);
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(irp->input, ioctl_code);
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Rewind(irp->input, 12);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
|
|
|
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:
|
|
|
|
|
2012-10-09 10:31:28 +04:00
|
|
|
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:
|
2012-10-09 10:31:28 +04:00
|
|
|
return TRUE;
|
2011-10-15 19:30:10 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* default to async */
|
2012-10-09 10:31:28 +04:00
|
|
|
return TRUE;
|
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 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;
|
2012-11-21 20:56:40 +04:00
|
|
|
const UINT32 header_lengths = 16;
|
|
|
|
|
|
|
|
/* MS-RPCE, Sections 2.2.6.1 and 2.2.6.2. */
|
2013-09-12 14:18:35 +04:00
|
|
|
if (Stream_GetRemainingLength(irp->input) < 32)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("Invalid IRP of length %d received, ignoring.",
|
|
|
|
Stream_GetRemainingLength(irp->input));
|
|
|
|
return;
|
|
|
|
}
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-05-09 00:09:16 +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
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_Seek(irp->input, 20); /* padding */
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
// Stream_Seek(irp->input, 4); /* TODO: parse len, le, v1 */
|
|
|
|
// Stream_Seek(irp->input, 4); /* 0xcccccccc */
|
|
|
|
// Stream_Seek(irp->input, 4); /* rpce len */
|
2011-10-15 19:30:10 +04:00
|
|
|
|
|
|
|
/* [MS-RDPESC] 3.2.5.1 Sending Outgoing Messages */
|
2013-05-02 02:15:55 +04:00
|
|
|
Stream_EnsureRemainingCapacity(irp->output, 2048);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
irp_result_pos = Stream_GetPosition(irp->output);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(irp->output, 0x00000000); /* MS-RDPEFS
|
2012-08-02 02:05:45 +04:00
|
|
|
* OutputBufferLength
|
|
|
|
* will be updated
|
|
|
|
* later in this
|
|
|
|
* function.
|
|
|
|
*/
|
2011-10-15 19:30:10 +04:00
|
|
|
/* [MS-RPCE] 2.2.6.1 */
|
2013-05-09 00:09:16 +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
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
output_len_pos = Stream_GetPosition(irp->output);
|
|
|
|
Stream_Seek(irp->output, 4); /* size */
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(irp->output, 0x0); /* filler */
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
result_pos = Stream_GetPosition(irp->output);
|
|
|
|
Stream_Seek(irp->output, 4); /* result */
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-09-12 14:18:35 +04:00
|
|
|
/* Ensure, that this package is fully available. */
|
|
|
|
if (Stream_GetRemainingLength(irp->input) < input_len)
|
|
|
|
{
|
|
|
|
DEBUG_WARN("Invalid IRP of length %d received, expected %d, ignoring.",
|
|
|
|
Stream_GetRemainingLength(irp->input), input_len);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* body. input_len contains the length of the remaining data
|
|
|
|
* that can be read from the current position of irp->input,
|
|
|
|
* so pass it on ;) */
|
2014-04-04 01:29:12 +04:00
|
|
|
|
2011-10-15 19:30:10 +04:00
|
|
|
switch (ioctl_code)
|
|
|
|
{
|
|
|
|
case SCARD_IOCTL_ESTABLISH_CONTEXT:
|
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_IS_VALID_CONTEXT:
|
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_RELEASE_CONTEXT:
|
2014-04-04 01:29:12 +04:00
|
|
|
result = handle_ReleaseContext(smartcard, irp);
|
2011-10-15 19:30:10 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SCARD_IOCTL_LIST_READERS:
|
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_LIST_READERS + 4:
|
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_LIST_READER_GROUPS:
|
|
|
|
case SCARD_IOCTL_LIST_READER_GROUPS + 4:
|
2011-11-22 05:46:58 +04:00
|
|
|
/* 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:
|
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_GET_STATUS_CHANGE + 4:
|
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_CONNECT:
|
2014-04-04 01:29:12 +04:00
|
|
|
result = handle_Connect(smartcard, irp, 0);
|
2011-10-15 19:30:10 +04:00
|
|
|
break;
|
|
|
|
case SCARD_IOCTL_CONNECT + 4:
|
2014-04-04 01:29:12 +04:00
|
|
|
result = handle_Connect(smartcard, irp, 1);
|
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_BEGIN_TRANSACTION:
|
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_END_TRANSACTION:
|
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_STATUS:
|
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_STATUS + 4:
|
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_ACCESS_STARTED_EVENT:
|
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_LOCATE_CARDS_BY_ATR:
|
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_LOCATE_CARDS_BY_ATR + 4:
|
2014-04-04 01:29:12 +04:00
|
|
|
result = handle_LocateCardsByATR(smartcard, irp, 1);
|
2011-10-15 19:30:10 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
result = 0xc0000001;
|
2013-09-12 14:18:35 +04:00
|
|
|
DEBUG_WARN("scard unknown ioctl 0x%x [%d]\n",
|
|
|
|
ioctl_code, input_len);
|
2011-10-15 19:30:10 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* look for NTSTATUS errors */
|
|
|
|
if ((result & 0xc0000000) == 0xc0000000)
|
2014-04-04 01:29:12 +04:00
|
|
|
return scard_error(smartcard, irp, result);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
|
|
|
/* per Ludovic Rousseau, map different usage of this particular
|
|
|
|
* error code between pcsc-lite & windows */
|
|
|
|
if (result == 0x8010001F)
|
|
|
|
result = 0x80100022;
|
|
|
|
|
|
|
|
/* handle response packet */
|
2013-04-30 06:35:15 +04:00
|
|
|
pos = Stream_GetPosition(irp->output);
|
2012-08-02 02:05:45 +04:00
|
|
|
stream_len = pos - irp_result_pos - 4; /* Value of OutputBufferLength */
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_SetPosition(irp->output, irp_result_pos);
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(irp->output, stream_len);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_SetPosition(irp->output, output_len_pos);
|
2012-08-02 02:05:45 +04:00
|
|
|
/* Remove the effect of the MS-RPCE Common Type Header and Private
|
|
|
|
* Header (Sections 2.2.6.1 and 2.2.6.2).
|
|
|
|
*/
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(irp->output, stream_len - header_lengths);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_SetPosition(irp->output, result_pos);
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(irp->output, result);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
2013-04-30 06:35:15 +04:00
|
|
|
Stream_SetPosition(irp->output, pos);
|
2011-10-15 19:30:10 +04:00
|
|
|
|
|
|
|
irp->IoStatus = 0;
|
|
|
|
|
|
|
|
irp->Complete(irp);
|
|
|
|
|
|
|
|
}
|