[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:
parent
0638c382f9
commit
3c18a9980f
@ -1971,7 +1971,7 @@ static int parse_gfx_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_
|
||||
WINPR_ASSERT(settings);
|
||||
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;
|
||||
|
||||
if (arg->Value)
|
||||
@ -3794,6 +3794,21 @@ static int freerdp_client_settings_parse_command_line_arguments_int(rdpSettings*
|
||||
settings->SendPreconnectionPdu = TRUE;
|
||||
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")
|
||||
{
|
||||
size_t count = 0, x;
|
||||
|
@ -111,6 +111,10 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
|
||||
"[DEPRECATED, use /cert:name:<name>] Certificate name" },
|
||||
{ "cert-tofu", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL,
|
||||
"[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
|
||||
{ "client-build-number", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL,
|
||||
"Client Build Number sent to server (influences smartcard behaviour, see [MS-RDPESC])" },
|
||||
|
@ -485,12 +485,12 @@ extern "C"
|
||||
/* ThreadingFlags */
|
||||
#define THREADING_FLAGS_DISABLE_THREADS 0x00000001
|
||||
|
||||
/* Settings */
|
||||
/* Settings */
|
||||
|
||||
/**
|
||||
* FreeRDP Settings Ids
|
||||
* This is generated with a script parsing the rdpSettings data structure
|
||||
*/
|
||||
/**
|
||||
* FreeRDP Settings Ids
|
||||
* This is generated with a script parsing the rdpSettings data structure
|
||||
*/
|
||||
|
||||
#define FreeRDP_instance (0)
|
||||
#define FreeRDP_ServerMode (16)
|
||||
@ -737,6 +737,7 @@ extern "C"
|
||||
#define FreeRDP_OldLicenseBehaviour (1606)
|
||||
#define FreeRDP_MouseUseRelativeMove (1607)
|
||||
#define FreeRDP_UseCommonStdioCallbacks (1608)
|
||||
#define FreeRDP_ConnectChildSession (1609)
|
||||
#define FreeRDP_ComputerName (1664)
|
||||
#define FreeRDP_ConnectionFile (1728)
|
||||
#define FreeRDP_AssistanceFile (1729)
|
||||
@ -941,9 +942,9 @@ extern "C"
|
||||
#define FreeRDP_Floatbar (5196)
|
||||
#define FreeRDP_TcpConnectTimeout (5197)
|
||||
|
||||
/**
|
||||
* FreeRDP Settings Data Structure
|
||||
*/
|
||||
/**
|
||||
* FreeRDP Settings Data Structure
|
||||
*/
|
||||
|
||||
#define FreeRDP_Settings_StableAPI_MAX 5312
|
||||
struct rdp_settings
|
||||
@ -1297,15 +1298,16 @@ extern "C"
|
||||
UINT64 padding1601[1601 - 1560]; /* 1560 */
|
||||
|
||||
/* Miscellaneous */
|
||||
ALIGN64 BOOL SoftwareGdi; /* 1601 */
|
||||
ALIGN64 BOOL LocalConnection; /* 1602 */
|
||||
ALIGN64 BOOL AuthenticationOnly; /* 1603 */
|
||||
ALIGN64 BOOL CredentialsFromStdin; /* 1604 */
|
||||
ALIGN64 BOOL UnmapButtons; /* 1605 */
|
||||
ALIGN64 BOOL OldLicenseBehaviour; /* 1606 */
|
||||
ALIGN64 BOOL MouseUseRelativeMove; /* 1607 */
|
||||
ALIGN64 BOOL SoftwareGdi; /* 1601 */
|
||||
ALIGN64 BOOL LocalConnection; /* 1602 */
|
||||
ALIGN64 BOOL AuthenticationOnly; /* 1603 */
|
||||
ALIGN64 BOOL CredentialsFromStdin; /* 1604 */
|
||||
ALIGN64 BOOL UnmapButtons; /* 1605 */
|
||||
ALIGN64 BOOL OldLicenseBehaviour; /* 1606 */
|
||||
ALIGN64 BOOL MouseUseRelativeMove; /* 1607 */
|
||||
ALIGN64 BOOL UseCommonStdioCallbacks; /* 1608 */
|
||||
UINT64 padding1664[1664 - 1609]; /* 1609 */
|
||||
ALIGN64 BOOL ConnectChildSession; /* 1609 */
|
||||
UINT64 padding1664[1664 - 1610]; /* 1610 */
|
||||
|
||||
/* Names */
|
||||
ALIGN64 char* ComputerName; /* 1664 */
|
||||
@ -1339,31 +1341,31 @@ extern "C"
|
||||
*/
|
||||
|
||||
/* Gateway */
|
||||
ALIGN64 UINT32 GatewayUsageMethod; /* 1984 */
|
||||
ALIGN64 UINT32 GatewayPort; /* 1985 */
|
||||
ALIGN64 char* GatewayHostname; /* 1986 */
|
||||
ALIGN64 char* GatewayUsername; /* 1987 */
|
||||
ALIGN64 char* GatewayPassword; /* 1988 */
|
||||
ALIGN64 char* GatewayDomain; /* 1989 */
|
||||
ALIGN64 UINT32 GatewayCredentialsSource; /* 1990 */
|
||||
ALIGN64 BOOL GatewayUseSameCredentials; /* 1991 */
|
||||
ALIGN64 BOOL GatewayEnabled; /* 1992 */
|
||||
ALIGN64 BOOL GatewayBypassLocal; /* 1993 */
|
||||
ALIGN64 BOOL GatewayRpcTransport; /* 1994 */
|
||||
ALIGN64 BOOL GatewayHttpTransport; /* 1995 */
|
||||
ALIGN64 BOOL GatewayUdpTransport; /* 1996 */
|
||||
ALIGN64 char* GatewayAccessToken; /* 1997 */
|
||||
ALIGN64 char* GatewayAcceptedCert; /* 1998 */
|
||||
ALIGN64 UINT32 GatewayAcceptedCertLength; /* 1999 */
|
||||
ALIGN64 BOOL GatewayHttpUseWebsockets; /* 2000 */
|
||||
ALIGN64 BOOL GatewayHttpExtAuthSspiNtlm; /* 2001 */
|
||||
ALIGN64 char* GatewayHttpExtAuthBearer; /* 2002 */
|
||||
ALIGN64 char* GatewayUrl; /* 2003 */
|
||||
ALIGN64 BOOL GatewayArmTransport; /* 2004 */
|
||||
ALIGN64 char* GatewayAvdWvdEndpointPool; /* 2005 */
|
||||
ALIGN64 char* GatewayAvdGeo; /* 2006 */
|
||||
ALIGN64 char* GatewayAvdArmpath; /* 2007 */
|
||||
ALIGN64 char* GatewayAvdAadtenantid; /* 2008 */
|
||||
ALIGN64 UINT32 GatewayUsageMethod; /* 1984 */
|
||||
ALIGN64 UINT32 GatewayPort; /* 1985 */
|
||||
ALIGN64 char* GatewayHostname; /* 1986 */
|
||||
ALIGN64 char* GatewayUsername; /* 1987 */
|
||||
ALIGN64 char* GatewayPassword; /* 1988 */
|
||||
ALIGN64 char* GatewayDomain; /* 1989 */
|
||||
ALIGN64 UINT32 GatewayCredentialsSource; /* 1990 */
|
||||
ALIGN64 BOOL GatewayUseSameCredentials; /* 1991 */
|
||||
ALIGN64 BOOL GatewayEnabled; /* 1992 */
|
||||
ALIGN64 BOOL GatewayBypassLocal; /* 1993 */
|
||||
ALIGN64 BOOL GatewayRpcTransport; /* 1994 */
|
||||
ALIGN64 BOOL GatewayHttpTransport; /* 1995 */
|
||||
ALIGN64 BOOL GatewayUdpTransport; /* 1996 */
|
||||
ALIGN64 char* GatewayAccessToken; /* 1997 */
|
||||
ALIGN64 char* GatewayAcceptedCert; /* 1998 */
|
||||
ALIGN64 UINT32 GatewayAcceptedCertLength; /* 1999 */
|
||||
ALIGN64 BOOL GatewayHttpUseWebsockets; /* 2000 */
|
||||
ALIGN64 BOOL GatewayHttpExtAuthSspiNtlm; /* 2001 */
|
||||
ALIGN64 char* GatewayHttpExtAuthBearer; /* 2002 */
|
||||
ALIGN64 char* GatewayUrl; /* 2003 */
|
||||
ALIGN64 BOOL GatewayArmTransport; /* 2004 */
|
||||
ALIGN64 char* GatewayAvdWvdEndpointPool; /* 2005 */
|
||||
ALIGN64 char* GatewayAvdGeo; /* 2006 */
|
||||
ALIGN64 char* GatewayAvdArmpath; /* 2007 */
|
||||
ALIGN64 char* GatewayAvdAadtenantid; /* 2008 */
|
||||
ALIGN64 char* GatewayAvdDiagnosticserviceurl; /* 2009 */
|
||||
ALIGN64 char* GatewayAvdHubdiscoverygeourl; /* 2010 */
|
||||
ALIGN64 char* GatewayAvdActivityhint; /* 2011 */
|
||||
@ -1646,7 +1648,7 @@ extern "C"
|
||||
* Other Redirection
|
||||
*/
|
||||
|
||||
ALIGN64 BOOL RedirectClipboard; /* 4800 */
|
||||
ALIGN64 BOOL RedirectClipboard; /* 4800 */
|
||||
ALIGN64 UINT32 ClipboardFeatureMask; /* 4801 */
|
||||
UINT64 padding4928[4928 - 4802]; /* 4802 */
|
||||
|
||||
|
@ -123,6 +123,9 @@ BOOL freerdp_settings_get_bool(const rdpSettings* settings, size_t id)
|
||||
case FreeRDP_CompressionEnabled:
|
||||
return settings->CompressionEnabled;
|
||||
|
||||
case FreeRDP_ConnectChildSession:
|
||||
return settings->ConnectChildSession;
|
||||
|
||||
case FreeRDP_ConsoleSession:
|
||||
return settings->ConsoleSession;
|
||||
|
||||
@ -717,6 +720,10 @@ BOOL freerdp_settings_set_bool(rdpSettings* settings, size_t id, BOOL val)
|
||||
settings->CompressionEnabled = cnv.c;
|
||||
break;
|
||||
|
||||
case FreeRDP_ConnectChildSession:
|
||||
settings->ConnectChildSession = cnv.c;
|
||||
break;
|
||||
|
||||
case FreeRDP_ConsoleSession:
|
||||
settings->ConsoleSession = cnv.c;
|
||||
break;
|
||||
|
@ -56,6 +56,7 @@ static const struct settings_str_entry settings_map[] = {
|
||||
{ FreeRDP_CertificateCallbackPreferPEM, FREERDP_SETTINGS_TYPE_BOOL,
|
||||
"FreeRDP_CertificateCallbackPreferPEM" },
|
||||
{ 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_CredentialsFromStdin, FREERDP_SETTINGS_TYPE_BOOL, "FreeRDP_CredentialsFromStdin" },
|
||||
{ FreeRDP_DeactivateClientDecoding, FREERDP_SETTINGS_TYPE_BOOL,
|
||||
|
@ -107,6 +107,7 @@ set(${MODULE_PREFIX}_SRCS
|
||||
multitransport.h
|
||||
timezone.c
|
||||
timezone.h
|
||||
childsession.c
|
||||
rdp.c
|
||||
rdp.h
|
||||
tcp.c
|
||||
|
340
libfreerdp/core/childsession.c
Normal file
340
libfreerdp/core/childsession.c
Normal 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;
|
||||
}
|
27
libfreerdp/core/childsession.h
Normal file
27
libfreerdp/core/childsession.h
Normal 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 */
|
@ -393,6 +393,7 @@ BOOL rdp_client_connect(rdpRdp* rdp)
|
||||
if (!status)
|
||||
return FALSE;
|
||||
|
||||
nego_set_childsession_enabled(rdp->nego, settings->ConnectChildSession);
|
||||
nego_set_send_preconnection_pdu(rdp->nego, settings->SendPreconnectionPdu);
|
||||
nego_set_preconnection_id(rdp->nego, settings->PreconnectionId);
|
||||
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 (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_NEGO))
|
||||
return FALSE;
|
||||
|
||||
|
@ -62,6 +62,7 @@ struct rdp_nego
|
||||
BOOL RestrictedAdminModeRequired;
|
||||
BOOL GatewayEnabled;
|
||||
BOOL GatewayBypassLocal;
|
||||
BOOL ConnectChildSession;
|
||||
|
||||
rdpTransport* transport;
|
||||
};
|
||||
@ -89,6 +90,7 @@ static const char* protocol_security_string(UINT32 security)
|
||||
return PROTOCOL_SECURITY_STRINGS[security];
|
||||
}
|
||||
|
||||
static BOOL nego_tcp_connect(rdpNego* nego);
|
||||
static BOOL nego_transport_connect(rdpNego* nego);
|
||||
static BOOL nego_transport_disconnect(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_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.
|
||||
*
|
||||
@ -222,6 +199,12 @@ BOOL nego_connect(rdpNego* nego)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!nego_tcp_connect(nego))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to connect");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nego->SendPreconnectionPdu)
|
||||
{
|
||||
if (!nego_send_preconnection_pdu(nego))
|
||||
@ -391,6 +374,10 @@ static BOOL nego_tcp_connect(rdpNego* nego)
|
||||
TcpConnectTimeout);
|
||||
}
|
||||
}
|
||||
else if (nego->ConnectChildSession)
|
||||
{
|
||||
nego->TcpConnected = transport_connect_childsession(nego->transport);
|
||||
}
|
||||
else
|
||||
{
|
||||
nego->TcpConnected =
|
||||
@ -1661,6 +1648,12 @@ void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdmin
|
||||
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)
|
||||
{
|
||||
nego->GatewayEnabled = GatewayEnabled;
|
||||
|
@ -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_restricted_admin_mode_required(rdpNego* nego,
|
||||
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_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal);
|
||||
FREERDP_LOCAL void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp);
|
||||
|
@ -41,6 +41,7 @@
|
||||
#define BIO_TYPE_TSG 65
|
||||
#define BIO_TYPE_SIMPLE 66
|
||||
#define BIO_TYPE_BUFFERED 67
|
||||
#define BIO_TYPE_NAMEDPIPE 69
|
||||
|
||||
#define BIO_C_SET_SOCKET 1101
|
||||
#define BIO_C_GET_SOCKET 1102
|
||||
@ -50,10 +51,12 @@
|
||||
#define BIO_C_WRITE_BLOCKED 1106
|
||||
#define BIO_C_WAIT_READ 1107
|
||||
#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_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_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_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)
|
||||
|
@ -25,6 +25,7 @@ static const size_t bool_list_indices[] = {
|
||||
FreeRDP_BitmapCompressionDisabled,
|
||||
FreeRDP_CertificateCallbackPreferPEM,
|
||||
FreeRDP_CompressionEnabled,
|
||||
FreeRDP_ConnectChildSession,
|
||||
FreeRDP_ConsoleSession,
|
||||
FreeRDP_CredentialsFromStdin,
|
||||
FreeRDP_DeactivateClientDecoding,
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "proxy.h"
|
||||
#include "utils.h"
|
||||
#include "state.h"
|
||||
#include "childsession.h"
|
||||
|
||||
#include "gateway/rdg.h"
|
||||
#include "gateway/wst.h"
|
||||
@ -578,6 +579,18 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por
|
||||
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)
|
||||
{
|
||||
if (!transport)
|
||||
|
@ -24,6 +24,7 @@ typedef enum
|
||||
{
|
||||
TRANSPORT_LAYER_TCP,
|
||||
TRANSPORT_LAYER_TLS,
|
||||
TRANSPORT_LAYER_NAMEDPIPE,
|
||||
TRANSPORT_LAYER_TSG,
|
||||
TRANSPORT_LAYER_TSG_TLS,
|
||||
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 BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port,
|
||||
DWORD timeout);
|
||||
FREERDP_LOCAL BOOL transport_connect_childsession(rdpTransport* transport);
|
||||
FREERDP_LOCAL BOOL transport_attach(rdpTransport* transport, int sockfd);
|
||||
FREERDP_LOCAL BOOL transport_disconnect(rdpTransport* transport);
|
||||
FREERDP_LOCAL BOOL transport_connect_rdp(rdpTransport* transport);
|
||||
|
@ -148,6 +148,9 @@ auth_status utils_authenticate(freerdp* instance, rdp_auth_reason reason, BOOL o
|
||||
if (freerdp_shall_disconnect_context(instance->context))
|
||||
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 */
|
||||
if (utils_str_is_empty(freerdp_settings_get_string(settings, FreeRDP_Username)) ||
|
||||
(settings->Password == NULL && settings->RedirectionPassword == NULL))
|
||||
|
Loading…
Reference in New Issue
Block a user