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,30 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP Shadow Server cmake build script
#
# Copyright 2025 Armin Novak <anoavk@thincast.com>
# Copyright 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(MODULE_NAME "freerdp-shadow-cli")
set(SRCS shadow.c)
addtargetwithresourcefile(${MODULE_NAME} TRUE "${FREERDP_VERSION}" SRCS)
list(APPEND LIBS freerdp-shadow-subsystem freerdp-shadow freerdp winpr)
target_link_libraries(${MODULE_NAME} PRIVATE ${LIBS})
installwithrpath(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT server)
generate_and_install_freerdp_man_from_template(${MODULE_NAME} "1" "${FREERDP_API_VERSION}")

View File

@@ -0,0 +1,93 @@
.de URL
\\$2 \(laURL: \\$1 \(ra\\$3
..
.if \n[.g] .mso www.tmac
.TH @MANPAGE_NAME@ 1 2017-01-12 "@FREERDP_VERSION_FULL@" "FreeRDP"
.SH NAME
@MANPAGE_NAME@ \- A utility for sharing a X display via RDP.
.SH SYNOPSIS
.B @MANPAGE_NAME@
[\fB/port:\fP\fI<port number>\fP]
[\fB/ipc-socket:\fP\fI<ipc-socket>\fP]
[\fB/monitors:\fP\fI<0,1,2,...>\fP]
[\fB/rect:\fP\fI<x,y,w,h>\fP]
[\fB+auth\fP]
[\fB-may-view\fP]
[\fB-may-interact\fP]
[\fB/sec:\fP\fI<rdp|tls|nla|ext>\fP]
[\fB-sec-rdp\fP]
[\fB-sec-tls\fP]
[\fB-sec-nla\fP]
[\fB-sec-ext\fP]
[\fB/sam-file:\fP\fI<file>\fP]
[\fB/version\fP]
[\fB/help\fP]
.SH DESCRIPTION
.B @MANPAGE_NAME@
can be used to share a running X display like with VNC but by using the RDP
instead. It is also possibly to share only parts (rect) of the display.
.SH OPTIONS
.IP /ipc-socket:<ipc-socket>
If this option is set an ipc socket with the path \fIipc-socket\fP is used
instead of a TCP socket.
.IP /port:<port>
Set the port to use. Default is 3389.
This option is ignored if ipc-socket is used.
.IP /monitors:<1,2,3,...>
Select the monitor(s) to share.
.IP /rect:<x,y,w,h>
Select rectangle within monitor to share.
.IP -auth
Disable authentication. If authentication is enabled PAM is used with the
X11 subsystem. Running as root is not necessary, however if run as user only
the same user that started @MANPAGE_NAME@ can authenticate.
.br
\fBWarning\fP: If authentication is disabled \fIeveryone\fP can connect.
.IP -may-view
Clients may view without prompt.
.IP -may-interact
Clients may interact without prompt.
.IP /sec:<rdp|tls|nla|ext>
Force a specific protocol security
.IP -sec-rdp
Disable RDP security (default:on)
.IP -sec-tls
Disable TLS protocol security (default:on)
.IP -sec-nla
Disable NLA protocol security (default:on)
.IP +sec-ext
Use NLA extended protocol security (default:off)
.IP /sam-file:<file>
NTLM SAM file for NLA authentication
.IP /version
Print the version and exit.
.IP /help
Print the help and exit.
.SH USAGE
#MANPAGE_NAME@ - start the shadow server on port 3389 with NLA security, SAM database at /etc/winpr/SAM
.br
@MANPAGE_NAME@ /sam-file:SAM.db - same as above, but a custom SAM database provided as argument
.br
@MANPAGE_NAME@ -sec-nla - start the shadow server on port 3380 with TLS/NLA security. This allows authenticating against PAM with unix users. Be aware that the password is transmitted plain text like with basic HTTP auth
.SH EXAMPLES
@MANPAGE_NAME@ /port:12345
When run as user within a X session (for example from an xterm) a socket on
12345 is opened and the current display is shared via RDP.
.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,199 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@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 <freerdp/config.h>
#include <winpr/crt.h>
#include <winpr/ssl.h>
#include <winpr/path.h>
#include <winpr/cmdline.h>
#include <winpr/winsock.h>
#include <winpr/tools/makecert.h>
#include <freerdp/server/shadow.h>
#include <freerdp/settings.h>
#include <freerdp/log.h>
#define TAG SERVER_TAG("shadow")
int main(int argc, char** argv)
{
int status = 0;
DWORD dwExitCode = 0;
COMMAND_LINE_ARGUMENT_A shadow_args[] = {
{ "log-filters", COMMAND_LINE_VALUE_REQUIRED, "<tag>:<level>[,<tag>:<level>[,...]]",
nullptr, nullptr, -1, nullptr, "Set logger filters, see wLog(7) for details" },
{ "log-level", COMMAND_LINE_VALUE_REQUIRED, "[OFF|FATAL|ERROR|WARN|INFO|DEBUG|TRACE]",
nullptr, nullptr, -1, nullptr, "Set the default log level, see wLog(7) for details" },
{ "port", COMMAND_LINE_VALUE_REQUIRED, "<number>", nullptr, nullptr, -1, nullptr,
"Server port" },
{ "ipc-socket", COMMAND_LINE_VALUE_REQUIRED, "<ipc-socket>", nullptr, nullptr, -1, nullptr,
"Server IPC socket" },
{ "bind-address", COMMAND_LINE_VALUE_REQUIRED, "<bind-address>[,<another address>, ...]",
nullptr, nullptr, -1, nullptr,
"An address to bind to. Use '[<ipv6>]' for IPv6 addresses, e.g. '[::1]' for "
"localhost" },
{ "server-side-cursor", COMMAND_LINE_VALUE_BOOL, nullptr, nullptr, nullptr, -1, nullptr,
"hide mouse cursor in RDP client." },
{ "monitors", COMMAND_LINE_VALUE_OPTIONAL, "<0,1,2...>", nullptr, nullptr, -1, nullptr,
"Select or list monitors" },
{ "max-connections", COMMAND_LINE_VALUE_REQUIRED, "<number>", nullptr, nullptr, -1, nullptr,
"maximum connections allowed to server, 0 to deactivate" },
{ "mouse-relative", COMMAND_LINE_VALUE_BOOL, nullptr, nullptr, nullptr, -1, nullptr,
"enable support for relative mouse events" },
{ "rect", COMMAND_LINE_VALUE_REQUIRED, "<x,y,w,h>", nullptr, nullptr, -1, nullptr,
"Select rectangle within monitor to share" },
{ "auth", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"Clients must authenticate" },
{ "remote-guard", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueFalse, nullptr, -1, nullptr,
"Remote credential guard" },
{ "restricted-admin", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"Restricted Admin" },
{ "vmconnect", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueFalse,
nullptr, -1, nullptr, "Hyper-V console server (bind on vsock://1)" },
{ "may-view", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"Clients may view without prompt" },
{ "may-interact", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"Clients may interact without prompt" },
{ "sec", COMMAND_LINE_VALUE_REQUIRED, "<rdp|tls|nla|ext>", nullptr, nullptr, -1, nullptr,
"force specific protocol security" },
{ "sec-rdp", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"rdp protocol security" },
{ "sec-tls", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"tls protocol security" },
{ "sec-nla", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"nla protocol security" },
{ "sec-ext", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueFalse, nullptr, -1, nullptr,
"nla extended protocol security" },
{ "sam-file", COMMAND_LINE_VALUE_REQUIRED, "<file>", nullptr, nullptr, -1, nullptr,
"NTLM SAM file for NLA authentication" },
{ "keytab", COMMAND_LINE_VALUE_REQUIRED, "<file>", nullptr, nullptr, -1, nullptr,
"Kerberos keytab file for NLA authentication" },
{ "ccache", COMMAND_LINE_VALUE_REQUIRED, "<file>", nullptr, nullptr, -1, nullptr,
"Kerberos host ccache file for NLA authentication" },
{ "tls-secrets-file", COMMAND_LINE_VALUE_REQUIRED, "<file>", nullptr, nullptr, -1, nullptr,
"file where tls secrets shall be stored" },
{ "nsc", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"Allow NSC codec" },
{ "rfx", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"Allow RFX surface bits" },
{ "gfx", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"Allow GFX pipeline" },
{ "gfx-progressive", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"Allow GFX progressive codec" },
{ "gfx-rfx", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"Allow GFX RFX codec" },
{ "gfx-planar", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"Allow GFX planar codec" },
{ "gfx-avc420", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"Allow GFX AVC420 codec" },
{ "gfx-avc444", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
"Allow GFX AVC444 codec" },
{ "bitmap-compat", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueFalse, nullptr, -1, nullptr,
"Limit BitmapUpdate to 1 rectangle (fixes broken windows 11 24H2 clients)" },
{ "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, nullptr, nullptr,
nullptr, -1, nullptr, "Print version" },
{ "buildconfig", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_BUILDCONFIG, nullptr, nullptr,
nullptr, -1, nullptr, "Print the build configuration" },
{ "help", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_HELP, nullptr, nullptr, nullptr, -1,
"?", "Print help" },
{ nullptr, 0, nullptr, nullptr, nullptr, -1, nullptr, nullptr }
};
shadow_subsystem_set_entry_builtin(nullptr);
rdpShadowServer* server = shadow_server_new();
if (!server)
{
status = -1;
WLog_ERR(TAG, "Server new failed");
goto fail;
}
{
rdpSettings* settings = server->settings;
WINPR_ASSERT(settings);
if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, TRUE))
goto fail;
/* By default allow all GFX modes.
* This can be changed with command line flags [+|-]gfx-CODEC
*/
if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32) ||
!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxImageCodec, TRUE) ||
!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR3) ||
!freerdp_settings_set_bool(settings, FreeRDP_GfxH264, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444v2, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_GfxProgressive, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_GfxProgressiveV2, TRUE))
goto fail;
if (!freerdp_settings_set_bool(settings, FreeRDP_MouseUseRelativeMove, FALSE) ||
!freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent, FALSE))
goto fail;
}
if ((status = shadow_server_parse_command_line(server, argc, argv, shadow_args)) < 0)
{
status = shadow_server_command_line_status_print(server, argc, argv, status, shadow_args);
goto fail;
}
if ((status = shadow_server_init(server)) < 0)
{
WLog_ERR(TAG, "Server initialization failed.");
goto fail;
}
if ((status = shadow_server_start(server)) < 0)
{
WLog_ERR(TAG, "Failed to start server.");
goto fail;
}
#ifdef _WIN32
{
MSG msg = WINPR_C_ARRAY_INIT;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#endif
(void)WaitForSingleObject(server->thread, INFINITE);
if (!GetExitCodeThread(server->thread, &dwExitCode))
status = -1;
else
status = (int)dwExitCode;
fail:
shadow_server_uninit(server);
shadow_server_free(server);
return status;
}