Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,29 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP Proxy Server
#
# Copyright 2021 Armin Novak <armin.novak@thincast.com>
# Copyright 2021 Thincast Technologies GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(PROXY_APP_SRCS freerdp_proxy.c)
set(APP_NAME "freerdp-proxy")
addtargetwithresourcefile(${APP_NAME} TRUE "${FREERDP_VERSION}" PROXY_APP_SRCS)
target_link_libraries(${APP_NAME} ${MODULE_NAME})
installwithrpath(TARGETS ${APP_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT server)
set_property(TARGET ${APP_NAME} PROPERTY FOLDER "Server/proxy")
generate_and_install_freerdp_man_from_template(${APP_NAME} "1" "${FREERDP_API_VERSION}")

View File

@@ -0,0 +1,85 @@
.de URL
\\$2 \(laURL: \\$1 \(ra\\$3
..
.if \n[.g] .mso www.tmac
.TH @MANPAGE_NAME@ 1 2023-12-14 "@FREERDP_VERSION_FULL@" "FreeRDP"
.SH NAME
@MANPAGE_NAME@ \- A server binary allowing MITM proxying of RDP connections
.SH SYNOPSIS
.B @MANPAGE_NAME@
[\fB-h\fP]
[\fB--help\fP]
[\fB--buildconfig\fP]
[\fB--dump-config\fP \fB<config file>\fP]
[\fB-v\fP]
[\fB--version\fP]
[\fB<config file>\fP]
.SH DESCRIPTION
.B @MANPAGE_NAME@
can be used to proxy a RDP connection between a target server and connecting clients.
Possible usage scenarios are:
.IP Proxying
Connect outdated/insecure RDP servers from behind a (more secure) proxy
.IP Analysis
Allow detailed protocol analysis of (many) unknown protocol features (channels)
.IP Inspection
MITM proxy for session inspection and recording
.SH OPTIONS
.IP -h,--help
Display a help text explaining usage.
.IP --buildconfig
Print the build configuration of the proxy and exit.
.IP -v,--version
Print the version of the proxy and exit.
.IP --dump-config \fB<config-ini-file>\fP
Dump a template configuration to \fB<config-ini-file>\fP
.IP \fB<config-ini-file>\fP
Start the proxy with settings read from \fB<config-ini-file>\fP
.SH WARNING
The proxy does not support authentication out of the box but acts simply as intermediary.
Only \fBRDP\fP and \fBTLS\fP security modes are supported, \fBNLA\fP will fail for connections to the proxy.
To implement authentication a \fBproxy-module\fP can be implemented that can authenticate against some backend
and map connecting users and credentials to target server users and credentials.
.SH EXAMPLES
@MANPAGE_NAME@ /some/config/file
@MANPAGE_NAME@ --dump-config /some/config/file
.SH PREPARATIONS
1. generate certificates for proxy
\fBwinpr-makecert -rdp -path . proxy\fP
2. generate proxy configuration
\fB@MANPAGE_NAME@ --dump-config proxy.ini\fP
3. edit configurartion and:
* provide (preferably absolute) paths for \fBCertificateFile\fP and \fBPrivateKeyFile\fP generated previously
* remove the \fBCertificateContents\fP and \fBPrivateKeyContents\fP
* Adjust the \fB[Server]\fP settings \fBHost\fP and \fBPort\fP to bind a specific port on a network interface
* Adjust the \fB[Target]\fP \fBHost\fP and \fBPort\fP settings to the \fBRDP\fP target server
* Adjust (or remove if unuse) the \fBPlugins\fP settings
3. start proxy server
\fB@MANPAGE_NAME@ proxy.ini\fP
.SH EXIT STATUS
.TP
.B 0
Successful program execution.
.TP
.B 1
Otherwise.
.SH SEE ALSO
wlog(7)
.SH AUTHOR
FreeRDP <team@freerdp.com>

View File

@@ -0,0 +1,193 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP Proxy Server
*
* Copyright 2019 Mati Shabtay <matishabtay@gmail.com>
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
* Copyright 2019 Idan Freiberg <speidy@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/collections.h>
#include <freerdp/version.h>
#include <freerdp/freerdp.h>
#include <freerdp/server/proxy/proxy_server.h>
#include <freerdp/server/proxy/proxy_log.h>
#include <stdlib.h>
#include <signal.h>
#define TAG PROXY_TAG("server")
static proxyServer* server = nullptr;
#if defined(_WIN32)
WINPR_ATTR_NODISCARD
static const char* strsignal(int signum)
{
switch (signum)
{
case SIGINT:
return "SIGINT";
case SIGTERM:
return "SIGTERM";
default:
return "UNKNOWN";
}
}
#endif
// NOLINTBEGIN(bugprone-signal-handler,cert-msc54-cpp,cert-sig30-c)
static void cleanup_handler(int signum)
{
// NOLINTNEXTLINE(concurrency-mt-unsafe)
WLog_INFO(TAG, "caught signal %s [%d], starting cleanup...", strsignal(signum), signum);
WLog_INFO(TAG, "stopping all connections.");
pf_server_stop(server);
}
// NOLINTEND(bugprone-signal-handler,cert-msc54-cpp,cert-sig30-c)
static void pf_server_register_signal_handlers(void)
{
(void)signal(SIGINT, cleanup_handler);
(void)signal(SIGTERM, cleanup_handler);
#ifndef _WIN32
(void)signal(SIGQUIT, cleanup_handler);
(void)signal(SIGKILL, cleanup_handler);
#endif
}
static int usage(const char* app)
{
printf("Usage:\n");
printf("%s -h Display this help text.\n", app);
printf("%s --help Display this help text.\n", app);
printf("%s --buildconfig Print the build configuration.\n", app);
printf("%s <config ini file> Start the proxy with <config.ini>\n", app);
printf("%s --dump-config <config ini file> Create a template <config.ini>\n", app);
printf("%s -v Print out binary version.\n", app);
printf("%s --version Print out binary version.\n", app);
return 0;
}
WINPR_ATTR_NODISCARD
static int version(const char* app)
{
printf("%s version %s", app, freerdp_get_version_string());
return 0;
}
WINPR_ATTR_NODISCARD
static int buildconfig(WINPR_ATTR_UNUSED const char* app)
{
printf("This is FreeRDP version %s (%s)\n", FREERDP_VERSION_FULL, FREERDP_GIT_REVISION);
printf("%s", freerdp_get_build_config());
return 0;
}
int main(int argc, char* argv[])
{
int status = -1;
pf_server_register_signal_handlers();
WLog_INFO(TAG, "freerdp-proxy version info:");
WLog_INFO(TAG, "\tFreeRDP version: %s", FREERDP_VERSION_FULL);
WLog_INFO(TAG, "\tGit commit: %s", FREERDP_GIT_REVISION);
WLog_DBG(TAG, "\tBuild config: %s", freerdp_get_build_config());
if (argc < 2)
{
status = usage(argv[0]);
goto fail;
}
{
const char* arg = argv[1];
if (_stricmp(arg, "-h") == 0)
{
status = usage(argv[0]);
goto fail;
}
else if (_stricmp(arg, "--help") == 0)
{
status = usage(argv[0]);
goto fail;
}
else if (_stricmp(arg, "--buildconfig") == 0)
{
status = buildconfig(argv[0]);
goto fail;
}
else if (_stricmp(arg, "--dump-config") == 0)
{
if (argc != 3)
{
status = usage(argv[0]);
goto fail;
}
status = pf_server_config_dump(argv[2]) ? 0 : -1;
goto fail;
}
else if (_stricmp(arg, "-v") == 0)
{
status = version(argv[0]);
goto fail;
}
else if (_stricmp(arg, "--version") == 0)
{
status = version(argv[0]);
goto fail;
}
}
{
const char* config_path = argv[1];
if (argc != 2)
{
status = usage(argv[0]);
goto fail;
}
{
proxyConfig* config = pf_server_config_load_file(config_path);
if (!config)
goto fail;
pf_server_config_print(config);
server = pf_server_new(config);
pf_server_config_free(config);
}
}
if (!server)
goto fail;
if (!pf_server_start(server))
goto fail;
if (!pf_server_run(server))
goto fail;
status = 0;
fail:
pf_server_free(server);
return status;
}