Issue with providing load balancing information using AxMSTSCLib - c#

I am trying to establish a remote desktop connection via a remote desktop session broker in my C# application using the 'AxInterop.MSTSCLib' where I encounter problems with the transfer of the load balancing information.
Basically, I create a new object and set the basic parameters. A connection directly to a single Remote Desktop (RD) server is already possible with this:
var rd = new AxMsRdpClient11NotSafeForScripting();
rd.Server = "target-server.domain.local";
rd.UserName = "user";
var secured = (MSTSCLib.IMsTscNonScriptable)rd.GetOcx();
secured.ClearTextPassword = "password";
The RD environment I want to connect to consists of multiple RD service collections, each managing one or more RD Servers. For new RD connections, RD clients connect to an RD broker server, which redirects the clients according to the individual load balancing information they provide.
To provide this load balancing info, using mstsc.exe and a .rdp file I provide the setting 'loadbalanceinfo:s:tsv://MS Terminal Services Plugin.1.99999' where '99999' is the name of the targeted RD Collection which works fine. To implement this in MSTSCLib, I have to set it with 'rd.AdvancedSettings9.LoadBalanceInfo'.
However, as this post on the Microsoft Technet forum also describes, the load balancing info string must first be re-encoded.
var lbinfo = "loadbalanceinfo:s:tsv://MS Terminal Services Plugin.1.99999";
if (lbinfo.Length % 2 == 1) lbinfo += " ";
lbinfo += "\r\n";
var b = Encoding.UTF8.GetBytes(lbinfo);
var final = Encoding.Unicode.GetString(b);
rd.AdvancedSettings9.LoadBalanceInfo = final;
According to the last comment in the Technet post, the number of bytes must be even, so a space (U+0020) is added if necessary.
With 'rd.Connect()' the connection is established and my client reaches the connection broker. In the first step, my connection request appears in the logs of the broker server:
[TerminalServices-SessionBroker (Operational)]
The Remote Desktop Connection Broker has received a connection request for user {user}.
Notes in the RDP file (TSV URL) = 'tsv://MS Terminal Services Plugin.1.99999 '
(note: there are two empty spaces at the end of the string)
Original application = NULL
The call comes from the redirection server = broker.domain.local
The redirector is configured as a virtual machine redirector.
Note the two spaces at the end of the TSV URL that gets added by the used code because the bytes count would be uneven otherwise. The only difference to mstsc.exe is that there is only one space (which is the new line break we also add I guess) displayed.
In the next step, the error occurs and our connection attempt fails. It says 'The farm specified for the connection does not exist.'
The OnDisconnected event is triggered and provides me the information: 'DiscReason: 3' and 'ExtendedDisconnectReason: 1040'.
My guess: Because of the space we add, the name of the RD collection can't be assigned correctly anymore. If we compare the passed information (loadbalanceinfo:s:tsv://MS Terminal Services Plugin.1.99999) on byte level, we also see that this added space is the only difference:
mstsc.exe
74 73 76 3a 2f 2f 4d 53 20 54 65 72 6d 69 6e 61 6c 20 53 65 72 76 69 63 65 73 20 50 6c 75 67 69 6e 2e 31 2e 39 39 39 39 39 0d 0a
AxMSTSCLib:
74 73 76 3a 2f 2f 4d 53 20 54 65 72 6d 69 6e 61 6c 20 53 65 72 76 69 63 65 73 20 50 6c 75 67 69 6e 2e 31 2e 39 39 39 39 39 20 0d 0a
Note the third last byte, the U+0020, which we added to achieve an even byte count.
If I do not add the space and the number of bytes (43) is thus not even, I see in WireShark that the TPKT packet is not even sent anymore. The broker server, according to its logs, also takes no notice of the connection attempt. The OnDisconnected event provides me the information:: 'DiscReason: 4' and 'ExtendedDisconnectReason: exDiscReasonNoInfo'. So it seems that the AxMSTSCLib already assumes that the byte number is even.
Unfortunately, I can't figure out how mstsc.exe manages to successfully transmit the same odd string. On the byte level, I work supposedly identically.
I have uploaded the entire byte contents of the TPKT packages here for better comparison: https://pastebin.com/tLtfWHiP
I am grateful for any ideas.
Thanks and regards
Lukas P.

I tried a lot before I came up with a solution: adding space, zero width space chars like \u200B, before the load balancing string, and behind it. But the rd broker didn't take it.
Solution:
In case of an odd number of bytes, if we put a dot (U+002E) in the right place, the rd session broker can extract the required identifier for the targeted rd collection and the connection will be established correctly.
private void RdpLogic()
{
AdvancedSettings9.LoadBalanceInfo = ToLoadBalanceString($"tsv://MS Terminal Services Plugin.1.lbinfo");
}
private string ToLoadBalanceString(string loadBalanceInfo)
{
var temp = loadBalanceInfo;
if (temp.Length % 2 == 1) temp = temp.Insert(temp.LastIndexOf('.'), ".");
var final = Encoding.Unicode.GetString(Encoding.UTF8.GetBytes(temp + "\r\n"));
return final;
}
Samples:
ToLoadBalanceString("tsv://MS Terminal Services Plugin.1.even")
Result: 'tsv://MS Terminal Services Plugin.1.even/r/n'
ToLoadBalanceString("tsv://MS Terminal Services Plugin.1.odd")
Results in 'tsv://MS Terminal Services Plugin.1..odd/r/n'

Related

C# Renci SshNet The server response contains a null character at position 0x0000002A

i have multiple Raspberries running with SSH server:
(OpenSSH_7.4p1 Raspbian-10+deb9u7, OpenSSL 1.0.2u 20 Dec 2019).
And if i try to connect via Renci SshNet, i get the following error message:
Renci.SshNet.Common.SshConnectionException: "The server response
contains a null character at position 0x0000002A:
00000000 53 53 48 2D 32 2E 30 2D 4F 70 65 6E 53 53 48 5F
SSH-2.0-OpenSSH_ 00000010 37 2E 34 70 31 20 52 61 73 70 62 69 61 6E
2D 31 7.4p1 Raspbian-1 00000020 30 2B 64 65 62 39 75 37 0A 00
0+deb9u7..
A server must not send a null character before the Protocol Version
Exchange is complete.
More information is available here:
https://www.rfc-editor.org/rfc/rfc4253#section-4.2"
SshClient scClient = new SshClient("123.123.123.123", "pi", "raspberry");
scClient.Connect();
is it possible to change the behavior of the ssh server,
or even better; can i tell renci ssh to ignore these protocol errors?
I think it's a problem of the latest SSH.NET NuGet Package. Currently the newest is 2020.0.0. And the one prior to that is 2020.0.0-beta1.
2020.0.0 gives me this problem, 2020.0.0-beta1 does not.
I will report this issue on https://github.com/sshnet/SSH.NET/issues
EDIT:
2020.0.1 just got published. That doesn't seem to have this problem. I recommend you to try that version.

See my packet details via Wireshark as byte instead of hex

I want to build DHCP packet and in the build process i am get params from user for example Agent Circuit Id (string) - attribute number 82.
After build my packet i am send this packet and see the result via Wireshark
My problem is that when i see my packet i see my Agent Circuit Id value as hex and i want to see this value as byte for example:
string agentCircuitId = "33445566778899";
i want this field will be 2 bytes 33 44 55 66 77 88 99
in my result i try the string "1234" and the result is 31 32 33 34
http://s27.postimg.org/bdhe9j4hv/123.png
Any idea how to do that ?

Calling WAMS from Windows Forms application, freezes

I have a simple Windows Azure Mobile Service. I can get data from it by IOS, now I want to do it from Windows Forms application. My problem, it is not working. It is very strange, because when I call the same code from unit test from the same solution, it works, but when from a Windows Forms app, it freezes. Project targets .net 4.5 and references WAMS client lib by nuget.
Here is my code:
var testTable = WAMSService.MobileService.GetTable<HBCDataLib.WAMS.Test>();
var testResult = testTable.Take(1000).ToListAsync().Result;
By investigating it by Fiddler, i can see this:
CONNECT xy.azure-mobile.net:443 HTTP/1.1
Host: xy.azure-mobile.net
Connection: Keep-Alive
A SSLv3-compatible ClientHello handshake was found. Fiddler extracted the parameters below.
Version: 3.1 (TLS/1.0)
Random: 52 A0 0F 12 01 B1 9A 53 9A 2C 43 13 BD AD 44 6E 9D FB 2E A1 92 FC 5A C0 15 EB 72 30 B9 29 C4 B6
SessionID: empty
Extensions:
renegotiation_info 00
server_name xy.azure-mobile.net
elliptic_curves 00 05 00 18 00 20
ec_point_formats 01 00
SessionTicket TLS empty
Ciphers:
[002F] TLS_RSA_AES_128_SHA
[0035] TLS_RSA_AES_256_SHA
[0005] SSL_RSA_WITH_RC4_128_SHA
[000A] SSL_RSA_WITH_3DES_EDE_SHA
[C013] TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA
[C014] TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA
[C009] TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
[C00A] TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
[0032] TLS_DHE_DSS_WITH_AES_128_SHA
[0038] TLS_DHE_DSS_WITH_AES_256_SHA
[0013] SSL_DHE_DSS_WITH_3DES_EDE_SHA
[0004] SSL_RSA_WITH_RC4_128_MD5
Compression:
[00] NO_COMPRESSION
It is trivial, and works from unit test from the same solution. So, is it restricted (?!) to call WAMS from Windows forms app? Or what could be the problem?
Thanks in advance!

mono, xsp2, npgsql Could not load assembly

I am writing web service and I have two classes:
<%# WebService Language="C#" Class="CairoParts.ProductsInfoWS.ProductsInfoWS.cs" %>
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
namespace CairoParts.ProductsInfoWS
{
[WebService(Namespace = "http://localhost:8081/ProductsInfoWS")]
public class ProductsInfoWS : System.Web.Services.WebService
{
[WebMethod]
public List<string> ReceiveFile(byte[] bytes, string fileName, string supplier)
{
}
{
}
and Database.cs:
using System;
using System.Data;
using System.Configuration;
using Npgsql;
namespace CairoParts.ProductsInfoWS
{
public class Database
{
}
}
When i fire xsp2 and type in browser http://localhost:8081/ProductsInfoWS.asmx i get this error:
/usr/lib/mono/2.0/gmcs.exe:22858): WARNING **: The following assembly referenced from /tmp/vadmin-temp-aspnet-0/b8083b1b/assembly/shadow/94001eba/43c949ff_d7c95745_00000001/CairoParts.ProductsInfoWS.dll could not be loaded:
Assembly: Npgsql (assemblyref_index=2)
Version: 2.0.6.0
Public Key: 5d8b90d52f46fda7
The assembly was not found in the Global Assembly Cache, a path listed in the MONO_PATH environment variable, or in the location of the executing assembly (/tmp/vadmin-temp-aspnet-0/b8083b1b/assembly/shadow/94001eba/43c949ff_d7c95745_00000001).
My Npgsql.dll file is in 'bin' directory. Whats wrong...
It could be that the dll Npgsql.dll is strong-name signed and therefore needs to be placed in the global assembly cache (GAC), have you tried copying the dll into the location where the GAC is?
Hope this helps,
Best regards,
Tom.
Run:
monodis --assembly bin/Npgsql.dll
to verify that your assembly has the same version and public key that is referenced from CairoParts.ProductsInfoWS.dll.
In my local Mono installation compiled from sources, I have 3 directories in the gac for Npgsql:
1.0.5000.0__5d8b90d52f46fda7
2.0.0.0__5d8b90d52f46fda7
4.0.0.0__5d8b90d52f46fda7
and none of them has version 2.0.6.0.
Perhaps you need to recompile CairoParts.ProductsInfoWS.dll so that it references the assemblies present in your system.
I recompiled my project and run command that you have suggested, here's the output:
Assembly Table
Name: Npgsql
Hash Algoritm: 0x00008004
Version: 2.0.6.0
Flags: 0x00000001
PublicKey: BlobPtr (0x000020b1)
Dump:
0x00000000: 00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00
0x00000010: 00 24 00 00 52 53 41 31 00 04 00 00 01 00 01 00
0x00000020: 2B 3C 59 0B 2A 4E 3D 34 7E 68 78 DC 0F F4 D2 1E
0x00000030: B0 56 A5 04 20 25 0C 66 17 04 43 30 70 1D 35 C9
0x00000040: 80 78 A5 DF 97 A6 2D 83 C9 A2 DB 2D 07 25 23 A8
0x00000050: FC 49 13 98 25 4C 6B 89 32 9B 8C 1D CE F4 3A 1E
0x00000060: 7A A1 61 53 BC EA 2A E9 A4 71 14 56 24 82 6F 60
0x00000070: D7 C8 E7 1C D0 25 B5 54 A0 17 7B D9 35 A7 80 96
0x00000080: 29 F0 A7 AF C7 78 EB B4 AD 03 3E 1B F5 12 C1 A9
0x00000090: C6 CE EA 26 B0 77 BC 46 CA C9 38 00 43 5E 77 EE
Culture:
It's look like npgsql versions are ok, but webservice still yields the same error.
I kinda solve this issue by putting Database class in webservice asmx file, but it's more like workaround then a real solution...

Why do I get Cryptography_CSP_NoPrivateKey when using IIS but not when using VS development server?

I'm doing a web application that utilizes an external web service. This external web service requires me to sign each of my requests. So I'm using WebServicesClientProtocol class and .NET 2.0 by first consuming the external web service and then manually edit the Reference.cs file and change the extended class from System.Web.Services.Protocols.SoapHttpClientProtocol to Microsoft.Web.Services2.WebServicesClientProtocol. Then in the Page_Load method I have the following code:
try
{
// Create the ws endpoint
var uriServiceAddress = new Uri("urn:something-wse:something_NNNN");
var uribuilderViaRouter = new UriBuilder("http://xx.xxx.xx/SrvXXX_NNNN/Test.asmx");
var endpointReference = new EndpointReference(uriServiceAddress, uribuilderViaRouter.Uri);
// Create the ws client
var client = (WebServicesClientProtocol) new Test.Something();
client.Destination = endpointReference;
// Read the certificate from MyStore on LocalMachine
X509CertificateStore localStore = X509CertificateStore.LocalMachineStore(X509CertificateStore.MyStore);
X509SecurityToken securityToken = null;
if (!localStore.OpenRead()) throw new Exception("Unable to open localstore for read");
X509CertificateCollection certificateCollection = localStore.FindCertificateBySubjectString("email#subject.test");
if (certificateCollection.Count == 0) throw new Exception("Unable to obtain security token.");
securityToken = new X509SecurityToken(certificateCollection[0]);
localStore.Close();
// Attach the security toekn to the client request
client.RequestSoapContext.Security.Tokens.Add(securityToken);
client.RequestSoapContext.Security.Elements.Add(new MessageSignature(securityToken));
// Set the timeouts
client.RequestSoapContext.Security.Timestamp.TtlInSeconds = 2 * 60;
client.Timeout = 60 * 10 * 1000; // 10 mínútur ættu að duga í flest.
// Call the test function
DataSet set = ((Test.Something)client).searchMethod("Parameter 1", "Parameter 2");
Label1.Text = User.Identity.Name+ " worked! " + set.Tables.Count + " tables!";
}
catch (Exception exc)
{
Label1.Text = User.Identity.Name + " exception: " + exc.ToString();
}
This works fine when I run this using the Visual Studio Development Server but when I change to IIS it stops working and I get the ugly Cryptography_CSP_NoPrivateKey exception.
1) I have already read the Certificate properly into LocalMachine/MyStore using MMC and then I change the private key permissions using WSE 2.0 SP3 so that Everyone has full access to it. You can see this from here:
alt text http://www1.ruedenet.is/files/CertError1.png
2) I also set the property so that the Visual Studio Development Server is used when I debug the application:
alt text http://www1.ruedenet.is/files/CertError2.png
3) Then I run it and get a nice result:
alt text http://www1.ruedenet.is/files/CertError3.png
4) However, when I change the property to use IIS (and have VS create the Virtual Directory) like this:
alt text http://www1.ruedenet.is/files/CertError4.png
5) I also change the authentication method in IIS so that I get logged on (no reason for this really):
alt text http://www1.ruedenet.is/files/CertError5.png
6) So I get asked for a windows logon:
alt text http://www1.ruedenet.is/files/CertError6.png
7) And then my page runs and produces the error:
alt text http://www1.ruedenet.is/files/CertError7.png
If you could help me with this I would surely appreciate it. I have already spent hours on it and I don't want to spend more time if I'm making a fundamental error that you guys can see. BTW: I'm developing using Visual Studio 2008 on Windows Server 2008 with UAC turned off :-)
Really looking forward to hearing from you guys. Thanks.
:-)
I have solved this issue in a couple of steps:
1) I changed the user of the Default Application Pool to my username ...
alt text http://www1.ruedenet.is/files/ErrorFix1.png
... and that worked. I changed the user of the application pool back to NETWORK SERVICE and it didn't work again. This told me that the problem had something to do with the NETWORK SERVICE user. So I went back to looking for what could be the problem with the permissions of this user.
2) When browsing and reading the web I found Tim Jacobs' blogpost App-V 4.5 Certificate Galore at http://timjacobs.blogspot.com/2008/11/app-v-45-certificate-galore.html. Well, there wasn't anything new in it until at the end where he talks about the storage location of the private key on the disk. So I ran the FindPrivateKey.exe tool, ...
C:\MyTools>FindPrivateKey.exe My LocalMachine -t "8c 1a e6 1b 6d f2 f8 18 c8 26 b6 fa cd 60 fd 94 c7 a1 96 58"
Private key directory:
C:\Users\alfred\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-3612370315-2559787 071-3412320394-1135
Private key file name:
b3765d4123902371ea91c5c9a521932e_96ce3a90-5634-44e6-8aa2-acb123b8b3bf
... which tells me that the location of the private key is in the C:\Users\alfred\... directory and the NETWORK SERVICE user probably doesn't have access in to this directory!!!
3) I therefore followed Tim's suggestion to use MMC to export the certificate & private key from the Local Computer/Personal/Certificates and then import it into Local Computer/Trusted Root Certificate Authorities/Certificates. After having exported, FindPrivateKey.exe reported, ...
C:\MyTools>FindPrivateKey.exe My LocalMachine -t "8c 1a e6 1b 7d f1 f8 18 c8 26 b6 fa cd 60 fd 94 c7 a1 96 58"
FindPrivateKey failed for the following reason: No certificates with key '8c 1a e6 1b 7d f1 f8 18 c8 26 b6 fa cd 60 fd 94 c7 a1 96 58' found in the store.
... which tells me the export worked. After importing and copy pasting it back to Local Computer/Personal/Certificates I get...
C:\MyTools>FindPrivateKey.exe My LocalMachine -t "8c 1a e6 1b 7d f1 f8 18 c8 26 b6 fa cd 60 fd 94 c7 a1 96 58"
Private key directory:
C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
Private key file name:
b3765d4d5a902371ea91c5c9a521932e_96ce3a90-5634-44e6-8aa2-acbaccb8b3bf
...and now the private key is in a public place, the C:\ProgramData\... directory. I then changed the private key permissions of the NETWORK SERVICE user to Full Access using the X509 Certificate Tool as I had done before.
And now it works!!!
I just can't thank you enough for your blogpost Tim. Thank you.

Categories

Resources