diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
commit | a9bcc81f821d7c66f623779fa5147e728eb3c388 (patch) | |
tree | 98676963bcdd537ae5908a067a8eb110b93486a6 /channels/smartcard | |
parent | Initial commit. (diff) | |
download | freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip |
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'channels/smartcard')
-rw-r--r-- | channels/smartcard/CMakeLists.txt | 22 | ||||
-rw-r--r-- | channels/smartcard/ChannelOptions.cmake | 12 | ||||
-rw-r--r-- | channels/smartcard/client/CMakeLists.txt | 33 | ||||
-rw-r--r-- | channels/smartcard/client/smartcard_main.c | 720 | ||||
-rw-r--r-- | channels/smartcard/client/smartcard_main.h | 59 |
5 files changed, 846 insertions, 0 deletions
diff --git a/channels/smartcard/CMakeLists.txt b/channels/smartcard/CMakeLists.txt new file mode 100644 index 0000000..98c6c72 --- /dev/null +++ b/channels/smartcard/CMakeLists.txt @@ -0,0 +1,22 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.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. + +define_channel("smartcard") + +if(WITH_CLIENT_CHANNELS) + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/smartcard/ChannelOptions.cmake b/channels/smartcard/ChannelOptions.cmake new file mode 100644 index 0000000..7af6e31 --- /dev/null +++ b/channels/smartcard/ChannelOptions.cmake @@ -0,0 +1,12 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_SERVER_DEFAULT OFF) + +define_channel_options(NAME "smartcard" TYPE "device" + DESCRIPTION "Smart Card Virtual Channel Extension" + SPECIFICATIONS "[MS-RDPESC]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_client_options(${OPTION_CLIENT_DEFAULT}) +define_channel_server_options(${OPTION_SERVER_DEFAULT}) diff --git a/channels/smartcard/client/CMakeLists.txt b/channels/smartcard/client/CMakeLists.txt new file mode 100644 index 0000000..08ce6af --- /dev/null +++ b/channels/smartcard/client/CMakeLists.txt @@ -0,0 +1,33 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.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. + +define_channel_client("smartcard") + +set(${MODULE_PREFIX}_SRCS + smartcard_main.c + smartcard_main.h +) + +set(${MODULE_PREFIX}_LIBS + winpr freerdp ${OPENSSL_LIBRARIES} +) +if (WITH_SMARTCARD_EMULATE) + list(APPEND ${MODULE_PREFIX}_LIBS + ZLIB::ZLIB + ) +endif() +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DeviceServiceEntry") diff --git a/channels/smartcard/client/smartcard_main.c b/channels/smartcard/client/smartcard_main.c new file mode 100644 index 0000000..0037b4e --- /dev/null +++ b/channels/smartcard/client/smartcard_main.c @@ -0,0 +1,720 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Smartcard Device Service Virtual Channel + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br> + * Copyright 2011 Anthony Tong <atong@trustedcs.com> + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com> + * Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.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. + */ + +#include <freerdp/config.h> + +#include <winpr/crt.h> +#include <winpr/smartcard.h> +#include <winpr/environment.h> + +#include <freerdp/freerdp.h> +#include <freerdp/channels/rdpdr.h> +#include <freerdp/channels/scard.h> +#include <freerdp/utils/smartcard_call.h> +#include <freerdp/utils/smartcard_operations.h> +#include <freerdp/utils/rdpdr_utils.h> + +#include "smartcard_main.h" + +#define CAST_FROM_DEVICE(device) cast_device_from(device, __func__, __FILE__, __LINE__) + +typedef struct +{ + SMARTCARD_OPERATION operation; + IRP* irp; +} scard_irp_queue_element; + +static SMARTCARD_DEVICE* sSmartcard = NULL; + +static void smartcard_context_free(void* pCtx); + +static UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled); + +static SMARTCARD_DEVICE* cast_device_from(DEVICE* device, const char* fkt, const char* file, + size_t line) +{ + if (!device) + { + WLog_ERR(TAG, "%s [%s:%" PRIuz "] Called smartcard channel with NULL device", fkt, file, + line); + return NULL; + } + + if (device->type != RDPDR_DTYP_SMARTCARD) + { + WLog_ERR(TAG, + "%s [%s:%" PRIuz "] Called smartcard channel with invalid device of type %" PRIx32, + fkt, file, line, device->type); + return NULL; + } + + return (SMARTCARD_DEVICE*)device; +} + +static DWORD WINAPI smartcard_context_thread(LPVOID arg) +{ + SMARTCARD_CONTEXT* pContext = (SMARTCARD_CONTEXT*)arg; + DWORD nCount = 0; + LONG status = 0; + DWORD waitStatus = 0; + HANDLE hEvents[2] = { 0 }; + wMessage message = { 0 }; + SMARTCARD_DEVICE* smartcard = NULL; + UINT error = CHANNEL_RC_OK; + smartcard = pContext->smartcard; + + hEvents[nCount++] = MessageQueue_Event(pContext->IrpQueue); + + while (1) + { + waitStatus = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE); + + if (waitStatus == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error); + break; + } + + waitStatus = WaitForSingleObject(MessageQueue_Event(pContext->IrpQueue), 0); + + if (waitStatus == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); + break; + } + + if (waitStatus == WAIT_OBJECT_0) + { + scard_irp_queue_element* element = NULL; + + if (!MessageQueue_Peek(pContext->IrpQueue, &message, TRUE)) + { + WLog_ERR(TAG, "MessageQueue_Peek failed!"); + status = ERROR_INTERNAL_ERROR; + break; + } + + if (message.id == WMQ_QUIT) + break; + + element = (scard_irp_queue_element*)message.wParam; + + if (element) + { + BOOL handled = FALSE; + WINPR_ASSERT(smartcard); + + if ((status = smartcard_irp_device_control_call( + smartcard->callctx, element->irp->output, &element->irp->IoStatus, + &element->operation))) + { + element->irp->Discard(element->irp); + smartcard_operation_free(&element->operation, TRUE); + WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %" PRIu32 "", + status); + break; + } + + error = smartcard_complete_irp(smartcard, element->irp, &handled); + if (!handled) + element->irp->Discard(element->irp); + smartcard_operation_free(&element->operation, TRUE); + + if (error) + { + WLog_ERR(TAG, "Queue_Enqueue failed!"); + break; + } + } + } + } + + if (status && smartcard->rdpcontext) + setChannelError(smartcard->rdpcontext, error, "smartcard_context_thread reported an error"); + + ExitThread(status); + return error; +} + +static void smartcard_operation_queue_free(void* obj) +{ + wMessage* msg = obj; + if (!msg) + return; + if (msg->id != 0) + return; + + scard_irp_queue_element* element = (scard_irp_queue_element*)msg->wParam; + if (!element) + return; + WINPR_ASSERT(element->irp); + WINPR_ASSERT(element->irp->Discard); + element->irp->Discard(element->irp); + smartcard_operation_free(&element->operation, TRUE); +} + +static void* smartcard_context_new(void* smartcard, SCARDCONTEXT hContext) +{ + SMARTCARD_CONTEXT* pContext = NULL; + pContext = (SMARTCARD_CONTEXT*)calloc(1, sizeof(SMARTCARD_CONTEXT)); + + if (!pContext) + { + WLog_ERR(TAG, "calloc failed!"); + return pContext; + } + + pContext->smartcard = smartcard; + pContext->hContext = hContext; + pContext->IrpQueue = MessageQueue_New(NULL); + + if (!pContext->IrpQueue) + { + WLog_ERR(TAG, "MessageQueue_New failed!"); + goto fail; + } + wObject* obj = MessageQueue_Object(pContext->IrpQueue); + WINPR_ASSERT(obj); + obj->fnObjectFree = smartcard_operation_queue_free; + + pContext->thread = CreateThread(NULL, 0, smartcard_context_thread, pContext, 0, NULL); + + if (!pContext->thread) + { + WLog_ERR(TAG, "CreateThread failed!"); + goto fail; + } + + return pContext; +fail: + smartcard_context_free(pContext); + return NULL; +} + +void smartcard_context_free(void* pCtx) +{ + SMARTCARD_CONTEXT* pContext = pCtx; + + if (!pContext) + return; + + /* cancel blocking calls like SCardGetStatusChange */ + WINPR_ASSERT(pContext->smartcard); + smartcard_call_cancel_context(pContext->smartcard->callctx, pContext->hContext); + + if (pContext->IrpQueue) + { + if (MessageQueue_PostQuit(pContext->IrpQueue, 0)) + { + if (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED) + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError()); + + CloseHandle(pContext->thread); + } + MessageQueue_Free(pContext->IrpQueue); + } + smartcard_call_release_context(pContext->smartcard->callctx, pContext->hContext); + free(pContext); +} + +static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) +{ + smartcard_call_cancel_all_context(smartcard->callctx); +} + +static UINT smartcard_free_(SMARTCARD_DEVICE* smartcard) +{ + if (!smartcard) + return CHANNEL_RC_OK; + + if (smartcard->IrpQueue) + { + MessageQueue_Free(smartcard->IrpQueue); + CloseHandle(smartcard->thread); + } + + Stream_Free(smartcard->device.data, TRUE); + ListDictionary_Free(smartcard->rgOutstandingMessages); + + smartcard_call_context_free(smartcard->callctx); + + free(smartcard); + return CHANNEL_RC_OK; +} +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT smartcard_free(DEVICE* device) +{ + SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device); + + if (!smartcard) + return ERROR_INVALID_PARAMETER; + + /** + * Calling smartcard_release_all_contexts to unblock all operations waiting for transactions + * to unlock. + */ + smartcard_release_all_contexts(smartcard); + + /* Stopping all threads and cancelling all IRPs */ + + if (smartcard->IrpQueue) + { + if (MessageQueue_PostQuit(smartcard->IrpQueue, 0) && + (WaitForSingleObject(smartcard->thread, INFINITE) == WAIT_FAILED)) + { + DWORD error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); + return error; + } + } + + if (sSmartcard == smartcard) + sSmartcard = NULL; + + return smartcard_free_(smartcard); +} + +/** + * Initialization occurs when the protocol server sends a device announce message. + * At that time, we need to cancel all outstanding IRPs. + */ + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT smartcard_init(DEVICE* device) +{ + SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device); + + if (!smartcard) + return ERROR_INVALID_PARAMETER; + + smartcard_release_all_contexts(smartcard); + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled) +{ + WINPR_ASSERT(smartcard); + WINPR_ASSERT(irp); + WINPR_ASSERT(handled); + + uintptr_t key = (uintptr_t)irp->CompletionId + 1; + ListDictionary_Remove(smartcard->rgOutstandingMessages, (void*)key); + + WINPR_ASSERT(irp->Complete); + *handled = TRUE; + return irp->Complete(irp); +} + +/** + * Multiple threads and SCardGetStatusChange: + * http://musclecard.996296.n3.nabble.com/Multiple-threads-and-SCardGetStatusChange-td4430.html + */ + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled) +{ + LONG status = 0; + BOOL asyncIrp = FALSE; + SMARTCARD_CONTEXT* pContext = NULL; + + WINPR_ASSERT(smartcard); + WINPR_ASSERT(handled); + WINPR_ASSERT(irp); + WINPR_ASSERT(irp->Complete); + + uintptr_t key = (uintptr_t)irp->CompletionId + 1; + + if (!ListDictionary_Add(smartcard->rgOutstandingMessages, (void*)key, irp)) + { + WLog_ERR(TAG, "ListDictionary_Add failed!"); + return ERROR_INTERNAL_ERROR; + } + + if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL) + { + scard_irp_queue_element* element = calloc(1, sizeof(scard_irp_queue_element)); + if (!element) + return ERROR_OUTOFMEMORY; + + element->irp = irp; + element->operation.completionID = irp->CompletionId; + + status = smartcard_irp_device_control_decode(irp->input, irp->CompletionId, irp->FileId, + &element->operation); + + if (status != SCARD_S_SUCCESS) + { + UINT error = 0; + + smartcard_operation_free(&element->operation, TRUE); + irp->IoStatus = (UINT32)STATUS_UNSUCCESSFUL; + + if ((error = smartcard_complete_irp(smartcard, irp, handled))) + { + WLog_ERR(TAG, "Queue_Enqueue failed!"); + return error; + } + + return CHANNEL_RC_OK; + } + + asyncIrp = TRUE; + + switch (element->operation.ioControlCode) + { + case SCARD_IOCTL_ESTABLISHCONTEXT: + case SCARD_IOCTL_RELEASECONTEXT: + case SCARD_IOCTL_ISVALIDCONTEXT: + case SCARD_IOCTL_CANCEL: + case SCARD_IOCTL_ACCESSSTARTEDEVENT: + case SCARD_IOCTL_RELEASETARTEDEVENT: + asyncIrp = FALSE; + break; + + case SCARD_IOCTL_LISTREADERGROUPSA: + case SCARD_IOCTL_LISTREADERGROUPSW: + case SCARD_IOCTL_LISTREADERSA: + case SCARD_IOCTL_LISTREADERSW: + case SCARD_IOCTL_INTRODUCEREADERGROUPA: + case SCARD_IOCTL_INTRODUCEREADERGROUPW: + case SCARD_IOCTL_FORGETREADERGROUPA: + case SCARD_IOCTL_FORGETREADERGROUPW: + case SCARD_IOCTL_INTRODUCEREADERA: + case SCARD_IOCTL_INTRODUCEREADERW: + case SCARD_IOCTL_FORGETREADERA: + case SCARD_IOCTL_FORGETREADERW: + case SCARD_IOCTL_ADDREADERTOGROUPA: + case SCARD_IOCTL_ADDREADERTOGROUPW: + case SCARD_IOCTL_REMOVEREADERFROMGROUPA: + case SCARD_IOCTL_REMOVEREADERFROMGROUPW: + case SCARD_IOCTL_LOCATECARDSA: + case SCARD_IOCTL_LOCATECARDSW: + case SCARD_IOCTL_LOCATECARDSBYATRA: + case SCARD_IOCTL_LOCATECARDSBYATRW: + case SCARD_IOCTL_READCACHEA: + case SCARD_IOCTL_READCACHEW: + case SCARD_IOCTL_WRITECACHEA: + case SCARD_IOCTL_WRITECACHEW: + case SCARD_IOCTL_GETREADERICON: + case SCARD_IOCTL_GETDEVICETYPEID: + case SCARD_IOCTL_GETSTATUSCHANGEA: + case SCARD_IOCTL_GETSTATUSCHANGEW: + case SCARD_IOCTL_CONNECTA: + case SCARD_IOCTL_CONNECTW: + case SCARD_IOCTL_RECONNECT: + case SCARD_IOCTL_DISCONNECT: + case SCARD_IOCTL_BEGINTRANSACTION: + case SCARD_IOCTL_ENDTRANSACTION: + case SCARD_IOCTL_STATE: + case SCARD_IOCTL_STATUSA: + case SCARD_IOCTL_STATUSW: + case SCARD_IOCTL_TRANSMIT: + case SCARD_IOCTL_CONTROL: + case SCARD_IOCTL_GETATTRIB: + case SCARD_IOCTL_SETATTRIB: + case SCARD_IOCTL_GETTRANSMITCOUNT: + asyncIrp = TRUE; + break; + } + + pContext = smartcard_call_get_context(smartcard->callctx, element->operation.hContext); + + if (!pContext) + asyncIrp = FALSE; + + if (!asyncIrp) + { + UINT error = 0; + + status = + smartcard_irp_device_control_call(smartcard->callctx, element->irp->output, + &element->irp->IoStatus, &element->operation); + smartcard_operation_free(&element->operation, TRUE); + + if (status) + { + WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %" PRId32 "!", + status); + return (UINT32)status; + } + + if ((error = smartcard_complete_irp(smartcard, irp, handled))) + { + WLog_ERR(TAG, "Queue_Enqueue failed!"); + return error; + } + } + else + { + if (pContext) + { + if (!MessageQueue_Post(pContext->IrpQueue, NULL, 0, (void*)element, NULL)) + { + smartcard_operation_free(&element->operation, TRUE); + WLog_ERR(TAG, "MessageQueue_Post failed!"); + return ERROR_INTERNAL_ERROR; + } + *handled = TRUE; + } + } + } + else + { + UINT ustatus = 0; + WLog_ERR(TAG, "Unexpected SmartCard IRP: MajorFunction %s, MinorFunction: 0x%08" PRIX32 "", + rdpdr_irp_string(irp->MajorFunction), irp->MinorFunction); + irp->IoStatus = (UINT32)STATUS_NOT_SUPPORTED; + + if ((ustatus = smartcard_complete_irp(smartcard, irp, handled))) + { + WLog_ERR(TAG, "Queue_Enqueue failed!"); + return ustatus; + } + } + + return CHANNEL_RC_OK; +} + +static DWORD WINAPI smartcard_thread_func(LPVOID arg) +{ + IRP* irp = NULL; + DWORD nCount = 0; + DWORD status = 0; + HANDLE hEvents[1] = { 0 }; + wMessage message = { 0 }; + UINT error = CHANNEL_RC_OK; + SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(arg); + + if (!smartcard) + return ERROR_INVALID_PARAMETER; + + hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue); + + while (1) + { + status = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE); + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error); + break; + } + + if (status == WAIT_OBJECT_0) + { + if (!MessageQueue_Peek(smartcard->IrpQueue, &message, TRUE)) + { + WLog_ERR(TAG, "MessageQueue_Peek failed!"); + error = ERROR_INTERNAL_ERROR; + break; + } + + if (message.id == WMQ_QUIT) + break; + + irp = (IRP*)message.wParam; + + if (irp) + { + BOOL handled = FALSE; + if ((error = smartcard_process_irp(smartcard, irp, &handled))) + { + WLog_ERR(TAG, "smartcard_process_irp failed with error %" PRIu32 "!", error); + goto out; + } + if (!handled) + { + WINPR_ASSERT(irp->Discard); + irp->Discard(irp); + } + } + } + } + +out: + + if (error && smartcard->rdpcontext) + setChannelError(smartcard->rdpcontext, error, "smartcard_thread_func reported an error"); + + ExitThread(error); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT smartcard_irp_request(DEVICE* device, IRP* irp) +{ + SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device); + + if (!smartcard) + return ERROR_INVALID_PARAMETER; + + if (!MessageQueue_Post(smartcard->IrpQueue, NULL, 0, (void*)irp, NULL)) + { + WLog_ERR(TAG, "MessageQueue_Post failed!"); + return ERROR_INTERNAL_ERROR; + } + + return CHANNEL_RC_OK; +} + +static void smartcard_free_irp(void* obj) +{ + wMessage* msg = obj; + if (!msg) + return; + if (msg->id != 0) + return; + + IRP* irp = (IRP*)msg->wParam; + if (!irp) + return; + WINPR_ASSERT(irp->Discard); + irp->Discard(irp); +} + +/* smartcard is always built-in */ +#define DeviceServiceEntry smartcard_DeviceServiceEntry + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +extern UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints); +UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) +{ + SMARTCARD_DEVICE* smartcard = NULL; + size_t length = 0; + UINT error = CHANNEL_RC_NO_MEMORY; + + if (!sSmartcard) + { + smartcard = (SMARTCARD_DEVICE*)calloc(1, sizeof(SMARTCARD_DEVICE)); + + if (!smartcard) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + smartcard->device.type = RDPDR_DTYP_SMARTCARD; + smartcard->device.name = "SCARD"; + smartcard->device.IRPRequest = smartcard_irp_request; + smartcard->device.Init = smartcard_init; + smartcard->device.Free = smartcard_free; + smartcard->rdpcontext = pEntryPoints->rdpcontext; + length = strlen(smartcard->device.name); + smartcard->device.data = Stream_New(NULL, length + 1); + + if (!smartcard->device.data) + { + WLog_ERR(TAG, "Stream_New failed!"); + goto fail; + } + + Stream_Write(smartcard->device.data, "SCARD", 6); + smartcard->IrpQueue = MessageQueue_New(NULL); + + if (!smartcard->IrpQueue) + { + WLog_ERR(TAG, "MessageQueue_New failed!"); + goto fail; + } + + wObject* obj = MessageQueue_Object(smartcard->IrpQueue); + WINPR_ASSERT(obj); + obj->fnObjectFree = smartcard_free_irp; + + smartcard->rgOutstandingMessages = ListDictionary_New(TRUE); + + if (!smartcard->rgOutstandingMessages) + { + WLog_ERR(TAG, "ListDictionary_New failed!"); + goto fail; + } + + smartcard->callctx = smartcard_call_context_new(smartcard->rdpcontext->settings); + if (!smartcard->callctx) + goto fail; + + if (!smarcard_call_set_callbacks(smartcard->callctx, smartcard, smartcard_context_new, + smartcard_context_free)) + goto fail; + + if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, &smartcard->device))) + { + WLog_ERR(TAG, "RegisterDevice failed!"); + goto fail; + } + + smartcard->thread = + CreateThread(NULL, 0, smartcard_thread_func, smartcard, CREATE_SUSPENDED, NULL); + + if (!smartcard->thread) + { + WLog_ERR(TAG, "ListDictionary_New failed!"); + error = ERROR_INTERNAL_ERROR; + goto fail; + } + + ResumeThread(smartcard->thread); + } + else + smartcard = sSmartcard; + + if (pEntryPoints->device->Name) + { + smartcard_call_context_add(smartcard->callctx, pEntryPoints->device->Name); + } + + sSmartcard = smartcard; + return CHANNEL_RC_OK; +fail: + smartcard_free_(smartcard); + return error; +} diff --git a/channels/smartcard/client/smartcard_main.h b/channels/smartcard/client/smartcard_main.h new file mode 100644 index 0000000..c588588 --- /dev/null +++ b/channels/smartcard/client/smartcard_main.h @@ -0,0 +1,59 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Smartcard Device Service Virtual Channel + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br> + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.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. + */ + +#ifndef FREERDP_CHANNEL_SMARTCARD_CLIENT_MAIN_H +#define FREERDP_CHANNEL_SMARTCARD_CLIENT_MAIN_H + +#include <freerdp/channels/log.h> +#include <freerdp/channels/rdpdr.h> + +#include <winpr/crt.h> +#include <winpr/wlog.h> +#include <winpr/synch.h> +#include <winpr/smartcard.h> +#include <winpr/collections.h> + +#include <freerdp/utils/smartcard_operations.h> +#include <freerdp/utils/smartcard_call.h> + +#define TAG CHANNELS_TAG("smartcard.client") + +typedef struct +{ + DEVICE device; + + HANDLE thread; + scard_call_context* callctx; + wMessageQueue* IrpQueue; + wListDictionary* rgOutstandingMessages; + rdpContext* rdpcontext; +} SMARTCARD_DEVICE; + +typedef struct +{ + HANDLE thread; + SCARDCONTEXT hContext; + wMessageQueue* IrpQueue; + SMARTCARD_DEVICE* smartcard; +} SMARTCARD_CONTEXT; + +#endif /* FREERDP_CHANNEL_SMARTCARD_CLIENT_MAIN_H */ |