summaryrefslogtreecommitdiffstats
path: root/libfreerdp/core
diff options
context:
space:
mode:
Diffstat (limited to 'libfreerdp/core')
-rw-r--r--libfreerdp/core/aad.c4
-rw-r--r--libfreerdp/core/capabilities.c7
-rw-r--r--libfreerdp/core/childsession.c268
-rw-r--r--libfreerdp/core/client.c9
-rw-r--r--libfreerdp/core/connection.c13
-rw-r--r--libfreerdp/core/credssp_auth.c1
-rw-r--r--libfreerdp/core/freerdp.c20
-rw-r--r--libfreerdp/core/gateway/arm.c9
-rw-r--r--libfreerdp/core/gateway/http.c20
-rw-r--r--libfreerdp/core/gateway/rdg.c221
-rw-r--r--libfreerdp/core/gateway/tsg.c120
-rw-r--r--libfreerdp/core/gateway/tsg.h2
-rw-r--r--libfreerdp/core/gateway/wst.c2
-rw-r--r--libfreerdp/core/gcc.c6
-rw-r--r--libfreerdp/core/info.c8
-rw-r--r--libfreerdp/core/input.h2
-rw-r--r--libfreerdp/core/license.c25
-rw-r--r--libfreerdp/core/listener.c14
-rw-r--r--libfreerdp/core/nla.c7
-rw-r--r--libfreerdp/core/peer.c4
-rw-r--r--libfreerdp/core/proxy.c8
-rw-r--r--libfreerdp/core/rdp.c4
-rw-r--r--libfreerdp/core/security.c1
-rw-r--r--libfreerdp/core/smartcardlogon.c11
-rw-r--r--libfreerdp/core/test/CMakeLists.txt17
-rw-r--r--libfreerdp/core/test/settings_property_lists.h2
-rw-r--r--libfreerdp/core/transport.c14
-rw-r--r--libfreerdp/core/transport.h15
-rw-r--r--libfreerdp/core/update.c8
-rw-r--r--libfreerdp/core/utils.c181
-rw-r--r--libfreerdp/core/utils.h14
31 files changed, 805 insertions, 232 deletions
diff --git a/libfreerdp/core/aad.c b/libfreerdp/core/aad.c
index 72204d7..15eabed 100644
--- a/libfreerdp/core/aad.c
+++ b/libfreerdp/core/aad.c
@@ -210,8 +210,8 @@ cJSON* cJSON_ParseWithLength(const char* value, size_t buffer_length)
static INLINE const char* aad_auth_result_to_string(DWORD code)
{
-#define ERROR_CASE(cd, x) \
- if (cd == (DWORD)(x)) \
+#define ERROR_CASE(cd, x) \
+ if ((cd) == (DWORD)(x)) \
return #x;
ERROR_CASE(code, S_OK)
diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c
index 427e434..e8df920 100644
--- a/libfreerdp/core/capabilities.c
+++ b/libfreerdp/core/capabilities.c
@@ -168,7 +168,7 @@ static BOOL rdp_apply_general_capability_set(rdpSettings* settings, const rdpSet
settings->NoBitmapCompressionHeader = src->NoBitmapCompressionHeader;
settings->LongCredentialsSupported = src->LongCredentialsSupported;
- settings->AutoReconnectionEnabled = src->AutoReconnectionEnabled;
+ settings->AutoReconnectionPacketSupported = src->AutoReconnectionPacketSupported;
if (!src->FastPathOutput)
settings->FastPathOutput = FALSE;
@@ -223,7 +223,8 @@ static BOOL rdp_read_general_capability_set(wStream* s, rdpSettings* settings)
settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) ? TRUE : FALSE;
settings->LongCredentialsSupported = (extraFlags & LONG_CREDENTIALS_SUPPORTED) ? TRUE : FALSE;
- settings->AutoReconnectionEnabled = (extraFlags & AUTORECONNECT_SUPPORTED) ? TRUE : FALSE;
+ settings->AutoReconnectionPacketSupported =
+ (extraFlags & AUTORECONNECT_SUPPORTED) ? TRUE : FALSE;
settings->FastPathOutput = (extraFlags & FASTPATH_OUTPUT_SUPPORTED) ? TRUE : FALSE;
settings->SaltedChecksum = (extraFlags & ENC_SALTED_CHECKSUM) ? TRUE : FALSE;
settings->RefreshRect = refreshRectSupport;
@@ -252,7 +253,7 @@ static BOOL rdp_write_general_capability_set(wStream* s, const rdpSettings* sett
if (settings->NoBitmapCompressionHeader)
extraFlags |= NO_BITMAP_COMPRESSION_HDR;
- if (settings->AutoReconnectionEnabled)
+ if (settings->AutoReconnectionPacketSupported)
extraFlags |= AUTORECONNECT_SUPPORTED;
if (settings->FastPathOutput)
diff --git a/libfreerdp/core/childsession.c b/libfreerdp/core/childsession.c
index 3bed262..f9d5b2c 100644
--- a/libfreerdp/core/childsession.c
+++ b/libfreerdp/core/childsession.c
@@ -2,7 +2,7 @@
* FreeRDP: A Remote Desktop Protocol Implementation
* Named pipe transport
*
- * Copyright 2023 David Fort <contact@hardening-consulting.com>
+ * Copyright 2023-2024 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,15 +18,29 @@
*/
#include "tcp.h"
+
#include <winpr/library.h>
#include <winpr/assert.h>
+#include <winpr/print.h>
+#include <winpr/sysinfo.h>
+
+#include <freerdp/utils/ringbuffer.h>
+
#include "childsession.h"
#define TAG FREERDP_TAG("childsession")
typedef struct
{
+ OVERLAPPED readOverlapped;
HANDLE hFile;
+ BOOL opInProgress;
+ BOOL lastOpClosed;
+ RingBuffer readBuffer;
+ BOOL blocking;
+ BYTE tmpReadBuffer[4096];
+
+ HANDLE readEvent;
} WINPR_BIO_NAMED;
static int transport_bio_named_uninit(BIO* bio);
@@ -44,47 +58,192 @@ static int transport_bio_named_write(BIO* bio, const char* buf, int size)
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
DWORD written = 0;
+ UINT64 start = GetTickCount64();
BOOL ret = WriteFile(ptr->hFile, buf, size, &written, NULL);
- WLog_VRB(TAG, "transport_bio_named_write(%d)=%d written=%d", size, ret, written);
+ // winpr_HexDump(TAG, WLOG_DEBUG, buf, size);
if (!ret)
- return -1;
+ {
+ WLog_VRB(TAG, "error or deferred");
+ return 0;
+ }
+
+ WLog_VRB(TAG, "(%d)=%d written=%d duration=%d", size, ret, written, GetTickCount64() - start);
if (written == 0)
- return -1;
+ {
+ WLog_VRB(TAG, "closed on write");
+ return 0;
+ }
return written;
}
+static BOOL treatReadResult(WINPR_BIO_NAMED* ptr, DWORD readBytes)
+{
+ WLog_VRB(TAG, "treatReadResult(readBytes=%" PRIu32 ")", readBytes);
+ ptr->opInProgress = FALSE;
+ if (readBytes == 0)
+ {
+ WLog_VRB(TAG, "readBytes == 0");
+ return TRUE;
+ }
+
+ if (!ringbuffer_write(&ptr->readBuffer, ptr->tmpReadBuffer, readBytes))
+ {
+ WLog_VRB(TAG, "ringbuffer_write()");
+ return FALSE;
+ }
+
+ return SetEvent(ptr->readEvent);
+}
+
+static BOOL doReadOp(WINPR_BIO_NAMED* ptr)
+{
+ DWORD readBytes;
+
+ if (!ResetEvent(ptr->readEvent))
+ return FALSE;
+
+ ptr->opInProgress = TRUE;
+ if (!ReadFile(ptr->hFile, ptr->tmpReadBuffer, sizeof(ptr->tmpReadBuffer), &readBytes,
+ &ptr->readOverlapped))
+ {
+ DWORD error = GetLastError();
+ switch (error)
+ {
+ case ERROR_NO_DATA:
+ WLog_VRB(TAG, "No Data, unexpected");
+ return TRUE;
+ case ERROR_IO_PENDING:
+ WLog_VRB(TAG, "ERROR_IO_PENDING");
+ return TRUE;
+ case ERROR_BROKEN_PIPE:
+ WLog_VRB(TAG, "broken pipe");
+ ptr->lastOpClosed = TRUE;
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ }
+
+ return treatReadResult(ptr, readBytes);
+}
+
static int transport_bio_named_read(BIO* bio, char* buf, int size)
{
WINPR_ASSERT(bio);
WINPR_ASSERT(buf);
WINPR_BIO_NAMED* ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
-
if (!buf)
return 0;
- BIO_clear_flags(bio, BIO_FLAGS_READ);
+ BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ);
- DWORD readBytes = 0;
- BOOL ret = ReadFile(ptr->hFile, buf, size, &readBytes, NULL);
- WLog_VRB(TAG, "transport_bio_named_read(%d)=%d read=%d", size, ret, readBytes);
- if (!ret)
+ if (ptr->blocking)
{
- if (GetLastError() == ERROR_NO_DATA)
- BIO_set_flags(bio, (BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ));
- return -1;
+ while (!ringbuffer_used(&ptr->readBuffer))
+ {
+ if (ptr->lastOpClosed)
+ return 0;
+
+ if (ptr->opInProgress)
+ {
+ DWORD status = WaitForSingleObjectEx(ptr->readEvent, 500, TRUE);
+ switch (status)
+ {
+ case WAIT_TIMEOUT:
+ case WAIT_IO_COMPLETION:
+ continue;
+ case WAIT_OBJECT_0:
+ break;
+ default:
+ return -1;
+ }
+
+ DWORD readBytes;
+ if (!GetOverlappedResult(ptr->hFile, &ptr->readOverlapped, &readBytes, FALSE))
+ {
+ WLog_ERR(TAG, "GetOverlappedResult blocking(lastError=%" PRIu32 ")",
+ GetLastError());
+ return -1;
+ }
+
+ if (!treatReadResult(ptr, readBytes))
+ {
+ WLog_ERR(TAG, "treatReadResult blocking");
+ return -1;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (ptr->opInProgress)
+ {
+ DWORD status = WaitForSingleObject(ptr->readEvent, 0);
+ switch (status)
+ {
+ case WAIT_OBJECT_0:
+ break;
+ case WAIT_TIMEOUT:
+ BIO_set_flags(bio, (BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ));
+ return -1;
+ default:
+ WLog_ERR(TAG, "error WaitForSingleObject(readEvent)=0x%" PRIx32 "", status);
+ return -1;
+ }
+
+ DWORD readBytes;
+ if (!GetOverlappedResult(ptr->hFile, &ptr->readOverlapped, &readBytes, FALSE))
+ {
+ WLog_ERR(TAG, "GetOverlappedResult non blocking(lastError=%" PRIu32 ")",
+ GetLastError());
+ return -1;
+ }
+
+ if (!treatReadResult(ptr, readBytes))
+ {
+ WLog_ERR(TAG, "error treatReadResult non blocking");
+ return -1;
+ }
+ }
}
- if (readBytes == 0)
+ int ret = MIN(size, ringbuffer_used(&ptr->readBuffer));
+ if (ret)
{
- BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY));
- return 0;
+ DataChunk chunks[2];
+ int nchunks = ringbuffer_peek(&ptr->readBuffer, chunks, ret);
+ for (int i = 0; i < nchunks; i++)
+ {
+ memcpy(buf, chunks[i].data, chunks[i].size);
+ buf += chunks[i].size;
+ }
+
+ ringbuffer_commit_read_bytes(&ptr->readBuffer, ret);
+
+ WLog_VRB(TAG, "(%d)=%d nchunks=%d", size, ret, nchunks);
+ }
+ else
+ {
+ ret = -1;
+ }
+
+ if (!ringbuffer_used(&ptr->readBuffer))
+ {
+ if (!ptr->opInProgress && !doReadOp(ptr))
+ {
+ WLog_ERR(TAG, "error rearming read");
+ return -1;
+ }
}
- return readBytes;
+ if (ret <= 0)
+ BIO_set_flags(bio, (BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ));
+
+ return ret;
}
static int transport_bio_named_puts(BIO* bio, const char* str)
@@ -100,7 +259,7 @@ static int transport_bio_named_gets(BIO* bio, char* str, int size)
WINPR_ASSERT(bio);
WINPR_ASSERT(str);
- return transport_bio_named_write(bio, str, size);
+ return transport_bio_named_read(bio, str, size);
}
static long transport_bio_named_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
@@ -119,7 +278,7 @@ static long transport_bio_named_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
if (!BIO_get_init(bio) || !arg2)
return 0;
- *((HANDLE*)arg2) = ptr->hFile;
+ *((HANDLE*)arg2) = ptr->readEvent;
return 1;
case BIO_C_SET_HANDLE:
BIO_set_init(bio, 1);
@@ -127,18 +286,25 @@ static long transport_bio_named_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
return 0;
ptr->hFile = (HANDLE)arg2;
+ ptr->blocking = TRUE;
+ if (!doReadOp(ptr))
+ return -1;
return 1;
case BIO_C_SET_NONBLOCK:
{
+ WLog_DBG(TAG, "BIO_C_SET_NONBLOCK");
+ ptr->blocking = FALSE;
return 1;
}
case BIO_C_WAIT_READ:
{
+ WLog_DBG(TAG, "BIO_C_WAIT_READ");
return 1;
}
case BIO_C_WAIT_WRITE:
{
+ WLog_DBG(TAG, "BIO_C_WAIT_WRITE");
return 1;
}
@@ -173,17 +339,34 @@ static long transport_bio_named_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
return status;
}
-static int transport_bio_named_uninit(BIO* bio)
+static void BIO_NAMED_free(WINPR_BIO_NAMED* ptr)
{
- WINPR_ASSERT(bio);
- WINPR_BIO_NAMED* ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
+ if (!ptr)
+ return;
- if (ptr && ptr->hFile)
+ if (ptr->hFile)
{
CloseHandle(ptr->hFile);
ptr->hFile = NULL;
}
+ if (ptr->readEvent)
+ {
+ CloseHandle(ptr->readEvent);
+ ptr->readEvent = NULL;
+ }
+
+ ringbuffer_destroy(&ptr->readBuffer);
+ free(ptr);
+}
+
+static int transport_bio_named_uninit(BIO* bio)
+{
+ WINPR_ASSERT(bio);
+ WINPR_BIO_NAMED* ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
+
+ BIO_NAMED_free(ptr);
+
BIO_set_init(bio, 0);
BIO_set_flags(bio, 0);
return 1;
@@ -192,15 +375,27 @@ static int transport_bio_named_uninit(BIO* bio)
static int transport_bio_named_new(BIO* bio)
{
WINPR_ASSERT(bio);
- BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
WINPR_BIO_NAMED* ptr = (WINPR_BIO_NAMED*)calloc(1, sizeof(WINPR_BIO_NAMED));
if (!ptr)
return 0;
+ if (!ringbuffer_init(&ptr->readBuffer, 0xfffff))
+ goto error;
+
+ ptr->readEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+ if (!ptr->readEvent || ptr->readEvent == INVALID_HANDLE_VALUE)
+ goto error;
+
+ ptr->readOverlapped.hEvent = ptr->readEvent;
+
BIO_set_data(bio, ptr);
BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
return 1;
+
+error:
+ BIO_NAMED_free(ptr);
+ return 0;
}
static int transport_bio_named_free(BIO* bio)
@@ -211,13 +406,10 @@ static int transport_bio_named_free(BIO* bio)
return 0;
transport_bio_named_uninit(bio);
- ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
+ ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
if (ptr)
- {
BIO_set_data(bio, NULL);
- free(ptr);
- }
return 1;
}
@@ -292,10 +484,28 @@ static BOOL createChildSessionTransport(HANDLE* pFile)
goto out;
}
+ const BYTE startOfPath[] = { '\\', 0, '\\', 0, '.', 0, '\\', 0 };
+ if (_wcsncmp(pipePath, (WCHAR*)startOfPath, 4))
+ {
+ /* when compiled under 32 bits, the path may miss "\\.\" at the beginning of the string
+ * so add it if it's not there
+ */
+ size_t len = _wcslen(pipePath);
+ if (len > 0x80 - (4 + 1))
+ {
+ WLog_ERR(TAG, "pipePath is too long to be adjusted");
+ goto out;
+ }
+
+ memmove(pipePath + 4, pipePath, (len + 1) * sizeof(WCHAR));
+ memcpy(pipePath, startOfPath, 8);
+ }
+
ConvertWCharNToUtf8(pipePath, 0x80, pipePathA, sizeof(pipePathA));
WLog_DBG(TAG, "child session is at '%s'", pipePathA);
- HANDLE f = CreateFileW(pipePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+ HANDLE f = CreateFileW(pipePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED, NULL);
if (f == INVALID_HANDLE_VALUE)
{
WLog_ERR(TAG, "error when connecting to local named pipe");
diff --git a/libfreerdp/core/client.c b/libfreerdp/core/client.c
index 1bfc617..7898a9d 100644
--- a/libfreerdp/core/client.c
+++ b/libfreerdp/core/client.c
@@ -661,6 +661,8 @@ static int freerdp_channels_process_sync(rdpChannels* channels, freerdp* instanc
int status = TRUE;
wMessage message = { 0 };
+ WINPR_ASSERT(channels);
+
while (MessageQueue_Peek(channels->queue, &message, TRUE))
{
freerdp_channels_process_message(instance, &message);
@@ -728,6 +730,8 @@ int freerdp_channels_process_pending_messages(freerdp* instance)
*/
BOOL freerdp_channels_check_fds(rdpChannels* channels, freerdp* instance)
{
+ WINPR_ASSERT(channels);
+
if (WaitForSingleObject(MessageQueue_Event(channels->queue), 0) == WAIT_OBJECT_0)
{
freerdp_channels_process_sync(channels, instance);
@@ -742,6 +746,8 @@ UINT freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance)
CHANNEL_OPEN_DATA* pChannelOpenData = NULL;
CHANNEL_CLIENT_DATA* pChannelClientData = NULL;
+ WINPR_ASSERT(channels);
+
if (!channels->connected)
return 0;
@@ -808,8 +814,6 @@ void freerdp_channels_close(rdpChannels* channels, freerdp* instance)
}
}
- channels->clientDataCount = 0;
-
for (int index = 0; index < channels->openDataCount; index++)
{
pChannelOpenData = &channels->openDataList[index];
@@ -818,6 +822,7 @@ void freerdp_channels_close(rdpChannels* channels, freerdp* instance)
channels->openDataCount = 0;
channels->initDataCount = 0;
+ channels->clientDataCount = 0;
WINPR_ASSERT(instance->context);
WINPR_ASSERT(instance->context->settings);
diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c
index 3abfa93..240a29f 100644
--- a/libfreerdp/core/connection.c
+++ b/libfreerdp/core/connection.c
@@ -622,11 +622,10 @@ BOOL rdp_client_redirect(rdpRdp* rdp)
if (!rdp_client_disconnect_and_clear(rdp))
return FALSE;
+ /* Only disconnect & close the channels here.
+ * they will be discarded and recreated after the new settings have been applied. */
freerdp_channels_disconnect(rdp->context->channels, rdp->context->instance);
freerdp_channels_close(rdp->context->channels, rdp->context->instance);
- freerdp_channels_free(rdp->context->channels);
- rdp->context->channels = freerdp_channels_new(rdp->context->instance);
- WINPR_ASSERT(rdp->context->channels);
if (rdp_redirection_apply_settings(rdp) != 0)
return FALSE;
@@ -684,14 +683,10 @@ BOOL rdp_client_redirect(rdpRdp* rdp)
if (!IFCALLRESULT(TRUE, rdp->context->instance->Redirect, rdp->context->instance))
return FALSE;
- BOOL ok = IFCALLRESULT(TRUE, rdp->context->instance->LoadChannels, rdp->context->instance);
+ BOOL ok = utils_reload_channels(rdp->context);
if (!ok)
return FALSE;
- if (CHANNEL_RC_OK !=
- freerdp_channels_pre_connect(rdp->context->channels, rdp->context->instance))
- return FALSE;
-
status = rdp_client_connect(rdp);
if (status)
@@ -782,7 +777,6 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp)
Stream_Zero(s, 8);
Stream_SealLength(s);
status = transport_write(rdp->mcs->transport, s);
- Stream_Free(s, TRUE);
if (status < 0)
goto end;
@@ -829,6 +823,7 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp)
ret = TRUE;
end:
+ Stream_Free(s, TRUE);
free(crypt_client_random);
if (!ret)
diff --git a/libfreerdp/core/credssp_auth.c b/libfreerdp/core/credssp_auth.c
index c14dbe1..8b4c0cb 100644
--- a/libfreerdp/core/credssp_auth.c
+++ b/libfreerdp/core/credssp_auth.c
@@ -808,6 +808,7 @@ static SecurityFunctionTable* auth_resolve_sspi_table(const rdpSettings* setting
if (!hSSPI)
{
WLog_ERR(TAG, "Failed to load SSPI module: %s", module_name);
+ free(sspi_module);
return FALSE;
}
diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c
index 29d907a..3660e24 100644
--- a/libfreerdp/core/freerdp.c
+++ b/libfreerdp/core/freerdp.c
@@ -84,7 +84,6 @@ static void sig_abort_connect(int signum, const char* signame, void* ctx)
static int freerdp_connect_begin(freerdp* instance)
{
BOOL rc = 0;
- UINT status2 = CHANNEL_RC_OK;
rdpRdp* rdp = NULL;
BOOL status = TRUE;
rdpSettings* settings = NULL;
@@ -121,16 +120,9 @@ static int freerdp_connect_begin(freerdp* instance)
freerdp_settings_print_warnings(settings);
if (status)
- {
- if (!rdp_set_backup_settings(rdp))
- return 0;
-
- WINPR_ASSERT(instance->LoadChannels);
- if (!instance->LoadChannels(instance))
- return 0;
-
- status2 = freerdp_channels_pre_connect(instance->context->channels, instance);
- }
+ status = rdp_set_backup_settings(rdp);
+ if (status)
+ status = utils_reload_channels(instance->context);
KeyboardLayout = freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout);
switch (KeyboardLayout)
@@ -151,7 +143,7 @@ static int freerdp_connect_begin(freerdp* instance)
break;
}
- if (!status || (status2 != CHANNEL_RC_OK))
+ if (!status)
{
rdpContext* context = instance->context;
WINPR_ASSERT(context);
@@ -413,8 +405,8 @@ static BOOL freerdp_prevent_session_lock(rdpContext* context)
if (now - in->lastInputTimestamp > FakeMouseMotionInterval)
{
WLog_Print(context->log, WLOG_DEBUG,
- "fake mouse move: x=%d y=%d lastInputTimestamp=%d "
- "FakeMouseMotionInterval=%d",
+ "fake mouse move: x=%d y=%d lastInputTimestamp=%" PRIu64 " "
+ "FakeMouseMotionInterval=%" PRIu32,
in->lastX, in->lastY, in->lastInputTimestamp, FakeMouseMotionInterval);
BOOL status = freerdp_input_send_mouse_event(context->input, PTR_FLAGS_MOVE, in->lastX,
diff --git a/libfreerdp/core/gateway/arm.c b/libfreerdp/core/gateway/arm.c
index 9848c48..d506c75 100644
--- a/libfreerdp/core/gateway/arm.c
+++ b/libfreerdp/core/gateway/arm.c
@@ -549,6 +549,7 @@ static BOOL arm_pick_base64Utf16Field(const cJSON* json, const char* name, BYTE*
if (!output1 || !len1)
{
WLog_ERR(TAG, "error when first unbase64 for %s", name);
+ free(output1);
return FALSE;
}
@@ -558,6 +559,7 @@ static BOOL arm_pick_base64Utf16Field(const cJSON* json, const char* name, BYTE*
if (!output2 || !len2)
{
WLog_ERR(TAG, "error when decode('utf-16') for %s", name);
+ free(output2);
return FALSE;
}
@@ -567,6 +569,7 @@ static BOOL arm_pick_base64Utf16Field(const cJSON* json, const char* name, BYTE*
if (!output || !*plen)
{
WLog_ERR(TAG, "error when second unbase64 for %s", name);
+ free(output);
return FALSE;
}
@@ -842,7 +845,11 @@ static BOOL arm_handle_bad_request(rdpArm* arm, const HttpResponse* response, BO
0)
{
*retry = TRUE;
- WLog_DBG(TAG, "Starting your VM. It may take up to 5 minutes");
+ const cJSON* message = cJSON_GetObjectItemCaseSensitive(json, "Message");
+ if (!cJSON_IsString(message) || !message->valuestring)
+ WLog_WARN(TAG, "Starting your VM. It may take up to 5 minutes");
+ else
+ WLog_WARN(TAG, "%s", message->valuestring);
}
else
{
diff --git a/libfreerdp/core/gateway/http.c b/libfreerdp/core/gateway/http.c
index cf70b3b..a7cdaab 100644
--- a/libfreerdp/core/gateway/http.c
+++ b/libfreerdp/core/gateway/http.c
@@ -322,8 +322,9 @@ static BOOL list_append(HttpContext* context, WINPR_FORMAT_ARG const char* str,
}
else
sstr = Pragma;
- free(context->Pragma);
+ Pragma = NULL;
+ free(context->Pragma);
context->Pragma = sstr;
rc = TRUE;
@@ -830,7 +831,10 @@ static BOOL http_response_parse_header_field(HttpResponse* response, const char*
const char* value)
{
BOOL status = TRUE;
- if (!response || !name)
+
+ WINPR_ASSERT(response);
+
+ if (!name)
return FALSE;
if (_stricmp(name, "Content-Length") == 0)
@@ -924,6 +928,10 @@ static BOOL http_response_parse_header_field(HttpResponse* response, const char*
*separator = '\0';
CookieName = value;
CookieValue = separator + 1;
+
+ if (!CookieName || !CookieValue)
+ return FALSE;
+
if (*CookieValue == '"')
{
char* p = CookieValue;
@@ -944,9 +952,6 @@ static BOOL http_response_parse_header_field(HttpResponse* response, const char*
}
*p = '\0';
}
-
- if (!CookieName || !CookieValue)
- return FALSE;
}
else
{
@@ -1053,12 +1058,13 @@ static void http_response_print(wLog* log, DWORD level, const HttpResponse* resp
freerdp_http_status_string_format(status, buffer, ARRAYSIZE(buffer)));
for (size_t i = 0; i < response->count; i++)
- WLog_Print(log, level, "[%" PRIuz "] %s", i, response->lines[i]);
+ WLog_Print(log, WLOG_DEBUG, "[%" PRIuz "] %s", i, response->lines[i]);
if (response->ReasonPhrase)
WLog_Print(log, level, "[reason] %s", response->ReasonPhrase);
- WLog_Print(log, level, "[body][%" PRIuz "] %s", response->BodyLength, response->BodyContent);
+ WLog_Print(log, WLOG_TRACE, "[body][%" PRIuz "] %s", response->BodyLength,
+ response->BodyContent);
}
static BOOL http_use_content_length(const char* cur)
diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c
index c6d952b..484b599 100644
--- a/libfreerdp/core/gateway/rdg.c
+++ b/libfreerdp/core/gateway/rdg.c
@@ -89,15 +89,6 @@
#define HTTP_TUNNEL_PACKET_FIELD_PAA_COOKIE 0x1
#define HTTP_TUNNEL_PACKET_FIELD_REAUTH 0x2
-/* HTTP tunnel redir flags. */
-#define HTTP_TUNNEL_REDIR_ENABLE_ALL 0x80000000
-#define HTTP_TUNNEL_REDIR_DISABLE_ALL 0x40000000
-#define HTTP_TUNNEL_REDIR_DISABLE_DRIVE 0x1
-#define HTTP_TUNNEL_REDIR_DISABLE_PRINTER 0x2
-#define HTTP_TUNNEL_REDIR_DISABLE_PORT 0x4
-#define HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD 0x8
-#define HTTP_TUNNEL_REDIR_DISABLE_PNP 0x10
-
/* HTTP tunnel response fields present flags. */
#define HTTP_TUNNEL_RESPONSE_FIELD_TUNNEL_ID 0x1
#define HTTP_TUNNEL_RESPONSE_FIELD_CAPS 0x2
@@ -146,6 +137,7 @@ struct rdp_rdg
rdg_http_encoding_context transferEncoding;
SmartcardCertInfo* smartcard;
+ wLog* log;
};
enum
@@ -261,15 +253,17 @@ static const char* capabilities_enum_to_string(UINT32 capabilities)
return flags_to_string(capabilities, capabilities_enum, ARRAYSIZE(capabilities_enum));
}
-static BOOL rdg_read_http_unicode_string(wStream* s, const WCHAR** string, UINT16* lengthInBytes)
+static BOOL rdg_read_http_unicode_string(wLog* log, wStream* s, const WCHAR** string,
+ UINT16* lengthInBytes)
{
UINT16 strLenBytes = 0;
size_t rem = Stream_GetRemainingLength(s);
/* Read length of the string */
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
{
- WLog_ERR(TAG, "Could not read stream length, only have %" PRIuz " bytes", rem);
+ WLog_Print(log, WLOG_ERROR, "Could not read stream length, only have %" PRIuz " bytes",
+ rem);
return FALSE;
}
Stream_Read_UINT16(s, strLenBytes);
@@ -280,8 +274,9 @@ static BOOL rdg_read_http_unicode_string(wStream* s, const WCHAR** string, UINT1
/* seek past the string - if this fails something is wrong */
if (!Stream_SafeSeek(s, strLenBytes))
{
- WLog_ERR(TAG, "Could not read stream data, only have %" PRIuz " bytes, expected %" PRIu16,
- rem - 4, strLenBytes);
+ WLog_Print(log, WLOG_ERROR,
+ "Could not read stream data, only have %" PRIuz " bytes, expected %" PRIu16,
+ rem - 4, strLenBytes);
return FALSE;
}
@@ -362,7 +357,13 @@ static int rdg_socket_read(BIO* bio, BYTE* pBuffer, size_t size,
}
}
-static BOOL rdg_read_all(rdpTls* tls, BYTE* buffer, size_t size,
+static BOOL rdg_shall_abort(rdpRdg* rdg)
+{
+ WINPR_ASSERT(rdg);
+ return freerdp_shall_disconnect_context(rdg->context);
+}
+
+static BOOL rdg_read_all(rdpContext* context, rdpTls* tls, BYTE* buffer, size_t size,
rdg_http_encoding_context* transferEncoding)
{
size_t readCount = 0;
@@ -370,6 +371,9 @@ static BOOL rdg_read_all(rdpTls* tls, BYTE* buffer, size_t size,
while (readCount < size)
{
+ if (freerdp_shall_disconnect_context(context))
+ return FALSE;
+
int status = rdg_socket_read(tls->bio, pBuffer, size - readCount, transferEncoding);
if (status <= 0)
{
@@ -396,7 +400,7 @@ static wStream* rdg_receive_packet(rdpRdg* rdg)
if (!s)
return NULL;
- if (!rdg_read_all(rdg->tlsOut, Stream_Buffer(s), header, &rdg->transferEncoding))
+ if (!rdg_read_all(rdg->context, rdg->tlsOut, Stream_Buffer(s), header, &rdg->transferEncoding))
{
Stream_Free(s, TRUE);
return NULL;
@@ -412,8 +416,8 @@ static wStream* rdg_receive_packet(rdpRdg* rdg)
return NULL;
}
- if (!rdg_read_all(rdg->tlsOut, Stream_Buffer(s) + header, (int)packetLength - (int)header,
- &rdg->transferEncoding))
+ if (!rdg_read_all(rdg->context, rdg->tlsOut, Stream_Buffer(s) + header,
+ (int)packetLength - (int)header, &rdg->transferEncoding))
{
Stream_Free(s, TRUE);
return NULL;
@@ -699,7 +703,7 @@ out:
return s;
}
-static BOOL rdg_recv_auth_token(rdpCredsspAuth* auth, HttpResponse* response)
+static BOOL rdg_recv_auth_token(wLog* log, rdpCredsspAuth* auth, HttpResponse* response)
{
size_t len = 0;
const char* token64 = NULL;
@@ -719,7 +723,7 @@ static BOOL rdg_recv_auth_token(rdpCredsspAuth* auth, HttpResponse* response)
case HTTP_STATUS_OK:
break;
default:
- http_response_log_error_status(WLog_Get(TAG), WLOG_WARN, response);
+ http_response_log_error_status(log, WLOG_WARN, response);
return FALSE;
}
@@ -738,6 +742,8 @@ static BOOL rdg_recv_auth_token(rdpCredsspAuth* auth, HttpResponse* response)
authToken.cbBuffer = authTokenLength;
credssp_auth_take_input_buffer(auth, &authToken);
}
+ else
+ free(authTokenData);
rc = credssp_auth_authenticate(auth);
if (rc < 0)
@@ -746,7 +752,7 @@ static BOOL rdg_recv_auth_token(rdpCredsspAuth* auth, HttpResponse* response)
return TRUE;
}
-static BOOL rdg_skip_seed_payload(rdpTls* tls, SSIZE_T lastResponseLength,
+static BOOL rdg_skip_seed_payload(rdpContext* context, rdpTls* tls, size_t lastResponseLength,
rdg_http_encoding_context* transferEncoding)
{
BYTE seed_payload[10] = { 0 };
@@ -755,9 +761,9 @@ static BOOL rdg_skip_seed_payload(rdpTls* tls, SSIZE_T lastResponseLength,
/* Per [MS-TSGU] 3.3.5.1 step 4, after final OK response RDG server sends
* random "seed" payload of limited size. In practice it's 10 bytes.
*/
- if (lastResponseLength < (SSIZE_T)size)
+ if (lastResponseLength < size)
{
- if (!rdg_read_all(tls, seed_payload, size - lastResponseLength, transferEncoding))
+ if (!rdg_read_all(context, tls, seed_payload, size - lastResponseLength, transferEncoding))
{
return FALSE;
}
@@ -774,14 +780,14 @@ static BOOL rdg_process_handshake_response(rdpRdg* rdg, wStream* s)
BYTE verMajor = 0;
BYTE verMinor = 0;
const char* error = NULL;
- WLog_DBG(TAG, "Handshake response received");
+ WLog_Print(rdg->log, WLOG_DEBUG, "Handshake response received");
if (rdg->state != RDG_CLIENT_STATE_HANDSHAKE)
{
return FALSE;
}
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 10))
return FALSE;
Stream_Read_UINT32(s, errorCode);
@@ -790,14 +796,14 @@ static BOOL rdg_process_handshake_response(rdpRdg* rdg, wStream* s)
Stream_Read_UINT16(s, serverVersion);
Stream_Read_UINT16(s, extendedAuth);
error = rpc_error_to_string(errorCode);
- WLog_DBG(TAG,
- "errorCode=%s, verMajor=%" PRId8 ", verMinor=%" PRId8 ", serverVersion=%" PRId16
- ", extendedAuth=%s",
- error, verMajor, verMinor, serverVersion, extended_auth_to_string(extendedAuth));
+ WLog_Print(rdg->log, WLOG_DEBUG,
+ "errorCode=%s, verMajor=%" PRId8 ", verMinor=%" PRId8 ", serverVersion=%" PRId16
+ ", extendedAuth=%s",
+ error, verMajor, verMinor, serverVersion, extended_auth_to_string(extendedAuth));
if (FAILED((HRESULT)errorCode))
{
- WLog_ERR(TAG, "Handshake error %s", error);
+ WLog_Print(rdg->log, WLOG_ERROR, "Handshake error %s", error);
freerdp_set_last_error_log(rdg->context, errorCode);
return FALSE;
}
@@ -815,8 +821,8 @@ static BOOL rdg_process_tunnel_response_optional(rdpRdg* rdg, wStream* s, UINT16
/* Seek over tunnelId (4 bytes) */
if (!Stream_SafeSeek(s, 4))
{
- WLog_ERR(TAG, "Short tunnelId, got %" PRIuz ", expected 4",
- Stream_GetRemainingLength(s));
+ WLog_Print(rdg->log, WLOG_ERROR, "Short tunnelId, got %" PRIuz ", expected 4",
+ Stream_GetRemainingLength(s));
return FALSE;
}
}
@@ -824,11 +830,11 @@ static BOOL rdg_process_tunnel_response_optional(rdpRdg* rdg, wStream* s, UINT16
if (fieldsPresent & HTTP_TUNNEL_RESPONSE_FIELD_CAPS)
{
UINT32 caps = 0;
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 4))
return FALSE;
Stream_Read_UINT32(s, caps);
- WLog_DBG(TAG, "capabilities=%s", capabilities_enum_to_string(caps));
+ WLog_Print(rdg->log, WLOG_DEBUG, "capabilities=%s", capabilities_enum_to_string(caps));
}
if (fieldsPresent & HTTP_TUNNEL_RESPONSE_FIELD_SOH_REQ)
@@ -836,14 +842,15 @@ static BOOL rdg_process_tunnel_response_optional(rdpRdg* rdg, wStream* s, UINT16
/* Seek over nonce (20 bytes) */
if (!Stream_SafeSeek(s, 20))
{
- WLog_ERR(TAG, "Short nonce, got %" PRIuz ", expected 20", Stream_GetRemainingLength(s));
+ WLog_Print(rdg->log, WLOG_ERROR, "Short nonce, got %" PRIuz ", expected 20",
+ Stream_GetRemainingLength(s));
return FALSE;
}
/* Read serverCert */
- if (!rdg_read_http_unicode_string(s, NULL, NULL))
+ if (!rdg_read_http_unicode_string(rdg->log, s, NULL, NULL))
{
- WLog_ERR(TAG, "Failed to read server certificate");
+ WLog_Print(rdg->log, WLOG_ERROR, "Failed to read server certificate");
return FALSE;
}
}
@@ -858,9 +865,9 @@ static BOOL rdg_process_tunnel_response_optional(rdpRdg* rdg, wStream* s, UINT16
WINPR_ASSERT(context->instance);
/* Read message string and invoke callback */
- if (!rdg_read_http_unicode_string(s, &msg, &msgLenBytes))
+ if (!rdg_read_http_unicode_string(rdg->log, s, &msg, &msgLenBytes))
{
- WLog_ERR(TAG, "Failed to read consent message");
+ WLog_Print(rdg->log, WLOG_ERROR, "Failed to read consent message");
return FALSE;
}
@@ -877,14 +884,14 @@ static BOOL rdg_process_tunnel_response(rdpRdg* rdg, wStream* s)
UINT16 fieldsPresent = 0;
UINT32 errorCode = 0;
const char* error = NULL;
- WLog_DBG(TAG, "Tunnel response received");
+ WLog_Print(rdg->log, WLOG_DEBUG, "Tunnel response received");
if (rdg->state != RDG_CLIENT_STATE_TUNNEL_CREATE)
{
return FALSE;
}
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 10))
return FALSE;
Stream_Read_UINT16(s, serverVersion);
@@ -892,12 +899,12 @@ static BOOL rdg_process_tunnel_response(rdpRdg* rdg, wStream* s)
Stream_Read_UINT16(s, fieldsPresent);
Stream_Seek_UINT16(s); /* reserved */
error = rpc_error_to_string(errorCode);
- WLog_DBG(TAG, "serverVersion=%" PRId16 ", errorCode=%s, fieldsPresent=%s", serverVersion, error,
- tunnel_response_fields_present_to_string(fieldsPresent));
+ WLog_Print(rdg->log, WLOG_DEBUG, "serverVersion=%" PRId16 ", errorCode=%s, fieldsPresent=%s",
+ serverVersion, error, tunnel_response_fields_present_to_string(fieldsPresent));
if (FAILED((HRESULT)errorCode))
{
- WLog_ERR(TAG, "Tunnel creation error %s", error);
+ WLog_Print(rdg->log, WLOG_ERROR, "Tunnel creation error %s", error);
freerdp_set_last_error_log(rdg->context, errorCode);
return FALSE;
}
@@ -913,31 +920,66 @@ static BOOL rdg_process_tunnel_authorization_response(rdpRdg* rdg, wStream* s)
UINT32 errorCode = 0;
UINT16 fieldsPresent = 0;
const char* error = NULL;
- WLog_DBG(TAG, "Tunnel authorization received");
+ WLog_Print(rdg->log, WLOG_DEBUG, "Tunnel authorization received");
if (rdg->state != RDG_CLIENT_STATE_TUNNEL_AUTHORIZE)
{
return FALSE;
}
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 8))
return FALSE;
Stream_Read_UINT32(s, errorCode);
Stream_Read_UINT16(s, fieldsPresent);
Stream_Seek_UINT16(s); /* reserved */
error = rpc_error_to_string(errorCode);
- WLog_DBG(TAG, "errorCode=%s, fieldsPresent=%s", error,
- tunnel_authorization_response_fields_present_to_string(fieldsPresent));
+ WLog_Print(rdg->log, WLOG_DEBUG, "errorCode=%s, fieldsPresent=%s", error,
+ tunnel_authorization_response_fields_present_to_string(fieldsPresent));
/* [MS-TSGU] 3.7.5.2.7 */
if (errorCode != S_OK && errorCode != E_PROXY_QUARANTINE_ACCESSDENIED)
{
- WLog_ERR(TAG, "Tunnel authorization error %s", error);
+ WLog_Print(rdg->log, WLOG_ERROR, "Tunnel authorization error %s", error);
freerdp_set_last_error_log(rdg->context, errorCode);
return FALSE;
}
+ if (fieldsPresent & HTTP_TUNNEL_AUTH_RESPONSE_FIELD_REDIR_FLAGS)
+ {
+ UINT32 redirFlags = 0;
+ if (!Stream_CheckAndLogRequiredCapacityWLog(rdg->log, s, 4))
+ return FALSE;
+ Stream_Read_UINT32(s, redirFlags);
+
+ rdpContext* context = rdg->context;
+ if (!utils_apply_gateway_policy(rdg->log, context, redirFlags, "RDG"))
+ return FALSE;
+ }
+
+ if (fieldsPresent & HTTP_TUNNEL_AUTH_RESPONSE_FIELD_IDLE_TIMEOUT)
+ {
+ UINT32 idleTimeout = 0;
+ if (!Stream_CheckAndLogRequiredCapacityWLog(rdg->log, s, 4))
+ return FALSE;
+ Stream_Read_UINT32(s, idleTimeout);
+ WLog_Print(rdg->log, WLOG_DEBUG, "[IDLE_TIMEOUT] idleTimeout=%" PRIu32 ": TODO: unused",
+ idleTimeout);
+ }
+
+ if (fieldsPresent & HTTP_TUNNEL_AUTH_RESPONSE_FIELD_SOH_RESPONSE)
+ {
+ UINT16 cbLen = 0;
+ if (!Stream_CheckAndLogRequiredCapacityWLog(rdg->log, s, 2))
+ return FALSE;
+ Stream_Read_UINT16(s, cbLen);
+
+ WLog_Print(rdg->log, WLOG_DEBUG, "[SOH_RESPONSE] cbLen=%" PRIu16 ": TODO: unused", cbLen);
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, cbLen))
+ return FALSE;
+ Stream_Seek(s, cbLen);
+ }
+
return rdg_send_channel_create(rdg);
}
@@ -955,8 +997,8 @@ static BOOL rdg_process_extauth_sspi(rdpRdg* rdg, wStream* s)
if (errorCode != ERROR_SUCCESS)
{
- WLog_ERR(TAG, "EXTAUTH_SSPI_NTLM failed with error %s [0x%08X]",
- GetSecurityStatusString(errorCode), errorCode);
+ WLog_Print(rdg->log, WLOG_ERROR, "EXTAUTH_SSPI_NTLM failed with error %s [0x%08X]",
+ GetSecurityStatusString(errorCode), errorCode);
return FALSE;
}
@@ -972,6 +1014,8 @@ static BOOL rdg_process_extauth_sspi(rdpRdg* rdg, wStream* s)
}
authTokenData = malloc(authBlobLen);
+ if (authTokenData == NULL)
+ return FALSE;
Stream_Read(s, authTokenData, authBlobLen);
authToken.pvBuffer = authTokenData;
@@ -993,27 +1037,27 @@ static BOOL rdg_process_channel_response(rdpRdg* rdg, wStream* s)
UINT16 fieldsPresent = 0;
UINT32 errorCode = 0;
const char* error = NULL;
- WLog_DBG(TAG, "Channel response received");
+ WLog_Print(rdg->log, WLOG_DEBUG, "Channel response received");
if (rdg->state != RDG_CLIENT_STATE_CHANNEL_CREATE)
{
return FALSE;
}
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 8))
return FALSE;
Stream_Read_UINT32(s, errorCode);
Stream_Read_UINT16(s, fieldsPresent);
Stream_Seek_UINT16(s); /* reserved */
error = rpc_error_to_string(errorCode);
- WLog_DBG(TAG, "channel response errorCode=%s, fieldsPresent=%s", error,
- channel_response_fields_present_to_string(fieldsPresent));
+ WLog_Print(rdg->log, WLOG_DEBUG, "channel response errorCode=%s, fieldsPresent=%s", error,
+ channel_response_fields_present_to_string(fieldsPresent));
if (FAILED((HRESULT)errorCode))
{
- WLog_ERR(TAG, "channel response errorCode=%s, fieldsPresent=%s", error,
- channel_response_fields_present_to_string(fieldsPresent));
+ WLog_Print(rdg->log, WLOG_ERROR, "channel response errorCode=%s, fieldsPresent=%s", error,
+ channel_response_fields_present_to_string(fieldsPresent));
freerdp_set_last_error_log(rdg->context, errorCode);
return FALSE;
}
@@ -1029,7 +1073,7 @@ static BOOL rdg_process_packet(rdpRdg* rdg, wStream* s)
UINT32 packetLength = 0;
Stream_SetPosition(s, 0);
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 8))
return FALSE;
Stream_Read_UINT16(s, type);
@@ -1038,7 +1082,8 @@ static BOOL rdg_process_packet(rdpRdg* rdg, wStream* s)
if (Stream_Length(s) < packetLength)
{
- WLog_ERR(TAG, "Short packet %" PRIuz ", expected %" PRIuz, Stream_Length(s), packetLength);
+ WLog_Print(rdg->log, WLOG_ERROR, "Short packet %" PRIuz ", expected %" PRIuz,
+ Stream_Length(s), packetLength);
return FALSE;
}
@@ -1061,7 +1106,7 @@ static BOOL rdg_process_packet(rdpRdg* rdg, wStream* s)
break;
case PKT_TYPE_DATA:
- WLog_ERR(TAG, "Unexpected packet type DATA");
+ WLog_Print(rdg->log, WLOG_ERROR, "Unexpected packet type DATA");
return FALSE;
case PKT_TYPE_EXTENDED_AUTH_MSG:
@@ -1069,7 +1114,7 @@ static BOOL rdg_process_packet(rdpRdg* rdg, wStream* s)
break;
default:
- WLog_ERR(TAG, "PKG TYPE 0x%x not implemented", type);
+ WLog_Print(rdg->log, WLOG_ERROR, "PKG TYPE 0x%x not implemented", type);
return FALSE;
}
@@ -1325,7 +1370,7 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
* sending an answer if it is not happy with the http request */
if (!response)
{
- WLog_INFO(TAG, "RD Gateway HTTP transport broken.");
+ WLog_Print(rdg->log, WLOG_INFO, "RD Gateway HTTP transport broken.");
*rpcFallback = TRUE;
return FALSE;
}
@@ -1336,7 +1381,7 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
{
case HTTP_STATUS_NOT_FOUND:
{
- WLog_INFO(TAG, "RD Gateway does not support HTTP transport.");
+ WLog_Print(rdg->log, WLOG_INFO, "RD Gateway does not support HTTP transport.");
*rpcFallback = TRUE;
http_response_free(response);
@@ -1345,13 +1390,13 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
case HTTP_STATUS_OK:
break;
default:
- http_response_log_error_status(WLog_Get(TAG), WLOG_WARN, response);
+ http_response_log_error_status(rdg->log, WLOG_WARN, response);
break;
}
while (!credssp_auth_is_complete(rdg->auth))
{
- if (!rdg_recv_auth_token(rdg->auth, response))
+ if (!rdg_recv_auth_token(rdg->log, rdg->auth, response))
{
http_response_free(response);
return FALSE;
@@ -1367,7 +1412,7 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
response = http_response_recv(tls, TRUE);
if (!response)
{
- WLog_INFO(TAG, "RD Gateway HTTP transport broken.");
+ WLog_Print(rdg->log, WLOG_INFO, "RD Gateway HTTP transport broken.");
*rpcFallback = TRUE;
return FALSE;
}
@@ -1388,7 +1433,7 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
if (!response)
{
- WLog_INFO(TAG, "RD Gateway HTTP transport broken.");
+ WLog_Print(rdg->log, WLOG_INFO, "RD Gateway HTTP transport broken.");
*rpcFallback = TRUE;
return FALSE;
}
@@ -1398,9 +1443,9 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
const size_t bodyLength = http_response_get_body_length(response);
const TRANSFER_ENCODING encoding = http_response_get_transfer_encoding(response);
const BOOL isWebsocket = http_response_is_websocket(rdg->http, response);
- http_response_free(response);
- WLog_DBG(TAG, "%s authorization result: %s", method,
- freerdp_http_status_string_format(statusCode, buffer, ARRAYSIZE(buffer)));
+
+ WLog_Print(rdg->log, WLOG_DEBUG, "%s authorization result: %s", method,
+ freerdp_http_status_string_format(statusCode, buffer, ARRAYSIZE(buffer)));
switch (statusCode)
{
@@ -1408,11 +1453,14 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
/* old rdg endpoint without websocket support, don't request websocket for RDG_IN_DATA
*/
http_context_enable_websocket_upgrade(rdg->http, FALSE);
+ http_response_free(response);
break;
case HTTP_STATUS_DENIED:
freerdp_set_last_error_log(rdg->context, FREERDP_ERROR_CONNECT_ACCESS_DENIED);
+ http_response_free(response);
return FALSE;
case HTTP_STATUS_SWITCH_PROTOCOLS:
+ http_response_free(response);
if (!isWebsocket)
{
/*
@@ -1442,7 +1490,8 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
}
return TRUE;
default:
- http_response_log_error_status(WLog_Get(TAG), WLOG_WARN, response);
+ http_response_log_error_status(rdg->log, WLOG_WARN, response);
+ http_response_free(response);
return FALSE;
}
@@ -1455,7 +1504,7 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
rdg->transferEncoding.context.chunked.headerFooterPos = 0;
rdg->transferEncoding.context.chunked.state = ChunkStateLenghHeader;
}
- if (!rdg_skip_seed_payload(tls, bodyLength, &rdg->transferEncoding))
+ if (!rdg_skip_seed_payload(rdg->context, tls, bodyLength, &rdg->transferEncoding))
{
return FALSE;
}
@@ -1522,7 +1571,7 @@ BOOL rdg_connect(rdpRdg* rdg, DWORD timeout, BOOL* rpcFallback)
{
if (rdg->transferEncoding.isWebsocketTransport)
{
- WLog_DBG(TAG, "Upgraded to websocket. RDG_IN_DATA not required");
+ WLog_Print(rdg->log, WLOG_DEBUG, "Upgraded to websocket. RDG_IN_DATA not required");
}
else
{
@@ -1717,7 +1766,7 @@ static BOOL rdg_process_close_packet(rdpRdg* rdg, wStream* s)
UINT32 packetSize = 12;
/* Read error code */
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 4))
return FALSE;
Stream_Read_UINT32(s, errorCode);
@@ -1769,9 +1818,9 @@ static BOOL rdg_process_service_message(rdpRdg* rdg, wStream* s)
WINPR_ASSERT(context->instance);
/* Read message string */
- if (!rdg_read_http_unicode_string(s, &msg, &msgLenBytes))
+ if (!rdg_read_http_unicode_string(rdg->log, s, &msg, &msgLenBytes))
{
- WLog_ERR(TAG, "Failed to read string");
+ WLog_Print(rdg->log, WLOG_ERROR, "Failed to read string");
return FALSE;
}
@@ -1783,7 +1832,7 @@ static BOOL rdg_process_unknown_packet(rdpRdg* rdg, int type)
{
WINPR_UNUSED(rdg);
WINPR_UNUSED(type);
- WLog_WARN(TAG, "Unknown Control Packet received: %X", type);
+ WLog_Print(rdg->log, WLOG_WARN, "Unknown Control Packet received: %X", type);
return TRUE;
}
@@ -1808,6 +1857,11 @@ static BOOL rdg_process_control_packet(rdpRdg* rdg, int type, size_t packetLengt
while (readCount < payloadSize)
{
+ if (rdg_shall_abort(rdg))
+ {
+ Stream_Free(s, TRUE);
+ return FALSE;
+ }
status = rdg_socket_read(rdg->tlsOut->bio, Stream_Pointer(s), payloadSize - readCount,
&rdg->transferEncoding);
@@ -1852,7 +1906,8 @@ static BOOL rdg_process_control_packet(rdpRdg* rdg, int type, size_t packetLengt
case PKT_TYPE_SERVICE_MESSAGE:
if (!s)
{
- WLog_ERR(TAG, "PKT_TYPE_SERVICE_MESSAGE requires payload but none was sent");
+ WLog_Print(rdg->log, WLOG_ERROR,
+ "PKT_TYPE_SERVICE_MESSAGE requires payload but none was sent");
return FALSE;
}
status = rdg_process_service_message(rdg, s);
@@ -1880,6 +1935,9 @@ static int rdg_read_data_packet(rdpRdg* rdg, BYTE* buffer, int size)
while (readCount < sizeof(RdgPacketHeader))
{
+ if (rdg_shall_abort(rdg))
+ return -1;
+
status = rdg_socket_read(rdg->tlsOut->bio, (BYTE*)(&header) + readCount,
(int)sizeof(RdgPacketHeader) - (int)readCount,
&rdg->transferEncoding);
@@ -1916,6 +1974,8 @@ static int rdg_read_data_packet(rdpRdg* rdg, BYTE* buffer, int size)
while (readCount < 2)
{
+ if (rdg_shall_abort(rdg))
+ return -1;
status =
rdg_socket_read(rdg->tlsOut->bio, (BYTE*)(&rdg->packetRemainingCount) + readCount,
2 - (int)readCount, &rdg->transferEncoding);
@@ -2153,6 +2213,7 @@ rdpRdg* rdg_new(rdpContext* context)
if (rdg)
{
+ rdg->log = WLog_Get(TAG);
rdg->state = RDG_CLIENT_STATE_INITIAL;
rdg->context = context;
rdg->settings = rdg->context->settings;
@@ -2212,8 +2273,8 @@ rdpRdg* rdg_new(rdpContext* context)
break;
default:
- WLog_DBG(TAG, "RDG extended authentication method %d not supported",
- rdg->extAuth);
+ WLog_Print(rdg->log, WLOG_DEBUG,
+ "RDG extended authentication method %d not supported", rdg->extAuth);
}
}
diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c
index 3ab833a..8101e53 100644
--- a/libfreerdp/core/gateway/tsg.c
+++ b/libfreerdp/core/gateway/tsg.c
@@ -35,6 +35,7 @@
#include "rpc_bind.h"
#include "rpc_client.h"
#include "tsg.h"
+#include "../utils.h"
#include "../../crypto/opensslcompat.h"
#define TAG FREERDP_TAG("core.gateway.tsg")
@@ -1590,7 +1591,7 @@ fail:
return FALSE;
}
-static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu,
+static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, const RPC_PDU* pdu,
CONTEXT_HANDLE* tunnelContext, UINT32* tunnelId)
{
BOOL rc = FALSE;
@@ -1728,7 +1729,41 @@ fail:
return FALSE;
}
-static BOOL TsProxyAuthorizeTunnelReadResponse(wLog* log, RPC_PDU* pdu)
+static UINT32 tsg_redir_to_flags(const TSG_REDIRECTION_FLAGS* redirect)
+{
+ UINT32 flags = 0;
+ if (redirect->enableAllRedirections)
+ flags |= HTTP_TUNNEL_REDIR_ENABLE_ALL;
+ if (redirect->disableAllRedirections)
+ flags |= HTTP_TUNNEL_REDIR_DISABLE_ALL;
+
+ if (redirect->driveRedirectionDisabled)
+ flags |= HTTP_TUNNEL_REDIR_DISABLE_DRIVE;
+ if (redirect->printerRedirectionDisabled)
+ flags |= HTTP_TUNNEL_REDIR_DISABLE_PRINTER;
+ if (redirect->portRedirectionDisabled)
+ flags |= HTTP_TUNNEL_REDIR_DISABLE_PORT;
+ if (redirect->clipboardRedirectionDisabled)
+ flags |= HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD;
+ if (redirect->pnpRedirectionDisabled)
+ flags |= HTTP_TUNNEL_REDIR_DISABLE_PNP;
+ return flags;
+}
+
+static BOOL tsg_redirect_apply(rdpTsg* tsg, const TSG_REDIRECTION_FLAGS* redirect)
+{
+ WINPR_ASSERT(tsg);
+ WINPR_ASSERT(redirect);
+
+ rdpTransport* transport = tsg->transport;
+ WINPR_ASSERT(transport);
+
+ rdpContext* context = transport_get_context(transport);
+ UINT32 redirFlags = tsg_redir_to_flags(redirect);
+ return utils_apply_gateway_policy(tsg->log, context, redirFlags, "TSG");
+}
+
+static BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, const RPC_PDU* pdu)
{
BOOL rc = FALSE;
UINT32 SwitchValue = 0;
@@ -1736,8 +1771,12 @@ static BOOL TsProxyAuthorizeTunnelReadResponse(wLog* log, RPC_PDU* pdu)
TSG_PACKET packet = { 0 };
UINT32 PacketPtr = 0;
UINT32 PacketResponsePtr = 0;
- if (!pdu)
- return FALSE;
+
+ WINPR_ASSERT(tsg);
+ WINPR_ASSERT(pdu);
+
+ wLog* log = tsg->log;
+ WINPR_ASSERT(log);
if (!tsg_ndr_pointer_read(log, pdu->s, &index, &PacketPtr, TRUE))
goto fail;
@@ -1773,6 +1812,9 @@ static BOOL TsProxyAuthorizeTunnelReadResponse(wLog* log, RPC_PDU* pdu)
goto fail;
rc = TRUE;
+
+ if (packet.tsgPacket.packetResponse.flags & TSG_PACKET_TYPE_QUARREQUEST)
+ rc = tsg_redirect_apply(tsg, &packet.tsgPacket.packetResponse.redirectionFlags);
fail:
return rc;
}
@@ -1846,7 +1888,7 @@ static BOOL TsProxyReadPacketSTringMessage(rdpTsg* tsg, wStream* s, TSG_PACKET_S
return tsg_ndr_read_string(tsg->log, s, &msg->msgBuffer, msg->msgBytes);
}
-static BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, RPC_PDU* pdu)
+static BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, const RPC_PDU* pdu)
{
BOOL rc = FALSE;
UINT32 index = 0;
@@ -1991,20 +2033,20 @@ fail:
static BOOL TsProxyCreateChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnelContext)
{
- size_t count = 0;
- wStream* s = NULL;
- rdpRpc* rpc = NULL;
+ WINPR_ASSERT(tsg);
+ WINPR_ASSERT(tunnelContext);
+
WLog_Print(tsg->log, WLOG_DEBUG, "TsProxyCreateChannelWriteRequest");
- if (!tsg || !tsg->rpc || !tunnelContext || !tsg->Hostname)
+ if (!tsg->rpc || !tsg->Hostname)
return FALSE;
- rpc = tsg->rpc;
- count = _wcslen(tsg->Hostname) + 1;
+ rdpRpc* rpc = tsg->rpc;
+ const size_t count = _wcslen(tsg->Hostname) + 1;
if (count > UINT32_MAX)
return FALSE;
- s = Stream_New(NULL, 60 + count * 2);
+ wStream* s = Stream_New(NULL, 60 + count * 2);
if (!s)
return FALSE;
@@ -2036,14 +2078,16 @@ fail:
return FALSE;
}
-static BOOL TsProxyCreateChannelReadResponse(wLog* log, RPC_PDU* pdu,
+static BOOL TsProxyCreateChannelReadResponse(wLog* log, const RPC_PDU* pdu,
CONTEXT_HANDLE* channelContext, UINT32* channelId)
{
BOOL rc = FALSE;
- WLog_Print(log, WLOG_DEBUG, "TsProxyCreateChannelReadResponse");
- if (!pdu)
- return FALSE;
+ WINPR_ASSERT(log);
+ WINPR_ASSERT(pdu);
+ WINPR_ASSERT(channelId);
+
+ WLog_Print(log, WLOG_DEBUG, "TsProxyCreateChannelReadResponse");
if (!Stream_CheckAndLogRequiredLengthWLog(log, pdu->s, 28))
goto fail;
@@ -2068,15 +2112,15 @@ fail:
static BOOL TsProxyCloseChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* context)
{
- wStream* s = NULL;
- rdpRpc* rpc = NULL;
+ WINPR_ASSERT(tsg);
+ WINPR_ASSERT(context);
+
WLog_Print(tsg->log, WLOG_DEBUG, "TsProxyCloseChannelWriteRequest");
- if (!tsg || !tsg->rpc || !context)
- return FALSE;
+ rdpRpc* rpc = tsg->rpc;
+ WINPR_ASSERT(rpc);
- rpc = tsg->rpc;
- s = Stream_New(NULL, 20);
+ wStream* s = Stream_New(NULL, 20);
if (!s)
return FALSE;
@@ -2090,7 +2134,7 @@ fail:
return FALSE;
}
-static BOOL TsProxyCloseChannelReadResponse(wLog* log, RPC_PDU* pdu, CONTEXT_HANDLE* context)
+static BOOL TsProxyCloseChannelReadResponse(wLog* log, const RPC_PDU* pdu, CONTEXT_HANDLE* context)
{
BOOL rc = FALSE;
WLog_Print(log, WLOG_DEBUG, "TsProxyCloseChannelReadResponse");
@@ -2124,15 +2168,15 @@ fail:
static BOOL TsProxyCloseTunnelWriteRequest(rdpTsg* tsg, const CONTEXT_HANDLE* context)
{
- wStream* s = NULL;
- rdpRpc* rpc = NULL;
+ WINPR_ASSERT(tsg);
+ WINPR_ASSERT(context);
+
WLog_Print(tsg->log, WLOG_DEBUG, "TsProxyCloseTunnelWriteRequest");
- if (!tsg || !tsg->rpc || !context)
- return FALSE;
+ rdpRpc* rpc = tsg->rpc;
+ WINPR_ASSERT(rpc);
- rpc = tsg->rpc;
- s = Stream_New(NULL, 20);
+ wStream* s = Stream_New(NULL, 20);
if (!s)
return FALSE;
@@ -2146,13 +2190,15 @@ fail:
return FALSE;
}
-static BOOL TsProxyCloseTunnelReadResponse(wLog* log, RPC_PDU* pdu, CONTEXT_HANDLE* context)
+static BOOL TsProxyCloseTunnelReadResponse(wLog* log, const RPC_PDU* pdu, CONTEXT_HANDLE* context)
{
BOOL rc = FALSE;
- WLog_Print(log, WLOG_DEBUG, "TsProxyCloseTunnelReadResponse");
- if (!pdu || !context)
- return FALSE;
+ WINPR_ASSERT(log);
+ WINPR_ASSERT(pdu);
+ WINPR_ASSERT(context);
+
+ WLog_Print(log, WLOG_DEBUG, "TsProxyCloseTunnelReadResponse");
if (!Stream_CheckAndLogRequiredLengthWLog(log, pdu->s, 24))
goto fail;
@@ -2294,7 +2340,7 @@ static BOOL tsg_proxy_reauth(rdpTsg* tsg)
return tsg_transition_to_state(tsg, TSG_STATE_INITIAL);
}
-BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu)
+BOOL tsg_recv_pdu(rdpTsg* tsg, const RPC_PDU* pdu)
{
BOOL rc = FALSE;
RpcClientCall* call = NULL;
@@ -2342,10 +2388,10 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu)
case TSG_STATE_CONNECTED:
{
- CONTEXT_HANDLE* TunnelContext = NULL;
- TunnelContext = (tsg->reauthSequence) ? &tsg->NewTunnelContext : &tsg->TunnelContext;
+ CONTEXT_HANDLE* TunnelContext =
+ (tsg->reauthSequence) ? &tsg->NewTunnelContext : &tsg->TunnelContext;
- if (!TsProxyAuthorizeTunnelReadResponse(tsg->log, pdu))
+ if (!TsProxyAuthorizeTunnelReadResponse(tsg, pdu))
{
WLog_Print(tsg->log, WLOG_ERROR, "TsProxyAuthorizeTunnelReadResponse failure");
return FALSE;
diff --git a/libfreerdp/core/gateway/tsg.h b/libfreerdp/core/gateway/tsg.h
index 626a7ac..81b50a7 100644
--- a/libfreerdp/core/gateway/tsg.h
+++ b/libfreerdp/core/gateway/tsg.h
@@ -109,7 +109,7 @@ FREERDP_LOCAL BOOL tsg_proxy_begin(rdpTsg* tsg);
FREERDP_LOCAL BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, DWORD timeout);
FREERDP_LOCAL BOOL tsg_disconnect(rdpTsg* tsg);
-FREERDP_LOCAL BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu);
+FREERDP_LOCAL BOOL tsg_recv_pdu(rdpTsg* tsg, const RPC_PDU* pdu);
FREERDP_LOCAL BOOL tsg_check_event_handles(rdpTsg* tsg);
FREERDP_LOCAL DWORD tsg_get_event_handles(rdpTsg* tsg, HANDLE* events, DWORD count);
diff --git a/libfreerdp/core/gateway/wst.c b/libfreerdp/core/gateway/wst.c
index 00581d3..87194da 100644
--- a/libfreerdp/core/gateway/wst.c
+++ b/libfreerdp/core/gateway/wst.c
@@ -199,6 +199,8 @@ static BOOL wst_recv_auth_token(rdpCredsspAuth* auth, HttpResponse* response)
authToken.cbBuffer = authTokenLength;
credssp_auth_take_input_buffer(auth, &authToken);
}
+ else
+ free(authTokenData);
rc = credssp_auth_authenticate(auth);
if (rc < 0)
diff --git a/libfreerdp/core/gcc.c b/libfreerdp/core/gcc.c
index d99ee86..733a763 100644
--- a/libfreerdp/core/gcc.c
+++ b/libfreerdp/core/gcc.c
@@ -1704,7 +1704,13 @@ BOOL gcc_read_server_security_data(wStream* s, rdpMcs* mcs)
Stream_Read_UINT32(s, settings->ServerCertificateLength); /* serverCertLen */
if ((settings->ServerRandomLength == 0) || (settings->ServerCertificateLength == 0))
+ {
+ WLog_ERR(TAG,
+ "Invalid ServerRandom (length=%" PRIu32 ") or ServerCertificate (length=%" PRIu32
+ ")",
+ settings->ServerRandomLength, settings->ServerCertificateLength);
return FALSE;
+ }
if (!Stream_CheckAndLogRequiredLength(TAG, s, settings->ServerRandomLength))
return FALSE;
diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c
index 0d8e90e..7d6eec1 100644
--- a/libfreerdp/core/info.c
+++ b/libfreerdp/core/info.c
@@ -469,8 +469,12 @@ static BOOL rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s)
rdpSettings* settings = rdp->settings;
WINPR_ASSERT(settings);
- const UINT16 clientAddressFamily =
- settings->IPv6Enabled ? ADDRESS_FAMILY_INET6 : ADDRESS_FAMILY_INET;
+ UINT16 clientAddressFamily = ADDRESS_FAMILY_INET;
+ if (settings->ConnectChildSession)
+ clientAddressFamily = 0x0000;
+ else if (settings->IPv6Enabled)
+ clientAddressFamily = ADDRESS_FAMILY_INET6;
+
WCHAR* clientAddress = ConvertUtf8ToWCharAlloc(settings->ClientAddress, &cbClientAddress);
if (cbClientAddress > (UINT16_MAX / sizeof(WCHAR)))
diff --git a/libfreerdp/core/input.h b/libfreerdp/core/input.h
index c67153b..9a1585d 100644
--- a/libfreerdp/core/input.h
+++ b/libfreerdp/core/input.h
@@ -38,7 +38,7 @@ typedef struct
rdpInputProxy* proxy;
wMessageQueue* queue;
- UINT32 lastInputTimestamp;
+ UINT64 lastInputTimestamp;
UINT16 lastX;
UINT16 lastY;
} rdp_input_internal;
diff --git a/libfreerdp/core/license.c b/libfreerdp/core/license.c
index 99d4fa2..aeb7bb2 100644
--- a/libfreerdp/core/license.c
+++ b/libfreerdp/core/license.c
@@ -1114,10 +1114,9 @@ BOOL license_generate_hwid(rdpLicense* license)
const char* hostname = license->rdp->settings->ClientHostname;
wStream* s = Stream_StaticInit(&buffer, license->HardwareId, 4);
Stream_Write_UINT32(s, license->PlatformId);
- Stream_Free(s, TRUE);
hashTarget = (const BYTE*)hostname;
- targetLen = strlen(hostname);
+ targetLen = hostname ? strlen(hostname) : 0;
}
/* Allow FIPS override for use of MD5 here, really this does not have to be MD5 as we are just
@@ -1723,14 +1722,15 @@ void license_free_scope_list(SCOPE_LIST* scopeList)
BOOL license_send_license_info(rdpLicense* license, const LICENSE_BLOB* calBlob,
const BYTE* signature, size_t signature_length)
{
- wStream* s = license_send_stream_init(license);
-
WINPR_ASSERT(calBlob);
WINPR_ASSERT(signature);
WINPR_ASSERT(license->certificate);
const rdpCertInfo* info = freerdp_certificate_get_info(license->certificate);
+ if (!info)
+ return FALSE;
+ wStream* s = license_send_stream_init(license);
if (!s)
return FALSE;
@@ -2802,18 +2802,25 @@ BOOL license_server_send_request(rdpLicense* license)
return license_set_state(license, LICENSE_STATE_REQUEST);
}
-static BOOL license_set_string(const char* what, const char* value, WCHAR** dst, UINT32* dstLen)
+static BOOL license_set_string(const char* what, const char* value, BYTE** bdst, UINT32* dstLen)
{
WINPR_ASSERT(what);
WINPR_ASSERT(value);
- WINPR_ASSERT(dst);
+ WINPR_ASSERT(bdst);
WINPR_ASSERT(dstLen);
+ union
+ {
+ WCHAR** w;
+ BYTE** b;
+ } cnv;
+ cnv.b = bdst;
+
size_t len = 0;
- *dst = (BYTE*)ConvertUtf8ToWCharAlloc(value, &len);
- if (!*dst || (len > UINT32_MAX / sizeof(WCHAR)))
+ *cnv.w = ConvertUtf8ToWCharAlloc(value, &len);
+ if (!*cnv.w || (len > UINT32_MAX / sizeof(WCHAR)))
{
- WLog_ERR(TAG, "license->ProductInfo: %s == %p || %" PRIu32 " > UINT32_MAX", what, *dst,
+ WLog_ERR(TAG, "license->ProductInfo: %s == %p || %" PRIu32 " > UINT32_MAX", what, *cnv.w,
len);
return FALSE;
}
diff --git a/libfreerdp/core/listener.c b/libfreerdp/core/listener.c
index 5a9c1e2..a7592da 100644
--- a/libfreerdp/core/listener.c
+++ b/libfreerdp/core/listener.c
@@ -188,10 +188,11 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&option_value,
sizeof(option_value)) == -1)
- WLog_ERR(TAG, "setsockopt");
+ WLog_ERR(TAG, "setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR)");
#ifndef _WIN32
- fcntl(sockfd, F_SETFL, O_NONBLOCK);
+ if (fcntl(sockfd, F_SETFL, O_NONBLOCK) != 0)
+ WLog_ERR(TAG, "fcntl(sockfd, F_SETFL, O_NONBLOCK)");
#else
arg = 1;
ioctlsocket(sockfd, FIONBIO, &arg);
@@ -256,7 +257,14 @@ static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char*
return FALSE;
}
- fcntl(sockfd, F_SETFL, O_NONBLOCK);
+ int rc = fcntl(sockfd, F_SETFL, O_NONBLOCK);
+ if (rc != 0)
+ {
+ WLog_ERR(TAG, "fcntl(sockfd, F_SETFL, O_NONBLOCK)");
+ closesocket((SOCKET)sockfd);
+ return FALSE;
+ }
+
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
unlink(path);
diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c
index ddee306..577e0b4 100644
--- a/libfreerdp/core/nla.c
+++ b/libfreerdp/core/nla.c
@@ -1148,6 +1148,11 @@ static BOOL nla_read_TSCspDataDetail(WinPrAsn1Decoder* dec, rdpSettings* setting
static BOOL nla_read_KERB_TICKET_LOGON(rdpNla* nla, wStream* s, KERB_TICKET_LOGON* ticket)
{
+ WINPR_ASSERT(nla);
+
+ if (!ticket)
+ return FALSE;
+
/* mysterious extra 16 bytes before TGS/TGT content */
if (!Stream_CheckAndLogRequiredLength(TAG, s, 16 + 16))
return FALSE;
@@ -1244,7 +1249,7 @@ static BOOL nla_read_ts_credentials(rdpNla* nla, SecBuffer* data)
WinPrAsn1_OctetString credentials = { 0 };
BOOL error = FALSE;
WinPrAsn1_INTEGER credType = -1;
- BOOL ret = true;
+ BOOL ret = TRUE;
WINPR_ASSERT(nla);
WINPR_ASSERT(data);
diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c
index 9d00c66..42c4c21 100644
--- a/libfreerdp/core/peer.c
+++ b/libfreerdp/core/peer.c
@@ -1495,7 +1495,8 @@ void freerdp_peer_free(freerdp_peer* client)
return;
sspi_FreeAuthIdentity(&client->identity);
- closesocket((SOCKET)client->sockfd);
+ if (client->sockfd >= 0)
+ closesocket((SOCKET)client->sockfd);
free(client);
}
@@ -1511,6 +1512,7 @@ static BOOL freerdp_peer_transport_setup(freerdp_peer* client)
if (!transport_attach(rdp->transport, client->sockfd))
return FALSE;
+ client->sockfd = -1;
if (!transport_set_recv_callbacks(rdp->transport, peer_recv_callback, client))
return FALSE;
diff --git a/libfreerdp/core/proxy.c b/libfreerdp/core/proxy.c
index 9312c22..ecb9b34 100644
--- a/libfreerdp/core/proxy.c
+++ b/libfreerdp/core/proxy.c
@@ -284,14 +284,12 @@ static BOOL check_no_proxy(rdpSettings* settings, const char* no_proxy)
void proxy_read_environment(rdpSettings* settings, char* envname)
{
- DWORD envlen = 0;
- char* env = NULL;
- envlen = GetEnvironmentVariableA(envname, NULL, 0);
+ const DWORD envlen = GetEnvironmentVariableA(envname, NULL, 0);
- if (!envlen)
+ if (!envlen || (envlen <= 1))
return;
- env = calloc(1, envlen);
+ char* env = calloc(1, envlen);
if (!env)
{
diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c
index c1f6d3a..466a9a7 100644
--- a/libfreerdp/core/rdp.c
+++ b/libfreerdp/core/rdp.c
@@ -261,7 +261,7 @@ BOOL rdp_read_share_control_header(rdpRdp* rdp, wStream* s, UINT16* tpktLength,
WLog_Print(rdp->log, WLOG_DEBUG,
"[Flow control PDU] type=%s, tpktLength=%" PRIuz ", remainingLength=%" PRIuz,
pdu_type_to_str(*type, buffer, sizeof(buffer)), tpktLength ? *tpktLength : 0,
- *remainingLength);
+ remainingLength ? *remainingLength : 0);
return TRUE;
}
@@ -2259,7 +2259,7 @@ rdpRdp* rdp_new(rdpContext* context)
/* Keep a backup copy of settings for later comparisons */
if (!rdp_set_backup_settings(rdp))
- return FALSE;
+ goto fail;
rdp->settings->instance = context->instance;
diff --git a/libfreerdp/core/security.c b/libfreerdp/core/security.c
index 653bf0a..96cf00b 100644
--- a/libfreerdp/core/security.c
+++ b/libfreerdp/core/security.c
@@ -592,6 +592,7 @@ static void fips_expand_key_bits(const BYTE* in, size_t in_len, BYTE* out, size_
}
else
{
+ WINPR_ASSERT(p + 1 < sizeof(buf));
/* c is accumulator */
BYTE c = (BYTE)(buf[p] << r) & 0xFF;
c |= buf[p + 1] >> (8 - r);
diff --git a/libfreerdp/core/smartcardlogon.c b/libfreerdp/core/smartcardlogon.c
index d5907cf..f3f5581 100644
--- a/libfreerdp/core/smartcardlogon.c
+++ b/libfreerdp/core/smartcardlogon.c
@@ -222,11 +222,14 @@ static BOOL set_info_certificate(SmartcardCertInfo* cert, BYTE* certBytes, DWORD
return FALSE;
}
- if (userFilter && cert->userHint && strcmp(cert->userHint, userFilter) != 0)
+ if (userFilter && (!cert->upn || (strcmp(cert->upn, userFilter) != 0)))
{
- WLog_DBG(TAG, "discarding non matching cert by user %s@%s", cert->userHint,
- cert->domainHint);
- return FALSE;
+ if (cert->userHint && strcmp(cert->userHint, userFilter) != 0)
+ {
+ WLog_DBG(TAG, "discarding non matching cert by user %s@%s", cert->userHint,
+ cert->domainHint);
+ return FALSE;
+ }
}
if (domainFilter && cert->domainHint && strcmp(cert->domainHint, domainFilter) != 0)
diff --git a/libfreerdp/core/test/CMakeLists.txt b/libfreerdp/core/test/CMakeLists.txt
index 3e0a652..ebd8fef 100644
--- a/libfreerdp/core/test/CMakeLists.txt
+++ b/libfreerdp/core/test/CMakeLists.txt
@@ -9,8 +9,9 @@ set(${MODULE_PREFIX}_TESTS
TestStreamDump.c
TestSettings.c)
-set(${MODULE_PREFIX}_FUZZERS
- TestFuzzCryptoCertificateDataSetPEM.c)
+set(FUZZERS
+ TestFuzzCryptoCertificateDataSetPEM.c
+)
if(WITH_SAMPLE AND WITH_SERVER AND NOT WIN32)
add_definitions(-DCMAKE_EXECUTABLE_SUFFIX="${CMAKE_EXECUTABLE_SUFFIX}")
@@ -32,16 +33,8 @@ add_definitions(-DTESTING_SRC_DIRECTORY="${PROJECT_SOURCE_DIR}")
target_link_libraries(${MODULE_NAME} freerdp winpr freerdp-client)
-if (BUILD_FUZZERS)
- foreach(test ${${MODULE_PREFIX}_FUZZERS})
- get_filename_component(TestName ${test} NAME_WE)
- add_executable(${TestName} ${test})
- target_link_libraries(${TestName} freerdp winpr freerdp-client fuzzer_config)
- add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
- set_target_properties(${TestName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
- add_dependencies(fuzzers ${TestName})
- endforeach()
-endif (BUILD_FUZZERS)
+include (AddFuzzerTest)
+add_fuzzer_test("${FUZZERS}" "freerdp winpr")
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
diff --git a/libfreerdp/core/test/settings_property_lists.h b/libfreerdp/core/test/settings_property_lists.h
index fb280e6..d966242 100644
--- a/libfreerdp/core/test/settings_property_lists.h
+++ b/libfreerdp/core/test/settings_property_lists.h
@@ -19,6 +19,7 @@ static const size_t bool_list_indices[] = {
FreeRDP_AutoDenyCertificate,
FreeRDP_AutoLogonEnabled,
FreeRDP_AutoReconnectionEnabled,
+ FreeRDP_AutoReconnectionPacketSupported,
FreeRDP_BitmapCacheEnabled,
FreeRDP_BitmapCachePersistEnabled,
FreeRDP_BitmapCacheV3Enabled,
@@ -68,6 +69,7 @@ static const size_t bool_list_indices[] = {
FreeRDP_GatewayHttpExtAuthSspiNtlm,
FreeRDP_GatewayHttpTransport,
FreeRDP_GatewayHttpUseWebsockets,
+ FreeRDP_GatewayIgnoreRedirectionPolicy,
FreeRDP_GatewayRpcTransport,
FreeRDP_GatewayUdpTransport,
FreeRDP_GatewayUseSameCredentials,
diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c
index e4cc570..a2a899b 100644
--- a/libfreerdp/core/transport.c
+++ b/libfreerdp/core/transport.c
@@ -197,8 +197,6 @@ static BOOL transport_default_attach(rdpTransport* transport, int sockfd)
if (!socketBio)
goto fail;
-
- BIO_set_fd(socketBio, sockfd, BIO_CLOSE);
}
bufferedBio = BIO_new(BIO_s_buffered_socket());
@@ -206,8 +204,18 @@ static BOOL transport_default_attach(rdpTransport* transport, int sockfd)
goto fail;
if (socketBio)
+ {
bufferedBio = BIO_push(bufferedBio, socketBio);
- WINPR_ASSERT(bufferedBio);
+ if (!bufferedBio)
+ goto fail;
+
+ /* Attach the socket only when this function can no longer fail.
+ * This ensures solid ownership:
+ * - if this function fails, the caller is responsible to clean up
+ * - if this function is successful, the caller MUST NOT close the socket any more.
+ */
+ BIO_set_fd(socketBio, sockfd, BIO_CLOSE);
+ }
transport->frontBio = bufferedBio;
return TRUE;
fail:
diff --git a/libfreerdp/core/transport.h b/libfreerdp/core/transport.h
index 8b5c5c6..912fffd 100644
--- a/libfreerdp/core/transport.h
+++ b/libfreerdp/core/transport.h
@@ -58,6 +58,21 @@ FREERDP_LOCAL wStream* transport_send_stream_init(rdpTransport* transport, size_
FREERDP_LOCAL BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port,
DWORD timeout);
FREERDP_LOCAL BOOL transport_connect_childsession(rdpTransport* transport);
+
+/**! \brief Attach a socket to the transport layer
+ *
+ * The ownership of the socket provided by \b sockfd is taken if and only if the function is
+ * successful. In such a case the caller must no longer close or otherwise use the socket. If the
+ * function fails it is up to the caller to close the socket.
+ *
+ * The implementation can be overridden by
+ * transport_set_io_callbacks(rdpTransportIo::TransportAttach)
+ *
+ * \param transport The transport instance to attach the socket to
+ * \param sockfd The socket to attach to the transport
+ *
+ * \return \b TRUE in case of success, \b FALSE otherwise.
+ */
FREERDP_LOCAL BOOL transport_attach(rdpTransport* transport, int sockfd);
FREERDP_LOCAL BOOL transport_disconnect(rdpTransport* transport);
FREERDP_LOCAL BOOL transport_connect_rdp(rdpTransport* transport);
diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c
index db8ddef..cfc0abc 100644
--- a/libfreerdp/core/update.c
+++ b/libfreerdp/core/update.c
@@ -3322,6 +3322,10 @@ BOOL update_begin_paint(rdpUpdate* update)
WINPR_ASSERT(update->context);
+ BOOL rc = IFCALLRESULT(TRUE, update->BeginPaint, update->context);
+ if (!rc)
+ WLog_WARN(TAG, "BeginPaint call failed");
+
/* Reset the invalid regions, we start a new frame here. */
rdpGdi* gdi = update->context->gdi;
WINPR_ASSERT(gdi);
@@ -3335,10 +3339,6 @@ BOOL update_begin_paint(rdpUpdate* update)
hwnd->ninvalid = 0;
}
- BOOL rc = IFCALLRESULT(TRUE, update->BeginPaint, update->context);
- if (!rc)
- WLog_WARN(TAG, "BeginPaint call failed");
-
return rc;
}
diff --git a/libfreerdp/core/utils.c b/libfreerdp/core/utils.c
index 1bcb090..f414611 100644
--- a/libfreerdp/core/utils.c
+++ b/libfreerdp/core/utils.c
@@ -25,6 +25,8 @@
#include <winpr/assert.h>
#include <freerdp/freerdp.h>
+#include <freerdp/channels/cliprdr.h>
+#include <freerdp/channels/rdpdr.h>
#include <freerdp/log.h>
#define TAG FREERDP_TAG("core.gateway.utils")
@@ -299,3 +301,182 @@ const char* utils_is_vsock(const char* hostname)
return &hostname[sizeof(vsock)];
return NULL;
}
+
+static BOOL remove_rdpdr_type(rdpSettings* settings, UINT32 type)
+{
+ RDPDR_DEVICE* printer = NULL;
+ do
+ {
+ printer = freerdp_device_collection_find_type(settings, type);
+ freerdp_device_collection_del(settings, printer);
+ freerdp_device_free(printer);
+ } while (printer);
+ return TRUE;
+}
+
+static BOOL disable_clipboard(rdpSettings* settings)
+{
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard, FALSE))
+ return FALSE;
+ freerdp_static_channel_collection_del(settings, CLIPRDR_SVC_CHANNEL_NAME);
+ return TRUE;
+}
+
+static BOOL disable_drive(rdpSettings* settings)
+{
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectDrives, FALSE))
+ return FALSE;
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectHomeDrive, FALSE))
+ return FALSE;
+
+ return remove_rdpdr_type(settings, RDPDR_DTYP_FILESYSTEM);
+}
+
+static BOOL disable_printers(rdpSettings* settings)
+{
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectPrinters, FALSE))
+ return FALSE;
+
+ return remove_rdpdr_type(settings, RDPDR_DTYP_PRINT);
+}
+
+static BOOL disable_port(rdpSettings* settings)
+{
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectParallelPorts, FALSE))
+ return FALSE;
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectSerialPorts, FALSE))
+ return FALSE;
+ if (!remove_rdpdr_type(settings, RDPDR_DTYP_SERIAL))
+ return FALSE;
+ return remove_rdpdr_type(settings, RDPDR_DTYP_PARALLEL);
+}
+
+static BOOL disable_pnp(rdpSettings* settings)
+{
+ // TODO(akallabeth): [MS-RDPEPNP] related stuff is disabled.
+ return TRUE;
+}
+
+static BOOL apply_gw_policy(rdpContext* context)
+{
+ WINPR_ASSERT(context);
+ return utils_reload_channels(context);
+}
+
+BOOL utils_apply_gateway_policy(wLog* log, rdpContext* context, UINT32 flags, const char* module)
+{
+ WINPR_ASSERT(log);
+ WINPR_ASSERT(context);
+
+ rdpSettings* settings = context->settings;
+ WINPR_ASSERT(settings);
+
+ if (flags & HTTP_TUNNEL_REDIR_ENABLE_ALL)
+ {
+ WLog_Print(log, WLOG_DEBUG, "[%s] policy allows all redirections", module);
+ }
+ else if (freerdp_settings_get_bool(settings, FreeRDP_GatewayIgnoreRedirectionPolicy))
+ {
+ char buffer[128] = { 0 };
+ WLog_Print(log, WLOG_INFO, "[%s] policy ignored on user request %s", module,
+ utils_redir_flags_to_string(flags, buffer, sizeof(buffer)));
+ }
+ else if (flags & HTTP_TUNNEL_REDIR_DISABLE_ALL)
+ {
+ WLog_Print(log, WLOG_INFO, "[%s] policy denies all redirections", module);
+ if (!disable_drive(settings))
+ return FALSE;
+ if (!disable_printers(settings))
+ return FALSE;
+ if (!disable_clipboard(settings))
+ return FALSE;
+ if (!disable_port(settings))
+ return FALSE;
+ if (!disable_pnp(settings))
+ return FALSE;
+ if (!apply_gw_policy(context))
+ return FALSE;
+ }
+ else
+ {
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_DRIVE)
+ {
+ WLog_Print(log, WLOG_INFO, "[%s] policy denies drive redirections", module);
+ if (!disable_drive(settings))
+ return FALSE;
+ }
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_PRINTER)
+ {
+ WLog_Print(log, WLOG_INFO, "[%s] policy denies printer redirections", module);
+ if (!disable_printers(settings))
+ return FALSE;
+ }
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_PORT)
+ {
+ WLog_Print(log, WLOG_INFO, "[%s] policy denies port redirections", module);
+ if (!disable_port(settings))
+ return FALSE;
+ }
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD)
+ {
+ WLog_Print(log, WLOG_INFO, "[%s] policy denies clipboard redirections", module);
+ if (!disable_clipboard(settings))
+ return FALSE;
+ }
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_PNP)
+ {
+ WLog_Print(log, WLOG_INFO, "[%s] policy denies PNP redirections", module);
+ if (!disable_pnp(settings))
+ return FALSE;
+ }
+ if (flags != 0)
+ {
+ if (!apply_gw_policy(context))
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+char* utils_redir_flags_to_string(UINT32 flags, char* buffer, size_t size)
+{
+ winpr_str_append("{", buffer, size, "");
+ if (flags & HTTP_TUNNEL_REDIR_ENABLE_ALL)
+ winpr_str_append("ENABLE_ALL", buffer, size, "|");
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_ALL)
+ winpr_str_append("DISABLE_ALL", buffer, size, "|");
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_DRIVE)
+ winpr_str_append("DISABLE_DRIVE", buffer, size, "|");
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_PRINTER)
+ winpr_str_append("DISABLE_PRINTER", buffer, size, "|");
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_PORT)
+ winpr_str_append("DISABLE_PORT", buffer, size, "|");
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD)
+ winpr_str_append("DISABLE_CLIPBOARD", buffer, size, "|");
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_PNP)
+ winpr_str_append("DISABLE_PNP", buffer, size, "|");
+
+ char fbuffer[16] = { 0 };
+ _snprintf(fbuffer, sizeof(fbuffer), "[0x%08" PRIx32 "]", flags);
+
+ winpr_str_append(fbuffer, buffer, size, " ");
+ winpr_str_append("{", buffer, size, "}");
+ return buffer;
+}
+
+BOOL utils_reload_channels(rdpContext* context)
+{
+ WINPR_ASSERT(context);
+
+ freerdp_channels_disconnect(context->channels, context->instance);
+ freerdp_channels_close(context->channels, context->instance);
+ freerdp_channels_free(context->channels);
+ context->channels = freerdp_channels_new(context->instance);
+ WINPR_ASSERT(context->channels);
+
+ BOOL rc = TRUE;
+ IFCALLRET(context->instance->LoadChannels, rc, context->instance);
+ if (rc)
+ return freerdp_channels_pre_connect(context->channels, context->instance) == CHANNEL_RC_OK;
+ return rc;
+}
diff --git a/libfreerdp/core/utils.h b/libfreerdp/core/utils.h
index 87fa272..54a7856 100644
--- a/libfreerdp/core/utils.h
+++ b/libfreerdp/core/utils.h
@@ -24,6 +24,15 @@
#include <winpr/winpr.h>
#include <freerdp/freerdp.h>
+/* HTTP tunnel redir flags. */
+#define HTTP_TUNNEL_REDIR_ENABLE_ALL 0x80000000
+#define HTTP_TUNNEL_REDIR_DISABLE_ALL 0x40000000
+#define HTTP_TUNNEL_REDIR_DISABLE_DRIVE 0x1
+#define HTTP_TUNNEL_REDIR_DISABLE_PRINTER 0x2
+#define HTTP_TUNNEL_REDIR_DISABLE_PORT 0x4
+#define HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD 0x8
+#define HTTP_TUNNEL_REDIR_DISABLE_PNP 0x10
+
typedef enum
{
AUTH_SUCCESS,
@@ -47,4 +56,9 @@ BOOL utils_str_copy(const char* value, char** dst);
const char* utils_is_vsock(const char* hostname);
+BOOL utils_apply_gateway_policy(wLog* log, rdpContext* context, UINT32 flags, const char* module);
+char* utils_redir_flags_to_string(UINT32 flags, char* buffer, size_t size);
+
+BOOL utils_reload_channels(rdpContext* context);
+
#endif /* FREERDP_LIB_CORE_UTILS_H */