hardend serial channel

This commit is contained in:
Martin Haimberger 2015-06-12 02:24:45 -07:00
parent dc68bdfce5
commit 62d7b1e4df

View File

@ -40,6 +40,9 @@
#include <freerdp/freerdp.h> #include <freerdp/freerdp.h>
#include <freerdp/channels/rdpdr.h> #include <freerdp/channels/rdpdr.h>
#include <freerdp/channels/log.h>
#define TAG CHANNELS_TAG("serial.client")
/* TODO: all #ifdef __linux__ could be removed once only some generic /* TODO: all #ifdef __linux__ could be removed once only some generic
* functions will be used. Replace CommReadFile by ReadFile, * functions will be used. Replace CommReadFile by ReadFile,
@ -226,7 +229,7 @@ static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
Stream_Zero(irp->output, 5); /* Padding (5 bytes) */ Stream_Zero(irp->output, 5); /* Padding (5 bytes) */
} }
static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) static WIN32ERROR serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
{ {
UINT32 Length; UINT32 Length;
UINT64 Offset; UINT64 Offset;
@ -273,11 +276,17 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
if (nbRead > 0) if (nbRead > 0)
{ {
Stream_EnsureRemainingCapacity(irp->output, nbRead); if (!Stream_EnsureRemainingCapacity(irp->output, nbRead))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
free(buffer);
return CHANNEL_RC_NO_MEMORY;
}
Stream_Write(irp->output, buffer, nbRead); /* ReadData */ Stream_Write(irp->output, buffer, nbRead); /* ReadData */
} }
free(buffer); free(buffer);
return CHANNEL_RC_OK;
} }
static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
@ -318,7 +327,7 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
} }
static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) static WIN32ERROR serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
{ {
UINT32 IoControlCode; UINT32 IoControlCode;
UINT32 InputBufferLength; UINT32 InputBufferLength;
@ -376,7 +385,14 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
if (BytesReturned > 0) if (BytesReturned > 0)
{ {
Stream_EnsureRemainingCapacity(irp->output, BytesReturned); if (!Stream_EnsureRemainingCapacity(irp->output, BytesReturned))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
free(InputBuffer);
free(OutputBuffer);
return CHANNEL_RC_NO_MEMORY;
}
Stream_Write(irp->output, OutputBuffer, BytesReturned); /* OutputBuffer */ Stream_Write(irp->output, OutputBuffer, BytesReturned); /* OutputBuffer */
} }
/* FIXME: Why at least Windows 2008R2 gets lost with this /* FIXME: Why at least Windows 2008R2 gets lost with this
@ -390,10 +406,12 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
free(InputBuffer); free(InputBuffer);
free(OutputBuffer); free(OutputBuffer);
return CHANNEL_RC_OK;
} }
static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) static WIN32ERROR serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
{ {
WIN32ERROR error = CHANNEL_RC_OK;
WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: 0x%04X MinorFunction: 0x%04X\n", WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: 0x%04X MinorFunction: 0x%04X\n",
irp->MajorFunction, irp->MinorFunction); irp->MajorFunction, irp->MinorFunction);
@ -408,7 +426,8 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
break; break;
case IRP_MJ_READ: case IRP_MJ_READ:
serial_process_irp_read(serial, irp); if ((error = serial_process_irp_read(serial, irp)))
WLog_ERR(TAG, "serial_process_irp_read failed with error %lu!", error);
break; break;
case IRP_MJ_WRITE: case IRP_MJ_WRITE:
@ -416,22 +435,26 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
break; break;
case IRP_MJ_DEVICE_CONTROL: case IRP_MJ_DEVICE_CONTROL:
serial_process_irp_device_control(serial, irp); if ((error = serial_process_irp_device_control(serial, irp)))
WLog_ERR(TAG, "serial_process_irp_device_control failed with error %lu!", error);
break; break;
default: default:
irp->IoStatus = STATUS_NOT_SUPPORTED; irp->IoStatus = STATUS_NOT_SUPPORTED;
break; break;
} }
return error;
} }
static void* irp_thread_func(void* arg) static void* irp_thread_func(void* arg)
{ {
IRP_THREAD_DATA *data = (IRP_THREAD_DATA*)arg; IRP_THREAD_DATA *data = (IRP_THREAD_DATA*)arg;
WIN32ERROR error;
/* blocks until the end of the request */ /* blocks until the end of the request */
serial_process_irp(data->serial, data->irp); if ((error = serial_process_irp(data->serial, data->irp)))
WLog_ERR(TAG, "serial_process_irp failed with error %lu", error);
EnterCriticalSection(&data->serial->TerminatingIrpThreadsLock); EnterCriticalSection(&data->serial->TerminatingIrpThreadsLock);
data->serial->IrpThreadToBeTerminatedCount++; data->serial->IrpThreadToBeTerminatedCount++;
@ -680,14 +703,14 @@ static void* serial_thread_func(void* arg)
} }
static void serial_irp_request(DEVICE* device, IRP* irp) static WIN32ERROR serial_irp_request(DEVICE* device, IRP* irp)
{ {
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
assert(irp != NULL); assert(irp != NULL);
if (irp == NULL) if (irp == NULL)
return; return CHANNEL_RC_OK;
/* NB: ENABLE_ASYNCIO is set, (MS-RDPEFS 2.2.2.7.2) this /* NB: ENABLE_ASYNCIO is set, (MS-RDPEFS 2.2.2.7.2) this
* allows the server to send multiple simultaneous read or * allows the server to send multiple simultaneous read or
@ -695,6 +718,7 @@ static void serial_irp_request(DEVICE* device, IRP* irp)
*/ */
MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL); MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL);
return CHANNEL_RC_OK;
} }
@ -726,7 +750,7 @@ static void serial_free(DEVICE* device)
#define DeviceServiceEntry serial_DeviceServiceEntry #define DeviceServiceEntry serial_DeviceServiceEntry
#endif #endif
int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) WIN32ERROR DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
{ {
char* name; char* name;
char* path; char* path;
@ -736,6 +760,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
int i, len; int i, len;
SERIAL_DEVICE* serial; SERIAL_DEVICE* serial;
#endif /* __linux__ */ #endif /* __linux__ */
WIN32ERROR error = CHANNEL_RC_OK;
device = (RDPDR_SERIAL*) pEntryPoints->device; device = (RDPDR_SERIAL*) pEntryPoints->device;
name = device->Name; name = device->Name;
@ -745,7 +770,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
if (!name || (name[0] == '*')) if (!name || (name[0] == '*'))
{ {
/* TODO: implement auto detection of serial ports */ /* TODO: implement auto detection of serial ports */
return 0; return CHANNEL_RC_OK;
} }
if ((name && name[0]) && (path && path[0])) if ((name && name[0]) && (path && path[0]))
@ -759,7 +784,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
#ifndef __linux__ /* to be removed */ #ifndef __linux__ /* to be removed */
WLog_Print(log, WLOG_WARN, "Serial ports redirection not supported on this platform."); WLog_Print(log, WLOG_WARN, "Serial ports redirection not supported on this platform.");
return -1; return CHANNEL_RC_INITIALIZATION_ERROR;
#else /* __linux __ */ #else /* __linux __ */
@ -767,12 +792,16 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */)) if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */))
{ {
return -1; WLog_ERR(TAG, "DefineCommDevice failed!");
return ERROR_INTERNAL_ERROR;
} }
serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE)); serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE));
if (!serial) if (!serial)
return -1; {
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
serial->log = log; serial->log = log;
@ -783,6 +812,12 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
len = strlen(name); len = strlen(name);
serial->device.data = Stream_New(NULL, len + 1); serial->device.data = Stream_New(NULL, len + 1);
if (!serial->device.data)
{
WLog_ERR(TAG, "calloc failed!");
error = CHANNEL_RC_NO_MEMORY;
goto error_out;
}
for (i = 0; i <= len; i++) for (i = 0; i <= len; i++)
Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]); Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]);
@ -828,22 +863,49 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
/* TODO: implement auto detection of the server's serial driver */ /* TODO: implement auto detection of the server's serial driver */
serial->MainIrpQueue = MessageQueue_New(NULL); serial->MainIrpQueue = MessageQueue_New(NULL);
if (!serial->MainIrpQueue)
{
WLog_ERR(TAG, "MessageQueue_New failed!");
error = CHANNEL_RC_NO_MEMORY;
goto error_out;
}
/* IrpThreads content only modified by create_irp_thread() */ /* IrpThreads content only modified by create_irp_thread() */
serial->IrpThreads = ListDictionary_New(FALSE); serial->IrpThreads = ListDictionary_New(FALSE);
if(!serial->IrpThreads)
{
WLog_ERR(TAG, "ListDictionary_New failed!");
error = CHANNEL_RC_NO_MEMORY;
goto error_out;
}
serial->IrpThreadToBeTerminatedCount = 0; serial->IrpThreadToBeTerminatedCount = 0;
InitializeCriticalSection(&serial->TerminatingIrpThreadsLock); InitializeCriticalSection(&serial->TerminatingIrpThreadsLock);
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial); if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial)))
{
WLog_ERR(TAG, "EntryPoints->RegisterDevice failed with error %lu!", error);
goto error_out;
}
serial->MainThread = CreateThread(NULL, if (!(serial->MainThread = CreateThread(NULL,
0, 0,
(LPTHREAD_START_ROUTINE) serial_thread_func, (LPTHREAD_START_ROUTINE) serial_thread_func,
(void*) serial, (void*) serial,
0, 0,
NULL); NULL)))
{
WLog_ERR(TAG, "CreateThread failed!");
error = ERROR_INTERNAL_ERROR;
goto error_out;
}
#endif /* __linux __ */ #endif /* __linux __ */
} }
return 0; return error;
error_out:
ListDictionary_Free(serial->IrpThreads);
MessageQueue_Free(serial->MainIrpQueue);
Stream_Free(serial->device.data, TRUE);
free(serial);
return error;
} }