[client,win32] implement connection to child session

Under windows you can connect to a child session by requesting a named pipe to
the local server, and then do some RDP on this named pipe.
The protocol is like for /vmconnect with CredSSP, then Nego and then the "normal"
workflow for a connection. For CredSSP we force the usage of NTLM for the Negociate
SSPI, and the credentials are empty.
This commit is contained in:
David Fort 2023-09-22 22:13:54 +02:00 committed by Martin Fleisz
parent 0638c382f9
commit 3c18a9980f
16 changed files with 482 additions and 69 deletions

View File

@ -1971,7 +1971,7 @@ static int parse_gfx_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_
WINPR_ASSERT(settings); WINPR_ASSERT(settings);
WINPR_ASSERT(arg); WINPR_ASSERT(arg);
if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE)) if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, (arg->Value != NULL)))
return COMMAND_LINE_ERROR; return COMMAND_LINE_ERROR;
if (arg->Value) if (arg->Value)
@ -3794,6 +3794,21 @@ static int freerdp_client_settings_parse_command_line_arguments_int(rdpSettings*
settings->SendPreconnectionPdu = TRUE; settings->SendPreconnectionPdu = TRUE;
settings->PreconnectionId = (UINT32)val; settings->PreconnectionId = (UINT32)val;
} }
#ifdef _WIN32
CommandLineSwitchCase(arg, "connect-child-session")
{
if (!freerdp_settings_set_string(settings, FreeRDP_AuthenticationServiceClass,
"vs-debug") ||
!freerdp_settings_set_string(settings, FreeRDP_ServerHostname, "localhost") ||
!freerdp_settings_set_string(settings, FreeRDP_AuthenticationPackageList, "ntlm") ||
!freerdp_settings_set_bool(settings, FreeRDP_NegotiateSecurityLayer, FALSE) ||
!freerdp_settings_set_bool(settings, FreeRDP_VmConnectMode, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_ConnectChildSession, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, TRUE) ||
!freerdp_settings_set_uint32(settings, FreeRDP_AuthenticationLevel, 0))
return COMMAND_LINE_ERROR_MEMORY;
}
#endif
CommandLineSwitchCase(arg, "sec") CommandLineSwitchCase(arg, "sec")
{ {
size_t count = 0, x; size_t count = 0, x;

View File

@ -111,6 +111,10 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
"[DEPRECATED, use /cert:name:<name>] Certificate name" }, "[DEPRECATED, use /cert:name:<name>] Certificate name" },
{ "cert-tofu", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, { "cert-tofu", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL,
"[DEPRECATED, use /cert:tofu] Automatically accept certificate on first connect" }, "[DEPRECATED, use /cert:tofu] Automatically accept certificate on first connect" },
#endif
#ifdef _WIN32
{ "connect-child-session", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, "",
"connect to child session (win32)" },
#endif #endif
{ "client-build-number", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL, { "client-build-number", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL,
"Client Build Number sent to server (influences smartcard behaviour, see [MS-RDPESC])" }, "Client Build Number sent to server (influences smartcard behaviour, see [MS-RDPESC])" },

View File

@ -485,12 +485,12 @@ extern "C"
/* ThreadingFlags */ /* ThreadingFlags */
#define THREADING_FLAGS_DISABLE_THREADS 0x00000001 #define THREADING_FLAGS_DISABLE_THREADS 0x00000001
/* Settings */ /* Settings */
/** /**
* FreeRDP Settings Ids * FreeRDP Settings Ids
* This is generated with a script parsing the rdpSettings data structure * This is generated with a script parsing the rdpSettings data structure
*/ */
#define FreeRDP_instance (0) #define FreeRDP_instance (0)
#define FreeRDP_ServerMode (16) #define FreeRDP_ServerMode (16)
@ -737,6 +737,7 @@ extern "C"
#define FreeRDP_OldLicenseBehaviour (1606) #define FreeRDP_OldLicenseBehaviour (1606)
#define FreeRDP_MouseUseRelativeMove (1607) #define FreeRDP_MouseUseRelativeMove (1607)
#define FreeRDP_UseCommonStdioCallbacks (1608) #define FreeRDP_UseCommonStdioCallbacks (1608)
#define FreeRDP_ConnectChildSession (1609)
#define FreeRDP_ComputerName (1664) #define FreeRDP_ComputerName (1664)
#define FreeRDP_ConnectionFile (1728) #define FreeRDP_ConnectionFile (1728)
#define FreeRDP_AssistanceFile (1729) #define FreeRDP_AssistanceFile (1729)
@ -941,9 +942,9 @@ extern "C"
#define FreeRDP_Floatbar (5196) #define FreeRDP_Floatbar (5196)
#define FreeRDP_TcpConnectTimeout (5197) #define FreeRDP_TcpConnectTimeout (5197)
/** /**
* FreeRDP Settings Data Structure * FreeRDP Settings Data Structure
*/ */
#define FreeRDP_Settings_StableAPI_MAX 5312 #define FreeRDP_Settings_StableAPI_MAX 5312
struct rdp_settings struct rdp_settings
@ -1297,15 +1298,16 @@ extern "C"
UINT64 padding1601[1601 - 1560]; /* 1560 */ UINT64 padding1601[1601 - 1560]; /* 1560 */
/* Miscellaneous */ /* Miscellaneous */
ALIGN64 BOOL SoftwareGdi; /* 1601 */ ALIGN64 BOOL SoftwareGdi; /* 1601 */
ALIGN64 BOOL LocalConnection; /* 1602 */ ALIGN64 BOOL LocalConnection; /* 1602 */
ALIGN64 BOOL AuthenticationOnly; /* 1603 */ ALIGN64 BOOL AuthenticationOnly; /* 1603 */
ALIGN64 BOOL CredentialsFromStdin; /* 1604 */ ALIGN64 BOOL CredentialsFromStdin; /* 1604 */
ALIGN64 BOOL UnmapButtons; /* 1605 */ ALIGN64 BOOL UnmapButtons; /* 1605 */
ALIGN64 BOOL OldLicenseBehaviour; /* 1606 */ ALIGN64 BOOL OldLicenseBehaviour; /* 1606 */
ALIGN64 BOOL MouseUseRelativeMove; /* 1607 */ ALIGN64 BOOL MouseUseRelativeMove; /* 1607 */
ALIGN64 BOOL UseCommonStdioCallbacks; /* 1608 */ ALIGN64 BOOL UseCommonStdioCallbacks; /* 1608 */
UINT64 padding1664[1664 - 1609]; /* 1609 */ ALIGN64 BOOL ConnectChildSession; /* 1609 */
UINT64 padding1664[1664 - 1610]; /* 1610 */
/* Names */ /* Names */
ALIGN64 char* ComputerName; /* 1664 */ ALIGN64 char* ComputerName; /* 1664 */
@ -1339,31 +1341,31 @@ extern "C"
*/ */
/* Gateway */ /* Gateway */
ALIGN64 UINT32 GatewayUsageMethod; /* 1984 */ ALIGN64 UINT32 GatewayUsageMethod; /* 1984 */
ALIGN64 UINT32 GatewayPort; /* 1985 */ ALIGN64 UINT32 GatewayPort; /* 1985 */
ALIGN64 char* GatewayHostname; /* 1986 */ ALIGN64 char* GatewayHostname; /* 1986 */
ALIGN64 char* GatewayUsername; /* 1987 */ ALIGN64 char* GatewayUsername; /* 1987 */
ALIGN64 char* GatewayPassword; /* 1988 */ ALIGN64 char* GatewayPassword; /* 1988 */
ALIGN64 char* GatewayDomain; /* 1989 */ ALIGN64 char* GatewayDomain; /* 1989 */
ALIGN64 UINT32 GatewayCredentialsSource; /* 1990 */ ALIGN64 UINT32 GatewayCredentialsSource; /* 1990 */
ALIGN64 BOOL GatewayUseSameCredentials; /* 1991 */ ALIGN64 BOOL GatewayUseSameCredentials; /* 1991 */
ALIGN64 BOOL GatewayEnabled; /* 1992 */ ALIGN64 BOOL GatewayEnabled; /* 1992 */
ALIGN64 BOOL GatewayBypassLocal; /* 1993 */ ALIGN64 BOOL GatewayBypassLocal; /* 1993 */
ALIGN64 BOOL GatewayRpcTransport; /* 1994 */ ALIGN64 BOOL GatewayRpcTransport; /* 1994 */
ALIGN64 BOOL GatewayHttpTransport; /* 1995 */ ALIGN64 BOOL GatewayHttpTransport; /* 1995 */
ALIGN64 BOOL GatewayUdpTransport; /* 1996 */ ALIGN64 BOOL GatewayUdpTransport; /* 1996 */
ALIGN64 char* GatewayAccessToken; /* 1997 */ ALIGN64 char* GatewayAccessToken; /* 1997 */
ALIGN64 char* GatewayAcceptedCert; /* 1998 */ ALIGN64 char* GatewayAcceptedCert; /* 1998 */
ALIGN64 UINT32 GatewayAcceptedCertLength; /* 1999 */ ALIGN64 UINT32 GatewayAcceptedCertLength; /* 1999 */
ALIGN64 BOOL GatewayHttpUseWebsockets; /* 2000 */ ALIGN64 BOOL GatewayHttpUseWebsockets; /* 2000 */
ALIGN64 BOOL GatewayHttpExtAuthSspiNtlm; /* 2001 */ ALIGN64 BOOL GatewayHttpExtAuthSspiNtlm; /* 2001 */
ALIGN64 char* GatewayHttpExtAuthBearer; /* 2002 */ ALIGN64 char* GatewayHttpExtAuthBearer; /* 2002 */
ALIGN64 char* GatewayUrl; /* 2003 */ ALIGN64 char* GatewayUrl; /* 2003 */
ALIGN64 BOOL GatewayArmTransport; /* 2004 */ ALIGN64 BOOL GatewayArmTransport; /* 2004 */
ALIGN64 char* GatewayAvdWvdEndpointPool; /* 2005 */ ALIGN64 char* GatewayAvdWvdEndpointPool; /* 2005 */
ALIGN64 char* GatewayAvdGeo; /* 2006 */ ALIGN64 char* GatewayAvdGeo; /* 2006 */
ALIGN64 char* GatewayAvdArmpath; /* 2007 */ ALIGN64 char* GatewayAvdArmpath; /* 2007 */
ALIGN64 char* GatewayAvdAadtenantid; /* 2008 */ ALIGN64 char* GatewayAvdAadtenantid; /* 2008 */
ALIGN64 char* GatewayAvdDiagnosticserviceurl; /* 2009 */ ALIGN64 char* GatewayAvdDiagnosticserviceurl; /* 2009 */
ALIGN64 char* GatewayAvdHubdiscoverygeourl; /* 2010 */ ALIGN64 char* GatewayAvdHubdiscoverygeourl; /* 2010 */
ALIGN64 char* GatewayAvdActivityhint; /* 2011 */ ALIGN64 char* GatewayAvdActivityhint; /* 2011 */
@ -1646,7 +1648,7 @@ extern "C"
* Other Redirection * Other Redirection
*/ */
ALIGN64 BOOL RedirectClipboard; /* 4800 */ ALIGN64 BOOL RedirectClipboard; /* 4800 */
ALIGN64 UINT32 ClipboardFeatureMask; /* 4801 */ ALIGN64 UINT32 ClipboardFeatureMask; /* 4801 */
UINT64 padding4928[4928 - 4802]; /* 4802 */ UINT64 padding4928[4928 - 4802]; /* 4802 */

View File

@ -123,6 +123,9 @@ BOOL freerdp_settings_get_bool(const rdpSettings* settings, size_t id)
case FreeRDP_CompressionEnabled: case FreeRDP_CompressionEnabled:
return settings->CompressionEnabled; return settings->CompressionEnabled;
case FreeRDP_ConnectChildSession:
return settings->ConnectChildSession;
case FreeRDP_ConsoleSession: case FreeRDP_ConsoleSession:
return settings->ConsoleSession; return settings->ConsoleSession;
@ -717,6 +720,10 @@ BOOL freerdp_settings_set_bool(rdpSettings* settings, size_t id, BOOL val)
settings->CompressionEnabled = cnv.c; settings->CompressionEnabled = cnv.c;
break; break;
case FreeRDP_ConnectChildSession:
settings->ConnectChildSession = cnv.c;
break;
case FreeRDP_ConsoleSession: case FreeRDP_ConsoleSession:
settings->ConsoleSession = cnv.c; settings->ConsoleSession = cnv.c;
break; break;

View File

@ -56,6 +56,7 @@ static const struct settings_str_entry settings_map[] = {
{ FreeRDP_CertificateCallbackPreferPEM, FREERDP_SETTINGS_TYPE_BOOL, { FreeRDP_CertificateCallbackPreferPEM, FREERDP_SETTINGS_TYPE_BOOL,
"FreeRDP_CertificateCallbackPreferPEM" }, "FreeRDP_CertificateCallbackPreferPEM" },
{ FreeRDP_CompressionEnabled, FREERDP_SETTINGS_TYPE_BOOL, "FreeRDP_CompressionEnabled" }, { FreeRDP_CompressionEnabled, FREERDP_SETTINGS_TYPE_BOOL, "FreeRDP_CompressionEnabled" },
{ FreeRDP_ConnectChildSession, FREERDP_SETTINGS_TYPE_BOOL, "FreeRDP_ConnectChildSession" },
{ FreeRDP_ConsoleSession, FREERDP_SETTINGS_TYPE_BOOL, "FreeRDP_ConsoleSession" }, { FreeRDP_ConsoleSession, FREERDP_SETTINGS_TYPE_BOOL, "FreeRDP_ConsoleSession" },
{ FreeRDP_CredentialsFromStdin, FREERDP_SETTINGS_TYPE_BOOL, "FreeRDP_CredentialsFromStdin" }, { FreeRDP_CredentialsFromStdin, FREERDP_SETTINGS_TYPE_BOOL, "FreeRDP_CredentialsFromStdin" },
{ FreeRDP_DeactivateClientDecoding, FREERDP_SETTINGS_TYPE_BOOL, { FreeRDP_DeactivateClientDecoding, FREERDP_SETTINGS_TYPE_BOOL,

View File

@ -107,6 +107,7 @@ set(${MODULE_PREFIX}_SRCS
multitransport.h multitransport.h
timezone.c timezone.c
timezone.h timezone.h
childsession.c
rdp.c rdp.c
rdp.h rdp.h
tcp.c tcp.c

View File

@ -0,0 +1,340 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Named pipe transport
*
* Copyright 2023 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.
* 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 "tcp.h"
#include <winpr/library.h>
#include <winpr/assert.h>
#include "childsession.h"
#define TAG FREERDP_TAG("childsession")
typedef struct
{
HANDLE hFile;
} WINPR_BIO_NAMED;
static int transport_bio_named_uninit(BIO* bio);
static int transport_bio_named_write(BIO* bio, const 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_WRITE);
DWORD written = 0;
BOOL ret = WriteFile(ptr->hFile, buf, size, &written, NULL);
WLog_VRB(TAG, "transport_bio_named_write(%d)=%d written=%d", size, ret, written);
if (!ret)
return -1;
if (written == 0)
return -1;
return written;
}
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);
DWORD readBytes;
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 (GetLastError() == ERROR_NO_DATA)
BIO_set_flags(bio, (BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ));
return -1;
}
if (readBytes == 0)
{
BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY));
return 0;
}
return readBytes;
}
static int transport_bio_named_puts(BIO* bio, const char* str)
{
WINPR_ASSERT(bio);
WINPR_ASSERT(str);
return transport_bio_named_write(bio, str, strlen(str));
}
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);
}
static long transport_bio_named_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
{
WINPR_ASSERT(bio);
int status = -1;
WINPR_BIO_NAMED* ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
switch (cmd)
{
case BIO_C_SET_SOCKET:
case BIO_C_GET_SOCKET:
return -1;
case BIO_C_GET_EVENT:
if (!BIO_get_init(bio) || !arg2)
return 0;
*((HANDLE*)arg2) = ptr->hFile;
return 1;
case BIO_C_SET_HANDLE:
BIO_set_init(bio, 1);
if (!BIO_get_init(bio) || !arg2)
return 0;
ptr->hFile = (HANDLE)arg2;
return 1;
case BIO_C_SET_NONBLOCK:
{
return 1;
}
case BIO_C_WAIT_READ:
{
int timeout = (int)arg1;
return 1;
}
break;
case BIO_C_WAIT_WRITE:
{
int timeout = (int)arg1;
return 1;
}
break;
default:
break;
}
switch (cmd)
{
case BIO_CTRL_GET_CLOSE:
status = BIO_get_shutdown(bio);
break;
case BIO_CTRL_SET_CLOSE:
BIO_set_shutdown(bio, (int)arg1);
status = 1;
break;
case BIO_CTRL_DUP:
status = 1;
break;
case BIO_CTRL_FLUSH:
status = 1;
break;
default:
status = 0;
break;
}
return status;
}
static int transport_bio_named_uninit(BIO* bio)
{
WINPR_ASSERT(bio);
WINPR_BIO_NAMED* ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
if (ptr && ptr->hFile)
{
CloseHandle(ptr->hFile);
ptr->hFile = NULL;
}
BIO_set_init(bio, 0);
BIO_set_flags(bio, 0);
return 1;
}
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;
BIO_set_data(bio, ptr);
BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
return 1;
}
static int transport_bio_named_free(BIO* bio)
{
WINPR_BIO_NAMED* ptr;
if (!bio)
return 0;
transport_bio_named_uninit(bio);
ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
if (ptr)
{
BIO_set_data(bio, NULL);
free(ptr);
}
return 1;
}
BIO_METHOD* BIO_s_namedpipe(void)
{
static BIO_METHOD* bio_methods = NULL;
if (bio_methods == NULL)
{
if (!(bio_methods = BIO_meth_new(BIO_TYPE_NAMEDPIPE, "NamedPipe")))
return NULL;
BIO_meth_set_write(bio_methods, transport_bio_named_write);
BIO_meth_set_read(bio_methods, transport_bio_named_read);
BIO_meth_set_puts(bio_methods, transport_bio_named_puts);
BIO_meth_set_gets(bio_methods, transport_bio_named_gets);
BIO_meth_set_ctrl(bio_methods, transport_bio_named_ctrl);
BIO_meth_set_create(bio_methods, transport_bio_named_new);
BIO_meth_set_destroy(bio_methods, transport_bio_named_free);
}
return bio_methods;
}
typedef NTSTATUS (*WinStationCreateChildSessionTransportFn)(WCHAR* path, DWORD len);
BOOL createChildSessionTransport(HANDLE* pFile)
{
WINPR_ASSERT(pFile);
HANDLE hModule = NULL;
BOOL ret = FALSE;
*pFile = INVALID_HANDLE_VALUE;
BOOL childEnabled;
if (!WTSIsChildSessionsEnabled(&childEnabled))
{
WLog_ERR(TAG, "error when calling WTSIsChildSessionsEnabled");
goto out;
}
if (!childEnabled)
{
WLog_INFO(TAG, "child sessions aren't enabled");
if (!WTSEnableChildSessions(TRUE))
{
WLog_ERR(TAG, "error when calling WTSEnableChildSessions");
goto out;
}
WLog_INFO(TAG, "successfully enabled child sessions");
}
hModule = LoadLibraryA("winsta.dll");
if (!hModule)
return FALSE;
WCHAR pipePath[0x80] = { 0 };
char pipePathA[0x80] = { 0 };
WinStationCreateChildSessionTransportFn createChildSessionFn =
(WinStationCreateChildSessionTransportFn)GetProcAddress(
hModule, "WinStationCreateChildSessionTransport");
if (!createChildSessionFn)
{
WLog_ERR(TAG, "unable to retrieve WinStationCreateChildSessionTransport function");
goto out;
}
HRESULT hStatus = createChildSessionFn(pipePath, 0x80);
if (!SUCCEEDED(hStatus))
{
WLog_ERR(TAG, "error 0x%x when creating childSessionTransport", hStatus);
goto out;
}
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);
if (f == INVALID_HANDLE_VALUE)
{
WLog_ERR(TAG, "error when connecting to local named pipe");
goto out;
}
*pFile = f;
ret = TRUE;
out:
FreeLibrary(hModule);
return ret;
}
BIO* createChildSessionBio(void)
{
HANDLE f = INVALID_HANDLE_VALUE;
if (!createChildSessionTransport(&f))
return NULL;
BIO* lowLevelBio = BIO_new(BIO_s_namedpipe());
if (!lowLevelBio)
{
CloseHandle(f);
return NULL;
}
BIO_set_handle(lowLevelBio, f);
BIO* bufferedBio = BIO_new(BIO_s_buffered_socket());
if (!bufferedBio)
{
BIO_free_all(lowLevelBio);
return FALSE;
}
bufferedBio = BIO_push(bufferedBio, lowLevelBio);
return bufferedBio;
}

View File

@ -0,0 +1,27 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Connecting to windows child session
*
* Copyright 2023 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.
* 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.
*/
#ifndef FREERDP_LIB_CORE_CHILDSESSION_H
#define FREERDP_LIB_CORE_CHILDSESSION_H
#include <openssl/bio.h>
FREERDP_LOCAL BIO* createChildSessionBio(void);
#endif /* FREERDP_LIB_CORE_CHILDSESSION_H */

View File

@ -393,6 +393,7 @@ BOOL rdp_client_connect(rdpRdp* rdp)
if (!status) if (!status)
return FALSE; return FALSE;
nego_set_childsession_enabled(rdp->nego, settings->ConnectChildSession);
nego_set_send_preconnection_pdu(rdp->nego, settings->SendPreconnectionPdu); nego_set_send_preconnection_pdu(rdp->nego, settings->SendPreconnectionPdu);
nego_set_preconnection_id(rdp->nego, settings->PreconnectionId); nego_set_preconnection_id(rdp->nego, settings->PreconnectionId);
nego_set_preconnection_blob(rdp->nego, settings->PreconnectionBlob); nego_set_preconnection_blob(rdp->nego, settings->PreconnectionBlob);
@ -421,7 +422,6 @@ BOOL rdp_client_connect(rdpRdp* rdp)
if (!freerdp_settings_get_bool(settings, FreeRDP_TransportDumpReplay)) if (!freerdp_settings_get_bool(settings, FreeRDP_TransportDumpReplay))
{ {
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_NEGO)) if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_NEGO))
return FALSE; return FALSE;

View File

@ -62,6 +62,7 @@ struct rdp_nego
BOOL RestrictedAdminModeRequired; BOOL RestrictedAdminModeRequired;
BOOL GatewayEnabled; BOOL GatewayEnabled;
BOOL GatewayBypassLocal; BOOL GatewayBypassLocal;
BOOL ConnectChildSession;
rdpTransport* transport; rdpTransport* transport;
}; };
@ -89,6 +90,7 @@ static const char* protocol_security_string(UINT32 security)
return PROTOCOL_SECURITY_STRINGS[security]; return PROTOCOL_SECURITY_STRINGS[security];
} }
static BOOL nego_tcp_connect(rdpNego* nego);
static BOOL nego_transport_connect(rdpNego* nego); static BOOL nego_transport_connect(rdpNego* nego);
static BOOL nego_transport_disconnect(rdpNego* nego); static BOOL nego_transport_disconnect(rdpNego* nego);
static BOOL nego_security_connect(rdpNego* nego); static BOOL nego_security_connect(rdpNego* nego);
@ -99,31 +101,6 @@ static BOOL nego_process_negotiation_request(rdpNego* nego, wStream* s);
static BOOL nego_process_negotiation_response(rdpNego* nego, wStream* s); static BOOL nego_process_negotiation_response(rdpNego* nego, wStream* s);
static BOOL nego_process_negotiation_failure(rdpNego* nego, wStream* s); static BOOL nego_process_negotiation_failure(rdpNego* nego, wStream* s);
static UINT32 nego_get_next_selected_protocol(rdpNego* nego)
{
WINPR_ASSERT(nego);
if (nego->EnabledProtocols[PROTOCOL_RDSAAD])
return PROTOCOL_RDSAAD;
if (nego->EnabledProtocols[PROTOCOL_RDSTLS])
return PROTOCOL_RDSTLS;
if (nego->EnabledProtocols[PROTOCOL_HYBRID_EX] || nego->EnabledProtocols[PROTOCOL_HYBRID])
return PROTOCOL_HYBRID_EX;
if (nego->EnabledProtocols[PROTOCOL_HYBRID])
return PROTOCOL_HYBRID;
if (nego->EnabledProtocols[PROTOCOL_SSL])
return PROTOCOL_SSL;
if (nego->EnabledProtocols[PROTOCOL_RDP])
return PROTOCOL_RDP;
WLog_ERR(TAG, "Invalid NEGO state 0x%08" PRIx32, nego_get_state(nego));
return 0;
}
/** /**
* Negotiate protocol security and connect. * Negotiate protocol security and connect.
* *
@ -222,6 +199,12 @@ BOOL nego_connect(rdpNego* nego)
return FALSE; return FALSE;
} }
if (!nego_tcp_connect(nego))
{
WLog_ERR(TAG, "Failed to connect");
return FALSE;
}
if (nego->SendPreconnectionPdu) if (nego->SendPreconnectionPdu)
{ {
if (!nego_send_preconnection_pdu(nego)) if (!nego_send_preconnection_pdu(nego))
@ -391,6 +374,10 @@ static BOOL nego_tcp_connect(rdpNego* nego)
TcpConnectTimeout); TcpConnectTimeout);
} }
} }
else if (nego->ConnectChildSession)
{
nego->TcpConnected = transport_connect_childsession(nego->transport);
}
else else
{ {
nego->TcpConnected = nego->TcpConnected =
@ -1661,6 +1648,12 @@ void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdmin
nego->RestrictedAdminModeRequired = RestrictedAdminModeRequired; nego->RestrictedAdminModeRequired = RestrictedAdminModeRequired;
} }
void nego_set_childsession_enabled(rdpNego* nego, BOOL ChildSessionEnabled)
{
WINPR_ASSERT(nego);
nego->ConnectChildSession = ChildSessionEnabled;
}
void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled) void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled)
{ {
nego->GatewayEnabled = GatewayEnabled; nego->GatewayEnabled = GatewayEnabled;

View File

@ -114,6 +114,7 @@ FREERDP_LOCAL BOOL nego_set_target(rdpNego* nego, const char* hostname, UINT16 p
FREERDP_LOCAL void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer); FREERDP_LOCAL void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer);
FREERDP_LOCAL void nego_set_restricted_admin_mode_required(rdpNego* nego, FREERDP_LOCAL void nego_set_restricted_admin_mode_required(rdpNego* nego,
BOOL RestrictedAdminModeRequired); BOOL RestrictedAdminModeRequired);
FREERDP_LOCAL void nego_set_childsession_enabled(rdpNego* nego, BOOL ChildSessionEnabled);
FREERDP_LOCAL void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled); FREERDP_LOCAL void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled);
FREERDP_LOCAL void nego_set_gateway_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal); FREERDP_LOCAL void nego_set_gateway_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal);
FREERDP_LOCAL void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp); FREERDP_LOCAL void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp);

View File

@ -41,6 +41,7 @@
#define BIO_TYPE_TSG 65 #define BIO_TYPE_TSG 65
#define BIO_TYPE_SIMPLE 66 #define BIO_TYPE_SIMPLE 66
#define BIO_TYPE_BUFFERED 67 #define BIO_TYPE_BUFFERED 67
#define BIO_TYPE_NAMEDPIPE 69
#define BIO_C_SET_SOCKET 1101 #define BIO_C_SET_SOCKET 1101
#define BIO_C_GET_SOCKET 1102 #define BIO_C_GET_SOCKET 1102
@ -50,10 +51,12 @@
#define BIO_C_WRITE_BLOCKED 1106 #define BIO_C_WRITE_BLOCKED 1106
#define BIO_C_WAIT_READ 1107 #define BIO_C_WAIT_READ 1107
#define BIO_C_WAIT_WRITE 1108 #define BIO_C_WAIT_WRITE 1108
#define BIO_C_SET_HANDLE 1109
#define BIO_set_socket(b, s, c) BIO_ctrl(b, BIO_C_SET_SOCKET, c, s); #define BIO_set_socket(b, s, c) BIO_ctrl(b, BIO_C_SET_SOCKET, c, s);
#define BIO_get_socket(b, c) BIO_ctrl(b, BIO_C_GET_SOCKET, 0, (char*)c) #define BIO_get_socket(b, c) BIO_ctrl(b, BIO_C_GET_SOCKET, 0, (char*)c)
#define BIO_get_event(b, c) BIO_ctrl(b, BIO_C_GET_EVENT, 0, (char*)c) #define BIO_get_event(b, c) BIO_ctrl(b, BIO_C_GET_EVENT, 0, (char*)c)
#define BIO_set_handle(b, h) BIO_ctrl(b, BIO_C_SET_HANDLE, 0, h)
#define BIO_set_nonblock(b, c) BIO_ctrl(b, BIO_C_SET_NONBLOCK, c, NULL) #define BIO_set_nonblock(b, c) BIO_ctrl(b, BIO_C_SET_NONBLOCK, c, NULL)
#define BIO_read_blocked(b) BIO_ctrl(b, BIO_C_READ_BLOCKED, 0, NULL) #define BIO_read_blocked(b) BIO_ctrl(b, BIO_C_READ_BLOCKED, 0, NULL)
#define BIO_write_blocked(b) BIO_ctrl(b, BIO_C_WRITE_BLOCKED, 0, NULL) #define BIO_write_blocked(b) BIO_ctrl(b, BIO_C_WRITE_BLOCKED, 0, NULL)

View File

@ -25,6 +25,7 @@ static const size_t bool_list_indices[] = {
FreeRDP_BitmapCompressionDisabled, FreeRDP_BitmapCompressionDisabled,
FreeRDP_CertificateCallbackPreferPEM, FreeRDP_CertificateCallbackPreferPEM,
FreeRDP_CompressionEnabled, FreeRDP_CompressionEnabled,
FreeRDP_ConnectChildSession,
FreeRDP_ConsoleSession, FreeRDP_ConsoleSession,
FreeRDP_CredentialsFromStdin, FreeRDP_CredentialsFromStdin,
FreeRDP_DeactivateClientDecoding, FreeRDP_DeactivateClientDecoding,

View File

@ -53,6 +53,7 @@
#include "proxy.h" #include "proxy.h"
#include "utils.h" #include "utils.h"
#include "state.h" #include "state.h"
#include "childsession.h"
#include "gateway/rdg.h" #include "gateway/rdg.h"
#include "gateway/wst.h" #include "gateway/wst.h"
@ -578,6 +579,18 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por
return status; return status;
} }
BOOL transport_connect_childsession(rdpTransport* transport)
{
WINPR_ASSERT(transport);
transport->frontBio = createChildSessionBio();
if (!transport->frontBio)
return FALSE;
transport->layer = TRANSPORT_LAYER_TSG;
return TRUE;
}
BOOL transport_accept_rdp(rdpTransport* transport) BOOL transport_accept_rdp(rdpTransport* transport)
{ {
if (!transport) if (!transport)

View File

@ -24,6 +24,7 @@ typedef enum
{ {
TRANSPORT_LAYER_TCP, TRANSPORT_LAYER_TCP,
TRANSPORT_LAYER_TLS, TRANSPORT_LAYER_TLS,
TRANSPORT_LAYER_NAMEDPIPE,
TRANSPORT_LAYER_TSG, TRANSPORT_LAYER_TSG,
TRANSPORT_LAYER_TSG_TLS, TRANSPORT_LAYER_TSG_TLS,
TRANSPORT_LAYER_CLOSED TRANSPORT_LAYER_CLOSED
@ -56,6 +57,7 @@ typedef state_run_t (*TransportRecv)(rdpTransport* transport, wStream* stream, v
FREERDP_LOCAL wStream* transport_send_stream_init(rdpTransport* transport, size_t size); FREERDP_LOCAL wStream* transport_send_stream_init(rdpTransport* transport, size_t size);
FREERDP_LOCAL BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port, FREERDP_LOCAL BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port,
DWORD timeout); DWORD timeout);
FREERDP_LOCAL BOOL transport_connect_childsession(rdpTransport* transport);
FREERDP_LOCAL BOOL transport_attach(rdpTransport* transport, int sockfd); FREERDP_LOCAL BOOL transport_attach(rdpTransport* transport, int sockfd);
FREERDP_LOCAL BOOL transport_disconnect(rdpTransport* transport); FREERDP_LOCAL BOOL transport_disconnect(rdpTransport* transport);
FREERDP_LOCAL BOOL transport_connect_rdp(rdpTransport* transport); FREERDP_LOCAL BOOL transport_connect_rdp(rdpTransport* transport);

View File

@ -148,6 +148,9 @@ auth_status utils_authenticate(freerdp* instance, rdp_auth_reason reason, BOOL o
if (freerdp_shall_disconnect_context(instance->context)) if (freerdp_shall_disconnect_context(instance->context))
return AUTH_FAILED; return AUTH_FAILED;
if (settings->ConnectChildSession)
return AUTH_NO_CREDENTIALS;
/* Ask for auth data if no or an empty username was specified or no password was given */ /* Ask for auth data if no or an empty username was specified or no password was given */
if (utils_str_is_empty(freerdp_settings_get_string(settings, FreeRDP_Username)) || if (utils_str_is_empty(freerdp_settings_get_string(settings, FreeRDP_Username)) ||
(settings->Password == NULL && settings->RedirectionPassword == NULL)) (settings->Password == NULL && settings->RedirectionPassword == NULL))