diff --git a/CMakeLists.txt b/CMakeLists.txt index 98c208f07..f3253a69e 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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") diff --git a/channels/parallel/client/parallel_main.c b/channels/parallel/client/parallel_main.c index 59e201c27..ff6da340a 100644 --- a/channels/parallel/client/parallel_main.c +++ b/channels/parallel/client/parallel_main.c @@ -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; diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index ffb6716db..ff8ff2646 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -45,6 +45,7 @@ #include "serial_constants.h" #include +#include #include #include #include @@ -64,39 +65,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 +97,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 +107,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 +120,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 +133,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 +179,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 +194,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 +258,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 +280,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 +297,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 +329,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 +367,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 +392,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; diff --git a/channels/serial/client/serial_tty.c b/channels/serial/client/serial_tty.c index 95bf375fe..8e051e930 100644 --- a/channels/serial/client/serial_tty.c +++ b/channels/serial/client/serial_tty.c @@ -73,24 +73,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 +124,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 +146,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 +160,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 +177,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 +223,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 +233,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 +292,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 +339,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 +379,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 +420,35 @@ 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) + 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; + } ZeroMemory(buffer, *Length); @@ -424,20 +467,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 +490,7 @@ BOOL serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length) tty->event_txempty = event_txempty; - return TRUE; + return status; } /** @@ -458,9 +502,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 +522,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 +542,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 +568,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 +603,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 +630,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 +645,6 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result) *result |= SERIAL_EV_RXCHAR; status = TRUE; } - } else { @@ -802,16 +843,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 +1046,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 +1058,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: diff --git a/channels/serial/client/serial_tty.h b/channels/serial/client/serial_tty.h index f75a3988d..840c448ec 100644 --- a/channels/serial/client/serial_tty.h +++ b/channels/serial/client/serial_tty.h @@ -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); diff --git a/channels/smartcard/client/smartcard_main.c b/channels/smartcard/client/smartcard_main.c index 1116dd1f0..cb801db8f 100644 --- a/channels/smartcard/client/smartcard_main.c +++ b/channels/smartcard/client/smartcard_main.c @@ -322,8 +322,10 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) 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"; @@ -337,6 +339,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) smartcard->name = NULL; smartcard->path = NULL; + if (path) { smartcard->path = path; diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m index 66b13a9d6..fda9a8dcc 100644 --- a/client/Mac/MRDPView.m +++ b/client/Mac/MRDPView.m @@ -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) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 31fc28a6a..2e4d2f01f 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -93,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" }, @@ -297,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; @@ -316,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; @@ -339,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]); @@ -360,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]); @@ -381,12 +397,16 @@ 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) parallel->Path = _strdup(params[2]); diff --git a/include/freerdp/codec/region.h b/include/freerdp/codec/region.h index eff10debb..a4526a47f 100644 --- a/include/freerdp/codec/region.h +++ b/include/freerdp/codec/region.h @@ -24,6 +24,7 @@ #ifndef __REGION_H___ #define __REGION_H___ +#include #include 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___ */ diff --git a/include/freerdp/crypto/tls.h b/include/freerdp/crypto/tls.h index 486db2bd6..bf5521300 100644 --- a/include/freerdp/crypto/tls.h +++ b/include/freerdp/crypto/tls.h @@ -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); diff --git a/include/freerdp/error.h b/include/freerdp/error.h index 9cd8f4daa..248b38e19 100755 --- a/include/freerdp/error.h +++ b/include/freerdp/error.h @@ -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 } diff --git a/libfreerdp/codec/planar.h b/libfreerdp/codec/planar.h index 54a98e644..bbb9f6068 100644 --- a/libfreerdp/codec/planar.h +++ b/libfreerdp/codec/planar.h @@ -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 */ diff --git a/libfreerdp/codec/test/TestFreeRDPRegion.c b/libfreerdp/codec/test/TestFreeRDPRegion.c index 0136b238b..80ff54729 100644 --- a/libfreerdp/codec/test/TestFreeRDPRegion.c +++ b/libfreerdp/codec/test/TestFreeRDPRegion.c @@ -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++) diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index 902939983..3eab8ce69 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -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) @@ -169,24 +169,27 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device) 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); 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: +out_fs_path_error: free(_drive->Name); - out_fs_name_error: +out_fs_name_error: free(_drive); return NULL; } @@ -194,24 +197,33 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device) 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); - if (!_printer->Name) - goto out_print_name_error; - _printer->DriverName = _strdup(printer->DriverName); - if(!_printer->DriverName) - goto out_print_path_error; + + 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: +out_print_path_error: free(_printer->Name); - out_print_name_error: +out_print_name_error: free(_printer); return NULL; } @@ -219,24 +231,33 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device) 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); - if (!_smartcard->Name) - goto out_smartc_name_error; - _smartcard->Path = _strdup(smartcard->Path); - if (!_smartcard->Path) - goto out_smartc_path_error; + + 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: +out_smartc_path_error: free(_smartcard->Name); - out_smartc_name_error: +out_smartc_name_error: free(_smartcard); return NULL; } @@ -244,24 +265,33 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device) 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); - if (!_serial->Name) - goto out_serial_name_error; - _serial->Path = _strdup(serial->Path); - if (!_serial->Path) - goto out_serial_path_error; + + 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: +out_serial_path_error: free(_serial->Name); - out_serial_name_error: +out_serial_name_error: free(_serial); return NULL; } @@ -269,23 +299,32 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device) 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); - if (!_parallel->Name) - goto out_parallel_name_error; - _parallel->Path = _strdup(parallel->Path); - if (!_parallel->Path) - goto out_parallel_path_error; + + 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: +out_parallel_path_error: free(_parallel->Name); - out_parallel_name_error: +out_parallel_name_error: free(_parallel); return NULL; diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 62e7b30b1..5beb44f90 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -251,6 +251,11 @@ BOOL rdp_client_connect(rdpRdp* rdp) 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; } @@ -286,7 +291,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; diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 5fc0977ed..e94882577 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -192,11 +192,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: diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index dc2395cc5..6c9c29571 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -224,6 +224,7 @@ BIO_METHOD* BIO_s_tsg(void) BOOL transport_connect_tls(rdpTransport* transport) { + int tls_status; freerdp* instance; rdpContext* context; @@ -245,13 +246,23 @@ BOOL transport_connect_tls(rdpTransport* transport) if (transport->TsgTls->port == 0) transport->TsgTls->port = 3389; - if (!tls_connect(transport->TsgTls)) - { - if (!connectErrorCode) - connectErrorCode = TLSCONNECTERROR; + tls_status = tls_connect(transport->TsgTls); - if (!freerdp_get_last_error(context)) - freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + if (tls_status < 1) + { + if (tls_status < 0) + { + if (!connectErrorCode) + connectErrorCode = TLSCONNECTERROR; + + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + } + else + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); + } tls_free(transport->TsgTls); transport->TsgTls = NULL; @@ -277,13 +288,23 @@ BOOL transport_connect_tls(rdpTransport* transport) if (transport->TlsIn->port == 0) transport->TlsIn->port = 3389; - if (!tls_connect(transport->TlsIn)) - { - if (!connectErrorCode) - connectErrorCode = TLSCONNECTERROR; + tls_status = tls_connect(transport->TlsIn); - if (!freerdp_get_last_error(context)) - freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + if (tls_status < 1) + { + if (tls_status < 0) + { + if (!connectErrorCode) + connectErrorCode = TLSCONNECTERROR; + + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + } + else + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); + } tls_free(transport->TlsIn); @@ -317,6 +338,7 @@ BOOL transport_connect_nla(rdpTransport* transport) if (!transport->credssp) { transport->credssp = credssp_new(instance, transport, settings); + transport_set_nla_mode(transport, TRUE); if (settings->AuthenticationServiceClass) { @@ -338,11 +360,14 @@ BOOL transport_connect_nla(rdpTransport* transport) fprintf(stderr, "Authentication failure, check credentials.\n" "If credentials are valid, the NTLMSSP implementation may be to blame.\n"); + transport_set_nla_mode(transport, FALSE); credssp_free(transport->credssp); transport->credssp = NULL; + return FALSE; } + transport_set_nla_mode(transport, FALSE); credssp_free(transport->credssp); transport->credssp = NULL; @@ -351,7 +376,15 @@ BOOL transport_connect_nla(rdpTransport* transport) BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 port) { - rdpTsg* tsg = tsg_new(transport); + rdpTsg* tsg; + int tls_status; + freerdp* instance; + rdpContext* context; + + instance = (freerdp*) transport->settings->instance; + context = instance->context; + + tsg = tsg_new(transport); tsg->transport = transport; transport->tsg = tsg; @@ -377,11 +410,41 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 if (transport->TlsOut->port == 0) transport->TlsOut->port = 443; - if (!tls_connect(transport->TlsIn)) - return FALSE; + tls_status = tls_connect(transport->TlsIn); + + if (tls_status < 1) + { + if (tls_status < 0) + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + } + else + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); + } - if (!tls_connect(transport->TlsOut)) return FALSE; + } + + tls_status = tls_connect(transport->TlsOut); + + if (tls_status < 1) + { + if (tls_status < 0) + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + } + else + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); + } + + return FALSE; + } if (!tsg_connect(tsg, hostname, port)) return FALSE; @@ -481,11 +544,16 @@ BOOL transport_accept_nla(rdpTransport* transport) return TRUE; if (!transport->credssp) + { transport->credssp = credssp_new(instance, transport, settings); + transport_set_nla_mode(transport, TRUE); + } if (credssp_authenticate(transport->credssp) < 0) { fprintf(stderr, "client authentication failure\n"); + + transport_set_nla_mode(transport, FALSE); credssp_free(transport->credssp); transport->credssp = NULL; @@ -495,6 +563,7 @@ BOOL transport_accept_nla(rdpTransport* transport) } /* don't free credssp module yet, we need to copy the credentials from it first */ + transport_set_nla_mode(transport, FALSE); return TRUE; } @@ -643,49 +712,56 @@ int transport_read(rdpTransport* transport, wStream* s) CopyMemory(header, Stream_Buffer(s), 4); /* peek at first 4 bytes */ - /* if header is present, read in exactly one PDU */ - if (header[0] == 0x03) - { - /* TPKT header */ + /* if header is present, read exactly one PDU */ - pduLength = (header[2] << 8) | header[3]; - } - else if (header[0] == 0x30) + if (transport->NlaMode) { - /* TSRequest (NLA) */ - - if (header[1] & 0x80) + if (header[0] == 0x30) { - if ((header[1] & ~(0x80)) == 1) + /* TSRequest (NLA) */ + + if (header[1] & 0x80) { - pduLength = header[2]; - pduLength += 3; - } - else if ((header[1] & ~(0x80)) == 2) - { - pduLength = (header[2] << 8) | header[3]; - pduLength += 4; + if ((header[1] & ~(0x80)) == 1) + { + pduLength = header[2]; + pduLength += 3; + } + else if ((header[1] & ~(0x80)) == 2) + { + pduLength = (header[2] << 8) | header[3]; + pduLength += 4; + } + else + { + fprintf(stderr, "Error reading TSRequest!\n"); + return -1; + } } else { - fprintf(stderr, "Error reading TSRequest!\n"); - return -1; + pduLength = header[1]; + pduLength += 2; } } - else - { - pduLength = header[1]; - pduLength += 2; - } } else { - /* Fast-Path Header */ + if (header[0] == 0x03) + { + /* TPKT header */ - if (header[1] & 0x80) - pduLength = ((header[1] & 0x7F) << 8) | header[2]; + pduLength = (header[2] << 8) | header[3]; + } else - pduLength = header[1]; + { + /* Fast-Path Header */ + + if (header[1] & 0x80) + pduLength = ((header[1] & 0x7F) << 8) | header[2]; + else + pduLength = header[1]; + } } status = transport_read_layer(transport, Stream_Buffer(s) + position, pduLength - position); @@ -889,72 +965,78 @@ int transport_check_fds(rdpTransport* transport) * Loop through and read all available PDUs. Since multiple * PDUs can exist, it's important to deliver them all before * returning. Otherwise we run the risk of having a thread - * wait for a socket to get signalled that data is available + * wait for a socket to get signaled that data is available * (which may never happen). */ for (;;) { status = transport_read_nonblocking(transport); - if (status < 0 || Stream_GetPosition(transport->ReceiveBuffer) == 0) + if ((status <= 0) || (Stream_GetPosition(transport->ReceiveBuffer) < 2)) return status; while ((pos = Stream_GetPosition(transport->ReceiveBuffer)) > 0) { Stream_SetPosition(transport->ReceiveBuffer, 0); - if (tpkt_verify_header(transport->ReceiveBuffer)) /* TPKT */ + if (transport->NlaMode) { - /* Ensure the TPKT header is available. */ - if (pos <= 4) + if (nla_verify_header(transport->ReceiveBuffer)) { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; - } + /* TSRequest */ - length = tpkt_read_header(transport->ReceiveBuffer); + /* Ensure the TSRequest header is available. */ + if (pos <= 4) + { + Stream_SetPosition(transport->ReceiveBuffer, pos); + return 0; + } + + /* TSRequest header can be 2, 3 or 4 bytes long */ + length = nla_header_length(transport->ReceiveBuffer); + + if (pos < length) + { + Stream_SetPosition(transport->ReceiveBuffer, pos); + return 0; + } + + length = nla_read_header(transport->ReceiveBuffer); + } } - else if (nla_verify_header(transport->ReceiveBuffer)) + else { - /* TSRequest */ - - /* Ensure the TSRequest header is available. */ - if (pos <= 4) + if (tpkt_verify_header(transport->ReceiveBuffer)) /* TPKT */ { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; + /* Ensure the TPKT header is available. */ + if (pos <= 4) + { + Stream_SetPosition(transport->ReceiveBuffer, pos); + return 0; + } + + length = tpkt_read_header(transport->ReceiveBuffer); } - - /* TSRequest header can be 2, 3 or 4 bytes long */ - length = nla_header_length(transport->ReceiveBuffer); - - if (pos < length) + else /* Fast Path */ { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; + /* Ensure the Fast Path header is available. */ + if (pos <= 2) + { + Stream_SetPosition(transport->ReceiveBuffer, pos); + return 0; + } + + /* Fastpath header can be two or three bytes long. */ + length = fastpath_header_length(transport->ReceiveBuffer); + + if (pos < length) + { + Stream_SetPosition(transport->ReceiveBuffer, pos); + return 0; + } + + length = fastpath_read_header(NULL, transport->ReceiveBuffer); } - - length = nla_read_header(transport->ReceiveBuffer); - } - else /* Fast Path */ - { - /* Ensure the Fast Path header is available. */ - if (pos <= 2) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; - } - - /* Fastpath header can be two or three bytes long. */ - length = fastpath_header_length(transport->ReceiveBuffer); - - if (pos < length) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; - } - - length = fastpath_read_header(NULL, transport->ReceiveBuffer); } if (length == 0) @@ -1039,6 +1121,11 @@ void transport_set_gateway_enabled(rdpTransport* transport, BOOL GatewayEnabled) transport->GatewayEnabled = GatewayEnabled; } +void transport_set_nla_mode(rdpTransport* transport, BOOL NlaMode) +{ + transport->NlaMode = NlaMode; +} + static void* transport_client_thread(void* arg) { DWORD status; diff --git a/libfreerdp/core/transport.h b/libfreerdp/core/transport.h index 49532f144..b8834ce7a 100644 --- a/libfreerdp/core/transport.h +++ b/libfreerdp/core/transport.h @@ -75,6 +75,7 @@ struct rdp_transport HANDLE stopEvent; HANDLE thread; BOOL async; + BOOL NlaMode; BOOL GatewayEnabled; CRITICAL_SECTION ReadLock; CRITICAL_SECTION WriteLock; @@ -99,6 +100,7 @@ void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount); int transport_check_fds(rdpTransport* transport); BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking); void transport_set_gateway_enabled(rdpTransport* transport, BOOL GatewayEnabled); +void transport_set_nla_mode(rdpTransport* transport, BOOL NlaMode); void transport_get_read_handles(rdpTransport* transport, HANDLE* events, DWORD* count); wStream* transport_receive_pool_take(rdpTransport* transport); diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 805105097..ea98e2812 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -105,10 +105,11 @@ static void tls_ssl_info_callback(const SSL* ssl, int type, int val) } } -BOOL tls_connect(rdpTls* tls) +int tls_connect(rdpTls* tls) { CryptoCert cert; long options = 0; + int verify_status; int connection_status; tls->ctx = SSL_CTX_new(TLSv1_client_method()); @@ -116,7 +117,7 @@ BOOL tls_connect(rdpTls* tls) if (!tls->ctx) { fprintf(stderr, "SSL_CTX_new failed\n"); - return FALSE; + return -1; } //SSL_CTX_set_mode(tls->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE); @@ -157,7 +158,7 @@ BOOL tls_connect(rdpTls* tls) if (!tls->ssl) { fprintf(stderr, "SSL_new failed\n"); - return FALSE; + return -1; } if (tls->tsg) @@ -167,7 +168,7 @@ BOOL tls_connect(rdpTls* tls) if (!tls->bio) { fprintf(stderr, "BIO_new failed\n"); - return FALSE; + return -1; } tls->bio->ptr = tls->tsg; @@ -181,7 +182,7 @@ BOOL tls_connect(rdpTls* tls) if (SSL_set_fd(tls->ssl, tls->sockfd) < 1) { fprintf(stderr, "SSL_set_fd failed\n"); - return FALSE; + return -1; } } @@ -191,7 +192,7 @@ BOOL tls_connect(rdpTls* tls) { if (tls_print_error("SSL_connect", tls->ssl, connection_status)) { - return FALSE; + return -1; } } @@ -200,7 +201,7 @@ BOOL tls_connect(rdpTls* tls) if (!cert) { fprintf(stderr, "tls_connect: tls_get_certificate failed to return the server certificate.\n"); - return FALSE; + return -1; } tls->Bindings = tls_get_channel_bindings(cert->px509); @@ -209,20 +210,22 @@ BOOL tls_connect(rdpTls* tls) { fprintf(stderr, "tls_connect: crypto_cert_get_public_key failed to return the server public key.\n"); tls_free_certificate(cert); - return FALSE; + return -1; } - if (!tls_verify_certificate(tls, cert, tls->hostname, tls->port)) + verify_status = tls_verify_certificate(tls, cert, tls->hostname, tls->port); + + if (verify_status < 1) { fprintf(stderr, "tls_connect: certificate not trusted, aborting.\n"); tls_disconnect(tls); tls_free_certificate(cert); - return FALSE; + return verify_status; } tls_free_certificate(cert); - return TRUE; + return (verify_status == 0) ? 0 : 1; } BOOL tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file) @@ -612,7 +615,7 @@ BOOL tls_match_hostname(char *pattern, int pattern_length, char *hostname) return FALSE; } -BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port) +int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port) { int match; int index; @@ -644,7 +647,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po if (!bio) { fprintf(stderr, "tls_verify_certificate: BIO_new() failure\n"); - return FALSE; + return -1; } status = PEM_write_bio_X509(bio, cert->px509); @@ -652,7 +655,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po if (status < 0) { fprintf(stderr, "tls_verify_certificate: PEM_write_bio_X509 failure: %d\n", status); - return FALSE; + return -1; } offset = 0; @@ -664,7 +667,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po if (status < 0) { fprintf(stderr, "tls_verify_certificate: failed to read certificate\n"); - return FALSE; + return -1; } offset += status; @@ -685,7 +688,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po if (status < 0) { fprintf(stderr, "tls_verify_certificate: failed to read certificate\n"); - return FALSE; + return -1; } length = offset; @@ -704,12 +707,15 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po free(pemCert); BIO_free(bio); - return (status < 0) ? FALSE : TRUE; + if (status < 0) + return -1; + + return (status == 0) ? 0 : 1; } /* ignore certificate verification if user explicitly required it (discouraged) */ if (tls->settings->IgnoreCertificate) - return TRUE; /* success! */ + return 1; /* success! */ /* if user explicitly specified a certificate name, use it instead of the hostname */ if (tls->settings->CertificateName) @@ -727,7 +733,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po /* compare against common name */ - if (common_name != NULL) + if (common_name) { if (tls_match_hostname(common_name, common_name_length, hostname)) hostname_match = TRUE; @@ -735,7 +741,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po /* compare against alternative names */ - if (alt_names != NULL) + if (alt_names) { for (index = 0; index < alt_names_count; index++) { @@ -851,7 +857,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po crypto_cert_subject_alt_name_free(alt_names_count, alt_names_lengths, alt_names); - return verification_status; + return (verification_status == 0) ? 0 : 1; } void tls_print_certificate_error(char* hostname, char* fingerprint, char *hosts_file) diff --git a/libfreerdp/gdi/drawing.c b/libfreerdp/gdi/drawing.c index 1ecd2c3e5..9b81d657d 100644 --- a/libfreerdp/gdi/drawing.c +++ b/libfreerdp/gdi/drawing.c @@ -31,6 +31,7 @@ #include #include +#include /** * Set current foreground draw mode.\n