protected void ClientThreadEntry() { try { TcpListener listenerV4 = new TcpListener(IPAddress.Any, PortNumber); TcpListener listenerV6 = new TcpListener(IPAddress.IPv6Any, PortNumber); listenerV4.Start(10); listenerV6.Start(10); // Start listening for connections. Log.WriteLine("Listening for TCP connections on port " + PortNumber + "...\n", Severity.Debug); while (!Stopping) { TcpClient ClientRequest; try { if (listenerV4.Pending()) { ClientRequest = listenerV4.AcceptTcpClient(); } else if (listenerV6.Pending()) { ClientRequest = listenerV6.AcceptTcpClient(); } else { Thread.Sleep(250); continue; } Log.WriteLine("TCP Client accepted.\n", Severity.Debug); NetworkStream = new SslStream(ClientRequest.GetStream(), false); NetworkStream.AuthenticateAsServer(GetRemoteDesktopCertificate(), false, SslProtocols.Tls12, true); if (!NetworkStream.IsAuthenticated) { NetworkStream = null; Log.WriteLine("Unable to authenticate incoming connection from " + ((IPEndPoint)ClientRequest.Client.RemoteEndPoint).Address.ToString() + ".", Severity.Warning); ClientRequest.Close(); continue; } if (!NetworkStream.IsEncrypted) { NetworkStream = null; Log.WriteLine("Unable to encrypt incoming connection from " + ((IPEndPoint)ClientRequest.Client.RemoteEndPoint).Address.ToString() + ".", Severity.Warning); ClientRequest.Close(); continue; } // Display the properties and settings for the authenticated stream. Log.WriteLine("Authentication successful [host].\n", Severity.Debug); #if DEBUG DisplaySecurityLevel(Log, NetworkStream, Severity.Debug); DisplaySecurityServices(Log, NetworkStream, Severity.Debug); DisplayCertificateInformation(Log, NetworkStream, Severity.Debug); DisplayStreamProperties(Log, NetworkStream, Severity.Debug); #endif // Transmit our version info as a hello. System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location); string version = fvi.FileVersion; string XmlMsg = "<Portal-Version Core-Library=\"" + fvi.FileVersion + "\" />"; byte[] RawMsg = Encoding.Unicode.GetBytes(XmlMsg); if (NetworkStream != null) { SendMessage(NetworkStream, RawMsg); } } catch (Win32Exception ex) { Log.WriteLine("Exception accepting new connection: " + ex.ToString(), Severity.Debug); if ((uint)ex.ErrorCode == 0x80004005) { // The credentials supplied to the pacakage were not recognized. // This error comes up rom NetworkStream.AuthenticateAsServer() or GetRemoteDesktopCertificate() for localhost slave when there is no administrative access. Log.WriteLine("This exception usually indicates that administrative access was required but not present.", Severity.Debug); } continue; } catch (Exception ex) { // Note: "The credentials supplied to the package were not recognized" is probably a sign that the code doesn't have Administrator access and can't access the subsystem or certificate it needs. Log.WriteLine("Exception accepting new connection: " + ex.ToString(), Severity.Debug); continue; } try { ServiceConnection(NetworkStream, ClientRequest, ClientRequest.GetStream()); } catch (Exception ex) { Log.WriteLine("Exception servicing connection: " + ex.ToString(), Severity.Debug); } lock (ProcessLock) { // Setting ConnectedProcess to null before accepting a new connection is essential to security. It prevents access to the console without a new authentication and Connect-Terminal. ConnectedProcess = null; // If we aren't attached to a console, FreeConsole() would return ERROR_INVALID_PARAMETER. ConsoleApi.FreeConsole(); Log.WriteLine("Closing connection in SlaveCore (if it isn't already).", Severity.Debug); if (ClientRequest != null) { ClientRequest.Dispose(); ClientRequest = null; } if (Conin != null) { Conin.Dispose(); Conin = null; } if (CT != null) { CT.Dispose(); CT = null; } } } lock (ProcessLock) { ConnectedProcess = null; foreach (var kvp in Processes) { kvp.Value.Dispose(); } Processes.Clear(); } } catch (Exception e) { Log.WriteLine("Error: " + e.ToString(), Severity.Error); } }