Backport several CVE fixes
It fixes CVE-2026-64624, CVE-2026-67289, CVE-2026-67299 and CVE-2026-68580. Resolves: RHEL-213171, RHEL-222788, RHEL-223001, RHEL-223611 Co-authored-by: Ondrej Holy <oholy@redhat.com>
This commit is contained in:
parent
f7a0cd9c5c
commit
41b92eb28a
37
channels-audin-limit-FramesPerPacket.patch
Normal file
37
channels-audin-limit-FramesPerPacket.patch
Normal file
@ -0,0 +1,37 @@
|
||||
From 97e9d90528690f6973398c9d7e4f8da52145f669 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Sun, 12 Jul 2026 17:37:48 +0200
|
||||
Subject: [PATCH] [channels,audin] limit FramesPerPacket
|
||||
|
||||
---
|
||||
channels/audin/client/audin_main.c | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c
|
||||
index 332aef9da..186e356cd 100644
|
||||
--- a/channels/audin/client/audin_main.c
|
||||
+++ b/channels/audin/client/audin_main.c
|
||||
@@ -488,7 +488,6 @@ static UINT audin_process_open(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* cal
|
||||
Stream_Read_UINT32(s, initialFormat);
|
||||
WLog_Print(audin->log, WLOG_DEBUG, "FramesPerPacket=%" PRIu32 " initialFormat=%" PRIu32 "",
|
||||
FramesPerPacket, initialFormat);
|
||||
- audin->FramesPerPacket = FramesPerPacket;
|
||||
|
||||
if (initialFormat >= callback->formats_count)
|
||||
{
|
||||
@@ -496,6 +496,15 @@ static UINT audin_process_open(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* cal
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
+ /* The RDP protocol field allows UINT32_MAX, but most backend API use INT32 as input parameter
|
||||
+ * or do some math with it, so ensure that the value does not exceed reasonable limits */
|
||||
+ if (FramesPerPacket >= INT32_MAX)
|
||||
+ {
|
||||
+ WLog_Print(audin->log, WLOG_ERROR, "invalid frames per packet %" PRIu32, FramesPerPacket);
|
||||
+ return ERROR_INVALID_DATA;
|
||||
+ }
|
||||
+
|
||||
+ audin->FramesPerPacket = FramesPerPacket;
|
||||
audin->format = &callback->formats[initialFormat];
|
||||
|
||||
if (!audin_open_device(audin, callback))
|
||||
65
client-common-deactivate-cli-parsing-in-rdp-files.patch
Normal file
65
client-common-deactivate-cli-parsing-in-rdp-files.patch
Normal file
@ -0,0 +1,65 @@
|
||||
From 20a3489c23763f94d31dcf8fd7ed880e07cbb2e8 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Thu, 2 Jul 2026 10:21:54 +0200
|
||||
Subject: [PATCH] [client,common] deactivate cli parsing in RDP files
|
||||
|
||||
This feature was uncodumented and might have unintended side effects.
|
||||
Deactivate it by default and (for the time being) keep an option to
|
||||
enable it at compile time.
|
||||
---
|
||||
client/common/CMakeLists.txt | 5 +++++
|
||||
client/common/file.c | 4 ++++
|
||||
2 files changed, 9 insertions(+)
|
||||
|
||||
diff --git a/client/common/CMakeLists.txt b/client/common/CMakeLists.txt
|
||||
index b465a6311..7bc7cf083 100644
|
||||
--- a/client/common/CMakeLists.txt
|
||||
+++ b/client/common/CMakeLists.txt
|
||||
@@ -85,6 +85,11 @@ if (WITH_DEBUG_SYMBOLS AND MSVC AND BUILD_SHARED_LIBS)
|
||||
install(FILES ${CMAKE_PDB_BINARY_DIR}/${OUTPUT_FILENAME}.pdb DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT symbols)
|
||||
endif()
|
||||
|
||||
+option(WITH_EMBEDDED_CLI_IN_RDP_FILES "[dangrous] allow embedded cli arguments in rdp files" OFF)
|
||||
+if(WITH_EMBEDDED_CLI_IN_RDP_FILES)
|
||||
+ add_compile_definitions(WITH_EMBEDDED_CLI_IN_RDP_FILES)
|
||||
+endif()
|
||||
+
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Common")
|
||||
|
||||
if(BUILD_TESTING)
|
||||
diff --git a/client/common/file.c b/client/common/file.c
|
||||
index b56fe6f06..bff94bad0 100644
|
||||
--- a/client/common/file.c
|
||||
+++ b/client/common/file.c
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <winpr/file.h>
|
||||
|
||||
+
|
||||
#include <freerdp/client/file.h>
|
||||
#include <freerdp/client/cmdline.h>
|
||||
|
||||
@@ -661,6 +662,7 @@ static BOOL trim_strings(rdpFile* file)
|
||||
return FALSE;
|
||||
if (!trim(&file->KdcProxyName))
|
||||
return FALSE;
|
||||
+
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -721,6 +723,7 @@ BOOL freerdp_client_parse_rdp_file_buffer_ex(rdpFile* file, const BYTE* buffer,
|
||||
if (freerdp_client_parse_rdp_file_add_line(file, line, index) == -1)
|
||||
goto fail;
|
||||
|
||||
+#if defined(WITH_EMBEDDED_CLI_IN_RDP_FILES)
|
||||
if (beg[0] == '/')
|
||||
{
|
||||
if (!freerdp_client_parse_rdp_file_option(file, line, index))
|
||||
@@ -728,6 +731,7 @@ BOOL freerdp_client_parse_rdp_file_buffer_ex(rdpFile* file, const BYTE* buffer,
|
||||
|
||||
goto next_line; /* FreeRDP option */
|
||||
}
|
||||
+#endif
|
||||
|
||||
d1 = strchr(line, ':');
|
||||
|
||||
37
core-message-fix-update_message_WindowIcon.patch
Normal file
37
core-message-fix-update_message_WindowIcon.patch
Normal file
@ -0,0 +1,37 @@
|
||||
From 9397fbeed4b2862ae68f9556950af415163c9398 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Tue, 7 Jul 2026 12:58:11 +0200
|
||||
Subject: [PATCH] [core,message] fix update_message_WindowIcon
|
||||
|
||||
---
|
||||
libfreerdp/core/message.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libfreerdp/core/message.c b/libfreerdp/core/message.c
|
||||
index 7af29e94d..1ab0d4e4e 100644
|
||||
--- a/libfreerdp/core/message.c
|
||||
+++ b/libfreerdp/core/message.c
|
||||
@@ -1147,18 +1147,21 @@ static BOOL update_message_WindowIcon(rdpContext* context, const WINDOW_ORDER_IN
|
||||
if (!wParam)
|
||||
return FALSE;
|
||||
|
||||
- CopyMemory(wParam, orderInfo, sizeof(WINDOW_ORDER_INFO));
|
||||
+ *wParam = *orderInfo;
|
||||
+
|
||||
lParam = (WINDOW_ICON_ORDER*)calloc(1, sizeof(WINDOW_ICON_ORDER));
|
||||
|
||||
if (!lParam)
|
||||
goto out_fail;
|
||||
|
||||
+ *lParam = *windowIcon;
|
||||
lParam->iconInfo = calloc(1, sizeof(ICON_INFO));
|
||||
|
||||
if (!lParam->iconInfo)
|
||||
goto out_fail;
|
||||
|
||||
- CopyMemory(lParam, windowIcon, sizeof(WINDOW_ICON_ORDER));
|
||||
+ *lParam->iconInfo = *windowIcon->iconInfo;
|
||||
+
|
||||
WLog_VRB(TAG, "update_message_WindowIcon");
|
||||
|
||||
if (windowIcon->iconInfo->cbBitsColor > 0)
|
||||
163
core-redirection-check-redirection-values-for-validity.patch
Normal file
163
core-redirection-check-redirection-values-for-validity.patch
Normal file
@ -0,0 +1,163 @@
|
||||
From cdabc78fc50a5a1859faebc1e41a3dfbbd007341 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Thu, 9 Jul 2026 08:34:24 +0200
|
||||
Subject: [PATCH] [core,redirection] check redirection values for validity
|
||||
|
||||
Add some basic validity checks for data provided by server.
|
||||
---
|
||||
libfreerdp/core/redirection.c | 25 ++++++++++++++++++++-----
|
||||
libfreerdp/core/utils.c | 33 +++++++++++++++++++++++++++++++++
|
||||
libfreerdp/core/utils.h | 2 ++
|
||||
3 files changed, 55 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c
|
||||
index 59c6dbcee..b4b222eb2 100644
|
||||
--- a/libfreerdp/core/redirection.c
|
||||
+++ b/libfreerdp/core/redirection.c
|
||||
@@ -406,6 +406,8 @@ static int rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
{
|
||||
if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddress), 80))
|
||||
return -1;
|
||||
+ if (!utils_is_valid_ip(redirection->TargetNetAddress))
|
||||
+ return -1;
|
||||
}
|
||||
|
||||
if (redirection->flags & LB_LOAD_BALANCE_INFO)
|
||||
@@ -419,13 +421,17 @@ static int rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
if (!rdp_redirection_read_data(LB_LOAD_BALANCE_INFO, s, &redirection->LoadBalanceInfoLength,
|
||||
&redirection->LoadBalanceInfo))
|
||||
return -1;
|
||||
+ if (!winpr_str_is_valid_urlN((const char*)redirection->LoadBalanceInfo,
|
||||
+ redirection->LoadBalanceInfoLength))
|
||||
+ return -1;
|
||||
}
|
||||
|
||||
if (redirection->flags & LB_USERNAME)
|
||||
{
|
||||
if (!rdp_redirection_read_unicode_string(s, &(redirection->Username), 512))
|
||||
return -1;
|
||||
-
|
||||
+ if (winpr_str_has_newlines(redirection->Username))
|
||||
+ return -1;
|
||||
WLog_DBG(TAG, "Username: %s", redirection->Username);
|
||||
}
|
||||
|
||||
@@ -433,7 +439,8 @@ static int rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
{
|
||||
if (!rdp_redirection_read_unicode_string(s, &(redirection->Domain), 52))
|
||||
return -1;
|
||||
-
|
||||
+ if (winpr_str_has_newlines(redirection->Domain))
|
||||
+ return -1;
|
||||
WLog_DBG(TAG, "Domain: %s", redirection->Domain);
|
||||
}
|
||||
|
||||
@@ -484,7 +491,8 @@ static int rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
{
|
||||
if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetFQDN), 512))
|
||||
return -1;
|
||||
-
|
||||
+ if (!winpr_str_is_valid_url(redirection->TargetFQDN))
|
||||
+ return -1;
|
||||
WLog_DBG(TAG, "TargetFQDN: %s", redirection->TargetFQDN);
|
||||
}
|
||||
|
||||
@@ -492,7 +500,8 @@ static int rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
{
|
||||
if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetBiosName), 32))
|
||||
return -1;
|
||||
-
|
||||
+ if (!winpr_str_is_valid_url(redirection->TargetNetBiosName))
|
||||
+ return -1;
|
||||
WLog_DBG(TAG, "TargetNetBiosName: %s", redirection->TargetNetBiosName);
|
||||
}
|
||||
|
||||
@@ -501,6 +510,8 @@ static int rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
if (!rdp_redirection_read_data(LB_CLIENT_TSV_URL, s, &redirection->TsvUrlLength,
|
||||
&redirection->TsvUrl))
|
||||
return -1;
|
||||
+ if (!winpr_str_is_valid_urlN((const char*)redirection->TsvUrl, redirection->TsvUrlLength))
|
||||
+ return -1;
|
||||
}
|
||||
|
||||
if (redirection->flags & LB_REDIRECTION_GUID)
|
||||
@@ -541,7 +552,8 @@ static int rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
{
|
||||
if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddresses[i]), 80))
|
||||
return -1;
|
||||
-
|
||||
+ if (!utils_is_valid_ip(redirection->TargetNetAddresses[i]))
|
||||
+ return -1;
|
||||
WLog_DBG(TAG, "TargetNetAddresses[%" PRIuz "]: %s", i,
|
||||
redirection->TargetNetAddresses[i]);
|
||||
}
|
||||
@@ -569,7 +581,10 @@ int rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, wStream* s)
|
||||
status = rdp_recv_server_redirection_pdu(rdp, s);
|
||||
|
||||
if (status < 0)
|
||||
+ {
|
||||
+ WLog_ERR(TAG, "redirection packet invalid, aborting");
|
||||
return status;
|
||||
+ }
|
||||
|
||||
if (Stream_GetRemainingLength(s) >= 1)
|
||||
{
|
||||
diff --git a/libfreerdp/core/utils.c b/libfreerdp/core/utils.c
|
||||
index 139c1a433..102819915 100644
|
||||
--- a/libfreerdp/core/utils.c
|
||||
+++ b/libfreerdp/core/utils.c
|
||||
@@ -22,6 +22,16 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
+#include <string.h>
|
||||
+
|
||||
+#ifdef _WIN32
|
||||
+#include <ws2tcpip.h>
|
||||
+#else
|
||||
+#include <sys/socket.h>
|
||||
+#include <netinet/in.h>
|
||||
+#include <arpa/inet.h>
|
||||
+#endif
|
||||
+
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
@@ -65,3 +75,26 @@ BOOL utils_str_is_empty(const char* str)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
+
|
||||
+static BOOL isValidIPv4(const char* ipAddress)
|
||||
+{
|
||||
+ struct sockaddr_in sa;
|
||||
+ int result;
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
|
||||
+ return result != 0;
|
||||
+}
|
||||
+
|
||||
+static BOOL isValidIPv6(const char* ipAddress)
|
||||
+{
|
||||
+ struct sockaddr_in6 sa;
|
||||
+ int result;
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ result = inet_pton(AF_INET6, ipAddress, &(sa.sin6_addr));
|
||||
+ return result != 0;
|
||||
+}
|
||||
+
|
||||
+BOOL utils_is_valid_ip(const char* ipAddress)
|
||||
+{
|
||||
+ return isValidIPv4(ipAddress) || isValidIPv6(ipAddress);
|
||||
+}
|
||||
diff --git a/libfreerdp/core/utils.h b/libfreerdp/core/utils.h
|
||||
index 432951812..4b150c416 100644
|
||||
--- a/libfreerdp/core/utils.h
|
||||
+++ b/libfreerdp/core/utils.h
|
||||
@@ -30,4 +30,6 @@ BOOL utils_abort_connect(rdpContext* context);
|
||||
BOOL utils_str_is_empty(const char* str);
|
||||
BOOL utils_str_copy(const char* value, char** dst);
|
||||
|
||||
+FREERDP_LOCAL BOOL utils_is_valid_ip(const char* ipAddress);
|
||||
+
|
||||
#endif /* FREERDP_LIB_CORE_UTILS_H */
|
||||
34
core-redirection-relax-checks.patch
Normal file
34
core-redirection-relax-checks.patch
Normal file
@ -0,0 +1,34 @@
|
||||
From b3cff65a1adbbdeda478f035218eeadc72ca0032 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Tue, 14 Jul 2026 12:30:27 +0200
|
||||
Subject: [PATCH] [core,redirection] relax checks
|
||||
|
||||
* TsvUrl is opaque, do not assume any format
|
||||
* LoadBalanceInfo is opaque, do not assume any format
|
||||
---
|
||||
libfreerdp/core/redirection.c | 5 -----
|
||||
1 file changed, 5 deletions(-)
|
||||
|
||||
diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c
|
||||
index b4b222eb2..773496603 100644
|
||||
--- a/libfreerdp/core/redirection.c
|
||||
+++ b/libfreerdp/core/redirection.c
|
||||
@@ -421,9 +421,6 @@ static int rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
if (!rdp_redirection_read_data(LB_LOAD_BALANCE_INFO, s, &redirection->LoadBalanceInfoLength,
|
||||
&redirection->LoadBalanceInfo))
|
||||
return -1;
|
||||
- if (!winpr_str_is_valid_urlN((const char*)redirection->LoadBalanceInfo,
|
||||
- redirection->LoadBalanceInfoLength))
|
||||
- return -1;
|
||||
}
|
||||
|
||||
if (redirection->flags & LB_USERNAME)
|
||||
@@ -510,8 +507,6 @@ static int rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
if (!rdp_redirection_read_data(LB_CLIENT_TSV_URL, s, &redirection->TsvUrlLength,
|
||||
&redirection->TsvUrl))
|
||||
return -1;
|
||||
- if (!winpr_str_is_valid_urlN((const char*)redirection->TsvUrl, redirection->TsvUrlLength))
|
||||
- return -1;
|
||||
}
|
||||
|
||||
if (redirection->flags & LB_REDIRECTION_GUID)
|
||||
27
freerdp.spec
27
freerdp.spec
@ -27,7 +27,7 @@
|
||||
|
||||
Name: freerdp
|
||||
Version: 2.11.7
|
||||
Release: 11%{?dist}
|
||||
Release: 12%{?dist}
|
||||
Epoch: 2
|
||||
Summary: Free implementation of the Remote Desktop Protocol (RDP)
|
||||
License: ASL 2.0
|
||||
@ -198,6 +198,26 @@ Patch: client-x11-fix-deadlock-on-output-expose.patch
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/4a065a941ae134a0433d1497c03b3c3eb91b9f85
|
||||
Patch: codec-planar-fix-bounds-checks.patch
|
||||
|
||||
# CVE-2026-68580
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/3bf07d4470bbe42faf4ef8197c8fe1b6b759b00f
|
||||
Patch: channels-audin-limit-FramesPerPacket.patch
|
||||
|
||||
# CVE-2026-67299
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/172edbddd24f33033b9eafae6ea1fff0641a24f4
|
||||
Patch: core-message-fix-update_message_WindowIcon.patch
|
||||
|
||||
# CVE-2026-64624
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/22c5deea52404f51a13276b3abda44e1e60704cf
|
||||
Patch: client-common-deactivate-cli-parsing-in-rdp-files.patch
|
||||
|
||||
# CVE-2026-67289
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/f163b2d2080d922cb725800781f43f16bc2882c0
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/ab5905cbada0d34cf85ffd32881cacaf8275744f
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/1db16b4b121a1221c0454f7d223096cac87bf244
|
||||
Patch: winpr-crt-add-functions-to-test-string.patch
|
||||
Patch: core-redirection-check-redirection-values-for-validity.patch
|
||||
Patch: core-redirection-relax-checks.patch
|
||||
|
||||
BuildRequires: gcc
|
||||
BuildRequires: gcc-c++
|
||||
BuildRequires: alsa-lib-devel
|
||||
@ -455,6 +475,11 @@ find %{buildroot} -name "*.a" -delete
|
||||
%{_libdir}/pkgconfig/winpr-tools2.pc
|
||||
|
||||
%changelog
|
||||
* Mon Aug 17 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2:2.11.7-12
|
||||
- Backport several CVE fixes (CVE-2026-64624, CVE-2026-67289, CVE-2026-67299,
|
||||
CVE-2026-68580)
|
||||
Resolves: RHEL-213171, RHEL-222788, RHEL-223001, RHEL-223611
|
||||
|
||||
* Wed Jun 24 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2:2.11.7-11
|
||||
- Fix incorrect bounds checks in planar codec (CVE-2026-45700)
|
||||
Resolves: RHEL-186992
|
||||
|
||||
266
winpr-crt-add-functions-to-test-string.patch
Normal file
266
winpr-crt-add-functions-to-test-string.patch
Normal file
@ -0,0 +1,266 @@
|
||||
From a7a47bc0bdab723b674fb05f51e93ae007ed6412 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Thu, 9 Jul 2026 08:34:23 +0200
|
||||
Subject: [PATCH] [winpr,crt] add functions to test string
|
||||
|
||||
* winpr_str_has_newlines to check for newlines in a string
|
||||
* winpr_str_is_valid_url and winpr_str_is_valid_urlN to check if a
|
||||
string is a valid url
|
||||
---
|
||||
winpr/include/winpr/string.h | 5 ++
|
||||
winpr/libwinpr/crt/CMakeLists.txt | 8 +++
|
||||
winpr/libwinpr/crt/string.c | 96 ++++++++++++++++++++++++++++
|
||||
winpr/libwinpr/crt/test/TestString.c | 82 ++++++++++++++++++++++++
|
||||
4 files changed, 191 insertions(+)
|
||||
|
||||
diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h
|
||||
index bb98dffdc..7de9f934f 100644
|
||||
--- a/winpr/include/winpr/string.h
|
||||
+++ b/winpr/include/winpr/string.h
|
||||
@@ -31,6 +31,11 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
+ WINPR_API BOOL winpr_str_is_valid_url(const char* str);
|
||||
+ WINPR_API BOOL winpr_str_is_valid_urlN(const char* str, size_t len);
|
||||
+ WINPR_API BOOL winpr_str_has_newlines(const char* str);
|
||||
+
|
||||
+
|
||||
WINPR_API BOOL winpr_str_append(const char* what, char* buffer, size_t size,
|
||||
const char* separator);
|
||||
|
||||
diff --git a/winpr/libwinpr/crt/CMakeLists.txt b/winpr/libwinpr/crt/CMakeLists.txt
|
||||
index 5ee4bbd1e..538e74dcf 100644
|
||||
--- a/winpr/libwinpr/crt/CMakeLists.txt
|
||||
+++ b/winpr/libwinpr/crt/CMakeLists.txt
|
||||
@@ -22,6 +22,14 @@ set (CRT_FILES alignment.c
|
||||
unicode.c
|
||||
string.c)
|
||||
|
||||
+include(CheckSymbolExists)
|
||||
+check_symbol_exists(regcomp regex.h WINPR_HAVE_REGCOMP)
|
||||
+check_symbol_exists(regexec regex.h WINPR_HAVE_REGEXEC)
|
||||
+check_symbol_exists(regfree regex.h WINPR_HAVE_REGFREE)
|
||||
+if(WINPR_HAVE_REGCOMP AND WINPR_HAVE_REGEXEC AND WINPR_HAVE_REGFREE)
|
||||
+ winpr_definition_add(-DWINPR_HAVE_REGCOMP)
|
||||
+endif()
|
||||
+
|
||||
if (NOT WITH_ICU)
|
||||
set (CRT_FILES ${CRT_FILES}
|
||||
utf.c
|
||||
diff --git a/winpr/libwinpr/crt/string.c b/winpr/libwinpr/crt/string.c
|
||||
index 6596b42f5..465b8d133 100644
|
||||
--- a/winpr/libwinpr/crt/string.c
|
||||
+++ b/winpr/libwinpr/crt/string.c
|
||||
@@ -29,11 +29,71 @@
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/endian.h>
|
||||
|
||||
+#if defined(WINPR_HAVE_REGCOMP)
|
||||
+#include <regex.h>
|
||||
+#endif
|
||||
+
|
||||
/* String Manipulation (CRT): http://msdn.microsoft.com/en-us/library/f0151s4x.aspx */
|
||||
|
||||
#include "../log.h"
|
||||
#define TAG WINPR_TAG("crt")
|
||||
|
||||
+BOOL winpr_str_is_valid_urlN(const char* str, size_t len)
|
||||
+{
|
||||
+ if (!str || (len == 0))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ char* url = strndup(str, len);
|
||||
+ if (!url)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ const BOOL rc = winpr_str_is_valid_url(url);
|
||||
+ free(url);
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+#if defined(_WIN32)
|
||||
+#include <shlwapi.h>
|
||||
+
|
||||
+BOOL winpr_str_is_valid_url(const char* str)
|
||||
+{
|
||||
+ if (!str)
|
||||
+ return FALSE;
|
||||
+ return PathIsURLA(str);
|
||||
+}
|
||||
+
|
||||
+#elif defined(WINPR_HAVE_REGCOMP)
|
||||
+BOOL winpr_str_is_valid_url(const char* str)
|
||||
+{
|
||||
+ regex_t regex;
|
||||
+ const char pattern[] = "^([a-z]+://)?([a-zA-Z0-9.-]+)(:[0-9]+)?(/[a-zA-Z0-9./?=&%-]*)?$";
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!str)
|
||||
+ return FALSE;
|
||||
+ memset(®ex, 0, sizeof(regex));
|
||||
+
|
||||
+ ret = regcomp(®ex, pattern, REG_EXTENDED);
|
||||
+ if (ret)
|
||||
+ {
|
||||
+ printf("Could not compile regex\n");
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ ret = regexec(®ex, str, 0, NULL, 0);
|
||||
+ regfree(®ex);
|
||||
+ return ret == 0;
|
||||
+}
|
||||
+
|
||||
+#else
|
||||
+BOOL winpr_str_is_valid_url(const char* str)
|
||||
+{
|
||||
+ WINPR_UNUSED(str);
|
||||
+ WLog_WARN(TAG, "URL validation not supported by your build, not performing check.");
|
||||
+ return TRUE;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
BOOL winpr_str_append(const char* what, char* buffer, size_t size, const char* separator)
|
||||
{
|
||||
const size_t used = strnlen(buffer, size);
|
||||
@@ -636,3 +696,39 @@ INT64 GetLine(char** lineptr, size_t* size, FILE* stream)
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
+
|
||||
+BOOL winpr_str_has_newlines(const char* str)
|
||||
+{
|
||||
+ if (!str)
|
||||
+ return FALSE;
|
||||
+ do
|
||||
+ {
|
||||
+ char c = *str++;
|
||||
+ switch (c)
|
||||
+ {
|
||||
+ case '\r':
|
||||
+ case '\n':
|
||||
+ case 0x0b: /* VT vertical tab */
|
||||
+ case 0x0c: /* FF form feed */
|
||||
+ case (char)0x85: /* NEL next line */
|
||||
+ return TRUE;
|
||||
+ case 0x20:
|
||||
+ {
|
||||
+ switch (*str)
|
||||
+ {
|
||||
+ case 0x28: /* LS line separator */
|
||||
+ case 0x29: /* PS paragraph separator */
|
||||
+ return TRUE;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case '\0':
|
||||
+ return FALSE;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ } while (1);
|
||||
+}
|
||||
diff --git a/winpr/libwinpr/crt/test/TestString.c b/winpr/libwinpr/crt/test/TestString.c
|
||||
index df154fe1c..bca470bdd 100644
|
||||
--- a/winpr/libwinpr/crt/test/TestString.c
|
||||
+++ b/winpr/libwinpr/crt/test/TestString.c
|
||||
@@ -27,6 +27,79 @@ static WCHAR testDelimiter[] = { '\r', '\n', '\0' };
|
||||
|
||||
#define testDelimiter_Length ((sizeof(testDelimiter) / sizeof(WCHAR)) - 1)
|
||||
|
||||
+static BOOL test_valid_url(void)
|
||||
+{
|
||||
+ struct test_t
|
||||
+ {
|
||||
+ char* string;
|
||||
+ size_t len;
|
||||
+ BOOL isUrl;
|
||||
+ };
|
||||
+
|
||||
+ static const struct test_t tests[] = { { "foo.bar.blabla", 15, TRUE },
|
||||
+ { "somehostname", 12, TRUE },
|
||||
+ { "somehostname:1234", 17, TRUE },
|
||||
+ { "tsv://somehostname", 18, TRUE },
|
||||
+ { "tsv://somehostname/path/foo/gaga", 32, TRUE },
|
||||
+ { "tsv://somehostname:1234", 23, TRUE },
|
||||
+ { "tsv://somehostname:1234/path/foo", 33, TRUE },
|
||||
+ { "lala\rgaga\n", 12, FALSE },
|
||||
+ { "192.168.0.1", 11, TRUE },
|
||||
+ //{ "192.168.0.1:1234", 16, FALSE },
|
||||
+ //{ "192.168.0.1:1234/foo/", 21, FALSE },
|
||||
+ { "192.168.0.1/bar/foo/", 20, TRUE },
|
||||
+ { "[::1]", 5, FALSE },
|
||||
+ { "[::1]:1234", 8, FALSE },
|
||||
+ { "[2001:db8:3333:4444:5555:6666:7777:8888]", 40,
|
||||
+ FALSE },
|
||||
+ { "[2001:db8::1]", 13, FALSE } };
|
||||
+ BOOL rc = TRUE;
|
||||
+ for (size_t x = 0; x < ARRAYSIZE(tests); x++)
|
||||
+ {
|
||||
+ const struct test_t* cur = &tests[x];
|
||||
+
|
||||
+ const BOOL rc1 = winpr_str_is_valid_url(cur->string);
|
||||
+ const BOOL rc2 = winpr_str_is_valid_urlN(cur->string, cur->len);
|
||||
+
|
||||
+#if defined(WINPR_HAVE_REGCOMP) || defined(WITH_URIPARSER)
|
||||
+ if (rc1 != rc2)
|
||||
+ rc = FALSE;
|
||||
+ if (rc1 != cur->isUrl)
|
||||
+ rc = FALSE;
|
||||
+#else
|
||||
+ fprintf(stderr, "[%s] TODO: !defined(WINPR_HAVE_REGCOMP) && !defined(WITH_URIPARSER)\n",
|
||||
+ __func__);
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+static BOOL test_newline(void)
|
||||
+{
|
||||
+ struct test_t
|
||||
+ {
|
||||
+ char* string;
|
||||
+ size_t len;
|
||||
+ BOOL hasNewlines;
|
||||
+ };
|
||||
+
|
||||
+ const struct test_t tests[] = { { "foo.bar.blabla", 15, FALSE },
|
||||
+ { "somehostname", 12, FALSE },
|
||||
+ { "lala\rgaga\n", 13, TRUE } };
|
||||
+
|
||||
+ for (size_t x = 0; x < ARRAYSIZE(tests); x++)
|
||||
+ {
|
||||
+ const struct test_t* cur = &tests[x];
|
||||
+
|
||||
+ const BOOL rc1 = winpr_str_has_newlines(cur->string);
|
||||
+ if (rc1 != cur->hasNewlines)
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
int TestString(int argc, char* argv[])
|
||||
{
|
||||
WCHAR* p;
|
||||
@@ -34,6 +107,15 @@ int TestString(int argc, char* argv[])
|
||||
size_t length;
|
||||
WCHAR* context;
|
||||
|
||||
+ WINPR_UNUSED(argc);
|
||||
+ WINPR_UNUSED(argv);
|
||||
+
|
||||
+ if (!test_valid_url())
|
||||
+ return -1;
|
||||
+
|
||||
+ if (!test_newline())
|
||||
+ return -1;
|
||||
+
|
||||
#ifdef __BIG_ENDIAN__
|
||||
/* Be sure that we always use LE encoded string */
|
||||
ByteSwapUnicode(testStringW, testStringW_Length);
|
||||
Loading…
Reference in New Issue
Block a user