2012-02-26 00:56:49 +04:00
|
|
|
/*
|
2012-10-09 07:02:04 +04:00
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
2011-07-10 09:48:10 +04:00
|
|
|
* Connection Sequence
|
|
|
|
*
|
|
|
|
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
2015-05-29 14:46:50 +03:00
|
|
|
* Copyright 2015 Thincast Technologies GmbH
|
|
|
|
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
2011-07-10 09:48:10 +04:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2022-02-16 13:20:38 +03:00
|
|
|
#include <freerdp/config.h>
|
2012-08-15 01:09:01 +04:00
|
|
|
|
2012-01-14 01:20:36 +04:00
|
|
|
#include "info.h"
|
|
|
|
#include "input.h"
|
2014-02-16 01:32:38 +04:00
|
|
|
#include "rdp.h"
|
2022-11-08 14:54:49 +03:00
|
|
|
#include "peer.h"
|
2012-01-14 01:20:36 +04:00
|
|
|
|
|
|
|
#include "connection.h"
|
2012-07-25 12:38:47 +04:00
|
|
|
#include "transport.h"
|
2011-07-10 09:48:10 +04:00
|
|
|
|
2012-10-09 07:42:01 +04:00
|
|
|
#include <winpr/crt.h>
|
2016-02-24 19:04:03 +03:00
|
|
|
#include <winpr/crypto.h>
|
2017-04-08 00:54:08 +03:00
|
|
|
#include <winpr/ssl.h>
|
2012-10-09 07:42:01 +04:00
|
|
|
|
2014-09-12 16:36:29 +04:00
|
|
|
#include <freerdp/log.h>
|
2012-12-14 09:25:48 +04:00
|
|
|
#include <freerdp/error.h>
|
2013-07-20 05:52:28 +04:00
|
|
|
#include <freerdp/listener.h>
|
2018-11-20 11:09:52 +03:00
|
|
|
#include <freerdp/cache/pointer.h>
|
2012-05-22 00:01:24 +04:00
|
|
|
|
2022-03-07 15:47:43 +03:00
|
|
|
#include "utils.h"
|
|
|
|
|
2014-09-12 16:36:29 +04:00
|
|
|
#define TAG FREERDP_TAG("core.connection")
|
|
|
|
|
2011-07-10 09:48:10 +04:00
|
|
|
/**
|
2014-09-12 16:36:29 +04:00
|
|
|
* Connection Sequence
|
|
|
|
* client server
|
|
|
|
* | |
|
|
|
|
* |-----------------------X.224 Connection Request PDU--------------------->|
|
|
|
|
* |<----------------------X.224 Connection Confirm PDU----------------------|
|
|
|
|
* |-------MCS Connect-Initial PDU with GCC Conference Create Request------->|
|
|
|
|
* |<-----MCS Connect-Response PDU with GCC Conference Create Response-------|
|
|
|
|
* |------------------------MCS Erect Domain Request PDU-------------------->|
|
|
|
|
* |------------------------MCS Attach User Request PDU--------------------->|
|
|
|
|
* |<-----------------------MCS Attach User Confirm PDU----------------------|
|
|
|
|
* |------------------------MCS Channel Join Request PDU-------------------->|
|
|
|
|
* |<-----------------------MCS Channel Join Confirm PDU---------------------|
|
|
|
|
* |----------------------------Security Exchange PDU----------------------->|
|
|
|
|
* |-------------------------------Client Info PDU-------------------------->|
|
|
|
|
* |<---------------------License Error PDU - Valid Client-------------------|
|
|
|
|
* |<-----------------------------Demand Active PDU--------------------------|
|
|
|
|
* |------------------------------Confirm Active PDU------------------------>|
|
|
|
|
* |-------------------------------Synchronize PDU-------------------------->|
|
|
|
|
* |---------------------------Control PDU - Cooperate---------------------->|
|
|
|
|
* |------------------------Control PDU - Request Control------------------->|
|
|
|
|
* |--------------------------Persistent Key List PDU(s)-------------------->|
|
|
|
|
* |--------------------------------Font List PDU--------------------------->|
|
|
|
|
* |<------------------------------Synchronize PDU---------------------------|
|
|
|
|
* |<--------------------------Control PDU - Cooperate-----------------------|
|
|
|
|
* |<-----------------------Control PDU - Granted Control--------------------|
|
|
|
|
* |<-------------------------------Font Map PDU-----------------------------|
|
2011-07-10 09:48:10 +04:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2013-07-18 23:18:59 +04:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Connection Sequence
|
|
|
|
*
|
|
|
|
* 1. Connection Initiation: The client initiates the connection by sending the server a
|
|
|
|
* Class 0 X.224 Connection Request PDU (section 2.2.1.1). The server responds with a
|
|
|
|
* Class 0 X.224 Connection Confirm PDU (section 2.2.1.2). From this point, all subsequent
|
|
|
|
* data sent between client and server is wrapped in an X.224 Data Protocol Data Unit (PDU).
|
|
|
|
*
|
|
|
|
* 2. Basic Settings Exchange: Basic settings are exchanged between the client and server by
|
2019-11-06 17:24:51 +03:00
|
|
|
* using the MCS Connect Initial PDU (section 2.2.1.3) and MCS Connect Response PDU
|
|
|
|
*(section 2.2.1.4). The Connect Initial PDU contains a Generic Conference Control (GCC) Conference
|
|
|
|
*Create Request, while the Connect Response PDU contains a GCC Conference Create Response. These
|
|
|
|
*two GCC packets contain concatenated blocks of settings data (such as core data, security data,
|
|
|
|
*and network data) which are read by client and server.
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
|
|
|
* 3. Channel Connection: The client sends an MCS Erect Domain Request PDU (section 2.2.1.5),
|
|
|
|
* followed by an MCS Attach User Request PDU (section 2.2.1.6) to attach the primary user identity
|
|
|
|
* to the MCS domain. The server responds with an MCS Attach User Confirm PDU (section 2.2.1.7)
|
|
|
|
* containing the User Channel ID. The client then proceeds to join the user channel, the
|
|
|
|
* input/output (I/O) channel, and all of the static virtual channels (the I/O and static virtual
|
2019-11-06 17:24:51 +03:00
|
|
|
* channel IDs are obtained from the data embedded in the GCC packets) by using multiple MCS
|
|
|
|
*Channel Join Request PDUs (section 2.2.1.8). The server confirms each channel with an MCS Channel
|
|
|
|
*Join Confirm PDU (section 2.2.1.9). (The client only sends a Channel Join Request after it has
|
|
|
|
*received the Channel Join Confirm for the previously sent request.)
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* From this point, all subsequent data sent from the client to the server is wrapped in an MCS
|
|
|
|
*Send Data Request PDU, while data sent from the server to the client is wrapped in an MCS Send
|
|
|
|
*Data Indication PDU. This is in addition to the data being wrapped by an X.224 Data PDU.
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* 4. RDP Security Commencement: If Standard RDP Security mechanisms (section 5.3) are being
|
|
|
|
*employed and encryption is in force (this is determined by examining the data embedded in the GCC
|
|
|
|
*Conference Create Response packet) then the client sends a Security Exchange PDU
|
|
|
|
*(section 2.2.1.10) containing an encrypted 32-byte random number to the server. This random number
|
|
|
|
*is encrypted with the public key of the server as described in section 5.3.4.1 (the server's
|
|
|
|
*public key, as well as a 32-byte server-generated random number, are both obtained from the data
|
|
|
|
*embedded in the GCC Conference Create Response packet). The client and server then utilize the two
|
|
|
|
*32-byte random numbers to generate session keys which are used to encrypt and validate the
|
|
|
|
*integrity of subsequent RDP traffic.
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* From this point, all subsequent RDP traffic can be encrypted and a security header is included
|
|
|
|
*with the data if encryption is in force. (The Client Info PDU (section 2.2.1.11) and licensing
|
|
|
|
*PDUs ([MS-RDPELE] section 2.2.2) are an exception in that they always have a security header). The
|
|
|
|
*Security Header follows the X.224 and MCS Headers and indicates whether the attached data is
|
|
|
|
*encrypted. Even if encryption is in force, server-to-client traffic may not always be encrypted,
|
|
|
|
*while client-to-server traffic must always be encrypted (encryption of licensing PDUs is optional,
|
|
|
|
*however).
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* 5. Secure Settings Exchange: Secure client data (such as the username, password, and
|
|
|
|
*auto-reconnect cookie) is sent to the server by using the Client Info PDU (section 2.2.1.11).
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* 6. Optional Connect-Time Auto-Detection: During the optional connect-time auto-detect phase the
|
|
|
|
*goal is to determine characteristics of the network, such as the round-trip latency time and the
|
|
|
|
*bandwidth of the link between the server and client. This is accomplished by exchanging a
|
|
|
|
*collection of PDUs (specified in section 2.2.1.4) over a predetermined period of time with enough
|
|
|
|
*data to ensure that the results are statistically relevant.
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* 7. Licensing: The goal of the licensing exchange is to transfer a license from the server to
|
|
|
|
*the client. The client stores this license and on subsequent connections sends the license to the
|
|
|
|
*server for validation. However, in some situations the client may not be issued a license to
|
|
|
|
*store. In effect, the packets exchanged during this phase of the protocol depend on the licensing
|
|
|
|
*mechanisms employed by the server. Within the context of this document, it is assumed that the
|
|
|
|
*client will not be issued a license to store. For details regarding more advanced licensing
|
|
|
|
*scenarios that take place during the Licensing Phase, see [MS-RDPELE] section 1.3.
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* 8. Optional Multitransport Bootstrapping: After the connection has been secured and the
|
|
|
|
*Licensing Phase has run to completion, the server can choose to initiate multitransport
|
|
|
|
*connections ([MS-RDPEMT] section 1.3). The Initiate Multitransport Request PDU (section 2.2.15.1)
|
|
|
|
*is sent by the server to the client and results in the out-of-band creation of a multitransport
|
|
|
|
*connection using messages from the RDP-UDP, TLS, DTLS, and multitransport protocols ([MS-RDPEMT]
|
|
|
|
*section 1.3.1).
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* 9. Capabilities Exchange: The server sends the set of capabilities it supports to the client in
|
|
|
|
*a Demand Active PDU (section 2.2.1.13.1). The client responds with its capabilities by sending a
|
|
|
|
*Confirm Active PDU (section 2.2.1.13.2).
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* 10. Connection Finalization: The client and server exchange PDUs to finalize the connection
|
|
|
|
*details. The client-to-server PDUs sent during this phase have no dependencies on any of the
|
|
|
|
*server-to-client PDUs; they may be sent as a single batch, provided that sequencing is maintained.
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* - The Client Synchronize PDU (section 2.2.1.14) is sent after transmitting the Confirm Active
|
|
|
|
*PDU.
|
|
|
|
* - The Client Control (Cooperate) PDU (section 2.2.1.15) is sent after transmitting the Client
|
|
|
|
*Synchronize PDU.
|
|
|
|
* - The Client Control (Request Control) PDU (section 2.2.1.16) is sent after transmitting the
|
|
|
|
*Client Control (Cooperate) PDU.
|
|
|
|
* - The optional Persistent Key List PDUs (section 2.2.1.17) are sent after transmitting the
|
|
|
|
*Client Control (Request Control) PDU.
|
|
|
|
* - The Font List PDU (section 2.2.1.18) is sent after transmitting the Persistent Key List PDUs
|
|
|
|
*or, if the Persistent Key List PDUs were not sent, it is sent after transmitting the Client
|
|
|
|
*Control (Request Control) PDU (section 2.2.1.16).
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* The server-to-client PDUs sent during the Connection Finalization Phase have dependencies on the
|
|
|
|
*client-to-server PDUs.
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* - The optional Monitor Layout PDU (section 2.2.12.1) has no dependency on any client-to-server
|
|
|
|
*PDUs and is sent after the Demand Active PDU.
|
2013-07-18 23:18:59 +04:00
|
|
|
* - The Server Synchronize PDU (section 2.2.1.19) is sent in response to the Confirm Active PDU.
|
2019-11-06 17:24:51 +03:00
|
|
|
* - The Server Control (Cooperate) PDU (section 2.2.1.20) is sent after transmitting the Server
|
|
|
|
*Synchronize PDU.
|
|
|
|
* - The Server Control (Granted Control) PDU (section 2.2.1.21) is sent in response to the Client
|
|
|
|
*Control (Request Control) PDU.
|
2013-07-18 23:18:59 +04:00
|
|
|
* - The Font Map PDU (section 2.2.1.22) is sent in response to the Font List PDU.
|
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* Once the client has sent the Confirm Active PDU, it can start sending mouse and keyboard input
|
|
|
|
*to the server, and upon receipt of the Font List PDU the server can start sending graphics output
|
|
|
|
*to the client.
|
2013-07-18 23:18:59 +04:00
|
|
|
*
|
2019-11-06 17:24:51 +03:00
|
|
|
* Besides input and graphics data, other data that can be exchanged between client and server
|
|
|
|
*after the connection has been finalized includes connection management information and virtual
|
|
|
|
*channel messages (exchanged between client-side plug-ins and server-side applications).
|
2013-07-18 23:18:59 +04:00
|
|
|
*/
|
|
|
|
|
2021-09-03 10:12:23 +03:00
|
|
|
static BOOL rdp_set_state(rdpRdp* rdp, CONNECTION_STATE state);
|
2018-07-10 13:21:38 +03:00
|
|
|
|
2018-09-19 13:03:07 +03:00
|
|
|
static BOOL rdp_client_reset_codecs(rdpContext* context)
|
|
|
|
{
|
|
|
|
rdpSettings* settings;
|
|
|
|
|
|
|
|
if (!context || !context->settings)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
settings = context->settings;
|
|
|
|
|
2021-09-17 09:59:10 +03:00
|
|
|
if (!freerdp_settings_get_bool(settings, FreeRDP_DeactivateClientDecoding))
|
|
|
|
{
|
|
|
|
codecs_free(context->codecs);
|
|
|
|
context->codecs = codecs_new(context);
|
2018-09-19 13:03:07 +03:00
|
|
|
|
2021-09-17 09:59:10 +03:00
|
|
|
if (!context->codecs)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!freerdp_client_codecs_prepare(context->codecs,
|
|
|
|
freerdp_settings_get_codecs_flags(settings),
|
|
|
|
settings->DesktopWidth, settings->DesktopHeight))
|
|
|
|
return FALSE;
|
2019-10-07 10:31:20 +03:00
|
|
|
|
|
|
|
/* Runtime H264 detection. (only available if dynamic backend loading is defined)
|
|
|
|
* If no backend is available disable it before the channel is loaded.
|
|
|
|
*/
|
|
|
|
#if defined(WITH_GFX_H264) && defined(WITH_OPENH264_LOADING)
|
2022-06-23 08:57:38 +03:00
|
|
|
if (!context->codecs->h264)
|
|
|
|
{
|
|
|
|
settings->GfxH264 = FALSE;
|
|
|
|
settings->GfxAVC444 = FALSE;
|
|
|
|
settings->GfxAVC444v2 = FALSE;
|
|
|
|
}
|
2019-10-07 10:31:20 +03:00
|
|
|
#endif
|
2021-09-17 09:59:10 +03:00
|
|
|
}
|
|
|
|
|
2019-10-07 10:31:20 +03:00
|
|
|
return TRUE;
|
2018-09-19 13:03:07 +03:00
|
|
|
}
|
|
|
|
|
2022-11-30 16:33:08 +03:00
|
|
|
static BOOL rdp_client_wait_for_activation(rdpRdp* rdp)
|
|
|
|
{
|
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
|
|
|
|
const rdpSettings* settings = rdp->settings;
|
|
|
|
WINPR_ASSERT(settings);
|
|
|
|
|
|
|
|
UINT64 now = GetTickCount64();
|
|
|
|
UINT64 dueDate = now + freerdp_settings_get_uint32(settings, FreeRDP_TcpAckTimeout);
|
|
|
|
|
|
|
|
for (; now < dueDate; now = GetTickCount64())
|
|
|
|
{
|
|
|
|
HANDLE events[MAXIMUM_WAIT_OBJECTS] = { 0 };
|
|
|
|
DWORD wstatus = 0;
|
|
|
|
DWORD nevents = freerdp_get_event_handles(rdp->context, events, ARRAYSIZE(events));
|
|
|
|
if (!nevents)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "error retrieving connection events");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
wstatus = WaitForMultipleObjectsEx(nevents, events, FALSE, (dueDate - now), TRUE);
|
|
|
|
switch (wstatus)
|
|
|
|
{
|
|
|
|
case WAIT_TIMEOUT:
|
|
|
|
/* will make us quit with a timeout */
|
|
|
|
now = dueDate + 1;
|
|
|
|
break;
|
|
|
|
case WAIT_ABANDONED:
|
|
|
|
case WAIT_FAILED:
|
|
|
|
return FALSE;
|
|
|
|
case WAIT_IO_COMPLETION:
|
|
|
|
break;
|
|
|
|
case WAIT_OBJECT_0:
|
|
|
|
default:
|
|
|
|
/* handles all WAIT_OBJECT_0 + [0 .. MAXIMUM_WAIT_OBJECTS-1] cases */
|
|
|
|
if (rdp_check_fds(rdp) < 0)
|
|
|
|
{
|
|
|
|
freerdp_set_last_error_if_not(rdp->context,
|
|
|
|
FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rdp_get_state(rdp) > CONNECTION_STATE_CAPABILITIES_EXCHANGE_CONFIRM_ACTIVE)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
WLog_ERR(TAG, "Timeout waiting for activation");
|
|
|
|
freerdp_set_last_error_if_not(rdp->context, FREERDP_ERROR_CONNECT_ACTIVATION_TIMEOUT);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2011-07-11 23:58:39 +04:00
|
|
|
/**
|
2012-10-26 02:38:51 +04:00
|
|
|
* Establish RDP Connection based on the settings given in the 'rdp' parameter.
|
2011-07-11 23:58:39 +04:00
|
|
|
* @msdn{cc240452}
|
2011-07-12 02:46:36 +04:00
|
|
|
* @param rdp RDP module
|
2012-10-09 10:31:28 +04:00
|
|
|
* @return true if the connection succeeded. FALSE otherwise.
|
2011-07-11 23:58:39 +04:00
|
|
|
*/
|
|
|
|
|
2012-10-09 10:38:39 +04:00
|
|
|
BOOL rdp_client_connect(rdpRdp* rdp)
|
2011-07-10 09:48:10 +04:00
|
|
|
{
|
2018-11-20 18:38:06 +03:00
|
|
|
UINT32 SelectedProtocol;
|
2015-02-06 22:21:26 +03:00
|
|
|
BOOL status;
|
2021-09-17 09:59:10 +03:00
|
|
|
rdpSettings* settings;
|
2019-11-06 17:24:51 +03:00
|
|
|
/* make sure SSL is initialize for earlier enough for crypto, by taking advantage of winpr SSL
|
|
|
|
* FIPS flag for openssl initialization */
|
2017-04-08 00:54:08 +03:00
|
|
|
DWORD flags = WINPR_SSL_INIT_DEFAULT;
|
|
|
|
|
2021-09-17 09:59:10 +03:00
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
|
|
|
|
settings = rdp->settings;
|
|
|
|
WINPR_ASSERT(settings);
|
|
|
|
|
2018-09-19 13:03:07 +03:00
|
|
|
if (!rdp_client_reset_codecs(rdp->context))
|
|
|
|
return FALSE;
|
|
|
|
|
2017-04-08 00:54:08 +03:00
|
|
|
if (settings->FIPSMode)
|
|
|
|
flags |= WINPR_SSL_INIT_ENABLE_FIPS;
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2017-04-08 00:54:08 +03:00
|
|
|
winpr_InitializeSSL(flags);
|
|
|
|
|
2017-11-22 21:25:32 +03:00
|
|
|
/* FIPS Mode forces the following and overrides the following(by happening later */
|
|
|
|
/* in the command line processing): */
|
2019-11-06 17:24:51 +03:00
|
|
|
/* 1. Disables NLA Security since NLA in freerdp uses NTLM(no Kerberos support yet) which uses
|
|
|
|
* algorithms */
|
2017-11-22 21:25:32 +03:00
|
|
|
/* not allowed in FIPS for sensitive data. So, we disallow NLA when FIPS is required. */
|
|
|
|
/* 2. Forces the only supported RDP encryption method to be FIPS. */
|
|
|
|
if (settings->FIPSMode || winpr_FIPSMode())
|
|
|
|
{
|
|
|
|
settings->NlaSecurity = FALSE;
|
|
|
|
settings->EncryptionMethods = ENCRYPTION_METHOD_FIPS;
|
|
|
|
}
|
|
|
|
|
2022-10-14 20:39:12 +03:00
|
|
|
const char* hostname = freerdp_settings_get_server_name(settings);
|
|
|
|
|
2011-07-12 02:46:36 +04:00
|
|
|
nego_init(rdp->nego);
|
2022-10-14 20:39:12 +03:00
|
|
|
nego_set_target(rdp->nego, hostname, settings->ServerPort);
|
2012-10-26 02:38:51 +04:00
|
|
|
|
2013-07-03 23:07:12 +04:00
|
|
|
if (settings->GatewayEnabled)
|
2012-10-26 02:38:51 +04:00
|
|
|
{
|
2013-11-01 18:01:16 +04:00
|
|
|
char* user = NULL;
|
|
|
|
char* domain = NULL;
|
|
|
|
char* cookie = NULL;
|
2021-12-17 19:28:41 +03:00
|
|
|
size_t user_length = 0;
|
|
|
|
size_t domain_length = 0;
|
|
|
|
size_t cookie_length = 0;
|
2012-10-26 02:38:51 +04:00
|
|
|
|
2013-07-18 23:18:59 +04:00
|
|
|
if (settings->Username)
|
|
|
|
{
|
|
|
|
user = settings->Username;
|
|
|
|
user_length = strlen(settings->Username);
|
|
|
|
}
|
2012-10-26 02:38:51 +04:00
|
|
|
|
2012-11-08 00:13:14 +04:00
|
|
|
if (settings->Domain)
|
|
|
|
domain = settings->Domain;
|
2012-10-26 02:38:51 +04:00
|
|
|
else
|
2012-11-08 00:13:14 +04:00
|
|
|
domain = settings->ComputerName;
|
2012-10-26 02:38:51 +04:00
|
|
|
|
|
|
|
domain_length = strlen(domain);
|
|
|
|
cookie_length = domain_length + 1 + user_length;
|
2019-11-06 17:24:51 +03:00
|
|
|
cookie = (char*)malloc(cookie_length + 1);
|
2015-02-06 22:21:26 +03:00
|
|
|
|
2014-04-10 23:07:53 +04:00
|
|
|
if (!cookie)
|
|
|
|
return FALSE;
|
2012-10-26 02:38:51 +04:00
|
|
|
|
|
|
|
CopyMemory(cookie, domain, domain_length);
|
|
|
|
CharUpperBuffA(cookie, domain_length);
|
|
|
|
cookie[domain_length] = '\\';
|
2013-07-04 22:42:40 +04:00
|
|
|
|
2013-07-18 23:18:59 +04:00
|
|
|
if (settings->Username)
|
|
|
|
CopyMemory(&cookie[domain_length + 1], user, user_length);
|
2013-07-04 22:42:40 +04:00
|
|
|
|
2013-07-18 23:18:59 +04:00
|
|
|
cookie[cookie_length] = '\0';
|
2015-02-06 22:21:26 +03:00
|
|
|
status = nego_set_cookie(rdp->nego, cookie);
|
2012-12-13 05:02:56 +04:00
|
|
|
free(cookie);
|
2012-10-26 02:38:51 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-02-06 22:21:26 +03:00
|
|
|
status = nego_set_cookie(rdp->nego, settings->Username);
|
2012-10-26 02:38:51 +04:00
|
|
|
}
|
|
|
|
|
2015-02-06 22:21:26 +03:00
|
|
|
if (!status)
|
2014-04-10 23:07:53 +04:00
|
|
|
return FALSE;
|
|
|
|
|
2012-11-08 00:13:14 +04:00
|
|
|
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);
|
2012-11-07 20:02:46 +04:00
|
|
|
nego_set_negotiation_enabled(rdp->nego, settings->NegotiateSecurityLayer);
|
2013-11-06 10:51:55 +04:00
|
|
|
nego_set_restricted_admin_mode_required(rdp->nego, settings->RestrictedAdminModeRequired);
|
2014-03-24 22:44:18 +04:00
|
|
|
nego_set_gateway_enabled(rdp->nego, settings->GatewayEnabled);
|
|
|
|
nego_set_gateway_bypass_local(rdp->nego, settings->GatewayBypassLocal);
|
2012-11-07 20:02:46 +04:00
|
|
|
nego_enable_rdp(rdp->nego, settings->RdpSecurity);
|
|
|
|
nego_enable_tls(rdp->nego, settings->TlsSecurity);
|
|
|
|
nego_enable_nla(rdp->nego, settings->NlaSecurity);
|
|
|
|
nego_enable_ext(rdp->nego, settings->ExtSecurity);
|
2012-11-01 04:38:48 +04:00
|
|
|
|
2012-11-08 00:13:14 +04:00
|
|
|
if (settings->MstscCookieMode)
|
|
|
|
settings->CookieMaxLength = MSTSC_COOKIE_MAX_LENGTH;
|
2012-11-01 04:38:48 +04:00
|
|
|
|
2012-11-08 00:13:14 +04:00
|
|
|
nego_set_cookie_max_length(rdp->nego, settings->CookieMaxLength);
|
2012-03-26 11:04:47 +04:00
|
|
|
|
2019-07-02 12:53:14 +03:00
|
|
|
if (settings->LoadBalanceInfo && (settings->LoadBalanceInfoLength > 0))
|
2014-04-10 23:07:53 +04:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
if (!nego_set_routing_token(rdp->nego, settings->LoadBalanceInfo,
|
|
|
|
settings->LoadBalanceInfoLength))
|
2014-04-10 23:07:53 +04:00
|
|
|
return FALSE;
|
|
|
|
}
|
2013-04-11 19:51:10 +04:00
|
|
|
|
2021-09-23 15:52:03 +03:00
|
|
|
if (!freerdp_settings_get_bool(settings, FreeRDP_TransportDumpReplay))
|
2012-05-31 18:34:38 +04:00
|
|
|
{
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_NEGO))
|
|
|
|
return FALSE;
|
2021-09-23 15:52:03 +03:00
|
|
|
|
|
|
|
if (!nego_connect(rdp->nego))
|
2018-04-11 10:00:32 +03:00
|
|
|
{
|
2021-09-23 15:52:03 +03:00
|
|
|
if (!freerdp_get_last_error(rdp->context))
|
|
|
|
{
|
|
|
|
freerdp_set_last_error_log(rdp->context,
|
|
|
|
FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED);
|
|
|
|
WLog_ERR(TAG, "Error: protocol security negotiation or connection failure");
|
|
|
|
}
|
2018-05-06 12:17:08 +03:00
|
|
|
|
2021-09-23 15:52:03 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
2011-07-18 07:16:31 +04:00
|
|
|
|
2021-09-23 15:52:03 +03:00
|
|
|
SelectedProtocol = nego_get_selected_protocol(rdp->nego);
|
2018-11-20 18:38:06 +03:00
|
|
|
|
2021-09-23 15:52:03 +03:00
|
|
|
if ((SelectedProtocol & PROTOCOL_SSL) || (SelectedProtocol == PROTOCOL_RDP))
|
|
|
|
{
|
2022-10-21 11:31:14 +03:00
|
|
|
wStream s = { 0 };
|
|
|
|
|
2021-09-23 15:52:03 +03:00
|
|
|
if ((settings->Username != NULL) &&
|
2022-03-18 12:57:47 +03:00
|
|
|
((freerdp_settings_get_string(settings, FreeRDP_Password) != NULL) ||
|
|
|
|
(settings->RedirectionPassword != NULL &&
|
|
|
|
settings->RedirectionPasswordLength > 0)))
|
2021-09-23 15:52:03 +03:00
|
|
|
settings->AutoLogonEnabled = TRUE;
|
2022-10-21 11:31:14 +03:00
|
|
|
|
|
|
|
if (rdp_recv_callback(rdp->transport, &s, rdp) < 0)
|
|
|
|
return FALSE;
|
2021-09-23 15:52:03 +03:00
|
|
|
}
|
2022-10-21 11:31:14 +03:00
|
|
|
|
2022-03-18 12:57:47 +03:00
|
|
|
transport_set_blocking_mode(rdp->transport, FALSE);
|
2011-12-10 19:54:09 +04:00
|
|
|
}
|
2022-10-21 11:31:14 +03:00
|
|
|
else
|
|
|
|
{
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CREATE_REQUEST))
|
|
|
|
return FALSE;
|
2022-10-21 11:31:14 +03:00
|
|
|
}
|
2011-12-10 19:54:09 +04:00
|
|
|
|
2015-02-15 22:54:10 +03:00
|
|
|
/* everything beyond this point is event-driven and non blocking */
|
2022-11-11 14:26:28 +03:00
|
|
|
if (!transport_set_recv_callbacks(rdp->transport, rdp_recv_callback, rdp))
|
|
|
|
return FALSE;
|
2015-02-15 22:54:10 +03:00
|
|
|
|
2022-11-30 16:33:08 +03:00
|
|
|
return rdp_client_wait_for_activation(rdp);
|
2011-08-22 11:03:58 +04:00
|
|
|
}
|
|
|
|
|
2012-10-09 10:38:39 +04:00
|
|
|
BOOL rdp_client_disconnect(rdpRdp* rdp)
|
2011-09-04 00:36:27 +04:00
|
|
|
{
|
2018-04-09 12:08:46 +03:00
|
|
|
rdpContext* context;
|
2015-01-12 15:36:38 +03:00
|
|
|
|
2018-04-09 12:08:46 +03:00
|
|
|
if (!rdp || !rdp->settings || !rdp->context)
|
|
|
|
return FALSE;
|
2015-02-06 22:21:26 +03:00
|
|
|
|
2018-04-09 12:08:46 +03:00
|
|
|
context = rdp->context;
|
2015-02-06 22:21:26 +03:00
|
|
|
|
2021-09-17 09:59:10 +03:00
|
|
|
if (rdp->nego)
|
|
|
|
{
|
|
|
|
if (!nego_disconnect(rdp->nego))
|
|
|
|
return FALSE;
|
|
|
|
}
|
2018-05-06 12:17:08 +03:00
|
|
|
|
2021-09-07 11:03:36 +03:00
|
|
|
if (!rdp_reset(rdp))
|
|
|
|
return FALSE;
|
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_INITIAL))
|
|
|
|
return FALSE;
|
2015-02-06 22:21:26 +03:00
|
|
|
|
2018-04-09 12:08:46 +03:00
|
|
|
if (freerdp_channels_disconnect(context->channels, context->instance) != CHANNEL_RC_OK)
|
|
|
|
return FALSE;
|
|
|
|
|
2018-09-19 13:03:07 +03:00
|
|
|
codecs_free(context->codecs);
|
2020-01-21 16:40:33 +03:00
|
|
|
context->codecs = NULL;
|
2018-04-11 10:30:40 +03:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL rdp_client_disconnect_and_clear(rdpRdp* rdp)
|
|
|
|
{
|
|
|
|
rdpContext* context;
|
|
|
|
|
|
|
|
if (!rdp_client_disconnect(rdp))
|
|
|
|
return FALSE;
|
|
|
|
|
2021-09-17 09:59:10 +03:00
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
|
2018-04-11 10:30:40 +03:00
|
|
|
context = rdp->context;
|
2021-09-17 09:59:10 +03:00
|
|
|
WINPR_ASSERT(context);
|
|
|
|
|
2022-03-07 15:47:43 +03:00
|
|
|
if (freerdp_get_last_error(context) == FREERDP_ERROR_CONNECT_CANCELLED)
|
|
|
|
return FALSE;
|
|
|
|
|
2018-04-11 10:30:40 +03:00
|
|
|
context->LastError = FREERDP_ERROR_SUCCESS;
|
2018-04-09 12:08:46 +03:00
|
|
|
clearChannelError(context);
|
2022-04-19 15:29:17 +03:00
|
|
|
return utils_reset_abort(rdp);
|
2011-09-04 00:36:27 +04:00
|
|
|
}
|
|
|
|
|
2018-07-13 14:11:38 +03:00
|
|
|
static BOOL rdp_client_reconnect_channels(rdpRdp* rdp, BOOL redirect)
|
2018-07-10 13:04:27 +03:00
|
|
|
{
|
2018-07-31 11:45:04 +03:00
|
|
|
BOOL status = FALSE;
|
2018-07-10 13:04:27 +03:00
|
|
|
rdpContext* context;
|
|
|
|
|
|
|
|
if (!rdp || !rdp->context || !rdp->context->channels)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
context = rdp->context;
|
|
|
|
|
|
|
|
if (context->instance->ConnectionCallbackState == CLIENT_STATE_INITIAL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (context->instance->ConnectionCallbackState == CLIENT_STATE_PRECONNECT_PASSED)
|
|
|
|
{
|
2018-07-13 14:11:38 +03:00
|
|
|
if (redirect)
|
|
|
|
return TRUE;
|
|
|
|
|
2018-11-20 11:09:52 +03:00
|
|
|
pointer_cache_register_callbacks(context->update);
|
|
|
|
|
2018-07-10 13:04:27 +03:00
|
|
|
if (!IFCALLRESULT(FALSE, context->instance->PostConnect, context->instance))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
context->instance->ConnectionCallbackState = CLIENT_STATE_POSTCONNECT_PASSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context->instance->ConnectionCallbackState == CLIENT_STATE_POSTCONNECT_PASSED)
|
2019-11-06 17:24:51 +03:00
|
|
|
status =
|
|
|
|
(freerdp_channels_post_connect(context->channels, context->instance) == CHANNEL_RC_OK);
|
2018-07-10 13:04:27 +03:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2018-08-08 13:26:57 +03:00
|
|
|
static BOOL rdp_client_redirect_resolvable(const char* host)
|
|
|
|
{
|
2018-09-27 17:08:28 +03:00
|
|
|
struct addrinfo* result = freerdp_tcp_resolve_host(host, -1, 0);
|
2018-08-08 13:26:57 +03:00
|
|
|
|
2018-09-27 17:08:28 +03:00
|
|
|
if (!result)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
freeaddrinfo(result);
|
|
|
|
return TRUE;
|
2018-08-08 13:26:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL rdp_client_redirect_try_fqdn(rdpSettings* settings)
|
|
|
|
{
|
|
|
|
if (settings->RedirectionFlags & LB_TARGET_FQDN)
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
if (settings->GatewayEnabled ||
|
|
|
|
rdp_client_redirect_resolvable(settings->RedirectionTargetFQDN))
|
2018-08-08 13:26:57 +03:00
|
|
|
{
|
2022-02-02 11:41:25 +03:00
|
|
|
if (!freerdp_settings_set_string(settings, FreeRDP_ServerHostname,
|
|
|
|
settings->RedirectionTargetFQDN))
|
2018-08-08 13:26:57 +03:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL rdp_client_redirect_try_ip(rdpSettings* settings)
|
|
|
|
{
|
|
|
|
if (settings->RedirectionFlags & LB_TARGET_NET_ADDRESS)
|
|
|
|
{
|
2022-02-02 11:41:25 +03:00
|
|
|
if (!freerdp_settings_set_string(settings, FreeRDP_ServerHostname,
|
|
|
|
settings->TargetNetAddress))
|
2018-08-08 13:26:57 +03:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL rdp_client_redirect_try_netbios(rdpSettings* settings)
|
|
|
|
{
|
|
|
|
if (settings->RedirectionFlags & LB_TARGET_NETBIOS_NAME)
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
if (settings->GatewayEnabled ||
|
|
|
|
rdp_client_redirect_resolvable(settings->RedirectionTargetNetBiosName))
|
2018-08-08 13:26:57 +03:00
|
|
|
{
|
2022-02-02 11:41:25 +03:00
|
|
|
if (!freerdp_settings_set_string(settings, FreeRDP_ServerHostname,
|
|
|
|
settings->RedirectionTargetNetBiosName))
|
2018-08-08 13:26:57 +03:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-10-09 10:38:39 +04:00
|
|
|
BOOL rdp_client_redirect(rdpRdp* rdp)
|
2011-09-04 00:36:27 +04:00
|
|
|
{
|
2013-11-01 22:13:09 +04:00
|
|
|
BOOL status;
|
2018-04-09 15:03:05 +03:00
|
|
|
rdpSettings* settings;
|
|
|
|
|
2018-05-06 12:17:08 +03:00
|
|
|
if (!rdp_client_disconnect_and_clear(rdp))
|
|
|
|
return FALSE;
|
2011-09-04 00:36:27 +04:00
|
|
|
|
2022-06-27 12:44:35 +03:00
|
|
|
freerdp_channels_disconnect(rdp->context->channels, rdp->context->instance);
|
|
|
|
freerdp_channels_close(rdp->context->channels, rdp->context->instance);
|
|
|
|
freerdp_channels_free(rdp->context->channels);
|
|
|
|
rdp->context->channels = freerdp_channels_new(rdp->context->instance);
|
|
|
|
WINPR_ASSERT(rdp->context->channels);
|
|
|
|
|
2015-06-17 23:08:02 +03:00
|
|
|
if (rdp_redirection_apply_settings(rdp) != 0)
|
|
|
|
return FALSE;
|
2013-11-04 01:25:56 +04:00
|
|
|
|
2021-09-17 09:59:10 +03:00
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
|
|
|
|
settings = rdp->settings;
|
|
|
|
WINPR_ASSERT(settings);
|
|
|
|
|
2013-11-04 01:25:56 +04:00
|
|
|
if (settings->RedirectionFlags & LB_LOAD_BALANCE_INFO)
|
2011-12-10 19:54:09 +04:00
|
|
|
{
|
2019-07-02 12:53:14 +03:00
|
|
|
if (settings->LoadBalanceInfo && (settings->LoadBalanceInfoLength > 0))
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
if (!nego_set_routing_token(rdp->nego, settings->LoadBalanceInfo,
|
|
|
|
settings->LoadBalanceInfoLength))
|
2019-07-02 12:53:14 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
2011-12-10 19:54:09 +04:00
|
|
|
}
|
2012-01-29 23:49:54 +04:00
|
|
|
else
|
2011-12-10 19:54:09 +04:00
|
|
|
{
|
2018-08-08 13:26:57 +03:00
|
|
|
BOOL haveRedirectAddress = FALSE;
|
|
|
|
UINT32 redirectionMask = settings->RedirectionPreferType;
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2018-08-08 13:26:57 +03:00
|
|
|
do
|
2012-01-29 23:49:54 +04:00
|
|
|
{
|
2018-08-08 13:26:57 +03:00
|
|
|
const BOOL tryFQDN = (redirectionMask & 0x01) == 0;
|
|
|
|
const BOOL tryNetAddress = (redirectionMask & 0x02) == 0;
|
|
|
|
const BOOL tryNetbios = (redirectionMask & 0x04) == 0;
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2018-08-08 13:26:57 +03:00
|
|
|
if (tryFQDN && !haveRedirectAddress)
|
|
|
|
haveRedirectAddress = rdp_client_redirect_try_fqdn(settings);
|
|
|
|
|
|
|
|
if (tryNetAddress && !haveRedirectAddress)
|
|
|
|
haveRedirectAddress = rdp_client_redirect_try_ip(settings);
|
|
|
|
|
|
|
|
if (tryNetbios && !haveRedirectAddress)
|
|
|
|
haveRedirectAddress = rdp_client_redirect_try_netbios(settings);
|
|
|
|
|
|
|
|
redirectionMask >>= 3;
|
2019-11-06 17:24:51 +03:00
|
|
|
} while (!haveRedirectAddress && (redirectionMask != 0));
|
2011-11-24 19:45:34 +04:00
|
|
|
}
|
2011-09-04 00:36:27 +04:00
|
|
|
|
2013-11-04 01:25:56 +04:00
|
|
|
if (settings->RedirectionFlags & LB_USERNAME)
|
2011-12-10 19:54:09 +04:00
|
|
|
{
|
2021-12-15 11:30:18 +03:00
|
|
|
if (!freerdp_settings_set_string(
|
|
|
|
settings, FreeRDP_Username,
|
|
|
|
freerdp_settings_get_string(settings, FreeRDP_RedirectionUsername)))
|
2015-06-17 23:08:02 +03:00
|
|
|
return FALSE;
|
2011-11-24 19:45:34 +04:00
|
|
|
}
|
2011-09-04 00:36:27 +04:00
|
|
|
|
2013-11-04 01:25:56 +04:00
|
|
|
if (settings->RedirectionFlags & LB_DOMAIN)
|
2011-12-10 19:54:09 +04:00
|
|
|
{
|
2021-12-15 11:30:18 +03:00
|
|
|
if (!freerdp_settings_set_string(
|
|
|
|
settings, FreeRDP_Domain,
|
|
|
|
freerdp_settings_get_string(settings, FreeRDP_RedirectionDomain)))
|
2015-06-17 23:08:02 +03:00
|
|
|
return FALSE;
|
2011-12-21 23:59:31 +04:00
|
|
|
}
|
|
|
|
|
2022-03-29 12:12:52 +03:00
|
|
|
WINPR_ASSERT(rdp->context);
|
|
|
|
WINPR_ASSERT(rdp->context->instance);
|
|
|
|
if (!IFCALLRESULT(TRUE, rdp->context->instance->Redirect, rdp->context->instance))
|
2021-12-15 12:58:43 +03:00
|
|
|
return FALSE;
|
|
|
|
|
2022-06-27 12:44:35 +03:00
|
|
|
BOOL ok = IFCALLRESULT(TRUE, rdp->context->instance->LoadChannels, rdp->context->instance);
|
|
|
|
if (!ok)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (CHANNEL_RC_OK !=
|
|
|
|
freerdp_channels_pre_connect(rdp->context->channels, rdp->context->instance))
|
|
|
|
return FALSE;
|
|
|
|
|
2013-11-01 22:13:09 +04:00
|
|
|
status = rdp_client_connect(rdp);
|
|
|
|
|
2018-07-10 13:04:27 +03:00
|
|
|
if (status)
|
2018-07-13 14:11:38 +03:00
|
|
|
status = rdp_client_reconnect_channels(rdp, TRUE);
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2013-11-01 22:13:09 +04:00
|
|
|
return status;
|
2011-09-04 00:36:27 +04:00
|
|
|
}
|
|
|
|
|
2015-02-06 22:21:26 +03:00
|
|
|
BOOL rdp_client_reconnect(rdpRdp* rdp)
|
|
|
|
{
|
|
|
|
BOOL status;
|
2018-05-06 12:17:08 +03:00
|
|
|
|
2018-04-11 10:30:40 +03:00
|
|
|
if (!rdp_client_disconnect_and_clear(rdp))
|
2018-04-09 12:08:46 +03:00
|
|
|
return FALSE;
|
2015-02-06 22:21:26 +03:00
|
|
|
|
|
|
|
status = rdp_client_connect(rdp);
|
|
|
|
|
2018-07-10 13:04:27 +03:00
|
|
|
if (status)
|
2018-07-13 14:11:38 +03:00
|
|
|
status = rdp_client_reconnect_channels(rdp, FALSE);
|
2015-02-07 01:35:14 +03:00
|
|
|
|
2015-02-06 22:21:26 +03:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2018-07-10 13:21:38 +03:00
|
|
|
static const BYTE fips_ivec[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
|
2013-11-01 07:35:24 +04:00
|
|
|
|
2012-10-09 10:38:39 +04:00
|
|
|
static BOOL rdp_client_establish_keys(rdpRdp* rdp)
|
2011-09-05 22:02:52 +04:00
|
|
|
{
|
2012-10-09 11:01:37 +04:00
|
|
|
BYTE* mod;
|
|
|
|
BYTE* exp;
|
2013-03-21 23:19:33 +04:00
|
|
|
wStream* s;
|
2012-11-08 20:16:54 +04:00
|
|
|
UINT32 length;
|
|
|
|
UINT32 key_len;
|
2014-04-03 13:36:51 +04:00
|
|
|
int status = 0;
|
2014-08-11 19:23:23 +04:00
|
|
|
BOOL ret = FALSE;
|
|
|
|
rdpSettings* settings;
|
|
|
|
BYTE* crypt_client_random = NULL;
|
|
|
|
settings = rdp->settings;
|
2011-09-05 22:02:52 +04:00
|
|
|
|
Standard RDP Security Layer Levels/Method Overhaul
[MS-RDPBCGR] Section 5.3 describes the encryption level and method values for
standard RDP security.
Looking at the current usage of these values in the FreeRDP code gives me
reason to believe that there is a certain lack of understanding of how these
values should be handled.
The encryption level is only configured on the server side in the "Encryption
Level" setting found in the Remote Desktop Session Host Configuration RDP-Tcp
properties dialog and this value is never transferred from the client to the
server over the wire.
The possible options are "None", "Low", "Client Compatible", "High" and
"FIPS Compliant". The client receices this value in the Server Security Data
block (TS_UD_SC_SEC1), probably only for informational purposes and maybe to
give the client the possibility to verify if the server's decision for the
encryption method confirms to the server's encryption level.
The possible encryption methods are "NONE", "40BIT", "56BIT", "128BIT" and
"FIPS" and the RDP client advertises the ones it supports to the server in the
Client Security Data block (TS_UD_CS_SEC).
The server's configured encryption level value restricts the possible final
encryption method.
Something that I was not able to find in the documentation is the priority
level of the individual encryption methods based on which the server makes its
final method decision if there are several options.
My analysis with Windows Servers reveiled that the order is 128, 56, 40, FIPS.
The server only chooses FIPS if the level is "FIPS Comliant" or if it is the
only method advertised by the client.
Bottom line:
* FreeRDP's client side does not need to set settings->EncryptionLevel
(which was done quite frequently).
* FreeRDP's server side does not have to set the supported encryption methods
list in settings->EncryptionMethods
Changes in this commit:
Removed unnecessary/confusing changes of EncryptionLevel/Methods settings
Refactor settings->DisableEncryption
* This value actually means "Advanced RDP Encryption (NLA/TLS) is NOT used"
* The old name caused lots of confusion among developers
* Renamed it to "UseRdpSecurityLayer" (the compare logic stays untouched)
Any client's setting of settings->EncryptionMethods were annihilated
* All clients "want" to set all supported methods
* Some clients forgot 56bit because 56bit was not supported at the time the
code was written
* settings->EncryptionMethods was overwritten anyways in nego_connect()
* Removed all client side settings of settings->EncryptionMethods
The default is "None" (0)
* Changed nego_connect() to advertise all supported methods if
settings->EncryptionMethods is 0 (None)
* Added a commandline option /encryption-methods:comma separated list of the
values "40", "56", "128", "FIPS". E.g. /encryption-methods:56,128
* Print warning if server chooses non-advertised method
Verify received level and method in client's gcc_read_server_security_data
* Only accept valid/known encryption methods
* Verify encryption level/method combinations according to MS-RDPBCGR 5.3.2
Server implementations can now set settings->EncryptionLevel
* The default for settings->EncryptionLevel is 0 (None)
* nego_send_negotiation_response() changes it to ClientCompatible in that case
* default to ClientCompatible if the server implementation set an invalid level
Fix server's gcc_write_server_security_data
* Verify server encryption level value set by server implementations
* Choose rdp encryption method based on level and supported client methods
* Moved FIPS to the lowest priority (only used if other methods are possible)
Updated sample server
* Support RDP Security (RdpKeyFile was not set)
* Added commented sample code for setting the security level
2014-12-12 04:17:12 +03:00
|
|
|
if (!settings->UseRdpSecurityLayer)
|
2011-09-05 22:02:52 +04:00
|
|
|
{
|
|
|
|
/* no RDP encryption */
|
2012-10-09 10:31:28 +04:00
|
|
|
return TRUE;
|
2011-09-05 22:02:52 +04:00
|
|
|
}
|
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT))
|
|
|
|
return FALSE;
|
2022-10-21 11:31:14 +03:00
|
|
|
|
2011-09-13 10:40:27 +04:00
|
|
|
/* encrypt client random */
|
2015-05-11 10:07:39 +03:00
|
|
|
free(settings->ClientRandom);
|
2014-08-11 19:23:23 +04:00
|
|
|
settings->ClientRandomLength = CLIENT_RANDOM_LENGTH;
|
|
|
|
settings->ClientRandom = malloc(settings->ClientRandomLength);
|
2013-11-01 07:35:24 +04:00
|
|
|
|
2014-08-11 19:23:23 +04:00
|
|
|
if (!settings->ClientRandom)
|
2013-11-01 07:35:24 +04:00
|
|
|
return FALSE;
|
|
|
|
|
2016-02-28 00:39:45 +03:00
|
|
|
winpr_RAND(settings->ClientRandom, settings->ClientRandomLength);
|
2014-08-11 19:23:23 +04:00
|
|
|
key_len = settings->RdpServerCertificate->cert_info.ModulusLength;
|
|
|
|
mod = settings->RdpServerCertificate->cert_info.Modulus;
|
|
|
|
exp = settings->RdpServerCertificate->cert_info.exponent;
|
2014-04-08 21:38:01 +04:00
|
|
|
/*
|
|
|
|
* client random must be (bitlen / 8) + 8 - see [MS-RDPBCGR] 5.3.4.1
|
|
|
|
* for details
|
|
|
|
*/
|
2017-05-30 11:46:43 +03:00
|
|
|
crypt_client_random = calloc(key_len + 8, 1);
|
2014-08-11 19:23:23 +04:00
|
|
|
|
2014-04-03 13:36:51 +04:00
|
|
|
if (!crypt_client_random)
|
|
|
|
return FALSE;
|
2014-08-11 19:23:23 +04:00
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
crypto_rsa_public_encrypt(settings->ClientRandom, settings->ClientRandomLength, key_len, mod,
|
|
|
|
exp, crypt_client_random);
|
2011-09-13 10:40:27 +04:00
|
|
|
/* send crypt client random to server */
|
2012-01-25 14:12:37 +04:00
|
|
|
length = RDP_PACKET_HEADER_MAX_LENGTH + RDP_SECURITY_HEADER_LENGTH + 4 + key_len + 8;
|
2013-05-15 21:17:29 +04:00
|
|
|
s = Stream_New(NULL, length);
|
2012-11-08 08:29:24 +04:00
|
|
|
|
2015-05-29 14:46:50 +03:00
|
|
|
if (!s)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Stream_New failed!");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2022-10-21 10:25:53 +03:00
|
|
|
if (!rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID))
|
|
|
|
goto end;
|
2014-04-02 16:17:39 +04:00
|
|
|
rdp_write_security_header(s, SEC_EXCHANGE_PKT | SEC_LICENSE_ENCRYPT_SC);
|
2011-09-13 10:40:27 +04:00
|
|
|
length = key_len + 8;
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Write_UINT32(s, length);
|
|
|
|
Stream_Write(s, crypt_client_random, length);
|
2013-05-15 20:14:26 +04:00
|
|
|
Stream_SealLength(s);
|
2014-04-03 13:36:51 +04:00
|
|
|
status = transport_write(rdp->mcs->transport, s);
|
2013-05-15 21:17:29 +04:00
|
|
|
Stream_Free(s, TRUE);
|
|
|
|
|
2014-04-03 13:36:51 +04:00
|
|
|
if (status < 0)
|
|
|
|
goto end;
|
|
|
|
|
2014-12-01 13:12:34 +03:00
|
|
|
rdp->do_crypt_license = TRUE;
|
|
|
|
|
2011-09-27 09:30:58 +04:00
|
|
|
/* now calculate encrypt / decrypt and update keys */
|
2014-08-11 19:23:23 +04:00
|
|
|
if (!security_establish_keys(settings->ClientRandom, rdp))
|
2014-04-03 13:36:51 +04:00
|
|
|
goto end;
|
2011-09-13 10:40:27 +04:00
|
|
|
|
2012-10-09 10:31:28 +04:00
|
|
|
rdp->do_crypt = TRUE;
|
2013-05-15 21:17:29 +04:00
|
|
|
|
2014-08-11 19:23:23 +04:00
|
|
|
if (settings->SaltedChecksum)
|
2012-10-09 10:31:28 +04:00
|
|
|
rdp->do_secure_checksum = TRUE;
|
2011-09-16 03:54:03 +04:00
|
|
|
|
2014-08-11 19:23:23 +04:00
|
|
|
if (settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
|
2011-09-16 03:54:03 +04:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
rdp->fips_encrypt = winpr_Cipher_New(WINPR_CIPHER_DES_EDE3_CBC, WINPR_ENCRYPT,
|
|
|
|
rdp->fips_encrypt_key, fips_ivec);
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2016-02-29 11:00:02 +03:00
|
|
|
if (!rdp->fips_encrypt)
|
2014-03-26 02:13:08 +04:00
|
|
|
{
|
2014-09-12 16:36:29 +04:00
|
|
|
WLog_ERR(TAG, "unable to allocate des3 encrypt key");
|
2014-04-03 13:36:51 +04:00
|
|
|
goto end;
|
2014-03-26 02:13:08 +04:00
|
|
|
}
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
rdp->fips_decrypt = winpr_Cipher_New(WINPR_CIPHER_DES_EDE3_CBC, WINPR_DECRYPT,
|
|
|
|
rdp->fips_decrypt_key, fips_ivec);
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2016-02-29 11:00:02 +03:00
|
|
|
if (!rdp->fips_decrypt)
|
2014-03-26 02:13:08 +04:00
|
|
|
{
|
2014-09-12 16:36:29 +04:00
|
|
|
WLog_ERR(TAG, "unable to allocate des3 decrypt key");
|
2014-04-03 13:36:51 +04:00
|
|
|
goto end;
|
2014-03-26 02:13:08 +04:00
|
|
|
}
|
2011-09-16 03:54:03 +04:00
|
|
|
|
2014-04-03 13:36:51 +04:00
|
|
|
ret = TRUE;
|
|
|
|
goto end;
|
2011-09-16 03:54:03 +04:00
|
|
|
}
|
|
|
|
|
2022-11-25 12:12:25 +03:00
|
|
|
if (!rdp_reset_rc4_encrypt_keys(rdp))
|
|
|
|
goto end;
|
|
|
|
if (!rdp_reset_rc4_decrypt_keys(rdp))
|
2016-02-28 13:12:17 +03:00
|
|
|
goto end;
|
2011-09-13 10:40:27 +04:00
|
|
|
|
2014-04-03 13:36:51 +04:00
|
|
|
ret = TRUE;
|
|
|
|
end:
|
2015-05-11 10:07:39 +03:00
|
|
|
free(crypt_client_random);
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2016-02-28 13:12:17 +03:00
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
winpr_Cipher_Free(rdp->fips_decrypt);
|
|
|
|
winpr_Cipher_Free(rdp->fips_encrypt);
|
|
|
|
rdp->fips_decrypt = NULL;
|
|
|
|
rdp->fips_encrypt = NULL;
|
2022-11-25 12:12:25 +03:00
|
|
|
|
|
|
|
rdp_free_rc4_decrypt_keys(rdp);
|
|
|
|
rdp_free_rc4_encrypt_keys(rdp);
|
2016-02-28 13:12:17 +03:00
|
|
|
}
|
|
|
|
|
2014-04-03 13:36:51 +04:00
|
|
|
return ret;
|
2012-01-25 19:57:23 +04:00
|
|
|
}
|
|
|
|
|
2013-07-19 01:15:10 +04:00
|
|
|
BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
|
2012-01-25 19:57:23 +04:00
|
|
|
{
|
2014-04-03 14:18:08 +04:00
|
|
|
BYTE* client_random = NULL;
|
|
|
|
BYTE* crypt_client_random = NULL;
|
2012-10-09 11:26:39 +04:00
|
|
|
UINT32 rand_len, key_len;
|
2012-10-09 11:01:37 +04:00
|
|
|
UINT16 channel_id, length, sec_flags;
|
|
|
|
BYTE* mod;
|
|
|
|
BYTE* priv_exp;
|
2014-04-03 13:36:51 +04:00
|
|
|
BOOL ret = FALSE;
|
2012-01-25 19:57:23 +04:00
|
|
|
|
Standard RDP Security Layer Levels/Method Overhaul
[MS-RDPBCGR] Section 5.3 describes the encryption level and method values for
standard RDP security.
Looking at the current usage of these values in the FreeRDP code gives me
reason to believe that there is a certain lack of understanding of how these
values should be handled.
The encryption level is only configured on the server side in the "Encryption
Level" setting found in the Remote Desktop Session Host Configuration RDP-Tcp
properties dialog and this value is never transferred from the client to the
server over the wire.
The possible options are "None", "Low", "Client Compatible", "High" and
"FIPS Compliant". The client receices this value in the Server Security Data
block (TS_UD_SC_SEC1), probably only for informational purposes and maybe to
give the client the possibility to verify if the server's decision for the
encryption method confirms to the server's encryption level.
The possible encryption methods are "NONE", "40BIT", "56BIT", "128BIT" and
"FIPS" and the RDP client advertises the ones it supports to the server in the
Client Security Data block (TS_UD_CS_SEC).
The server's configured encryption level value restricts the possible final
encryption method.
Something that I was not able to find in the documentation is the priority
level of the individual encryption methods based on which the server makes its
final method decision if there are several options.
My analysis with Windows Servers reveiled that the order is 128, 56, 40, FIPS.
The server only chooses FIPS if the level is "FIPS Comliant" or if it is the
only method advertised by the client.
Bottom line:
* FreeRDP's client side does not need to set settings->EncryptionLevel
(which was done quite frequently).
* FreeRDP's server side does not have to set the supported encryption methods
list in settings->EncryptionMethods
Changes in this commit:
Removed unnecessary/confusing changes of EncryptionLevel/Methods settings
Refactor settings->DisableEncryption
* This value actually means "Advanced RDP Encryption (NLA/TLS) is NOT used"
* The old name caused lots of confusion among developers
* Renamed it to "UseRdpSecurityLayer" (the compare logic stays untouched)
Any client's setting of settings->EncryptionMethods were annihilated
* All clients "want" to set all supported methods
* Some clients forgot 56bit because 56bit was not supported at the time the
code was written
* settings->EncryptionMethods was overwritten anyways in nego_connect()
* Removed all client side settings of settings->EncryptionMethods
The default is "None" (0)
* Changed nego_connect() to advertise all supported methods if
settings->EncryptionMethods is 0 (None)
* Added a commandline option /encryption-methods:comma separated list of the
values "40", "56", "128", "FIPS". E.g. /encryption-methods:56,128
* Print warning if server chooses non-advertised method
Verify received level and method in client's gcc_read_server_security_data
* Only accept valid/known encryption methods
* Verify encryption level/method combinations according to MS-RDPBCGR 5.3.2
Server implementations can now set settings->EncryptionLevel
* The default for settings->EncryptionLevel is 0 (None)
* nego_send_negotiation_response() changes it to ClientCompatible in that case
* default to ClientCompatible if the server implementation set an invalid level
Fix server's gcc_write_server_security_data
* Verify server encryption level value set by server implementations
* Choose rdp encryption method based on level and supported client methods
* Moved FIPS to the lowest priority (only used if other methods are possible)
Updated sample server
* Support RDP Security (RdpKeyFile was not set)
* Added commented sample code for setting the security level
2014-12-12 04:17:12 +03:00
|
|
|
if (!rdp->settings->UseRdpSecurityLayer)
|
2012-01-25 19:57:23 +04:00
|
|
|
{
|
|
|
|
/* No RDP Security. */
|
2012-10-09 10:31:28 +04:00
|
|
|
return TRUE;
|
2012-01-25 19:57:23 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!rdp_read_header(rdp, s, &length, &channel_id))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2012-09-24 12:40:32 +04:00
|
|
|
|
2017-05-29 11:50:22 +03:00
|
|
|
if (!rdp_read_security_header(s, &sec_flags, NULL))
|
2014-04-10 23:07:53 +04:00
|
|
|
{
|
2014-09-12 16:36:29 +04:00
|
|
|
WLog_ERR(TAG, "invalid security header");
|
2013-01-15 02:40:34 +04:00
|
|
|
return FALSE;
|
2014-04-10 23:07:53 +04:00
|
|
|
}
|
2012-09-24 12:40:32 +04:00
|
|
|
|
2012-01-25 19:57:23 +04:00
|
|
|
if ((sec_flags & SEC_EXCHANGE_PKT) == 0)
|
|
|
|
{
|
2014-09-12 16:36:29 +04:00
|
|
|
WLog_ERR(TAG, "missing SEC_EXCHANGE_PKT in security header");
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2012-01-25 19:57:23 +04:00
|
|
|
}
|
2012-09-24 12:40:32 +04:00
|
|
|
|
2014-09-19 03:38:04 +04:00
|
|
|
rdp->do_crypt_license = (sec_flags & SEC_LICENSE_ENCRYPT_SC) != 0 ? TRUE : FALSE;
|
|
|
|
|
2022-04-19 15:29:17 +03:00
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
|
2013-01-15 02:40:34 +04:00
|
|
|
return FALSE;
|
2013-07-19 01:15:10 +04:00
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read_UINT32(s, rand_len);
|
2013-07-19 01:15:10 +04:00
|
|
|
|
2014-03-26 02:13:08 +04:00
|
|
|
/* rand_len already includes 8 bytes of padding */
|
2022-04-19 15:29:17 +03:00
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, rand_len))
|
2013-01-15 02:40:34 +04:00
|
|
|
return FALSE;
|
|
|
|
|
2012-11-08 08:29:24 +04:00
|
|
|
key_len = rdp->settings->RdpServerRsaKey->ModulusLength;
|
2014-04-03 13:36:51 +04:00
|
|
|
client_random = malloc(key_len);
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2014-04-03 13:36:51 +04:00
|
|
|
if (!client_random)
|
|
|
|
return FALSE;
|
2012-09-24 12:40:32 +04:00
|
|
|
|
2012-01-25 19:57:23 +04:00
|
|
|
if (rand_len != key_len + 8)
|
|
|
|
{
|
2014-09-12 16:36:29 +04:00
|
|
|
WLog_ERR(TAG, "invalid encrypted client random length");
|
2017-03-28 15:33:02 +03:00
|
|
|
free(client_random);
|
2016-02-28 13:12:17 +03:00
|
|
|
goto end;
|
2012-01-25 19:57:23 +04:00
|
|
|
}
|
2012-09-24 12:40:32 +04:00
|
|
|
|
2014-04-03 13:36:51 +04:00
|
|
|
crypt_client_random = calloc(1, rand_len);
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2014-04-03 13:36:51 +04:00
|
|
|
if (!crypt_client_random)
|
2017-03-28 15:33:02 +03:00
|
|
|
{
|
|
|
|
free(client_random);
|
2016-02-28 13:12:17 +03:00
|
|
|
goto end;
|
2017-03-28 15:33:02 +03:00
|
|
|
}
|
|
|
|
|
2013-05-09 00:09:16 +04:00
|
|
|
Stream_Read(s, crypt_client_random, rand_len);
|
2012-11-08 08:29:24 +04:00
|
|
|
mod = rdp->settings->RdpServerRsaKey->Modulus;
|
|
|
|
priv_exp = rdp->settings->RdpServerRsaKey->PrivateExponent;
|
2018-04-09 12:08:46 +03:00
|
|
|
|
|
|
|
if (crypto_rsa_private_decrypt(crypt_client_random, rand_len - 8, key_len, mod, priv_exp,
|
|
|
|
client_random) <= 0)
|
2017-03-21 12:32:17 +03:00
|
|
|
{
|
|
|
|
free(client_random);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
rdp->settings->ClientRandom = client_random;
|
|
|
|
rdp->settings->ClientRandomLength = 32;
|
2012-01-25 19:57:23 +04:00
|
|
|
|
|
|
|
/* now calculate encrypt / decrypt and update keys */
|
|
|
|
if (!security_establish_keys(client_random, rdp))
|
2014-04-03 13:36:51 +04:00
|
|
|
goto end;
|
2012-01-25 19:57:23 +04:00
|
|
|
|
2012-10-09 10:31:28 +04:00
|
|
|
rdp->do_crypt = TRUE;
|
2013-07-19 01:15:10 +04:00
|
|
|
|
2012-11-08 08:29:24 +04:00
|
|
|
if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
|
2012-01-25 19:57:23 +04:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
rdp->fips_encrypt = winpr_Cipher_New(WINPR_CIPHER_DES_EDE3_CBC, WINPR_ENCRYPT,
|
|
|
|
rdp->fips_encrypt_key, fips_ivec);
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2016-02-29 11:00:02 +03:00
|
|
|
if (!rdp->fips_encrypt)
|
2014-03-26 02:13:08 +04:00
|
|
|
{
|
2014-09-12 16:36:29 +04:00
|
|
|
WLog_ERR(TAG, "unable to allocate des3 encrypt key");
|
2014-04-03 13:36:51 +04:00
|
|
|
goto end;
|
2014-03-26 02:13:08 +04:00
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
rdp->fips_decrypt = winpr_Cipher_New(WINPR_CIPHER_DES_EDE3_CBC, WINPR_DECRYPT,
|
|
|
|
rdp->fips_decrypt_key, fips_ivec);
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2016-02-29 11:00:02 +03:00
|
|
|
if (!rdp->fips_decrypt)
|
2014-03-26 02:13:08 +04:00
|
|
|
{
|
2014-09-12 16:36:29 +04:00
|
|
|
WLog_ERR(TAG, "unable to allocate des3 decrypt key");
|
2014-04-03 13:36:51 +04:00
|
|
|
goto end;
|
2014-03-26 02:13:08 +04:00
|
|
|
}
|
2012-01-25 19:57:23 +04:00
|
|
|
|
2014-04-03 13:36:51 +04:00
|
|
|
ret = TRUE;
|
|
|
|
goto end;
|
2012-01-25 19:57:23 +04:00
|
|
|
}
|
|
|
|
|
2022-11-25 12:12:25 +03:00
|
|
|
if (!rdp_reset_rc4_encrypt_keys(rdp))
|
|
|
|
goto end;
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2022-11-25 12:12:25 +03:00
|
|
|
if (!rdp_reset_rc4_decrypt_keys(rdp))
|
2016-02-28 13:12:17 +03:00
|
|
|
goto end;
|
2014-03-26 02:13:08 +04:00
|
|
|
|
2020-02-20 10:22:19 +03:00
|
|
|
ret = tpkt_ensure_stream_consumed(s, length);
|
2014-04-03 13:36:51 +04:00
|
|
|
end:
|
2015-05-11 10:07:39 +03:00
|
|
|
free(crypt_client_random);
|
2012-01-25 19:57:23 +04:00
|
|
|
|
2016-02-28 13:12:17 +03:00
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
winpr_Cipher_Free(rdp->fips_encrypt);
|
|
|
|
winpr_Cipher_Free(rdp->fips_decrypt);
|
|
|
|
rdp->fips_encrypt = NULL;
|
|
|
|
rdp->fips_decrypt = NULL;
|
2022-11-25 12:12:25 +03:00
|
|
|
|
|
|
|
rdp_free_rc4_encrypt_keys(rdp);
|
|
|
|
rdp_free_rc4_decrypt_keys(rdp);
|
2016-02-28 13:12:17 +03:00
|
|
|
}
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2014-04-03 13:36:51 +04:00
|
|
|
return ret;
|
2011-09-05 22:02:52 +04:00
|
|
|
}
|
|
|
|
|
2013-03-21 23:19:33 +04:00
|
|
|
BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s)
|
2011-08-22 11:03:58 +04:00
|
|
|
{
|
2014-02-11 07:12:13 +04:00
|
|
|
UINT32 i;
|
2014-02-14 02:06:33 +04:00
|
|
|
UINT16 channelId;
|
|
|
|
BOOL allJoined = TRUE;
|
2014-02-16 01:32:38 +04:00
|
|
|
rdpMcs* mcs = rdp->mcs;
|
2011-08-22 11:03:58 +04:00
|
|
|
|
2014-02-16 01:32:38 +04:00
|
|
|
if (!mcs_recv_channel_join_confirm(mcs, s, &channelId))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2011-08-22 11:03:58 +04:00
|
|
|
|
2014-02-16 01:32:38 +04:00
|
|
|
if (!mcs->userChannelJoined)
|
2011-08-22 11:03:58 +04:00
|
|
|
{
|
2014-02-16 01:32:38 +04:00
|
|
|
if (channelId != mcs->userId)
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2013-02-15 05:39:56 +04:00
|
|
|
|
2014-02-16 01:32:38 +04:00
|
|
|
mcs->userChannelJoined = TRUE;
|
2011-08-22 11:03:58 +04:00
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN_REQUEST))
|
|
|
|
return FALSE;
|
2014-02-16 01:32:38 +04:00
|
|
|
if (!mcs_send_channel_join_request(mcs, MCS_GLOBAL_CHANNEL_ID))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN_RESPONSE))
|
|
|
|
return FALSE;
|
2011-08-22 11:03:58 +04:00
|
|
|
}
|
2014-02-16 01:32:38 +04:00
|
|
|
else if (!mcs->globalChannelJoined)
|
2011-08-22 11:03:58 +04:00
|
|
|
{
|
2014-02-14 02:06:33 +04:00
|
|
|
if (channelId != MCS_GLOBAL_CHANNEL_ID)
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2013-02-15 05:39:56 +04:00
|
|
|
|
2014-02-16 01:32:38 +04:00
|
|
|
mcs->globalChannelJoined = TRUE;
|
2011-08-22 11:03:58 +04:00
|
|
|
|
2014-02-16 01:32:38 +04:00
|
|
|
if (mcs->messageChannelId != 0)
|
2014-01-30 07:53:32 +04:00
|
|
|
{
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN_REQUEST))
|
|
|
|
return FALSE;
|
2014-02-16 01:32:38 +04:00
|
|
|
if (!mcs_send_channel_join_request(mcs, mcs->messageChannelId))
|
2014-01-30 07:53:32 +04:00
|
|
|
return FALSE;
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN_RESPONSE))
|
|
|
|
return FALSE;
|
2014-01-30 07:53:32 +04:00
|
|
|
|
2014-02-14 02:06:33 +04:00
|
|
|
allJoined = FALSE;
|
2014-01-30 07:53:32 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-02-16 01:32:38 +04:00
|
|
|
if (mcs->channelCount > 0)
|
2014-01-30 07:53:32 +04:00
|
|
|
{
|
2021-08-24 15:09:40 +03:00
|
|
|
const rdpMcsChannel* cur = &mcs->channels[0];
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN_REQUEST))
|
|
|
|
return FALSE;
|
2021-08-24 15:09:40 +03:00
|
|
|
if (!mcs_send_channel_join_request(mcs, cur->ChannelId))
|
2014-01-30 07:53:32 +04:00
|
|
|
return FALSE;
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp,
|
|
|
|
CONNECTION_STATE_MCS_CHANNEL_JOIN_RESPONSE))
|
|
|
|
return FALSE;
|
2014-01-30 07:53:32 +04:00
|
|
|
|
2014-02-14 02:06:33 +04:00
|
|
|
allJoined = FALSE;
|
2014-01-30 07:53:32 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-02-16 01:32:38 +04:00
|
|
|
else if ((mcs->messageChannelId != 0) && !mcs->messageChannelJoined)
|
2014-01-30 07:53:32 +04:00
|
|
|
{
|
2014-02-16 01:32:38 +04:00
|
|
|
if (channelId != mcs->messageChannelId)
|
2014-01-30 07:53:32 +04:00
|
|
|
return FALSE;
|
|
|
|
|
2014-02-16 01:32:38 +04:00
|
|
|
mcs->messageChannelJoined = TRUE;
|
2014-01-30 07:53:32 +04:00
|
|
|
|
2014-02-16 01:32:38 +04:00
|
|
|
if (mcs->channelCount > 0)
|
2011-08-22 11:03:58 +04:00
|
|
|
{
|
2021-08-24 15:09:40 +03:00
|
|
|
const rdpMcsChannel* cur = &mcs->channels[0];
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN_REQUEST))
|
|
|
|
return FALSE;
|
2021-08-24 15:09:40 +03:00
|
|
|
if (!mcs_send_channel_join_request(mcs, cur->ChannelId))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN_RESPONSE))
|
|
|
|
return FALSE;
|
2011-08-22 11:03:58 +04:00
|
|
|
|
2014-02-14 02:06:33 +04:00
|
|
|
allJoined = FALSE;
|
2011-08-22 11:03:58 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-02-16 01:32:38 +04:00
|
|
|
for (i = 0; i < mcs->channelCount; i++)
|
2011-08-22 11:03:58 +04:00
|
|
|
{
|
2021-08-24 15:09:40 +03:00
|
|
|
rdpMcsChannel* cur = &mcs->channels[i];
|
|
|
|
if (cur->joined)
|
2011-08-22 11:03:58 +04:00
|
|
|
continue;
|
|
|
|
|
2021-08-24 15:09:40 +03:00
|
|
|
if (cur->ChannelId != channelId)
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2011-07-12 09:16:59 +04:00
|
|
|
|
2021-08-24 15:09:40 +03:00
|
|
|
cur->joined = TRUE;
|
2011-08-22 11:03:58 +04:00
|
|
|
break;
|
|
|
|
}
|
2013-02-15 05:39:56 +04:00
|
|
|
|
2014-02-16 01:32:38 +04:00
|
|
|
if (i + 1 < mcs->channelCount)
|
2011-08-22 11:03:58 +04:00
|
|
|
{
|
2021-08-24 15:09:40 +03:00
|
|
|
const rdpMcsChannel* cur = &mcs->channels[i + 1];
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN_REQUEST))
|
|
|
|
return FALSE;
|
2021-08-24 15:09:40 +03:00
|
|
|
if (!mcs_send_channel_join_request(mcs, cur->ChannelId))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN_RESPONSE))
|
|
|
|
return FALSE;
|
2011-08-22 11:03:58 +04:00
|
|
|
|
2014-02-14 02:06:33 +04:00
|
|
|
allJoined = FALSE;
|
2011-08-22 11:03:58 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-16 01:32:38 +04:00
|
|
|
if (mcs->userChannelJoined && mcs->globalChannelJoined && allJoined)
|
2011-07-18 10:34:28 +04:00
|
|
|
{
|
2012-01-23 21:20:10 +04:00
|
|
|
if (!rdp_client_establish_keys(rdp))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2013-02-15 05:39:56 +04:00
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE))
|
|
|
|
return FALSE;
|
2011-08-22 11:03:58 +04:00
|
|
|
if (!rdp_send_client_info(rdp))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT_REQUEST))
|
|
|
|
return FALSE;
|
2011-08-22 11:03:58 +04:00
|
|
|
}
|
|
|
|
|
2012-10-09 10:31:28 +04:00
|
|
|
return TRUE;
|
2011-08-22 11:03:58 +04:00
|
|
|
}
|
|
|
|
|
2015-01-12 15:36:38 +03:00
|
|
|
BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream* s)
|
2014-01-30 07:53:32 +04:00
|
|
|
{
|
2021-10-04 09:48:38 +03:00
|
|
|
size_t pos;
|
2014-01-30 07:53:32 +04:00
|
|
|
UINT16 length;
|
|
|
|
UINT16 channelId;
|
|
|
|
|
2022-10-21 10:25:53 +03:00
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
WINPR_ASSERT(rdp->mcs);
|
|
|
|
|
2014-01-30 07:53:32 +04:00
|
|
|
/* If the MCS message channel has been joined... */
|
2014-02-14 02:06:33 +04:00
|
|
|
if (rdp->mcs->messageChannelId != 0)
|
2014-01-30 07:53:32 +04:00
|
|
|
{
|
|
|
|
/* Process any MCS message channel PDUs. */
|
2021-10-04 09:48:38 +03:00
|
|
|
pos = Stream_GetPosition(s);
|
2014-01-30 07:53:32 +04:00
|
|
|
|
|
|
|
if (rdp_read_header(rdp, s, &length, &channelId))
|
|
|
|
{
|
2014-02-14 02:06:33 +04:00
|
|
|
if (channelId == rdp->mcs->messageChannelId)
|
2014-01-30 07:53:32 +04:00
|
|
|
{
|
2016-12-02 12:46:43 +03:00
|
|
|
UINT16 securityFlags = 0;
|
2015-06-19 15:47:00 +03:00
|
|
|
|
2017-05-29 11:50:22 +03:00
|
|
|
if (!rdp_read_security_header(s, &securityFlags, &length))
|
2015-06-19 15:47:00 +03:00
|
|
|
return FALSE;
|
|
|
|
|
2017-05-15 14:10:10 +03:00
|
|
|
if (securityFlags & SEC_ENCRYPT)
|
|
|
|
{
|
2020-03-09 23:54:34 +03:00
|
|
|
if (!rdp_decrypt(rdp, s, &length, securityFlags))
|
2017-05-15 14:10:10 +03:00
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "rdp_decrypt failed");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-19 15:47:00 +03:00
|
|
|
if (rdp_recv_message_channel_pdu(rdp, s, securityFlags) == 0)
|
2020-02-20 10:22:19 +03:00
|
|
|
return tpkt_ensure_stream_consumed(s, length);
|
2014-01-30 07:53:32 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-04 09:48:38 +03:00
|
|
|
Stream_SetPosition(s, pos);
|
2014-01-30 07:53:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2022-11-11 14:26:28 +03:00
|
|
|
state_run_t rdp_client_connect_license(rdpRdp* rdp, wStream* s)
|
2011-08-22 11:03:58 +04:00
|
|
|
{
|
2022-11-11 14:26:28 +03:00
|
|
|
state_run_t status = STATE_RUN_FAILED;
|
2022-10-06 12:32:08 +03:00
|
|
|
LICENSE_STATE state;
|
|
|
|
UINT16 length, channelId, securityFlags;
|
2013-11-05 00:52:29 +04:00
|
|
|
|
2022-10-06 12:32:08 +03:00
|
|
|
if (!rdp_read_header(rdp, s, &length, &channelId))
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2011-08-22 11:03:58 +04:00
|
|
|
|
2022-10-06 12:32:08 +03:00
|
|
|
if (!rdp_read_security_header(s, &securityFlags, &length))
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2011-07-18 10:34:28 +04:00
|
|
|
|
2022-10-06 12:32:08 +03:00
|
|
|
if (securityFlags & SEC_ENCRYPT)
|
2011-08-22 11:03:58 +04:00
|
|
|
{
|
2022-10-06 12:32:08 +03:00
|
|
|
if (!rdp_decrypt(rdp, s, &length, securityFlags))
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2011-08-22 11:03:58 +04:00
|
|
|
}
|
|
|
|
|
2022-10-06 12:32:08 +03:00
|
|
|
if ((securityFlags & SEC_LICENSE_PKT) == 0)
|
2022-12-03 00:04:39 +03:00
|
|
|
{
|
|
|
|
char buffer[512] = { 0 };
|
|
|
|
char lbuffer[32] = { 0 };
|
2022-12-09 18:35:53 +03:00
|
|
|
WLog_ERR(TAG, "[%s] securityFlags=%s, missing required flag %s", __FUNCTION__,
|
2022-12-03 00:04:39 +03:00
|
|
|
rdp_security_flag_string(securityFlags, buffer, sizeof(buffer)),
|
|
|
|
rdp_security_flag_string(SEC_LICENSE_PKT, lbuffer, sizeof(lbuffer)));
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2022-12-03 00:04:39 +03:00
|
|
|
}
|
2022-10-21 10:25:53 +03:00
|
|
|
|
2022-10-06 12:32:08 +03:00
|
|
|
status = license_recv(rdp->license, s);
|
|
|
|
|
2022-11-11 14:26:28 +03:00
|
|
|
if (state_run_failed(status))
|
2022-10-06 12:32:08 +03:00
|
|
|
return status;
|
|
|
|
|
|
|
|
state = license_get_state(rdp->license);
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case LICENSE_STATE_ABORTED:
|
|
|
|
WLog_ERR(TAG, "license connection sequence aborted.");
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2022-10-06 12:32:08 +03:00
|
|
|
case LICENSE_STATE_COMPLETED:
|
2022-10-21 11:31:14 +03:00
|
|
|
if (rdp->settings->MultitransportFlags)
|
|
|
|
{
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(
|
|
|
|
rdp, CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING_REQUEST))
|
|
|
|
return STATE_RUN_FAILED;
|
2022-10-21 11:31:14 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(
|
|
|
|
rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE_DEMAND_ACTIVE))
|
|
|
|
return STATE_RUN_FAILED;
|
2022-10-21 11:31:14 +03:00
|
|
|
}
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_SUCCESS;
|
2022-10-06 12:32:08 +03:00
|
|
|
default:
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_SUCCESS;
|
2022-10-06 12:32:08 +03:00
|
|
|
}
|
2011-08-22 11:03:58 +04:00
|
|
|
}
|
|
|
|
|
2022-11-11 14:26:28 +03:00
|
|
|
state_run_t rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s)
|
2011-08-22 11:03:58 +04:00
|
|
|
{
|
2021-10-04 09:48:38 +03:00
|
|
|
size_t pos;
|
2020-02-20 10:22:19 +03:00
|
|
|
UINT16 length;
|
2022-10-21 10:53:24 +03:00
|
|
|
|
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
WINPR_ASSERT(s);
|
|
|
|
WINPR_ASSERT(rdp->settings);
|
2021-10-04 09:48:38 +03:00
|
|
|
|
|
|
|
pos = Stream_GetPosition(s);
|
2011-09-03 05:34:51 +04:00
|
|
|
|
2011-08-23 09:05:58 +04:00
|
|
|
if (!rdp_recv_demand_active(rdp, s))
|
2011-09-03 05:34:51 +04:00
|
|
|
{
|
2022-11-11 14:26:28 +03:00
|
|
|
state_run_t rc;
|
2013-04-05 22:53:22 +04:00
|
|
|
UINT16 channelId;
|
2021-10-04 09:48:38 +03:00
|
|
|
|
|
|
|
Stream_SetPosition(s, pos);
|
2020-02-20 10:22:19 +03:00
|
|
|
if (!rdp_recv_get_active_header(rdp, s, &channelId, &length))
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2013-04-30 06:35:15 +04:00
|
|
|
/* Was Stream_Seek(s, RDP_PACKET_HEADER_MAX_LENGTH);
|
2013-04-05 22:53:22 +04:00
|
|
|
* but the headers aren't always that length,
|
|
|
|
* so that could result in a bad offset.
|
|
|
|
*/
|
2020-02-20 10:22:19 +03:00
|
|
|
rc = rdp_recv_out_of_sequence_pdu(rdp, s);
|
2022-11-11 14:26:28 +03:00
|
|
|
if (state_run_failed(rc))
|
2020-02-20 10:22:19 +03:00
|
|
|
return rc;
|
|
|
|
if (!tpkt_ensure_stream_consumed(s, length))
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2020-02-20 10:22:19 +03:00
|
|
|
return rc;
|
2011-09-03 05:34:51 +04:00
|
|
|
}
|
2011-08-22 11:03:58 +04:00
|
|
|
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_SUCCESS;
|
2011-12-19 00:15:48 +04:00
|
|
|
}
|
|
|
|
|
2022-11-11 14:26:28 +03:00
|
|
|
state_run_t rdp_client_connect_finalize(rdpRdp* rdp)
|
2011-12-19 00:15:48 +04:00
|
|
|
{
|
2011-08-22 11:03:58 +04:00
|
|
|
/**
|
|
|
|
* [MS-RDPBCGR] 1.3.1.1 - 8.
|
2019-11-06 17:24:51 +03:00
|
|
|
* The client-to-server PDUs sent during this phase have no dependencies on any of the
|
|
|
|
* server-to- client PDUs; they may be sent as a single batch, provided that sequencing is
|
|
|
|
* maintained.
|
2011-08-22 11:03:58 +04:00
|
|
|
*/
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION_SYNC))
|
|
|
|
return STATE_RUN_FAILED;
|
|
|
|
|
2011-08-22 11:03:58 +04:00
|
|
|
if (!rdp_send_client_synchronize_pdu(rdp))
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2013-07-19 01:15:10 +04:00
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION_COOPERATE))
|
|
|
|
return STATE_RUN_FAILED;
|
2011-08-22 11:03:58 +04:00
|
|
|
if (!rdp_send_client_control_pdu(rdp, CTRLACTION_COOPERATE))
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2013-07-19 01:15:10 +04:00
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION_REQUEST_CONTROL))
|
|
|
|
return STATE_RUN_FAILED;
|
2011-08-22 11:03:58 +04:00
|
|
|
if (!rdp_send_client_control_pdu(rdp, CTRLACTION_REQUEST_CONTROL))
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2018-04-09 12:08:46 +03:00
|
|
|
|
2013-06-13 22:24:17 +04:00
|
|
|
/**
|
|
|
|
* [MS-RDPBCGR] 2.2.1.17
|
|
|
|
* Client persistent key list must be sent if a bitmap is
|
|
|
|
* stored in persistent bitmap cache or the server has advertised support for bitmap
|
|
|
|
* host cache and a deactivation reactivation sequence is *not* in progress.
|
|
|
|
*/
|
2013-07-19 01:15:10 +04:00
|
|
|
|
2022-06-23 10:59:24 +03:00
|
|
|
if (!rdp_finalize_is_flag_set(rdp, FINALIZE_DEACTIVATE_REACTIVATE) &&
|
|
|
|
rdp->settings->BitmapCachePersistEnabled)
|
2013-07-19 01:15:10 +04:00
|
|
|
{
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION_PERSISTENT_KEY_LIST))
|
|
|
|
return STATE_RUN_FAILED;
|
2013-06-13 22:24:17 +04:00
|
|
|
if (!rdp_send_client_persistent_key_list_pdu(rdp))
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2013-07-19 01:15:10 +04:00
|
|
|
}
|
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION_FONT_LIST))
|
|
|
|
return STATE_RUN_FAILED;
|
2011-08-22 11:03:58 +04:00
|
|
|
if (!rdp_send_client_font_list_pdu(rdp, FONTLIST_FIRST | FONTLIST_LAST))
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2011-08-22 11:03:58 +04:00
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_client_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION_CLIENT_SYNC))
|
|
|
|
return STATE_RUN_FAILED;
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_SUCCESS;
|
2011-07-24 00:40:33 +04:00
|
|
|
}
|
|
|
|
|
2022-11-08 13:54:03 +03:00
|
|
|
BOOL rdp_client_transition_to_state(rdpRdp* rdp, CONNECTION_STATE state)
|
2013-07-19 01:15:10 +04:00
|
|
|
{
|
2022-10-21 11:31:14 +03:00
|
|
|
const char* name = rdp_state_string(state);
|
2013-07-19 01:15:10 +04:00
|
|
|
|
2022-10-21 11:31:14 +03:00
|
|
|
WLog_DBG(TAG, "%s %s --> %s", __FUNCTION__, rdp_get_state_string(rdp), name);
|
2022-11-08 13:54:03 +03:00
|
|
|
if (!rdp_set_state(rdp, state))
|
|
|
|
return FALSE;
|
2021-09-03 13:17:30 +03:00
|
|
|
|
2013-07-19 01:15:10 +04:00
|
|
|
switch (state)
|
|
|
|
{
|
2022-10-21 11:31:14 +03:00
|
|
|
case CONNECTION_STATE_FINALIZATION_SYNC:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_COOPERATE:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_REQUEST_CONTROL:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_PERSISTENT_KEY_LIST:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_FONT_LIST:
|
2013-07-19 01:15:10 +04:00
|
|
|
update_reset_state(rdp->update);
|
2022-11-08 13:54:03 +03:00
|
|
|
if (!rdp_finalize_reset_flags(rdp, FALSE))
|
|
|
|
return FALSE;
|
2013-07-19 01:15:10 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CONNECTION_STATE_ACTIVE:
|
2021-09-03 13:17:30 +03:00
|
|
|
{
|
2022-11-08 13:54:03 +03:00
|
|
|
ActivatedEventArgs activatedEvent = { 0 };
|
2021-09-03 13:17:30 +03:00
|
|
|
rdpContext* context = rdp->context;
|
|
|
|
EventArgsInit(&activatedEvent, "libfreerdp");
|
2022-06-23 10:59:24 +03:00
|
|
|
activatedEvent.firstActivation =
|
|
|
|
!rdp_finalize_is_flag_set(rdp, FINALIZE_DEACTIVATE_REACTIVATE);
|
2022-07-06 10:36:53 +03:00
|
|
|
PubSub_OnActivated(rdp->pubSub, context, &activatedEvent);
|
2022-06-23 08:57:38 +03:00
|
|
|
}
|
2021-02-08 12:41:34 +03:00
|
|
|
|
2022-06-23 08:57:38 +03:00
|
|
|
break;
|
2013-07-19 01:15:10 +04:00
|
|
|
|
2022-06-23 08:57:38 +03:00
|
|
|
default:
|
|
|
|
break;
|
2013-07-19 01:15:10 +04:00
|
|
|
}
|
|
|
|
|
2021-02-08 12:41:34 +03:00
|
|
|
{
|
2022-11-08 13:54:03 +03:00
|
|
|
ConnectionStateChangeEventArgs stateEvent = { 0 };
|
2021-02-08 12:41:34 +03:00
|
|
|
rdpContext* context = rdp->context;
|
|
|
|
EventArgsInit(&stateEvent, "libfreerdp");
|
2021-09-03 09:17:27 +03:00
|
|
|
stateEvent.state = rdp_get_state(rdp);
|
|
|
|
stateEvent.active = rdp_get_state(rdp) == CONNECTION_STATE_ACTIVE;
|
2022-07-06 10:36:53 +03:00
|
|
|
PubSub_OnConnectionStateChange(rdp->pubSub, context, &stateEvent);
|
2021-02-08 12:41:34 +03:00
|
|
|
}
|
|
|
|
|
2022-11-08 13:54:03 +03:00
|
|
|
return TRUE;
|
2013-07-19 01:15:10 +04:00
|
|
|
}
|
|
|
|
|
2013-03-21 23:19:33 +04:00
|
|
|
BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s)
|
2011-08-19 05:54:43 +04:00
|
|
|
{
|
2018-11-20 18:38:06 +03:00
|
|
|
UINT32 SelectedProtocol = 0;
|
|
|
|
UINT32 RequestedProtocols;
|
2012-10-09 10:38:39 +04:00
|
|
|
BOOL status;
|
2021-09-17 09:59:10 +03:00
|
|
|
rdpSettings* settings;
|
|
|
|
rdpNego* nego;
|
|
|
|
|
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
WINPR_ASSERT(s);
|
|
|
|
|
|
|
|
settings = rdp->settings;
|
|
|
|
WINPR_ASSERT(settings);
|
|
|
|
|
|
|
|
nego = rdp->nego;
|
|
|
|
WINPR_ASSERT(nego);
|
|
|
|
|
2012-10-09 10:31:28 +04:00
|
|
|
transport_set_blocking_mode(rdp->transport, TRUE);
|
2011-08-19 09:35:29 +04:00
|
|
|
|
2014-03-26 02:13:08 +04:00
|
|
|
if (!nego_read_request(nego, s))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2012-01-25 20:08:10 +04:00
|
|
|
|
2018-11-20 18:38:06 +03:00
|
|
|
RequestedProtocols = nego_get_requested_protocols(nego);
|
2015-02-06 22:21:26 +03:00
|
|
|
WLog_INFO(TAG, "Client Security: NLA:%d TLS:%d RDP:%d",
|
2018-11-20 19:27:47 +03:00
|
|
|
(RequestedProtocols & PROTOCOL_HYBRID) ? 1 : 0,
|
|
|
|
(RequestedProtocols & PROTOCOL_SSL) ? 1 : 0,
|
2019-11-06 17:24:51 +03:00
|
|
|
(RequestedProtocols == PROTOCOL_RDP) ? 1 : 0);
|
|
|
|
WLog_INFO(TAG, "Server Security: NLA:%" PRId32 " TLS:%" PRId32 " RDP:%" PRId32 "",
|
2018-04-09 12:08:46 +03:00
|
|
|
settings->NlaSecurity, settings->TlsSecurity, settings->RdpSecurity);
|
2012-06-18 23:56:40 +04:00
|
|
|
|
2018-11-20 19:27:47 +03:00
|
|
|
if ((settings->NlaSecurity) && (RequestedProtocols & PROTOCOL_HYBRID))
|
2011-08-19 05:54:43 +04:00
|
|
|
{
|
2018-11-20 19:27:47 +03:00
|
|
|
SelectedProtocol = PROTOCOL_HYBRID;
|
2011-08-19 05:54:43 +04:00
|
|
|
}
|
2018-11-20 19:27:47 +03:00
|
|
|
else if ((settings->TlsSecurity) && (RequestedProtocols & PROTOCOL_SSL))
|
2011-08-19 05:54:43 +04:00
|
|
|
{
|
2018-11-20 19:27:47 +03:00
|
|
|
SelectedProtocol = PROTOCOL_SSL;
|
2011-08-19 05:54:43 +04:00
|
|
|
}
|
2018-11-20 18:38:06 +03:00
|
|
|
else if ((settings->RdpSecurity) && (RequestedProtocols == PROTOCOL_RDP))
|
2012-01-25 20:08:10 +04:00
|
|
|
{
|
2018-11-20 18:38:06 +03:00
|
|
|
SelectedProtocol = PROTOCOL_RDP;
|
2012-01-25 20:08:10 +04:00
|
|
|
}
|
|
|
|
else
|
2012-06-20 04:10:49 +04:00
|
|
|
{
|
2015-02-11 23:38:32 +03:00
|
|
|
/*
|
|
|
|
* when here client and server aren't compatible, we select the right
|
|
|
|
* error message to return to the client in the nego failure packet
|
|
|
|
*/
|
2018-11-20 18:38:06 +03:00
|
|
|
SelectedProtocol = PROTOCOL_FAILED_NEGO;
|
2015-02-11 23:38:32 +03:00
|
|
|
|
|
|
|
if (settings->RdpSecurity)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "server supports only Standard RDP Security");
|
2018-11-20 18:38:06 +03:00
|
|
|
SelectedProtocol |= SSL_NOT_ALLOWED_BY_SERVER;
|
2015-02-11 23:38:32 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (settings->NlaSecurity && !settings->TlsSecurity)
|
|
|
|
{
|
2016-07-22 00:53:20 +03:00
|
|
|
WLog_WARN(TAG, "server supports only NLA Security");
|
2018-11-20 18:38:06 +03:00
|
|
|
SelectedProtocol |= HYBRID_REQUIRED_BY_SERVER;
|
2015-02-11 23:38:32 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-07-22 00:53:20 +03:00
|
|
|
WLog_WARN(TAG, "server supports only a SSL based Security (TLS or NLA)");
|
2018-11-20 18:38:06 +03:00
|
|
|
SelectedProtocol |= SSL_REQUIRED_BY_SERVER;
|
2015-02-11 23:38:32 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-06 22:21:26 +03:00
|
|
|
WLog_ERR(TAG, "Protocol security negotiation failure");
|
2012-06-20 04:10:49 +04:00
|
|
|
}
|
|
|
|
|
2018-11-20 18:38:06 +03:00
|
|
|
if (!(SelectedProtocol & PROTOCOL_FAILED_NEGO))
|
2015-02-11 23:38:32 +03:00
|
|
|
{
|
|
|
|
WLog_INFO(TAG, "Negotiated Security: NLA:%d TLS:%d RDP:%d",
|
2018-11-20 19:27:47 +03:00
|
|
|
(SelectedProtocol & PROTOCOL_HYBRID) ? 1 : 0,
|
|
|
|
(SelectedProtocol & PROTOCOL_SSL) ? 1 : 0,
|
2019-11-06 17:24:51 +03:00
|
|
|
(SelectedProtocol == PROTOCOL_RDP) ? 1 : 0);
|
2015-02-11 23:38:32 +03:00
|
|
|
}
|
2011-08-19 05:54:43 +04:00
|
|
|
|
2018-11-20 18:38:06 +03:00
|
|
|
if (!nego_set_selected_protocol(nego, SelectedProtocol))
|
|
|
|
return FALSE;
|
|
|
|
|
2014-03-26 02:13:08 +04:00
|
|
|
if (!nego_send_negotiation_response(nego))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2011-08-19 05:54:43 +04:00
|
|
|
|
2018-11-20 18:38:06 +03:00
|
|
|
SelectedProtocol = nego_get_selected_protocol(nego);
|
2012-10-09 10:31:28 +04:00
|
|
|
status = FALSE;
|
2013-07-19 01:15:10 +04:00
|
|
|
|
2018-11-20 19:27:47 +03:00
|
|
|
if (SelectedProtocol & PROTOCOL_HYBRID)
|
2012-02-14 07:27:59 +04:00
|
|
|
status = transport_accept_nla(rdp->transport);
|
2018-11-20 19:27:47 +03:00
|
|
|
else if (SelectedProtocol & PROTOCOL_SSL)
|
2012-02-14 07:27:59 +04:00
|
|
|
status = transport_accept_tls(rdp->transport);
|
2018-11-20 18:38:06 +03:00
|
|
|
else if (SelectedProtocol == PROTOCOL_RDP) /* 0 */
|
2012-02-14 07:27:59 +04:00
|
|
|
status = transport_accept_rdp(rdp->transport);
|
2011-08-19 09:35:29 +04:00
|
|
|
|
2012-02-14 07:27:59 +04:00
|
|
|
if (!status)
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2011-08-19 09:35:29 +04:00
|
|
|
|
2012-10-09 10:31:28 +04:00
|
|
|
transport_set_blocking_mode(rdp->transport, FALSE);
|
2022-10-21 11:31:14 +03:00
|
|
|
|
2012-10-09 10:31:28 +04:00
|
|
|
return TRUE;
|
2011-08-19 05:54:43 +04:00
|
|
|
}
|
|
|
|
|
2013-03-21 23:19:33 +04:00
|
|
|
BOOL rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, wStream* s)
|
2011-08-19 13:39:37 +04:00
|
|
|
{
|
2014-02-11 07:12:13 +04:00
|
|
|
UINT32 i;
|
2022-10-21 11:31:14 +03:00
|
|
|
rdpMcs* mcs;
|
|
|
|
|
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
WINPR_ASSERT(s);
|
2011-08-19 14:11:33 +04:00
|
|
|
|
2022-10-21 11:31:14 +03:00
|
|
|
mcs = rdp->mcs;
|
|
|
|
WINPR_ASSERT(mcs);
|
|
|
|
|
|
|
|
WINPR_ASSERT(rdp_get_state(rdp) == CONNECTION_STATE_MCS_CREATE_REQUEST);
|
2014-02-16 01:32:38 +04:00
|
|
|
if (!mcs_recv_connect_initial(mcs, s))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2022-10-21 11:31:14 +03:00
|
|
|
WINPR_ASSERT(rdp->settings);
|
|
|
|
|
|
|
|
if (!mcs_server_apply_to_settings(mcs, rdp->settings))
|
|
|
|
return FALSE;
|
2011-08-19 13:39:37 +04:00
|
|
|
|
2015-02-06 22:21:26 +03:00
|
|
|
WLog_INFO(TAG, "Accepted client: %s", rdp->settings->ClientHostname);
|
|
|
|
WLog_INFO(TAG, "Accepted channels:");
|
2012-09-17 05:05:51 +04:00
|
|
|
|
2022-10-21 11:31:14 +03:00
|
|
|
WINPR_ASSERT(mcs->channels || (mcs->channelCount == 0));
|
2014-02-16 01:32:38 +04:00
|
|
|
for (i = 0; i < mcs->channelCount; i++)
|
2011-08-19 14:11:33 +04:00
|
|
|
{
|
2022-10-21 11:31:14 +03:00
|
|
|
ADDIN_ARGV* arg;
|
2021-08-24 15:09:40 +03:00
|
|
|
rdpMcsChannel* cur = &mcs->channels[i];
|
2022-10-21 11:31:14 +03:00
|
|
|
const char* params[1] = { cur->Name };
|
2021-08-24 15:09:40 +03:00
|
|
|
WLog_INFO(TAG, " %s", cur->Name);
|
2022-10-21 11:31:14 +03:00
|
|
|
arg = freerdp_addin_argv_new(ARRAYSIZE(params), params);
|
|
|
|
if (!arg)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!freerdp_static_channel_collection_add(rdp->settings, arg))
|
|
|
|
{
|
|
|
|
freerdp_addin_argv_free(arg);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2011-08-19 14:11:33 +04:00
|
|
|
}
|
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_CREATE_RESPONSE))
|
|
|
|
return FALSE;
|
2014-02-16 01:32:38 +04:00
|
|
|
if (!mcs_send_connect_response(mcs))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_ERECT_DOMAIN))
|
|
|
|
return FALSE;
|
2011-08-19 19:56:47 +04:00
|
|
|
|
2012-10-09 10:31:28 +04:00
|
|
|
return TRUE;
|
2011-08-19 13:39:37 +04:00
|
|
|
}
|
|
|
|
|
2013-03-21 23:19:33 +04:00
|
|
|
BOOL rdp_server_accept_mcs_erect_domain_request(rdpRdp* rdp, wStream* s)
|
2011-08-19 22:03:48 +04:00
|
|
|
{
|
2022-10-21 11:31:14 +03:00
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
WINPR_ASSERT(s);
|
|
|
|
WINPR_ASSERT(rdp_get_state(rdp) == CONNECTION_STATE_MCS_ERECT_DOMAIN);
|
|
|
|
|
2011-08-23 09:05:58 +04:00
|
|
|
if (!mcs_recv_erect_domain_request(rdp->mcs, s))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2011-08-19 22:03:48 +04:00
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
return rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER);
|
2011-08-19 22:03:48 +04:00
|
|
|
}
|
|
|
|
|
2013-03-21 23:19:33 +04:00
|
|
|
BOOL rdp_server_accept_mcs_attach_user_request(rdpRdp* rdp, wStream* s)
|
2011-08-19 22:03:48 +04:00
|
|
|
{
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER))
|
|
|
|
return FALSE;
|
|
|
|
|
2011-08-23 09:05:58 +04:00
|
|
|
if (!mcs_recv_attach_user_request(rdp->mcs, s))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2011-08-19 22:03:48 +04:00
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER_CONFIRM))
|
|
|
|
return FALSE;
|
|
|
|
|
2011-08-19 22:03:48 +04:00
|
|
|
if (!mcs_send_attach_user_confirm(rdp->mcs))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2011-08-19 22:03:48 +04:00
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
return rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN_REQUEST);
|
2011-08-19 22:03:48 +04:00
|
|
|
}
|
|
|
|
|
2013-03-21 23:19:33 +04:00
|
|
|
BOOL rdp_server_accept_mcs_channel_join_request(rdpRdp* rdp, wStream* s)
|
2011-08-20 10:05:03 +04:00
|
|
|
{
|
2014-02-11 07:12:13 +04:00
|
|
|
UINT32 i;
|
2014-02-14 02:06:33 +04:00
|
|
|
UINT16 channelId;
|
|
|
|
BOOL allJoined = TRUE;
|
2022-10-21 11:31:14 +03:00
|
|
|
rdpMcs* mcs;
|
|
|
|
|
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
WINPR_ASSERT(rdp->context);
|
|
|
|
|
|
|
|
mcs = rdp->mcs;
|
|
|
|
WINPR_ASSERT(mcs);
|
|
|
|
|
|
|
|
WINPR_ASSERT(rdp_get_state(rdp) == CONNECTION_STATE_MCS_CHANNEL_JOIN_REQUEST);
|
2011-08-20 10:05:03 +04:00
|
|
|
|
2022-10-21 11:31:14 +03:00
|
|
|
if (!mcs_recv_channel_join_request(mcs, rdp->context->settings, s, &channelId))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2011-08-20 10:05:03 +04:00
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
if (!rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN_RESPONSE))
|
|
|
|
return FALSE;
|
|
|
|
|
2014-02-16 01:32:38 +04:00
|
|
|
if (!mcs_send_channel_join_confirm(mcs, channelId))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2011-08-20 10:05:03 +04:00
|
|
|
|
2014-02-16 01:32:38 +04:00
|
|
|
if (channelId == mcs->userId)
|
|
|
|
mcs->userChannelJoined = TRUE;
|
2022-10-21 11:31:14 +03:00
|
|
|
if (channelId == MCS_GLOBAL_CHANNEL_ID)
|
2014-02-16 01:32:38 +04:00
|
|
|
mcs->globalChannelJoined = TRUE;
|
2022-10-21 11:31:14 +03:00
|
|
|
if (channelId == mcs->messageChannelId)
|
2014-10-28 11:06:04 +03:00
|
|
|
mcs->messageChannelJoined = TRUE;
|
2011-08-20 10:05:03 +04:00
|
|
|
|
2014-02-16 01:32:38 +04:00
|
|
|
for (i = 0; i < mcs->channelCount; i++)
|
2011-08-20 10:05:03 +04:00
|
|
|
{
|
2021-08-24 15:09:40 +03:00
|
|
|
rdpMcsChannel* cur = &mcs->channels[i];
|
|
|
|
if (cur->ChannelId == channelId)
|
|
|
|
cur->joined = TRUE;
|
2011-08-20 10:05:03 +04:00
|
|
|
|
2021-08-24 15:09:40 +03:00
|
|
|
if (!cur->joined)
|
2014-02-14 02:06:33 +04:00
|
|
|
allJoined = FALSE;
|
2011-08-20 10:05:03 +04:00
|
|
|
}
|
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
CONNECTION_STATE rc;
|
2019-11-06 17:24:51 +03:00
|
|
|
if ((mcs->userChannelJoined) && (mcs->globalChannelJoined) &&
|
|
|
|
(mcs->messageChannelId == 0 || mcs->messageChannelJoined) && allJoined)
|
2022-11-15 16:19:54 +03:00
|
|
|
rc = CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT;
|
2022-10-21 11:31:14 +03:00
|
|
|
else
|
2022-11-15 16:19:54 +03:00
|
|
|
rc = CONNECTION_STATE_MCS_CHANNEL_JOIN_REQUEST;
|
2011-08-20 14:22:14 +04:00
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
return rdp_server_transition_to_state(rdp, rc);
|
2011-08-20 14:22:14 +04:00
|
|
|
}
|
|
|
|
|
2020-02-21 11:17:00 +03:00
|
|
|
BOOL rdp_server_accept_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength)
|
2011-08-21 11:52:44 +04:00
|
|
|
{
|
2022-10-21 11:31:14 +03:00
|
|
|
freerdp_peer* peer;
|
2017-02-22 01:44:47 +03:00
|
|
|
|
2022-10-21 11:31:14 +03:00
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
WINPR_ASSERT(rdp->context);
|
|
|
|
WINPR_ASSERT(rdp->settings);
|
|
|
|
WINPR_ASSERT(s);
|
|
|
|
|
|
|
|
peer = rdp->context->peer;
|
|
|
|
WINPR_ASSERT(peer);
|
|
|
|
|
|
|
|
if (rdp_get_state(rdp) != CONNECTION_STATE_CAPABILITIES_EXCHANGE_CONFIRM_ACTIVE)
|
|
|
|
{
|
|
|
|
if (freerdp_settings_get_bool(rdp->settings, FreeRDP_TransportDumpReplay))
|
|
|
|
rdp_finalize_set_flag(rdp, FINALIZE_DEACTIVATE_REACTIVATE);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WLog_WARN(TAG, "Invalid state, got %s, expected %s", rdp_get_state_string(rdp),
|
|
|
|
rdp_state_string(CONNECTION_STATE_CAPABILITIES_EXCHANGE_CONFIRM_ACTIVE));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
2013-07-20 02:24:56 +04:00
|
|
|
|
2020-02-21 11:17:00 +03:00
|
|
|
if (!rdp_recv_confirm_active(rdp, s, pduLength))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2011-08-21 11:52:44 +04:00
|
|
|
|
2017-02-22 01:44:47 +03:00
|
|
|
if (peer->ClientCapabilities && !peer->ClientCapabilities(peer))
|
|
|
|
return FALSE;
|
|
|
|
|
2014-09-19 03:38:04 +04:00
|
|
|
if (rdp->settings->SaltedChecksum)
|
|
|
|
rdp->do_secure_checksum = TRUE;
|
|
|
|
|
2022-11-15 16:19:54 +03:00
|
|
|
return rdp_server_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION_SYNC);
|
2011-08-21 11:52:44 +04:00
|
|
|
}
|
|
|
|
|
2012-10-09 10:38:39 +04:00
|
|
|
BOOL rdp_server_reactivate(rdpRdp* rdp)
|
2011-09-06 13:19:16 +04:00
|
|
|
{
|
2014-11-19 22:21:23 +03:00
|
|
|
freerdp_peer* client = NULL;
|
|
|
|
|
|
|
|
if (rdp->context && rdp->context->peer)
|
|
|
|
client = rdp->context->peer;
|
|
|
|
|
|
|
|
if (client)
|
|
|
|
client->activated = FALSE;
|
|
|
|
|
2011-09-06 13:19:16 +04:00
|
|
|
if (!rdp_send_deactivate_all(rdp))
|
2012-10-09 10:31:28 +04:00
|
|
|
return FALSE;
|
2011-09-06 13:19:16 +04:00
|
|
|
|
2022-10-21 11:31:14 +03:00
|
|
|
rdp_finalize_set_flag(rdp, FINALIZE_DEACTIVATE_REACTIVATE);
|
2022-11-08 14:54:49 +03:00
|
|
|
if (!rdp_server_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE_DEMAND_ACTIVE))
|
|
|
|
return FALSE;
|
2022-11-22 13:05:57 +03:00
|
|
|
|
|
|
|
state_run_t rc = rdp_peer_handle_state_demand_active(client);
|
|
|
|
return state_run_success(rc);
|
2011-09-06 13:19:16 +04:00
|
|
|
}
|
|
|
|
|
2022-12-01 16:40:27 +03:00
|
|
|
static BOOL rdp_is_active_peer_state(CONNECTION_STATE state)
|
|
|
|
{
|
|
|
|
/* [MS-RDPBCGR] 1.3.1.1 Connection Sequence states:
|
|
|
|
* 'upon receipt of the Font List PDU the server can start sending graphics
|
|
|
|
* output to the client'
|
|
|
|
*/
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case CONNECTION_STATE_FINALIZATION_CLIENT_SYNC:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_CLIENT_COOPERATE:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_CLIENT_GRANTED_CONTROL:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_CLIENT_FONT_MAP:
|
|
|
|
case CONNECTION_STATE_ACTIVE:
|
|
|
|
return TRUE;
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL rdp_is_active_client_state(CONNECTION_STATE state)
|
|
|
|
{
|
|
|
|
/* [MS-RDPBCGR] 1.3.1.1 Connection Sequence states:
|
|
|
|
* 'Once the client has sent the Confirm Active PDU, it can start sending
|
|
|
|
* mouse and keyboard input to the server'
|
|
|
|
*/
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case CONNECTION_STATE_FINALIZATION_SYNC:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_COOPERATE:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_REQUEST_CONTROL:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_PERSISTENT_KEY_LIST:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_FONT_LIST:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_CLIENT_SYNC:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_CLIENT_COOPERATE:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_CLIENT_GRANTED_CONTROL:
|
|
|
|
case CONNECTION_STATE_FINALIZATION_CLIENT_FONT_MAP:
|
|
|
|
case CONNECTION_STATE_ACTIVE:
|
|
|
|
return TRUE;
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL rdp_is_active_state(const rdpRdp* rdp)
|
|
|
|
{
|
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
WINPR_ASSERT(rdp->context);
|
|
|
|
|
|
|
|
const CONNECTION_STATE state = rdp_get_state(rdp);
|
|
|
|
if (freerdp_settings_get_bool(rdp->context->settings, FreeRDP_ServerMode))
|
|
|
|
return rdp_is_active_peer_state(state);
|
|
|
|
else
|
|
|
|
return rdp_is_active_client_state(state);
|
|
|
|
}
|
|
|
|
|
2022-03-18 12:57:47 +03:00
|
|
|
BOOL rdp_server_transition_to_state(rdpRdp* rdp, CONNECTION_STATE state)
|
2013-07-19 01:15:10 +04:00
|
|
|
{
|
2022-03-18 12:57:47 +03:00
|
|
|
BOOL status = FALSE;
|
2013-07-20 05:52:28 +04:00
|
|
|
freerdp_peer* client = NULL;
|
2022-02-01 13:06:22 +03:00
|
|
|
const CONNECTION_STATE cstate = rdp_get_state(rdp);
|
2013-07-20 05:52:28 +04:00
|
|
|
|
2021-09-03 09:17:27 +03:00
|
|
|
if (cstate >= CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT)
|
2013-07-20 05:52:28 +04:00
|
|
|
client = rdp->context->peer;
|
|
|
|
|
2021-09-03 09:17:27 +03:00
|
|
|
if (cstate < CONNECTION_STATE_ACTIVE)
|
2013-07-20 05:52:28 +04:00
|
|
|
{
|
|
|
|
if (client)
|
|
|
|
client->activated = FALSE;
|
|
|
|
}
|
2013-07-19 01:15:10 +04:00
|
|
|
|
2021-09-03 09:17:27 +03:00
|
|
|
WLog_DBG(TAG, "%s %s --> %s", __FUNCTION__, rdp_get_state_string(rdp), rdp_state_string(state));
|
2022-03-18 12:57:47 +03:00
|
|
|
if (!rdp_set_state(rdp, state))
|
|
|
|
goto fail;
|
2013-07-19 01:15:10 +04:00
|
|
|
|
2022-03-18 12:57:47 +03:00
|
|
|
status = TRUE;
|
|
|
|
fail:
|
2013-07-19 01:15:10 +04:00
|
|
|
return status;
|
|
|
|
}
|
2020-02-21 11:17:00 +03:00
|
|
|
|
|
|
|
const char* rdp_client_connection_state_string(int state)
|
|
|
|
{
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case CLIENT_STATE_INITIAL:
|
|
|
|
return "CLIENT_STATE_INITIAL";
|
|
|
|
case CLIENT_STATE_PRECONNECT_PASSED:
|
|
|
|
return "CLIENT_STATE_PRECONNECT_PASSED";
|
|
|
|
case CLIENT_STATE_POSTCONNECT_PASSED:
|
|
|
|
return "CLIENT_STATE_POSTCONNECT_PASSED";
|
|
|
|
default:
|
|
|
|
return "UNKNOWN";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-03 10:12:23 +03:00
|
|
|
const char* rdp_state_string(CONNECTION_STATE state)
|
2020-02-21 11:17:00 +03:00
|
|
|
{
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case CONNECTION_STATE_INITIAL:
|
|
|
|
return "CONNECTION_STATE_INITIAL";
|
|
|
|
case CONNECTION_STATE_NEGO:
|
|
|
|
return "CONNECTION_STATE_NEGO";
|
|
|
|
case CONNECTION_STATE_NLA:
|
|
|
|
return "CONNECTION_STATE_NLA";
|
2022-10-21 11:31:14 +03:00
|
|
|
case CONNECTION_STATE_MCS_CREATE_REQUEST:
|
|
|
|
return "CONNECTION_STATE_MCS_CREATE_REQUEST";
|
|
|
|
case CONNECTION_STATE_MCS_CREATE_RESPONSE:
|
|
|
|
return "CONNECTION_STATE_MCS_CREATE_RESPONSE";
|
2020-02-21 11:17:00 +03:00
|
|
|
case CONNECTION_STATE_MCS_ERECT_DOMAIN:
|
|
|
|
return "CONNECTION_STATE_MCS_ERECT_DOMAIN";
|
|
|
|
case CONNECTION_STATE_MCS_ATTACH_USER:
|
|
|
|
return "CONNECTION_STATE_MCS_ATTACH_USER";
|
2022-10-21 11:31:14 +03:00
|
|
|
case CONNECTION_STATE_MCS_ATTACH_USER_CONFIRM:
|
|
|
|
return "CONNECTION_STATE_MCS_ATTACH_USER_CONFIRM";
|
|
|
|
case CONNECTION_STATE_MCS_CHANNEL_JOIN_REQUEST:
|
|
|
|
return "CONNECTION_STATE_MCS_CHANNEL_JOIN_REQUEST";
|
|
|
|
case CONNECTION_STATE_MCS_CHANNEL_JOIN_RESPONSE:
|
|
|
|
return "CONNECTION_STATE_MCS_CHANNEL_JOIN_RESPONSE";
|
2020-02-21 11:17:00 +03:00
|
|
|
case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT:
|
|
|
|
return "CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT";
|
|
|
|
case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE:
|
|
|
|
return "CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE";
|
2022-10-21 11:31:14 +03:00
|
|
|
case CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT_REQUEST:
|
|
|
|
return "CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT_REQUEST";
|
|
|
|
case CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT_RESPONSE:
|
|
|
|
return "CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT_RESPONSE";
|
2020-02-21 11:17:00 +03:00
|
|
|
case CONNECTION_STATE_LICENSING:
|
|
|
|
return "CONNECTION_STATE_LICENSING";
|
2022-10-21 11:31:14 +03:00
|
|
|
case CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING_REQUEST:
|
|
|
|
return "CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING_REQUEST";
|
|
|
|
case CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING_RESPONSE:
|
|
|
|
return "CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING_RESPONSE";
|
|
|
|
case CONNECTION_STATE_CAPABILITIES_EXCHANGE_DEMAND_ACTIVE:
|
|
|
|
return "CONNECTION_STATE_CAPABILITIES_EXCHANGE_DEMAND_ACTIVE";
|
|
|
|
case CONNECTION_STATE_CAPABILITIES_EXCHANGE_MONITOR_LAYOUT:
|
|
|
|
return "CONNECTION_STATE_CAPABILITIES_EXCHANGE_MONITOR_LAYOUT";
|
|
|
|
case CONNECTION_STATE_CAPABILITIES_EXCHANGE_CONFIRM_ACTIVE:
|
|
|
|
return "CONNECTION_STATE_CAPABILITIES_EXCHANGE_CONFIRM_ACTIVE";
|
|
|
|
case CONNECTION_STATE_FINALIZATION_SYNC:
|
|
|
|
return "CONNECTION_STATE_FINALIZATION_SYNC";
|
|
|
|
case CONNECTION_STATE_FINALIZATION_COOPERATE:
|
|
|
|
return "CONNECTION_STATE_FINALIZATION_COOPERATE";
|
|
|
|
case CONNECTION_STATE_FINALIZATION_REQUEST_CONTROL:
|
|
|
|
return "CONNECTION_STATE_FINALIZATION_REQUEST_CONTROL";
|
|
|
|
case CONNECTION_STATE_FINALIZATION_PERSISTENT_KEY_LIST:
|
|
|
|
return "CONNECTION_STATE_FINALIZATION_PERSISTENT_KEY_LIST";
|
|
|
|
case CONNECTION_STATE_FINALIZATION_FONT_LIST:
|
|
|
|
return "CONNECTION_STATE_FINALIZATION_FONT_LIST";
|
|
|
|
case CONNECTION_STATE_FINALIZATION_CLIENT_SYNC:
|
|
|
|
return "CONNECTION_STATE_FINALIZATION_CLIENT_SYNC";
|
|
|
|
case CONNECTION_STATE_FINALIZATION_CLIENT_COOPERATE:
|
|
|
|
return "CONNECTION_STATE_FINALIZATION_CLIENT_COOPERATE";
|
|
|
|
case CONNECTION_STATE_FINALIZATION_CLIENT_GRANTED_CONTROL:
|
|
|
|
return "CONNECTION_STATE_FINALIZATION_CLIENT_GRANTED_CONTROL";
|
|
|
|
case CONNECTION_STATE_FINALIZATION_CLIENT_FONT_MAP:
|
|
|
|
return "CONNECTION_STATE_FINALIZATION_CLIENT_FONT_MAP";
|
2020-02-21 11:17:00 +03:00
|
|
|
case CONNECTION_STATE_ACTIVE:
|
|
|
|
return "CONNECTION_STATE_ACTIVE";
|
|
|
|
default:
|
|
|
|
return "UNKNOWN";
|
|
|
|
}
|
|
|
|
}
|
2021-01-22 10:24:16 +03:00
|
|
|
|
2021-09-10 10:06:35 +03:00
|
|
|
CONNECTION_STATE rdp_get_state(const rdpRdp* rdp)
|
2021-01-22 10:24:16 +03:00
|
|
|
{
|
2021-09-03 09:17:27 +03:00
|
|
|
WINPR_ASSERT(rdp);
|
2021-01-22 10:24:16 +03:00
|
|
|
return rdp->state;
|
|
|
|
}
|
2021-09-03 09:17:27 +03:00
|
|
|
|
2021-09-03 10:12:23 +03:00
|
|
|
BOOL rdp_set_state(rdpRdp* rdp, CONNECTION_STATE state)
|
2021-09-03 09:17:27 +03:00
|
|
|
{
|
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
rdp->state = state;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2022-11-21 10:52:46 +03:00
|
|
|
const char* rdp_get_state_string(const rdpRdp* rdp)
|
2021-09-03 09:17:27 +03:00
|
|
|
{
|
2021-12-17 19:28:41 +03:00
|
|
|
CONNECTION_STATE state = rdp_get_state(rdp);
|
2021-09-03 09:17:27 +03:00
|
|
|
return rdp_state_string(state);
|
|
|
|
}
|
2021-09-22 15:27:21 +03:00
|
|
|
|
|
|
|
BOOL rdp_channels_from_mcs(rdpSettings* settings, const rdpRdp* rdp)
|
|
|
|
{
|
|
|
|
size_t x;
|
|
|
|
const rdpMcs* mcs;
|
|
|
|
|
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
|
|
|
|
mcs = rdp->mcs;
|
|
|
|
WINPR_ASSERT(mcs);
|
|
|
|
|
|
|
|
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ChannelDefArray, NULL,
|
|
|
|
mcs->channelCount))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
for (x = 0; x < mcs->channelCount; x++)
|
|
|
|
{
|
|
|
|
const rdpMcsChannel* mchannel = &mcs->channels[x];
|
|
|
|
CHANNEL_DEF cur = { 0 };
|
|
|
|
|
|
|
|
memcpy(cur.name, mchannel->Name, sizeof(cur.name));
|
|
|
|
cur.options = mchannel->options;
|
|
|
|
if (!freerdp_settings_set_pointer_array(settings, FreeRDP_ChannelDefArray, x, &cur))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
2022-10-21 10:53:24 +03:00
|
|
|
|
2022-11-30 18:06:33 +03:00
|
|
|
/* Here we are in client state CONFIRM_ACTIVE.
|
|
|
|
*
|
|
|
|
* This means:
|
|
|
|
* 1. send the CONFIRM_ACTIVE PDU to the server
|
|
|
|
* 2. register callbacks, the server can now start sending stuff
|
|
|
|
*/
|
2022-11-11 14:26:28 +03:00
|
|
|
state_run_t rdp_client_connect_confirm_active(rdpRdp* rdp, wStream* s)
|
2022-10-21 10:53:24 +03:00
|
|
|
{
|
|
|
|
WINPR_ASSERT(rdp);
|
|
|
|
WINPR_ASSERT(rdp->settings);
|
|
|
|
WINPR_ASSERT(s);
|
|
|
|
|
|
|
|
const UINT32 width = rdp->settings->DesktopWidth;
|
|
|
|
const UINT32 height = rdp->settings->DesktopHeight;
|
|
|
|
|
|
|
|
if (!rdp_send_confirm_active(rdp))
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2022-10-21 10:53:24 +03:00
|
|
|
|
|
|
|
if (!input_register_client_callbacks(rdp->input))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "error registering client callbacks");
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2022-10-21 10:53:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The server may request a different desktop size during Deactivation-Reactivation sequence.
|
|
|
|
* In this case, the UI should be informed and do actual window resizing at this point.
|
|
|
|
*/
|
|
|
|
const BOOL deactivate_reactivate =
|
|
|
|
rdp->was_deactivated && ((rdp->deactivated_width != rdp->settings->DesktopWidth) ||
|
|
|
|
(rdp->deactivated_height != rdp->settings->DesktopHeight));
|
|
|
|
const BOOL resolution_change =
|
|
|
|
((width != rdp->settings->DesktopWidth) || (height != rdp->settings->DesktopHeight));
|
|
|
|
if (deactivate_reactivate || resolution_change)
|
|
|
|
{
|
|
|
|
BOOL status = TRUE;
|
|
|
|
IFCALLRET(rdp->update->DesktopResize, status, rdp->update->context);
|
|
|
|
|
|
|
|
if (!status)
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "client desktop resize callback failed");
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_FAILED;
|
2022-10-21 10:53:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WINPR_ASSERT(rdp->context);
|
|
|
|
if (freerdp_shall_disconnect_context(rdp->context))
|
2022-11-11 14:26:28 +03:00
|
|
|
return STATE_RUN_SUCCESS;
|
2022-10-21 10:53:24 +03:00
|
|
|
|
2022-11-30 18:06:33 +03:00
|
|
|
state_run_t status = STATE_RUN_SUCCESS;
|
|
|
|
if (!rdp->settings->SupportMonitorLayoutPdu)
|
|
|
|
status = rdp_client_connect_finalize(rdp);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!rdp_client_transition_to_state(rdp,
|
|
|
|
CONNECTION_STATE_CAPABILITIES_EXCHANGE_MONITOR_LAYOUT))
|
|
|
|
status = STATE_RUN_FAILED;
|
|
|
|
}
|
|
|
|
return status;
|
2022-10-21 10:53:24 +03:00
|
|
|
}
|