Skip to content

Commit c54e496

Browse files
clean up
1 parent a1e3551 commit c54e496

File tree

3 files changed

+125
-193
lines changed

3 files changed

+125
-193
lines changed

ffi/dotnet/Devolutions.IronRdp/src/Connection.cs

Lines changed: 2 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,11 @@ public static class Connection
1717

1818
var connector = ClientConnector.New(config, clientAddr);
1919

20-
connector.WithDynamicChannelDisplayControl();
21-
var dvcPipeProxy = config.DvcPipeProxy;
22-
if (dvcPipeProxy != null)
23-
{
24-
connector.WithDynamicChannelPipeProxy(dvcPipeProxy);
25-
}
26-
27-
if (factory != null)
28-
{
29-
var cliprdr = factory.BuildCliprdr();
30-
connector.AttachStaticCliprdr(cliprdr);
31-
}
20+
ConnectionHelpers.SetupConnector(connector, config, factory);
3221

3322
await ConnectBegin(framed, connector);
3423
var (serverPublicKey, framedSsl) = await SecurityUpgrade(framed, connector);
35-
var result = await ConnectFinalize(serverName, connector, serverPublicKey, framedSsl);
24+
var result = await ConnectionHelpers.ConnectFinalize(serverName, connector, serverPublicKey, framedSsl);
3625

3726
return (result, framedSsl);
3827
}
@@ -67,74 +56,6 @@ private static async Task ConnectBegin(Framed<NetworkStream> framed, ClientConne
6756
}
6857
}
6958

70-
71-
private static async Task<ConnectionResult> ConnectFinalize(string serverName, ClientConnector connector,
72-
byte[] serverPubKey, Framed<SslStream> framedSsl)
73-
{
74-
var writeBuf2 = WriteBuf.New();
75-
if (connector.ShouldPerformCredssp())
76-
{
77-
await PerformCredsspSteps(connector, serverName, writeBuf2, framedSsl, serverPubKey);
78-
}
79-
80-
while (!connector.GetDynState().IsTerminal())
81-
{
82-
await SingleSequenceStep(connector, writeBuf2, framedSsl);
83-
}
84-
85-
ClientConnectorState state = connector.ConsumeAndCastToClientConnectorState();
86-
87-
if (state.GetEnumType() == ClientConnectorStateType.Connected)
88-
{
89-
return state.GetConnectedResult();
90-
}
91-
else
92-
{
93-
throw new IronRdpLibException(IronRdpLibExceptionType.ConnectionFailed, "Connection failed");
94-
}
95-
}
96-
97-
private static async Task PerformCredsspSteps(ClientConnector connector, string serverName, WriteBuf writeBuf,
98-
Framed<SslStream> framedSsl, byte[] serverpubkey)
99-
{
100-
var credsspSequenceInitResult = CredsspSequence.Init(connector, serverName, serverpubkey, null);
101-
var credsspSequence = credsspSequenceInitResult.GetCredsspSequence();
102-
var tsRequest = credsspSequenceInitResult.GetTsRequest();
103-
var tcpClient = new TcpClient();
104-
while (true)
105-
{
106-
var generator = credsspSequence.ProcessTsRequest(tsRequest);
107-
var clientState = await ResolveGenerator(generator, tcpClient);
108-
writeBuf.Clear();
109-
var written = credsspSequence.HandleProcessResult(clientState, writeBuf);
110-
111-
if (written.GetSize().IsSome())
112-
{
113-
var actualSize = (int)written.GetSize().Get();
114-
var response = new byte[actualSize];
115-
writeBuf.ReadIntoBuf(response);
116-
await framedSsl.Write(response);
117-
}
118-
119-
var pduHint = credsspSequence.NextPduHint();
120-
if (pduHint == null)
121-
{
122-
break;
123-
}
124-
125-
var pdu = await framedSsl.ReadByHint(pduHint);
126-
var decoded = credsspSequence.DecodeServerMessage(pdu);
127-
128-
// Don't remove, DecodeServerMessage is generated, and it can return null
129-
if (null == decoded)
130-
{
131-
break;
132-
}
133-
134-
tsRequest = decoded;
135-
}
136-
}
137-
13859
internal static async Task<ClientState> ResolveGenerator(CredsspProcessGenerator generator, TcpClient tcpClient)
13960
{
14061
var state = generator.Start();
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
using System.Net.Sockets;
2+
3+
namespace Devolutions.IronRdp;
4+
5+
/// <summary>
6+
/// Internal helper class providing shared connection logic for both direct and RDCleanPath connections.
7+
/// </summary>
8+
internal static class ConnectionHelpers
9+
{
10+
/// <summary>
11+
/// Sets up common connector configuration including dynamic channels and clipboard.
12+
/// </summary>
13+
internal static void SetupConnector(ClientConnector connector, Config config, CliprdrBackendFactory? factory)
14+
{
15+
connector.WithDynamicChannelDisplayControl();
16+
17+
var dvcPipeProxy = config.DvcPipeProxy;
18+
if (dvcPipeProxy != null)
19+
{
20+
connector.WithDynamicChannelPipeProxy(dvcPipeProxy);
21+
}
22+
23+
if (factory != null)
24+
{
25+
var cliprdr = factory.BuildCliprdr();
26+
connector.AttachStaticCliprdr(cliprdr);
27+
}
28+
}
29+
30+
/// <summary>
31+
/// Performs CredSSP authentication steps over any stream type.
32+
/// </summary>
33+
internal static async Task PerformCredsspSteps<T>(
34+
ClientConnector connector,
35+
string serverName,
36+
WriteBuf writeBuf,
37+
Framed<T> framed,
38+
byte[] serverpubkey) where T : Stream
39+
{
40+
// Extract hostname from "hostname:port" format if needed
41+
// CredSSP needs just the hostname for the service principal name (TERMSRV/hostname)
42+
var hostname = serverName;
43+
var colonIndex = serverName.IndexOf(':');
44+
if (colonIndex > 0)
45+
{
46+
hostname = serverName.Substring(0, colonIndex);
47+
}
48+
49+
var credsspSequenceInitResult = CredsspSequence.Init(connector, hostname, serverpubkey, null);
50+
var credsspSequence = credsspSequenceInitResult.GetCredsspSequence();
51+
var tsRequest = credsspSequenceInitResult.GetTsRequest();
52+
var tcpClient = new TcpClient();
53+
54+
while (true)
55+
{
56+
var generator = credsspSequence.ProcessTsRequest(tsRequest);
57+
var clientState = await Connection.ResolveGenerator(generator, tcpClient);
58+
writeBuf.Clear();
59+
var written = credsspSequence.HandleProcessResult(clientState, writeBuf);
60+
61+
if (written.GetSize().IsSome())
62+
{
63+
var actualSize = (int)written.GetSize().Get();
64+
var response = new byte[actualSize];
65+
writeBuf.ReadIntoBuf(response);
66+
await framed.Write(response);
67+
}
68+
69+
var pduHint = credsspSequence.NextPduHint();
70+
if (pduHint == null)
71+
{
72+
break;
73+
}
74+
75+
var pdu = await framed.ReadByHint(pduHint);
76+
var decoded = credsspSequence.DecodeServerMessage(pdu);
77+
78+
// Don't remove, DecodeServerMessage is generated, and it can return null
79+
if (null == decoded)
80+
{
81+
break;
82+
}
83+
84+
tsRequest = decoded;
85+
}
86+
}
87+
88+
/// <summary>
89+
/// Finalizes the RDP connection after security upgrade, performing CredSSP if needed
90+
/// and completing the connection sequence.
91+
/// </summary>
92+
internal static async Task<ConnectionResult> ConnectFinalize<T>(
93+
string serverName,
94+
ClientConnector connector,
95+
byte[] serverPubKey,
96+
Framed<T> framedSsl) where T : Stream
97+
{
98+
var writeBuf = WriteBuf.New();
99+
100+
if (connector.ShouldPerformCredssp())
101+
{
102+
await PerformCredsspSteps(connector, serverName, writeBuf, framedSsl, serverPubKey);
103+
}
104+
105+
while (!connector.GetDynState().IsTerminal())
106+
{
107+
await Connection.SingleSequenceStep(connector, writeBuf, framedSsl);
108+
}
109+
110+
ClientConnectorState state = connector.ConsumeAndCastToClientConnectorState();
111+
112+
if (state.GetEnumType() == ClientConnectorStateType.Connected)
113+
{
114+
return state.GetConnectedResult();
115+
}
116+
else
117+
{
118+
throw new IronRdpLibException(IronRdpLibExceptionType.ConnectionFailed, "Connection failed");
119+
}
120+
}
121+
}

ffi/dotnet/Devolutions.IronRdp/src/RDCleanPathConnection.cs

Lines changed: 2 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,7 @@ public static class RDCleanPathConnection
3737

3838
// Step 3: Setup ClientConnector
3939
var connector = ClientConnector.New(config, clientAddr);
40-
41-
// Attach optional dynamic/static channels
42-
connector.WithDynamicChannelDisplayControl();
43-
var dvcPipeProxy = config.DvcPipeProxy;
44-
if (dvcPipeProxy != null)
45-
{
46-
connector.WithDynamicChannelPipeProxy(dvcPipeProxy);
47-
}
48-
49-
if (factory != null)
50-
{
51-
var cliprdr = factory.BuildCliprdr();
52-
connector.AttachStaticCliprdr(cliprdr);
53-
}
40+
ConnectionHelpers.SetupConnector(connector, config, factory);
5441

5542
// Step 4: Perform RDCleanPath handshake
5643
System.Diagnostics.Debug.WriteLine("Performing RDCleanPath handshake...");
@@ -62,7 +49,7 @@ public static class RDCleanPathConnection
6249

6350
// Step 6: Finalize connection
6451
System.Diagnostics.Debug.WriteLine("Finalizing RDP connection...");
65-
var result = await ConnectFinalize(destination, connector, serverPublicKey, framedAfterHandshake);
52+
var result = await ConnectionHelpers.ConnectFinalize(destination, connector, serverPublicKey, framedAfterHandshake);
6653

6754
System.Diagnostics.Debug.WriteLine("Gateway connection established successfully!");
6855
return (result, framedAfterHandshake);
@@ -165,103 +152,6 @@ public static class RDCleanPathConnection
165152
}
166153
}
167154

168-
/// <summary>
169-
/// Finalizes the RDP connection after RDCleanPath handshake.
170-
/// </summary>
171-
private static async Task<ConnectionResult> ConnectFinalize(
172-
string serverName,
173-
ClientConnector connector,
174-
byte[] serverPubKey,
175-
Framed<WebSocketStream> framedSsl)
176-
{
177-
var writeBuf = WriteBuf.New();
178-
179-
// Perform CredSSP if needed
180-
if (connector.ShouldPerformCredssp())
181-
{
182-
System.Diagnostics.Debug.WriteLine("Performing CredSSP authentication...");
183-
await PerformCredsspSteps(connector, serverName, writeBuf, framedSsl, serverPubKey);
184-
}
185-
186-
// Continue with remaining connection steps
187-
System.Diagnostics.Debug.WriteLine("Completing connection sequence...");
188-
while (!connector.GetDynState().IsTerminal())
189-
{
190-
await Connection.SingleSequenceStep(connector, writeBuf, framedSsl);
191-
}
192-
193-
// Get final connection result
194-
ClientConnectorState state = connector.ConsumeAndCastToClientConnectorState();
195-
196-
if (state.GetEnumType() == ClientConnectorStateType.Connected)
197-
{
198-
return state.GetConnectedResult();
199-
}
200-
else
201-
{
202-
throw new IronRdpLibException(
203-
IronRdpLibExceptionType.ConnectionFailed,
204-
"Connection failed after RDCleanPath handshake");
205-
}
206-
}
207-
208-
/// <summary>
209-
/// Performs CredSSP authentication steps.
210-
/// </summary>
211-
private static async Task PerformCredsspSteps(
212-
ClientConnector connector,
213-
string serverName,
214-
WriteBuf writeBuf,
215-
Framed<WebSocketStream> framedSsl,
216-
byte[] serverpubkey)
217-
{
218-
// Extract hostname from "hostname:port" format for CredSSP
219-
// CredSSP needs just the hostname for the service principal name (TERMSRV/hostname)
220-
var hostname = serverName;
221-
var colonIndex = serverName.IndexOf(':');
222-
if (colonIndex > 0)
223-
{
224-
hostname = serverName.Substring(0, colonIndex);
225-
}
226-
227-
var credsspSequenceInitResult = CredsspSequence.Init(connector, hostname, serverpubkey, null);
228-
var credsspSequence = credsspSequenceInitResult.GetCredsspSequence();
229-
var tsRequest = credsspSequenceInitResult.GetTsRequest();
230-
var tcpClient = new System.Net.Sockets.TcpClient();
231-
232-
while (true)
233-
{
234-
var generator = credsspSequence.ProcessTsRequest(tsRequest);
235-
var clientState = await Connection.ResolveGenerator(generator, tcpClient);
236-
writeBuf.Clear();
237-
var written = credsspSequence.HandleProcessResult(clientState, writeBuf);
238-
239-
if (written.GetSize().IsSome())
240-
{
241-
var actualSize = (int)written.GetSize().Get();
242-
var response = new byte[actualSize];
243-
writeBuf.ReadIntoBuf(response);
244-
await framedSsl.Write(response);
245-
}
246-
247-
var pduHint = credsspSequence.NextPduHint();
248-
if (pduHint == null)
249-
{
250-
break;
251-
}
252-
253-
var pdu = await framedSsl.ReadByHint(pduHint);
254-
var decoded = credsspSequence.DecodeServerMessage(pdu);
255-
256-
if (null == decoded)
257-
{
258-
break;
259-
}
260-
261-
tsRequest = decoded;
262-
}
263-
}
264-
265155
/// <summary>
266156
/// Extracts the public key from an X.509 certificate in DER format.
267157
/// </summary>

0 commit comments

Comments
 (0)