internal static PipeSecurity?CreatePipeSecurity() { if (PlatformInformation.IsRunningOnMono) { // Pipe security and additional access rights constructor arguments // are not supported by Mono // https://github.com/dotnet/roslyn/pull/30810 // https://github.com/mono/mono/issues/11406 return(null); } var security = new PipeSecurity(); SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; // Restrict access to just this account. PipeAccessRule rule = new PipeAccessRule( identifier, PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow ); security.AddAccessRule(rule); security.SetOwner(identifier); return(security); }
/// <summary> /// Create an instance of the pipe. This might be the first instance, or a subsequent instance. /// There always needs to be an instance of the pipe created to listen for a new client connection. /// </summary> /// <returns>The pipe instance or throws an exception.</returns> private NamedPipeServerStream ConstructPipe(string pipeName) { CompilerServerLogger.Log("Constructing pipe '{0}'.", pipeName); SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; PipeSecurity security = new PipeSecurity(); // Restrict access to just this account. PipeAccessRule rule = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow); security.AddAccessRule(rule); security.SetOwner(identifier); NamedPipeServerStream pipeStream = new NamedPipeServerStream( pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, // Maximum connections. PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, PipeBufferSize, // Default input buffer PipeBufferSize, // Default output buffer security, HandleInheritability.None); CompilerServerLogger.Log("Successfully constructed pipe '{0}'.", pipeName); return(pipeStream); }
/// <summary> /// Instantiates an endpoint to act as a client /// </summary> /// <param name="pipeName">The name of the pipe to which we should connect.</param> internal void InternalConstruct(string pipeName) { ErrorUtilities.VerifyThrowArgumentLength(pipeName, nameof(pipeName)); _debugCommunications = (Environment.GetEnvironmentVariable("MSBUILDDEBUGCOMM") == "1"); _status = LinkStatus.Inactive; _asyncDataMonitor = new object(); _sharedReadBuffer = InterningBinaryReader.CreateSharedBuffer(); _packetStream = new MemoryStream(); _binaryWriter = new BinaryWriter(_packetStream); #if FEATURE_PIPE_SECURITY && FEATURE_NAMED_PIPE_SECURITY_CONSTRUCTOR if (!NativeMethodsShared.IsMono) { SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; PipeSecurity security = new PipeSecurity(); // Restrict access to just this account. We set the owner specifically here, and on the // pipe client side they will check the owner against this one - they must have identical // SIDs or the client will reject this server. This is used to avoid attacks where a // hacked server creates a less restricted pipe in an attempt to lure us into using it and // then sending build requests to the real pipe client (which is the MSBuild Build Manager.) PipeAccessRule rule = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite, AccessControlType.Allow); security.AddAccessRule(rule); security.SetOwner(identifier); _pipeServer = new NamedPipeServerStream ( pipeName, PipeDirection.InOut, 1, // Only allow one connection at a time. PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, PipeBufferSize, // Default input buffer PipeBufferSize, // Default output buffer security, HandleInheritability.None ); } else #endif { _pipeServer = new NamedPipeServerStream ( pipeName, PipeDirection.InOut, 1, // Only allow one connection at a time. PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, PipeBufferSize, // Default input buffer PipeBufferSize // Default output buffer ); } }
private void StartNamedPipeServer() { if (!StartServer) { return; } #if NETCOREAPP2_1 || NETCOREAPP3_1 || NET5_0 if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) { throw new PlatformNotSupportedException("The communication with the first instance is only supported on Windows"); } _server = new NamedPipeServerStream( PipeName, PipeDirection.In, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Message, PipeOptions.CurrentUserOnly); #elif NET461 using (var currentIdentity = WindowsIdentity.GetCurrent()) { var identifier = currentIdentity.Owner; // Grant full control to the owner so multiple servers can be opened. // Full control is the default per MSDN docs for CreateNamedPipe. var rule = new PipeAccessRule(identifier, PipeAccessRights.FullControl, AccessControlType.Allow); var pipeSecurity = new PipeSecurity(); pipeSecurity.AddAccessRule(rule); pipeSecurity.SetOwner(identifier); _server = new NamedPipeServerStream( PipeName, PipeDirection.In, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 0, 0, pipeSecurity); } #else #error Platform not supported #endif try { _server.BeginWaitForConnection(Listen, state: null !); // TODO-NULLABLE https://github.com/dotnet/runtime/pull/42442 } catch (ObjectDisposedException) { // The server was disposed before getting a connection } }
internal static NamedPipeServerStream CreateNamedPipeServer(string pipeName, int?inputBufferSize = null, int?outputBufferSize = null, int maxNumberOfServerInstances = 1, bool allowNewInstances = false) { inputBufferSize ??= PipeBufferSize; outputBufferSize ??= PipeBufferSize; #if FEATURE_PIPE_SECURITY && FEATURE_NAMED_PIPE_SECURITY_CONSTRUCTOR if (!NativeMethodsShared.IsMono) { SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; PipeSecurity security = new PipeSecurity(); // Restrict access to just this account. We set the owner specifically here, and on the // pipe client side they will check the owner against this one - they must have identical // SIDs or the client will reject this server. This is used to avoid attacks where a // hacked server creates a less restricted pipe in an attempt to lure us into using it and // then sending build requests to the real pipe client (which is the MSBuild Build Manager.) PipeAccessRights rights = PipeAccessRights.ReadWrite; if (allowNewInstances) { rights |= PipeAccessRights.CreateNewInstance; } PipeAccessRule rule = new PipeAccessRule(identifier, rights, AccessControlType.Allow); security.AddAccessRule(rule); security.SetOwner(identifier); return(new NamedPipeServerStream ( pipeName, PipeDirection.InOut, maxNumberOfServerInstances, // Only allow one connection at a time. PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, inputBufferSize.Value, // Default input buffer outputBufferSize.Value, // Default output buffer security, HandleInheritability.None )); } #endif return(new NamedPipeServerStream ( pipeName, PipeDirection.InOut, maxNumberOfServerInstances, // Only allow one connection at a time. PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, inputBufferSize.Value, // Default input buffer outputBufferSize.Value // Default output buffer )); }
// This is the code we use in the Create method called by the NamedPipeServerStream constructor private PipeSecurity GetPipeSecurityForCurrentUserOnly() { PipeSecurity security = new PipeSecurity(); using WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent(); SecurityIdentifier identifier = currentIdentity.Owner; PipeAccessRule rule = new PipeAccessRule(identifier, PipeAccessRights.FullControl, AccessControlType.Allow); security.AddAccessRule(rule); security.SetOwner(identifier); return(security); }
private void StartNamedPipeServer() { if (!StartServer) { return; } #if NETCOREAPP2_1 || NETCOREAPP3_0 _server = new NamedPipeServerStream( PipeName, PipeDirection.In, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Message, PipeOptions.CurrentUserOnly); #elif NET461 using (var currentIdentity = WindowsIdentity.GetCurrent()) { var identifier = currentIdentity.Owner; // Grant full control to the owner so multiple servers can be opened. // Full control is the default per MSDN docs for CreateNamedPipe. var rule = new PipeAccessRule(identifier, PipeAccessRights.FullControl, AccessControlType.Allow); var pipeSecurity = new PipeSecurity(); pipeSecurity.AddAccessRule(rule); pipeSecurity.SetOwner(identifier); _server = new NamedPipeServerStream( PipeName, PipeDirection.In, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 0, 0, pipeSecurity); } #else #error Platform not supported #endif try { _server.BeginWaitForConnection(Listen, state: null); } catch (ObjectDisposedException) { // The server was disposed before getting a connection } }
private NamedPipeServerStream CreateSecuredPipe() { var user = WindowsIdentity.GetCurrent().User; var security = new PipeSecurity(); security.AddAccessRule(new PipeAccessRule( user, PipeAccessRights.FullControl, AccessControlType.Allow)); security.SetOwner(user); security.SetGroup(user); return(new NamedPipeServerStream( pipe, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, MaxBytes, MaxBytes, security)); }
/// <summary> /// Create an instance of the pipe. This might be the first instance, or a subsequent instance. /// There always needs to be an instance of the pipe created to listen for a new client connection. /// </summary> /// <returns>The pipe instance or throws an exception.</returns> private NamedPipeServerStream ConstructPipe(string pipeName) { CompilerServerLogger.Log("Constructing pipe '{0}'.", pipeName); #if NET46 SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; PipeSecurity security = new PipeSecurity(); // Restrict access to just this account. PipeAccessRule rule = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow); security.AddAccessRule(rule); security.SetOwner(identifier); NamedPipeServerStream pipeStream = new NamedPipeServerStream( pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, // Maximum connections. PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, PipeBufferSize, // Default input buffer PipeBufferSize, // Default output buffer security, HandleInheritability.None); #else // The overload of NamedPipeServerStream with the PipeAccessRule // parameter was removed in netstandard. However, the default // constructor does not provide WRITE_DAC, so attempting to use // SetAccessControl will always fail. So, completely ignore ACLs on // netcore, and trust that our `ClientAndOurIdentitiesMatch` // verification will catch any invalid connections. // Issue to add WRITE_DAC support: // https://github.com/dotnet/corefx/issues/24040 NamedPipeServerStream pipeStream = new NamedPipeServerStream( pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, // Maximum connections. PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, PipeBufferSize, // Default input buffer PipeBufferSize); // Default output buffer #endif CompilerServerLogger.Log("Successfully constructed pipe '{0}'.", pipeName); return(pipeStream); }
PipeSecurity makePipeSecurity() { var pipeSecurity = new PipeSecurity(); var admins = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null); var system = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null); if (IsElevated) { pipeSecurity.SetOwner(admins); pipeSecurity.SetGroup(system); } pipeSecurity.AddAccessRule(new PipeAccessRule(admins, PipeAccessRights.FullControl, AccessControlType.Allow)); pipeSecurity.AddAccessRule(new PipeAccessRule(system, PipeAccessRights.FullControl, AccessControlType.Allow)); pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null), PipeAccessRights.ReadWrite, AccessControlType.Allow)); return(pipeSecurity); }
private Task AddBuildServiceNamedPipeServerAsync() { return(Task.Factory.StartNew(async() => { try { var identity = WindowsIdentity.GetCurrent(); var identifier = identity.Owner; var security = new PipeSecurity(); // Restrict access to just this account. var rule = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow); security.AddAccessRule(rule); security.SetOwner(identifier); // And our current elevation level var principal = new WindowsPrincipal(identity); var isServerElevated = principal.IsInRole(WindowsBuiltInRole.Administrator); using (var serverPipe = new NamedPipeServerStream( _pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, 0x10000, // 64k input buffer 0x10000, // 64k output buffer security, HandleInheritability.None)) { // As soon as we receive a connection, spin up another background // listener to wait for the next connection await serverPipe.WaitForConnectionAsync(); _ = AddBuildServiceNamedPipeServerAsync(); await HandleRequestAsync(serverPipe, isServerElevated); } } catch (Exception ex) { await AttemptLogErrorAsync( $"Error in Blazor AutoRebuildService:\n{ex.Message}\n{ex.StackTrace}"); } }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default)); }
/// <summary> /// Create an instance of the pipe. This might be the first instance, or a subsequent instance. /// There always needs to be an instance of the pipe created to listen for a new client connection. /// </summary> /// <returns>The pipe instance, or NULL if the pipe couldn't be created..</returns> private NamedPipeServerStream ConstructPipe() { // Add the process ID onto the pipe name so each process gets a unique pipe name. // The client must user this algorithm too to connect. string pipeName = basePipeName + Process.GetCurrentProcess().Id.ToString(); try { CompilerServerLogger.Log("Constructing pipe '{0}'.", pipeName); SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; PipeSecurity security = new PipeSecurity(); // Restrict access to just this account. PipeAccessRule rule = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow); security.AddAccessRule(rule); security.SetOwner(identifier); NamedPipeServerStream pipeStream = new NamedPipeServerStream( pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, // Maximum connections. PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, PipeBufferSize, // Default input buffer PipeBufferSize, // Default output buffer security, HandleInheritability.None); CompilerServerLogger.Log("Successfully constructed pipe '{0}'.", pipeName); return(pipeStream); } catch (Exception e) { // Windows may not create the pipe for a number of reasons. CompilerServerLogger.LogException(e, string.Format("Construction of pipe '{0}' failed", pipeName)); return(null); } }
// Workaround: create the pipe via API call // we have to do it this way, since NamedPipeServerStream() for netstd still lacks a few CTORs // and _stream.SetAccessControl(pipesec); only keeps throwing ACCESS_DENIED errors at us // References: // - https://github.com/dotnet/corefx/issues/30170 (closed, continued in 31190) // - https://github.com/dotnet/corefx/issues/31190 System.IO.Pipes.AccessControl package does not work // - https://github.com/dotnet/corefx/issues/24040 NamedPipeServerStream: Provide support for WRITE_DAC // - https://github.com/dotnet/corefx/issues/34400 Have a mechanism for lower privileged user to connect to a privileged user's pipe private static SafePipeHandle CreatePipeNative(string name, int inbuf, int outbuf) { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return(null); // Windows only } var pinningHandle = new GCHandle(); try { // owner gets full access, everyone else read/write var pipesec = new PipeSecurity(); using (var currentIdentity = WindowsIdentity.GetCurrent()) { var sidOwner = currentIdentity.Owner; var sidWorld = new SecurityIdentifier(WellKnownSidType.WorldSid, null); pipesec.SetOwner(sidOwner); pipesec.AddAccessRule(new PipeAccessRule(sidOwner, PipeAccessRights.FullControl, AccessControlType.Allow)); pipesec.AddAccessRule(new PipeAccessRule(sidWorld, PipeAccessRights.ReadWrite, AccessControlType.Allow)); } // create a security descriptor and assign it to the security attribs var secAttrs = new SECURITY_ATTRIBUTES(); byte[] sdBytes = pipesec.GetSecurityDescriptorBinaryForm(); pinningHandle = GCHandle.Alloc(sdBytes, GCHandleType.Pinned); unsafe { fixed(byte *pSD = sdBytes) { secAttrs.lpSecurityDescriptor = (IntPtr)pSD; } } // a bunch of constants we will need shortly const int PIPE_ACCESS_DUPLEX = 0x00000003; const int FILE_FLAG_OVERLAPPED = 0x40000000; const int WRITE_DAC = 0x00040000; const int PIPE_TYPE_BYTE = 0x00000000; const int PIPE_READMODE_BYTE = 0x00000000; const int PIPE_UNLIMITED_INSTANCES = 255; // create the pipe via API call var rawHandle = CreateNamedPipe( @"\\.\pipe\" + name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, PIPE_UNLIMITED_INSTANCES, (uint)inbuf, (uint)outbuf, 5 * 1000, secAttrs ); // make a SafePipeHandle() from it var handle = new SafePipeHandle(rawHandle, true); if (handle.IsInvalid) { throw new Win32Exception(Marshal.GetLastWin32Error()); } // return it (to be packaged) return(handle); } finally { if (pinningHandle.IsAllocated) { pinningHandle.Free(); } } }
/// <summary> /// Create an instance of the pipe. This might be the first instance, or a subsequent instance. /// There always needs to be an instance of the pipe created to listen for a new client connection. /// </summary> /// <returns>The pipe instance or throws an exception.</returns> private NamedPipeServerStream ConstructPipe(string pipeName) { CompilerServerLogger.Log("Constructing pipe '{0}'.", pipeName); #if NET472 PipeSecurity security; PipeOptions pipeOptions = PipeOptions.Asynchronous | PipeOptions.WriteThrough; if (!PlatformInformation.IsRunningOnMono) { security = new PipeSecurity(); SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; // Restrict access to just this account. PipeAccessRule rule = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow); security.AddAccessRule(rule); security.SetOwner(identifier); } else { // Pipe security and additional access rights constructor arguments // are not supported by Mono // https://github.com/dotnet/roslyn/pull/30810 // https://github.com/mono/mono/issues/11406 security = null; // This enum value is implemented by Mono to restrict pipe access to // the current user const int CurrentUserOnly = unchecked ((int)0x20000000); pipeOptions |= (PipeOptions)CurrentUserOnly; } NamedPipeServerStream pipeStream = new NamedPipeServerStream( pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, // Maximum connections. PipeTransmissionMode.Byte, pipeOptions, PipeBufferSize, // Default input buffer PipeBufferSize, // Default output buffer security, HandleInheritability.None); #else // The overload of NamedPipeServerStream with the PipeAccessRule // parameter was removed in netstandard. However, the default // constructor does not provide WRITE_DAC, so attempting to use // SetAccessControl will always fail. So, completely ignore ACLs on // netcore, and trust that our `ClientAndOurIdentitiesMatch` // verification will catch any invalid connections. // Issue to add WRITE_DAC support: // https://github.com/dotnet/corefx/issues/24040 NamedPipeServerStream pipeStream = new NamedPipeServerStream( pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, // Maximum connections. PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, PipeBufferSize, // Default input buffer PipeBufferSize); // Default output buffer #endif CompilerServerLogger.Log("Successfully constructed pipe '{0}'.", pipeName); return(pipeStream); }
// https://github.com/dotnet/corefx/blob/e753ecfe12d6af9b7fec5dee154395e7d29caed9/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.Windows.cs#L31-L108 private static SafePipeHandle CreatePipeHandle(string pipeName, PipeDirection direction, int maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, int inBufferSize, int outBufferSize, PipeSecurity pipeSecurity, HandleInheritability inheritability, PipeAccessRights additionalAccessRights) { Debug.Assert(pipeName != null && pipeName.Length != 0, "fullPipeName is null or empty"); Debug.Assert(direction >= PipeDirection.In && direction <= PipeDirection.InOut, "invalid pipe direction"); Debug.Assert(inBufferSize >= 0, "inBufferSize is negative"); Debug.Assert(outBufferSize >= 0, "outBufferSize is negative"); Debug.Assert((maxNumberOfServerInstances >= 1 && maxNumberOfServerInstances <= 254) || (maxNumberOfServerInstances == MaxAllowedServerInstances), "maxNumberOfServerInstances is invalid"); Debug.Assert(transmissionMode >= PipeTransmissionMode.Byte && transmissionMode <= PipeTransmissionMode.Message, "transmissionMode is out of range"); string fullPipeName = Path.GetFullPath(@"\\.\pipe\" + pipeName); // Make sure the pipe name isn't one of our reserved names for anonymous pipes. if (string.Equals(fullPipeName, @"\\.\pipe\anonymous", StringComparison.OrdinalIgnoreCase)) { throw new ArgumentOutOfRangeException(nameof(pipeName)); } if ((options & PipeOptions.CurrentUserOnly) != 0) { Debug.Assert(pipeSecurity == null); using (WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent()) { SecurityIdentifier identifier = currentIdentity.Owner; // Grant full control to the owner so multiple servers can be opened. // Full control is the default per MSDN docs for CreateNamedPipe. PipeAccessRule rule = new PipeAccessRule(identifier, PipeAccessRights.FullControl, AccessControlType.Allow); pipeSecurity = new PipeSecurity(); pipeSecurity.AddAccessRule(rule); pipeSecurity.SetOwner(identifier); } // PipeOptions.CurrentUserOnly is special since it doesn't match directly to a corresponding Win32 valid flag. // Remove it, while keeping others untouched since historically this has been used as a way to pass flags to CreateNamedPipe // that were not defined in the enumeration. options &= ~PipeOptions.CurrentUserOnly; } int openMode = (int)direction | (int)(maxNumberOfServerInstances == 1 ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0) | (int)options | (int)additionalAccessRights; // We automatically set the ReadMode to match the TransmissionMode. int pipeModes = (int)transmissionMode << 2 | (int)transmissionMode << 1; // Convert -1 to 255 to match win32 (we asserted that it is between -1 and 254). if (maxNumberOfServerInstances == MaxAllowedServerInstances) { maxNumberOfServerInstances = 255; } var pinningHandle = new GCHandle(); try { SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(inheritability, pipeSecurity, ref pinningHandle); SafePipeHandle handle = CreateNamedPipe(fullPipeName, openMode, pipeModes, maxNumberOfServerInstances, outBufferSize, inBufferSize, 0, ref secAttrs); if (handle.IsInvalid) { throw new Win32Exception(Marshal.GetLastWin32Error()); } return(handle); } finally { if (pinningHandle.IsAllocated) { pinningHandle.Free(); } } }
public async Task RunAsync() { _namedPipeClient = new NamedPipeClientStream(".", "CosmosSerial1", PipeDirection.InOut); var pipeSecurity = new PipeSecurity(); var identity = WindowsIdentity.GetCurrent().User; var pipeAccessRule = new PipeAccessRule( identity, PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow); pipeSecurity.AddAccessRule(pipeAccessRule); pipeSecurity.SetOwner(identity); _namedPipeServer = new NamedPipeServerStream( "CosmosSerial", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.None, 256, 256, pipeSecurity, HandleInheritability.None); _ = Task.Run(WaitForNamedPipeConnections); using (var reader = new StreamReader(_tcpClient.GetStream())) { while (_tcpClient.Connected) { if (_tcpClient.Available > 0) { var command = await reader.ReadLineAsync().ConfigureAwait(false); var parts = command.Split(';'); switch (parts[0]) { case "CreateVirtualMachine": CreateVirtualMachine(parts[1], parts[2], parts[3]); break; case "RemoveVirtualMachine": RemoveVirtualMachine(parts[1]); break; case "StartVirtualMachine": StartVirtualMachine(parts[1]); break; case "StopVirtualMachine": StopVirtualMachine(parts[1]); break; } reader.BaseStream.WriteByte(0x20); } else { await Task.Delay(1000).ConfigureAwait(false); } } } }