Blame channels/smartcard/client/smartcard_main.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * Smartcard Device Service Virtual Channel
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2011 O.S. Systems Software Ltda.
Packit Service fa4841
 * Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
Packit Service fa4841
 * Copyright 2011 Anthony Tong <atong@trustedcs.com>
Packit Service fa4841
 * Copyright 2015 Thincast Technologies GmbH
Packit Service fa4841
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
Packit Service fa4841
 * Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <winpr/crt.h>
Packit Service fa4841
#include <winpr/smartcard.h>
Packit Service fa4841
#include <winpr/environment.h>
Packit Service fa4841
Packit Service fa4841
#include <freerdp/channels/rdpdr.h>
Packit Service fa4841
Packit Service fa4841
#include "smartcard_main.h"
Packit Service fa4841
Packit Service fa4841
#define CAST_FROM_DEVICE(device) cast_device_from(device, __FUNCTION__, __FILE__, __LINE__)
Packit Service fa4841
Packit Service fa4841
static SMARTCARD_DEVICE* sSmartcard = NULL;
Packit Service fa4841
Packit Service fa4841
static SMARTCARD_DEVICE* cast_device_from(DEVICE* device, const char* fkt, const char* file,
Packit Service b1ea74
                                          int line)
Packit Service fa4841
{
Packit Service fa4841
	if (!device)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "%s [%s:%d] Called smartcard channel with NULL device", fkt, file, line);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (device->type != RDPDR_DTYP_SMARTCARD)
Packit Service fa4841
	{
Packit Service b1ea74
		WLog_ERR(TAG, "%s [%s:%d] Called smartcard channel with invalid device of type %" PRIx32,
Packit Service fa4841
		         fkt, file, line, device->type);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return (SMARTCARD_DEVICE*)device;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static DWORD WINAPI smartcard_context_thread(LPVOID arg)
Packit Service fa4841
{
Packit Service fa4841
	SMARTCARD_CONTEXT* pContext = (SMARTCARD_CONTEXT*)arg;
Packit Service fa4841
	DWORD nCount;
Packit Service fa4841
	LONG status = 0;
Packit Service fa4841
	DWORD waitStatus;
Packit Service fa4841
	HANDLE hEvents[2];
Packit Service fa4841
	wMessage message;
Packit Service fa4841
	SMARTCARD_DEVICE* smartcard;
Packit Service fa4841
	SMARTCARD_OPERATION* operation;
Packit Service fa4841
	UINT error = CHANNEL_RC_OK;
Packit Service fa4841
	smartcard = pContext->smartcard;
Packit Service fa4841
	nCount = 0;
Packit Service fa4841
	hEvents[nCount++] = MessageQueue_Event(pContext->IrpQueue);
Packit Service fa4841
Packit Service fa4841
	while (1)
Packit Service fa4841
	{
Packit Service fa4841
		waitStatus = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
Packit Service fa4841
Packit Service fa4841
		if (waitStatus == WAIT_FAILED)
Packit Service fa4841
		{
Packit Service fa4841
			error = GetLastError();
Packit Service b1ea74
			WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		waitStatus = WaitForSingleObject(MessageQueue_Event(pContext->IrpQueue), 0);
Packit Service fa4841
Packit Service fa4841
		if (waitStatus == WAIT_FAILED)
Packit Service fa4841
		{
Packit Service fa4841
			error = GetLastError();
Packit Service b1ea74
			WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (waitStatus == WAIT_OBJECT_0)
Packit Service fa4841
		{
Packit Service fa4841
			if (!MessageQueue_Peek(pContext->IrpQueue, &message, TRUE))
Packit Service fa4841
			{
Packit Service fa4841
				WLog_ERR(TAG, "MessageQueue_Peek failed!");
Packit Service fa4841
				status = ERROR_INTERNAL_ERROR;
Packit Service fa4841
				break;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			if (message.id == WMQ_QUIT)
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service b1ea74
			operation = (SMARTCARD_OPERATION*)message.wParam;
Packit Service fa4841
Packit Service fa4841
			if (operation)
Packit Service fa4841
			{
Packit Service fa4841
				if ((status = smartcard_irp_device_control_call(smartcard, operation)))
Packit Service fa4841
				{
Packit Service b1ea74
					WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %" PRIu32 "",
Packit Service fa4841
					         status);
Packit Service fa4841
					break;
Packit Service fa4841
				}
Packit Service fa4841
Packit Service b1ea74
				if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*)operation->irp))
Packit Service fa4841
				{
Packit Service fa4841
					WLog_ERR(TAG, "Queue_Enqueue failed!");
Packit Service fa4841
					status = ERROR_INTERNAL_ERROR;
Packit Service fa4841
					break;
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				free(operation);
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (status && smartcard->rdpcontext)
Packit Service b1ea74
		setChannelError(smartcard->rdpcontext, error, "smartcard_context_thread reported an error");
Packit Service fa4841
Packit Service fa4841
	ExitThread(status);
Packit Service fa4841
	return error;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
SMARTCARD_CONTEXT* smartcard_context_new(SMARTCARD_DEVICE* smartcard, SCARDCONTEXT hContext)
Packit Service fa4841
{
Packit Service fa4841
	SMARTCARD_CONTEXT* pContext;
Packit Service b1ea74
	pContext = (SMARTCARD_CONTEXT*)calloc(1, sizeof(SMARTCARD_CONTEXT));
Packit Service fa4841
Packit Service fa4841
	if (!pContext)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "calloc failed!");
Packit Service fa4841
		return pContext;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	pContext->smartcard = smartcard;
Packit Service fa4841
	pContext->hContext = hContext;
Packit Service fa4841
	pContext->IrpQueue = MessageQueue_New(NULL);
Packit Service fa4841
Packit Service fa4841
	if (!pContext->IrpQueue)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "MessageQueue_New failed!");
Packit Service fa4841
		goto error_irpqueue;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service b1ea74
	pContext->thread = CreateThread(NULL, 0, smartcard_context_thread, pContext, 0, NULL);
Packit Service fa4841
Packit Service fa4841
	if (!pContext->thread)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "CreateThread failed!");
Packit Service fa4841
		goto error_thread;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return pContext;
Packit Service fa4841
error_thread:
Packit Service fa4841
	MessageQueue_Free(pContext->IrpQueue);
Packit Service fa4841
error_irpqueue:
Packit Service fa4841
	free(pContext);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void smartcard_context_free(void* pCtx)
Packit Service fa4841
{
Packit Service fa4841
	SMARTCARD_CONTEXT* pContext = pCtx;
Packit Service fa4841
Packit Service fa4841
	if (!pContext)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	/* cancel blocking calls like SCardGetStatusChange */
Packit Service fa4841
	SCardCancel(pContext->hContext);
Packit Service fa4841
Packit Service b1ea74
	if (MessageQueue_PostQuit(pContext->IrpQueue, 0) &&
Packit Service b1ea74
	    (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED))
Packit Service b1ea74
		WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError());
Packit Service fa4841
Packit Service fa4841
	CloseHandle(pContext->thread);
Packit Service fa4841
	MessageQueue_Free(pContext->IrpQueue);
Packit Service fa4841
	free(pContext);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard)
Packit Service fa4841
{
Packit Service fa4841
	int index;
Packit Service fa4841
	int keyCount;
Packit Service fa4841
	ULONG_PTR* pKeys;
Packit Service fa4841
	SCARDCONTEXT hContext;
Packit Service fa4841
	SMARTCARD_CONTEXT* pContext;
Packit Service fa4841
Packit Service fa4841
	/**
Packit Service fa4841
	 * On protocol termination, the following actions are performed:
Packit Service b1ea74
	 * For each context in rgSCardContextList, SCardCancel is called causing all
Packit Service b1ea74
	 * SCardGetStatusChange calls to be processed. After that, SCardReleaseContext is called on each
Packit Service b1ea74
	 * context and the context MUST be removed from rgSCardContextList.
Packit Service fa4841
	 */
Packit Service fa4841
Packit Service fa4841
	/**
Packit Service fa4841
	 * Call SCardCancel on existing contexts, unblocking all outstanding SCardGetStatusChange calls.
Packit Service fa4841
	 */
Packit Service fa4841
Packit Service fa4841
	if (ListDictionary_Count(smartcard->rgSCardContextList) > 0)
Packit Service fa4841
	{
Packit Service fa4841
		pKeys = NULL;
Packit Service fa4841
		keyCount = ListDictionary_GetKeys(smartcard->rgSCardContextList, &pKeys);
Packit Service fa4841
Packit Service fa4841
		for (index = 0; index < keyCount; index++)
Packit Service fa4841
		{
Packit Service b1ea74
			pContext = (SMARTCARD_CONTEXT*)ListDictionary_GetItemValue(
Packit Service b1ea74
			    smartcard->rgSCardContextList, (void*)pKeys[index]);
Packit Service fa4841
Packit Service fa4841
			if (!pContext)
Packit Service fa4841
				continue;
Packit Service fa4841
Packit Service fa4841
			hContext = pContext->hContext;
Packit Service fa4841
Packit Service fa4841
			if (SCardIsValidContext(hContext) == SCARD_S_SUCCESS)
Packit Service fa4841
			{
Packit Service fa4841
				SCardCancel(hContext);
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		free(pKeys);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/**
Packit Service fa4841
	 * Call SCardReleaseContext on remaining contexts and remove them from rgSCardContextList.
Packit Service fa4841
	 */
Packit Service fa4841
Packit Service fa4841
	if (ListDictionary_Count(smartcard->rgSCardContextList) > 0)
Packit Service fa4841
	{
Packit Service fa4841
		pKeys = NULL;
Packit Service fa4841
		keyCount = ListDictionary_GetKeys(smartcard->rgSCardContextList, &pKeys);
Packit Service fa4841
Packit Service fa4841
		for (index = 0; index < keyCount; index++)
Packit Service fa4841
		{
Packit Service b1ea74
			pContext = (SMARTCARD_CONTEXT*)ListDictionary_Remove(smartcard->rgSCardContextList,
Packit Service b1ea74
			                                                     (void*)pKeys[index]);
Packit Service fa4841
Packit Service fa4841
			if (!pContext)
Packit Service fa4841
				continue;
Packit Service fa4841
Packit Service fa4841
			hContext = pContext->hContext;
Packit Service fa4841
Packit Service fa4841
			if (SCardIsValidContext(hContext) == SCARD_S_SUCCESS)
Packit Service fa4841
			{
Packit Service fa4841
				SCardReleaseContext(hContext);
Packit Service fa4841
Packit Service b1ea74
				if (MessageQueue_PostQuit(pContext->IrpQueue, 0) &&
Packit Service b1ea74
				    (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED))
Packit Service b1ea74
					WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!",
Packit Service b1ea74
					         GetLastError());
Packit Service fa4841
Packit Service fa4841
				CloseHandle(pContext->thread);
Packit Service fa4841
				MessageQueue_Free(pContext->IrpQueue);
Packit Service fa4841
				free(pContext);
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		free(pKeys);
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static UINT smartcard_free_(SMARTCARD_DEVICE* smartcard)
Packit Service fa4841
{
Packit Service fa4841
	if (!smartcard)
Packit Service fa4841
		return CHANNEL_RC_OK;
Packit Service fa4841
Packit Service fa4841
	if (smartcard->IrpQueue)
Packit Service fa4841
	{
Packit Service fa4841
		MessageQueue_Free(smartcard->IrpQueue);
Packit Service fa4841
		CloseHandle(smartcard->thread);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	Stream_Free(smartcard->device.data, TRUE);
Packit Service fa4841
	LinkedList_Free(smartcard->names);
Packit Service fa4841
	ListDictionary_Free(smartcard->rgSCardContextList);
Packit Service fa4841
	ListDictionary_Free(smartcard->rgOutstandingMessages);
Packit Service fa4841
	Queue_Free(smartcard->CompletedIrpQueue);
Packit Service fa4841
Packit Service fa4841
	if (smartcard->StartedEvent)
Packit Service fa4841
		SCardReleaseStartedEvent();
Packit Service fa4841
Packit Service fa4841
	free(smartcard);
Packit Service fa4841
	return CHANNEL_RC_OK;
Packit Service fa4841
}
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT smartcard_free(DEVICE* device)
Packit Service fa4841
{
Packit Service fa4841
	UINT error;
Packit Service fa4841
	SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
Packit Service fa4841
Packit Service fa4841
	if (!smartcard)
Packit Service fa4841
		return ERROR_INVALID_PARAMETER;
Packit Service fa4841
Packit Service fa4841
	/**
Packit Service fa4841
	 * Calling smartcard_release_all_contexts to unblock all operations waiting for transactions
Packit Service fa4841
	 * to unlock.
Packit Service fa4841
	 */
Packit Service fa4841
	smartcard_release_all_contexts(smartcard);
Packit Service fa4841
Packit Service fa4841
	/* Stopping all threads and cancelling all IRPs */
Packit Service fa4841
Packit Service fa4841
	if (smartcard->IrpQueue)
Packit Service fa4841
	{
Packit Service b1ea74
		if (MessageQueue_PostQuit(smartcard->IrpQueue, 0) &&
Packit Service b1ea74
		    (WaitForSingleObject(smartcard->thread, INFINITE) == WAIT_FAILED))
Packit Service fa4841
		{
Packit Service fa4841
			error = GetLastError();
Packit Service b1ea74
			WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
Packit Service fa4841
			return error;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (sSmartcard == smartcard)
Packit Service fa4841
		sSmartcard = NULL;
Packit Service fa4841
Packit Service fa4841
	return smartcard_free_(smartcard);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Initialization occurs when the protocol server sends a device announce message.
Packit Service fa4841
 * At that time, we need to cancel all outstanding IRPs.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT smartcard_init(DEVICE* device)
Packit Service fa4841
{
Packit Service fa4841
	SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
Packit Service fa4841
Packit Service fa4841
	if (!smartcard)
Packit Service fa4841
		return ERROR_INVALID_PARAMETER;
Packit Service fa4841
Packit Service fa4841
	smartcard_release_all_contexts(smartcard);
Packit Service fa4841
	return CHANNEL_RC_OK;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
Packit Service fa4841
{
Packit Service fa4841
	void* key;
Packit Service b1ea74
	key = (void*)(size_t)irp->CompletionId;
Packit Service fa4841
	ListDictionary_Remove(smartcard->rgOutstandingMessages, key);
Packit Service fa4841
	return irp->Complete(irp);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Multiple threads and SCardGetStatusChange:
Packit Service fa4841
 * http://musclecard.996296.n3.nabble.com/Multiple-threads-and-SCardGetStatusChange-td4430.html
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
Packit Service fa4841
{
Packit Service fa4841
	void* key;
Packit Service fa4841
	LONG status;
Packit Service fa4841
	BOOL asyncIrp = FALSE;
Packit Service fa4841
	SMARTCARD_CONTEXT* pContext = NULL;
Packit Service fa4841
	SMARTCARD_OPERATION* operation = NULL;
Packit Service b1ea74
	key = (void*)(size_t)irp->CompletionId;
Packit Service fa4841
Packit Service fa4841
	if (!ListDictionary_Add(smartcard->rgOutstandingMessages, key, irp))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "ListDictionary_Add failed!");
Packit Service fa4841
		return ERROR_INTERNAL_ERROR;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
Packit Service fa4841
	{
Packit Service b1ea74
		operation = (SMARTCARD_OPERATION*)calloc(1, sizeof(SMARTCARD_OPERATION));
Packit Service fa4841
Packit Service fa4841
		if (!operation)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "calloc failed!");
Packit Service fa4841
			return CHANNEL_RC_NO_MEMORY;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		operation->irp = irp;
Packit Service fa4841
		status = smartcard_irp_device_control_decode(smartcard, operation);
Packit Service fa4841
Packit Service fa4841
		if (status != SCARD_S_SUCCESS)
Packit Service fa4841
		{
Packit Service fa4841
			irp->IoStatus = (UINT32)STATUS_UNSUCCESSFUL;
Packit Service fa4841
Packit Service b1ea74
			if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*)irp))
Packit Service fa4841
			{
Packit Service fa4841
				free(operation);
Packit Service fa4841
				WLog_ERR(TAG, "Queue_Enqueue failed!");
Packit Service fa4841
				return ERROR_INTERNAL_ERROR;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			free(operation);
Packit Service fa4841
			return CHANNEL_RC_OK;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		asyncIrp = TRUE;
Packit Service fa4841
Packit Service fa4841
		switch (operation->ioControlCode)
Packit Service fa4841
		{
Packit Service fa4841
			case SCARD_IOCTL_ESTABLISHCONTEXT:
Packit Service fa4841
			case SCARD_IOCTL_RELEASECONTEXT:
Packit Service fa4841
			case SCARD_IOCTL_ISVALIDCONTEXT:
Packit Service fa4841
			case SCARD_IOCTL_CANCEL:
Packit Service fa4841
			case SCARD_IOCTL_ACCESSSTARTEDEVENT:
Packit Service b1ea74
			case SCARD_IOCTL_RELEASETARTEDEVENT:
Packit Service fa4841
				asyncIrp = FALSE;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case SCARD_IOCTL_LISTREADERGROUPSA:
Packit Service fa4841
			case SCARD_IOCTL_LISTREADERGROUPSW:
Packit Service fa4841
			case SCARD_IOCTL_LISTREADERSA:
Packit Service fa4841
			case SCARD_IOCTL_LISTREADERSW:
Packit Service fa4841
			case SCARD_IOCTL_INTRODUCEREADERGROUPA:
Packit Service fa4841
			case SCARD_IOCTL_INTRODUCEREADERGROUPW:
Packit Service fa4841
			case SCARD_IOCTL_FORGETREADERGROUPA:
Packit Service fa4841
			case SCARD_IOCTL_FORGETREADERGROUPW:
Packit Service fa4841
			case SCARD_IOCTL_INTRODUCEREADERA:
Packit Service fa4841
			case SCARD_IOCTL_INTRODUCEREADERW:
Packit Service fa4841
			case SCARD_IOCTL_FORGETREADERA:
Packit Service fa4841
			case SCARD_IOCTL_FORGETREADERW:
Packit Service fa4841
			case SCARD_IOCTL_ADDREADERTOGROUPA:
Packit Service fa4841
			case SCARD_IOCTL_ADDREADERTOGROUPW:
Packit Service fa4841
			case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
Packit Service fa4841
			case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
Packit Service fa4841
			case SCARD_IOCTL_LOCATECARDSA:
Packit Service fa4841
			case SCARD_IOCTL_LOCATECARDSW:
Packit Service fa4841
			case SCARD_IOCTL_LOCATECARDSBYATRA:
Packit Service fa4841
			case SCARD_IOCTL_LOCATECARDSBYATRW:
Packit Service fa4841
			case SCARD_IOCTL_READCACHEA:
Packit Service fa4841
			case SCARD_IOCTL_READCACHEW:
Packit Service fa4841
			case SCARD_IOCTL_WRITECACHEA:
Packit Service fa4841
			case SCARD_IOCTL_WRITECACHEW:
Packit Service fa4841
			case SCARD_IOCTL_GETREADERICON:
Packit Service fa4841
			case SCARD_IOCTL_GETDEVICETYPEID:
Packit Service fa4841
			case SCARD_IOCTL_GETSTATUSCHANGEA:
Packit Service fa4841
			case SCARD_IOCTL_GETSTATUSCHANGEW:
Packit Service fa4841
			case SCARD_IOCTL_CONNECTA:
Packit Service fa4841
			case SCARD_IOCTL_CONNECTW:
Packit Service fa4841
			case SCARD_IOCTL_RECONNECT:
Packit Service fa4841
			case SCARD_IOCTL_DISCONNECT:
Packit Service fa4841
			case SCARD_IOCTL_BEGINTRANSACTION:
Packit Service fa4841
			case SCARD_IOCTL_ENDTRANSACTION:
Packit Service fa4841
			case SCARD_IOCTL_STATE:
Packit Service fa4841
			case SCARD_IOCTL_STATUSA:
Packit Service fa4841
			case SCARD_IOCTL_STATUSW:
Packit Service fa4841
			case SCARD_IOCTL_TRANSMIT:
Packit Service fa4841
			case SCARD_IOCTL_CONTROL:
Packit Service fa4841
			case SCARD_IOCTL_GETATTRIB:
Packit Service fa4841
			case SCARD_IOCTL_SETATTRIB:
Packit Service fa4841
			case SCARD_IOCTL_GETTRANSMITCOUNT:
Packit Service fa4841
				asyncIrp = TRUE;
Packit Service fa4841
				break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service b1ea74
		pContext =
Packit Service b1ea74
		    ListDictionary_GetItemValue(smartcard->rgSCardContextList, (void*)operation->hContext);
Packit Service fa4841
Packit Service fa4841
		if (!pContext)
Packit Service fa4841
			asyncIrp = FALSE;
Packit Service fa4841
Packit Service fa4841
		if (!asyncIrp)
Packit Service fa4841
		{
Packit Service fa4841
			if ((status = smartcard_irp_device_control_call(smartcard, operation)))
Packit Service fa4841
			{
Packit Service b1ea74
				WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %" PRId32 "!",
Packit Service fa4841
				         status);
Packit Service fa4841
				return (UINT32)status;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service b1ea74
			if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*)irp))
Packit Service fa4841
			{
Packit Service fa4841
				free(operation);
Packit Service fa4841
				WLog_ERR(TAG, "Queue_Enqueue failed!");
Packit Service fa4841
				return ERROR_INTERNAL_ERROR;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			free(operation);
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service fa4841
			if (pContext)
Packit Service fa4841
			{
Packit Service b1ea74
				if (!MessageQueue_Post(pContext->IrpQueue, NULL, 0, (void*)operation, NULL))
Packit Service fa4841
				{
Packit Service fa4841
					WLog_ERR(TAG, "MessageQueue_Post failed!");
Packit Service fa4841
					return ERROR_INTERNAL_ERROR;
Packit Service fa4841
				}
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG,
Packit Service b1ea74
		         "Unexpected SmartCard IRP: MajorFunction 0x%08" PRIX32
Packit Service b1ea74
		         " MinorFunction: 0x%08" PRIX32 "",
Packit Service fa4841
		         irp->MajorFunction, irp->MinorFunction);
Packit Service fa4841
		irp->IoStatus = (UINT32)STATUS_NOT_SUPPORTED;
Packit Service fa4841
Packit Service b1ea74
		if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*)irp))
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "Queue_Enqueue failed!");
Packit Service fa4841
			return ERROR_INTERNAL_ERROR;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return CHANNEL_RC_OK;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static DWORD WINAPI smartcard_thread_func(LPVOID arg)
Packit Service fa4841
{
Packit Service fa4841
	IRP* irp;
Packit Service fa4841
	DWORD nCount;
Packit Service fa4841
	DWORD status;
Packit Service fa4841
	HANDLE hEvents[2];
Packit Service fa4841
	wMessage message;
Packit Service fa4841
	UINT error = CHANNEL_RC_OK;
Packit Service fa4841
	SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(arg);
Packit Service fa4841
Packit Service fa4841
	if (!smartcard)
Packit Service fa4841
		return ERROR_INVALID_PARAMETER;
Packit Service fa4841
Packit Service fa4841
	nCount = 0;
Packit Service fa4841
	hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue);
Packit Service fa4841
	hEvents[nCount++] = Queue_Event(smartcard->CompletedIrpQueue);
Packit Service fa4841
Packit Service fa4841
	while (1)
Packit Service fa4841
	{
Packit Service fa4841
		status = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
Packit Service fa4841
Packit Service fa4841
		if (status == WAIT_FAILED)
Packit Service fa4841
		{
Packit Service fa4841
			error = GetLastError();
Packit Service b1ea74
			WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		status = WaitForSingleObject(MessageQueue_Event(smartcard->IrpQueue), 0);
Packit Service fa4841
Packit Service fa4841
		if (status == WAIT_FAILED)
Packit Service fa4841
		{
Packit Service fa4841
			error = GetLastError();
Packit Service b1ea74
			WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (status == WAIT_OBJECT_0)
Packit Service fa4841
		{
Packit Service fa4841
			if (!MessageQueue_Peek(smartcard->IrpQueue, &message, TRUE))
Packit Service fa4841
			{
Packit Service fa4841
				WLog_ERR(TAG, "MessageQueue_Peek failed!");
Packit Service fa4841
				error = ERROR_INTERNAL_ERROR;
Packit Service fa4841
				break;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			if (message.id == WMQ_QUIT)
Packit Service fa4841
			{
Packit Service fa4841
				while (1)
Packit Service fa4841
				{
Packit Service fa4841
					status = WaitForSingleObject(Queue_Event(smartcard->CompletedIrpQueue), 0);
Packit Service fa4841
Packit Service fa4841
					if (status == WAIT_FAILED)
Packit Service fa4841
					{
Packit Service fa4841
						error = GetLastError();
Packit Service b1ea74
						WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
Packit Service fa4841
						goto out;
Packit Service fa4841
					}
Packit Service fa4841
Packit Service fa4841
					if (status == WAIT_TIMEOUT)
Packit Service fa4841
						break;
Packit Service fa4841
Packit Service b1ea74
					irp = (IRP*)Queue_Dequeue(smartcard->CompletedIrpQueue);
Packit Service fa4841
Packit Service fa4841
					if (irp)
Packit Service fa4841
					{
Packit Service fa4841
						if (irp->thread)
Packit Service fa4841
						{
Packit Service fa4841
							status = WaitForSingleObject(irp->thread, INFINITE);
Packit Service fa4841
Packit Service fa4841
							if (status == WAIT_FAILED)
Packit Service fa4841
							{
Packit Service fa4841
								error = GetLastError();
Packit Service b1ea74
								WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!",
Packit Service b1ea74
								         error);
Packit Service fa4841
								goto out;
Packit Service fa4841
							}
Packit Service fa4841
Packit Service fa4841
							CloseHandle(irp->thread);
Packit Service fa4841
							irp->thread = NULL;
Packit Service fa4841
						}
Packit Service fa4841
Packit Service fa4841
						if ((error = smartcard_complete_irp(smartcard, irp)))
Packit Service fa4841
						{
Packit Service b1ea74
							WLog_ERR(TAG, "smartcard_complete_irp failed with error %" PRIu32 "!",
Packit Service b1ea74
							         error);
Packit Service fa4841
							goto out;
Packit Service fa4841
						}
Packit Service fa4841
					}
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service b1ea74
			irp = (IRP*)message.wParam;
Packit Service fa4841
Packit Service fa4841
			if (irp)
Packit Service fa4841
			{
Packit Service fa4841
				if ((error = smartcard_process_irp(smartcard, irp)))
Packit Service fa4841
				{
Packit Service b1ea74
					WLog_ERR(TAG, "smartcard_process_irp failed with error %" PRIu32 "!", error);
Packit Service fa4841
					goto out;
Packit Service fa4841
				}
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		status = WaitForSingleObject(Queue_Event(smartcard->CompletedIrpQueue), 0);
Packit Service fa4841
Packit Service fa4841
		if (status == WAIT_FAILED)
Packit Service fa4841
		{
Packit Service fa4841
			error = GetLastError();
Packit Service b1ea74
			WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (status == WAIT_OBJECT_0)
Packit Service fa4841
		{
Packit Service b1ea74
			irp = (IRP*)Queue_Dequeue(smartcard->CompletedIrpQueue);
Packit Service fa4841
Packit Service fa4841
			if (irp)
Packit Service fa4841
			{
Packit Service fa4841
				if (irp->thread)
Packit Service fa4841
				{
Packit Service fa4841
					status = WaitForSingleObject(irp->thread, INFINITE);
Packit Service fa4841
Packit Service fa4841
					if (status == WAIT_FAILED)
Packit Service fa4841
					{
Packit Service fa4841
						error = GetLastError();
Packit Service b1ea74
						WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
Packit Service fa4841
						break;
Packit Service fa4841
					}
Packit Service fa4841
Packit Service fa4841
					CloseHandle(irp->thread);
Packit Service fa4841
					irp->thread = NULL;
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				if ((error = smartcard_complete_irp(smartcard, irp)))
Packit Service fa4841
				{
Packit Service fa4841
					if (error == CHANNEL_RC_NOT_CONNECTED)
Packit Service fa4841
					{
Packit Service fa4841
						error = CHANNEL_RC_OK;
Packit Service fa4841
						goto out;
Packit Service fa4841
					}
Packit Service fa4841
Packit Service b1ea74
					WLog_ERR(TAG, "smartcard_complete_irp failed with error %" PRIu32 "!", error);
Packit Service fa4841
					goto out;
Packit Service fa4841
				}
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
out:
Packit Service fa4841
Packit Service fa4841
	if (error && smartcard->rdpcontext)
Packit Service b1ea74
		setChannelError(smartcard->rdpcontext, error, "smartcard_thread_func reported an error");
Packit Service fa4841
Packit Service fa4841
	ExitThread(error);
Packit Service fa4841
	return error;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT smartcard_irp_request(DEVICE* device, IRP* irp)
Packit Service fa4841
{
Packit Service fa4841
	SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
Packit Service fa4841
Packit Service fa4841
	if (!smartcard)
Packit Service fa4841
		return ERROR_INVALID_PARAMETER;
Packit Service fa4841
Packit Service b1ea74
	if (!MessageQueue_Post(smartcard->IrpQueue, NULL, 0, (void*)irp, NULL))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "MessageQueue_Post failed!");
Packit Service fa4841
		return ERROR_INTERNAL_ERROR;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return CHANNEL_RC_OK;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/* smartcard is always built-in */
Packit Service b1ea74
#define DeviceServiceEntry smartcard_DeviceServiceEntry
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
Packit Service fa4841
{
Packit Service fa4841
	SMARTCARD_DEVICE* smartcard = NULL;
Packit Service fa4841
	size_t length;
Packit Service fa4841
	UINT error = CHANNEL_RC_NO_MEMORY;
Packit Service fa4841
Packit Service fa4841
	if (!sSmartcard)
Packit Service fa4841
	{
Packit Service fa4841
		wObject* obj;
Packit Service b1ea74
		smartcard = (SMARTCARD_DEVICE*)calloc(1, sizeof(SMARTCARD_DEVICE));
Packit Service fa4841
Packit Service fa4841
		if (!smartcard)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "calloc failed!");
Packit Service fa4841
			return CHANNEL_RC_NO_MEMORY;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		smartcard->device.type = RDPDR_DTYP_SMARTCARD;
Packit Service fa4841
		smartcard->device.name = "SCARD";
Packit Service fa4841
		smartcard->device.IRPRequest = smartcard_irp_request;
Packit Service fa4841
		smartcard->device.Init = smartcard_init;
Packit Service fa4841
		smartcard->device.Free = smartcard_free;
Packit Service fa4841
		smartcard->names = LinkedList_New();
Packit Service fa4841
		smartcard->rdpcontext = pEntryPoints->rdpcontext;
Packit Service fa4841
		length = strlen(smartcard->device.name);
Packit Service fa4841
		smartcard->device.data = Stream_New(NULL, length + 1);
Packit Service fa4841
Packit Service fa4841
		if (!smartcard->device.data || !smartcard->names)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "Stream_New failed!");
Packit Service fa4841
			goto fail;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		Stream_Write(smartcard->device.data, "SCARD", 6);
Packit Service fa4841
		smartcard->IrpQueue = MessageQueue_New(NULL);
Packit Service fa4841
Packit Service fa4841
		if (!smartcard->IrpQueue)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "MessageQueue_New failed!");
Packit Service fa4841
			goto fail;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		smartcard->CompletedIrpQueue = Queue_New(TRUE, -1, -1);
Packit Service fa4841
Packit Service fa4841
		if (!smartcard->CompletedIrpQueue)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "Queue_New failed!");
Packit Service fa4841
			goto fail;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		smartcard->rgSCardContextList = ListDictionary_New(TRUE);
Packit Service fa4841
Packit Service fa4841
		if (!smartcard->rgSCardContextList)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "ListDictionary_New failed!");
Packit Service fa4841
			goto fail;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		obj = ListDictionary_ValueObject(smartcard->rgSCardContextList);
Packit Service fa4841
		obj->fnObjectFree = smartcard_context_free;
Packit Service fa4841
		smartcard->rgOutstandingMessages = ListDictionary_New(TRUE);
Packit Service fa4841
Packit Service fa4841
		if (!smartcard->rgOutstandingMessages)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "ListDictionary_New failed!");
Packit Service fa4841
			goto fail;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, &smartcard->device)))
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "RegisterDevice failed!");
Packit Service fa4841
			goto fail;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service b1ea74
		smartcard->thread =
Packit Service b1ea74
		    CreateThread(NULL, 0, smartcard_thread_func, smartcard, CREATE_SUSPENDED, NULL);
Packit Service fa4841
Packit Service fa4841
		if (!smartcard->thread)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "ListDictionary_New failed!");
Packit Service fa4841
			error = ERROR_INTERNAL_ERROR;
Packit Service fa4841
			goto fail;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		ResumeThread(smartcard->thread);
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
		smartcard = sSmartcard;
Packit Service fa4841
Packit Service fa4841
	if (pEntryPoints->device->Name)
Packit Service fa4841
		LinkedList_AddLast(smartcard->names, pEntryPoints->device->Name);
Packit Service fa4841
Packit Service fa4841
	sSmartcard = smartcard;
Packit Service fa4841
	return CHANNEL_RC_OK;
Packit Service fa4841
fail:
Packit Service fa4841
	smartcard_free_(smartcard);
Packit Service fa4841
	return error;
Packit Service fa4841
}