Merge branch 'master' of github.com:awakecoding/FreeRDP into fdsapi

This commit is contained in:
Marc-André Moreau 2014-04-27 19:18:23 -04:00
commit b67288868d
209 changed files with 14660 additions and 5531 deletions

View File

@ -20,7 +20,7 @@
cmake_minimum_required(VERSION 2.8)
project(FreeRDP C)
project(FreeRDP C CXX)
if(NOT DEFINED VENDOR)
set(VENDOR "FreeRDP" CACHE STRING "FreeRDP package vendor")
@ -116,6 +116,15 @@ if(MSVC)
endif()
endif()
CHECK_C_COMPILER_FLAG (-Wno-builtin-macro-redefined Wno-builtin-macro-redefined)
if(Wno-builtin-macro-redefined)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -D__FILE__='\"$(subst ${CMAKE_BINARY_DIR}/,,$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<)))\"'")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -D__FILE__='\"$(subst ${CMAKE_BINARY_DIR}/,,$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<)))\"'")
endif()
# Compiler-specific flags
if(CMAKE_COMPILER_IS_GNUCC)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "i686")
@ -134,15 +143,6 @@ if(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
# Hack to strip absolute paths out of the __FILE__ macro
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__FILE__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILE__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'")
CHECK_C_COMPILER_FLAG (-Wno-builtin-macro-redefined Wno-builtin-macro-redefined)
if(Wno-builtin-macro-redefined)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined")
endif()
CHECK_C_COMPILER_FLAG (-Wno-unused-result Wno-unused-result)
if(Wno-unused-result)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-result")
@ -171,6 +171,7 @@ if(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
endif()
if(WITH_SSE2)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2")
@ -340,6 +341,8 @@ else()
set(X11_FEATURE_TYPE "DISABLED")
endif()
find_package(PCSCWinPR)
set(X11_FEATURE_PURPOSE "X11")
set(X11_FEATURE_DESCRIPTION "X11 client and server")
@ -489,6 +492,10 @@ add_definitions("-DHAVE_CONFIG_H")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
# RPATH configuration
if(CMAKE_SKIP_RPATH)
set(CMAKE_SKIP_RPATH FALSE)
set(CMAKE_SKIP_INSTALL_RPATH TRUE)
endif()
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
@ -605,3 +612,30 @@ endif()
#message("VENDOR: ${VENDOR} CLIENT_VENDOR_PATH: ${CLIENT_VENDOR_PATH} CMAKE_CPACK_INCLUDE_FILE: ${CMAKE_CPACK_INCLUDE_FILE}")
include(${CMAKE_CPACK_INCLUDE_FILE})
if(MONOLITHIC_BUILD)
set(FREERDP_PC_LIBS "-lfreerdp -lfreerdp-client")
set(WINPR_PC_LIBS "-lwinpr")
if (WITH_SERVER)
set(FREERDP_PC_LIBS "${FREERDP_PC_LIBS} -lfreerdp-server")
endif()
else(MONOLITHIC_BUILD)
# freerdp exports
get_property(MEXPORTS GLOBAL PROPERTY "freerdp_EXPORTS")
foreach(EXPORT_MODULE ${MEXPORTS})
list(APPEND FREERDP_PC_LIBS "-lfreerdp-${EXPORT_MODULE}")
endforeach()
string(REPLACE ";" " " FREERDP_PC_LIBS "${FREERDP_PC_LIBS}")
# winpr exports
get_property(MEXPORTS GLOBAL PROPERTY "winpr_EXPORTS")
foreach(EXPORT_MODULE ${MEXPORTS})
list(APPEND WINPR_PC_LIBS "-lwinpr-${EXPORT_MODULE}")
endforeach()
string(REPLACE ";" " " WINPR_PC_LIBS "${WINPR_PC_LIBS}")
endif(MONOLITHIC_BUILD)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/winpr.pc.in ${CMAKE_CURRENT_BINARY_DIR}/winpr.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/winpr.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)

View File

@ -36,5 +36,5 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ALSA_LIBRARIES})
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT FreeRDPTargets)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -49,7 +49,6 @@ typedef struct _audin_server
BOOL opened;
HANDLE event;
HANDLE stopEvent;
HANDLE thread;
@ -284,26 +283,35 @@ static void* audin_server_thread_func(void* arg)
void* fd;
wStream* s;
void* buffer;
DWORD nCount;
BYTE MessageId;
HANDLE events[8];
BOOL ready = FALSE;
HANDLE ChannelEvent;
DWORD BytesReturned = 0;
audin_server* audin = (audin_server*) arg;
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualFileHandle, &buffer, &BytesReturned) == TRUE)
{
fd = *((void**) buffer);
WTSFreeMemory(buffer);
buffer = NULL;
BytesReturned = 0;
ChannelEvent = NULL;
audin->event = CreateWaitObjectEvent(NULL, TRUE, FALSE, fd);
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE)
{
if (BytesReturned == sizeof(HANDLE))
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
WTSFreeMemory(buffer);
}
nCount = 0;
events[nCount++] = audin->stopEvent;
events[nCount++] = ChannelEvent;
/* Wait for the client to confirm that the Audio Input dynamic channel is ready */
while (1)
{
WaitForSingleObject(audin->event, INFINITE);
if (WaitForSingleObject(audin->stopEvent, 0) == WAIT_OBJECT_0)
if (WaitForMultipleObjects(nCount, events, FALSE, 100) == WAIT_OBJECT_0)
break;
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE)
@ -326,9 +334,7 @@ static void* audin_server_thread_func(void* arg)
while (ready)
{
WaitForSingleObject(audin->event, INFINITE);
if (WaitForSingleObject(audin->stopEvent, 0) == WAIT_OBJECT_0)
if (WaitForMultipleObjects(nCount, events, FALSE, INFINITE) == WAIT_OBJECT_0)
break;
Stream_SetPosition(s, 0);
@ -405,7 +411,7 @@ static BOOL audin_server_open(audin_server_context* context)
audin->SessionId = WTS_CURRENT_SESSION;
if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION,
WTSSessionId, (LPSTR*) pSessionId, &BytesReturned))
WTSSessionId, (LPSTR*) &pSessionId, &BytesReturned))
{
audin->SessionId = (DWORD) *pSessionId;
WTSFreeMemory(pSessionId);

View File

@ -481,8 +481,8 @@ void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UI
Stream_Read(s, formatDataResponse.requestedFormatData, dataLen);
}
if (context->ClientFormatDataResponse)
context->ClientFormatDataResponse(context, &formatDataResponse);
if (context->ServerFormatDataResponse)
context->ServerFormatDataResponse(context, &formatDataResponse);
free(formatDataResponse.requestedFormatData);
}

View File

@ -30,7 +30,6 @@
#include <winpr/stream.h>
#include <freerdp/addin.h>
#include <freerdp/utils/list.h>
#include "drdynvc_types.h"
#include "dvcman.h"

View File

@ -659,7 +659,7 @@ void drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, char*
drive->path = path;
drive->files = ListDictionary_New(TRUE);
ListDictionary_Object(drive->files)->fnObjectFree = (OBJECT_FREE_FN) drive_file_free;
ListDictionary_ValueObject(drive->files)->fnObjectFree = (OBJECT_FREE_FN) drive_file_free;
drive->IrpQueue = MessageQueue_New(NULL);
drive->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) drive_thread_func, drive, CREATE_SUSPENDED, NULL);

View File

@ -285,10 +285,10 @@ static void parallel_free(DEVICE* device)
MessageQueue_PostQuit(parallel->queue, 0);
WaitForSingleObject(parallel->thread, INFINITE);
CloseHandle(parallel->thread);
Stream_Free(parallel->device.data, TRUE);
MessageQueue_Free(parallel->queue);
CloseHandle(parallel->thread);
free(parallel);
}
@ -309,10 +309,18 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
name = device->Name;
path = device->Path;
if (!name || (name[0] == '*'))
{
/* TODO: implement auto detection of parallel ports */
return 0;
}
if (name[0] && path[0])
{
parallel = (PARALLEL_DEVICE*) malloc(sizeof(PARALLEL_DEVICE));
ZeroMemory(parallel, sizeof(PARALLEL_DEVICE));
parallel = (PARALLEL_DEVICE*) calloc(1, sizeof(PARALLEL_DEVICE));
if (!parallel)
return -1;
parallel->device.type = RDPDR_DTYP_PARALLEL;
parallel->device.name = name;

View File

@ -31,14 +31,13 @@
#include <freerdp/types.h>
#include <freerdp/addin.h>
#include <freerdp/utils/list.h>
#include <freerdp/client/channels.h>
#include "rdpdr_main.h"
#include "devman.h"
static void devman_device_free(DEVICE* device)
void devman_device_free(DEVICE* device)
{
IFCALL(device->Free, device);
}
@ -55,7 +54,7 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr)
devman->devices = ListDictionary_New(TRUE);
ListDictionary_Object(devman->devices)->fnObjectFree =
ListDictionary_ValueObject(devman->devices)->fnObjectFree =
(OBJECT_FREE_FN) devman_device_free;
return devman;
@ -71,7 +70,8 @@ void devman_unregister_device(DEVMAN* devman, void* key)
{
DEVICE* device;
device = (DEVICE *)ListDictionary_Remove(devman->devices, key);
device = (DEVICE*) ListDictionary_Remove(devman->devices, key);
if (device)
devman_device_free(device);
}

View File

@ -35,6 +35,9 @@
static void irp_free(IRP* irp)
{
if (!irp)
return;
Stream_Free(irp->input, TRUE);
Stream_Free(irp->output, TRUE);
@ -46,8 +49,8 @@ static void irp_complete(IRP* irp)
int pos;
pos = (int) Stream_GetPosition(irp->output);
Stream_SetPosition(irp->output, 12);
Stream_Write_UINT32(irp->output, irp->IoStatus);
Stream_SetPosition(irp->output, RDPDR_DEVICE_IO_RESPONSE_LENGTH - 4);
Stream_Write_UINT32(irp->output, irp->IoStatus); /* IoStatus (4 bytes) */
Stream_SetPosition(irp->output, pos);
rdpdr_send((rdpdrPlugin*) irp->devman->plugin, irp->output);
@ -59,37 +62,39 @@ static void irp_complete(IRP* irp)
IRP* irp_new(DEVMAN* devman, wStream* s)
{
IRP* irp;
UINT32 DeviceId;
DEVICE* device;
UINT32 DeviceId;
Stream_Read_UINT32(s, DeviceId);
Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */
device = devman_get_device_by_id(devman, DeviceId);
if (!device)
{
return NULL;
}
irp = (IRP*) _aligned_malloc(sizeof(IRP), MEMORY_ALLOCATION_ALIGNMENT);
ZeroMemory(irp, sizeof(IRP));
irp->input = s;
irp->device = device;
irp->devman = devman;
Stream_Read_UINT32(s, irp->FileId);
Stream_Read_UINT32(s, irp->CompletionId);
Stream_Read_UINT32(s, irp->MajorFunction);
Stream_Read_UINT32(s, irp->MinorFunction);
irp->input = s;
Stream_Read_UINT32(s, irp->FileId); /* FileId (4 bytes) */
Stream_Read_UINT32(s, irp->CompletionId); /* CompletionId (4 bytes) */
Stream_Read_UINT32(s, irp->MajorFunction); /* MajorFunction (4 bytes) */
Stream_Read_UINT32(s, irp->MinorFunction); /* MinorFunction (4 bytes) */
irp->output = Stream_New(NULL, 256);
Stream_Write_UINT16(irp->output, RDPDR_CTYP_CORE);
Stream_Write_UINT16(irp->output, PAKID_CORE_DEVICE_IOCOMPLETION);
Stream_Write_UINT32(irp->output, DeviceId);
Stream_Write_UINT32(irp->output, irp->CompletionId);
Stream_Seek_UINT32(irp->output); /* IoStatus */
Stream_Write_UINT16(irp->output, RDPDR_CTYP_CORE); /* Component (2 bytes) */
Stream_Write_UINT16(irp->output, PAKID_CORE_DEVICE_IOCOMPLETION); /* PacketId (2 bytes) */
Stream_Write_UINT32(irp->output, DeviceId); /* DeviceId (4 bytes) */
Stream_Write_UINT32(irp->output, irp->CompletionId); /* CompletionId (4 bytes) */
Stream_Write_UINT32(irp->output, 0); /* IoStatus (4 bytes) */
irp->Complete = irp_complete;
irp->Discard = irp_free;
irp->thread = NULL;
irp->cancelled = FALSE;
return irp;
}

View File

@ -434,15 +434,16 @@ static void* drive_hotplug_thread_func(void* arg)
struct timeval tv;
int rv;
rdpdr = (rdpdrPlugin *)arg;
rdpdr = (rdpdrPlugin*) arg;
rdpdr->stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
rdpdr->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
mfd = open("/proc/mounts", O_RDONLY, 0);
if (mfd < 0)
{
fprintf(stderr, "ERROR: Unable to open /proc/mounts.");
return NULL;
fprintf(stderr, "ERROR: Unable to open /proc/mounts.");
return NULL;
}
FD_ZERO(&rfds);
@ -452,7 +453,7 @@ static void* drive_hotplug_thread_func(void* arg)
while ((rv = select(mfd+1, NULL, NULL, &rfds, &tv)) >= 0)
{
if (WaitForSingleObject(rdpdr->stop_event, 0) == WAIT_OBJECT_0)
if (WaitForSingleObject(rdpdr->stopEvent, 0) == WAIT_OBJECT_0)
break;
if (FD_ISSET(mfd, &rfds))
@ -467,13 +468,19 @@ static void* drive_hotplug_thread_func(void* arg)
tv.tv_usec = 0;
}
return NULL;
return NULL;
}
static void drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr)
{
if (rdpdr->stop_event)
SetEvent(rdpdr->stop_event);
if (rdpdr->hotplugThread)
{
if (rdpdr->stopEvent)
SetEvent(rdpdr->stopEvent);
WaitForSingleObject(rdpdr->hotplugThread, INFINITE);
rdpdr->hotplugThread = NULL;
}
}
#endif
@ -493,11 +500,14 @@ static void rdpdr_process_connect(rdpdrPlugin* rdpdr)
for (index = 0; index < settings->DeviceCount; index++)
{
device = settings->DeviceArray[index];
if (strcmp(device->Name, "*") == 0)
if (device->Name && (strcmp(device->Name, "*") == 0))
{
rdpdr->hotplug_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)drive_hotplug_thread_func, rdpdr, 0, NULL);
rdpdr->hotplugThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) drive_hotplug_thread_func, rdpdr, 0, NULL);
continue;
}
devman_load_device_service(rdpdr->devman, device);
}
}
@ -670,6 +680,26 @@ static BOOL rdpdr_process_irp(rdpdrPlugin* rdpdr, wStream* s)
return TRUE;
}
static void rdpdr_process_init(rdpdrPlugin* rdpdr)
{
int index;
int keyCount;
DEVICE* device;
ULONG_PTR* pKeys;
pKeys = NULL;
keyCount = ListDictionary_GetKeys(rdpdr->devman->devices, &pKeys);
for (index = 0; index < keyCount; index++)
{
device = (DEVICE*) ListDictionary_GetItemValue(rdpdr->devman->devices, (void*) pKeys[index]);
IFCALL(device->Init, device);
}
free(pKeys);
}
static void rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
{
UINT16 component;
@ -688,6 +718,7 @@ static void rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
rdpdr_process_server_announce_request(rdpdr, s);
rdpdr_send_client_announce_reply(rdpdr);
rdpdr_send_client_name_request(rdpdr);
rdpdr_process_init(rdpdr);
break;
case PAKID_CORE_SERVER_CAPABILITY:
@ -939,8 +970,6 @@ static void rdpdr_virtual_channel_event_terminated(rdpdrPlugin* rdpdr)
drive_hotplug_thread_terminate(rdpdr);
WaitForSingleObject(rdpdr->hotplug_thread, INFINITE);
rdpdr->channelEntryPoints.pVirtualChannelClose(rdpdr->OpenHandle);
if (rdpdr->data_in)

View File

@ -54,11 +54,11 @@ struct rdpdr_plugin
char computerName[256];
/* hotplug support */
HANDLE hotplug_thread;
HANDLE hotplugThread;
#ifdef _WIN32
HWND hotplug_wnd;
#else
HANDLE stop_event;
HANDLE stopEvent;
#endif
};

View File

@ -21,7 +21,6 @@
#include "config.h"
#endif
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -160,8 +159,11 @@ static void* rdpei_schedule_thread(void* arg)
RdpeiClientContext* context = (RdpeiClientContext*) rdpei->iface.pInterface;
HANDLE hdl[] = {rdpei->event, rdpei->stopEvent};
assert(NULL != rdpei);
assert(NULL != context);
if (!rdpei)
return NULL;
if (!context)
return NULL;
while (1)
{
@ -516,7 +518,8 @@ static int rdpei_plugin_terminated(IWTSPlugin* pPlugin)
DEBUG_DVC("");
assert(NULL != pPlugin);
if (!pPlugin)
return -1;
SetEvent(rdpei->stopEvent);
EnterCriticalSection(&rdpei->lock);

View File

@ -27,11 +27,14 @@
// 3. This notice may not be removed or altered from any source distribution.
//
#include <winpr/wlog.h>
#include "TPCircularBuffer.h"
#include <mach/mach.h>
#include <stdio.h>
#define reportResult(result,operation) (_reportResult((result),(operation),strrchr(__FILE__, '/')+1,__LINE__))
#define reportResult(result,operation) (_reportResult((result),(operation),__FILE__,__LINE__))
static inline bool _reportResult(kern_return_t result, const char *operation, const char* file, int line) {
if ( result != ERR_SUCCESS ) {
printf("%s:%d: %s: %s\n", file, line, operation, mach_error_string(result));

View File

@ -31,11 +31,10 @@
#include <string.h>
#include <winpr/crt.h>
#include <winpr/stream.h>
#include <freerdp/types.h>
#include <freerdp/constants.h>
#include <winpr/stream.h>
#include <freerdp/utils/list.h>
#include <freerdp/utils/svc_plugin.h>
#include "sample_main.h"

View File

@ -45,13 +45,13 @@
#include "serial_constants.h"
#include <winpr/crt.h>
#include <winpr/wlog.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <winpr/collections.h>
#include <freerdp/freerdp.h>
#include <freerdp/utils/list.h>
#include <freerdp/channels/rdpdr.h>
#include <freerdp/utils/svc_plugin.h>
@ -64,39 +64,27 @@ struct _SERIAL_DEVICE
char* path;
SERIAL_TTY* tty;
wLog* log;
HANDLE thread;
HANDLE mthread;
HANDLE stopEvent;
HANDLE newEvent;
wQueue* queue;
LIST* pending_irps;
fd_set read_fds;
fd_set write_fds;
UINT32 nfds;
struct timeval tv;
UINT32 select_timeout;
UINT32 timeout_id;
wMessageQueue* IrpQueue;
};
static void serial_abort_single_io(SERIAL_DEVICE* serial, UINT32 file_id, UINT32 abort_io, UINT32 io_status);
static void serial_check_for_events(SERIAL_DEVICE* serial);
static void serial_handle_async_irp(SERIAL_DEVICE* serial, IRP* irp);
static BOOL serial_check_fds(SERIAL_DEVICE* serial);
static void* serial_thread_mfunc(void* arg);
static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
{
char* path = NULL;
int status;
SERIAL_TTY* tty;
UINT32 PathLength;
UINT32 FileId;
UINT32 PathLength;
char* path = NULL;
SERIAL_TTY* tty;
Stream_Seek(irp->input, 28); /* DesiredAccess(4) AllocationSize(8), FileAttributes(4) */
/* SharedAccess(4) CreateDisposition(4), CreateOptions(4) */
Stream_Read_UINT32(irp->input, PathLength);
Stream_Seek_UINT32(irp->input); /* DesiredAccess (4 bytes) */
Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */
Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */
Stream_Seek_UINT32(irp->input); /* SharedAccess (4 bytes) */
Stream_Seek_UINT32(irp->input); /* CreateDisposition (4 bytes) */
Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */
Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */
status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(irp->input),
PathLength / 2, &path, 0, NULL, NULL);
@ -108,7 +96,7 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
tty = serial_tty_new(serial->path, FileId);
if (tty == NULL)
if (!tty)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
FileId = 0;
@ -118,23 +106,11 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
else
{
serial->tty = tty;
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_NONE,
STATUS_CANCELLED);
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_READ,
STATUS_CANCELLED);
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_WRITE,
STATUS_CANCELLED);
serial->mthread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) serial_thread_mfunc, (void*) serial,
0, NULL);
DEBUG_SVC("%s(%d) created.", serial->path, FileId);
}
Stream_Write_UINT32(irp->output, FileId);
Stream_Write_UINT8(irp->output, 0);
Stream_Write_UINT32(irp->output, FileId); /* FileId (4 bytes) */
Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */
free(path);
@ -143,11 +119,11 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
{
SERIAL_TTY* tty;
SERIAL_TTY* tty = serial->tty;
tty = serial->tty;
Stream_Seek(irp->input, 32); /* Padding (32 bytes) */
if (tty == NULL)
if (!tty)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
DEBUG_WARN("tty not valid.");
@ -156,35 +132,27 @@ static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
{
DEBUG_SVC("%s(%d) closed.", serial->path, tty->id);
TerminateThread(serial->mthread, 0);
WaitForSingleObject(serial->mthread, INFINITE);
CloseHandle(serial->mthread);
serial->mthread = NULL;
serial_tty_free(tty);
serial->tty = NULL;
}
Stream_Zero(irp->output, 5); /* Padding(5) */
Stream_Zero(irp->output, 5); /* Padding (5 bytes) */
irp->Complete(irp);
}
static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
{
SERIAL_TTY* tty;
UINT32 Length;
UINT64 Offset;
BYTE* buffer = NULL;
SERIAL_TTY* tty = serial->tty;
Stream_Read_UINT32(irp->input, Length);
Stream_Read_UINT64(irp->input, Offset);
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
DEBUG_SVC("length %u offset %llu", Length, Offset);
tty = serial->tty;
if (tty == NULL)
if (!tty)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
Length = 0;
@ -210,7 +178,7 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
}
}
Stream_Write_UINT32(irp->output, Length);
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
if (Length > 0)
{
@ -225,59 +193,60 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
{
SERIAL_TTY* tty;
int status;
UINT32 Length;
UINT64 Offset;
SERIAL_TTY* tty = serial->tty;
Stream_Read_UINT32(irp->input, Length);
Stream_Read_UINT64(irp->input, Offset);
Stream_Seek(irp->input, 20); /* Padding */
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
DEBUG_SVC("length %u offset %llu", Length, Offset);
tty = serial->tty;
if (tty == NULL)
if (!tty)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
Length = 0;
DEBUG_WARN("tty not valid.");
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
irp->Complete(irp);
return;
}
else if (!serial_tty_write(tty, Stream_Pointer(irp->input), Length))
status = serial_tty_write(tty, Stream_Pointer(irp->input), Length);
if (status < 0)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
Length = 0;
DEBUG_WARN("write %s(%d) failed.", serial->path, tty->id);
}
else
{
DEBUG_SVC("write %llu-%llu to %s(%d).", Offset, Offset + Length, serial->path, tty->id);
printf("serial_tty_write failure: status: %d, errno: %d\n", status, errno);
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
irp->Complete(irp);
return;
}
Stream_Write_UINT32(irp->output, Length);
Stream_Write_UINT8(irp->output, 0); /* Padding */
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
irp->Complete(irp);
}
static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
{
SERIAL_TTY* tty;
UINT32 IoControlCode;
UINT32 InputBufferLength;
UINT32 OutputBufferLength;
UINT32 abort_io = SERIAL_ABORT_IO_NONE;
UINT32 abortIo = SERIAL_ABORT_IO_NONE;
SERIAL_TTY* tty = serial->tty;
DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps));
Stream_Read_UINT32(irp->input, InputBufferLength);
Stream_Read_UINT32(irp->input, OutputBufferLength);
Stream_Read_UINT32(irp->input, IoControlCode);
Stream_Seek(irp->input, 20); /* Padding */
tty = serial->tty;
Stream_Read_UINT32(irp->input, OutputBufferLength); /* OutputBufferLength (4 bytes) */
Stream_Read_UINT32(irp->input, InputBufferLength); /* InputBufferLength (4 bytes) */
Stream_Read_UINT32(irp->input, IoControlCode); /* IoControlCode (4 bytes) */
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
if (!tty)
{
@ -288,23 +257,16 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
}
else
{
irp->IoStatus = serial_tty_control(tty, IoControlCode, irp->input, irp->output, &abort_io);
irp->IoStatus = serial_tty_control(tty, IoControlCode, irp->input, irp->output, &abortIo);
}
if (abort_io & SERIAL_ABORT_IO_WRITE)
serial_abort_single_io(serial, tty->id, SERIAL_ABORT_IO_WRITE, STATUS_CANCELLED);
if (abort_io & SERIAL_ABORT_IO_READ)
serial_abort_single_io(serial, tty->id, SERIAL_ABORT_IO_READ, STATUS_CANCELLED);
if (irp->IoStatus == STATUS_PENDING)
list_enqueue(serial->pending_irps, irp);
else
irp->Complete(irp);
irp->Complete(irp);
}
static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
{
DEBUG_SVC("MajorFunction %u", irp->MajorFunction);
WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: 0x%04X MinorFunction: 0x%04X\n",
irp->MajorFunction, irp->MinorFunction);
switch (irp->MajorFunction)
{
@ -317,13 +279,11 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
break;
case IRP_MJ_READ:
serial_handle_async_irp(serial, irp);
//serial_process_irp_read(serial, irp);
serial_process_irp_read(serial, irp);
break;
case IRP_MJ_WRITE:
serial_handle_async_irp(serial, irp);
//serial_process_irp_write(serial, irp);
serial_process_irp_write(serial, irp);
break;
case IRP_MJ_DEVICE_CONTROL:
@ -336,74 +296,29 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
irp->Complete(irp);
break;
}
serial_check_for_events(serial);
}
/* This thread is used as a workaround for the missing serial event
* support in WaitForMultipleObjects.
* It monitors the terminal for events and posts it in a supported
* form that WaitForMultipleObjects can use it. */
void* serial_thread_mfunc(void* arg)
{
SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg;
assert(NULL != serial);
while(1)
{
int sl;
fd_set rd;
if(!serial->tty || serial->tty->fd <= 0)
{
DEBUG_WARN("Monitor thread still running, but no terminal opened!");
sleep(1);
}
else
{
FD_ZERO(&rd);
FD_SET(serial->tty->fd, &rd);
sl = select(serial->tty->fd + 1, &rd, NULL, NULL, NULL);
if( sl > 0 )
SetEvent(serial->newEvent);
}
}
ExitThread(0);
return NULL;
}
static void* serial_thread_func(void* arg)
{
IRP* irp;
DWORD status;
SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg;
HANDLE ev[] = {serial->stopEvent, Queue_Event(serial->queue), serial->newEvent};
wMessage message;
SERIAL_DEVICE* drive = (SERIAL_DEVICE*) arg;
assert(NULL != serial);
while (1)
{
status = WaitForMultipleObjects(3, ev, FALSE, INFINITE);
if (WAIT_OBJECT_0 == status)
if (!MessageQueue_Wait(drive->IrpQueue))
break;
else if (status == WAIT_OBJECT_0 + 1)
{
FD_ZERO(&serial->read_fds);
FD_ZERO(&serial->write_fds);
serial->tv.tv_sec = 0;
serial->tv.tv_usec = 0;
serial->select_timeout = 0;
if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE))
break;
if ((irp = (IRP*) Queue_Dequeue(serial->queue)))
serial_process_irp(serial, irp);
}
else if (status == WAIT_OBJECT_0 + 2)
ResetEvent(serial->newEvent);
if (message.id == WMQ_QUIT)
break;
if(serial->tty)
serial_check_fds(serial);
irp = (IRP*) message.wParam;
if (irp)
serial_process_irp(drive, irp);
}
ExitThread(0);
@ -413,366 +328,28 @@ static void* serial_thread_func(void* arg)
static void serial_irp_request(DEVICE* device, IRP* irp)
{
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
Queue_Enqueue(serial->queue, irp);
MessageQueue_Post(serial->IrpQueue, NULL, 0, (void*) irp, NULL);
}
static void serial_free(DEVICE* device)
{
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
DEBUG_SVC("freeing device");
WLog_Print(serial->log, WLOG_DEBUG, "freeing");
/* Stop thread */
SetEvent(serial->stopEvent);
if(serial->mthread)
{
TerminateThread(serial->mthread, 0);
WaitForSingleObject(serial->mthread, INFINITE);
CloseHandle(serial->mthread);
}
MessageQueue_PostQuit(serial->IrpQueue, 0);
WaitForSingleObject(serial->thread, INFINITE);
CloseHandle(serial->thread);
serial_tty_free(serial->tty);
/* Clean up resources */
Stream_Free(serial->device.data, TRUE);
Queue_Free(serial->queue);
list_free(serial->pending_irps);
CloseHandle(serial->stopEvent);
CloseHandle(serial->newEvent);
CloseHandle(serial->thread);
MessageQueue_Free(serial->IrpQueue);
free(serial);
}
static void serial_abort_single_io(SERIAL_DEVICE* serial, UINT32 file_id, UINT32 abort_io, UINT32 io_status)
{
UINT32 major;
IRP* irp = NULL;
SERIAL_TTY* tty;
DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps));
tty = serial->tty;
if(!tty)
{
DEBUG_WARN("tty = %p", tty);
return;
}
switch (abort_io)
{
case SERIAL_ABORT_IO_NONE:
major = 0;
break;
case SERIAL_ABORT_IO_READ:
major = IRP_MJ_READ;
break;
case SERIAL_ABORT_IO_WRITE:
major = IRP_MJ_WRITE;
break;
default:
DEBUG_SVC("unexpected abort_io code %d", abort_io);
return;
}
irp = (IRP*) list_peek(serial->pending_irps);
while (irp)
{
if (irp->FileId != file_id || irp->MajorFunction != major)
{
irp = (IRP*) list_next(serial->pending_irps, irp);
continue;
}
/* Process a SINGLE FileId and MajorFunction */
list_remove(serial->pending_irps, irp);
irp->IoStatus = io_status;
Stream_Write_UINT32(irp->output, 0);
irp->Complete(irp);
break;
}
DEBUG_SVC("[out] pending size %d", list_size(serial->pending_irps));
}
static void serial_check_for_events(SERIAL_DEVICE* serial)
{
IRP* irp = NULL;
IRP* prev;
UINT32 result = 0;
SERIAL_TTY* tty;
tty = serial->tty;
if(!tty)
{
DEBUG_WARN("tty = %p", tty);
return;
}
DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps));
irp = (IRP*) list_peek(serial->pending_irps);
while (irp)
{
prev = NULL;
if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
{
if (serial_tty_get_event(tty, &result))
{
DEBUG_SVC("got event result %u", result);
irp->IoStatus = STATUS_SUCCESS;
Stream_Write_UINT32(irp->output, result);
irp->Complete(irp);
prev = irp;
irp = (IRP*) list_next(serial->pending_irps, irp);
list_remove(serial->pending_irps, prev);
}
}
if (!prev)
irp = (IRP*) list_next(serial->pending_irps, irp);
}
DEBUG_SVC("[out] pending size %d", list_size(serial->pending_irps));
}
void serial_get_timeouts(SERIAL_DEVICE* serial, IRP* irp, UINT32* timeout, UINT32* interval_timeout)
{
SERIAL_TTY* tty;
UINT32 Length;
UINT32 pos;
pos = Stream_GetPosition(irp->input);
Stream_Read_UINT32(irp->input, Length);
Stream_SetPosition(irp->input, pos);
DEBUG_SVC("length read %u", Length);
tty = serial->tty;
if(!tty)
{
DEBUG_WARN("tty = %p", tty);
return;
}
*timeout = (tty->read_total_timeout_multiplier * Length) + tty->read_total_timeout_constant;
*interval_timeout = tty->read_interval_timeout;
DEBUG_SVC("timeouts %u %u", *timeout, *interval_timeout);
}
static void serial_handle_async_irp(SERIAL_DEVICE* serial, IRP* irp)
{
UINT32 timeout = 0;
UINT32 itv_timeout = 0;
SERIAL_TTY* tty;
tty = serial->tty;
if(!tty)
{
DEBUG_WARN("tty = %p", tty);
return;
}
switch (irp->MajorFunction)
{
case IRP_MJ_WRITE:
DEBUG_SVC("handling IRP_MJ_WRITE");
break;
case IRP_MJ_READ:
DEBUG_SVC("handling IRP_MJ_READ");
serial_get_timeouts(serial, irp, &timeout, &itv_timeout);
/* Check if io request timeout is smaller than current (but not 0). */
if (timeout && ((serial->select_timeout == 0) || (timeout < serial->select_timeout)))
{
serial->select_timeout = timeout;
serial->tv.tv_sec = serial->select_timeout / 1000;
serial->tv.tv_usec = (serial->select_timeout % 1000) * 1000;
serial->timeout_id = tty->id;
}
if (itv_timeout && ((serial->select_timeout == 0) || (itv_timeout < serial->select_timeout)))
{
serial->select_timeout = itv_timeout;
serial->tv.tv_sec = serial->select_timeout / 1000;
serial->tv.tv_usec = (serial->select_timeout % 1000) * 1000;
serial->timeout_id = tty->id;
}
DEBUG_SVC("select_timeout %u, tv_sec %lu tv_usec %lu, timeout_id %u",
serial->select_timeout, serial->tv.tv_sec, serial->tv.tv_usec, serial->timeout_id);
break;
default:
DEBUG_SVC("no need to handle %d", irp->MajorFunction);
return;
}
irp->IoStatus = STATUS_PENDING;
list_enqueue(serial->pending_irps, irp);
}
static void __serial_check_fds(SERIAL_DEVICE* serial)
{
IRP* irp;
IRP* prev;
SERIAL_TTY* tty;
UINT32 result = 0;
BOOL irp_completed = FALSE;
ZeroMemory(&serial->tv, sizeof(struct timeval));
tty = serial->tty;
if(!tty)
{
DEBUG_WARN("tty = %p", tty);
return;
}
/* scan every pending */
irp = list_peek(serial->pending_irps);
while (irp)
{
DEBUG_SVC("MajorFunction %u", irp->MajorFunction);
switch (irp->MajorFunction)
{
case IRP_MJ_READ:
if (FD_ISSET(tty->fd, &serial->read_fds))
{
irp->IoStatus = STATUS_SUCCESS;
serial_process_irp_read(serial, irp);
irp_completed = TRUE;
}
break;
case IRP_MJ_WRITE:
if (FD_ISSET(tty->fd, &serial->write_fds))
{
irp->IoStatus = STATUS_SUCCESS;
serial_process_irp_write(serial, irp);
irp_completed = TRUE;
}
break;
case IRP_MJ_DEVICE_CONTROL:
if (serial_tty_get_event(tty, &result))
{
DEBUG_SVC("got event result %u", result);
irp->IoStatus = STATUS_SUCCESS;
Stream_Write_UINT32(irp->output, result);
irp->Complete(irp);
irp_completed = TRUE;
}
break;
default:
DEBUG_SVC("no request found");
break;
}
prev = irp;
irp = (IRP*) list_next(serial->pending_irps, irp);
if (irp_completed || (prev->IoStatus == STATUS_SUCCESS))
list_remove(serial->pending_irps, prev);
}
}
static void serial_set_fds(SERIAL_DEVICE* serial)
{
IRP* irp;
fd_set* fds;
SERIAL_TTY* tty;
DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps));
tty = serial->tty;
if(!tty)
{
DEBUG_WARN("tty = %p", tty);
return;
}
irp = (IRP*) list_peek(serial->pending_irps);
while (irp)
{
fds = NULL;
switch (irp->MajorFunction)
{
case IRP_MJ_WRITE:
fds = &serial->write_fds;
break;
case IRP_MJ_READ:
fds = &serial->read_fds;
break;
}
if (fds && (tty->fd >= 0))
{
FD_SET(tty->fd, fds);
serial->nfds = MAX(serial->nfds, tty->fd);
}
irp = (IRP*) list_next(serial->pending_irps, irp);
}
}
static BOOL serial_check_fds(SERIAL_DEVICE* serial)
{
if (list_size(serial->pending_irps) == 0)
return 1;
FD_ZERO(&serial->read_fds);
FD_ZERO(&serial->write_fds);
serial->tv.tv_sec = 0;
serial->tv.tv_usec = 0;
serial->select_timeout = 0;
serial_set_fds(serial);
DEBUG_SVC("waiting %lu %lu", serial->tv.tv_sec, serial->tv.tv_usec);
switch (select(serial->nfds + 1, &serial->read_fds, &serial->write_fds, NULL, &serial->tv))
{
case -1:
DEBUG_SVC("select has returned -1 with error: %s", strerror(errno));
return 0;
case 0:
if (serial->select_timeout)
{
__serial_check_fds(serial);
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_NONE, STATUS_TIMEOUT);
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_READ, STATUS_TIMEOUT);
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_WRITE, STATUS_TIMEOUT);
}
DEBUG_SVC("select has timed out");
return 0;
default:
break;
}
__serial_check_fds(serial);
return 1;
}
#ifdef STATIC_CHANNELS
#define DeviceServiceEntry serial_DeviceServiceEntry
#endif
@ -789,10 +366,18 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
name = device->Name;
path = device->Path;
if (!name || (name[0] == '*'))
{
/* TODO: implement auto detection of parallel ports */
return 0;
}
if ((name && name[0]) && (path && path[0]))
{
serial = (SERIAL_DEVICE*) malloc(sizeof(SERIAL_DEVICE));
ZeroMemory(serial, sizeof(SERIAL_DEVICE));
serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE));
if (!serial)
return -1;
serial->device.type = RDPDR_DTYP_SERIAL;
serial->device.name = name;
@ -806,17 +391,16 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]);
serial->path = path;
serial->queue = Queue_New(TRUE, -1, -1);
serial->pending_irps = list_new();
serial->IrpQueue = MessageQueue_New(NULL);
serial->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
serial->newEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
WLog_Init();
serial->log = WLog_Get("com.freerdp.channel.serial.client");
WLog_Print(serial->log, WLOG_DEBUG, "initializing");
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial);
serial->thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL);
serial->mthread = NULL;
}
return 0;

View File

@ -28,9 +28,8 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/stream.h>
#include <freerdp/utils/list.h>
#include <freerdp/utils/svc_plugin.h>
#include <freerdp/channels/rdpdr.h>
@ -73,24 +72,47 @@
#define TIOCOUTQ FIONWRITE
#endif
/**
* Refer to ReactOS's ntddser.h (public domain) for constant definitions
*/
static UINT32 tty_write_data(SERIAL_TTY* tty, BYTE* data, int len);
static void tty_set_termios(SERIAL_TTY* tty);
static BOOL tty_get_termios(SERIAL_TTY* tty);
static int tty_get_error_status();
UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input, wStream* output, UINT32* abort_io)
UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input, wStream* output, UINT32* abortIo)
{
int purge_mask;
UINT32 result;
UINT32 modemstate;
BYTE immediate;
UINT32 ret = STATUS_SUCCESS;
UINT32 length = 0;
UINT32 pos;
int purge_mask;
UINT32 modemstate;
UINT32 begPos, endPos;
UINT32 OutputBufferLength;
UINT32 status = STATUS_SUCCESS;
UINT32 IoCtlDeviceType;
UINT32 IoCtlFunction;
UINT32 IoCtlMethod;
UINT32 IoCtlAccess;
DEBUG_SVC("in");
IoCtlMethod = (IoControlCode & 0x3);
IoCtlFunction = ((IoControlCode >> 2) & 0xFFF);
IoCtlAccess = ((IoControlCode >> 14) & 0x3);
IoCtlDeviceType = ((IoControlCode >> 16) & 0xFFFF);
Stream_Seek(output, sizeof(UINT32));
/**
* FILE_DEVICE_SERIAL_PORT 0x0000001B
* FILE_DEVICE_UNKNOWN 0x00000022
*/
if (IoCtlDeviceType == 0x00000022)
{
IoControlCode &= 0xFFFF;
IoControlCode |= (0x0000001B << 16);
}
Stream_Seek_UINT32(output); /* OutputBufferLength (4 bytes) */
begPos = (UINT32) Stream_GetPosition(output);
switch (IoControlCode)
{
@ -101,7 +123,7 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
break;
case IOCTL_SERIAL_GET_BAUD_RATE:
length = 4;
OutputBufferLength = 4;
Stream_Write_UINT32(output, tty->baud_rate);
DEBUG_SVC("SERIAL_GET_BAUD_RATE %d", tty->baud_rate);
break;
@ -123,7 +145,7 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
case IOCTL_SERIAL_GET_LINE_CONTROL:
DEBUG_SVC("SERIAL_GET_LINE_CONTROL");
length = 3;
OutputBufferLength = 3;
Stream_Write_UINT8(output, tty->stop_bits);
Stream_Write_UINT8(output, tty->parity);
Stream_Write_UINT8(output, tty->word_length);
@ -137,13 +159,13 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
case IOCTL_SERIAL_CONFIG_SIZE:
DEBUG_SVC("SERIAL_CONFIG_SIZE");
length = 4;
OutputBufferLength = 4;
Stream_Write_UINT32(output, 0);
break;
case IOCTL_SERIAL_GET_CHARS:
DEBUG_SVC("SERIAL_GET_CHARS");
length = 6;
OutputBufferLength = 6;
Stream_Write(output, tty->chars, 6);
break;
@ -154,7 +176,7 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
break;
case IOCTL_SERIAL_GET_HANDFLOW:
length = 16;
OutputBufferLength = 16;
tty_get_termios(tty);
Stream_Write_UINT32(output, tty->control);
Stream_Write_UINT32(output, tty->xonoff);
@ -200,7 +222,7 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
tty->read_interval_timeout,
tty->read_total_timeout_multiplier,
tty->read_total_timeout_constant);
length = 20;
OutputBufferLength = 20;
Stream_Write_UINT32(output, tty->read_interval_timeout);
Stream_Write_UINT32(output, tty->read_total_timeout_multiplier);
Stream_Write_UINT32(output, tty->read_total_timeout_constant);
@ -210,7 +232,7 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
case IOCTL_SERIAL_GET_WAIT_MASK:
DEBUG_SVC("SERIAL_GET_WAIT_MASK %X", tty->wait_mask);
length = 4;
OutputBufferLength = 4;
Stream_Write_UINT32(output, tty->wait_mask);
break;
@ -269,12 +291,12 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
modemstate |= SERIAL_MS_RTS;
#endif
DEBUG_SVC("SERIAL_GET_MODEMSTATUS %X", modemstate);
length = 4;
OutputBufferLength = 4;
Stream_Write_UINT32(output, modemstate);
break;
case IOCTL_SERIAL_GET_COMMSTATUS:
length = 18;
OutputBufferLength = 18;
Stream_Write_UINT32(output, 0); /* Errors */
Stream_Write_UINT32(output, 0); /* Hold reasons */
@ -316,21 +338,21 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
#endif
if (purge_mask & SERIAL_PURGE_TXABORT)
*abort_io |= SERIAL_ABORT_IO_WRITE;
*abortIo |= SERIAL_ABORT_IO_WRITE;
if (purge_mask & SERIAL_PURGE_RXABORT)
*abort_io |= SERIAL_ABORT_IO_READ;
*abortIo |= SERIAL_ABORT_IO_READ;
break;
case IOCTL_SERIAL_WAIT_ON_MASK:
DEBUG_SVC("SERIAL_WAIT_ON_MASK %X", tty->wait_mask);
tty->event_pending = 1;
length = 4;
OutputBufferLength = 4;
if (serial_tty_get_event(tty, &result))
{
DEBUG_SVC("WAIT end event = %X", result);
Stream_Write_UINT32(output, result);
break;
}
ret = STATUS_PENDING;
status = STATUS_PENDING;
break;
case IOCTL_SERIAL_SET_BREAK_ON:
@ -356,27 +378,33 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
break;
default:
DEBUG_SVC("NOT FOUND IoControlCode SERIAL IOCTL %d", IoControlCode);
DEBUG_SVC("NOT FOUND IoControlCode SERIAL IOCTL 0x%08X", IoControlCode);
return STATUS_INVALID_PARAMETER;
}
/* Write OutputBufferLength */
pos = Stream_GetPosition(output);
Stream_SetPosition(output, 16);
Stream_Write_UINT32(output, length);
Stream_SetPosition(output, pos);
endPos = (UINT32) Stream_GetPosition(output);
OutputBufferLength = endPos - begPos;
return ret;
if (OutputBufferLength < 1)
{
Stream_Write_UINT8(output, 0); /* Padding (1 byte) */
endPos = (UINT32) Stream_GetPosition(output);
OutputBufferLength = endPos - begPos;
}
Stream_SealLength(output);
Stream_SetPosition(output, 16);
Stream_Write_UINT32(output, OutputBufferLength); /* OutputBufferLength (4 bytes) */
Stream_SetPosition(output, endPos);
return status;
}
BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length)
{
ssize_t status;
long timeout = 90;
struct termios* ptermios;
DEBUG_SVC("in");
ptermios = tty->ptermios;
/* Set timeouts kind of like the windows serial timeout parameters. Multiply timeout
with requested read size */
@ -391,21 +419,38 @@ BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length)
timeout = (tty->read_interval_timeout * (*Length) + 99) / 100;
}
/* If a timeout is set, do a blocking read, which times out after some time.
It will make FreeRDP less responsive, but it will improve serial performance,
by not reading one character at a time. */
if (timeout == 0)
{
ptermios->c_cc[VTIME] = 0;
ptermios->c_cc[VMIN] = 0;
}
else
{
ptermios->c_cc[VTIME] = timeout;
ptermios->c_cc[VMIN] = 1;
}
if (tty->timeout != timeout)
{
struct termios* ptermios;
tcsetattr(tty->fd, TCSANOW, ptermios);
ptermios = (struct termios*) calloc(1, sizeof(struct termios));
if (tcgetattr(tty->fd, ptermios) < 0) {
free(ptermios);
return FALSE;
}
/**
* If a timeout is set, do a blocking read, which times out after some time.
* It will make FreeRDP less responsive, but it will improve serial performance,
* by not reading one character at a time.
*/
if (timeout == 0)
{
ptermios->c_cc[VTIME] = 0;
ptermios->c_cc[VMIN] = 0;
}
else
{
ptermios->c_cc[VTIME] = timeout;
ptermios->c_cc[VMIN] = 1;
}
tcsetattr(tty->fd, TCSANOW, ptermios);
tty->timeout = timeout;
free(ptermios);
}
ZeroMemory(buffer, *Length);
@ -424,20 +469,21 @@ BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length)
return TRUE;
}
BOOL serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length)
int serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length)
{
ssize_t status;
ssize_t status = 0;
UINT32 event_txempty = Length;
DEBUG_SVC("in");
while (Length > 0)
{
status = write(tty->fd, buffer, Length);
if (status < 0)
{
return FALSE;
if (errno == EAGAIN)
status = 0;
else
return status;
}
Length -= status;
@ -446,7 +492,7 @@ BOOL serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length)
tty->event_txempty = event_txempty;
return TRUE;
return status;
}
/**
@ -458,9 +504,7 @@ BOOL serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length)
*/
void serial_tty_free(SERIAL_TTY* tty)
{
DEBUG_SVC("in");
if(!tty)
if (!tty)
return;
if (tty->fd >= 0)
@ -480,8 +524,10 @@ SERIAL_TTY* serial_tty_new(const char* path, UINT32 id)
{
SERIAL_TTY* tty;
tty = (SERIAL_TTY*) malloc(sizeof(SERIAL_TTY));
ZeroMemory(tty, sizeof(SERIAL_TTY));
tty = (SERIAL_TTY*) calloc(1, sizeof(SERIAL_TTY));
if (!tty)
return NULL;
tty->id = id;
tty->fd = open(path, O_RDWR | O_NOCTTY | O_NONBLOCK);
@ -498,19 +544,17 @@ SERIAL_TTY* serial_tty_new(const char* path, UINT32 id)
DEBUG_SVC("tty fd %d successfully opened", tty->fd);
}
tty->ptermios = (struct termios*) malloc(sizeof(struct termios));
ZeroMemory(tty->ptermios, sizeof(struct termios));
tty->ptermios = (struct termios*) calloc(1, sizeof(struct termios));
if (tty->ptermios == NULL)
if (!tty->ptermios)
{
serial_tty_free(tty);
return NULL ;
return NULL;
}
tty->pold_termios = (struct termios*) malloc(sizeof(struct termios));
ZeroMemory(tty->pold_termios, sizeof(struct termios));
tty->pold_termios = (struct termios*) calloc(1, sizeof(struct termios));
if (tty->pold_termios == NULL)
if (!tty->pold_termios)
{
serial_tty_free(tty);
return NULL;
@ -526,11 +570,14 @@ SERIAL_TTY* serial_tty_new(const char* path, UINT32 id)
}
tty->ptermios->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty->ptermios->c_iflag = IGNPAR | ICRNL;
tty->ptermios->c_oflag &= ~OPOST;
tty->ptermios->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty->ptermios->c_cflag &= ~(CSIZE | PARENB);
tty->ptermios->c_cflag |= CLOCAL | CREAD | CS8;
tty->ptermios->c_cflag |= CS8;
tty->ptermios->c_iflag = IGNPAR;
tty->ptermios->c_cflag |= CLOCAL | CREAD;
tcsetattr(tty->fd, TCSANOW, tty->ptermios);
tty->event_txempty = 0;
@ -558,8 +605,6 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result)
int bytes;
BOOL status = FALSE;
DEBUG_SVC("in");
*result = 0;
#ifdef TIOCINQ
@ -587,7 +632,6 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result)
*result |= SERIAL_EV_RLSD;
status = TRUE;
}
}
if ((bytes > 1) && (tty->wait_mask & SERIAL_EV_RXFLAG))
@ -603,7 +647,6 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result)
*result |= SERIAL_EV_RXCHAR;
status = TRUE;
}
}
else
{
@ -802,16 +845,18 @@ static BOOL tty_get_termios(SERIAL_TTY* tty)
tty->chars[SERIAL_CHAR_BREAK] = ptermios->c_cc[VINTR];
tty->chars[SERIAL_CHAR_ERROR] = ptermios->c_cc[VKILL];
tty->timeout = ptermios->c_cc[VTIME];
return TRUE;
}
static void tty_set_termios(SERIAL_TTY* tty)
{
speed_t speed;
struct termios *ptermios;
struct termios* ptermios;
DEBUG_SVC("in");
ptermios = tty->ptermios;
switch (tty->baud_rate)
{
#ifdef B75
@ -1003,8 +1048,6 @@ static UINT32 tty_write_data(SERIAL_TTY* tty, BYTE* data, int len)
{
ssize_t status;
DEBUG_SVC("in");
status = write(tty->fd, data, len);
if (status < 0)
@ -1017,8 +1060,6 @@ static UINT32 tty_write_data(SERIAL_TTY* tty, BYTE* data, int len)
static int tty_get_error_status()
{
DEBUG_SVC("in errno %d", errno);
switch (errno)
{
case EACCES:

View File

@ -65,13 +65,14 @@ struct _SERIAL_TTY
int event_dsr;
int event_rlsd;
int event_pending;
long timeout;
};
SERIAL_TTY* serial_tty_new(const char* path, UINT32 id);
void serial_tty_free(SERIAL_TTY* tty);
BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length);
BOOL serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length);
int serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length);
UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input, wStream* output, UINT32* abort_io);
BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result);

View File

@ -40,7 +40,7 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-crt winpr-synch winpr-interlocked winpr-error)
MODULES winpr-crt winpr-synch winpr-interlocked winpr-error winpr-wtsapi)
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} PARENT_SCOPE)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)

View File

@ -1,13 +1,8 @@
set(OPTION_DEFAULT OFF)
set(OPTION_CLIENT_DEFAULT OFF)
set(OPTION_CLIENT_DEFAULT ON)
set(OPTION_SERVER_DEFAULT OFF)
if(WITH_PCSC)
set(OPTION_CLIENT_DEFAULT ON)
set(OPTION_SERVER_DEFAULT OFF)
endif()
define_channel_options(NAME "smartcard" TYPE "device"
DESCRIPTION "Smart Card Virtual Channel Extension"
SPECIFICATIONS "[MS-RDPESC]"

View File

@ -20,11 +20,11 @@ define_channel_client("smartcard")
set(${MODULE_PREFIX}_SRCS
smartcard_main.c
smartcard_main.h
smartcard_pack.c
smartcard_pack.h
smartcard_operations.c)
include_directories(${PCSC_INCLUDE_DIR})
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry")
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DeviceServiceEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
@ -36,13 +36,7 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-crt winpr-synch winpr-thread winpr-interlocked)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${PCSC_LIBRARIES})
if(WIN32)
list(APPEND ${MODULE_PREFIX}_LIBS winscard)
endif()
MODULES winpr-crt winpr-smartcard winpr-synch winpr-thread winpr-interlocked winpr-utils)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -28,306 +28,208 @@
#include <string.h>
#include <winpr/crt.h>
#include <freerdp/utils/list.h>
#include <freerdp/utils/debug.h>
#include <winpr/smartcard.h>
#include <freerdp/channels/rdpdr.h>
#include "smartcard_main.h"
static void smartcard_free(DEVICE* dev)
{
IRP* irp;
COMPLETIONIDINFO* CompletionIdInfo;
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) dev;
#define SMARTCARD_ASYNC_IRP 1
SetEvent(smartcard->stopEvent);
static void smartcard_free(DEVICE* device)
{
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) device;
MessageQueue_PostQuit(smartcard->IrpQueue, 0);
WaitForSingleObject(smartcard->thread, INFINITE);
while ((irp = (IRP*) InterlockedPopEntrySList(smartcard->pIrpList)) != NULL)
irp->Discard(irp);
_aligned_free(smartcard->pIrpList);
/* Begin TS Client defect workaround. */
while ((CompletionIdInfo = (COMPLETIONIDINFO*) list_dequeue(smartcard->CompletionIds)) != NULL)
free(CompletionIdInfo);
CloseHandle(smartcard->thread);
CloseHandle(smartcard->irpEvent);
CloseHandle(smartcard->stopEvent);
CloseHandle(smartcard->CompletionIdsMutex);
Stream_Free(smartcard->device.data, TRUE);
list_free(smartcard->CompletionIds);
/* End TS Client defect workaround. */
MessageQueue_Free(smartcard->IrpQueue);
ListDictionary_Free(smartcard->OutstandingIrps);
free(dev);
free(device);
}
static void smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
{
switch (irp->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL:
smartcard_device_control(smartcard, irp);
break;
/**
* Initialization occurs when the protocol server sends a device announce message.
* At that time, we need to cancel all outstanding IRPs.
*/
default:
fprintf(stderr, "MajorFunction 0x%X unexpected for smartcards.", irp->MajorFunction);
DEBUG_WARN("Smartcard MajorFunction 0x%X not supported.", irp->MajorFunction);
irp->IoStatus = STATUS_NOT_SUPPORTED;
irp->Complete(irp);
break;
}
}
static void smartcard_process_irp_list(SMARTCARD_DEVICE* smartcard)
static void smartcard_init(DEVICE* device)
{
IRP* irp;
int index;
int keyCount;
ULONG_PTR* pKeys;
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) device;
while (1)
if (ListDictionary_Count(smartcard->OutstandingIrps) > 0)
{
if (WaitForSingleObject(smartcard->stopEvent, 0) == WAIT_OBJECT_0)
break;
pKeys = NULL;
keyCount = ListDictionary_GetKeys(smartcard->OutstandingIrps, &pKeys);
irp = (IRP*) InterlockedPopEntrySList(smartcard->pIrpList);
for (index = 0; index < keyCount; index++)
{
irp = (IRP*) ListDictionary_GetItemValue(smartcard->OutstandingIrps, (void*) pKeys[index]);
if (irp == NULL)
break;
if (irp)
irp->cancelled = TRUE;
}
smartcard_process_irp(smartcard, irp);
free(pKeys);
}
}
struct _SMARTCARD_IRP_WORKER
void smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
{
void* key;
key = (void*) (size_t) irp->CompletionId;
ListDictionary_Remove(smartcard->OutstandingIrps, key);
if (!irp->cancelled)
irp->Complete(irp);
else
irp->Discard(irp);
}
void* smartcard_process_irp_worker_proc(IRP* irp)
{
SMARTCARD_DEVICE* smartcard;
IRP* irp;
HANDLE thread;
};
typedef struct _SMARTCARD_IRP_WORKER SMARTCARD_IRP_WORKER;
static void *smartcard_process_irp_thread_func(SMARTCARD_IRP_WORKER* irpWorker)
{
smartcard_process_irp(irpWorker->smartcard, irpWorker->irp);
CloseHandle(irpWorker->thread);
smartcard = (SMARTCARD_DEVICE*) irp->device;
free(irpWorker);
smartcard_irp_device_control(smartcard, irp);
ExitThread(0);
return NULL;
}
/**
* Multiple threads and SCardGetStatusChange:
* http://musclecard.996296.n3.nabble.com/Multiple-threads-and-SCardGetStatusChange-td4430.html
*/
void smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
{
void* key;
BOOL asyncIrp = FALSE;
UINT32 ioControlCode = 0;
key = (void*) (size_t) irp->CompletionId;
ListDictionary_Add(smartcard->OutstandingIrps, key, irp);
if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
{
smartcard_irp_device_control_peek_io_control_code(smartcard, irp, &ioControlCode);
if (!ioControlCode)
return;
#ifdef SMARTCARD_ASYNC_IRP
asyncIrp = TRUE;
switch (ioControlCode)
{
case SCARD_IOCTL_ESTABLISHCONTEXT:
case SCARD_IOCTL_RELEASECONTEXT:
case SCARD_IOCTL_ISVALIDCONTEXT:
case SCARD_IOCTL_ACCESSSTARTEDEVENT:
case SCARD_IOCTL_RELEASESTARTEDEVENT:
asyncIrp = FALSE;
break;
case SCARD_IOCTL_TRANSMIT:
case SCARD_IOCTL_STATUSA:
case SCARD_IOCTL_STATUSW:
case SCARD_IOCTL_GETSTATUSCHANGEA:
case SCARD_IOCTL_GETSTATUSCHANGEW:
asyncIrp = TRUE;
break;
}
#endif
if (!asyncIrp)
{
smartcard_irp_device_control(smartcard, irp);
}
else
{
irp->thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) smartcard_process_irp_worker_proc,
irp, 0, NULL);
}
}
else
{
fprintf(stderr, "Unexpected SmartCard IRP: MajorFunction 0x%08X MinorFunction: 0x%08X",
irp->MajorFunction, irp->MinorFunction);
irp->IoStatus = STATUS_NOT_SUPPORTED;
smartcard_complete_irp(smartcard, irp);
}
}
static void* smartcard_thread_func(void* arg)
{
IRP* irp;
wMessage message;
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) arg;
HANDLE ev[] = {smartcard->irpEvent, smartcard->stopEvent};
while (1)
{
DWORD status = WaitForMultipleObjects(2, ev, FALSE, INFINITE);
if (status == WAIT_OBJECT_0 + 1)
if (!MessageQueue_Wait(smartcard->IrpQueue))
break;
else if(status != WAIT_OBJECT_0)
continue;
ResetEvent(smartcard->irpEvent);
smartcard_process_irp_list(smartcard);
if (!MessageQueue_Peek(smartcard->IrpQueue, &message, TRUE))
break;
if (message.id == WMQ_QUIT)
break;
irp = (IRP*) message.wParam;
if (irp)
smartcard_process_irp(smartcard, irp);
}
ExitThread(0);
return NULL;
}
/* Begin TS Client defect workaround. */
static COMPLETIONIDINFO* smartcard_mark_duplicate_id(SMARTCARD_DEVICE* smartcard, UINT32 CompletionId)
{
LIST_ITEM* item;
COMPLETIONIDINFO* CompletionIdInfo;
/*
* Search from the beginning of the LIST for one outstanding "CompletionID"
* that matches the one passed in. If there is one, mark it as a duplicate
* if it is not already marked.
*/
for (item = smartcard->CompletionIds->head; item; item = item->next)
{
CompletionIdInfo = (COMPLETIONIDINFO*) item->data;
if (CompletionIdInfo->ID == CompletionId)
{
if (!CompletionIdInfo->duplicate)
{
CompletionIdInfo->duplicate = TRUE;
DEBUG_WARN("CompletionID number %u is now marked as a duplicate.", CompletionId);
}
return CompletionIdInfo;
}
}
return NULL; /* Either no items in the list or no match. */
}
static BOOL smartcard_check_for_duplicate_id(SMARTCARD_DEVICE* smartcard, UINT32 CompletionId)
{
BOOL duplicate;
LIST_ITEM* item;
COMPLETIONIDINFO* CompletionIdInfo;
/*
* Search from the end of the LIST for one outstanding "CompletionID"
* that matches the one passed in. Remove it from the list and free the
* memory associated with it. Return whether or not it was marked
* as a duplicate.
*/
for (item = smartcard->CompletionIds->tail; item; item = item->prev)
{
CompletionIdInfo = (COMPLETIONIDINFO*) item->data;
if (CompletionIdInfo->ID == CompletionId)
{
duplicate = CompletionIdInfo->duplicate;
if (duplicate)
{
DEBUG_WARN("CompletionID number %u was previously marked as a duplicate.", CompletionId);
}
list_remove(smartcard->CompletionIds, CompletionIdInfo);
free(CompletionIdInfo);
return duplicate;
}
}
/* This function should only be called when there is
* at least one outstanding CompletionID item in the list.
*/
DEBUG_WARN("Error!!! No CompletionIDs (or no matching IDs) in the list!");
return FALSE;
}
static void smartcard_irp_complete(IRP* irp)
{
int pos;
BOOL duplicate;
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) irp->device;
/* This function is (mostly) a copy of the statically-declared "irp_complete()"
* function except that this function adds extra operations for the
* smart card's handling of duplicate "CompletionID"s. This function needs
* to be in this file so that "smartcard_irp_request()" can reference it.
*/
DEBUG_SCARD("DeviceId %d FileId %d CompletionId %d", irp->device->id, irp->FileId, irp->CompletionId);
pos = Stream_GetPosition(irp->output);
Stream_SetPosition(irp->output, 12);
Stream_Write_UINT32(irp->output, irp->IoStatus);
Stream_SetPosition(irp->output, pos);
/* Begin TS Client defect workaround. */
WaitForSingleObject(smartcard->CompletionIdsMutex, INFINITE);
/* Remove from the list the item identified by the CompletionID.
* The function returns whether or not it was a duplicate CompletionID.
*/
duplicate = smartcard_check_for_duplicate_id(smartcard, irp->CompletionId);
ReleaseMutex(smartcard->CompletionIdsMutex);
if (!duplicate)
{
irp->Complete(irp);
}
/* End TS Client defect workaround. */
/* irp_free(irp); The "irp_free()" function is statically-declared
* and so is not available to be called
* here. Instead, call it indirectly by calling
* the IRP's "Discard()" function,
* which has already been assigned
* to point to "irp_free()" in "irp_new()".
*/
irp->Discard(irp);
}
/* End TS Client defect workaround. */
static void smartcard_irp_request(DEVICE* device, IRP* irp)
{
COMPLETIONIDINFO* CompletionIdInfo;
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) device;
/* Begin TS Client defect workaround. */
CompletionIdInfo = (COMPLETIONIDINFO*) malloc(sizeof(COMPLETIONIDINFO));
ZeroMemory(CompletionIdInfo, sizeof(COMPLETIONIDINFO));
CompletionIdInfo->ID = irp->CompletionId;
WaitForSingleObject(smartcard->CompletionIdsMutex, INFINITE);
smartcard_mark_duplicate_id(smartcard, irp->CompletionId);
list_enqueue(smartcard->CompletionIds, CompletionIdInfo);
ReleaseMutex(smartcard->CompletionIdsMutex);
/* Overwrite the previous assignment made in irp_new() */
irp->Complete = smartcard_irp_complete;
/* End TS Client defect workaround. */
if ((irp->MajorFunction == IRP_MJ_DEVICE_CONTROL) && smartcard_async_op(irp))
{
/* certain potentially long running operations get their own thread */
SMARTCARD_IRP_WORKER* irpWorker = malloc(sizeof(SMARTCARD_IRP_WORKER));
irpWorker->thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) smartcard_process_irp_thread_func,
irpWorker, CREATE_SUSPENDED, NULL);
irpWorker->smartcard = smartcard;
irpWorker->irp = irp;
ResumeThread(irpWorker->thread);
return;
}
InterlockedPushEntrySList(smartcard->pIrpList, &(irp->ItemEntry));
SetEvent(smartcard->irpEvent);
MessageQueue_Post(smartcard->IrpQueue, NULL, 0, (void*) irp, NULL);
}
#ifdef STATIC_CHANNELS
/* smartcard is always built-in */
#define DeviceServiceEntry smartcard_DeviceServiceEntry
#endif
int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
{
char* name;
char* path;
int i, length, ck;
int length, ck;
RDPDR_SMARTCARD* device;
SMARTCARD_DEVICE* smartcard;
device = (RDPDR_SMARTCARD*) pEntryPoints->device;
name = device->Name;
path = device->Path;
/* TODO: check if server supports sc redirect (version 5.1) */
smartcard = (SMARTCARD_DEVICE*) malloc(sizeof(SMARTCARD_DEVICE));
ZeroMemory(smartcard, sizeof(SMARTCARD_DEVICE));
smartcard = (SMARTCARD_DEVICE*) calloc(1, sizeof(SMARTCARD_DEVICE));
if (!smartcard)
return -1;
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;
length = strlen(smartcard->device.name);
@ -337,6 +239,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
smartcard->name = NULL;
smartcard->path = NULL;
if (path)
{
smartcard->path = path;
@ -350,17 +253,16 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
smartcard->name = name;
}
smartcard->pIrpList = (PSLIST_HEADER) _aligned_malloc(sizeof(SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT);
InitializeSListHead(smartcard->pIrpList);
smartcard->log = WLog_Get("com.freerdp.channel.smartcard.client");
WLog_SetLogLevel(smartcard->log, WLOG_DEBUG);
smartcard->IrpQueue = MessageQueue_New(NULL);
smartcard->OutstandingIrps = ListDictionary_New(TRUE);
smartcard->irpEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
smartcard->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
smartcard->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) smartcard_thread_func,
smartcard, CREATE_SUSPENDED, NULL);
smartcard->CompletionIds = list_new();
smartcard->CompletionIdsMutex = CreateMutex(NULL, FALSE, NULL);
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) smartcard);
ResumeThread(smartcard->thread);

View File

@ -21,101 +21,87 @@
#ifndef FREERDP_CHANNEL_SMARTCARD_CLIENT_MAIN_H
#define FREERDP_CHANNEL_SMARTCARD_CLIENT_MAIN_H
#include <freerdp/utils/list.h>
#include <freerdp/utils/debug.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>
/*
* When using Windows Server 2008 R2 as the Terminal Services (TS)
* server, and with a smart card reader connected to the TS client machine
* and used to authenticate to an existing login session, the TS server
* will initiate the protocol initialization of MS-RDPEFS, Section 1.3.1,
* twice as it re-establishes a connection. The TS server starts both
* initializations with a "Server Announce Request" message.
* When the TS client receives this message, as per Section 3.2.5.1.2,
*
* The client SHOULD treat this packet as the beginning
* of a new sequence. The client SHOULD also cancel all
* outstanding requests and release previous references to
* all devices.
*
* As of this writing, the code does not cancel all outstanding requests.
* This leads to a problem where, after the first MS-RDPEFS initialization,
* the TS server sends an SCARD_IOCTL_GETSTATUSCHANGEx control in a message
* that uses an available "CompletionID". The
* TS client doesn't respond immediately because it is blocking while
* waiting for a change in the smart card's status in the reader.
* Then the TS server initiates a second MS-RDPEFS initialization sequence.
* As noted above, this should cancel the outstanding
* SCARD_IOCTL_GETSTATUSCHANGEx request, but it does not.
* At this point, the TS server is free to reuse the previously used
* "CompletionID", and it does reuse it for other SCARD_IOCTLs.
* Therefore, when the user removes (for example) the card from the reader,
* the TS client sends an "IOCompetion" message in response to the
* GETSTATUSCHANGEx using the original "CompletionID". The TS server does not
* expect this "CompletionID" and so, as per Section 3.1.5.2 of MS-RDPEFS,
* it treats that "IOCompletion" message as an error and terminates the
* virtual channel.
*
* The following structure is part of a work-around for this missing
* capability of canceling outstanding requests. This work-around
* allows the TS client to send an "IOCompletion" back to the
* TS server for the second (and subsequent) SCARD_IOCTLs that use
* the same "CompletionID" as the still outstanding
* SCARD_IOCTL_GETSTATUSCHANGEx. The work-around in the TS client
* prevents the client from sending the "IOCompletion" back (when
* the user removes the card) for the SCARD_IOCTL_GETSTATUSCHANGEx.
*
* This TS client expects the responses from the PCSC daemon for the second
* and subsequent SCARD_IOCTLs that use the same "CompletionID"
* to arrive at the TS client before the daemon's response to the
* SCARD_IOCTL_GETSTATUSCHANGEx. This is a race condition.
*
* The "CompletionIDs" are a global pool of IDs across all "DeviceIDs".
* However, this problem of duplicate "CompletionIDs" only affects smart cards.
*
* This structure tracks outstanding Terminal Services server "CompletionIDs"
* used by the redirected smart card device.
*/
#define RDP_SCARD_CTL_CODE(code) CTL_CODE(FILE_DEVICE_FILE_SYSTEM, (code), METHOD_BUFFERED, FILE_ANY_ACCESS)
struct _COMPLETIONIDINFO
{
UINT32 ID; /* CompletionID */
BOOL duplicate; /* Indicates whether or not this
* CompletionID is a duplicate of an
* earlier, outstanding, CompletionID.
*/
};
typedef struct _COMPLETIONIDINFO COMPLETIONIDINFO;
#define SCARD_IOCTL_ESTABLISHCONTEXT RDP_SCARD_CTL_CODE(5) /* SCardEstablishContext */
#define SCARD_IOCTL_RELEASECONTEXT RDP_SCARD_CTL_CODE(6) /* SCardReleaseContext */
#define SCARD_IOCTL_ISVALIDCONTEXT RDP_SCARD_CTL_CODE(7) /* SCardIsValidContext */
#define SCARD_IOCTL_LISTREADERGROUPSA RDP_SCARD_CTL_CODE(8) /* SCardListReaderGroupsA */
#define SCARD_IOCTL_LISTREADERGROUPSW RDP_SCARD_CTL_CODE(9) /* SCardListReaderGroupsW */
#define SCARD_IOCTL_LISTREADERSA RDP_SCARD_CTL_CODE(10) /* SCardListReadersA */
#define SCARD_IOCTL_LISTREADERSW RDP_SCARD_CTL_CODE(11) /* SCardListReadersW */
#define SCARD_IOCTL_INTRODUCEREADERGROUPA RDP_SCARD_CTL_CODE(20) /* SCardIntroduceReaderGroupA */
#define SCARD_IOCTL_INTRODUCEREADERGROUPW RDP_SCARD_CTL_CODE(21) /* SCardIntroduceReaderGroupW */
#define SCARD_IOCTL_FORGETREADERGROUPA RDP_SCARD_CTL_CODE(22) /* SCardForgetReaderGroupA */
#define SCARD_IOCTL_FORGETREADERGROUPW RDP_SCARD_CTL_CODE(23) /* SCardForgetReaderGroupW */
#define SCARD_IOCTL_INTRODUCEREADERA RDP_SCARD_CTL_CODE(24) /* SCardIntroduceReaderA */
#define SCARD_IOCTL_INTRODUCEREADERW RDP_SCARD_CTL_CODE(25) /* SCardIntroduceReaderW */
#define SCARD_IOCTL_FORGETREADERA RDP_SCARD_CTL_CODE(26) /* SCardForgetReaderA */
#define SCARD_IOCTL_FORGETREADERW RDP_SCARD_CTL_CODE(27) /* SCardForgetReaderW */
#define SCARD_IOCTL_ADDREADERTOGROUPA RDP_SCARD_CTL_CODE(28) /* SCardAddReaderToGroupA */
#define SCARD_IOCTL_ADDREADERTOGROUPW RDP_SCARD_CTL_CODE(29) /* SCardAddReaderToGroupW */
#define SCARD_IOCTL_REMOVEREADERFROMGROUPA RDP_SCARD_CTL_CODE(30) /* SCardRemoveReaderFromGroupA */
#define SCARD_IOCTL_REMOVEREADERFROMGROUPW RDP_SCARD_CTL_CODE(31) /* SCardRemoveReaderFromGroupW */
#define SCARD_IOCTL_LOCATECARDSA RDP_SCARD_CTL_CODE(38) /* SCardLocateCardsA */
#define SCARD_IOCTL_LOCATECARDSW RDP_SCARD_CTL_CODE(39) /* SCardLocateCardsW */
#define SCARD_IOCTL_GETSTATUSCHANGEA RDP_SCARD_CTL_CODE(40) /* SCardGetStatusChangeA */
#define SCARD_IOCTL_GETSTATUSCHANGEW RDP_SCARD_CTL_CODE(41) /* SCardGetStatusChangeW */
#define SCARD_IOCTL_CANCEL RDP_SCARD_CTL_CODE(42) /* SCardCancel */
#define SCARD_IOCTL_CONNECTA RDP_SCARD_CTL_CODE(43) /* SCardConnectA */
#define SCARD_IOCTL_CONNECTW RDP_SCARD_CTL_CODE(44) /* SCardConnectW */
#define SCARD_IOCTL_RECONNECT RDP_SCARD_CTL_CODE(45) /* SCardReconnect */
#define SCARD_IOCTL_DISCONNECT RDP_SCARD_CTL_CODE(46) /* SCardDisconnect */
#define SCARD_IOCTL_BEGINTRANSACTION RDP_SCARD_CTL_CODE(47) /* SCardBeginTransaction */
#define SCARD_IOCTL_ENDTRANSACTION RDP_SCARD_CTL_CODE(48) /* SCardEndTransaction */
#define SCARD_IOCTL_STATE RDP_SCARD_CTL_CODE(49) /* SCardState */
#define SCARD_IOCTL_STATUSA RDP_SCARD_CTL_CODE(50) /* SCardStatusA */
#define SCARD_IOCTL_STATUSW RDP_SCARD_CTL_CODE(51) /* SCardStatusW */
#define SCARD_IOCTL_TRANSMIT RDP_SCARD_CTL_CODE(52) /* SCardTransmit */
#define SCARD_IOCTL_CONTROL RDP_SCARD_CTL_CODE(53) /* SCardControl */
#define SCARD_IOCTL_GETATTRIB RDP_SCARD_CTL_CODE(54) /* SCardGetAttrib */
#define SCARD_IOCTL_SETATTRIB RDP_SCARD_CTL_CODE(55) /* SCardSetAttrib */
#define SCARD_IOCTL_ACCESSSTARTEDEVENT RDP_SCARD_CTL_CODE(56) /* SCardAccessStartedEvent */
#define SCARD_IOCTL_LOCATECARDSBYATRA RDP_SCARD_CTL_CODE(58) /* SCardLocateCardsByATRA */
#define SCARD_IOCTL_LOCATECARDSBYATRW RDP_SCARD_CTL_CODE(59) /* SCardLocateCardsByATRW */
#define SCARD_IOCTL_READCACHEA RDP_SCARD_CTL_CODE(60) /* SCardReadCacheA */
#define SCARD_IOCTL_READCACHEW RDP_SCARD_CTL_CODE(61) /* SCardReadCacheW */
#define SCARD_IOCTL_WRITECACHEA RDP_SCARD_CTL_CODE(62) /* SCardWriteCacheA */
#define SCARD_IOCTL_WRITECACHEW RDP_SCARD_CTL_CODE(63) /* SCardWriteCacheW */
#define SCARD_IOCTL_GETTRANSMITCOUNT RDP_SCARD_CTL_CODE(64) /* SCardGetTransmitCount */
#define SCARD_IOCTL_RELEASESTARTEDEVENT RDP_SCARD_CTL_CODE(66) /* SCardReleaseStartedEvent */
#define SCARD_IOCTL_GETREADERICON RDP_SCARD_CTL_CODE(67) /* SCardGetReaderIconA */
#define SCARD_IOCTL_GETDEVICETYPEID RDP_SCARD_CTL_CODE(68) /* SCardGetDeviceTypeIdA */
struct _SMARTCARD_DEVICE
{
DEVICE device;
wLog* log;
char* name;
char* path;
PSLIST_HEADER pIrpList;
HANDLE thread;
HANDLE irpEvent;
HANDLE stopEvent;
LIST* CompletionIds;
HANDLE CompletionIdsMutex;
wMessageQueue* IrpQueue;
wListDictionary* OutstandingIrps;
};
typedef struct _SMARTCARD_DEVICE SMARTCARD_DEVICE;
#ifdef WITH_DEBUG_SCARD
#define DEBUG_SCARD(fmt, ...) DEBUG_CLASS(SCARD, fmt, ## __VA_ARGS__)
#else
#define DEBUG_SCARD(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
void smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp);
void smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp);
BOOL smartcard_async_op(IRP*);
void smartcard_device_control(SMARTCARD_DEVICE*, IRP*);
void smartcard_irp_device_control(SMARTCARD_DEVICE* smartcard, IRP* irp);
void smartcard_irp_device_control_peek_io_control_code(SMARTCARD_DEVICE* smartcard, IRP* irp, UINT32* ioControlCode);
#include "smartcard_pack.h"
#endif /* FREERDP_CHANNEL_SMARTCARD_CLIENT_MAIN_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,528 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Smart Card Structure Packing
*
* Copyright 2014 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.
*/
#ifndef FREERDP_CHANNEL_SMARTCARD_CLIENT_PACK_H
#define FREERDP_CHANNEL_SMARTCARD_CLIENT_PACK_H
#include <winpr/crt.h>
#include <winpr/stream.h>
#include <winpr/smartcard.h>
#include "smartcard_main.h"
/* interface type_scard_pack */
/* [unique][version][uuid] */
typedef struct _REDIR_SCARDCONTEXT
{
/* [range] */ DWORD cbContext;
/* [size_is][unique] */ BYTE pbContext[8];
} REDIR_SCARDCONTEXT;
typedef struct _REDIR_SCARDHANDLE
{
/* [range] */ DWORD cbHandle;
/* [size_is] */ BYTE pbHandle[8];
} REDIR_SCARDHANDLE;
typedef struct _Long_Return
{
LONG ReturnCode;
} Long_Return;
typedef struct _longAndMultiString_Return
{
LONG ReturnCode;
/* [range] */ DWORD cBytes;
/* [size_is][unique] */ BYTE *msz;
} ListReaderGroups_Return;
typedef struct _longAndMultiString_Return ListReaders_Return;
typedef struct _Context_Call
{
REDIR_SCARDCONTEXT hContext;
} Context_Call;
typedef struct _ContextAndStringA_Call
{
REDIR_SCARDCONTEXT hContext;
/* [string] */ unsigned char *sz;
} ContextAndStringA_Call;
typedef struct _ContextAndStringW_Call
{
REDIR_SCARDCONTEXT hContext;
/* [string] */ WCHAR *sz;
} ContextAndStringW_Call;
typedef struct _ContextAndTwoStringA_Call
{
REDIR_SCARDCONTEXT hContext;
/* [string] */ unsigned char *sz1;
/* [string] */ unsigned char *sz2;
} ContextAndTwoStringA_Call;
typedef struct _ContextAndTwoStringW_Call
{
REDIR_SCARDCONTEXT hContext;
/* [string] */ WCHAR *sz1;
/* [string] */ WCHAR *sz2;
} ContextAndTwoStringW_Call;
typedef struct _EstablishContext_Call
{
DWORD dwScope;
} EstablishContext_Call;
typedef struct _EstablishContext_Return
{
LONG ReturnCode;
REDIR_SCARDCONTEXT hContext;
} EstablishContext_Return;
typedef struct _ListReaderGroups_Call
{
REDIR_SCARDCONTEXT hContext;
LONG fmszGroupsIsNULL;
DWORD cchGroups;
} ListReaderGroups_Call;
typedef struct _ListReaders_Call
{
REDIR_SCARDCONTEXT hContext;
/* [range] */ DWORD cBytes;
/* [size_is][unique] */ BYTE *mszGroups;
LONG fmszReadersIsNULL;
DWORD cchReaders;
} ListReaders_Call;
typedef struct _ReaderState_Common_Call
{
DWORD dwCurrentState;
DWORD dwEventState;
/* [range] */ DWORD cbAtr;
BYTE rgbAtr[36];
} ReaderState_Common_Call;
typedef struct _ReaderStateA
{
/* [string] */ unsigned char *szReader;
ReaderState_Common_Call Common;
} ReaderStateA;
typedef struct _ReaderStateW
{
/* [string] */ WCHAR *szReader;
ReaderState_Common_Call Common;
} ReaderStateW;
typedef struct _ReaderState_Return
{
DWORD dwCurrentState;
DWORD dwEventState;
/* [range] */ DWORD cbAtr;
BYTE rgbAtr[36];
} ReaderState_Return;
typedef struct _GetStatusChangeA_Call
{
REDIR_SCARDCONTEXT hContext;
DWORD dwTimeOut;
/* [range] */ DWORD cReaders;
/* [size_is] */ LPSCARD_READERSTATEA rgReaderStates;
} GetStatusChangeA_Call;
typedef struct _LocateCardsA_Call
{
REDIR_SCARDCONTEXT hContext;
/* [range] */ DWORD cBytes;
/* [size_is] */ BYTE *mszCards;
/* [range] */ DWORD cReaders;
/* [size_is] */ ReaderStateA *rgReaderStates;
} LocateCardsA_Call;
typedef struct _LocateCardsW_Call
{
REDIR_SCARDCONTEXT hContext;
/* [range] */ DWORD cBytes;
/* [size_is] */ BYTE *mszCards;
/* [range] */ DWORD cReaders;
/* [size_is] */ ReaderStateW *rgReaderStates;
} LocateCardsW_Call;
typedef struct _LocateCards_ATRMask
{
/* [range] */ DWORD cbAtr;
BYTE rgbAtr[ 36 ];
BYTE rgbMask[ 36 ];
} LocateCards_ATRMask;
typedef struct _LocateCardsByATRA_Call
{
REDIR_SCARDCONTEXT hContext;
/* [range] */ DWORD cAtrs;
/* [size_is] */ LocateCards_ATRMask *rgAtrMasks;
/* [range] */ DWORD cReaders;
/* [size_is] */ ReaderStateA *rgReaderStates;
} LocateCardsByATRA_Call;
typedef struct _LocateCardsByATRW_Call
{
REDIR_SCARDCONTEXT hContext;
/* [range] */ DWORD cAtrs;
/* [size_is] */ LocateCards_ATRMask *rgAtrMasks;
/* [range] */ DWORD cReaders;
/* [size_is] */ ReaderStateW *rgReaderStates;
} LocateCardsByATRW_Call;
typedef struct _GetStatusChange_Return
{
LONG ReturnCode;
/* [range] */ DWORD cReaders;
/* [size_is] */ ReaderState_Return *rgReaderStates;
} LocateCards_Return;
typedef struct _GetStatusChange_Return GetStatusChange_Return;
typedef struct _GetStatusChangeW_Call
{
REDIR_SCARDCONTEXT hContext;
DWORD dwTimeOut;
/* [range] */ DWORD cReaders;
/* [size_is] */ LPSCARD_READERSTATEW rgReaderStates;
} GetStatusChangeW_Call;
typedef struct _Connect_Common
{
REDIR_SCARDCONTEXT hContext;
DWORD dwShareMode;
DWORD dwPreferredProtocols;
} Connect_Common;
typedef struct _ConnectA_Call
{
/* [string] */ unsigned char *szReader;
Connect_Common Common;
} ConnectA_Call;
typedef struct _ConnectW_Call
{
/* [string] */ WCHAR *szReader;
Connect_Common Common;
} ConnectW_Call;
typedef struct _Connect_Return
{
LONG ReturnCode;
REDIR_SCARDCONTEXT hContext;
REDIR_SCARDHANDLE hCard;
DWORD dwActiveProtocol;
} Connect_Return;
typedef struct _Reconnect_Call
{
REDIR_SCARDCONTEXT hContext;
REDIR_SCARDHANDLE hCard;
DWORD dwShareMode;
DWORD dwPreferredProtocols;
DWORD dwInitialization;
} Reconnect_Call;
typedef struct Reconnect_Return
{
LONG ReturnCode;
DWORD dwActiveProtocol;
} Reconnect_Return;
typedef struct _HCardAndDisposition_Call
{
REDIR_SCARDCONTEXT hContext;
REDIR_SCARDHANDLE hCard;
DWORD dwDisposition;
} HCardAndDisposition_Call;
typedef struct _State_Call
{
REDIR_SCARDCONTEXT hContext;
REDIR_SCARDHANDLE hCard;
LONG fpbAtrIsNULL;
DWORD cbAtrLen;
} State_Call;
typedef struct _State_Return
{
LONG ReturnCode;
DWORD dwState;
DWORD dwProtocol;
/* [range] */ DWORD cbAtrLen;
/* [size_is][unique] */ BYTE rgAtr[36];
} State_Return;
typedef struct _Status_Call
{
REDIR_SCARDCONTEXT hContext;
REDIR_SCARDHANDLE hCard;
LONG fmszReaderNamesIsNULL;
DWORD cchReaderLen;
DWORD cbAtrLen;
} Status_Call;
typedef struct _Status_Return
{
LONG ReturnCode;
/* [range] */ DWORD cBytes;
/* [size_is][unique] */ BYTE *mszReaderNames;
DWORD dwState;
DWORD dwProtocol;
BYTE pbAtr[32];
/* [range] */ DWORD cbAtrLen;
} Status_Return;
typedef struct _SCardIO_Request
{
DWORD dwProtocol;
/* [range] */ DWORD cbExtraBytes;
/* [size_is][unique] */ BYTE *pbExtraBytes;
} SCardIO_Request;
typedef struct _Transmit_Call
{
REDIR_SCARDCONTEXT hContext;
REDIR_SCARDHANDLE hCard;
LPSCARD_IO_REQUEST pioSendPci;
/* [range] */ DWORD cbSendLength;
/* [size_is] */ BYTE *pbSendBuffer;
/* [unique] */ LPSCARD_IO_REQUEST pioRecvPci;
LONG fpbRecvBufferIsNULL;
DWORD cbRecvLength;
} Transmit_Call;
typedef struct _Transmit_Return
{
LONG ReturnCode;
/* [unique] */ LPSCARD_IO_REQUEST pioRecvPci;
/* [range] */ DWORD cbRecvLength;
/* [size_is][unique] */ BYTE *pbRecvBuffer;
} Transmit_Return;
typedef struct _GetTransmitCount_Call
{
REDIR_SCARDCONTEXT hContext;
REDIR_SCARDHANDLE hCard;
} GetTransmitCount_Call;
typedef struct _GetTransmitCount_Return
{
LONG ReturnCode;
DWORD cTransmitCount;
} GetTransmitCount_Return;
typedef struct _Control_Call
{
REDIR_SCARDCONTEXT hContext;
REDIR_SCARDHANDLE hCard;
DWORD dwControlCode;
/* [range] */ DWORD cbInBufferSize;
/* [size_is][unique] */ BYTE *pvInBuffer;
LONG fpvOutBufferIsNULL;
DWORD cbOutBufferSize;
} Control_Call;
typedef struct _Control_Return
{
LONG ReturnCode;
/* [range] */ DWORD cbOutBufferSize;
/* [size_is][unique] */ BYTE *pvOutBuffer;
} Control_Return;
typedef struct _GetAttrib_Call
{
REDIR_SCARDCONTEXT hContext;
REDIR_SCARDHANDLE hCard;
DWORD dwAttrId;
LONG fpbAttrIsNULL;
DWORD cbAttrLen;
} GetAttrib_Call;
typedef struct _GetAttrib_Return
{
LONG ReturnCode;
/* [range] */ DWORD cbAttrLen;
/* [size_is][unique] */ BYTE *pbAttr;
} GetAttrib_Return;
typedef struct _SetAttrib_Call
{
REDIR_SCARDCONTEXT hContext;
REDIR_SCARDHANDLE hCard;
DWORD dwAttrId;
/* [range] */ DWORD cbAttrLen;
/* [size_is] */ BYTE *pbAttr;
} SetAttrib_Call;
typedef struct _ReadCache_Common
{
REDIR_SCARDCONTEXT hContext;
UUID *CardIdentifier;
DWORD FreshnessCounter;
LONG fPbDataIsNULL;
DWORD cbDataLen;
} ReadCache_Common;
typedef struct _ReadCacheA_Call
{
/* [string] */ unsigned char *szLookupName;
ReadCache_Common Common;
} ReadCacheA_Call;
typedef struct _ReadCacheW_Call
{
/* [string] */ WCHAR *szLookupName;
ReadCache_Common Common;
} ReadCacheW_Call;
typedef struct _ReadCache_Return
{
LONG ReturnCode;
/* [range] */ DWORD cbDataLen;
/* [size_is][unique] */ BYTE *pbData;
} ReadCache_Return;
typedef struct _WriteCache_Common
{
REDIR_SCARDCONTEXT hContext;
UUID *CardIdentifier;
DWORD FreshnessCounter;
/* [range] */ DWORD cbDataLen;
/* [size_is][unique] */ BYTE *pbData;
} WriteCache_Common;
typedef struct _WriteCacheA_Call
{
/* [string] */ unsigned char *szLookupName;
WriteCache_Common Common;
} WriteCacheA_Call;
typedef struct _WriteCacheW_Call
{
/* [string] */ WCHAR *szLookupName;
WriteCache_Common Common;
} WriteCacheW_Call;
#define SMARTCARD_COMMON_TYPE_HEADER_LENGTH 8
#define SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH 8
UINT32 smartcard_pack_write_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, UINT32 size, UINT32 alignment);
UINT32 smartcard_unpack_read_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, UINT32 size, UINT32 alignment);
SCARDCONTEXT smartcard_scard_context_native_from_redir(SMARTCARD_DEVICE* smartcard, REDIR_SCARDCONTEXT* context);
void smartcard_scard_context_native_to_redir(SMARTCARD_DEVICE* smartcard, REDIR_SCARDCONTEXT* context, SCARDCONTEXT hContext);
SCARDHANDLE smartcard_scard_handle_native_from_redir(SMARTCARD_DEVICE* smartcard, REDIR_SCARDHANDLE* handle);
void smartcard_scard_handle_native_to_redir(SMARTCARD_DEVICE* smartcard, REDIR_SCARDHANDLE* handle, SCARDHANDLE hCard);
UINT32 smartcard_unpack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s);
UINT32 smartcard_pack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s);
UINT32 smartcard_unpack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s);
UINT32 smartcard_pack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s, UINT32 objectBufferLength);
UINT32 smartcard_unpack_redir_scard_context(SMARTCARD_DEVICE* smartcard, wStream* s, REDIR_SCARDCONTEXT* context);
UINT32 smartcard_pack_redir_scard_context(SMARTCARD_DEVICE* smartcard, wStream* s, REDIR_SCARDCONTEXT* context);
UINT32 smartcard_unpack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s, REDIR_SCARDCONTEXT* context);
UINT32 smartcard_pack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s, REDIR_SCARDCONTEXT* context);
UINT32 smartcard_unpack_redir_scard_handle(SMARTCARD_DEVICE* smartcard, wStream* s, REDIR_SCARDHANDLE* handle);
UINT32 smartcard_pack_redir_scard_handle(SMARTCARD_DEVICE* smartcard, wStream* s, REDIR_SCARDHANDLE* handle);
UINT32 smartcard_unpack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s, REDIR_SCARDHANDLE* handle);
UINT32 smartcard_pack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s, REDIR_SCARDHANDLE* handle);
UINT32 smartcard_unpack_establish_context_call(SMARTCARD_DEVICE* smartcard, wStream* s, EstablishContext_Call* call);
void smartcard_trace_establish_context_call(SMARTCARD_DEVICE* smartcard, EstablishContext_Call* call);
UINT32 smartcard_pack_establish_context_return(SMARTCARD_DEVICE* smartcard, wStream* s, EstablishContext_Return* ret);
void smartcard_trace_establish_context_return(SMARTCARD_DEVICE* smartcard, EstablishContext_Return* ret);
UINT32 smartcard_unpack_context_call(SMARTCARD_DEVICE* smartcard, wStream* s, Context_Call* call);
void smartcard_trace_context_call(SMARTCARD_DEVICE* smartcard, Context_Call* call, const char* name);
UINT32 smartcard_unpack_list_readers_call(SMARTCARD_DEVICE* smartcard, wStream* s, ListReaders_Call* call);
void smartcard_trace_list_readers_call(SMARTCARD_DEVICE* smartcard, ListReaders_Call* call, BOOL unicode);
UINT32 smartcard_pack_list_readers_return(SMARTCARD_DEVICE* smartcard, wStream* s, ListReaders_Return* ret);
void smartcard_trace_list_readers_return(SMARTCARD_DEVICE* smartcard, ListReaders_Return* ret, BOOL unicode);
UINT32 smartcard_unpack_connect_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, ConnectA_Call* call);
void smartcard_trace_connect_a_call(SMARTCARD_DEVICE* smartcard, ConnectA_Call* call);
UINT32 smartcard_unpack_connect_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, ConnectW_Call* call);
void smartcard_trace_connect_w_call(SMARTCARD_DEVICE* smartcard, ConnectW_Call* call);
UINT32 smartcard_pack_connect_return(SMARTCARD_DEVICE* smartcard, wStream* s, Connect_Return* ret);
void smartcard_trace_connect_return(SMARTCARD_DEVICE* smartcard, Connect_Return* ret);
UINT32 smartcard_unpack_reconnect_call(SMARTCARD_DEVICE* smartcard, wStream* s, Reconnect_Call* call);
void smartcard_trace_reconnect_call(SMARTCARD_DEVICE* smartcard, Reconnect_Call* call);
UINT32 smartcard_pack_reconnect_return(SMARTCARD_DEVICE* smartcard, wStream* s, Reconnect_Return* ret);
void smartcard_trace_reconnect_return(SMARTCARD_DEVICE* smartcard, Reconnect_Return* ret);
UINT32 smartcard_unpack_hcard_and_disposition_call(SMARTCARD_DEVICE* smartcard, wStream* s, HCardAndDisposition_Call* call);
void smartcard_trace_hcard_and_disposition_call(SMARTCARD_DEVICE* smartcard, HCardAndDisposition_Call* call, const char* name);
UINT32 smartcard_unpack_get_status_change_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, GetStatusChangeA_Call* call);
void smartcard_trace_get_status_change_a_call(SMARTCARD_DEVICE* smartcard, GetStatusChangeA_Call* call);
UINT32 smartcard_unpack_get_status_change_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, GetStatusChangeW_Call* call);
void smartcard_trace_get_status_change_w_call(SMARTCARD_DEVICE* smartcard, GetStatusChangeW_Call* call);
UINT32 smartcard_pack_get_status_change_return(SMARTCARD_DEVICE* smartcard, wStream* s, GetStatusChange_Return* ret);
void smartcard_trace_get_status_change_return(SMARTCARD_DEVICE* smartcard, GetStatusChange_Return* ret, BOOL unicode);
UINT32 smartcard_unpack_state_call(SMARTCARD_DEVICE* smartcard, wStream* s, State_Call* call);
UINT32 smartcard_pack_state_return(SMARTCARD_DEVICE* smartcard, wStream* s, State_Return* ret);
UINT32 smartcard_unpack_status_call(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Call* call);
void smartcard_trace_status_call(SMARTCARD_DEVICE* smartcard, Status_Call* call, BOOL unicode);
UINT32 smartcard_pack_status_return(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Return* ret);
void smartcard_trace_status_return(SMARTCARD_DEVICE* smartcard, Status_Return* ret, BOOL unicode);
UINT32 smartcard_unpack_get_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, GetAttrib_Call* call);
void smartcard_trace_get_attrib_call(SMARTCARD_DEVICE* smartcard, GetAttrib_Call* call);
UINT32 smartcard_pack_get_attrib_return(SMARTCARD_DEVICE* smartcard, wStream* s, GetAttrib_Return* ret);
void smartcard_trace_get_attrib_return(SMARTCARD_DEVICE* smartcard, GetAttrib_Return* ret, DWORD dwAttrId);
UINT32 smartcard_unpack_control_call(SMARTCARD_DEVICE* smartcard, wStream* s, Control_Call* call);
void smartcard_trace_control_call(SMARTCARD_DEVICE* smartcard, Control_Call* call);
UINT32 smartcard_pack_control_return(SMARTCARD_DEVICE* smartcard, wStream* s, Control_Return* ret);
void smartcard_trace_control_return(SMARTCARD_DEVICE* smartcard, Control_Return* ret);
UINT32 smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Transmit_Call* call);
void smartcard_trace_transmit_call(SMARTCARD_DEVICE* smartcard, Transmit_Call* call);
UINT32 smartcard_pack_transmit_return(SMARTCARD_DEVICE* smartcard, wStream* s, Transmit_Return* ret);
void smartcard_trace_transmit_return(SMARTCARD_DEVICE* smartcard, Transmit_Return* ret);
#endif /* FREERDP_CHANNEL_SMARTCARD_CLIENT_PACK_H */

View File

@ -38,10 +38,9 @@
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <winpr/collections.h>
#include <winpr/stream.h>
#include <freerdp/utils/list.h>
#include <freerdp/utils/event.h>
#include <freerdp/client/tsmf.h>
@ -90,7 +89,7 @@ struct _TSMF_PRESENTATION
HANDLE mutex;
HANDLE thread;
LIST* stream_list;
wArrayList* stream_list;
};
struct _TSMF_STREAM
@ -142,7 +141,7 @@ struct _TSMF_SAMPLE
UINT64 ack_time;
};
static LIST* presentation_list = NULL;
static wArrayList* presentation_list = NULL;
static UINT64 last_played_audio_time = 0;
static HANDLE tsmf_mutex = NULL;
static int TERMINATING = 0;
@ -157,8 +156,9 @@ static UINT64 get_current_time(void)
static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync)
{
UINT32 index;
UINT32 count;
TSMF_STREAM* s;
LIST_ITEM* item;
TSMF_SAMPLE* sample;
BOOL pending = FALSE;
TSMF_PRESENTATION* presentation = stream->presentation;
@ -177,11 +177,13 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync)
/* Check if some other stream has earlier sample that needs to be played first */
if (stream->last_end_time > AUDIO_TOLERANCE)
{
WaitForSingleObject(presentation->mutex, INFINITE);
ArrayList_Lock(presentation->stream_list);
for (item = presentation->stream_list->head; item; item = item->next)
count = ArrayList_Count(presentation->stream_list);
for (index = 0; index < count; index++)
{
s = (TSMF_STREAM*) item->data;
s = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index);
if (s != stream && !s->eos && s->last_end_time &&
s->last_end_time < stream->last_end_time - AUDIO_TOLERANCE)
@ -191,7 +193,7 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync)
}
}
ReleaseMutex(presentation->mutex);
ArrayList_Unlock(presentation->stream_list);
}
}
else
@ -279,35 +281,48 @@ TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid, IWTSVirtualChannelCal
return NULL;
}
presentation = (TSMF_PRESENTATION*) malloc(sizeof(TSMF_PRESENTATION));
ZeroMemory(presentation, sizeof(TSMF_PRESENTATION));
presentation = (TSMF_PRESENTATION*) calloc(1, sizeof(TSMF_PRESENTATION));
memcpy(presentation->presentation_id, guid, GUID_SIZE);
CopyMemory(presentation->presentation_id, guid, GUID_SIZE);
presentation->channel_callback = pChannelCallback;
presentation->volume = 5000; /* 50% */
presentation->muted = 0;
presentation->mutex = CreateMutex(NULL, FALSE, NULL);
presentation->stream_list = list_new();
presentation->stream_list = ArrayList_New(TRUE);
ArrayList_Object(presentation->stream_list)->fnObjectFree = (OBJECT_FREE_FN) tsmf_stream_free;
list_enqueue(presentation_list, presentation);
ArrayList_Add(presentation_list, presentation);
return presentation;
}
TSMF_PRESENTATION* tsmf_presentation_find_by_id(const BYTE* guid)
{
LIST_ITEM* item;
UINT32 index;
UINT32 count;
BOOL found = FALSE;
TSMF_PRESENTATION* presentation;
for (item = presentation_list->head; item; item = item->next)
ArrayList_Lock(presentation_list);
count = ArrayList_Count(presentation_list);
for (index = 0; index < count; index++)
{
presentation = (TSMF_PRESENTATION*) item->data;
presentation = (TSMF_PRESENTATION*) ArrayList_GetItem(presentation_list, index);
if (memcmp(presentation->presentation_id, guid, GUID_SIZE) == 0)
return presentation;
{
found = TRUE;
break;
}
}
return NULL;
ArrayList_Unlock(presentation_list);
return (found) ? presentation : NULL;
}
static void tsmf_presentation_restore_last_video_frame(TSMF_PRESENTATION* presentation)
@ -789,69 +804,103 @@ static void tsmf_stream_change_volume(TSMF_STREAM* stream, UINT32 newVolume, UIN
void tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, UINT32 newVolume, UINT32 muted)
{
LIST_ITEM* item;
UINT32 index;
UINT32 count;
TSMF_STREAM* stream;
presentation->volume = newVolume;
presentation->muted = muted;
for (item = presentation->stream_list->head; item; item = item->next)
ArrayList_Lock(presentation->stream_list);
count = ArrayList_Count(presentation->stream_list);
for (index = 0; index < count; index++)
{
stream = (TSMF_STREAM*) item->data;
stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index);
tsmf_stream_change_volume(stream, newVolume, muted);
}
ArrayList_Unlock(presentation->stream_list);
}
void tsmf_presentation_paused(TSMF_PRESENTATION* presentation)
{
LIST_ITEM* item;
UINT32 index;
UINT32 count;
TSMF_STREAM* stream;
for (item = presentation->stream_list->head; item; item = item->next)
ArrayList_Lock(presentation->stream_list);
count = ArrayList_Count(presentation->stream_list);
for (index = 0; index < count; index++)
{
stream = (TSMF_STREAM*) item->data;
stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index);
tsmf_stream_pause(stream);
}
ArrayList_Unlock(presentation->stream_list);
}
void tsmf_presentation_restarted(TSMF_PRESENTATION* presentation)
{
LIST_ITEM* item;
UINT32 index;
UINT32 count;
TSMF_STREAM* stream;
for (item = presentation->stream_list->head; item; item = item->next)
ArrayList_Lock(presentation->stream_list);
count = ArrayList_Count(presentation->stream_list);
for (index = 0; index < count; index++)
{
stream = (TSMF_STREAM*) item->data;
stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index);
tsmf_stream_restart(stream);
}
ArrayList_Unlock(presentation->stream_list);
}
void tsmf_presentation_start(TSMF_PRESENTATION* presentation)
{
LIST_ITEM* item;
UINT32 index;
UINT32 count;
TSMF_STREAM* stream;
for (item = presentation->stream_list->head; item; item = item->next)
ArrayList_Lock(presentation->stream_list);
count = ArrayList_Count(presentation->stream_list);
for (index = 0; index < count; index++)
{
stream = (TSMF_STREAM*) item->data;
stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index);
tsmf_stream_start(stream);
}
ArrayList_Unlock(presentation->stream_list);
}
void tsmf_presentation_stop(TSMF_PRESENTATION* presentation)
{
LIST_ITEM* item;
UINT32 index;
UINT32 count;
TSMF_STREAM* stream;
tsmf_presentation_flush(presentation);
for (item = presentation->stream_list->head; item; item = item->next)
ArrayList_Lock(presentation->stream_list);
count = ArrayList_Count(presentation->stream_list);
for (index = 0; index < count; index++)
{
stream = (TSMF_STREAM*) item->data;
stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index);
tsmf_stream_stop(stream);
}
ArrayList_Unlock(presentation->stream_list);
tsmf_presentation_restore_last_video_frame(presentation);
if (presentation->last_rects)
@ -914,15 +963,22 @@ static void tsmf_stream_flush(TSMF_STREAM* stream)
void tsmf_presentation_flush(TSMF_PRESENTATION* presentation)
{
LIST_ITEM* item;
UINT32 index;
UINT32 count;
TSMF_STREAM * stream;
for (item = presentation->stream_list->head; item; item = item->next)
ArrayList_Lock(presentation->stream_list);
count = ArrayList_Count(presentation->stream_list);
for (index = 0; index < count; index++)
{
stream = (TSMF_STREAM*) item->data;
stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index);
tsmf_stream_flush(stream);
}
ArrayList_Unlock(presentation->stream_list);
presentation->eos = 0;
presentation->audio_start_time = 0;
presentation->audio_end_time = 0;
@ -930,19 +986,10 @@ void tsmf_presentation_flush(TSMF_PRESENTATION* presentation)
void tsmf_presentation_free(TSMF_PRESENTATION* presentation)
{
TSMF_STREAM* stream;
tsmf_presentation_stop(presentation);
WaitForSingleObject(presentation->mutex, INFINITE);
list_remove(presentation_list, presentation);
ReleaseMutex(presentation->mutex);
while (list_size(presentation->stream_list) > 0)
{
stream = (TSMF_STREAM*) list_dequeue(presentation->stream_list);
tsmf_stream_free(stream);
}
list_free(presentation->stream_list);
ArrayList_Remove(presentation_list, presentation);
ArrayList_Free(presentation->stream_list);
CloseHandle(presentation->mutex);
@ -978,27 +1025,36 @@ TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id)
stream->sample_ack_list = Queue_New(TRUE, -1, -1);
stream->sample_ack_list->object.fnObjectFree = free;
WaitForSingleObject(presentation->mutex, INFINITE);
list_enqueue(presentation->stream_list, stream);
ReleaseMutex(presentation->mutex);
ArrayList_Add(presentation->stream_list, stream);
return stream;
}
TSMF_STREAM* tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation, UINT32 stream_id)
{
LIST_ITEM* item;
UINT32 index;
UINT32 count;
BOOL found = FALSE;
TSMF_STREAM* stream;
for (item = presentation->stream_list->head; item; item = item->next)
ArrayList_Lock(presentation->stream_list);
count = ArrayList_Count(presentation->stream_list);
for (index = 0; index < count; index++)
{
stream = (TSMF_STREAM*) item->data;
stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index);
if (stream->stream_id == stream_id)
return stream;
{
found = TRUE;
break;
}
}
return NULL;
ArrayList_Unlock(presentation->stream_list);
return (found) ? stream : NULL;
}
void tsmf_stream_set_format(TSMF_STREAM* stream, const char* name, wStream* s)
@ -1054,9 +1110,7 @@ void tsmf_stream_free(TSMF_STREAM* stream)
tsmf_stream_stop(stream);
tsmf_stream_flush(stream);
WaitForSingleObject(presentation->mutex, INFINITE);
list_remove(presentation->stream_list, stream);
ReleaseMutex(presentation->mutex);
ArrayList_Remove(presentation->stream_list, stream);
Queue_Free(stream->sample_list);
Queue_Free(stream->sample_ack_list);
@ -1089,8 +1143,7 @@ void tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pC
ReleaseMutex(tsmf_mutex);
sample = (TSMF_SAMPLE*) malloc(sizeof(TSMF_SAMPLE));
ZeroMemory(sample, sizeof(TSMF_SAMPLE));
sample = (TSMF_SAMPLE*) calloc(1, sizeof(TSMF_SAMPLE));
sample->sample_id = sample_id;
sample->start_time = start_time;
@ -1111,28 +1164,11 @@ void tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pC
static void tsmf_signal_handler(int s)
{
LIST_ITEM* p_item;
TSMF_PRESENTATION* presentation;
LIST_ITEM* s_item;
TSMF_STREAM* _stream;
WaitForSingleObject(tsmf_mutex, INFINITE);
TERMINATING = 1;
ReleaseMutex(tsmf_mutex);
if (presentation_list)
{
for (p_item = presentation_list->head; p_item; p_item = p_item->next)
{
presentation = (TSMF_PRESENTATION*) p_item->data;
for (s_item = presentation->stream_list->head; s_item; s_item = s_item->next)
{
_stream = (TSMF_STREAM*) s_item->data;
tsmf_stream_free(_stream);
}
tsmf_presentation_free(presentation);
}
}
ArrayList_Free(presentation_list);
unlink("/tmp/tsmf.tid");
@ -1162,7 +1198,9 @@ void tsmf_media_init(void)
tsmf_mutex = CreateMutex(NULL, FALSE, NULL);
if (presentation_list == NULL)
presentation_list = list_new();
if (!presentation_list)
{
presentation_list = ArrayList_New(TRUE);
ArrayList_Object(presentation_list)->fnObjectFree = (OBJECT_FREE_FN) tsmf_presentation_free;
}
}

View File

@ -17,6 +17,20 @@
define_channel("urbdrc")
if(WITH_CLIENT_CHANNELS)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
if(NOT WIN32)
find_package(UDev)
find_package(UUID)
find_package(DbusGlib)
find_package(libusb-1.0)
endif()
if(UDEV_FOUND AND UUID_FOUND AND DBUS_GLIB_FOUND AND LIBUSB_1_FOUND)
set(URBDRC_DEPENDENCIES_FOUND TRUE)
message(STATUS "Found all URBDRC dependencies")
endif()
if(WITH_CLIENT_CHANNELS)
if(URBDRC_DEPENDENCIES_FOUND)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()
endif()

View File

@ -31,10 +31,6 @@ set(${MODULE_PREFIX}_SRCS
include_directories(..)
find_package(UDev REQUIRED)
find_package(UUID REQUIRED)
find_package(DbusGlib REQUIRED)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")

View File

@ -27,8 +27,6 @@ set(${MODULE_PREFIX}_SRCS
include_directories(..)
find_package(libusb-1.0 REQUIRED)
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
@ -37,10 +35,9 @@ set(${MODULE_PREFIX}_LIBS
${CMAKE_THREAD_LIBS_INIT})
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}
${DBUS_GLIB_LIBRARIES}
${UUID_LIBRARIES}
${LIBUSB_1_LIBRARIES}
)
${DBUS_GLIB_LIBRARIES}
${UUID_LIBRARIES}
${LIBUSB_1_LIBRARIES})
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
@ -49,6 +46,5 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
if(NOT STATIC_CHANNELS)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH})
endif()
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -152,7 +152,7 @@ DWORD mac_client_update_thread(void* param)
}
ExitThread(0);
return NULL;
return 0;
}
DWORD mac_client_input_thread(void* param)
@ -177,7 +177,7 @@ DWORD mac_client_input_thread(void* param)
}
ExitThread(0);
return NULL;
return 0;
}
DWORD mac_client_channels_thread(void* param)
@ -214,7 +214,7 @@ DWORD mac_client_channels_thread(void* param)
}
ExitThread(0);
return NULL;
return 0;
}
DWORD mac_client_thread(void* param)

View File

@ -94,7 +94,7 @@ void tf_end_paint(rdpContext* context)
return;
}
int tf_receive_channel_data(freerdp* instance, int channelId, BYTE* data, int size, int flags, int total_size)
int tf_receive_channel_data(freerdp* instance, UINT16 channelId, BYTE* data, int size, int flags, int total_size)
{
return freerdp_channels_data(instance, channelId, data, size, flags, total_size);
}

View File

@ -21,6 +21,7 @@ set(MODULE_PREFIX "FREERDP_CLIENT_X11_CONTROL")
include(FindDocBookXSL)
include_directories(${X11_INCLUDE_DIRS})
include_directories(${OPENSSL_INCLUDE_DIR})
set(${MODULE_PREFIX}_SRCS
xf_gdi.c

View File

@ -841,7 +841,7 @@ BOOL xf_pre_connect(freerdp* instance)
fprintf(stderr, "--authonly, but no -p password. Please provide one.\n");
return FALSE;
}
fprintf(stderr, "%s:%d: Authentication only. Don't connect to X.\n", __FILE__, __LINE__);
fprintf(stderr, "Authentication only. Don't connect to X.\n");
/* Avoid XWindows initialization and configuration below. */
return TRUE;
}
@ -868,7 +868,7 @@ BOOL xf_pre_connect(freerdp* instance)
xfc->WM_DELETE_WINDOW = XInternAtom(xfc->display, "WM_DELETE_WINDOW", False);
xfc->WM_STATE = XInternAtom(xfc->display, "WM_STATE", False);
xf_kbd_init(xfc);
xf_keyboard_init(xfc);
xfc->clrconv = freerdp_clrconv_new(CLRCONV_ALPHA);
@ -972,10 +972,10 @@ BOOL xf_post_connect(freerdp* instance)
ZeroMemory(&gcv, sizeof(gcv));
if (xfc->modifier_map)
XFreeModifiermap(xfc->modifier_map);
if (xfc->modifierMap)
XFreeModifiermap(xfc->modifierMap);
xfc->modifier_map = XGetModifierMapping(xfc->display);
xfc->modifierMap = XGetModifierMapping(xfc->display);
xfc->gc = XCreateGC(xfc->display, xfc->drawable, GCGraphicsExposures, &gcv);
xfc->primary = XCreatePixmap(xfc->display, xfc->drawable, xfc->width, xfc->height, xfc->depth);
@ -1161,11 +1161,7 @@ void xf_window_free(xfContext* xfc)
{
rdpContext* context = (rdpContext*) xfc;
if (xfc->modifier_map)
{
XFreeModifiermap(xfc->modifier_map);
xfc->modifier_map = NULL;
}
xf_keyboard_free(xfc);
if (xfc->gc)
{
@ -1461,7 +1457,7 @@ void* xf_thread(void* param)
if (instance->settings->AuthenticationOnly)
{
freerdp_disconnect(instance);
fprintf(stderr, "%s:%d: Authentication only, exit status %d\n", __FILE__, __LINE__, !status);
fprintf(stderr, "Authentication only, exit status %d\n", !status);
ExitThread(exit_code);
}
@ -1515,8 +1511,8 @@ void* xf_thread(void* param)
*/
if (freerdp_focus_required(instance))
{
xf_kbd_focus_in(xfc);
xf_kbd_focus_in(xfc);
xf_keyboard_focus_in(xfc);
xf_keyboard_focus_in(xfc);
}
if (!async_transport)

View File

@ -87,6 +87,99 @@ const char* const X11_EVENT_STRINGS[] =
#define DEBUG_X11_LMS(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
int xf_event_action_script_init(xfContext* xfc)
{
int exitCode;
char* xevent;
FILE* actionScript;
char buffer[1024] = { 0 };
char command[1024] = { 0 };
xfc->xevents = ArrayList_New(TRUE);
ArrayList_Object(xfc->xevents)->fnObjectFree = free;
sprintf_s(command, sizeof(command), "%s xevent", xfc->actionScript);
actionScript = popen(command, "r");
if (actionScript < 0)
return -1;
while (fgets(buffer, sizeof(buffer), actionScript) != NULL)
{
strtok(buffer, "\n");
xevent = _strdup(buffer);
ArrayList_Add(xfc->xevents, xevent);
}
exitCode = pclose(actionScript);
return 1;
}
void xf_event_action_script_free(xfContext* xfc)
{
if (xfc->xevents)
{
ArrayList_Free(xfc->xevents);
xfc->xevents = NULL;
}
}
int xf_event_execute_action_script(xfContext* xfc, XEvent* event)
{
int index;
int count;
char* name;
int exitCode;
FILE* actionScript;
BOOL match = FALSE;
const char* xeventName;
char buffer[1024] = { 0 };
char command[1024] = { 0 };
if (!xfc->actionScript)
return 1;
if (event->type > (sizeof(X11_EVENT_STRINGS) / sizeof(const char*)))
return 1;
xeventName = X11_EVENT_STRINGS[event->type];
count = ArrayList_Count(xfc->xevents);
for (index = 0; index < count; index++)
{
name = (char*) ArrayList_GetItem(xfc->xevents, index);
if (_stricmp(name, xeventName) == 0)
{
match = TRUE;
break;
}
}
if (!match)
return 1;
sprintf_s(command, sizeof(command), "%s xevent %s %d",
xfc->actionScript, xeventName, (int) xfc->window->handle);
actionScript = popen(command, "r");
if (actionScript < 0)
return -1;
while (fgets(buffer, sizeof(buffer), actionScript) != NULL)
{
strtok(buffer, "\n");
}
exitCode = pclose(actionScript);
return 1;
}
static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app)
{
int x, y;
@ -395,34 +488,28 @@ static BOOL xf_event_KeyPress(xfContext* xfc, XEvent* event, BOOL app)
XLookupString((XKeyEvent*) event, str, sizeof(str), &keysym, NULL);
xf_kbd_set_keypress(xfc, event->xkey.keycode, keysym);
if (xfc->fullscreen_toggle && xf_kbd_handle_special_keys(xfc, keysym))
return TRUE;
xf_kbd_send_key(xfc, TRUE, event->xkey.keycode);
xf_keyboard_key_press(xfc, event->xkey.keycode, keysym);
return TRUE;
}
static BOOL xf_event_KeyRelease(xfContext* xfc, XEvent* event, BOOL app)
{
XEvent next_event;
XEvent nextEvent;
if (XPending(xfc->display))
{
ZeroMemory(&next_event, sizeof(next_event));
XPeekEvent(xfc->display, &next_event);
ZeroMemory(&nextEvent, sizeof(nextEvent));
XPeekEvent(xfc->display, &nextEvent);
if (next_event.type == KeyPress)
if (nextEvent.type == KeyPress)
{
if (next_event.xkey.keycode == event->xkey.keycode)
if (nextEvent.xkey.keycode == event->xkey.keycode)
return TRUE;
}
}
xf_kbd_unset_keypress(xfc, event->xkey.keycode);
xf_kbd_send_key(xfc, FALSE, event->xkey.keycode);
xf_keyboard_key_release(xfc, event->xkey.keycode);
return TRUE;
}
@ -451,7 +538,7 @@ static BOOL xf_event_FocusIn(xfContext* xfc, XEvent* event, BOOL app)
xf_rail_adjust_position(xfc, window);
}
xf_kbd_focus_in(xfc);
xf_keyboard_focus_in(xfc);
if (!app)
xf_cliprdr_check_owner(xfc);
@ -469,7 +556,7 @@ static BOOL xf_event_FocusOut(xfContext* xfc, XEvent* event, BOOL app)
if (event->xfocus.mode == NotifyWhileGrabbed)
XUngrabKeyboard(xfc->display, CurrentTime);
xf_kbd_clear(xfc);
xf_keyboard_clear(xfc);
if (app)
xf_rail_send_activate(xfc, event->xany.window, FALSE);
@ -481,10 +568,10 @@ static BOOL xf_event_MappingNotify(xfContext* xfc, XEvent* event, BOOL app)
{
if (event->xmapping.request == MappingModifier)
{
if (xfc->modifier_map)
XFreeModifiermap(xfc->modifier_map);
if (xfc->modifierMap)
XFreeModifiermap(xfc->modifierMap);
xfc->modifier_map = XGetModifierMapping(xfc->display);
xfc->modifierMap = XGetModifierMapping(xfc->display);
}
return TRUE;
@ -681,7 +768,7 @@ static BOOL xf_event_UnmapNotify(xfContext* xfc, XEvent* event, BOOL app)
rdpUpdate* update = xfc->instance->update;
rdpRail* rail = ((rdpContext*) xfc)->rail;
xf_kbd_release_all_keypress(xfc);
xf_keyboard_release_all_keypress(xfc);
if (!app)
{
@ -941,6 +1028,8 @@ BOOL xf_event_process(freerdp* instance, XEvent* event)
}
}
xf_event_execute_action_script(xfc, event);
if (event->type != MotionNotify)
DEBUG_X11("%s Event(%d): wnd=0x%04X", X11_EVENT_STRINGS[event->type], event->type, (UINT32) event->xany.window);

View File

@ -25,6 +25,9 @@
#include "xf_client.h"
#include "xfreerdp.h"
int xf_event_action_script_init(xfContext* xfc);
void xf_event_action_script_free(xfContext* xfc);
BOOL xf_event_process(freerdp* instance, XEvent* event);
void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, ...);

View File

@ -236,7 +236,6 @@ void xf_input_save_last_event(XGenericEventCookie* cookie)
lastEvent.detail = event->detail;
lastEvent.event_x = event->event_x;
lastEvent.event_y = event->event_y;
}
void xf_input_detect_pan(xfContext* xfc)
@ -269,13 +268,10 @@ void xf_input_detect_pan(xfContext* xfc)
dist_x = fabs(contacts[0].pos_x - contacts[1].pos_x);
dist_y = fabs(contacts[0].pos_y - contacts[1].pos_y);
//only pan in x if dist_y is greater than something
if(dist_y > MIN_FINGER_DIST)
if (dist_y > MIN_FINGER_DIST)
{
if(px_vector > PAN_THRESHOLD)
if (px_vector > PAN_THRESHOLD)
{
{
@ -293,7 +289,7 @@ void xf_input_detect_pan(xfContext* xfc)
py_vector = 0;
z_vector = 0;
}
else if(px_vector < -PAN_THRESHOLD)
else if (px_vector < -PAN_THRESHOLD)
{
{
PanningChangeEventArgs e;
@ -313,10 +309,10 @@ void xf_input_detect_pan(xfContext* xfc)
}
if(dist_x > MIN_FINGER_DIST)
if (dist_x > MIN_FINGER_DIST)
{
if(py_vector > PAN_THRESHOLD)
if (py_vector > PAN_THRESHOLD)
{
{
PanningChangeEventArgs e;
@ -333,7 +329,7 @@ void xf_input_detect_pan(xfContext* xfc)
py_vector = 0;
z_vector = 0;
}
else if(py_vector < -PAN_THRESHOLD)
else if (py_vector < -PAN_THRESHOLD)
{
{
PanningChangeEventArgs e;
@ -351,7 +347,6 @@ void xf_input_detect_pan(xfContext* xfc)
z_vector = 0;
}
}
}
void xf_input_detect_pinch(xfContext* xfc)
@ -368,7 +363,6 @@ void xf_input_detect_pinch(xfContext* xfc)
return;
}
/* first calculate the distance */
dist = sqrt(pow(contacts[1].pos_x - contacts[0].last_x, 2.0) +
pow(contacts[1].pos_y - contacts[0].last_y, 2.0));
@ -399,7 +393,6 @@ void xf_input_detect_pinch(xfContext* xfc)
z_vector += delta;
lastDist = dist;
if (z_vector > ZOOM_THRESHOLD)
@ -451,8 +444,6 @@ void xf_input_detect_pinch(xfContext* xfc)
void xf_input_touch_begin(xfContext* xfc, XIDeviceEvent* event)
{
int i;
if(active_contacts == MAX_CONTACTS)
printf("Houston, we have a problem!\n\n");
for (i = 0; i < MAX_CONTACTS; i++)
{
@ -472,6 +463,7 @@ void xf_input_touch_begin(xfContext* xfc, XIDeviceEvent* event)
void xf_input_touch_update(xfContext* xfc, XIDeviceEvent* event)
{
int i;
for (i = 0; i < MAX_CONTACTS; i++)
{
if (contacts[i].id == event->detail)
@ -493,14 +485,13 @@ void xf_input_touch_update(xfContext* xfc, XIDeviceEvent* event)
void xf_input_touch_end(xfContext* xfc, XIDeviceEvent* event)
{
int i;
for (i = 0; i < MAX_CONTACTS; i++)
{
if (contacts[i].id == event->detail)
{
contacts[i].id = 0;
contacts[i].count = 0;
//contacts[i].pos_x = (int)event->event_x;
//contacts[i].pos_y = (int)event->event_y;
active_contacts--;
break;printf("TouchBegin\n");
@ -733,15 +724,15 @@ void xf_process_rdpei_event(xfContext* xfc, wMessage* event)
int xf_input_handle_event(xfContext* xfc, XEvent* event)
{
#ifdef WITH_XI
//printf("m:%d g:%d\n", (xfc->settings->MultiTouchInput), (xfc->settings->MultiTouchGestures) );
if (xfc->settings->MultiTouchInput)
{
return xf_input_handle_event_remote(xfc, event);
}
if (xfc->settings->MultiTouchGestures)
{
return xf_input_handle_event_local(xfc, event);
}
#endif
return 0;

View File

@ -26,6 +26,8 @@
#include <string.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/collections.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
@ -33,66 +35,153 @@
#include <freerdp/locale/keyboard.h>
#include "xf_event.h"
#include "xf_keyboard.h"
void xf_kbd_init(xfContext* xfc)
int xf_keyboard_action_script_init(xfContext* xfc)
{
xf_kbd_clear(xfc);
int exitCode;
FILE* keyScript;
char* keyCombination;
char buffer[1024] = { 0 };
char command[1024] = { 0 };
xfc->keyboard_layout_id = xfc->instance->settings->KeyboardLayout;
xfc->keyboard_layout_id = freerdp_keyboard_init(xfc->keyboard_layout_id);
xfc->instance->settings->KeyboardLayout = xfc->keyboard_layout_id;
if (xfc->actionScript)
{
free(xfc->actionScript);
xfc->actionScript = NULL;
}
if (xfc->modifier_map)
XFreeModifiermap(xfc->modifier_map);
if (PathFileExistsA("/usr/share/freerdp/action.sh"))
xfc->actionScript = _strdup("/usr/share/freerdp/action.sh");
xfc->modifier_map = XGetModifierMapping(xfc->display);
if (!xfc->actionScript)
return 0;
xfc->keyCombinations = ArrayList_New(TRUE);
ArrayList_Object(xfc->keyCombinations)->fnObjectFree = free;
sprintf_s(command, sizeof(command), "%s key", xfc->actionScript);
keyScript = popen(command, "r");
if (keyScript < 0)
{
free(xfc->actionScript);
xfc->actionScript = NULL;
return 0;
}
while (fgets(buffer, sizeof(buffer), keyScript) != NULL)
{
strtok(buffer, "\n");
keyCombination = _strdup(buffer);
ArrayList_Add(xfc->keyCombinations, keyCombination);
}
exitCode = pclose(keyScript);
xf_event_action_script_init(xfc);
return 1;
}
void xf_kbd_clear(xfContext* xfc)
void xf_keyboard_action_script_free(xfContext* xfc)
{
ZeroMemory(xfc->pressed_keys, 256 * sizeof(BOOL));
xf_event_action_script_free(xfc);
if (xfc->keyCombinations)
{
ArrayList_Free(xfc->keyCombinations);
xfc->keyCombinations = NULL;
}
if (xfc->actionScript)
{
free(xfc->actionScript);
xfc->actionScript = NULL;
}
}
void xf_kbd_set_keypress(xfContext* xfc, BYTE keycode, KeySym keysym)
void xf_keyboard_init(xfContext* xfc)
{
if (keycode >= 8)
xfc->pressed_keys[keycode] = keysym;
else
xf_keyboard_clear(xfc);
xfc->KeyboardLayout = xfc->instance->settings->KeyboardLayout;
xfc->KeyboardLayout = freerdp_keyboard_init(xfc->KeyboardLayout);
xfc->instance->settings->KeyboardLayout = xfc->KeyboardLayout;
if (xfc->modifierMap)
XFreeModifiermap(xfc->modifierMap);
xfc->modifierMap = XGetModifierMapping(xfc->display);
xf_keyboard_action_script_init(xfc);
}
void xf_keyboard_free(xfContext* xfc)
{
if (xfc->modifierMap)
{
XFreeModifiermap(xfc->modifierMap);
xfc->modifierMap = NULL;
}
xf_keyboard_action_script_free(xfc);
}
void xf_keyboard_clear(xfContext* xfc)
{
ZeroMemory(xfc->KeyboardState, 256 * sizeof(BOOL));
}
void xf_keyboard_key_press(xfContext* xfc, BYTE keycode, KeySym keysym)
{
if (keycode < 8)
return;
}
void xf_kbd_unset_keypress(xfContext* xfc, BYTE keycode)
{
if (keycode >= 8)
xfc->pressed_keys[keycode] = NoSymbol;
else
xfc->KeyboardState[keycode] = keysym;
if (xf_keyboard_handle_special_keys(xfc, keysym))
return;
xf_keyboard_send_key(xfc, TRUE, keycode);
}
void xf_kbd_release_all_keypress(xfContext* xfc)
void xf_keyboard_key_release(xfContext* xfc, BYTE keycode)
{
if (keycode < 8)
return;
xfc->KeyboardState[keycode] = NoSymbol;
xf_keyboard_send_key(xfc, FALSE, keycode);
}
void xf_keyboard_release_all_keypress(xfContext* xfc)
{
int keycode;
DWORD rdp_scancode;
for (keycode = 0; keycode < ARRAYSIZE(xfc->pressed_keys); keycode++)
for (keycode = 0; keycode < ARRAYSIZE(xfc->KeyboardState); keycode++)
{
if (xfc->pressed_keys[keycode] != NoSymbol)
if (xfc->KeyboardState[keycode] != NoSymbol)
{
rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(keycode);
freerdp_input_send_keyboard_event_ex(xfc->instance->input, FALSE, rdp_scancode);
xfc->pressed_keys[keycode] = NoSymbol;
xfc->KeyboardState[keycode] = NoSymbol;
}
}
}
BOOL xf_kbd_key_pressed(xfContext* xfc, KeySym keysym)
BOOL xf_keyboard_key_pressed(xfContext* xfc, KeySym keysym)
{
KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
return (xfc->pressed_keys[keycode] == keysym);
return (xfc->KeyboardState[keycode] == keysym);
}
void xf_kbd_send_key(xfContext* xfc, BOOL down, BYTE keycode)
void xf_keyboard_send_key(xfContext* xfc, BOOL down, BYTE keycode)
{
DWORD rdp_scancode;
rdpInput* input;
@ -105,7 +194,7 @@ void xf_kbd_send_key(xfContext* xfc, BOOL down, BYTE keycode)
fprintf(stderr, "Unknown key with X keycode 0x%02x\n", keycode);
}
else if (rdp_scancode == RDP_SCANCODE_PAUSE &&
!xf_kbd_key_pressed(xfc, XK_Control_L) && !xf_kbd_key_pressed(xfc, XK_Control_R))
!xf_keyboard_key_pressed(xfc, XK_Control_L) && !xf_keyboard_key_pressed(xfc, XK_Control_R))
{
/* Pause without Ctrl has to be sent as Ctrl + NumLock. */
if (down)
@ -123,13 +212,13 @@ void xf_kbd_send_key(xfContext* xfc, BOOL down, BYTE keycode)
if ((rdp_scancode == RDP_SCANCODE_CAPSLOCK) && (down == FALSE))
{
UINT32 syncFlags;
syncFlags = xf_kbd_get_toggle_keys_state(xfc);
syncFlags = xf_keyboard_get_toggle_keys_state(xfc);
input->SynchronizeEvent(input, syncFlags);
}
}
}
int xf_kbd_read_keyboard_state(xfContext* xfc)
int xf_keyboard_read_keyboard_state(xfContext* xfc)
{
int dummy;
Window wdummy;
@ -145,10 +234,11 @@ int xf_kbd_read_keyboard_state(xfContext* xfc)
XQueryPointer(xfc->display, DefaultRootWindow(xfc->display),
&wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
}
return state;
}
BOOL xf_kbd_get_key_state(xfContext* xfc, int state, int keysym)
BOOL xf_keyboard_get_key_state(xfContext* xfc, int state, int keysym)
{
int offset;
int modifierpos, key, keysymMask = 0;
@ -159,11 +249,11 @@ BOOL xf_kbd_get_key_state(xfContext* xfc, int state, int keysym)
for (modifierpos = 0; modifierpos < 8; modifierpos++)
{
offset = xfc->modifier_map->max_keypermod * modifierpos;
offset = xfc->modifierMap->max_keypermod * modifierpos;
for (key = 0; key < xfc->modifier_map->max_keypermod; key++)
for (key = 0; key < xfc->modifierMap->max_keypermod; key++)
{
if (xfc->modifier_map->modifiermap[offset + key] == keycode)
if (xfc->modifierMap->modifiermap[offset + key] == keycode)
{
keysymMask |= 1 << modifierpos;
}
@ -173,26 +263,26 @@ BOOL xf_kbd_get_key_state(xfContext* xfc, int state, int keysym)
return (state & keysymMask) ? TRUE : FALSE;
}
int xf_kbd_get_toggle_keys_state(xfContext* xfc)
UINT32 xf_keyboard_get_toggle_keys_state(xfContext* xfc)
{
int state;
int toggle_keys_state = 0;
UINT32 toggleKeysState = 0;
state = xf_kbd_read_keyboard_state(xfc);
state = xf_keyboard_read_keyboard_state(xfc);
if (xf_kbd_get_key_state(xfc, state, XK_Scroll_Lock))
toggle_keys_state |= KBD_SYNC_SCROLL_LOCK;
if (xf_kbd_get_key_state(xfc, state, XK_Num_Lock))
toggle_keys_state |= KBD_SYNC_NUM_LOCK;
if (xf_kbd_get_key_state(xfc, state, XK_Caps_Lock))
toggle_keys_state |= KBD_SYNC_CAPS_LOCK;
if (xf_kbd_get_key_state(xfc, state, XK_Kana_Lock))
toggle_keys_state |= KBD_SYNC_KANA_LOCK;
if (xf_keyboard_get_key_state(xfc, state, XK_Scroll_Lock))
toggleKeysState |= KBD_SYNC_SCROLL_LOCK;
if (xf_keyboard_get_key_state(xfc, state, XK_Num_Lock))
toggleKeysState |= KBD_SYNC_NUM_LOCK;
if (xf_keyboard_get_key_state(xfc, state, XK_Caps_Lock))
toggleKeysState |= KBD_SYNC_CAPS_LOCK;
if (xf_keyboard_get_key_state(xfc, state, XK_Kana_Lock))
toggleKeysState |= KBD_SYNC_KANA_LOCK;
return toggle_keys_state;
return toggleKeysState;
}
void xf_kbd_focus_in(xfContext* xfc)
void xf_keyboard_focus_in(xfContext* xfc)
{
rdpInput* input;
UINT32 syncFlags;
@ -200,39 +290,141 @@ void xf_kbd_focus_in(xfContext* xfc)
Window wdummy;
UINT32 state = 0;
if (xfc->display && xfc->window)
{
input = xfc->instance->input;
syncFlags = xf_kbd_get_toggle_keys_state(xfc);
XQueryPointer(xfc->display, xfc->window->handle, &wdummy, &wdummy, &mouseX, &mouseY, &dummy, &dummy, &state);
input->FocusInEvent(input, syncFlags, mouseX, mouseY);
if (xfc->display && xfc->window)
{
input = xfc->instance->input;
syncFlags = xf_keyboard_get_toggle_keys_state(xfc);
XQueryPointer(xfc->display, xfc->window->handle, &wdummy, &wdummy, &mouseX, &mouseY, &dummy, &dummy, &state);
input->FocusInEvent(input, syncFlags, mouseX, mouseY);
}
}
BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
int xf_keyboard_execute_action_script(xfContext* xfc, XF_MODIFIER_KEYS* mod, KeySym keysym)
{
int index;
int count;
int exitCode;
int status = 1;
FILE* keyScript;
const char* keyStr;
BOOL match = FALSE;
char* keyCombination;
char buffer[1024] = { 0 };
char command[1024] = { 0 };
char combination[1024] = { 0 };
if (!xfc->actionScript)
return 1;
if ((keysym == XK_Shift_L) || (keysym == XK_Shift_R) ||
(keysym == XK_Alt_L) || (keysym == XK_Alt_R) ||
(keysym == XK_Control_L) || (keysym == XK_Control_R))
{
return 1;
}
keyStr = XKeysymToString(keysym);
if (mod->Shift)
strcat(combination, "Shift+");
if (mod->Ctrl)
strcat(combination, "Ctrl+");
if (mod->Alt)
strcat(combination, "Alt+");
strcat(combination, keyStr);
count = ArrayList_Count(xfc->keyCombinations);
for (index = 0; index < count; index++)
{
keyCombination = (char*) ArrayList_GetItem(xfc->keyCombinations, index);
if (_stricmp(keyCombination, combination) == 0)
{
match = TRUE;
break;
}
}
if (!match)
return 1;
sprintf_s(command, sizeof(command), "%s key %s",
xfc->actionScript, combination);
keyScript = popen(command, "r");
if (keyScript < 0)
return -1;
while (fgets(buffer, sizeof(buffer), keyScript) != NULL)
{
strtok(buffer, "\n");
if (strcmp(buffer, "key-local") == 0)
status = 0;
}
exitCode = pclose(keyScript);
return status;
}
int xk_keyboard_get_modifier_keys(xfContext* xfc, XF_MODIFIER_KEYS* mod)
{
mod->LeftShift = xf_keyboard_key_pressed(xfc, XK_Shift_L);
mod->RightShift = xf_keyboard_key_pressed(xfc, XK_Shift_R);
mod->Shift = mod->LeftShift || mod->RightShift;
mod->LeftAlt = xf_keyboard_key_pressed(xfc, XK_Alt_L);
mod->RightAlt = xf_keyboard_key_pressed(xfc, XK_Alt_R);
mod->Alt = mod->LeftAlt || mod->RightAlt;
mod->LeftCtrl = xf_keyboard_key_pressed(xfc, XK_Control_L);
mod->RightCtrl = xf_keyboard_key_pressed(xfc, XK_Control_R);
mod->Ctrl = mod->LeftCtrl || mod->RightCtrl;
mod->LeftSuper = xf_keyboard_key_pressed(xfc, XK_Super_L);
mod->RightSuper = xf_keyboard_key_pressed(xfc, XK_Super_R);
mod->Super = mod->LeftSuper || mod->RightSuper;
return 0;
}
BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym)
{
XF_MODIFIER_KEYS mod = { 0 };
xk_keyboard_get_modifier_keys(xfc, &mod);
if (!xf_keyboard_execute_action_script(xfc, &mod, keysym))
{
return TRUE;
}
if (keysym == XK_Return)
{
if ((xf_kbd_key_pressed(xfc, XK_Alt_L) || xf_kbd_key_pressed(xfc, XK_Alt_R))
&& (xf_kbd_key_pressed(xfc, XK_Control_L) || xf_kbd_key_pressed(xfc, XK_Control_R)))
if (mod.Ctrl && mod.Alt)
{
/* Ctrl-Alt-Enter: toggle full screen */
xf_toggle_fullscreen(xfc);
return TRUE;
}
}
if (keysym == XK_period)
{
if ((xf_kbd_key_pressed(xfc, XK_Alt_L)
|| xf_kbd_key_pressed(xfc, XK_Alt_R))
&& (xf_kbd_key_pressed(xfc, XK_Control_L)
|| xf_kbd_key_pressed(xfc,
XK_Control_R)))
if (mod.Ctrl && mod.Alt)
{
//Zoom in (scale larger)
/* Zoom In (scale larger) */
double s = xfc->settings->ScalingFactor;
s += 0.1;
if (s > 2.0)
s = 2.0;
@ -258,15 +450,14 @@ BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
if (keysym == XK_comma)
{
if ((xf_kbd_key_pressed(xfc, XK_Alt_L)
|| xf_kbd_key_pressed(xfc, XK_Alt_R))
&& (xf_kbd_key_pressed(xfc, XK_Control_L)
|| xf_kbd_key_pressed(xfc,
XK_Control_R)))
if (mod.Ctrl && mod.Alt)
{
//Zoom out (scale smaller)
/* Zoom Out (scale smaller) */
double s = xfc->settings->ScalingFactor;
s -= 0.1;
if (s < 0.5)
s = 0.5;
@ -293,11 +484,7 @@ BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
if (keysym == XK_KP_4)
{
if ((xf_kbd_key_pressed(xfc, XK_Alt_L)
|| xf_kbd_key_pressed(xfc, XK_Alt_R))
&& (xf_kbd_key_pressed(xfc, XK_Control_L)
|| xf_kbd_key_pressed(xfc,
XK_Control_R)))
if (mod.Ctrl && mod.Alt)
{
{
@ -315,11 +502,7 @@ BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
if (keysym == XK_KP_6)
{
if ((xf_kbd_key_pressed(xfc, XK_Alt_L)
|| xf_kbd_key_pressed(xfc, XK_Alt_R))
&& (xf_kbd_key_pressed(xfc, XK_Control_L)
|| xf_kbd_key_pressed(xfc,
XK_Control_R)))
if (mod.Ctrl && mod.Alt)
{
{
@ -336,11 +519,7 @@ BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
if (keysym == XK_KP_8)
{
if ((xf_kbd_key_pressed(xfc, XK_Alt_L)
|| xf_kbd_key_pressed(xfc, XK_Alt_R))
&& (xf_kbd_key_pressed(xfc, XK_Control_L)
|| xf_kbd_key_pressed(xfc,
XK_Control_R)))
if (mod.Ctrl && mod.Alt)
{
{
PanningChangeEventArgs e;
@ -356,11 +535,7 @@ BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
if (keysym == XK_KP_2)
{
if ((xf_kbd_key_pressed(xfc, XK_Alt_L)
|| xf_kbd_key_pressed(xfc, XK_Alt_R))
&& (xf_kbd_key_pressed(xfc, XK_Control_L)
|| xf_kbd_key_pressed(xfc,
XK_Control_R)))
if (mod.Ctrl && mod.Alt)
{
{
PanningChangeEventArgs e;
@ -374,7 +549,6 @@ BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
}
}
return FALSE;
}

View File

@ -25,17 +25,37 @@
#include "xf_client.h"
#include "xfreerdp.h"
void xf_kbd_init(xfContext* xfc);
void xf_kbd_clear(xfContext* xfc);
void xf_kbd_set_keypress(xfContext* xfc, BYTE keycode, KeySym keysym);
void xf_kbd_unset_keypress(xfContext* xfc, BYTE keycode);
void xf_kbd_release_all_keypress(xfContext* xfc);
BOOL xf_kbd_key_pressed(xfContext* xfc, KeySym keysym);
void xf_kbd_send_key(xfContext* xfc, BOOL down, BYTE keycode);
int xf_kbd_read_keyboard_state(xfContext* xfc);
BOOL xf_kbd_get_key_state(xfContext* xfc, int state, int keysym);
int xf_kbd_get_toggle_keys_state(xfContext* xfc);
void xf_kbd_focus_in(xfContext* xfc);
BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym);
#define XF_ACTION_SCRIPT "~/.config/freerdp/action.sh"
struct _XF_MODIFIER_KEYS
{
BOOL Shift;
BOOL LeftShift;
BOOL RightShift;
BOOL Alt;
BOOL LeftAlt;
BOOL RightAlt;
BOOL Ctrl;
BOOL LeftCtrl;
BOOL RightCtrl;
BOOL Super;
BOOL LeftSuper;
BOOL RightSuper;
};
typedef struct _XF_MODIFIER_KEYS XF_MODIFIER_KEYS;
void xf_keyboard_init(xfContext* xfc);
void xf_keyboard_free(xfContext* xfc);
void xf_keyboard_clear(xfContext* xfc);
void xf_keyboard_key_press(xfContext* xfc, BYTE keycode, KeySym keysym);
void xf_keyboard_key_release(xfContext* xfc, BYTE keycode);
void xf_keyboard_release_all_keypress(xfContext* xfc);
BOOL xf_keyboard_key_pressed(xfContext* xfc, KeySym keysym);
void xf_keyboard_send_key(xfContext* xfc, BOOL down, BYTE keycode);
int xf_keyboard_read_keyboard_state(xfContext* xfc);
BOOL xf_keyboard_get_key_state(xfContext* xfc, int state, int keysym);
UINT32 xf_keyboard_get_toggle_keys_state(xfContext* xfc);
void xf_keyboard_focus_in(xfContext* xfc);
BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym);
#endif /* __XF_KEYBOARD_H */

View File

@ -125,9 +125,13 @@ struct xf_context
BOOL mouse_active;
BOOL suppress_output;
BOOL fullscreen_toggle;
UINT32 keyboard_layout_id;
BOOL pressed_keys[256];
XModifierKeymap* modifier_map;
UINT32 KeyboardLayout;
BOOL KeyboardState[256];
XModifierKeymap* modifierMap;
wArrayList* keyCombinations;
wArrayList* xevents;
char* actionScript;
XSetWindowAttributes attribs;
BOOL complex_regions;
VIRTUAL_SCREEN vscreen;

View File

@ -71,4 +71,4 @@ set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Common")
if(BUILD_TESTING)
add_subdirectory(test)
endif()
export_complex_library(LIBNAME ${MODULE_NAME})

View File

@ -56,6 +56,7 @@ COMMAND_LINE_ARGUMENT_A args[] =
{ "pth", COMMAND_LINE_VALUE_REQUIRED, "<password hash>", NULL, NULL, -1, "pass-the-hash", "Pass the hash (restricted admin mode)" },
{ "client-hostname", COMMAND_LINE_VALUE_REQUIRED, "<name>", NULL, NULL, -1, NULL, "Client Hostname to send to server" },
{ "multimon", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Use multiple monitors" },
{ "span", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Span screen over multiple monitors" },
{ "workarea", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Use available work area" },
{ "monitors", COMMAND_LINE_VALUE_REQUIRED, "<0,1,2...>", NULL, NULL, -1, NULL, "Select monitors to use" },
{ "monitor-list", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT, NULL, NULL, NULL, -1, NULL, "List detected monitors" },
@ -92,8 +93,8 @@ COMMAND_LINE_ARGUMENT_A args[] =
{ "drives", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect all drives" },
{ "home-drive", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect home drive" },
{ "clipboard", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect clipboard" },
{ "serial", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, "tty", "Redirect serial device" },
{ "parallel", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect parallel device" },
{ "serial", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, "tty", "Redirect serial device" },
{ "parallel", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Redirect parallel device" },
{ "smartcard", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Redirect smartcard device" },
{ "printer", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Redirect printer device" },
{ "usb", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect USB device" },
@ -296,12 +297,18 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p
if (count < 3)
return -1;
drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE));
ZeroMemory(drive, sizeof(RDPDR_DRIVE));
drive = (RDPDR_DRIVE*) calloc(1, sizeof(RDPDR_DRIVE));
if (!drive)
return -1;
drive->Type = RDPDR_DTYP_FILESYSTEM;
drive->Name = _strdup(params[1]);
drive->Path = _strdup(params[2]);
if (count > 1)
drive->Name = _strdup(params[1]);
if (count > 2)
drive->Path = _strdup(params[2]);
freerdp_device_collection_add(settings, (RDPDR_DEVICE*) drive);
settings->DeviceRedirection = TRUE;
@ -315,8 +322,10 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p
if (count < 1)
return -1;
printer = (RDPDR_PRINTER*) malloc(sizeof(RDPDR_PRINTER));
ZeroMemory(printer, sizeof(RDPDR_PRINTER));
printer = (RDPDR_PRINTER*) calloc(1, sizeof(RDPDR_PRINTER));
if (!printer)
return -1;
printer->Type = RDPDR_DTYP_PRINT;
@ -338,12 +347,16 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p
if (count < 1)
return -1;
smartcard = (RDPDR_SMARTCARD*) malloc(sizeof(RDPDR_SMARTCARD));
ZeroMemory(smartcard, sizeof(RDPDR_SMARTCARD));
smartcard = (RDPDR_SMARTCARD*) calloc(1, sizeof(RDPDR_SMARTCARD));
if (!smartcard)
return -1;
smartcard->Type = RDPDR_DTYP_SMARTCARD;
if (count > 1)
smartcard->Name = _strdup(params[1]);
if (count > 2)
smartcard->Path = _strdup(params[2]);
@ -359,12 +372,16 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p
if (count < 1)
return -1;
serial = (RDPDR_SERIAL*) malloc(sizeof(RDPDR_SERIAL));
ZeroMemory(serial, sizeof(RDPDR_SERIAL));
serial = (RDPDR_SERIAL*) calloc(1, sizeof(RDPDR_SERIAL));
if (!serial)
return -1;
serial->Type = RDPDR_DTYP_SERIAL;
if (count > 1)
serial->Name = _strdup(params[1]);
if (count > 2)
serial->Path = _strdup(params[2]);
@ -380,13 +397,17 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p
if (count < 1)
return -1;
parallel = (RDPDR_PARALLEL*) malloc(sizeof(RDPDR_PARALLEL));
ZeroMemory(parallel, sizeof(RDPDR_PARALLEL));
parallel = (RDPDR_PARALLEL*) calloc(1, sizeof(RDPDR_PARALLEL));
if (!parallel)
return -1;
parallel->Type = RDPDR_DTYP_PARALLEL;
if (count > 1)
parallel->Name = _strdup(params[1]);
if (count > 1)
if (count > 2)
parallel->Path = _strdup(params[2]);
freerdp_device_collection_add(settings, (RDPDR_DEVICE*) parallel);
@ -1188,13 +1209,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
{
settings->Fullscreen = TRUE;
}
CommandLineSwitchCase(arg, "span")
{
settings->SpanMonitors = TRUE;
}
CommandLineSwitchCase(arg, "multimon")
{
settings->UseMultimon = TRUE;
settings->SpanMonitors = FALSE;
settings->Fullscreen = TRUE;
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
@ -1205,6 +1223,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
}
}
}
CommandLineSwitchCase(arg, "span")
{
settings->UseMultimon = TRUE;
settings->SpanMonitors = TRUE;
settings->Fullscreen = TRUE;
}
CommandLineSwitchCase(arg, "workarea")
{
settings->Workarea = TRUE;
@ -1345,9 +1369,11 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
settings->GatewayHostname = _strdup(settings->ServerHostname);
}
settings->GatewayUsageMethod = TSC_PROXY_MODE_DIRECT;
settings->GatewayUseSameCredentials = TRUE;
settings->GatewayUsageMethod = TSC_PROXY_MODE_DETECT;
settings->GatewayEnabled = TRUE;
settings->GatewayBypassLocal = TRUE;
}
CommandLineSwitchCase(arg, "gu")
{
@ -1575,7 +1601,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
settings->NlaSecurity = FALSE;
settings->ExtSecurity = FALSE;
settings->DisableEncryption = TRUE;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT| ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
}
else if (strcmp("tls", arg->Value) == 0) /* TLS */

View File

@ -693,7 +693,7 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
settings->TlsSecurity = FALSE;
settings->NlaSecurity = FALSE;
settings->DisableEncryption = FALSE;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
}
else if (strncmp("tls", arg->Value, 1) == 0) /* TLS */

View File

@ -674,6 +674,7 @@ BOOL freerdp_client_write_rdp_file(const rdpFile* file, const char* name, BOOL u
if (freerdp_client_write_rdp_file_buffer(file, buffer, length + 1) != length)
{
fprintf(stderr, "freerdp_client_write_rdp_file: error writing to output buffer\n");
free(buffer);
return FALSE;
}
@ -863,18 +864,7 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
freerdp_set_param_string(settings, FreeRDP_GatewayHostname, file->GatewayHostname);
if (~file->GatewayUsageMethod)
{
freerdp_set_param_uint32(settings, FreeRDP_GatewayUsageMethod, file->GatewayUsageMethod);
if (file->GatewayUsageMethod == TSC_PROXY_MODE_DIRECT)
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE);
else if (file->GatewayUsageMethod == TSC_PROXY_MODE_DETECT)
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE);
else if (file->GatewayUsageMethod == TSC_PROXY_MODE_DEFAULT)
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE);
else if (file->GatewayUsageMethod == TSC_PROXY_MODE_NONE_DETECT)
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, FALSE);
}
freerdp_set_gateway_usage_method(settings, settings->GatewayUsageMethod);
if (~file->PromptCredentialOnce)
freerdp_set_param_bool(settings, FreeRDP_GatewayUseSameCredentials, file->PromptCredentialOnce);

View File

@ -57,7 +57,7 @@
AdvancedKeyboardView* _advanced_keyboard_view;
BOOL _advanced_keyboard_visible;
BOOL _requesting_advanced_keyboard;
CGFloat _keyboard_height_delta;
CGFloat _keyboard_last_height;
// delayed mouse move event sending
NSTimer* _mouse_move_event_timer;

View File

@ -51,7 +51,7 @@
_advanced_keyboard_view = nil;
_advanced_keyboard_visible = NO;
_requesting_advanced_keyboard = NO;
_keyboard_height_delta = 0;
_keyboard_last_height = 0;
_session_toolbar_visible = NO;
@ -549,25 +549,46 @@
#pragma mark -
#pragma mark iOS Keyboard Notification Handlers
- (void)keyboardWillShow:(NSNotification *)notification
{
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboardFrame = [[self view] convertRect:keyboardEndFrame toView:nil];
// the keyboard is given in a portrait frame of reference
- (BOOL)isLandscape {
UIInterfaceOrientation ori = [[UIApplication sharedApplication] statusBarOrientation];
return ( ori == UIInterfaceOrientationLandscapeLeft || ori == UIInterfaceOrientationLandscapeRight );
}
CGFloat newHeightDelta = (keyboardFrame.size.height - _keyboard_height_delta);
if (newHeightDelta < 0.1 && newHeightDelta > -0.1)
return; // nothing changed
[UIView beginAnimations:nil context:NULL];
- (void)shiftKeyboard: (NSNotification*)notification {
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat previousHeight = _keyboard_last_height;
if( [self isLandscape] ) {
// landscape has the keyboard based on x, so x can go negative
_keyboard_last_height = keyboardEndFrame.size.width + keyboardEndFrame.origin.x;
} else {
// portrait has the keyboard based on the difference of the height and the frames y.
CGFloat height = [[UIScreen mainScreen] bounds].size.height;
_keyboard_last_height = height - keyboardEndFrame.origin.y;
}
CGFloat shiftHeight = _keyboard_last_height - previousHeight;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
CGRect frame = [_session_scrollview frame];
frame.size.height -= newHeightDelta;
_keyboard_height_delta += newHeightDelta;
frame.size.height -= shiftHeight;
[_session_scrollview setFrame:frame];
[_touchpointer_view setFrame:frame];
[_touchpointer_view setFrame:frame];
[UIView commitAnimations];
}
- (void)keyboardWillShow:(NSNotification *)notification
{
[self shiftKeyboard: notification];
[_touchpointer_view ensurePointerIsVisible];
}
@ -583,17 +604,9 @@
- (void)keyboardWillHide:(NSNotification *)notification
{
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
CGRect frame = [_session_scrollview frame];
frame.size.height += [[self view] convertRect:keyboardEndFrame toView:nil].size.height;
[_session_scrollview setFrame:frame];
[_touchpointer_view setFrame:frame];
[UIView commitAnimations];
_keyboard_height_delta = 0;
[self shiftKeyboard: notification];
}
- (void)keyboardDidHide:(NSNotification*)notification

View File

@ -31,12 +31,45 @@ macro(set_complex_link_libraries)
endmacro(set_complex_link_libraries)
# - add a new library to a module for export
# MODULE - module the library belongs to
# LIBNAME - name of the library
# - if MODULE isn't set the NAME should must be in the form MODULE-NAME
function(export_complex_library)
set(PREFIX "EXPORT_COMPLEX_LIBRARY")
cmake_parse_arguments(${PREFIX}
""
"LIBNAME;MODULE"
""
${ARGN})
if (NOT ${PREFIX}_LIBNAME)
message(FATAL_ERROR "export_complex_library requires a name to be set")
endif()
if (NOT ${PREFIX}_MODULE)
# get the module prefix and remove it from libname
string(REPLACE "-" ";" LIBNAME_LIST "${${PREFIX}_LIBNAME}")
list(GET LIBNAME_LIST 0 MODULE)
list(REMOVE_AT LIBNAME_LIST 0)
string(REPLACE ";" "-" LIBNAME "${LIBNAME_LIST}")
else()
set(MODULE ${${PREFIX}_MODULE})
set(LIBNAME ${${PREFIX}_LIBNAME})
endif()
if (NOT MODULE)
message(FATAL_ERROR "export_complex_library couldn't identify MODULE")
endif()
get_property(MEXPORTS GLOBAL PROPERTY ${MODULE}_EXPORTS)
list(APPEND MEXPORTS ${LIBNAME})
set_property(GLOBAL PROPERTY ${MODULE}_EXPORTS "${MEXPORTS}")
endfunction(export_complex_library)
macro(add_complex_library)
set(PREFIX "COMPLEX_LIBRARY")
cmake_parse_arguments(${PREFIX}
""
"EXPORT"
"MODULE;TYPE;MONOLITHIC"
"SOURCES"
${ARGN})
@ -46,6 +79,9 @@ macro(add_complex_library)
else()
add_library(${${PREFIX}_MODULE} ${${PREFIX}_SOURCES})
endif()
if (${PREFIX}_EXPORT)
export_complex_library(LIBNAME ${${PREFIX}_MODULE})
endif()
endmacro(add_complex_library)

View File

@ -35,4 +35,8 @@ include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(dbus-glib DEFAULT_MSG
DBUS_GLIB_LIBRARY DBUS_GLIB_INCLUDE_DIR)
mark_as_advanced(DBUS_GLIB_INCLUDE_DIR DBUS_GLIB_LIBRARY )
if(DBUS_GLIB_LIBRARIES AND DBUS_GLIB_INCLUDE_DIRS)
set(DBUS_GLIB_FOUND TRUE)
endif()
mark_as_advanced(DBUS_GLIB_INCLUDE_DIR DBUS_GLIB_LIBRARY)

View File

@ -5,16 +5,17 @@
# PCSC_LIBRARIES - libraries needed for linking
include(FindPkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(PC_PCSC QUIET libpcsclite)
if(PKG_CONFIG_FOUND)
pkg_check_modules(PC_PCSC QUIET libpcsclite)
endif()
find_path(PCSC_INCLUDE_DIR pcsclite.h WinSCard.h
HINTS ${PC_PCSC_INCLUDEDIR} ${PC_PCSC_INCLUDE_DIRS}
PATH_SUFFIXES PCSC)
HINTS ${PC_PCSC_INCLUDEDIR} ${PC_PCSC_INCLUDE_DIRS}
PATH_SUFFIXES PCSC)
find_library(PCSC_LIBRARY NAMES PCSC WinSCard pcsclite
HINTS ${PC_PCSC_LIBDIR} ${PC_PCSC_LIBRARY_DIRS})
HINTS ${PC_PCSC_LIBDIR} ${PC_PCSC_LIBRARY_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PCSC DEFAULT_MSG PCSC_LIBRARY PCSC_INCLUDE_DIR)
@ -24,3 +25,4 @@ set(PCSC_INCLUDE_DIRS ${PCSC_INCLUDE_DIR})
mark_as_advanced(PCSC_INCLUDE_DIR PCSC_LIBRARY)

15
cmake/FindPCSCWinPR.cmake Normal file
View File

@ -0,0 +1,15 @@
find_library(PCSC_WINPR_LIBRARY
NAMES libpcsc-winpr.a
PATHS
/opt/lib
/usr/lib
/usr/local/lib
)
if(NOT ${PCSC_WINPR_LIBRARY} MATCHES ".*-NOTFOUND")
set(PCSC_WINPR_FOUND 1)
message(STATUS "Found PCSC-WinPR: ${PCSC_WINPR_LIBRARY}")
endif()
mark_as_advanced(PCSC_WINPR_LIBRARY)

View File

@ -9,5 +9,7 @@ Description: FreeRDP: A Remote Desktop Protocol Implementation
URL: http://www.freerdp.com/
Version: @FREERDP_VERSION_FULL@
Requires:
Requires.private: winpr zlib libssl
Libs: -L${libdir} ${libs}
Libs.private: -ldl -lpthread
Cflags: -I${includedir}

View File

@ -32,7 +32,12 @@
#include <winpr/collections.h>
#include <freerdp/freerdp.h>
#include <freerdp/utils/list.h>
#define RDPDR_DEVICE_IO_REQUEST_LENGTH 24
#define RDPDR_DEVICE_IO_RESPONSE_LENGTH 16
#define RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH 32
#define RDPDR_DEVICE_IO_CONTROL_RSP_HDR_LENGTH 4
/* RDPDR_HEADER.Component */
enum RDPDR_CTYP
@ -206,34 +211,36 @@ enum RDPDR_PRINTER_ANNOUNCE_FLAG
#endif
/* [MS-FSCC] FSCTL Structures */
enum FSCTL_STRUCTURE
{
FSCTL_CREATE_OR_GET_OBJECT_ID = 0x900c0,
FSCTL_GET_REPARSE_POINT = 0x900a8,
FSCTL_GET_RETRIEVAL_POINTERS = 0x90073,
FSCTL_IS_PATHNAME_VALID = 0x9002c,
FSCTL_LMR_SET_LINK_TRACKING_INFORMATION = 0x1400ec,
FSCTL_PIPE_PEEK = 0x11400c,
FSCTL_PIPE_TRANSCEIVE = 0x11c017,
FSCTL_PIPE_WAIT = 0x110018,
FSCTL_QUERY_FAT_BPB = 0x90058,
FSCTL_QUERY_ALLOCATED_RANGES = 0x940cf,
FSCTL_QUERY_ON_DISK_VOLUME_INFO = 0x9013c,
FSCTL_QUERY_SPARING_INFO = 0x90138,
FSCTL_READ_FILE_USN_DATA = 0x900eb,
FSCTL_RECALL_FILE = 0x90117,
FSCTL_SET_COMPRESSION = 0x9c040,
FSCTL_SET_DEFECT_MANAGEMENT = 0x98134,
FSCTL_SET_ENCRYPTION = 0x900D7,
FSCTL_SET_OBJECT_ID = 0x90098,
FSCTL_SET_OBJECT_ID_EXTENDED = 0x900bc,
FSCTL_SET_REPARSE_POINT = 0x900a4,
FSCTL_SET_SPARSE = 0x900c4,
FSCTL_SET_ZERO_DATA = 0x980c8,
FSCTL_SET_ZERO_ON_DEALLOCATION = 0x90194,
FSCTL_SIS_COPYFILE = 0x90100,
FSCTL_WRITE_USN_CLOSE_RECORD = 0x900ef
};
#define FSCTL_LMR_SET_LINK_TRACKING_INFORMATION 0x1400ec
#define FSCTL_PIPE_PEEK 0x11400c
#define FSCTL_PIPE_TRANSCEIVE 0x11c017
#define FSCTL_PIPE_WAIT 0x110018
#define FSCTL_QUERY_ON_DISK_VOLUME_INFO 0x9013c
#define FSCTL_QUERY_SPARING_INFO 0x90138
#ifndef _WIN32
#define FSCTL_CREATE_OR_GET_OBJECT_ID 0x900c0
#define FSCTL_GET_REPARSE_POINT 0x900a8
#define FSCTL_GET_RETRIEVAL_POINTERS 0x90073
#define FSCTL_IS_PATHNAME_VALID 0x9002c
#define FSCTL_READ_FILE_USN_DATA 0x900eb
#define FSCTL_RECALL_FILE 0x90117
#define FSCTL_QUERY_FAT_BPB 0x90058
#define FSCTL_QUERY_ALLOCATED_RANGES 0x940cf
#define FSCTL_SET_COMPRESSION 0x9c040
#define FSCTL_SET_ENCRYPTION 0x900D7
#define FSCTL_SET_OBJECT_ID 0x90098
#define FSCTL_SET_OBJECT_ID_EXTENDED 0x900bc
#define FSCTL_SET_REPARSE_POINT 0x900a4
#define FSCTL_SET_SPARSE 0x900c4
#define FSCTL_SET_ZERO_DATA 0x980c8
#define FSCTL_SIS_COPYFILE 0x90100
#define FSCTL_WRITE_USN_CLOSE_RECORD 0x900ef
#endif
#define FSCTL_SET_DEFECT_MANAGEMENT 0x98134
#define FSCTL_SET_ZERO_ON_DEALLOCATION 0x90194
/* [MS-FSCC] FileFsAttributeInformation.FileSystemAttributes */
@ -304,6 +311,7 @@ typedef struct _IRP IRP;
typedef struct _DEVMAN DEVMAN;
typedef void (*pcIRPRequest)(DEVICE* device, IRP* irp);
typedef void (*pcInitDevice)(DEVICE* device);
typedef void (*pcFreeDevice)(DEVICE* device);
struct _DEVICE
@ -315,6 +323,7 @@ struct _DEVICE
wStream* data;
pcIRPRequest IRPRequest;
pcInitDevice Init;
pcFreeDevice Free;
};
@ -337,6 +346,9 @@ struct _IRP
pcIRPResponse Complete;
pcIRPResponse Discard;
HANDLE thread;
BOOL cancelled;
};
struct _DEVMAN

View File

@ -46,7 +46,7 @@ typedef struct _MPPC_CONTEXT MPPC_CONTEXT;
extern "C" {
#endif
FREERDP_API int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstData, UINT32* pDstSize, UINT32* pFlags);
FREERDP_API int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags);
FREERDP_API int mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags);
FREERDP_API void mppc_set_compression_level(MPPC_CONTEXT* mppc, DWORD CompressionLevel);

View File

@ -33,9 +33,14 @@ struct _NCRUSH_CONTEXT
BYTE* HistoryPtr;
UINT32 HistoryOffset;
UINT32 HistoryEndOffset;
UINT32 HistoryBufferSize;
BYTE HistoryBuffer[65536];
UINT32 HistoryBufferFence;
UINT32 OffsetCache[4];
UINT16 HashTable[65536];
UINT16 MatchTable[65536];
BYTE HuffTableCopyOffset[1024];
BYTE HuffTableLOM[4096];
};
typedef struct _NCRUSH_CONTEXT NCRUSH_CONTEXT;
@ -43,7 +48,7 @@ typedef struct _NCRUSH_CONTEXT NCRUSH_CONTEXT;
extern "C" {
#endif
FREERDP_API int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstData, UINT32* pDstSize, UINT32* pFlags);
FREERDP_API int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags);
FREERDP_API int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags);
FREERDP_API void ncrush_context_reset(NCRUSH_CONTEXT* ncrush);

View File

@ -24,6 +24,7 @@
#ifndef __REGION_H___
#define __REGION_H___
#include <freerdp/api.h>
#include <freerdp/types.h>
struct _REGION16_DATA;
@ -43,7 +44,7 @@ typedef struct _REGION16 REGION16;
* @param r2 second rectangle
* @return if the two rectangles intersect
*/
BOOL rectangles_intersects(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2);
FREERDP_API BOOL rectangles_intersects(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2);
/** computes the intersection of two rectangles
* @param r1 first rectangle
@ -51,15 +52,15 @@ BOOL rectangles_intersects(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2);
* @param dst resulting intersection
* @return if the two rectangles intersect
*/
BOOL rectangles_intersection(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2, RECTANGLE_16 *dst);
FREERDP_API BOOL rectangles_intersection(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2, RECTANGLE_16 *dst);
/** initialize a region16
* @param region the region to initialise
*/
void region16_init(REGION16 *region);
FREERDP_API void region16_init(REGION16 *region);
/** @return the number of rectangles of this region16 */
int region16_n_rects(const REGION16 *region);
FREERDP_API int region16_n_rects(const REGION16 *region);
/** returns a pointer on rectangles and the number of rectangles in this region.
* nbRect can be set to NULL if not interested by the numnber of rectangles.
@ -67,33 +68,33 @@ int region16_n_rects(const REGION16 *region);
* @param nbRects a pointer that will be filled with the number of rectangles
* @return a pointer on the rectangles
*/
const RECTANGLE_16 *region16_rects(const REGION16 *region, int *nbRects);
FREERDP_API const RECTANGLE_16 *region16_rects(const REGION16 *region, int *nbRects);
/** @return the extents rectangle of this region */
const RECTANGLE_16 *region16_extents(const REGION16 *region);
FREERDP_API const RECTANGLE_16 *region16_extents(const REGION16 *region);
/** returns if the region is empty
* @param region
* @return if the region is empty
*/
BOOL region16_is_empty(const REGION16 *region);
FREERDP_API BOOL region16_is_empty(const REGION16 *region);
/** clears the region, the region is resetted to a (0,0,0,0) region
* @param region
*/
void region16_clear(REGION16 *region);
FREERDP_API void region16_clear(REGION16 *region);
/** dumps the region on stderr
* @param region the region to dump
*/
void region16_print(const REGION16 *region);
FREERDP_API void region16_print(const REGION16 *region);
/** copies the region to another region
* @param dst destination region
* @param src source region
* @return if the operation was successful (false meaning out-of-memory)
*/
BOOL region16_copy(REGION16 *dst, const REGION16 *src);
FREERDP_API BOOL region16_copy(REGION16 *dst, const REGION16 *src);
/** adds a rectangle in src and stores the resulting region in dst
* @param dst destination region
@ -101,14 +102,14 @@ BOOL region16_copy(REGION16 *dst, const REGION16 *src);
* @param rect the rectangle to add
* @return if the operation was successful (false meaning out-of-memory)
*/
BOOL region16_union_rect(REGION16 *dst, const REGION16 *src, const RECTANGLE_16 *rect);
FREERDP_API BOOL region16_union_rect(REGION16 *dst, const REGION16 *src, const RECTANGLE_16 *rect);
/** returns if a rectangle intersects the region
* @param src the region
* @param arg2 the rectangle
* @return if region and rectangle intersect
*/
BOOL region16_intersects_rect(const REGION16 *src, const RECTANGLE_16 *arg2);
FREERDP_API BOOL region16_intersects_rect(const REGION16 *src, const RECTANGLE_16 *arg2);
/** computes the intersection between a region and a rectangle
* @param dst destination region
@ -116,12 +117,12 @@ BOOL region16_intersects_rect(const REGION16 *src, const RECTANGLE_16 *arg2);
* @param arg2 the rectangle that intersects
* @return if the operation was successful (false meaning out-of-memory)
*/
BOOL region16_intersect_rect(REGION16 *dst, const REGION16 *src, const RECTANGLE_16 *arg2);
FREERDP_API BOOL region16_intersect_rect(REGION16 *dst, const REGION16 *src, const RECTANGLE_16 *arg2);
/** release internal data associated with this region
* @param region the region to release
*/
void region16_uninit(REGION16 *region);
FREERDP_API void region16_uninit(REGION16 *region);
#endif /* __REGION_H___ */

View File

@ -84,7 +84,7 @@ struct rdp_tls
int alertDescription;
};
FREERDP_API BOOL tls_connect(rdpTls* tls);
FREERDP_API int tls_connect(rdpTls* tls);
FREERDP_API BOOL tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file);
FREERDP_API BOOL tls_disconnect(rdpTls* tls);
@ -99,7 +99,7 @@ FREERDP_API int tls_wait_write(rdpTls* tls);
FREERDP_API int tls_set_alert_code(rdpTls* tls, int level, int description);
FREERDP_API BOOL tls_match_hostname(char *pattern, int pattern_length, char *hostname);
FREERDP_API BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port);
FREERDP_API int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port);
FREERDP_API void tls_print_certificate_error(char* hostname, char* fingerprint, char* hosts_file);
FREERDP_API void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name, char** alt_names, int alt_names_count);

View File

@ -177,7 +177,6 @@ FREERDP_API extern int connectErrorCode;
#define CANCELEDBYUSER ERRORSTART + 11
/**
* FreeRDP Context Error Codes
*/
@ -229,6 +228,8 @@ FREERDP_API extern int connectErrorCode;
#define FREERDP_ERROR_AUTHENTICATION_FAILED MAKE_FREERDP_ERROR(CONNECT, 9)
#define FREERDP_ERROR_INSUFFICIENT_PRIVILEGES MAKE_FREERDP_ERROR(CONNECT, 10)
#define FREERDP_ERROR_CONNECT_CANCELLED MAKE_FREERDP_ERROR(CONNECT, 11)
#define FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED MAKE_FREERDP_ERROR(CONNECT, 12)
#define FREERDP_ERROR_CONNECT_TRANSPORT_FAILED MAKE_FREERDP_ERROR(CONNECT, 13)
#ifdef __cplusplus
}

View File

@ -336,11 +336,29 @@ struct _RAIL_GET_APPID_RESP_ORDER
};
typedef struct _RAIL_GET_APPID_RESP_ORDER RAIL_GET_APPID_RESP_ORDER;
struct _RAIL_LANGBARINFO_ORDER
struct _RAIL_LANGBAR_INFO_ORDER
{
UINT32 languageBarStatus;
};
typedef struct _RAIL_LANGBARINFO_ORDER RAIL_LANGBAR_INFO_ORDER;
typedef struct _RAIL_LANGBAR_INFO_ORDER RAIL_LANGBAR_INFO_ORDER;
struct _RAIL_LANGUAGE_IME_INFO_ORDER
{
UINT32 ProfileType;
UINT32 LanguageId;
GUID LanguageProfileClsId;
GUID ProfileGuid;
};
typedef struct _RAIL_LANGUAGE_IME_INFO_ORDER RAIL_LANGUAGE_IME_INFO_ORDER;
struct _RAIL_COMPARTMENT_INFO_ORDER
{
UINT32 ImeState;
UINT32 ImeConvMode;
UINT32 ImeSentenceMode;
UINT32 KanaMode;
};
typedef struct _RAIL_COMPARTMENT_INFO_ORDER RAIL_COMPARTMENT_INFO_ORDER;
/* RAIL Constants */
@ -360,6 +378,7 @@ typedef struct _RAIL_LANGBARINFO_ORDER RAIL_LANGBAR_INFO_ORDER;
#define RDP_RAIL_ORDER_GET_APPID_REQ 0x000E
#define RDP_RAIL_ORDER_GET_APPID_RESP 0x000F
#define RDP_RAIL_ORDER_LANGUAGEIMEINFO 0x0011
#define RDP_RAIL_ORDER_COMPARTMENTINFO 0x0012
#define RDP_RAIL_ORDER_HANDSHAKE_EX 0x0013
#endif /* FREERDP_RAIL_GLOBAL_H */

View File

@ -669,6 +669,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_GatewayCredentialsSource 1990
#define FreeRDP_GatewayUseSameCredentials 1991
#define FreeRDP_GatewayEnabled 1992
#define FreeRDP_GatewayBypassLocal 1993
#define FreeRDP_RemoteApplicationMode 2112
#define FreeRDP_RemoteApplicationName 2113
#define FreeRDP_RemoteApplicationIcon 2114
@ -1073,7 +1074,8 @@ struct rdp_settings
ALIGN64 UINT32 GatewayCredentialsSource; /* 1990 */
ALIGN64 BOOL GatewayUseSameCredentials; /* 1991 */
ALIGN64 BOOL GatewayEnabled; /* 1992 */
UINT64 padding2048[2048 - 1993]; /* 1993 */
ALIGN64 BOOL GatewayBypassLocal; /* 1993 */
UINT64 padding2048[2048 - 1994]; /* 1994 */
UINT64 padding2112[2112 - 2048]; /* 2048 */
/**
@ -1376,6 +1378,8 @@ FREERDP_API void freerdp_target_net_addresses_free(rdpSettings* settings);
FREERDP_API void freerdp_performance_flags_make(rdpSettings* settings);
FREERDP_API void freerdp_performance_flags_split(rdpSettings* settings);
FREERDP_API void freerdp_set_gateway_usage_method(rdpSettings* settings, UINT32 GatewayUsageMethod);
FREERDP_API BOOL freerdp_get_param_bool(rdpSettings* settings, int id);
FREERDP_API int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param);

View File

@ -20,10 +20,6 @@
#ifndef FREERDP_UTILS_DEBUG_H
#define FREERDP_UTILS_DEBUG_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define DEBUG_NULL(fmt, ...) do { } while (0)
/* When building for android redirect all debug messages
@ -61,10 +57,4 @@
#define DEBUG_WARN(fmt, ...) DEBUG_PRINT("Warning %s (%s:%d): ", fmt, ## __VA_ARGS__)
#endif
#ifdef WITH_DEBUG
#define DEBUG_MSG(fmt, ...) DEBUG_PRINT("DBG %s (%s:%d): ", fmt, ## __VA_ARGS__)
#else
#define DEBUG_MSG(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
#endif /* FREERDP_UTILS_DEBUG_H */

View File

@ -1,61 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Double-linked List Utils
*
* Copyright 2011 Vic Lee
*
* 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_UTILS_LIST_H
#define FREERDP_UTILS_LIST_H
#include <freerdp/api.h>
typedef struct _LIST_ITEM LIST_ITEM;
struct _LIST_ITEM
{
void* data;
LIST_ITEM* prev;
LIST_ITEM* next;
};
typedef struct _LIST LIST;
struct _LIST
{
int count;
LIST_ITEM* head;
LIST_ITEM* tail;
};
#ifdef __cplusplus
extern "C" {
#endif
FREERDP_API LIST* list_new(void);
FREERDP_API void list_free(LIST* list);
FREERDP_API void list_enqueue(LIST* list, void* data);
FREERDP_API void* list_dequeue(LIST* list);
FREERDP_API void* list_peek(LIST* list);
FREERDP_API void* list_next(LIST* list, void* data);
#define list_add(_l, _d) list_enqueue(_l, _d)
FREERDP_API void* list_remove(LIST* list, void* data);
FREERDP_API int list_size(LIST* list);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_UTILS_LIST_H */

View File

@ -50,6 +50,7 @@ struct rdp_svc_plugin
void (*terminate_callback)(rdpSvcPlugin* plugin);
HANDLE thread;
HANDLE started;
wStream* data_in;
void* InitHandle;
DWORD OpenHandle;

View File

@ -66,9 +66,4 @@ if(MONOLITHIC_BUILD)
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries EXPORT FreeRDPTargets)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp")
endif()
set(FREERDP_PC_LIBS "-lfreerdp -lwinpr")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
endif(MONOLITHIC_BUILD)

View File

@ -30,7 +30,8 @@ set(${MODULE_PREFIX}_SRCS
add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
MONOLITHIC ${MONOLITHIC_BUILD}
SOURCES ${${MODULE_PREFIX}_SRCS})
SOURCES ${${MODULE_PREFIX}_SRCS}
EXPORT)
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib")

View File

@ -22,7 +22,6 @@
#endif
#include <stdio.h>
#include <assert.h>
#include <winpr/crt.h>
#include <freerdp/update.h>
@ -91,8 +90,11 @@ void* brush_cache_get(rdpBrushCache* brushCache, UINT32 index, UINT32* bpp)
{
void* entry;
assert(brushCache);
assert(bpp);
if (!brushCache)
return NULL;
if (!bpp)
return NULL;
if (*bpp == 1)
{

View File

@ -84,7 +84,8 @@ endif()
add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
MONOLITHIC ${MONOLITHIC_BUILD}
SOURCES ${${MODULE_PREFIX}_SRCS})
SOURCES ${${MODULE_PREFIX}_SRCS}
EXPORT)
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib")

View File

@ -458,14 +458,18 @@ int mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** p
return 1;
}
int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstData, UINT32* pDstSize, UINT32* pFlags)
int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
{
BYTE* pSrcPtr;
BYTE* pSrcEnd;
BYTE* pDstEnd;
BYTE* MatchPtr;
UINT32 DstSize;
BYTE* pDstData;
UINT32 MatchIndex;
UINT32 accumulator;
BOOL PacketFlushed;
BOOL PacketAtFront;
DWORD CopyOffset;
DWORD LengthOfMatch;
BYTE* HistoryBuffer;
@ -483,23 +487,41 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE* pDst
HistoryPtr = mppc->HistoryPtr;
HistoryOffset = mppc->HistoryOffset;
BitStream_Attach(bs, pDstData, SrcSize);
*pFlags = 0;
PacketFlushed = FALSE;
if (((HistoryOffset + SrcSize) < (HistoryBufferSize - 3)) && HistoryOffset)
{
*pFlags = 0;
PacketAtFront = FALSE;
}
else
{
if (HistoryOffset == (HistoryBufferSize + 1))
PacketFlushed = TRUE;
HistoryOffset = 0;
*pFlags = PACKET_AT_FRONT;
PacketAtFront = TRUE;
}
HistoryPtr = &(HistoryBuffer[HistoryOffset]);
pDstData = *ppDstData;
if (!pDstData)
return -1;
DstSize = *pDstSize;
if (DstSize < SrcSize)
return -1;
DstSize = SrcSize;
BitStream_Attach(bs, pDstData, DstSize);
pSrcPtr = pSrcData;
pSrcEnd = &(pSrcData[SrcSize - 1]);
pDstEnd = &(pDstData[*pDstSize - 1]);
pDstEnd = &(pDstData[DstSize - 1]);
while (pSrcPtr < (pSrcEnd - 2))
{
@ -512,21 +534,24 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE* pDst
MatchIndex = MPPC_MATCH_INDEX(Sym1, Sym2, Sym3);
MatchPtr = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]);
if (MatchPtr != &HistoryPtr[-1])
if (MatchPtr != (HistoryPtr - 1))
mppc->MatchBuffer[MatchIndex] = (UINT16) (HistoryPtr - HistoryBuffer);
if (mppc->HistoryPtr < HistoryPtr)
mppc->HistoryPtr = HistoryPtr;
if ((Sym1 != MatchPtr[-1]) || (Sym2 != MatchPtr[0]) || (Sym3 != MatchPtr[1]) ||
if ((Sym1 != *(MatchPtr - 1)) || (Sym2 != MatchPtr[0]) || (Sym3 != MatchPtr[1]) ||
(&MatchPtr[1] > mppc->HistoryPtr) || (MatchPtr == HistoryBuffer) ||
(MatchPtr == &HistoryPtr[-1]) || (MatchPtr == HistoryPtr))
(MatchPtr == (HistoryPtr - 1)) || (MatchPtr == HistoryPtr))
{
if (((bs->position / 8) + 2) > (SrcSize - 1))
if (((bs->position / 8) + 2) > (DstSize - 1))
{
*pFlags |= PACKET_FLUSHED;
ZeroMemory(HistoryBuffer, HistoryBufferSize);
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
mppc->HistoryOffset = HistoryBufferSize + 1;
*pFlags |= PACKET_FLUSHED;
*pFlags |= CompressionLevel;
*ppDstData = pSrcData;
*pDstSize = SrcSize;
return 1;
}
@ -573,11 +598,14 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE* pDst
/* Encode CopyOffset */
if (((bs->position / 8) + 7) > (SrcSize - 1))
if (((bs->position / 8) + 7) > (DstSize - 1))
{
*pFlags = PACKET_FLUSHED;
ZeroMemory(HistoryBuffer, HistoryBufferSize);
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
mppc->HistoryOffset = HistoryBufferSize + 1;
*pFlags |= PACKET_FLUSHED;
*pFlags |= CompressionLevel;
*ppDstData = pSrcData;
*pDstSize = SrcSize;
return 1;
}
@ -729,11 +757,14 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE* pDst
while (pSrcPtr <= pSrcEnd)
{
if (((bs->position / 8) + 2) > (SrcSize - 1))
if (((bs->position / 8) + 2) > (DstSize - 1))
{
*pFlags |= PACKET_FLUSHED;
ZeroMemory(HistoryBuffer, HistoryBufferSize);
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
mppc->HistoryOffset = HistoryBufferSize + 1;
*pFlags |= PACKET_FLUSHED;
*pFlags |= CompressionLevel;
*ppDstData = pSrcData;
*pDstSize = SrcSize;
return 1;
}
@ -763,6 +794,13 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE* pDst
*pFlags |= PACKET_COMPRESSED;
*pFlags |= CompressionLevel;
if (PacketAtFront)
*pFlags |= PACKET_AT_FRONT;
if (PacketFlushed)
*pFlags |= PACKET_FLUSHED;
*pDstSize = ((bs->position + 7) / 8);
mppc->HistoryPtr = HistoryPtr;

File diff suppressed because it is too large Load Diff

View File

@ -87,11 +87,11 @@ struct _BITMAP_PLANAR_CONTEXT
BYTE* rlePlanesBuffer;
};
int freerdp_bitmap_planar_decompress(BYTE* srcData, BYTE* dstData, int width, int height, int size);
FREERDP_API int freerdp_bitmap_planar_decompress(BYTE* srcData, BYTE* dstData, int width, int height, int size);
int freerdp_split_color_planes(BYTE* data, UINT32 format, int width, int height, int scanline, BYTE* planes[4]);
BYTE* freerdp_bitmap_planar_compress_plane_rle(BYTE* plane, int width, int height, BYTE* outPlane, int* dstSize);
BYTE* freerdp_bitmap_planar_delta_encode_plane(BYTE* inPlane, int width, int height, BYTE* outPlane);
int freerdp_bitmap_planar_delta_encode_planes(BYTE* inPlanes[4], int width, int height, BYTE* outPlanes[4]);
FREERDP_API int freerdp_split_color_planes(BYTE* data, UINT32 format, int width, int height, int scanline, BYTE* planes[4]);
FREERDP_API BYTE* freerdp_bitmap_planar_compress_plane_rle(BYTE* plane, int width, int height, BYTE* outPlane, int* dstSize);
FREERDP_API BYTE* freerdp_bitmap_planar_delta_encode_plane(BYTE* inPlane, int width, int height, BYTE* outPlane);
FREERDP_API int freerdp_bitmap_planar_delta_encode_planes(BYTE* inPlanes[4], int width, int height, BYTE* outPlanes[4]);
#endif /* FREERDP_CODEC_PLANAR_PRIVATE_H */

View File

@ -737,8 +737,10 @@ BOOL region16_intersect_rect(REGION16 *dst, const REGION16 *src, const RECTANGLE
free(dst->data);
dst->data = realloc(newItems, newItems->size);
if (!dst->data)
if (!dst->data) {
free(newItems);
return FALSE;
}
dst->extents = newExtents;
return region16_simplify_bands(dst);

View File

@ -711,6 +711,7 @@ int test_MppcCompressBellsRdp5()
UINT32 SrcSize;
BYTE* pSrcData;
UINT32 DstSize;
BYTE* pDstData;
MPPC_CONTEXT* mppc;
UINT32 expectedSize;
BYTE OutputBuffer[65536];
@ -719,10 +720,12 @@ int test_MppcCompressBellsRdp5()
SrcSize = sizeof(TEST_MPPC_BELLS) - 1;
pSrcData = (BYTE*) TEST_MPPC_BELLS;
DstSize = sizeof(OutputBuffer);
expectedSize = sizeof(TEST_MPPC_BELLS_RDP5) - 1;
status = mppc_compress(mppc, pSrcData, SrcSize, OutputBuffer, &DstSize, &Flags);
DstSize = sizeof(OutputBuffer);
pDstData = OutputBuffer;
status = mppc_compress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, &Flags);
printf("Flags: 0x%04X DstSize: %d\n", Flags, DstSize);
@ -732,12 +735,12 @@ int test_MppcCompressBellsRdp5()
return -1;
}
if (memcmp(OutputBuffer, TEST_MPPC_BELLS_RDP5, DstSize) != 0)
if (memcmp(pDstData, TEST_MPPC_BELLS_RDP5, DstSize) != 0)
{
printf("MppcCompressBellsRdp5: output mismatch\n");
printf("Actual\n");
BitDump(OutputBuffer, DstSize * 8, 0);
BitDump(pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(TEST_MPPC_BELLS_RDP5, DstSize * 8, 0);
@ -757,6 +760,7 @@ int test_MppcCompressBellsRdp4()
BYTE* pSrcData;
UINT32 SrcSize;
UINT32 DstSize;
BYTE* pDstData;
MPPC_CONTEXT* mppc;
UINT32 expectedSize;
BYTE OutputBuffer[65536];
@ -766,9 +770,11 @@ int test_MppcCompressBellsRdp4()
SrcSize = sizeof(TEST_MPPC_BELLS) - 1;
pSrcData = (BYTE*) TEST_MPPC_BELLS;
expectedSize = sizeof(TEST_MPPC_BELLS_RDP4) - 1;
DstSize = sizeof(OutputBuffer);
status = mppc_compress(mppc, pSrcData, SrcSize, OutputBuffer, &DstSize, &Flags);
DstSize = sizeof(OutputBuffer);
pDstData = OutputBuffer;
status = mppc_compress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, &Flags);
printf("flags: 0x%04X size: %d\n", Flags, DstSize);
@ -778,12 +784,12 @@ int test_MppcCompressBellsRdp4()
return -1;
}
if (memcmp(OutputBuffer, TEST_MPPC_BELLS_RDP4, DstSize) != 0)
if (memcmp(pDstData, TEST_MPPC_BELLS_RDP4, DstSize) != 0)
{
printf("MppcCompressBellsRdp4: output mismatch\n");
printf("Actual\n");
BitDump(OutputBuffer, DstSize * 8, 0);
BitDump(pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(TEST_MPPC_BELLS_RDP4, DstSize * 8, 0);
@ -879,20 +885,22 @@ int test_MppcCompressBufferRdp5()
BYTE* pSrcData;
UINT32 SrcSize;
UINT32 DstSize;
BYTE* pDstData;
MPPC_CONTEXT* mppc;
UINT32 expectedSize;
BYTE OutputBuffer[65536];
BYTE* pDstData = NULL;
mppc = mppc_context_new(1, TRUE);
SrcSize = sizeof(TEST_RDP5_UNCOMPRESSED_DATA);
pSrcData = (BYTE*) TEST_RDP5_UNCOMPRESSED_DATA;
expectedSize = sizeof(TEST_RDP5_COMPRESSED_DATA);
DstSize = sizeof(OutputBuffer);
pDstData = OutputBuffer;
status = mppc_compress(mppc, pSrcData, SrcSize, pDstData, &DstSize, &Flags);
status = mppc_compress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, &Flags);
printf("flags: 0x%04X size: %d\n", Flags, DstSize);
if (DstSize != expectedSize)
@ -901,7 +909,7 @@ int test_MppcCompressBufferRdp5()
return -1;
}
if (memcmp(OutputBuffer, TEST_RDP5_COMPRESSED_DATA, DstSize) != 0)
if (memcmp(pDstData, TEST_RDP5_COMPRESSED_DATA, DstSize) != 0)
{
printf("MppcCompressBufferRdp5: output mismatch: compressed output does not match Microsoft implementation\n");
return -1;

View File

@ -17,6 +17,7 @@ int test_NCrushCompressBells()
UINT32 SrcSize;
BYTE* pSrcData;
UINT32 DstSize;
BYTE* pDstData;
UINT32 expectedSize;
BYTE OutputBuffer[65536];
NCRUSH_CONTEXT* ncrush;
@ -25,28 +26,38 @@ int test_NCrushCompressBells()
SrcSize = sizeof(TEST_BELLS_DATA) - 1;
pSrcData = (BYTE*) TEST_BELLS_DATA;
DstSize = sizeof(OutputBuffer);
expectedSize = sizeof(TEST_BELLS_NCRUSH) - 1;
status = ncrush_compress(ncrush, pSrcData, SrcSize, OutputBuffer, &DstSize, &Flags);
pDstData = OutputBuffer;
DstSize = sizeof(OutputBuffer);
ZeroMemory(OutputBuffer, sizeof(OutputBuffer));
printf("Flags: 0x%04X DstSize: %d\n", Flags, DstSize);
status = ncrush_compress(ncrush, pSrcData, SrcSize, &pDstData, &DstSize, &Flags);
printf("status: %d Flags: 0x%04X DstSize: %d\n", status, Flags, DstSize);
if (DstSize != expectedSize)
{
printf("NCrushCompressBells: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize);
printf("Actual\n");
BitDump(pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(TEST_BELLS_NCRUSH, expectedSize * 8, 0);
return -1;
}
if (memcmp(OutputBuffer, TEST_BELLS_NCRUSH, DstSize) != 0)
if (memcmp(pDstData, TEST_BELLS_NCRUSH, DstSize) != 0)
{
printf("NCrushCompressBells: output mismatch\n");
printf("Actual\n");
BitDump(OutputBuffer, DstSize * 8, 0);
BitDump(pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(TEST_BELLS_NCRUSH, DstSize * 8, 0);
BitDump(TEST_BELLS_NCRUSH, expectedSize * 8, 0);
return -1;
}
@ -96,10 +107,11 @@ int test_NCrushDecompressBells()
int TestFreeRDPCodecNCrush(int argc, char* argv[])
{
//test_NCrushCompressBells();
test_NCrushDecompressBells();
if (test_NCrushCompressBells() < 0)
return -1;
//BitDump(TEST_BELLS_NCRUSH, (sizeof(TEST_BELLS_NCRUSH) - 1) * 8, 0);
if (test_NCrushDecompressBells() < 0)
return -1;
return 0;
}

View File

@ -690,7 +690,7 @@ struct UnitaryTest tests[] = {
int TestFreeRDPRegion(int argc, char* argv[])
{
int i, testNb;
int i, testNb = 0;
int retCode = -1;
for (i = 0; tests[i].func; i++)

View File

@ -24,7 +24,8 @@ set(${MODULE_PREFIX}_SRCS
add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
MONOLITHIC ${MONOLITHIC_BUILD}
SOURCES ${${MODULE_PREFIX}_SRCS})
SOURCES ${${MODULE_PREFIX}_SRCS}
EXPORT)
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION_FULL} SOVERSION ${FREERDP_VERSION} PREFIX "lib")

View File

@ -154,7 +154,7 @@ RDPDR_DEVICE* freerdp_device_collection_find(rdpSettings* settings, const char*
{
device = (RDPDR_DEVICE*) settings->DeviceArray[index];
if (NULL == device->Name)
if (!device->Name)
continue;
if (strcmp(device->Name, name) == 0)
@ -166,70 +166,172 @@ RDPDR_DEVICE* freerdp_device_collection_find(rdpSettings* settings, const char*
RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device)
{
RDPDR_DEVICE* _device = NULL;
if (device->Type == RDPDR_DTYP_FILESYSTEM)
{
RDPDR_DRIVE* drive = (RDPDR_DRIVE*) device;
RDPDR_DRIVE* _drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE));
RDPDR_DRIVE* _drive = (RDPDR_DRIVE*) calloc(1, sizeof(RDPDR_DRIVE));
if (!_drive)
return NULL;
_drive->Id = drive->Id;
_drive->Type = drive->Type;
_drive->Name = _strdup(drive->Name);
_drive->Path = _strdup(drive->Path);
_device = (RDPDR_DEVICE*) _drive;
_drive->Name = _strdup(drive->Name);
if (!_drive->Name)
goto out_fs_name_error;
_drive->Path = _strdup(drive->Path);
if (!_drive->Path)
goto out_fs_path_error;
return (RDPDR_DEVICE*) _drive;
out_fs_path_error:
free(_drive->Name);
out_fs_name_error:
free(_drive);
return NULL;
}
else if (device->Type == RDPDR_DTYP_PRINT)
if (device->Type == RDPDR_DTYP_PRINT)
{
RDPDR_PRINTER* printer = (RDPDR_PRINTER*) device;
RDPDR_PRINTER* _printer = (RDPDR_PRINTER*) malloc(sizeof(RDPDR_PRINTER));
RDPDR_PRINTER* _printer = (RDPDR_PRINTER*) calloc(1, sizeof(RDPDR_PRINTER));
if (!_printer)
return NULL;
_printer->Id = printer->Id;
_printer->Type = printer->Type;
_printer->Name = _strdup(printer->Name);
_printer->DriverName = _strdup(printer->DriverName);
_device = (RDPDR_DEVICE*) _printer;
if (printer->Name)
{
_printer->Name = _strdup(printer->Name);
if (!_printer->Name)
goto out_print_name_error;
}
if (printer->DriverName)
{
_printer->DriverName = _strdup(printer->DriverName);
if (!_printer->DriverName)
goto out_print_path_error;
}
return (RDPDR_DEVICE*) _printer;
out_print_path_error:
free(_printer->Name);
out_print_name_error:
free(_printer);
return NULL;
}
else if (device->Type == RDPDR_DTYP_SMARTCARD)
if (device->Type == RDPDR_DTYP_SMARTCARD)
{
RDPDR_SMARTCARD* smartcard = (RDPDR_SMARTCARD*) device;
RDPDR_SMARTCARD* _smartcard = (RDPDR_SMARTCARD*) malloc(sizeof(RDPDR_SMARTCARD));
RDPDR_SMARTCARD* _smartcard = (RDPDR_SMARTCARD*) calloc(1, sizeof(RDPDR_SMARTCARD));
if (!_smartcard)
return NULL;
_smartcard->Id = smartcard->Id;
_smartcard->Type = smartcard->Type;
_smartcard->Name = _strdup(smartcard->Name);
_smartcard->Path = _strdup(smartcard->Path);
_device = (RDPDR_DEVICE*) _smartcard;
if (smartcard->Name)
{
_smartcard->Name = _strdup(smartcard->Name);
if (!_smartcard->Name)
goto out_smartc_name_error;
}
if (smartcard->Path)
{
_smartcard->Path = _strdup(smartcard->Path);
if (!_smartcard->Path)
goto out_smartc_path_error;
}
return (RDPDR_DEVICE*) _smartcard;
out_smartc_path_error:
free(_smartcard->Name);
out_smartc_name_error:
free(_smartcard);
return NULL;
}
else if (device->Type == RDPDR_DTYP_SERIAL)
if (device->Type == RDPDR_DTYP_SERIAL)
{
RDPDR_SERIAL* serial = (RDPDR_SERIAL*) device;
RDPDR_SERIAL* _serial = (RDPDR_SERIAL*) malloc(sizeof(RDPDR_SERIAL));
RDPDR_SERIAL* _serial = (RDPDR_SERIAL*) calloc(1, sizeof(RDPDR_SERIAL));
if (!_serial)
return NULL;
_serial->Id = serial->Id;
_serial->Type = serial->Type;
_serial->Name = _strdup(serial->Name);
_serial->Path = _strdup(serial->Path);
_device = (RDPDR_DEVICE*) _serial;
if (serial->Name)
{
_serial->Name = _strdup(serial->Name);
if (!_serial->Name)
goto out_serial_name_error;
}
if (serial->Path)
{
_serial->Path = _strdup(serial->Path);
if (!_serial->Path)
goto out_serial_path_error;
}
return (RDPDR_DEVICE*) _serial;
out_serial_path_error:
free(_serial->Name);
out_serial_name_error:
free(_serial);
return NULL;
}
else if (device->Type == RDPDR_DTYP_PARALLEL)
if (device->Type == RDPDR_DTYP_PARALLEL)
{
RDPDR_PARALLEL* parallel = (RDPDR_PARALLEL*) device;
RDPDR_PARALLEL* _parallel = (RDPDR_PARALLEL*) malloc(sizeof(RDPDR_PARALLEL));
RDPDR_PARALLEL* _parallel = (RDPDR_PARALLEL*) calloc(1, sizeof(RDPDR_PARALLEL));
if (!_parallel)
return NULL;
_parallel->Id = parallel->Id;
_parallel->Type = parallel->Type;
_parallel->Name = _strdup(parallel->Name);
_parallel->Path = _strdup(parallel->Path);
_device = (RDPDR_DEVICE*) _parallel;
if (parallel->Name)
{
_parallel->Name = _strdup(parallel->Name);
if (!_parallel->Name)
goto out_parallel_name_error;
}
if (parallel->Path)
{
_parallel->Path = _strdup(parallel->Path);
if (!_parallel->Path)
goto out_parallel_path_error;
}
return (RDPDR_DEVICE*) _parallel;
out_parallel_path_error:
free(_parallel->Name);
out_parallel_name_error:
free(_parallel);
return NULL;
}
return _device;
fprintf(stderr, "%s: unknown device type %d\n", __FUNCTION__, device->Type);
return NULL;
}
void freerdp_device_collection_free(rdpSettings* settings)
@ -308,16 +410,29 @@ ADDIN_ARGV* freerdp_static_channel_clone(ADDIN_ARGV* channel)
ADDIN_ARGV* _channel = NULL;
_channel = (ADDIN_ARGV*) malloc(sizeof(ADDIN_ARGV));
if (!_channel)
return NULL;
_channel->argc = channel->argc;
_channel->argv = (char**) malloc(sizeof(char*) * channel->argc);
_channel->argv = (char**) calloc(channel->argc, sizeof(char*));
if (!_channel->argv)
goto out_free;
for (index = 0; index < _channel->argc; index++)
{
_channel->argv[index] = _strdup(channel->argv[index]);
if (!_channel->argv[index])
goto out_release_args;
}
return _channel;
out_release_args:
for (index = 0; _channel->argv[index]; index++)
free(_channel->argv[index]);
out_free:
free(_channel);
return NULL;
}
void freerdp_static_channel_collection_free(rdpSettings* settings)
@ -375,16 +490,29 @@ ADDIN_ARGV* freerdp_dynamic_channel_clone(ADDIN_ARGV* channel)
ADDIN_ARGV* _channel = NULL;
_channel = (ADDIN_ARGV*) malloc(sizeof(ADDIN_ARGV));
if (!_channel)
return NULL;
_channel->argc = channel->argc;
_channel->argv = (char**) malloc(sizeof(char*) * channel->argc);
if (!_channel->argv)
goto out_free;
for (index = 0; index < _channel->argc; index++)
{
_channel->argv[index] = _strdup(channel->argv[index]);
if (!_channel->argv[index])
goto out_release_args;
}
return _channel;
out_release_args:
for (index = 0; _channel->argv[index]; index++)
free(_channel->argv[index]);
out_free:
free(_channel);
return NULL;
}
void freerdp_dynamic_channel_collection_free(rdpSettings* settings)
@ -454,6 +582,42 @@ void freerdp_performance_flags_split(rdpSettings* settings)
settings->DisableThemes = (settings->PerformanceFlags & PERF_DISABLE_THEMING) ? TRUE : FALSE;
}
void freerdp_set_gateway_usage_method(rdpSettings* settings, UINT32 GatewayUsageMethod)
{
freerdp_set_param_uint32(settings, FreeRDP_GatewayUsageMethod, GatewayUsageMethod);
if (GatewayUsageMethod == TSC_PROXY_MODE_NONE_DIRECT)
{
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, FALSE);
freerdp_set_param_bool(settings, FreeRDP_GatewayBypassLocal, FALSE);
}
else if (GatewayUsageMethod == TSC_PROXY_MODE_DIRECT)
{
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE);
freerdp_set_param_bool(settings, FreeRDP_GatewayBypassLocal, FALSE);
}
else if (GatewayUsageMethod == TSC_PROXY_MODE_DETECT)
{
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE);
freerdp_set_param_bool(settings, FreeRDP_GatewayBypassLocal, TRUE);
}
else if (GatewayUsageMethod == TSC_PROXY_MODE_DEFAULT)
{
/**
* This corresponds to "Automatically detect RD Gateway server settings",
* which means the client attempts to use gateway group policy settings
* http://technet.microsoft.com/en-us/library/cc770601.aspx
*/
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, FALSE);
freerdp_set_param_bool(settings, FreeRDP_GatewayBypassLocal, FALSE);
}
else if (GatewayUsageMethod == TSC_PROXY_MODE_NONE_DETECT)
{
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, FALSE);
freerdp_set_param_bool(settings, FreeRDP_GatewayBypassLocal, FALSE);
}
}
/**
* Partially Generated Code
*/
@ -746,6 +910,10 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id)
return settings->GatewayEnabled;
break;
case FreeRDP_GatewayBypassLocal:
return settings->GatewayBypassLocal;
break;
case FreeRDP_RemoteApplicationMode:
return settings->RemoteApplicationMode;
break;
@ -1218,6 +1386,10 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param)
settings->GatewayEnabled = param;
break;
case FreeRDP_GatewayBypassLocal:
settings->GatewayBypassLocal = param;
break;
case FreeRDP_RemoteApplicationMode:
settings->RemoteApplicationMode = param;
break;

View File

@ -52,8 +52,6 @@ set(${MODULE_PREFIX}_SRCS
bulk.h
activation.c
activation.h
extension.c
extension.h
gcc.c
gcc.h
mcs.c
@ -128,7 +126,8 @@ set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_GATEWAY_SR
add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
MONOLITHIC ${MONOLITHIC_BUILD}
SOURCES ${${MODULE_PREFIX}_SRCS})
SOURCES ${${MODULE_PREFIX}_SRCS}
EXPORT)
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib")

View File

@ -25,10 +25,34 @@
//#define WITH_BULK_DEBUG 1
const char* bulk_get_compression_flags_string(UINT32 flags)
{
flags &= BULK_COMPRESSION_FLAGS_MASK;
if (flags == 0)
return "PACKET_UNCOMPRESSED";
else if (flags == PACKET_COMPRESSED)
return "PACKET_COMPRESSED";
else if (flags == PACKET_AT_FRONT)
return "PACKET_AT_FRONT";
else if (flags == PACKET_FLUSHED)
return "PACKET_FLUSHED";
else if (flags == (PACKET_COMPRESSED | PACKET_AT_FRONT))
return "PACKET_COMPRESSED | PACKET_AT_FRONT";
else if (flags == (PACKET_COMPRESSED | PACKET_FLUSHED))
return "PACKET_COMPRESSED | PACKET_FLUSHED";
else if (flags == (PACKET_AT_FRONT | PACKET_FLUSHED))
return "PACKET_AT_FRONT | PACKET_FLUSHED";
else if (flags == (PACKET_COMPRESSED | PACKET_AT_FRONT | PACKET_FLUSHED))
return "PACKET_COMPRESSED | PACKET_AT_FRONT | PACKET_FLUSHED";
return "PACKET_UNKNOWN";
}
UINT32 bulk_compression_level(rdpBulk* bulk)
{
rdpSettings* settings = bulk->context->settings;
bulk->CompressionLevel = (settings->CompressionLevel >= 1) ? 1 : 0;
bulk->CompressionLevel = (settings->CompressionLevel >= 2) ? 2 : settings->CompressionLevel;
return bulk->CompressionLevel;
}
@ -39,14 +63,62 @@ UINT32 bulk_compression_max_size(rdpBulk* bulk)
return bulk->CompressionMaxSize;
}
int bulk_compress_validate(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
{
int status;
BYTE* _pSrcData = NULL;
BYTE* _pDstData = NULL;
UINT32 _SrcSize = 0;
UINT32 _DstSize = 0;
UINT32 _Flags = 0;
_pSrcData = *ppDstData;
_SrcSize = *pDstSize;
_Flags = *pFlags | bulk->CompressionLevel;
status = bulk_decompress(bulk, _pSrcData, _SrcSize, &_pDstData, &_DstSize, _Flags);
if (status < 0)
{
printf("compression/decompression failure\n");
return status;
}
if (_DstSize != SrcSize)
{
printf("compression/decompression size mismatch: Actual: %d, Expected: %d\n", _DstSize, SrcSize);
return -1;
}
if (memcmp(_pDstData, pSrcData, SrcSize) != 0)
{
printf("compression/decompression input/output mismatch! flags: 0x%04X\n", _Flags);
#if 1
printf("Actual:\n");
winpr_HexDump(_pDstData, SrcSize);
printf("Expected:\n");
winpr_HexDump(pSrcData, SrcSize);
#endif
return -1;
}
return status;
}
int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags)
{
UINT32 type;
int status = -1;
UINT32 CompressedBytes;
UINT32 UncompressedBytes;
UINT32 type = flags & 0x0F;
if (flags & PACKET_COMPRESSED)
bulk_compression_max_size(bulk);
type = flags & BULK_COMPRESSION_TYPE_MASK;
if (flags & BULK_COMPRESSION_FLAGS_MASK)
{
switch (type)
{
@ -77,7 +149,7 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD
{
*ppDstData = pSrcData;
*pDstSize = SrcSize;
status = 1;
status = 0;
}
if (status >= 0)
@ -96,8 +168,10 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD
CompressionRatio = ((double) CompressedBytes) / ((double) UncompressedBytes);
TotalCompressionRatio = ((double) bulk->TotalCompressedBytes) / ((double) bulk->TotalUncompressedBytes);
printf("Type: %d Flags: 0x%04X Compression Ratio: %f Total: %f %d / %d\n",
type, flags, CompressionRatio, TotalCompressionRatio, CompressedBytes, UncompressedBytes);
printf("Decompress Type: %d Flags: %s (0x%04X) Compression Ratio: %f (%d / %d), Total: %f (%d / %d)\n",
type, bulk_get_compression_flags_string(flags), flags,
CompressionRatio, CompressedBytes, UncompressedBytes,
TotalCompressionRatio, bulk->TotalCompressedBytes, bulk->TotalUncompressedBytes);
}
#endif
}
@ -111,18 +185,33 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD
int bulk_compress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
{
UINT32 type;
int status = -1;
UINT32 CompressedBytes;
UINT32 UncompressedBytes;
if ((SrcSize <= 50) || (SrcSize >= 16384))
{
*ppDstData = pSrcData;
*pDstSize = SrcSize;
return 0;
}
*ppDstData = bulk->OutputBuffer;
*pDstSize = sizeof(bulk->OutputBuffer);
bulk_compression_level(bulk);
mppc_set_compression_level(bulk->mppcSend, bulk->CompressionLevel);
status = mppc_compress(bulk->mppcSend, pSrcData, SrcSize, *ppDstData, pDstSize, pFlags);
bulk_compression_max_size(bulk);
if (bulk->CompressionLevel < PACKET_COMPR_TYPE_RDP6)
{
mppc_set_compression_level(bulk->mppcSend, bulk->CompressionLevel);
status = mppc_compress(bulk->mppcSend, pSrcData, SrcSize, ppDstData, pDstSize, pFlags);
}
else
{
status = ncrush_compress(bulk->ncrushSend, pSrcData, SrcSize, ppDstData, pDstSize, pFlags);
}
if (status >= 0)
{
CompressedBytes = *pDstSize;
@ -133,6 +222,7 @@ int bulk_compress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstDat
#ifdef WITH_BULK_DEBUG
{
UINT32 type;
double CompressionRatio;
double TotalCompressionRatio;
@ -141,12 +231,19 @@ int bulk_compress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstDat
CompressionRatio = ((double) CompressedBytes) / ((double) UncompressedBytes);
TotalCompressionRatio = ((double) bulk->TotalCompressedBytes) / ((double) bulk->TotalUncompressedBytes);
printf("Type: %d Flags: 0x%04X Compression Ratio: %f Total: %f %d / %d\n",
type, *pFlags, CompressionRatio, TotalCompressionRatio, CompressedBytes, UncompressedBytes);
printf("Compress Type: %d Flags: %s (0x%04X) Compression Ratio: %f (%d / %d), Total: %f (%d / %d)\n",
type, bulk_get_compression_flags_string(*pFlags), *pFlags,
CompressionRatio, CompressedBytes, UncompressedBytes,
TotalCompressionRatio, bulk->TotalCompressedBytes, bulk->TotalUncompressedBytes);
}
#endif
}
#if 0
if (bulk_compress_validate(bulk, pSrcData, SrcSize, ppDstData, pDstSize, pFlags) < 0)
status = -1;
#endif
return status;
}
@ -155,6 +252,7 @@ void bulk_reset(rdpBulk* bulk)
mppc_context_reset(bulk->mppcSend);
mppc_context_reset(bulk->mppcRecv);
ncrush_context_reset(bulk->ncrushRecv);
ncrush_context_reset(bulk->ncrushSend);
}
rdpBulk* bulk_new(rdpContext* context)
@ -171,6 +269,7 @@ rdpBulk* bulk_new(rdpContext* context)
bulk->mppcRecv = mppc_context_new(1, FALSE);
bulk->ncrushRecv = ncrush_context_new(FALSE);
bulk->ncrushSend = ncrush_context_new(TRUE);
bulk->CompressionLevel = context->settings->CompressionLevel;
@ -183,13 +282,14 @@ rdpBulk* bulk_new(rdpContext* context)
void bulk_free(rdpBulk* bulk)
{
if (bulk)
{
mppc_context_free(bulk->mppcSend);
mppc_context_free(bulk->mppcRecv);
if (!bulk)
return;
ncrush_context_free(bulk->ncrushRecv);
mppc_context_free(bulk->mppcSend);
mppc_context_free(bulk->mppcRecv);
free(bulk);
}
ncrush_context_free(bulk->ncrushRecv);
ncrush_context_free(bulk->ncrushSend);
free(bulk);
}

View File

@ -35,12 +35,15 @@ struct rdp_bulk
MPPC_CONTEXT* mppcSend;
MPPC_CONTEXT* mppcRecv;
NCRUSH_CONTEXT* ncrushRecv;
NCRUSH_CONTEXT* ncrushSend;
BYTE OutputBuffer[65536];
UINT64 TotalCompressedBytes;
UINT64 TotalUncompressedBytes;
};
#define BULK_COMPRESSION_FLAGS_MASK 0xE0
#define BULK_COMPRESSION_TYPE_MASK 0x0F
UINT32 bulk_compression_level(rdpBulk* bulk);
UINT32 bulk_compression_max_size(rdpBulk* bulk);

View File

@ -2275,8 +2275,44 @@ BOOL rdp_read_multifragment_update_capability_set(wStream* s, UINT16 length, rdp
Stream_Read_UINT32(s, multifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
if (multifragMaxRequestSize < settings->MultifragMaxRequestSize)
settings->MultifragMaxRequestSize = multifragMaxRequestSize;
if (settings->ServerMode)
{
if (settings->RemoteFxCodec)
{
/**
* If we are using RemoteFX the client MUST use a value greater
* than or equal to the value we've previously sent in the server to
* client multi-fragment update capability set (MS-RDPRFX 1.5)
*/
if (multifragMaxRequestSize < settings->MultifragMaxRequestSize)
{
/**
* If it happens to be smaller we honor the client's value but
* have to disable RemoteFX
*/
settings->RemoteFxCodec = FALSE;
settings->MultifragMaxRequestSize = multifragMaxRequestSize;
}
else
{
/* no need to increase server's max request size setting here */
}
}
else
{
settings->MultifragMaxRequestSize = multifragMaxRequestSize;
}
}
else
{
/**
* In client mode we keep up with the server's capabilites.
* In RemoteFX mode we MUST do this but it might also be useful to
* receive larger related bitmap updates.
*/
if (multifragMaxRequestSize > settings->MultifragMaxRequestSize)
settings->MultifragMaxRequestSize = multifragMaxRequestSize;
}
return TRUE;
}
@ -2294,6 +2330,29 @@ void rdp_write_multifragment_update_capability_set(wStream* s, rdpSettings* sett
Stream_EnsureRemainingCapacity(s, 32);
if (settings->ServerMode)
{
/**
* In server mode we prefer to use the highest useful request size that
* will allow us to pack a complete screen update into a single fast
* path PDU using any of the supported codecs.
* However, the client is completely free to accept our proposed
* max request size or send a different value in the client-to-server
* multi-fragment update capability set and we have to accept that,
* unless we are using RemoteFX where the client MUST announce a value
* greater than or equal to the value we're sending here.
* See [MS-RDPRFX 1.5 capability #2]
*/
UINT32 tileNumX = (settings->DesktopWidth+63)/64;
UINT32 tileNumY = (settings->DesktopHeight+63)/64;
settings->MultifragMaxRequestSize = tileNumX * tileNumY * 16384;
/* and add room for headers, regions, frame markers, etc. */
settings->MultifragMaxRequestSize += 16384;
}
header = rdp_capability_set_start(s);
Stream_Write_UINT32(s, settings->MultifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
@ -2531,6 +2590,8 @@ BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, UINT16 length, rdpSetting
BYTE bitmapCodecCount;
UINT16 codecPropertiesLength;
UINT16 remainingLength;
BOOL receivedRemoteFxCodec = FALSE;
BOOL receivedNSCodec = FALSE;
if (length < 5)
return FALSE;
@ -2538,13 +2599,6 @@ BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, UINT16 length, rdpSetting
Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
remainingLength = length - 5;
if (settings->ServerMode)
{
settings->RemoteFxCodec = FALSE;
settings->NSCodec = FALSE;
settings->JpegCodec = FALSE;
}
while (bitmapCodecCount > 0)
{
if (remainingLength < 19)
@ -2557,12 +2611,12 @@ BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, UINT16 length, rdpSetting
if (UuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX, &rpc_status))
{
Stream_Read_UINT8(s, settings->RemoteFxCodecId);
settings->RemoteFxCodec = TRUE;
receivedRemoteFxCodec = TRUE;
}
else if (UuidEqual(&codecGuid, &CODEC_GUID_NSCODEC, &rpc_status))
{
Stream_Read_UINT8(s, settings->NSCodecId);
settings->NSCodec = TRUE;
receivedNSCodec = TRUE;
}
else
{
@ -2601,6 +2655,14 @@ BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, UINT16 length, rdpSetting
bitmapCodecCount--;
}
if (settings->ServerMode)
{
/* only enable a codec if we've announced/enabled it before */
settings->RemoteFxCodec = settings->RemoteFxCodec && receivedRemoteFxCodec;
settings->NSCodec = settings->NSCodec && receivedNSCodec;
settings->JpegCodec = FALSE;
}
return TRUE;
}

View File

@ -161,6 +161,8 @@ BOOL certificate_read_x509_certificate(rdpCertBlob* cert, rdpCertInfo* info)
int error = 0;
s = Stream_New(cert->data, cert->length);
if (!s)
return FALSE;
info->Modulus = 0;
if (!ber_read_sequence_tag(s, &length)) /* Certificate (SEQUENCE) */
@ -253,6 +255,8 @@ BOOL certificate_read_x509_certificate(rdpCertBlob* cert, rdpCertInfo* info)
info->ModulusLength = modulus_length;
info->Modulus = (BYTE*) malloc(info->ModulusLength);
if (!info->Modulus)
goto error1;
Stream_Read(s, info->Modulus, info->ModulusLength);
error++;
@ -290,12 +294,17 @@ rdpX509CertChain* certificate_new_x509_certificate_chain(UINT32 count)
{
rdpX509CertChain* x509_cert_chain;
x509_cert_chain = (rdpX509CertChain*) malloc(sizeof(rdpX509CertChain));
x509_cert_chain = (rdpX509CertChain *)malloc(sizeof(rdpX509CertChain));
if (!x509_cert_chain)
return NULL;
x509_cert_chain->count = count;
x509_cert_chain->array = (rdpCertBlob*) malloc(sizeof(rdpCertBlob) * count);
ZeroMemory(x509_cert_chain->array, sizeof(rdpCertBlob) * count);
x509_cert_chain->array = (rdpCertBlob *)calloc(count, sizeof(rdpCertBlob));
if (!x509_cert_chain->array)
{
free(x509_cert_chain);
return NULL;
}
return x509_cert_chain;
}
@ -308,17 +317,17 @@ void certificate_free_x509_certificate_chain(rdpX509CertChain* x509_cert_chain)
{
int i;
if (x509_cert_chain != NULL)
{
for (i = 0; i < (int) x509_cert_chain->count; i++)
{
if (x509_cert_chain->array[i].data != NULL)
free(x509_cert_chain->array[i].data);
}
if (!x509_cert_chain)
return;
free(x509_cert_chain->array);
free(x509_cert_chain);
for (i = 0; i < (int)x509_cert_chain->count; i++)
{
if (x509_cert_chain->array[i].data)
free(x509_cert_chain->array[i].data);
}
free(x509_cert_chain->array);
free(x509_cert_chain);
}
static BOOL certificate_process_server_public_key(rdpCertificate* certificate, wStream* s, UINT32 length)
@ -335,7 +344,7 @@ static BOOL certificate_process_server_public_key(rdpCertificate* certificate, w
if (memcmp(magic, "RSA1", 4) != 0)
{
fprintf(stderr, "gcc_process_server_public_key: magic error\n");
fprintf(stderr, "%s: magic error\n", __FUNCTION__);
return FALSE;
}
@ -349,6 +358,8 @@ static BOOL certificate_process_server_public_key(rdpCertificate* certificate, w
return FALSE;
certificate->cert_info.ModulusLength = modlen;
certificate->cert_info.Modulus = malloc(certificate->cert_info.ModulusLength);
if (!certificate->cert_info.Modulus)
return FALSE;
Stream_Read(s, certificate->cert_info.Modulus, certificate->cert_info.ModulusLength);
/* 8 bytes of zero padding */
Stream_Seek(s, 8);
@ -366,6 +377,8 @@ static BOOL certificate_process_server_public_signature(rdpCertificate* certific
BYTE md5hash[CRYPTO_MD5_DIGEST_LENGTH];
md5ctx = crypto_md5_init();
if (!md5ctx)
return FALSE;
crypto_md5_update(md5ctx, sigdata, sigdatalen);
crypto_md5_final(md5ctx, md5hash);
@ -378,18 +391,19 @@ static BOOL certificate_process_server_public_signature(rdpCertificate* certific
if (sum != 0)
{
fprintf(stderr, "certificate_process_server_public_signature: invalid signature\n");
fprintf(stderr, "%s: invalid signature\n", __FUNCTION__);
//return FALSE;
}
siglen -= 8;
// TODO: check the result of decrypt
crypto_rsa_public_decrypt(encsig, siglen, TSSK_KEY_LENGTH, tssk_modulus, tssk_exponent, sig);
/* Verify signature. */
if (memcmp(md5hash, sig, sizeof(md5hash)) != 0)
{
fprintf(stderr, "certificate_process_server_public_signature: invalid signature\n");
fprintf(stderr, "%s: invalid signature\n", __FUNCTION__);
//return FALSE;
}
@ -405,7 +419,7 @@ static BOOL certificate_process_server_public_signature(rdpCertificate* certific
if (sig[16] != 0x00 || sum != 0xFF * (62 - 17) || sig[62] != 0x01)
{
fprintf(stderr, "certificate_process_server_public_signature: invalid signature\n");
fprintf(stderr, "%s: invalid signature\n", __FUNCTION__);
//return FALSE;
}
@ -439,7 +453,8 @@ BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate
if (!(dwSigAlgId == SIGNATURE_ALG_RSA && dwKeyAlgId == KEY_EXCHANGE_ALG_RSA))
{
fprintf(stderr, "certificate_read_server_proprietary_certificate: parse error 1\n");
fprintf(stderr, "%s: unsupported signature or key algorithm, dwSigAlgId=%d dwKeyAlgId=%d\n",
__FUNCTION__, dwSigAlgId, dwKeyAlgId);
return FALSE;
}
@ -447,7 +462,7 @@ BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate
if (wPublicKeyBlobType != BB_RSA_KEY_BLOB)
{
fprintf(stderr, "certificate_read_server_proprietary_certificate: parse error 2\n");
fprintf(stderr, "%s: unsupported public key blob type %d\n", __FUNCTION__, wPublicKeyBlobType);
return FALSE;
}
@ -457,7 +472,7 @@ BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate
if (!certificate_process_server_public_key(certificate, s, wPublicKeyBlobLen))
{
fprintf(stderr, "certificate_read_server_proprietary_certificate: parse error 3\n");
fprintf(stderr, "%s: error in server public key\n", __FUNCTION__);
return FALSE;
}
@ -469,23 +484,26 @@ BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate
if (wSignatureBlobType != BB_RSA_SIGNATURE_BLOB)
{
fprintf(stderr, "certificate_read_server_proprietary_certificate: parse error 4\n");
fprintf(stderr, "%s: unsupported blob signature %d\n", __FUNCTION__, wSignatureBlobType);
return FALSE;
}
Stream_Read_UINT16(s, wSignatureBlobLen);
if (Stream_GetRemainingLength(s) < wSignatureBlobLen)
{
fprintf(stderr, "%s: not enought bytes for signature(len=%d)\n", __FUNCTION__, wSignatureBlobLen);
return FALSE;
}
if (wSignatureBlobLen != 72)
{
fprintf(stderr, "certificate_process_server_public_signature: invalid signature length (got %d, expected %d)\n", wSignatureBlobLen, 64);
fprintf(stderr, "%s: invalid signature length (got %d, expected %d)\n", __FUNCTION__, wSignatureBlobLen, 64);
return FALSE;
}
if (!certificate_process_server_public_signature(certificate, sigdata, sigdatalen, s, wSignatureBlobLen))
{
fprintf(stderr, "certificate_read_server_proprietary_certificate: parse error 5\n");
fprintf(stderr, "%s: unable to parse server public signature\n", __FUNCTION__);
return FALSE;
}
@ -512,6 +530,8 @@ BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate,
Stream_Read_UINT32(s, numCertBlobs); /* numCertBlobs */
certificate->x509_cert_chain = certificate_new_x509_certificate_chain(numCertBlobs);
if (!certificate->x509_cert_chain)
return FALSE;
for (i = 0; i < (int) numCertBlobs; i++)
{
@ -526,6 +546,8 @@ BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate,
DEBUG_CERTIFICATE("\nX.509 Certificate #%d, length:%d", i + 1, certLength);
certificate->x509_cert_chain->array[i].data = (BYTE*) malloc(certLength);
if (!certificate->x509_cert_chain->array[i].data)
return FALSE;
Stream_Read(s, certificate->x509_cert_chain->array[i].data, certLength);
certificate->x509_cert_chain->array[i].length = certLength;
@ -562,20 +584,14 @@ BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate,
* @param length certificate length
*/
int certificate_read_server_certificate(rdpCertificate* certificate, BYTE* server_cert, int length)
BOOL certificate_read_server_certificate(rdpCertificate* certificate, BYTE* server_cert, int length)
{
wStream* s;
UINT32 dwVersion;
int status = 1;
if (length < 1)
{
DEBUG_CERTIFICATE("null server certificate\n");
return 0;
}
BOOL ret;
if (length < 4)
return -1;
return FALSE;
s = Stream_New(server_cert, length);
@ -584,22 +600,22 @@ int certificate_read_server_certificate(rdpCertificate* certificate, BYTE* serve
switch (dwVersion & CERT_CHAIN_VERSION_MASK)
{
case CERT_CHAIN_VERSION_1:
status = certificate_read_server_proprietary_certificate(certificate, s);
ret = certificate_read_server_proprietary_certificate(certificate, s);
break;
case CERT_CHAIN_VERSION_2:
status = certificate_read_server_x509_certificate_chain(certificate, s);
ret = certificate_read_server_x509_certificate_chain(certificate, s);
break;
default:
fprintf(stderr, "invalid certificate chain version:%d\n", dwVersion & CERT_CHAIN_VERSION_MASK);
status = -1;
ret = FALSE;
break;
}
Stream_Free(s, FALSE);
return status;
return ret;
}
rdpRsaKey* key_new(const char* keyfile)
@ -608,29 +624,24 @@ rdpRsaKey* key_new(const char* keyfile)
RSA* rsa;
rdpRsaKey* key;
key = (rdpRsaKey*) malloc(sizeof(rdpRsaKey));
ZeroMemory(key, sizeof(rdpRsaKey));
if (key == NULL)
key = (rdpRsaKey *)calloc(1, sizeof(rdpRsaKey));
if (!key)
return NULL;
fp = fopen(keyfile, "r");
if (fp == NULL)
{
fprintf(stderr, "unable to load RSA key from %s: %s.", keyfile, strerror(errno));
free(key) ;
return NULL;
fprintf(stderr, "%s: unable to open RSA key file %s: %s.", __FUNCTION__, keyfile, strerror(errno));
goto out_free;
}
rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
if (rsa == NULL)
{
ERR_print_errors_fp(stdout);
fprintf(stderr, "%s: unable to load RSA key from %s: %s.", __FUNCTION__, keyfile, strerror(errno));
ERR_print_errors_fp(stderr);
fclose(fp);
free(key) ;
return NULL;
goto out_free;
}
fclose(fp);
@ -638,37 +649,36 @@ rdpRsaKey* key_new(const char* keyfile)
switch (RSA_check_key(rsa))
{
case 0:
RSA_free(rsa);
fprintf(stderr, "invalid RSA key in %s", keyfile);
free(key) ;
return NULL;
fprintf(stderr, "%s: invalid RSA key in %s\n", __FUNCTION__, keyfile);
goto out_free_rsa;
case 1:
/* Valid key. */
break;
default:
fprintf(stderr, "%s: unexpected error when checking RSA key from %s: %s.", __FUNCTION__, keyfile, strerror(errno));
ERR_print_errors_fp(stderr);
RSA_free(rsa);
free(key) ;
return NULL;
goto out_free_rsa;
}
if (BN_num_bytes(rsa->e) > 4)
{
RSA_free(rsa);
fprintf(stderr, "RSA public exponent too large in %s", keyfile);
free(key) ;
return NULL;
fprintf(stderr, "%s: RSA public exponent too large in %s\n", __FUNCTION__, keyfile);
goto out_free_rsa;
}
key->ModulusLength = BN_num_bytes(rsa->n);
key->Modulus = (BYTE*) malloc(key->ModulusLength);
key->Modulus = (BYTE *)malloc(key->ModulusLength);
if (!key->Modulus)
goto out_free_rsa;
BN_bn2bin(rsa->n, key->Modulus);
crypto_reverse(key->Modulus, key->ModulusLength);
key->PrivateExponentLength = BN_num_bytes(rsa->d);
key->PrivateExponent = (BYTE*) malloc(key->PrivateExponentLength);
key->PrivateExponent = (BYTE *)malloc(key->PrivateExponentLength);
if (!key->PrivateExponent)
goto out_free_modulus;
BN_bn2bin(rsa->d, key->PrivateExponent);
crypto_reverse(key->PrivateExponent, key->PrivateExponentLength);
@ -677,18 +687,26 @@ rdpRsaKey* key_new(const char* keyfile)
crypto_reverse(key->exponent, sizeof(key->exponent));
RSA_free(rsa);
return key;
out_free_modulus:
free(key->Modulus);
out_free_rsa:
RSA_free(rsa);
out_free:
free(key);
return NULL;
}
void key_free(rdpRsaKey* key)
{
if (key != NULL)
{
if (!key)
return;
if (key->Modulus)
free(key->Modulus);
free(key->PrivateExponent);
free(key);
}
free(key->PrivateExponent);
free(key);
}
/**
@ -701,13 +719,9 @@ rdpCertificate* certificate_new()
{
rdpCertificate* certificate;
certificate = (rdpCertificate*) malloc(sizeof(rdpCertificate));
ZeroMemory(certificate, sizeof(rdpCertificate));
if (certificate != NULL)
{
certificate->x509_cert_chain = NULL;
}
certificate = (rdpCertificate*) calloc(1, sizeof(rdpCertificate));
if (!certificate)
return NULL;
return certificate;
}
@ -719,13 +733,13 @@ rdpCertificate* certificate_new()
void certificate_free(rdpCertificate* certificate)
{
if (certificate != NULL)
{
certificate_free_x509_certificate_chain(certificate->x509_cert_chain);
if (!certificate)
return;
if (certificate->cert_info.Modulus != NULL)
free(certificate->cert_info.Modulus);
certificate_free_x509_certificate_chain(certificate->x509_cert_chain);
free(certificate);
}
if (certificate->cert_info.Modulus)
free(certificate->cert_info.Modulus);
free(certificate);
}

View File

@ -50,7 +50,7 @@ void certificate_free_x509_certificate_chain(rdpX509CertChain* x509_cert_chain);
BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate, wStream* s);
BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, wStream* s);
int certificate_read_server_certificate(rdpCertificate* certificate, BYTE* server_cert, int length);
BOOL certificate_read_server_certificate(rdpCertificate* certificate, BYTE* server_cert, int length);
rdpCertificate* certificate_new(void);
void certificate_free(rdpCertificate* certificate);

View File

@ -169,6 +169,7 @@
BOOL rdp_client_connect(rdpRdp* rdp)
{
BOOL ret;
rdpSettings* settings = rdp->settings;
if (rdp->settingsCopy)
@ -178,6 +179,8 @@ BOOL rdp_client_connect(rdpRdp* rdp)
}
rdp->settingsCopy = freerdp_settings_clone(settings);
if (!rdp->settingsCopy)
return FALSE;
nego_init(rdp->nego);
nego_set_target(rdp->nego, settings->ServerHostname, settings->ServerPort);
@ -206,6 +209,8 @@ BOOL rdp_client_connect(rdpRdp* rdp)
cookie_length = domain_length + 1 + user_length;
cookie = (char*) malloc(cookie_length + 1);
if (!cookie)
return FALSE;
CopyMemory(cookie, domain, domain_length);
CharUpperBuffA(cookie, domain_length);
@ -216,14 +221,17 @@ BOOL rdp_client_connect(rdpRdp* rdp)
cookie[cookie_length] = '\0';
nego_set_cookie(rdp->nego, cookie);
ret = nego_set_cookie(rdp->nego, cookie);
free(cookie);
}
else
{
nego_set_cookie(rdp->nego, settings->Username);
ret = nego_set_cookie(rdp->nego, settings->Username);
}
if (!ret)
return FALSE;
nego_set_send_preconnection_pdu(rdp->nego, settings->SendPreconnectionPdu);
nego_set_preconnection_id(rdp->nego, settings->PreconnectionId);
nego_set_preconnection_blob(rdp->nego, settings->PreconnectionBlob);
@ -231,6 +239,9 @@ BOOL rdp_client_connect(rdpRdp* rdp)
nego_set_negotiation_enabled(rdp->nego, settings->NegotiateSecurityLayer);
nego_set_restricted_admin_mode_required(rdp->nego, settings->RestrictedAdminModeRequired);
nego_set_gateway_enabled(rdp->nego, settings->GatewayEnabled);
nego_set_gateway_bypass_local(rdp->nego, settings->GatewayBypassLocal);
nego_enable_rdp(rdp->nego, settings->RdpSecurity);
nego_enable_tls(rdp->nego, settings->TlsSecurity);
nego_enable_nla(rdp->nego, settings->NlaSecurity);
@ -242,10 +253,18 @@ BOOL rdp_client_connect(rdpRdp* rdp)
nego_set_cookie_max_length(rdp->nego, settings->CookieMaxLength);
if (settings->LoadBalanceInfo)
nego_set_routing_token(rdp->nego, settings->LoadBalanceInfo, settings->LoadBalanceInfoLength);
{
if (!nego_set_routing_token(rdp->nego, settings->LoadBalanceInfo, settings->LoadBalanceInfoLength))
return FALSE;
}
if (!nego_connect(rdp->nego))
{
if (!freerdp_get_last_error(rdp->context))
{
freerdp_set_last_error(rdp->context, FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED);
}
fprintf(stderr, "Error: protocol security negotiation or connection failure\n");
return FALSE;
}
@ -281,7 +300,14 @@ BOOL rdp_client_connect(rdpRdp* rdp)
while (rdp->state != CONNECTION_STATE_ACTIVE)
{
if (rdp_check_fds(rdp) < 0)
{
if (!freerdp_get_last_error(rdp->context))
{
freerdp_set_last_error(rdp->context, FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
}
return FALSE;
}
}
return TRUE;
@ -379,7 +405,9 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp)
wStream* s;
UINT32 length;
UINT32 key_len;
BYTE crypt_client_random[256 + 8];
BYTE *crypt_client_random = NULL;
BOOL ret = FALSE;
int status = 0;
if (!rdp->settings->DisableEncryption)
{
@ -397,12 +425,18 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp)
if (!rdp->settings->ClientRandom)
return FALSE;
ZeroMemory(crypt_client_random, sizeof(crypt_client_random));
crypto_nonce(rdp->settings->ClientRandom, CLIENT_RANDOM_LENGTH);
key_len = rdp->settings->RdpServerCertificate->cert_info.ModulusLength;
mod = rdp->settings->RdpServerCertificate->cert_info.Modulus;
exp = rdp->settings->RdpServerCertificate->cert_info.exponent;
/*
* client random must be (bitlen / 8) + 8 - see [MS-RDPBCGR] 5.3.4.1
* for details
*/
crypt_client_random = calloc(1,key_len+8);
if (!crypt_client_random)
return FALSE;
crypto_rsa_public_encrypt(rdp->settings->ClientRandom, CLIENT_RANDOM_LENGTH, key_len, mod, exp, crypt_client_random);
/* send crypt client random to server */
@ -410,25 +444,22 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp)
s = Stream_New(NULL, length);
rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID);
rdp_write_security_header(s, SEC_EXCHANGE_PKT);
rdp_write_security_header(s, SEC_EXCHANGE_PKT | SEC_LICENSE_ENCRYPT_SC);
length = key_len + 8;
Stream_Write_UINT32(s, length);
Stream_Write(s, crypt_client_random, length);
Stream_SealLength(s);
if (transport_write(rdp->mcs->transport, s) < 0)
{
return FALSE;
}
status = transport_write(rdp->mcs->transport, s);
Stream_Free(s, TRUE);
if (status < 0)
goto end;
/* now calculate encrypt / decrypt and update keys */
if (!security_establish_keys(rdp->settings->ClientRandom, rdp))
{
return FALSE;
}
goto end;
rdp->do_crypt = TRUE;
@ -438,26 +469,57 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp)
if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
{
rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec);
if (!rdp->fips_encrypt)
{
fprintf(stderr, "%s: unable to allocate des3 encrypt key\n", __FUNCTION__);
goto end;
}
rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec);
if (!rdp->fips_decrypt)
{
fprintf(stderr, "%s: unable to allocate des3 decrypt key\n", __FUNCTION__);
goto end;
}
rdp->fips_hmac = crypto_hmac_new();
return TRUE;
if (!rdp->fips_hmac)
{
fprintf(stderr, "%s: unable to allocate fips hmac\n", __FUNCTION__);
goto end;
}
ret = TRUE;
goto end;
}
rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len);
rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len);
if (!rdp->rc4_decrypt_key)
{
fprintf(stderr, "%s: unable to allocate rc4 decrypt key\n", __FUNCTION__);
goto end;
}
return TRUE;
rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len);
if (!rdp->rc4_encrypt_key)
{
fprintf(stderr, "%s: unable to allocate rc4 encrypt key\n", __FUNCTION__);
goto end;
}
ret = TRUE;
end:
if (crypt_client_random)
free(crypt_client_random);
return ret;
}
BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
{
BYTE client_random[64]; /* Should be only 32 after successful decryption, but on failure might take up to 64 bytes. */
BYTE crypt_client_random[256 + 8];
BYTE* client_random = NULL;
BYTE* crypt_client_random = NULL;
UINT32 rand_len, key_len;
UINT16 channel_id, length, sec_flags;
BYTE* mod;
BYTE* priv_exp;
BOOL ret = FALSE;
if (!rdp->settings->DisableEncryption)
{
@ -467,16 +529,19 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
if (!rdp_read_header(rdp, s, &length, &channel_id))
{
fprintf(stderr, "rdp_server_establish_keys: invalid RDP header\n");
fprintf(stderr, "%s: invalid RDP header\n", __FUNCTION__);
return FALSE;
}
if (!rdp_read_security_header(s, &sec_flags))
{
fprintf(stderr, "%s: invalid security header\n", __FUNCTION__);
return FALSE;
}
if ((sec_flags & SEC_EXCHANGE_PKT) == 0)
{
fprintf(stderr, "rdp_server_establish_keys: missing SEC_EXCHANGE_PKT in security header\n");
fprintf(stderr, "%s: missing SEC_EXCHANGE_PKT in security header\n", __FUNCTION__);
return FALSE;
}
@ -485,21 +550,26 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
Stream_Read_UINT32(s, rand_len);
if (Stream_GetRemainingLength(s) < rand_len + 8) /* include 8 bytes of padding */
/* rand_len already includes 8 bytes of padding */
if (Stream_GetRemainingLength(s) < rand_len)
return FALSE;
key_len = rdp->settings->RdpServerRsaKey->ModulusLength;
client_random = malloc(key_len);
if (!client_random)
return FALSE;
if (rand_len != key_len + 8)
{
fprintf(stderr, "rdp_server_establish_keys: invalid encrypted client random length\n");
return FALSE;
fprintf(stderr, "%s: invalid encrypted client random length\n", __FUNCTION__);
goto end2;
}
ZeroMemory(crypt_client_random, sizeof(crypt_client_random));
crypt_client_random = calloc(1, rand_len);
if (!crypt_client_random)
goto end2;
Stream_Read(s, crypt_client_random, rand_len);
/* 8 zero bytes of padding */
Stream_Seek(s, 8);
mod = rdp->settings->RdpServerRsaKey->Modulus;
priv_exp = rdp->settings->RdpServerRsaKey->PrivateExponent;
crypto_rsa_private_decrypt(crypt_client_random, rand_len - 8, key_len, mod, priv_exp, client_random);
@ -507,7 +577,7 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
/* now calculate encrypt / decrypt and update keys */
if (!security_establish_keys(client_random, rdp))
{
return FALSE;
goto end;
}
rdp->do_crypt = TRUE;
@ -518,16 +588,51 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
{
rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec);
if (!rdp->fips_encrypt)
{
fprintf(stderr, "%s: unable to allocate des3 encrypt key\n", __FUNCTION__);
goto end;
}
rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec);
if (!rdp->fips_decrypt)
{
fprintf(stderr, "%s: unable to allocate des3 decrypt key\n", __FUNCTION__);
goto end;
}
rdp->fips_hmac = crypto_hmac_new();
return TRUE;
if (!rdp->fips_hmac)
{
fprintf(stderr, "%s: unable to allocate fips hmac\n", __FUNCTION__);
goto end;
}
ret = TRUE;
goto end;
}
rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len);
rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len);
if (!rdp->rc4_decrypt_key)
{
fprintf(stderr, "%s: unable to allocate rc4 decrypt key\n", __FUNCTION__);
goto end;
}
return TRUE;
rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len);
if (!rdp->rc4_encrypt_key)
{
fprintf(stderr, "%s: unable to allocate rc4 encrypt key\n", __FUNCTION__);
goto end;
}
ret = TRUE;
end:
if (crypt_client_random)
free(crypt_client_random);
end2:
if (client_random)
free(client_random);
return ret;
}
BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s)
@ -869,33 +974,35 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s)
{
BOOL status;
rdpSettings* settings = rdp->settings;
rdpNego *nego = rdp->nego;
transport_set_blocking_mode(rdp->transport, TRUE);
if (!nego_read_request(rdp->nego, s))
if (!nego_read_request(nego, s))
return FALSE;
rdp->nego->selected_protocol = 0;
nego->selected_protocol = 0;
fprintf(stderr, "Client Security: NLA:%d TLS:%d RDP:%d\n",
(rdp->nego->requested_protocols & PROTOCOL_NLA) ? 1 : 0,
(rdp->nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0,
(rdp->nego->requested_protocols == PROTOCOL_RDP) ? 1: 0);
(nego->requested_protocols & PROTOCOL_NLA) ? 1 : 0,
(nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0,
(nego->requested_protocols == PROTOCOL_RDP) ? 1 : 0
);
fprintf(stderr, "Server Security: NLA:%d TLS:%d RDP:%d\n",
settings->NlaSecurity, settings->TlsSecurity, settings->RdpSecurity);
if ((settings->NlaSecurity) && (rdp->nego->requested_protocols & PROTOCOL_NLA))
if ((settings->NlaSecurity) && (nego->requested_protocols & PROTOCOL_NLA))
{
rdp->nego->selected_protocol = PROTOCOL_NLA;
nego->selected_protocol = PROTOCOL_NLA;
}
else if ((settings->TlsSecurity) && (rdp->nego->requested_protocols & PROTOCOL_TLS))
else if ((settings->TlsSecurity) && (nego->requested_protocols & PROTOCOL_TLS))
{
rdp->nego->selected_protocol = PROTOCOL_TLS;
nego->selected_protocol = PROTOCOL_TLS;
}
else if ((settings->RdpSecurity) && (rdp->nego->selected_protocol == PROTOCOL_RDP))
else if ((settings->RdpSecurity) && (nego->selected_protocol == PROTOCOL_RDP))
{
rdp->nego->selected_protocol = PROTOCOL_RDP;
nego->selected_protocol = PROTOCOL_RDP;
}
else
{
@ -903,20 +1010,21 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s)
}
fprintf(stderr, "Negotiated Security: NLA:%d TLS:%d RDP:%d\n",
(rdp->nego->selected_protocol & PROTOCOL_NLA) ? 1 : 0,
(rdp->nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0,
(rdp->nego->selected_protocol == PROTOCOL_RDP) ? 1: 0);
(nego->selected_protocol & PROTOCOL_NLA) ? 1 : 0,
(nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0,
(nego->selected_protocol == PROTOCOL_RDP) ? 1: 0
);
if (!nego_send_negotiation_response(rdp->nego))
if (!nego_send_negotiation_response(nego))
return FALSE;
status = FALSE;
if (rdp->nego->selected_protocol & PROTOCOL_NLA)
if (nego->selected_protocol & PROTOCOL_NLA)
status = transport_accept_nla(rdp->transport);
else if (rdp->nego->selected_protocol & PROTOCOL_TLS)
else if (nego->selected_protocol & PROTOCOL_TLS)
status = transport_accept_tls(rdp->transport);
else if (rdp->nego->selected_protocol == PROTOCOL_RDP) /* 0 */
else if (nego->selected_protocol == PROTOCOL_RDP) /* 0 */
status = transport_accept_rdp(rdp->transport);
if (!status)

View File

@ -1,233 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP Extension Plugin Interface
*
* Copyright 2010-2011 Vic Lee
* Copyright 2011 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <freerdp/freerdp.h>
#include "extension.h"
#ifdef _WIN32
#define DLOPEN(f) LoadLibraryA(f)
#define DLSYM(f, n) GetProcAddress(f, n)
#define DLCLOSE(f) FreeLibrary(f)
#define PATH_SEPARATOR '\\'
#define PLUGIN_EXT "dll"
#else
#include <dlfcn.h>
#define DLOPEN(f) dlopen(f, RTLD_LOCAL | RTLD_LAZY)
#define DLSYM(f, n) dlsym(f, n)
#define DLCLOSE(f) dlclose(f)
#define PATH_SEPARATOR '/'
#ifdef __APPLE__
#define PLUGIN_EXT "dylib"
#else
#define PLUGIN_EXT "so"
#endif
#endif
static UINT32 FREERDP_CC extension_register_plugin(rdpExtPlugin* plugin)
{
rdpExtension* ext = (rdpExtension*) plugin->ext;
if (ext->num_plugins >= FREERDP_EXT_MAX_COUNT)
{
fprintf(stderr, "extension_register_extension: maximum number of plugins reached.\n");
return 1;
}
ext->plugins[ext->num_plugins++] = plugin;
return 0;
}
static UINT32 FREERDP_CC extension_register_pre_connect_hook(rdpExtPlugin* plugin, PFREERDP_EXTENSION_HOOK hook)
{
rdpExtension* ext = (rdpExtension*) plugin->ext;
if (ext->num_pre_connect_hooks >= FREERDP_EXT_MAX_COUNT)
{
fprintf(stderr, "extension_register_pre_connect_hook: maximum plugin reached.\n");
return 1;
}
ext->pre_connect_hooks[ext->num_pre_connect_hooks] = hook;
ext->pre_connect_hooks_instances[ext->num_pre_connect_hooks] = plugin;
ext->num_pre_connect_hooks++;
return 0;
}
static UINT32 FREERDP_CC extension_register_post_connect_hook(rdpExtPlugin* plugin, PFREERDP_EXTENSION_HOOK hook)
{
rdpExtension* ext = (rdpExtension*) plugin->ext;
if (ext->num_post_connect_hooks >= FREERDP_EXT_MAX_COUNT)
{
fprintf(stderr, "extension_register_post_connect_hook: maximum plugin reached.\n");
return 1;
}
ext->post_connect_hooks[ext->num_post_connect_hooks] = hook;
ext->post_connect_hooks_instances[ext->num_post_connect_hooks] = plugin;
ext->num_post_connect_hooks++;
return 0;
}
static int extension_load_plugins(rdpExtension* extension)
{
int i;
void* han;
char path[256];
rdpSettings* settings;
PFREERDP_EXTENSION_ENTRY entry;
FREERDP_EXTENSION_ENTRY_POINTS entryPoints;
settings = extension->instance->settings;
entryPoints.ext = extension;
entryPoints.pRegisterExtension = extension_register_plugin;
entryPoints.pRegisterPreConnectHook = extension_register_pre_connect_hook;
entryPoints.pRegisterPostConnectHook = extension_register_post_connect_hook;
for (i = 0; settings->extensions[i].name[0]; i++)
{
if (strchr(settings->extensions[i].name, PATH_SEPARATOR) == NULL)
sprintf_s(path, sizeof(path), EXT_PATH "/%s." PLUGIN_EXT, settings->extensions[i].name);
else
sprintf_s(path, sizeof(path), "%s", settings->extensions[i].name);
han = DLOPEN(path);
fprintf(stderr, "extension_load_plugins: %s\n", path);
if (han == NULL)
{
fprintf(stderr, "extension_load_plugins: failed to load %s\n", path);
continue;
}
entry = (PFREERDP_EXTENSION_ENTRY) DLSYM(han, FREERDP_EXT_EXPORT_FUNC_NAME);
if (entry == NULL)
{
DLCLOSE(han);
fprintf(stderr, "extension_load_plugins: failed to find export function in %s\n", path);
continue;
}
entryPoints.data = extension->instance->settings->extensions[i].data;
if (entry(&entryPoints) != 0)
{
DLCLOSE(han);
fprintf(stderr, "extension_load_plugins: %s entry returns error.\n", path);
continue;
}
DLCLOSE(han);
}
return 0;
}
static int extension_init_plugins(rdpExtension* extension)
{
int i;
for (i = 0; i < extension->num_plugins; i++)
extension->plugins[i]->init(extension->plugins[i], extension->instance);
return 0;
}
static int extension_uninit_plugins(rdpExtension* extension)
{
int i;
for (i = 0; i < extension->num_plugins; i++)
extension->plugins[i]->uninit(extension->plugins[i], extension->instance);
return 0;
}
/** Gets through all registered pre-connect hooks and executes them.
* @param extension - pointer to a rdpExtension structure
* @return 0 always
*/
int extension_pre_connect(rdpExtension* extension)
{
int i;
for (i = 0; i < extension->num_pre_connect_hooks; i++)
extension->pre_connect_hooks[i](extension->pre_connect_hooks_instances[i], extension->instance);
return 0;
}
/** Gets through all registered post-connect hooks and executes them.
* @param extension - pointer to a rdpExtension structure
* @return 0 always
*/
int extension_post_connect(rdpExtension* ext)
{
int i;
for (i = 0; i < ext->num_post_connect_hooks; i++)
ext->post_connect_hooks[i](ext->post_connect_hooks_instances[i], ext->instance);
return 0;
}
void extension_load_and_init_plugins(rdpExtension* extension)
{
extension_load_plugins(extension);
extension_init_plugins(extension);
}
rdpExtension* extension_new(freerdp* instance)
{
rdpExtension* extension = NULL;
if (instance != NULL)
{
extension = (rdpExtension*) malloc(sizeof(rdpExtension));
ZeroMemory(extension, sizeof(rdpExtension));
extension->instance = instance;
}
return extension;
}
void extension_free(rdpExtension* extension)
{
if (extension != NULL)
{
extension_uninit_plugins(extension);
free(extension);
}
}

View File

@ -1,54 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP Extension Plugin Interface
*
* Copyright 2010-2011 Vic Lee
* Copyright 2011 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.
*/
#ifndef __EXTENSION_H
#define __EXTENSION_H
#include <winpr/windows.h>
#include <freerdp/api.h>
#include <freerdp/freerdp.h>
#include <freerdp/extension.h>
#define FREERDP_EXT_MAX_COUNT 16
struct rdp_extension
{
freerdp* instance;
rdpExtPlugin* plugins[FREERDP_EXT_MAX_COUNT];
int num_plugins;
PFREERDP_EXTENSION_HOOK pre_connect_hooks[FREERDP_EXT_MAX_COUNT];
rdpExtPlugin* pre_connect_hooks_instances[FREERDP_EXT_MAX_COUNT];
int num_pre_connect_hooks;
PFREERDP_EXTENSION_HOOK post_connect_hooks[FREERDP_EXT_MAX_COUNT];
rdpExtPlugin* post_connect_hooks_instances[FREERDP_EXT_MAX_COUNT];
int num_post_connect_hooks;
};
typedef struct rdp_extension rdpExtension;
FREERDP_API int extension_pre_connect(rdpExtension* extension);
FREERDP_API int extension_post_connect(rdpExtension* extension);
FREERDP_API rdpExtension* extension_new(freerdp* instance);
FREERDP_API void extension_free(rdpExtension* extension);
FREERDP_API void extension_load_and_init_plugins(rdpExtension* extension);
#endif /* __EXTENSION_H */

View File

@ -3,6 +3,7 @@
* Fast Path
*
* Copyright 2011 Vic Lee
* Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -137,7 +138,7 @@ UINT32 fastpath_get_update_header_size(FASTPATH_UPDATE_HEADER* fpUpdateHeader)
return (fpUpdateHeader->compression) ? 4 : 3;
}
void fastpath_write_update_pdu_header(wStream* s, FASTPATH_UPDATE_PDU_HEADER* fpUpdatePduHeader)
void fastpath_write_update_pdu_header(wStream* s, FASTPATH_UPDATE_PDU_HEADER* fpUpdatePduHeader, rdpRdp* rdp)
{
fpUpdatePduHeader->fpOutputHeader = 0;
fpUpdatePduHeader->fpOutputHeader |= (fpUpdatePduHeader->action & 0x03);
@ -147,18 +148,25 @@ void fastpath_write_update_pdu_header(wStream* s, FASTPATH_UPDATE_PDU_HEADER* fp
Stream_Write_UINT8(s, 0x80 | (fpUpdatePduHeader->length >> 8)); /* length1 */
Stream_Write_UINT8(s, fpUpdatePduHeader->length & 0xFF); /* length2 */
}
UINT32 fastpath_get_update_pdu_header_size(FASTPATH_UPDATE_PDU_HEADER* fpUpdatePduHeader)
{
UINT32 size = 1;
size += 2;
if (fpUpdatePduHeader->secFlags)
{
size += 4;
size += 8;
if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
Stream_Write(s, fpUpdatePduHeader->fipsInformation, 4);
Stream_Write(s, fpUpdatePduHeader->dataSignature, 8);
}
}
UINT32 fastpath_get_update_pdu_header_size(FASTPATH_UPDATE_PDU_HEADER* fpUpdatePduHeader, rdpRdp* rdp)
{
UINT32 size = 3; /* fpUpdatePduHeader + length1 + length2 */
if (fpUpdatePduHeader->secFlags)
{
size += 8; /* dataSignature */
if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
size += 4; /* fipsInformation */
}
return size;
@ -337,6 +345,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s)
rdpRdp* rdp;
int next_pos;
wStream* cs;
int bulkStatus;
UINT32 totalSize;
BYTE updateCode;
BYTE fragmentation;
@ -365,8 +374,18 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s)
cs = s;
next_pos = Stream_GetPosition(s) + size;
if (bulk_decompress(rdp->bulk, Stream_Pointer(s), size, &pDstData, &DstSize, compressionFlags))
bulkStatus = bulk_decompress(rdp->bulk, Stream_Pointer(s), size, &pDstData, &DstSize, compressionFlags);
if (bulkStatus < 0)
{
fprintf(stderr, "bulk_decompress() failed\n");
return -1;
}
if (bulkStatus > 0)
{
/* data was compressed, copy from decompression buffer */
size = DstSize;
cs = StreamPool_Take(transport->ReceivePool, DstSize);
@ -375,11 +394,6 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s)
Stream_SealLength(cs);
Stream_SetPosition(cs, 0);
}
else
{
fprintf(stderr, "bulk_decompress() failed\n");
Stream_Seek(s, size);
}
if (fragmentation == FASTPATH_FRAGMENT_SINGLE)
{
@ -740,7 +754,6 @@ BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, int iNu
rdpRdp* rdp;
UINT16 length;
BYTE eventHeader;
int sec_bytes;
/*
* A maximum of 15 events are allowed per request
@ -770,7 +783,48 @@ BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, int iNu
Stream_SetPosition(s, 0);
Stream_Write_UINT8(s, eventHeader);
sec_bytes = fastpath_get_sec_bytes(fastpath->rdp);
/* Write length later, RDP encryption might add a padding */
Stream_Seek(s, 2);
if (rdp->sec_flags & SEC_ENCRYPT)
{
int sec_bytes = fastpath_get_sec_bytes(fastpath->rdp);
BYTE* fpInputEvents = Stream_Pointer(s) + sec_bytes;
UINT16 fpInputEvents_length = length - 3 - sec_bytes;
if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
{
BYTE pad;
if ((pad = 8 - (fpInputEvents_length % 8)) == 8)
pad = 0;
Stream_Write_UINT16(s, 0x10); /* length */
Stream_Write_UINT8(s, 0x1); /* TSFIPS_VERSION 1*/
Stream_Write_UINT8(s, pad); /* padding */
security_hmac_signature(fpInputEvents, fpInputEvents_length, Stream_Pointer(s), rdp);
if (pad)
memset(fpInputEvents + fpInputEvents_length, 0, pad);
security_fips_encrypt(fpInputEvents, fpInputEvents_length + pad, rdp);
length += pad;
}
else
{
if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
security_salted_mac_signature(rdp, fpInputEvents, fpInputEvents_length, TRUE, Stream_Pointer(s));
else
security_mac_signature(rdp, fpInputEvents, fpInputEvents_length, Stream_Pointer(s));
security_encrypt(fpInputEvents, fpInputEvents_length, rdp);
}
}
rdp->sec_flags = 0;
/*
* We always encode length in two bytes, even though we could use
@ -778,26 +832,9 @@ BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, int iNu
* because we can leave room for fixed-length header, store all
* the data first and then store the header.
*/
Stream_SetPosition(s, 1);
Stream_Write_UINT16_BE(s, 0x8000 | length);
if (sec_bytes > 0)
{
BYTE* fpInputEvents;
UINT16 fpInputEvents_length;
fpInputEvents = Stream_Pointer(s) + sec_bytes;
fpInputEvents_length = length - 3 - sec_bytes;
if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
security_salted_mac_signature(rdp, fpInputEvents, fpInputEvents_length, TRUE, Stream_Pointer(s));
else
security_mac_signature(rdp, fpInputEvents, fpInputEvents_length, Stream_Pointer(s));
security_encrypt(fpInputEvents, fpInputEvents_length, rdp);
}
rdp->sec_flags = 0;
Stream_SetPosition(s, length);
Stream_SealLength(s);
@ -854,6 +891,14 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s
maxLength -= 20;
}
if (rdp->do_crypt)
{
rdp->sec_flags |= SEC_ENCRYPT;
if (rdp->do_secure_checksum)
rdp->sec_flags |= SEC_SECURE_CHECKSUM;
}
totalLength = Stream_GetPosition(s);
Stream_SetPosition(s, 0);
@ -864,6 +909,8 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s
UINT32 DstSize = 0;
BYTE* pDstData = NULL;
UINT32 compressionFlags = 0;
BYTE pad = 0;
BYTE* pSignature = NULL;
fpUpdatePduHeader.action = 0;
fpUpdatePduHeader.secFlags = 0;
@ -876,11 +923,16 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s
pSrcData = pDstData = Stream_Pointer(s);
SrcSize = DstSize = fpUpdateHeader.size;
if (rdp->sec_flags & SEC_ENCRYPT)
fpUpdatePduHeader.secFlags |= FASTPATH_OUTPUT_ENCRYPTED;
if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
fpUpdatePduHeader.secFlags |= FASTPATH_OUTPUT_SECURE_CHECKSUM;
if (settings->CompressionEnabled)
{
if (bulk_compress(rdp->bulk, pSrcData, SrcSize, &pDstData, &DstSize, &compressionFlags) >= 0)
{
if (compressionFlags & PACKET_COMPRESSED)
if (compressionFlags)
{
fpUpdateHeader.compressionFlags = compressionFlags;
fpUpdateHeader.compression = FASTPATH_OUTPUT_COMPRESSION_USED;
@ -903,16 +955,58 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s
fpUpdateHeader.fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_FIRST : FASTPATH_FRAGMENT_NEXT;
fpUpdateHeaderSize = fastpath_get_update_header_size(&fpUpdateHeader);
fpUpdatePduHeaderSize = fastpath_get_update_pdu_header_size(&fpUpdatePduHeader);
fpUpdatePduHeaderSize = fastpath_get_update_pdu_header_size(&fpUpdatePduHeader, rdp);
fpHeaderSize = fpUpdateHeaderSize + fpUpdatePduHeaderSize;
fpUpdatePduHeader.length = fpUpdateHeader.size + fpHeaderSize;
if (rdp->sec_flags & SEC_ENCRYPT)
{
pSignature = Stream_Buffer(fs) + 3;
if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
{
pSignature += 4;
if ((pad = 8 - ((DstSize + fpUpdateHeaderSize) % 8)) == 8)
pad = 0;
fpUpdatePduHeader.fipsInformation[0] = 0x10;
fpUpdatePduHeader.fipsInformation[1] = 0x00;
fpUpdatePduHeader.fipsInformation[2] = 0x01;
fpUpdatePduHeader.fipsInformation[3] = pad;
}
}
fpUpdatePduHeader.length = fpUpdateHeader.size + fpHeaderSize + pad;
Stream_SetPosition(fs, 0);
fastpath_write_update_pdu_header(fs, &fpUpdatePduHeader);
fastpath_write_update_pdu_header(fs, &fpUpdatePduHeader, rdp);
fastpath_write_update_header(fs, &fpUpdateHeader);
Stream_Write(fs, pDstData, DstSize);
if (pad)
Stream_Zero(fs, pad);
if (rdp->sec_flags & SEC_ENCRYPT)
{
UINT32 dataSize = fpUpdateHeaderSize + DstSize + pad;
BYTE *data = Stream_Pointer(fs) - dataSize;
if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
{
security_hmac_signature(data, dataSize - pad, pSignature, rdp);
security_fips_encrypt(data, dataSize, rdp);
}
else
{
if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
security_salted_mac_signature(rdp, data, dataSize, TRUE, pSignature);
else
security_mac_signature(rdp, data, dataSize, pSignature);
security_encrypt(data, dataSize, rdp);
}
}
Stream_SealLength(fs);
if (transport_write(rdp->transport, fs) < 0)
@ -924,6 +1018,8 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s
Stream_Seek(s, SrcSize);
}
rdp->sec_flags = 0;
return status;
}

View File

@ -27,7 +27,6 @@
#include "surface.h"
#include "transport.h"
#include "connection.h"
#include "extension.h"
#include "message.h"
#include <assert.h>
@ -79,9 +78,6 @@ BOOL freerdp_connect(freerdp* instance)
settings->KeyboardFunctionKey = 12;
}
extension_load_and_init_plugins(rdp->extension);
extension_pre_connect(rdp->extension);
if (!status)
{
if (!connectErrorCode)
@ -94,7 +90,7 @@ BOOL freerdp_connect(freerdp* instance)
freerdp_set_last_error(instance->context, FREERDP_ERROR_PRE_CONNECT_FAILED);
}
fprintf(stderr, "%s:%d: freerdp_pre_connect failed\n", __FILE__, __LINE__);
fprintf(stderr, "freerdp_pre_connect failed\n");
goto freerdp_connect_finally;
}
@ -104,7 +100,7 @@ BOOL freerdp_connect(freerdp* instance)
/* --authonly tests the connection without a UI */
if (instance->settings->AuthenticationOnly)
{
fprintf(stderr, "%s:%d: Authentication only, exit status %d\n", __FILE__, __LINE__, !status);
fprintf(stderr, "Authentication only, exit status %d\n", !status);
goto freerdp_connect_finally;
}
@ -117,8 +113,6 @@ BOOL freerdp_connect(freerdp* instance)
instance->update->dump_rfx = TRUE;
}
extension_post_connect(rdp->extension);
IFCALLRET(instance->PostConnect, status, instance);
update_post_connect(instance->update);
@ -192,11 +186,6 @@ BOOL freerdp_connect(freerdp* instance)
freerdp_set_last_error(instance->context, FREERDP_ERROR_INSUFFICIENT_PRIVILEGES);
}
if (!connectErrorCode)
{
connectErrorCode = UNDEFINEDCONNECTERROR;
}
SetEvent(rdp->transport->connectedEvent);
freerdp_connect_finally:

View File

@ -30,14 +30,7 @@
HttpContext* http_context_new()
{
HttpContext* http_context = (HttpContext*) malloc(sizeof(HttpContext));
if (http_context != NULL)
{
ZeroMemory(http_context, sizeof(HttpContext));
}
return http_context;
return (HttpContext *)calloc(1, sizeof(HttpContext));
}
void http_context_set_method(HttpContext* http_context, char* method)
@ -46,6 +39,7 @@ void http_context_set_method(HttpContext* http_context, char* method)
free(http_context->Method);
http_context->Method = _strdup(method);
// TODO: check result
}
void http_context_set_uri(HttpContext* http_context, char* uri)
@ -54,6 +48,7 @@ void http_context_set_uri(HttpContext* http_context, char* uri)
free(http_context->URI);
http_context->URI = _strdup(uri);
// TODO: check result
}
void http_context_set_user_agent(HttpContext* http_context, char* user_agent)
@ -62,6 +57,7 @@ void http_context_set_user_agent(HttpContext* http_context, char* user_agent)
free(http_context->UserAgent);
http_context->UserAgent = _strdup(user_agent);
// TODO: check result
}
void http_context_set_host(HttpContext* http_context, char* host)
@ -70,6 +66,7 @@ void http_context_set_host(HttpContext* http_context, char* host)
free(http_context->Host);
http_context->Host = _strdup(host);
// TODO: check result
}
void http_context_set_accept(HttpContext* http_context, char* accept)
@ -78,6 +75,7 @@ void http_context_set_accept(HttpContext* http_context, char* accept)
free(http_context->Accept);
http_context->Accept = _strdup(accept);
// TODO: check result
}
void http_context_set_cache_control(HttpContext* http_context, char* cache_control)
@ -86,6 +84,7 @@ void http_context_set_cache_control(HttpContext* http_context, char* cache_contr
free(http_context->CacheControl);
http_context->CacheControl = _strdup(cache_control);
// TODO: check result
}
void http_context_set_connection(HttpContext* http_context, char* connection)
@ -94,6 +93,7 @@ void http_context_set_connection(HttpContext* http_context, char* connection)
free(http_context->Connection);
http_context->Connection = _strdup(connection);
// TODO: check result
}
void http_context_set_pragma(HttpContext* http_context, char* pragma)
@ -102,6 +102,7 @@ void http_context_set_pragma(HttpContext* http_context, char* pragma)
free(http_context->Pragma);
http_context->Pragma = _strdup(pragma);
// TODO: check result
}
void http_context_free(HttpContext* http_context)
@ -126,6 +127,7 @@ void http_request_set_method(HttpRequest* http_request, char* method)
free(http_request->Method);
http_request->Method = _strdup(method);
// TODO: check result
}
void http_request_set_uri(HttpRequest* http_request, char* uri)
@ -134,6 +136,7 @@ void http_request_set_uri(HttpRequest* http_request, char* uri)
free(http_request->URI);
http_request->URI = _strdup(uri);
// TODO: check result
}
void http_request_set_auth_scheme(HttpRequest* http_request, char* auth_scheme)
@ -142,6 +145,7 @@ void http_request_set_auth_scheme(HttpRequest* http_request, char* auth_scheme)
free(http_request->AuthScheme);
http_request->AuthScheme = _strdup(auth_scheme);
// TODO: check result
}
void http_request_set_auth_param(HttpRequest* http_request, char* auth_param)
@ -150,6 +154,7 @@ void http_request_set_auth_param(HttpRequest* http_request, char* auth_param)
free(http_request->AuthParam);
http_request->AuthParam = _strdup(auth_param);
// TODO: check result
}
char* http_encode_body_line(char* param, char* value)
@ -159,6 +164,8 @@ char* http_encode_body_line(char* param, char* value)
length = strlen(param) + strlen(value) + 2;
line = (char*) malloc(length + 1);
if (!line)
return NULL;
sprintf_s(line, length + 1, "%s: %s", param, value);
return line;
@ -172,7 +179,9 @@ char* http_encode_content_length_line(int ContentLength)
_itoa_s(ContentLength, str, sizeof(str), 10);
length = strlen("Content-Length") + strlen(str) + 2;
line = (char*) malloc(length + 1);
line = (char *)malloc(length + 1);
if (!line)
return NULL;
sprintf_s(line, length + 1, "Content-Length: %s", str);
return line;
@ -184,7 +193,9 @@ char* http_encode_header_line(char* Method, char* URI)
int length;
length = strlen("HTTP/1.1") + strlen(Method) + strlen(URI) + 2;
line = (char*) malloc(length + 1);
line = (char *)malloc(length + 1);
if (!line)
return NULL;
sprintf_s(line, length + 1, "%s %s HTTP/1.1", Method, URI);
return line;
@ -197,6 +208,8 @@ char* http_encode_authorization_line(char* AuthScheme, char* AuthParam)
length = strlen("Authorization") + strlen(AuthScheme) + strlen(AuthParam) + 3;
line = (char*) malloc(length + 1);
if (!line)
return NULL;
sprintf_s(line, length + 1, "Authorization: %s %s", AuthScheme, AuthParam);
return line;
@ -204,81 +217,101 @@ char* http_encode_authorization_line(char* AuthScheme, char* AuthParam)
wStream* http_request_write(HttpContext* http_context, HttpRequest* http_request)
{
int i;
int i, count;
char **lines;
wStream* s;
int length = 0;
http_request->count = 9;
http_request->lines = (char**) malloc(sizeof(char*) * http_request->count);
count = 9;
lines = (char **)calloc(count, sizeof(char *));
if (!lines)
return NULL;
http_request->lines[0] = http_encode_header_line(http_request->Method, http_request->URI);
http_request->lines[1] = http_encode_body_line("Cache-Control", http_context->CacheControl);
http_request->lines[2] = http_encode_body_line("Connection", http_context->Connection);
http_request->lines[3] = http_encode_body_line("Pragma", http_context->Pragma);
http_request->lines[4] = http_encode_body_line("Accept", http_context->Accept);
http_request->lines[5] = http_encode_body_line("User-Agent", http_context->UserAgent);
http_request->lines[6] = http_encode_content_length_line(http_request->ContentLength);
http_request->lines[7] = http_encode_body_line("Host", http_context->Host);
lines[0] = http_encode_header_line(http_request->Method, http_request->URI);
lines[1] = http_encode_body_line("Cache-Control", http_context->CacheControl);
lines[2] = http_encode_body_line("Connection", http_context->Connection);
lines[3] = http_encode_body_line("Pragma", http_context->Pragma);
lines[4] = http_encode_body_line("Accept", http_context->Accept);
lines[5] = http_encode_body_line("User-Agent", http_context->UserAgent);
lines[6] = http_encode_content_length_line(http_request->ContentLength);
lines[7] = http_encode_body_line("Host", http_context->Host);
/* check that everything went well */
for (i = 0; i < 8; i++)
{
if (!lines[i])
goto out_free;
}
if (http_request->Authorization != NULL)
{
http_request->lines[8] = http_encode_body_line("Authorization", http_request->Authorization);
lines[8] = http_encode_body_line("Authorization", http_request->Authorization);
if (!lines[8])
goto out_free;
}
else if ((http_request->AuthScheme != NULL) && (http_request->AuthParam != NULL))
{
http_request->lines[8] = http_encode_authorization_line(http_request->AuthScheme, http_request->AuthParam);
lines[8] = http_encode_authorization_line(http_request->AuthScheme, http_request->AuthParam);
if (!lines[8])
goto out_free;
}
for (i = 0; i < http_request->count; i++)
for (i = 0; i < count; i++)
{
length += (strlen(http_request->lines[i]) + 2); /* add +2 for each '\r\n' character */
length += (strlen(lines[i]) + 2); /* add +2 for each '\r\n' character */
}
length += 2; /* empty line "\r\n" at end of header */
length += 1; /* null terminator */
s = Stream_New(NULL, length);
if (!s)
goto out_free;
for (i = 0; i < http_request->count; i++)
for (i = 0; i < count; i++)
{
Stream_Write(s, http_request->lines[i], strlen(http_request->lines[i]));
Stream_Write(s, lines[i], strlen(lines[i]));
Stream_Write(s, "\r\n", 2);
free(http_request->lines[i]);
free(lines[i]);
}
Stream_Write(s, "\r\n", 2);
free(http_request->lines);
free(lines);
Stream_Write(s, "\0", 1); /* append null terminator */
Stream_Rewind(s, 1); /* don't include null terminator in length */
Stream_Length(s) = Stream_GetPosition(s);
return s;
out_free:
for (i = 0; i < 9; i++)
{
if (lines[i])
free(lines[i]);
}
free(lines);
return NULL;
}
HttpRequest* http_request_new()
{
HttpRequest* http_request = (HttpRequest*) malloc(sizeof(HttpRequest));
if (http_request != NULL)
{
ZeroMemory(http_request, sizeof(HttpRequest));
}
return http_request;
return (HttpRequest*) calloc(1, sizeof(HttpRequest));
}
void http_request_free(HttpRequest* http_request)
{
if (http_request != NULL)
{
if (!http_request)
return;
if (http_request->AuthParam)
free(http_request->AuthParam);
if (http_request->AuthScheme)
free(http_request->AuthScheme);
if (http_request->Authorization)
free(http_request->Authorization);
free(http_request->Content);
free(http_request->Method);
free(http_request->URI);
free(http_request);
}
free(http_request->Content);
free(http_request->Method);
free(http_request->URI);
free(http_request);
}
BOOL http_response_parse_header_status_line(HttpResponse* http_response, char* status_line)
@ -300,58 +333,52 @@ BOOL http_response_parse_header_status_line(HttpResponse* http_response, char* s
*separator = '\0';
http_response->StatusCode = atoi(status_code);
http_response->ReasonPhrase = _strdup(reason_phrase);
if (!http_response->ReasonPhrase)
return FALSE;
*separator = ' ';
return TRUE;
}
void http_response_parse_header_field(HttpResponse* http_response, char* name, char* value)
BOOL http_response_parse_header_field(HttpResponse* http_response, char* name, char* value)
{
if (_stricmp(name, "Content-Length") == 0)
{
http_response->ContentLength = atoi(value);
}
else if (_stricmp(name, "Authorization") == 0)
{
char* separator;
http_response->Authorization = _strdup(value);
separator = strchr(value, ' ');
if (separator != NULL)
{
*separator = '\0';
http_response->AuthScheme = _strdup(value);
http_response->AuthParam = _strdup(separator + 1);
*separator = ' ';
}
}
else if (_stricmp(name, "WWW-Authenticate") == 0)
{
char* separator;
separator = strstr(value, "=\"");
if (separator != NULL)
{
/* WWW-Authenticate: parameter with spaces="value" */
return;
}
char *authScheme, *authValue;
separator = strchr(value, ' ');
if (separator != NULL)
{
/* WWW-Authenticate: NTLM base64token */
/* WWW-Authenticate: Basic realm=""
* WWW-Authenticate: NTLM base64token
* WWW-Authenticate: Digest realm="testrealm@host.com", qop="auth, auth-int",
* nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
* opaque="5ccc069c403ebaf9f0171e9517f40e41"
*/
*separator = '\0';
http_response->AuthScheme = _strdup(value);
http_response->AuthParam = _strdup(separator + 1);
*separator = ' ';
return;
authScheme = _strdup(value);
authValue = _strdup(separator + 1);
if (!authScheme || !authValue)
return FALSE;
*separator = ' ';
}
else
{
authScheme = _strdup(value);
if (!authScheme)
return FALSE;
authValue = NULL;
}
return ListDictionary_Add(http_response->Authenticates, authScheme, authValue);
}
return TRUE;
}
BOOL http_response_parse_header(HttpResponse* http_response)
@ -412,7 +439,8 @@ BOOL http_response_parse_header(HttpResponse* http_response)
break;
}
http_response_parse_header_field(http_response, name, value);
if (!http_response_parse_header_field(http_response, name, value))
return FALSE;
*end_of_header = end_of_header_char;
}
@ -445,7 +473,12 @@ HttpResponse* http_response_recv(rdpTls* tls)
length = 10000;
content = NULL;
buffer = malloc(length);
if (!buffer)
return NULL;
http_response = http_response_new();
if (!http_response)
goto out_free;
p = buffer;
http_response->ContentLength = 0;
@ -456,20 +489,14 @@ HttpResponse* http_response_recv(rdpTls* tls)
{
status = tls_read(tls, p, length - nbytes);
if (status > 0)
{
nbytes += status;
p = (BYTE*) &buffer[nbytes];
}
else if (status == 0)
{
if (status < 0)
goto out_error;
if (!status)
continue;
}
else
{
http_response_free(http_response);
return NULL;
}
nbytes += status;
p = (BYTE*) &buffer[nbytes];
}
header_end = strstr((char*) buffer, "\r\n\r\n");
@ -478,8 +505,7 @@ HttpResponse* http_response_recv(rdpTls* tls)
{
fprintf(stderr, "http_response_recv: invalid response:\n");
winpr_HexDump(buffer, status);
http_response_free(http_response);
return NULL;
goto out_error;
}
header_end += 2;
@ -505,8 +531,9 @@ HttpResponse* http_response_recv(rdpTls* tls)
http_response->count = count;
if (count)
{
http_response->lines = (char**) malloc(sizeof(char*) * http_response->count);
ZeroMemory(http_response->lines, sizeof(char*) * http_response->count);
http_response->lines = (char **)calloc(http_response->count, sizeof(char *));
if (!http_response->lines)
goto out_error;
}
count = 0;
@ -515,19 +542,21 @@ HttpResponse* http_response_recv(rdpTls* tls)
while (line != NULL)
{
http_response->lines[count] = _strdup(line);
if (!http_response->lines[count])
goto out_error;
line = strtok(NULL, "\r\n");
count++;
}
if (!http_response_parse_header(http_response))
{
http_response_free(http_response);
return NULL;
}
goto out_error;
if (http_response->ContentLength > 0)
{
http_response->Content = _strdup(content);
if (!http_response->Content)
goto out_error;
}
break;
@ -544,42 +573,61 @@ HttpResponse* http_response_recv(rdpTls* tls)
free(buffer);
return http_response;
out_error:
http_response_free(http_response);
out_free:
free(buffer);
return NULL;
}
static BOOL strings_equals_nocase(void *obj1, void *obj2)
{
if (!obj1 || !obj2)
return FALSE;
return _stricmp(obj1, obj2) == 0;
}
static void string_free(void *obj1)
{
if (!obj1)
return;
free(obj1);
}
HttpResponse* http_response_new()
{
HttpResponse* http_response;
HttpResponse *ret = (HttpResponse *)calloc(1, sizeof(HttpResponse));
if (!ret)
return NULL;
http_response = (HttpResponse*) malloc(sizeof(HttpResponse));
if (http_response != NULL)
{
ZeroMemory(http_response, sizeof(HttpResponse));
}
return http_response;
ret->Authenticates = ListDictionary_New(FALSE);
ListDictionary_KeyObject(ret->Authenticates)->fnObjectEquals = strings_equals_nocase;
ListDictionary_KeyObject(ret->Authenticates)->fnObjectFree = string_free;
ListDictionary_ValueObject(ret->Authenticates)->fnObjectEquals = strings_equals_nocase;
ListDictionary_ValueObject(ret->Authenticates)->fnObjectFree = string_free;
return ret;
}
void http_response_free(HttpResponse* http_response)
{
int i;
if (http_response != NULL)
{
for (i = 0; i < http_response->count; i++)
free(http_response->lines[i]);
if (!http_response)
return;
free(http_response->lines);
for (i = 0; i < http_response->count; i++)
free(http_response->lines[i]);
free(http_response->ReasonPhrase);
free(http_response->lines);
free(http_response->AuthParam);
free(http_response->AuthScheme);
free(http_response->Authorization);
free(http_response->ReasonPhrase);
if (http_response->ContentLength > 0)
free(http_response->Content);
ListDictionary_Free(http_response->Authenticates);
free(http_response);
}
if (http_response->ContentLength > 0)
free(http_response->Content);
free(http_response);
}

View File

@ -55,9 +55,6 @@ void http_context_free(HttpContext* http_context);
struct _http_request
{
int count;
char** lines;
char* Method;
char* URI;
char* AuthScheme;
@ -85,9 +82,7 @@ struct _http_response
int StatusCode;
char* ReasonPhrase;
char* AuthScheme;
char* AuthParam;
char* Authorization;
wListDictionary *Authenticates;
int ContentLength;
char* Content;
};

View File

@ -92,23 +92,27 @@ int rpc_ncacn_http_send_in_channel_request(rdpRpc* rpc)
int rpc_ncacn_http_recv_in_channel_response(rdpRpc* rpc)
{
int ntlm_token_length;
BYTE* ntlm_token_data;
int ntlm_token_length = 0;
BYTE* ntlm_token_data = NULL;
HttpResponse* http_response;
rdpNtlm* ntlm = rpc->NtlmHttpIn->ntlm;
http_response = http_response_recv(rpc->TlsIn);
if (http_response->AuthParam)
if (ListDictionary_Contains(http_response->Authenticates, "NTLM"))
{
ntlm_token_data = NULL;
crypto_base64_decode((BYTE*) http_response->AuthParam, strlen(http_response->AuthParam),
&ntlm_token_data, &ntlm_token_length);
char *token64 = ListDictionary_GetItemValue(http_response->Authenticates, "NTLM");
if (!token64)
goto out;
ntlm->inputBuffer[0].pvBuffer = ntlm_token_data;
ntlm->inputBuffer[0].cbBuffer = ntlm_token_length;
ntlm_token_data = NULL;
crypto_base64_decode((BYTE*) token64, strlen(token64), &ntlm_token_data, &ntlm_token_length);
}
ntlm->inputBuffer[0].pvBuffer = ntlm_token_data;
ntlm->inputBuffer[0].cbBuffer = ntlm_token_length;
out:
http_response_free(http_response);
return 0;
@ -231,10 +235,10 @@ int rpc_ncacn_http_recv_out_channel_response(rdpRpc* rpc)
http_response = http_response_recv(rpc->TlsOut);
ntlm_token_data = NULL;
if (http_response && http_response->AuthParam)
if (http_response && ListDictionary_Contains(http_response->Authenticates, "NTLM"))
{
crypto_base64_decode((BYTE*) http_response->AuthParam, strlen(http_response->AuthParam),
&ntlm_token_data, &ntlm_token_length);
char *token64 = ListDictionary_GetItemValue(http_response->Authenticates, "NTLM");
crypto_base64_decode((BYTE*) token64, strlen(token64), &ntlm_token_data, &ntlm_token_length);
}
ntlm->inputBuffer[0].pvBuffer = ntlm_token_data;
@ -307,25 +311,35 @@ rdpNtlmHttp* ntlm_http_new()
{
rdpNtlmHttp* ntlm_http;
ntlm_http = (rdpNtlmHttp*) malloc(sizeof(rdpNtlmHttp));
ntlm_http = (rdpNtlmHttp *)calloc(1, sizeof(rdpNtlmHttp));
if (ntlm_http != NULL)
{
ZeroMemory(ntlm_http, sizeof(rdpNtlmHttp));
ntlm_http->ntlm = ntlm_new();
ntlm_http->context = http_context_new();
}
if (!ntlm_http)
return NULL;
ntlm_http->ntlm = ntlm_new();
if (!ntlm_http->ntlm)
goto out_free;
ntlm_http->context = http_context_new();
if (!ntlm_http->context)
goto out_free_ntlm;
return ntlm_http;
out_free_ntlm:
ntlm_free(ntlm_http->ntlm);
out_free:
free(ntlm_http);
return NULL;
}
void ntlm_http_free(rdpNtlmHttp* ntlm_http)
{
if (ntlm_http != NULL)
{
ntlm_free(ntlm_http->ntlm);
http_context_free(ntlm_http->context);
if (!ntlm_http)
return;
free(ntlm_http);
}
ntlm_free(ntlm_http->ntlm);
http_context_free(ntlm_http->context);
free(ntlm_http);
}

View File

@ -137,6 +137,8 @@ BOOL ntlm_client_make_spn(rdpNtlm* ntlm, LPCTSTR ServiceClass, char* hostname)
if (!ServiceClass)
{
ntlm->ServicePrincipalName = (LPTSTR) _tcsdup(hostnameX);
if (!ntlm->ServicePrincipalName)
return FALSE;
return TRUE;
}
@ -147,6 +149,8 @@ BOOL ntlm_client_make_spn(rdpNtlm* ntlm, LPCTSTR ServiceClass, char* hostname)
return FALSE;
ntlm->ServicePrincipalName = (LPTSTR) malloc(SpnLength * sizeof(TCHAR));
if (!ntlm->ServicePrincipalName)
return FALSE;
status = DsMakeSpn(ServiceClass, hostnameX, NULL, 0, NULL, &SpnLength, ntlm->ServicePrincipalName);
@ -210,6 +214,8 @@ BOOL ntlm_authenticate(rdpNtlm* ntlm)
ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
if (!ntlm->outputBuffer[0].pvBuffer)
return FALSE;
if (ntlm->haveInputBuffer)
{
@ -286,14 +292,7 @@ void ntlm_client_uninit(rdpNtlm* ntlm)
rdpNtlm* ntlm_new()
{
rdpNtlm* ntlm = (rdpNtlm*) malloc(sizeof(rdpNtlm));
if (ntlm != NULL)
{
ZeroMemory(ntlm, sizeof(rdpNtlm));
}
return ntlm;
return (rdpNtlm *)calloc(1, sizeof(rdpNtlm));
}
void ntlm_free(rdpNtlm* ntlm)

View File

@ -497,20 +497,27 @@ void rpc_client_virtual_connection_init(rdpRpc* rpc, RpcVirtualConnection* conne
RpcVirtualConnection* rpc_client_virtual_connection_new(rdpRpc* rpc)
{
RpcVirtualConnection* connection = (RpcVirtualConnection*) malloc(sizeof(RpcVirtualConnection));
RpcVirtualConnection* connection = (RpcVirtualConnection*) calloc(1, sizeof(RpcVirtualConnection));
if (connection != NULL)
{
ZeroMemory(connection, sizeof(RpcVirtualConnection));
connection->State = VIRTUAL_CONNECTION_STATE_INITIAL;
connection->DefaultInChannel = (RpcInChannel*) malloc(sizeof(RpcInChannel));
connection->DefaultOutChannel = (RpcOutChannel*) malloc(sizeof(RpcOutChannel));
ZeroMemory(connection->DefaultInChannel, sizeof(RpcInChannel));
ZeroMemory(connection->DefaultOutChannel, sizeof(RpcOutChannel));
rpc_client_virtual_connection_init(rpc, connection);
}
if (!connection)
return NULL;
connection->State = VIRTUAL_CONNECTION_STATE_INITIAL;
connection->DefaultInChannel = (RpcInChannel *)calloc(1, sizeof(RpcInChannel));
if (!connection->DefaultInChannel)
goto out_free;
connection->DefaultOutChannel = (RpcOutChannel*)calloc(1, sizeof(RpcOutChannel));
if (!connection->DefaultOutChannel)
goto out_default_in;
rpc_client_virtual_connection_init(rpc, connection);
return connection;
out_default_in:
free(connection->DefaultInChannel);
out_free:
free(connection);
return NULL;
}
void rpc_client_virtual_connection_free(RpcVirtualConnection* virtual_connection)
@ -525,64 +532,84 @@ void rpc_client_virtual_connection_free(RpcVirtualConnection* virtual_connection
rdpRpc* rpc_new(rdpTransport* transport)
{
rdpRpc* rpc = (rdpRpc*) malloc(sizeof(rdpRpc));
rdpRpc* rpc = (rdpRpc*) calloc(1, sizeof(rdpRpc));
if (!rpc)
return NULL;
if (rpc != NULL)
{
ZeroMemory(rpc, sizeof(rdpRpc));
rpc->State = RPC_CLIENT_STATE_INITIAL;
rpc->State = RPC_CLIENT_STATE_INITIAL;
rpc->transport = transport;
rpc->settings = transport->settings;
rpc->transport = transport;
rpc->settings = transport->settings;
rpc->SendSeqNum = 0;
rpc->ntlm = ntlm_new();
if (!rpc->ntlm)
goto out_free;
rpc->SendSeqNum = 0;
rpc->ntlm = ntlm_new();
rpc->NtlmHttpIn = ntlm_http_new();
if (!rpc->NtlmHttpIn)
goto out_free_ntlm;
rpc->NtlmHttpOut = ntlm_http_new();
if (!rpc->NtlmHttpOut)
goto out_free_ntlm_http_in;
rpc->NtlmHttpIn = ntlm_http_new();
rpc->NtlmHttpOut = ntlm_http_new();
rpc_ntlm_http_init_channel(rpc, rpc->NtlmHttpIn, TSG_CHANNEL_IN);
rpc_ntlm_http_init_channel(rpc, rpc->NtlmHttpOut, TSG_CHANNEL_OUT);
rpc_ntlm_http_init_channel(rpc, rpc->NtlmHttpIn, TSG_CHANNEL_IN);
rpc_ntlm_http_init_channel(rpc, rpc->NtlmHttpOut, TSG_CHANNEL_OUT);
rpc->PipeCallId = 0;
rpc->PipeCallId = 0;
rpc->StubCallId = 0;
rpc->StubFragCount = 0;
rpc->StubCallId = 0;
rpc->StubFragCount = 0;
rpc->rpc_vers = 5;
rpc->rpc_vers_minor = 0;
rpc->rpc_vers = 5;
rpc->rpc_vers_minor = 0;
/* little-endian data representation */
rpc->packed_drep[0] = 0x10;
rpc->packed_drep[1] = 0x00;
rpc->packed_drep[2] = 0x00;
rpc->packed_drep[3] = 0x00;
/* little-endian data representation */
rpc->packed_drep[0] = 0x10;
rpc->packed_drep[1] = 0x00;
rpc->packed_drep[2] = 0x00;
rpc->packed_drep[3] = 0x00;
rpc->max_xmit_frag = 0x0FF8;
rpc->max_recv_frag = 0x0FF8;
rpc->max_xmit_frag = 0x0FF8;
rpc->max_recv_frag = 0x0FF8;
rpc->ReceiveWindow = 0x00010000;
rpc->ReceiveWindow = 0x00010000;
rpc->ChannelLifetime = 0x40000000;
rpc->ChannelLifetimeSet = 0;
rpc->ChannelLifetime = 0x40000000;
rpc->ChannelLifetimeSet = 0;
rpc->KeepAliveInterval = 300000;
rpc->CurrentKeepAliveInterval = rpc->KeepAliveInterval;
rpc->CurrentKeepAliveTime = 0;
rpc->KeepAliveInterval = 300000;
rpc->CurrentKeepAliveInterval = rpc->KeepAliveInterval;
rpc->CurrentKeepAliveTime = 0;
rpc->VirtualConnection = rpc_client_virtual_connection_new(rpc);
if (!rpc->VirtualConnection)
goto out_free_ntlm_http_out;
rpc->VirtualConnection = rpc_client_virtual_connection_new(rpc);
rpc->VirtualConnectionCookieTable = ArrayList_New(TRUE);
rpc->VirtualConnectionCookieTable = ArrayList_New(TRUE);
if (!rpc->VirtualConnectionCookieTable)
goto out_free_virtual_connection;
rpc->CallId = 2;
rpc->CallId = 2;
rpc_client_new(rpc);
rpc_client_new(rpc);
rpc->client->SynchronousSend = TRUE;
rpc->client->SynchronousReceive = TRUE;
}
rpc->client->SynchronousSend = TRUE;
rpc->client->SynchronousReceive = TRUE;
return rpc;
out_free_virtual_connection:
rpc_client_virtual_connection_free(rpc->VirtualConnection);
out_free_ntlm_http_out:
ntlm_http_free(rpc->NtlmHttpOut);
out_free_ntlm_http_in:
ntlm_http_free(rpc->NtlmHttpIn);
out_free_ntlm:
ntlm_free(rpc->ntlm);
out_free:
free(rpc);
return NULL;
}
void rpc_free(rdpRpc* rpc)

View File

@ -554,14 +554,10 @@ int rpc_client_new(rdpRpc* rpc)
{
RpcClient* client = NULL;
client = (RpcClient*) malloc(sizeof(RpcClient));
client = (RpcClient*) calloc(1, sizeof(RpcClient));
if (client)
{
client->Thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) rpc_client_thread,
rpc, CREATE_SUSPENDED, NULL);
client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
client->PduSentEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
@ -592,16 +588,21 @@ int rpc_client_new(rdpRpc* rpc)
int rpc_client_start(rdpRpc* rpc)
{
ResumeThread(rpc->client->Thread);
rpc->client->Thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) rpc_client_thread,
rpc, 0, NULL);
return 0;
}
int rpc_client_stop(rdpRpc* rpc)
{
SetEvent(rpc->client->StopEvent);
WaitForSingleObject(rpc->client->Thread, INFINITE);
if (rpc->client->Thread)
{
SetEvent(rpc->client->StopEvent);
WaitForSingleObject(rpc->client->Thread, INFINITE);
rpc->client->Thread = NULL;
}
rpc_client_free(rpc);

View File

@ -360,6 +360,10 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu)
if (MsgBytes > TSG_MESSAGING_MAX_MESSAGE_LENGTH)
{
fprintf(stderr, "Out of Spec Message Length %d", MsgBytes);
free(tsgCaps);
free(versionCaps);
free(packetCapsResponse);
free(packet);
return FALSE;
}
offset += MsgBytes;
@ -373,6 +377,10 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu)
default:
fprintf(stderr, "Unexpected Message Type: 0x%X\n", (int) MessageSwitchValue);
free(tsgCaps);
free(versionCaps);
free(packetCapsResponse);
free(packet);
return FALSE;
}
@ -619,6 +627,7 @@ BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu)
{
fprintf(stderr, "status: E_PROXY_NAP_ACCESSDENIED (0x%08X)\n", E_PROXY_NAP_ACCESSDENIED);
fprintf(stderr, "Ensure that the Gateway Connection Authorization Policy is correct\n");
free(packet);
return FALSE;
}

View File

@ -407,16 +407,17 @@ void gcc_write_client_data_blocks(wStream* s, rdpMcs* mcs)
if (settings->NegotiationFlags & EXTENDED_CLIENT_DATA_SUPPORTED)
{
if (settings->SpanMonitors)
if (settings->UseMultimon && !settings->SpanMonitors)
{
gcc_write_client_monitor_data(s, mcs);
}
gcc_write_client_message_channel_data(s, mcs);
gcc_write_client_multitransport_channel_data(s, mcs);
}
else
{
if (settings->UseMultimon)
if (settings->UseMultimon && !settings->SpanMonitors)
{
fprintf(stderr, "WARNING: true multi monitor support was not advertised by server!\n");
@ -915,6 +916,8 @@ BOOL gcc_read_client_security_data(wStream* s, rdpMcs* mcs, UINT16 blockLength)
Stream_Read_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */
if (settings->EncryptionMethods == 0)
Stream_Read_UINT32(s, settings->EncryptionMethods); /* extEncryptionMethods */
else
Stream_Seek(s, 4);
}
else
{
@ -1081,6 +1084,10 @@ void gcc_write_server_security_data(wStream* s, rdpMcs* mcs)
{
settings->EncryptionMethods = ENCRYPTION_METHOD_128BIT;
}
else if ((settings->EncryptionMethods & ENCRYPTION_METHOD_56BIT) != 0)
{
settings->EncryptionMethods = ENCRYPTION_METHOD_56BIT;
}
else if ((settings->EncryptionMethods & ENCRYPTION_METHOD_40BIT) != 0)
{
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT;
@ -1166,11 +1173,17 @@ void gcc_write_server_security_data(wStream* s, rdpMcs* mcs)
sigDataLen = Stream_Pointer(s) - sigData;
Stream_Write_UINT16(s, BB_RSA_SIGNATURE_BLOB); /* wSignatureBlobType */
Stream_Write_UINT16(s, keyLen + 8); /* wSignatureBlobLen */
Stream_Write_UINT16(s, sizeof(encryptedSignature) + 8); /* wSignatureBlobLen */
memcpy(signature, initial_signature, sizeof(initial_signature));
md5 = crypto_md5_init();
if (!md5)
{
fprintf(stderr, "%s: unable to allocate a md5\n", __FUNCTION__);
return;
}
crypto_md5_update(md5, sigData, sigDataLen);
crypto_md5_final(md5, signature);

View File

@ -248,6 +248,11 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings)
clientCookie->logonId = serverCookie->logonId;
hmac = crypto_hmac_new();
if (!hmac)
{
fprintf(stderr, "%s: unable to allocate hmac\n", __FUNCTION__);
goto out_free;
}
crypto_hmac_md5_init(hmac, serverCookie->arcRandomBits, 16);
@ -270,11 +275,12 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings)
rdp_write_client_auto_reconnect_cookie(s, settings); /* autoReconnectCookie */
/* mark as used */
settings->ServerAutoReconnectCookie->cbLen = 0;
crypto_hmac_free(hmac);
}
/* reserved1 (2 bytes) */
/* reserved2 (2 bytes) */
out_free:
free(clientAddress);
free(clientDir);
}

View File

@ -163,7 +163,7 @@ void input_send_focus_in_event(rdpInput* input, UINT16 toggleStates, UINT16 x, U
input_send_keyboard_event(input, KBD_FLAGS_RELEASE, 0x0f);
/* finish with a mouse pointer position like mstsc.exe */
input_send_extended_mouse_event(input, PTR_FLAGS_MOVE, x, y);
input_send_mouse_event(input, PTR_FLAGS_MOVE, x, y);
}
void input_send_fastpath_synchronize_event(rdpInput* input, UINT32 flags)

View File

@ -3,6 +3,7 @@
* RDP Licensing
*
* Copyright 2011-2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -163,8 +164,15 @@ wStream* license_send_stream_init(rdpLicense* license)
{
wStream* s;
s = Stream_New(NULL, 4096);
Stream_Seek(s, LICENSE_PACKET_HEADER_MAX_LENGTH);
license->rdp->sec_flags = SEC_LICENSE_PKT;
if (license->rdp->do_crypt)
license->rdp->sec_flags |= SEC_LICENSE_ENCRYPT_CS;
s = transport_send_stream_init(license->rdp->transport, 4096);
rdp_init_stream(license->rdp, s);
license->PacketHeaderLength = Stream_GetPosition(s);
Stream_Seek(s, LICENSE_PREAMBLE_LENGTH);
return s;
}
@ -181,15 +189,13 @@ BOOL license_send(rdpLicense* license, wStream* s, BYTE type)
int length;
BYTE flags;
UINT16 wMsgSize;
UINT16 sec_flags;
rdpRdp* rdp = license->rdp;
DEBUG_LICENSE("Sending %s Packet", LICENSE_MESSAGE_STRINGS[type & 0x1F]);
length = Stream_GetPosition(s);
Stream_SetPosition(s, 0);
sec_flags = SEC_LICENSE_PKT;
wMsgSize = length - LICENSE_PACKET_HEADER_MAX_LENGTH + 4;
wMsgSize = length - license->PacketHeaderLength;
Stream_SetPosition(s, license->PacketHeaderLength);
flags = PREAMBLE_VERSION_3_0;
@ -198,25 +204,20 @@ BOOL license_send(rdpLicense* license, wStream* s, BYTE type)
* running in server mode! This flag seems to be incorrectly documented.
*/
if (!license->rdp->settings->ServerMode)
if (!rdp->settings->ServerMode)
flags |= EXTENDED_ERROR_MSG_SUPPORTED;
rdp_write_header(license->rdp, s, length, MCS_GLOBAL_CHANNEL_ID);
rdp_write_security_header(s, sec_flags);
license_write_preamble(s, type, flags, wMsgSize);
#ifdef WITH_DEBUG_LICENSE
fprintf(stderr, "Sending %s Packet, length %d\n", LICENSE_MESSAGE_STRINGS[type & 0x1F], wMsgSize);
winpr_HexDump(Stream_Pointer(s) - 4, wMsgSize);
winpr_HexDump(Stream_Pointer(s) - LICENSE_PREAMBLE_LENGTH, wMsgSize);
#endif
Stream_SetPosition(s, length);
Stream_SealLength(s);
rdp_send(rdp, s, MCS_GLOBAL_CHANNEL_ID);
if (transport_write(license->rdp->transport, s) < 0)
return FALSE;
Stream_Free(s, TRUE);
rdp->sec_flags = 0;
return TRUE;
}
@ -392,6 +393,12 @@ void license_generate_hwid(rdpLicense* license)
mac_address = license->rdp->transport->TcpIn->mac_address;
md5 = crypto_md5_init();
if (!md5)
{
fprintf(stderr, "%s: unable to allocate a md5\n", __FUNCTION__);
return;
}
crypto_md5_update(md5, mac_address, 6);
crypto_md5_final(md5, &license->HardwareId[HWID_PLATFORM_ID_LENGTH]);
}
@ -458,6 +465,11 @@ void license_decrypt_platform_challenge(rdpLicense* license)
license->PlatformChallenge->length = license->EncryptedPlatformChallenge->length;
rc4 = crypto_rc4_init(license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH);
if (!rc4)
{
fprintf(stderr, "%s: unable to allocate a rc4\n", __FUNCTION__);
return;
}
crypto_rc4(rc4, license->EncryptedPlatformChallenge->length,
license->EncryptedPlatformChallenge->data,
@ -763,7 +775,7 @@ BOOL license_read_license_request_packet(rdpLicense* license, wStream* s)
/* Parse Server Certificate */
if (!certificate_read_server_certificate(license->certificate,
license->ServerCertificate->data, license->ServerCertificate->length) < 0)
license->ServerCertificate->data, license->ServerCertificate->length))
return FALSE;
license_generate_keys(license);
@ -1042,6 +1054,12 @@ void license_send_platform_challenge_response_packet(rdpLicense* license)
buffer = (BYTE*) malloc(HWID_LENGTH);
rc4 = crypto_rc4_init(license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH);
if (!rc4)
{
fprintf(stderr, "%s: unable to allocate a rc4\n", __FUNCTION__);
free(buffer);
return;
}
crypto_rc4(rc4, HWID_LENGTH, license->HardwareId, buffer);
crypto_rc4_free(rc4);

View File

@ -48,7 +48,6 @@ typedef struct rdp_license rdpLicense;
#define LICENSE_PKT_MASK (LICENSE_PKT_CS_MASK | LICENSE_PKT_SC_MASK)
#define LICENSE_PREAMBLE_LENGTH 4
#define LICENSE_PACKET_HEADER_MAX_LENGTH (RDP_PACKET_HEADER_MAX_LENGTH + RDP_SECURITY_HEADER_LENGTH + LICENSE_PREAMBLE_LENGTH)
/* Cryptographic Lengths */
@ -198,6 +197,7 @@ struct rdp_license
LICENSE_BLOB* EncryptedPlatformChallenge;
LICENSE_BLOB* EncryptedHardwareId;
SCOPE_LIST* ScopeList;
UINT32 PacketHeaderLength;
};
int license_recv(rdpLicense* license, wStream* s);

View File

@ -1037,7 +1037,7 @@ BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs)
mcs_write_domain_mcspdu_header(s, DomainMCSPDU_DisconnectProviderUltimatum, length, 1);
per_write_enumerated(s, 0, 0); /* reason */
per_write_enumerated(s, 0x80, 0);
status = transport_write(mcs->transport, s);
@ -1087,6 +1087,7 @@ void mcs_free(rdpMcs* mcs)
{
if (mcs)
{
free(mcs->channels);
free(mcs);
}
}

View File

@ -88,6 +88,7 @@ BOOL nego_connect(rdpNego* nego)
{
DEBUG_NEGO("No security protocol is enabled");
nego->state = NEGO_STATE_FAIL;
return FALSE;
}
if (!nego->NegotiateSecurityLayer)
@ -156,7 +157,7 @@ BOOL nego_connect(rdpNego* nego)
if (nego->selected_protocol == PROTOCOL_RDP)
{
nego->transport->settings->DisableEncryption = TRUE;
nego->transport->settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
nego->transport->settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
nego->transport->settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
}
@ -212,7 +213,27 @@ BOOL nego_security_connect(rdpNego* nego)
BOOL nego_tcp_connect(rdpNego* nego)
{
if (!nego->tcp_connected)
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port);
{
if (nego->GatewayEnabled)
{
if (nego->GatewayBypassLocal)
{
/* Attempt a direct connection first, and then fallback to using the gateway */
transport_set_gateway_enabled(nego->transport, FALSE);
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port);
}
if (!nego->tcp_connected)
{
transport_set_gateway_enabled(nego->transport, TRUE);
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port);
}
}
else
{
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port);
}
}
return nego->tcp_connected;
}
@ -479,9 +500,10 @@ BOOL nego_recv_response(rdpNego* nego)
wStream* s;
s = Stream_New(NULL, 1024);
if (!s)
return FALSE;
status = transport_read(nego->transport, s);
if (status < 0)
{
Stream_Free(s, TRUE);
@ -851,6 +873,8 @@ BOOL nego_send_negotiation_response(rdpNego* nego)
settings = nego->transport->settings;
s = Stream_New(NULL, 512);
if (!s)
return FALSE;
length = TPDU_CONNECTION_CONFIRM_LENGTH;
bm = Stream_GetPosition(s);
@ -881,7 +905,7 @@ BOOL nego_send_negotiation_response(rdpNego* nego)
* TODO: Check for other possibilities,
* like SSL_NOT_ALLOWED_BY_SERVER.
*/
fprintf(stderr, "nego_send_negotiation_response: client supports only Standard RDP Security\n");
fprintf(stderr, "%s: client supports only Standard RDP Security\n", __FUNCTION__);
Stream_Write_UINT32(s, SSL_REQUIRED_BY_SERVER);
length += 8;
status = FALSE;
@ -918,11 +942,11 @@ BOOL nego_send_negotiation_response(rdpNego* nego)
if (!settings->LocalConnection)
{
settings->DisableEncryption = TRUE;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
}
if (settings->DisableEncryption && settings->RdpServerRsaKey == NULL && settings->RdpKeyFile == NULL)
if (settings->DisableEncryption && !settings->RdpServerRsaKey && !settings->RdpKeyFile)
return FALSE;
}
else if (settings->SelectedProtocol == PROTOCOL_TLS)
@ -972,15 +996,13 @@ void nego_init(rdpNego* nego)
rdpNego* nego_new(rdpTransport* transport)
{
rdpNego* nego = (rdpNego*) malloc(sizeof(rdpNego));
rdpNego* nego = (rdpNego*) calloc(1, sizeof(rdpNego));
if (!nego)
return NULL;
if (nego)
{
ZeroMemory(nego, sizeof(rdpNego));
nego->transport = transport;
nego_init(nego);
}
nego->transport = transport;
nego_init(nego);
return nego;
}
@ -1034,6 +1056,16 @@ void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdmin
nego->RestrictedAdminModeRequired = RestrictedAdminModeRequired;
}
void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled)
{
nego->GatewayEnabled = GatewayEnabled;
}
void nego_set_gateway_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal)
{
nego->GatewayBypassLocal = GatewayBypassLocal;
}
/**
* Enable RDP security protocol.
* @param nego pointer to the negotiation structure
@ -1089,12 +1121,15 @@ void nego_enable_ext(rdpNego* nego, BOOL enable_ext)
* @param RoutingTokenLength
*/
void nego_set_routing_token(rdpNego* nego, BYTE* RoutingToken, DWORD RoutingTokenLength)
BOOL nego_set_routing_token(rdpNego* nego, BYTE* RoutingToken, DWORD RoutingTokenLength)
{
free(nego->RoutingToken);
nego->RoutingTokenLength = RoutingTokenLength;
nego->RoutingToken = (BYTE*) malloc(nego->RoutingTokenLength);
if (!nego->RoutingToken)
return FALSE;
CopyMemory(nego->RoutingToken, RoutingToken, nego->RoutingTokenLength);
return TRUE;
}
/**
@ -1103,12 +1138,21 @@ void nego_set_routing_token(rdpNego* nego, BYTE* RoutingToken, DWORD RoutingToke
* @param cookie
*/
void nego_set_cookie(rdpNego* nego, char* cookie)
BOOL nego_set_cookie(rdpNego* nego, char* cookie)
{
if (nego->cookie)
{
free(nego->cookie);
nego->cookie = 0;
}
if (!cookie)
return TRUE;
nego->cookie = _strdup(cookie);
if (!nego->cookie)
return FALSE;
return TRUE;
}
/**

View File

@ -110,6 +110,8 @@ struct rdp_nego
BOOL NegotiateSecurityLayer;
BYTE enabled_protocols[16];
BOOL RestrictedAdminModeRequired;
BOOL GatewayEnabled;
BOOL GatewayBypassLocal;
rdpTransport* transport;
};
@ -142,12 +144,14 @@ void nego_init(rdpNego* nego);
void nego_set_target(rdpNego* nego, char* hostname, int port);
void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer_enabled);
void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdminModeRequired);
void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled);
void nego_set_gateway_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal);
void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp);
void nego_enable_tls(rdpNego* nego, BOOL enable_tls);
void nego_enable_nla(rdpNego* nego, BOOL enable_nla);
void nego_enable_ext(rdpNego* nego, BOOL enable_ext);
void nego_set_routing_token(rdpNego* nego, BYTE* RoutingToken, DWORD RoutingTokenLength);
void nego_set_cookie(rdpNego* nego, char* cookie);
BOOL nego_set_routing_token(rdpNego* nego, BYTE* RoutingToken, DWORD RoutingTokenLength);
BOOL nego_set_cookie(rdpNego* nego, char* cookie);
void nego_set_cookie_max_length(rdpNego* nego, UINT32 cookie_max_length);
void nego_set_send_preconnection_pdu(rdpNego* nego, BOOL send_pcpdu);
void nego_set_preconnection_id(rdpNego* nego, UINT32 id);

Some files were not shown because too many files have changed in this diff Show More