using System; using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Security.Principal; using System.Text; namespace ScreenConnect; public class WindowsClientToolkit : ClientToolkit { private class WindowsProxyAttempter : IProxyAttempter { public IEnumerable GetPossibleProxyUris(Uri endPointUri) { Uri proxyUri = null; if (Uri.TryCreate(WindowsExtensions.TryUnprotectString(ApplicationSettings.Instance.ExplicitProxyUri, Guid.Empty), UriKind.Absolute, out proxyUri)) { yield return proxyUri; } if (Uri.TryCreate(WindowsExtensions.TryUnprotectString(ApplicationSettings.Instance.DiscoveredProxyUri, Guid.Empty), UriKind.Absolute, out proxyUri)) { yield return proxyUri; } yield return null; if (TryGetSystemWebProxyUri(endPointUri, ref proxyUri)) { yield return proxyUri; } foreach (var item in WindowsExtensions.TryGetValidSessionInfos().SafeEnumerate()) { if (TryGetSystemWebProxyUri(endPointUri, item.SessionID, ref proxyUri)) { yield return proxyUri; } } } private bool TryGetSystemWebProxyUri(Uri endPointUri, int impersonateTokenFromSessionID, ref Uri proxyUri) { IntPtr phToken = default(IntPtr); try { if (WindowsExtensions.GetTrueOSVersion() < new Version(5, 1) || !WindowsNative.WTSQueryUserToken(impersonateTokenFromSessionID, out phToken)) { return false; } WindowsNative.RegDisablePredefinedCache(); WindowsImpersonationContext val = WindowsIdentity.Impersonate(phToken); try { return TryGetSystemWebProxyUri(endPointUri, ref proxyUri); } finally { ((IDisposable)val)?.Dispose(); } } catch { return false; } finally { WindowsNative.CloseHandle(phToken); } } private bool TryGetSystemWebProxyUri(Uri endPointUri, ref Uri proxyUri) { try { endPointUri = new UriBuilder(Uri.UriSchemeHttp, endPointUri.Host, endPointUri.Port).Uri; IWebProxy systemWebProxy = WebRequest.GetSystemWebProxy(); proxyUri = systemWebProxy.GetProxy(endPointUri); if (proxyUri.Host == endPointUri.Host) { return false; } if (systemWebProxy.Credentials == null) { return true; } NetworkCredential credential = systemWebProxy.Credentials.GetCredential(proxyUri, null); proxyUri = proxyUri.AddUserInfo(Extensions.WindowsDomainUserNameToString(credential.Domain, credential.UserName), credential.Password); return true; } catch { return false; } } public void NotifyProxyUriWorking(Uri proxyUri) { if (proxyUri.SafeNav((Uri p) => p.AbsoluteUri) != WindowsExtensions.TryUnprotectString(ApplicationSettings.Instance.ExplicitProxyUri, Guid.Empty)) { ApplicationSettings.Instance.DiscoveredProxyUri = WindowsExtensions.ProtectString(proxyUri.SafeNav((Uri p) => p.AbsoluteUri), Guid.Empty); } } } private class WindowsClientClientResourceManager : ResourcesClientResourceManager { public override ICollection LoadResourcePacks() { return (from _ in new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).GetFiles("*" + FileExtension) select LoadResourcePackFromFile(_.FullName)).ToList(); } private ResourcePack LoadResourcePackFromFile(string filePath) { using FileStream fileStream = File.OpenRead(filePath); MemoryStream memoryStream = new MemoryStream(); fileStream.WriteTo(memoryStream, 1048576L); memoryStream.Position = 0L; return LoadResourcePack(filePath, LoadResourcesFromStream(memoryStream)); } } public unsafe override NetworkConnection ConnectNetworkConnection(Uri endPointUri, Uri httpProxyUri) { if (httpProxyUri == null) { return base.ConnectNetworkConnection(endPointUri, null); } bool flag = false; bool flag2 = false; byte[] array = new byte[4096]; byte[] array2 = new byte[4096]; fixed (byte* pvBuffer = array) { fixed (byte* pvBuffer2 = array2) { while (true) { WindowsNative.SecHandle secHandle = default(WindowsNative.SecHandle); WindowsNative.SecHandle secHandle2 = default(WindowsNative.SecHandle); WindowsNative.SecBuffer secBuffer = new WindowsNative.SecBuffer { BufferType = 2u, pvBuffer = pvBuffer }; WindowsNative.SecBuffer secBuffer2 = new WindowsNative.SecBuffer { BufferType = 2u, pvBuffer = pvBuffer2 }; WindowsNative.SecBufferDesc secBufferDesc = new WindowsNative.SecBufferDesc { cBuffers = 1u, pBuffers = &secBuffer }; WindowsNative.SecBufferDesc secBufferDesc2 = new WindowsNative.SecBufferDesc { cBuffers = 1u, pBuffers = &secBuffer2 }; ulong num = 0uL; int num2 = 0; string text = null; Socket socket = null; try { socket = ClientNetworkExtensions.ConnectTcpSocket(httpProxyUri); using (NetworkStream stream = new NetworkStream(socket)) { using StreamReader streamReader = new StreamReader(stream, Encoding.ASCII); using StreamWriter streamWriter = new StreamWriter(stream, Encoding.ASCII); bool flag3; do { streamWriter.WriteLine("CONNECT {0}:{1} HTTP/1.1", endPointUri.Host, endPointUri.Port); streamWriter.WriteLine("Host: " + httpProxyUri.Host); if (flag) { if (secHandle.dwLower == (IntPtr)0 && secHandle.dwUpper == (IntPtr)0) { if (!string.IsNullOrEmpty(httpProxyUri.UserInfo)) { (string, string) tuple = Extensions.ParseCredentialsString(httpProxyUri.UserInfo, isUrlEncoded: true); NetworkCredential networkCredential = Extensions.ParseWindowsCredentials(tuple.Item1, tuple.Item2); fixed (char* domain = networkCredential.Domain) { fixed (char* userName = networkCredential.UserName) { fixed (char* password = networkCredential.Password) { WindowsNative.SEC_WINNT_AUTH_IDENTITY sEC_WINNT_AUTH_IDENTITY = new WindowsNative.SEC_WINNT_AUTH_IDENTITY { Domain = domain, DomainLength = networkCredential.Domain.Length, User = userName, UserLength = networkCredential.UserName.Length, Password = password, PasswordLength = networkCredential.Password.Length, Flags = 2 }; WindowsNative.AcquireCredentialsHandle(null, "NTLM", 2, null, &sEC_WINNT_AUTH_IDENTITY, null, null, &secHandle, &num).AssertWin32ResultZero(); } } } } else { WindowsNative.AcquireCredentialsHandle(null, "NTLM", 2, null, null, null, null, &secHandle, &num).AssertWin32ResultZero(); } secBuffer.cbBuffer = array.Length; WindowsNative.InitializeSecurityContext(&secHandle, null, httpProxyUri.Host, 2076, 0, 16, null, 0, &secHandle2, &secBufferDesc, &num2, null).AssertWin32Result(0, 590610); } else if (text != null) { byte[] array3 = Convert.FromBase64String(text); Buffer.BlockCopy(array3, 0, array2, 0, array3.Length); secBuffer2.cbBuffer = array3.Length; secBuffer.cbBuffer = array.Length; WindowsNative.InitializeSecurityContext(&secHandle, &secHandle2, httpProxyUri.Host, 2076, 0, 16, &secBufferDesc2, 0, &secHandle2, &secBufferDesc, &num2, null).AssertWin32ResultZero(); } string text2 = Convert.ToBase64String(array, 0, secBuffer.cbBuffer); streamWriter.WriteLine("Proxy-Authorization: NTLM " + text2); streamWriter.WriteLine("Proxy-Connection: Keep-Alive"); } else if (flag2 && !string.IsNullOrEmpty(httpProxyUri.UserInfo)) { streamWriter.WriteLine("Proxy-Authorization: " + Extensions.GetBasicAuthorizationHeaderString(httpProxyUri.UserInfo)); } streamWriter.WriteLine(); streamWriter.Flush(); int num3 = -1; int num4 = -1; string text3 = null; string text4 = null; flag3 = false; while (!string.IsNullOrEmpty(text3 = streamReader.ReadLine())) { string[] array4 = text3.Split(new char[0]); if (text4 == null) { text4 = text3; } if (array4[0].StartsWith("HTTP/")) { num3 = int.Parse(array4[1]); } else if (array4[0] == "Content-Length:") { num4 = int.Parse(array4[1]); } else if (array4[0] == "Connection:" && array4[1] == "close") { flag3 = true; } else if (array4[0] == "Proxy-Authenticate:" && array4[1] == "NTLM" && array4.Length == 3) { text = array4[2]; } else if (array4[0] == "Proxy-Authenticate:" && array4[1] == "NTLM" && array4.Length == 2) { flag = true; } else if (array4[0] == "Proxy-Authenticate:" && array4[1] == "Basic") { flag2 = true; } } if (num4 != -1) { char[] buffer = new char[num4]; streamReader.ReadBlock(buffer, 0, num4); } switch (num3) { case 200: return new SocketNetworkConnection(socket); case -1: throw new ProxyException("Proxy closed connection with no response.", null); case 407: if (flag || flag2) { break; } goto default; default: throw new ProxyException("Error from proxy: " + text4, null); } } while (!flag3); } socket.DisposeQuietly(); } catch (Exception ex) { socket.DisposeQuietly(); if (ex is ProxyException) { throw; } throw new ProxyException("Error connecting through proxy: " + ex.Message, ex); } finally { if (secHandle2.dwLower != (IntPtr)0 || secHandle2.dwUpper != (IntPtr)0) { WindowsNative.DeleteSecurityContext(&secHandle2); } if (secHandle.dwLower != (IntPtr)0 || secHandle.dwUpper != (IntPtr)0) { WindowsNative.FreeCredentialsHandle(&secHandle); } } } } } } public override IPAddress[] GetIPAddresses(string hostOrIPAddressString) { try { IPAddress[] array = base.GetIPAddresses(hostOrIPAddressString).AssertNonNullOrEmpty(); NameValueCollection nameValueCollection = Extensions.DecodeQueryString(ApplicationSettings.Instance.HostToAddressMap); nameValueCollection[hostOrIPAddressString] = array.SelectToString().Join(',') + "-" + DateTime.UtcNow; ApplicationSettings.Instance.HostToAddressMap = nameValueCollection.EncodeQueryString(); return array; } catch { (Extensions.DecodeQueryString(ApplicationSettings.Instance.HostToAddressMap)[hostOrIPAddressString]?.SplitFirstNullable('-')).GetValueOrDefault().Deconstruct(out var key, out var value); if (key.IsNotNullOrWhitespace() && value.IsNotNullOrWhitespace() && DateTime.UtcNow - value.TryParseDateTime() < TimeSpan.FromDays(30.0)) { IPAddress[] array2 = key.Split(new char[1] { ',' }).Select(NetworkExtensions.TryParseIPAddress).WhereNotDefault() .ToArray(); if (!array2.IsNullOrEmpty()) { return array2; } } throw; } } public override Guid GetMachineBasedSessionID() { byte[] machineGuidBytes = Extensions.EmptyArray(); byte[] bytes = Encoding.UTF8.GetBytes(Environment.MachineName); Extensions.Try(delegate { machineGuidBytes = Singleton.Instance.GetMachineGuid().ToByteArray(); }); byte[] array = new byte[machineGuidBytes.Length + bytes.Length]; Buffer.BlockCopy(machineGuidBytes, 0, array, 0, machineGuidBytes.Length); Buffer.BlockCopy(bytes, 0, array, machineGuidBytes.Length, bytes.Length); return Extensions.DeriveGuid(array); } public override long GetApplicationPingTimeMilliseconds() { return ApplicationSettings.Instance.ApplicationPingTimeSeconds * 1000; } public override IProxyAttempter CreateProxyAttempter() { return new WindowsProxyAttempter(); } public override int GetKeepAliveTimeSeconds() { return ApplicationSettings.Instance.KeepAliveTimeSeconds; } public override int GetClientConnectionMaxRetrySleepMilliseconds() { return ApplicationSettings.Instance.MaxRetrySleepMilliseconds; } public override int GetClientConnectionLimitPeriodMilliseconds() { return ApplicationSettings.Instance.ClientConnectionLimitPeriodMilliseconds; } public override int GetClientConnectionLimitPerPeriodBeforeMaxWait() { return ApplicationSettings.Instance.ClientConnectionLimitPerPeriodBeforeMaxWait; } public override string ExpandEnvironmentVariables(string s) { return s?.Pipe(Environment.ExpandEnvironmentVariables); } public override IVideoFileEncoder CreateVideoFileEncoder() { return new VfwEncoder(); } public override ResourceManagerEx CreateClientResourceManager() { return new WindowsClientClientResourceManager(); } }