Example #1
0
 public void ConnectedToChildProcess()
 {
     // Close the writing end of the pipe - it's still open in the child process.
     // If we didn't close it, a StreamReader would never reach EndOfStream.
     _writingEnd?.Dispose();
     IsConnected = true;
 }
Example #2
0
 protected virtual void Dispose(bool disposing)
 {
     if (disposing)
     {
         PipeHandle.Dispose();
     }
 }
Example #3
0
 protected override void Dispose(bool disposing)
 {
     if (handle != null && disposing)
     {
         handle.Dispose();
     }
 }
Example #4
0
        /// <summary>
        /// Helper method to open a named pipe via native APIs and return in
        /// .Net NamedPipeClientStream wrapper object.
        /// </summary>
        protected override NamedPipeClientStream DoConnect(int timeout)
        {
            // Create pipe flags.
            uint pipeFlags = NamedPipeNative.FILE_FLAG_OVERLAPPED;

            //
            // WaitNamedPipe API is not supported by Windows Server container now, so we need to repeatedly
            // attempt connection to pipe server until timeout expires.
            //
            int            startTime   = Environment.TickCount;
            int            elapsedTime = 0;
            SafePipeHandle pipeHandle  = null;

            do
            {
                // Get handle to pipe.
                pipeHandle = NamedPipeNative.CreateFile(
                    _pipeName,
                    NamedPipeNative.GENERIC_READ | NamedPipeNative.GENERIC_WRITE,
                    0,
                    IntPtr.Zero,
                    NamedPipeNative.OPEN_EXISTING,
                    pipeFlags,
                    IntPtr.Zero);

                int lastError = Marshal.GetLastWin32Error();
                if (pipeHandle.IsInvalid)
                {
                    if (lastError == NamedPipeNative.ERROR_FILE_NOT_FOUND)
                    {
                        elapsedTime = unchecked (Environment.TickCount - startTime);
                        Thread.Sleep(100);
                        continue;
                    }
                    else
                    {
                        throw new PSInvalidOperationException(
                                  StringUtil.Format(RemotingErrorIdStrings.CannotConnectContainerNamedPipe, lastError));
                    }
                }
                else
                {
                    break;
                }
            } while (elapsedTime < timeout);

            try
            {
                return(new NamedPipeClientStream(
                           PipeDirection.InOut,
                           true,
                           true,
                           pipeHandle));
            }
            catch (Exception)
            {
                pipeHandle.Dispose();
                throw;
            }
        }
        public AnonymousPipeClientStream(PipeDirection direction, string pipeHandleAsString)
            : base(direction, 0)
        {
            if (direction == PipeDirection.InOut)
            {
                throw new NotSupportedException(SR.NotSupported_AnonymousPipeUnidirectional);
            }
            ArgumentNullException.ThrowIfNull(pipeHandleAsString);

            // Initialize SafePipeHandle from String and check if it's valid. First see if it's parseable
            bool parseable = long.TryParse(pipeHandleAsString, out long result);

            if (!parseable)
            {
                throw new ArgumentException(SR.Argument_InvalidHandle, nameof(pipeHandleAsString));
            }

            // next check whether the handle is invalid
            SafePipeHandle safePipeHandle = new SafePipeHandle((IntPtr)result, true);

            if (safePipeHandle.IsInvalid)
            {
                safePipeHandle.Dispose();
                throw new ArgumentException(SR.Argument_InvalidHandle, nameof(pipeHandleAsString));
            }

            Init(direction, safePipeHandle);
        }
Example #6
0
        private void HandleAcceptedSocket(Socket acceptedSocket)
        {
            var serverHandle = new SafePipeHandle(acceptedSocket);

            try
            {
                if (IsCurrentUserOnly)
                {
                    uint serverEUID = Interop.Sys.GetEUid();

                    uint peerID;
                    if (Interop.Sys.GetPeerID(serverHandle, out peerID) == -1)
                    {
                        throw CreateExceptionForLastError(_instance?.PipeName);
                    }

                    if (serverEUID != peerID)
                    {
                        throw new UnauthorizedAccessException(string.Format(SR.UnauthorizedAccess_ClientIsNotCurrentUser, peerID, serverEUID));
                    }
                }

                ConfigureSocket(acceptedSocket, serverHandle, _direction, _inBufferSize, _outBufferSize, _inheritability);
            }
            catch
            {
                serverHandle.Dispose();
                acceptedSocket.Dispose();
                throw;
            }

            InitializeHandle(serverHandle, isExposed: false, isAsync: (_options & PipeOptions.Asynchronous) != 0);
            State = PipeState.Connected;
        }
        /// <summary>
        /// Helper method to create a PowerShell transport named pipe via native API, along
        /// with a returned .Net NamedPipeServerStream object wrapping the named pipe.
        /// </summary>
        /// <param name="pipeName">Named pipe core name.</param>
        /// <param name="securityDesc"></param>
        /// <returns>NamedPipeServerStream</returns>
        internal static NamedPipeServerStream CreateNamedPipe(
            string pipeName,
            PipeSecurity pipeSecurity)

        {
            string fullPipeName = @"\\.\pipe\" + pipeName;
            CommonSecurityDescriptor securityDesc = new CommonSecurityDescriptor(false, false, pipeSecurity.GetSecurityDescriptorBinaryForm(), 0);

            // Create optional security attributes based on provided PipeSecurity.
            NamedPipeNative.SECURITY_ATTRIBUTES securityAttributes = null;
            GCHandle?securityDescHandle = null;

            if (securityDesc != null)
            {
                byte[] securityDescBuffer = new byte[securityDesc.BinaryLength];
                securityDesc.GetBinaryForm(securityDescBuffer, 0);

                securityDescHandle = GCHandle.Alloc(securityDescBuffer, GCHandleType.Pinned);
                securityAttributes = NamedPipeNative.GetSecurityAttributes(securityDescHandle.Value);
            }

            // Create named pipe.
            SafePipeHandle pipeHandle = NamedPipeNative.CreateNamedPipe(
                fullPipeName,
                NamedPipeNative.PIPE_ACCESS_DUPLEX | NamedPipeNative.FILE_FLAG_FIRST_PIPE_INSTANCE | NamedPipeNative.FILE_FLAG_OVERLAPPED,
                NamedPipeNative.PIPE_TYPE_BYTE | NamedPipeNative.PIPE_READMODE_BYTE,
                1,
                1024,
                1024,
                0,
                securityAttributes);

            int lastError = Marshal.GetLastWin32Error();

            if (securityDescHandle != null)
            {
                securityDescHandle.Value.Free();
            }

            if (pipeHandle.IsInvalid)
            {
                throw new InvalidOperationException();
            }
            // Create the .Net NamedPipeServerStream wrapper.
            try
            {
                return(new NamedPipeServerStream(
                           PipeDirection.InOut,
                           true,                // IsAsync
                           false,               // IsConnected
                           pipeHandle));
            }
            catch (Exception)
            {
                pipeHandle.Dispose();
                throw;
            }
        }
Example #8
0
        public void Dispose()
        {
            GC.SuppressFinalize(this);

            ClientStream?.Dispose();
            ClientStream = null;

            PipeHandle?.Dispose();
            PipeHandle = null;
        }
Example #9
0
        internal static NamedPipeServerStream CreateNamedServerPipe(
            string serverName,
            string namespaceName,
            string pipeName,
            PipeSecurity pipeSecurity)
        {
            string fullPipeName       = $@"\\{serverName}\{namespaceName}\{pipeName}";
            var    securityDescriptor = new CommonSecurityDescriptor(
                false,
                false,
                pipeSecurity.GetSecurityDescriptorBinaryForm(),
                0);

            byte[] securityDescriptorBuffer = new byte[securityDescriptor.BinaryLength];
            securityDescriptor.GetBinaryForm(securityDescriptorBuffer, 0);

            GCHandle?securityDescriptorHandle = GCHandle.Alloc(securityDescriptorBuffer, GCHandleType.Pinned);
            var      securityAttributes       = GetSecurityAttributes(securityDescriptorHandle.Value);

            if (Interop.Kernel32.WaitNamedPipe(fullPipeName, System.Threading.Timeout.Infinite))
            {
                if (Marshal.GetLastWin32Error() != Interop.Errors.ERROR_FILE_NOT_FOUND)
                {
                    throw new InvalidOperationException();
                }
            }

            SafePipeHandle pipeHandle = Interop.Kernel32.CreateNamedPipe(
                fullPipeName,
                Interop.Kernel32.PipeOptions.PIPE_ACCESS_DUPLEX | Interop.Kernel32.FileOperations.FILE_FLAG_OVERLAPPED,
                Interop.Kernel32.PipeOptions.PIPE_TYPE_BYTE | Interop.Kernel32.PipeOptions.PIPE_READMODE_BYTE,
                1,
                65536,
                65536,
                0,
                ref securityAttributes);

            securityDescriptorHandle.Value.Free();

            if (pipeHandle.IsInvalid)
            {
                throw new InvalidOperationException();
            }

            try
            {
                return(new NamedPipeServerStream(PipeDirection.InOut, true, true, pipeHandle));
            }
            catch (Exception)
            {
                pipeHandle.Dispose();
                throw;
            }
        }
        // Creates the anonymous pipe.
        private void Create(PipeDirection direction, HandleInheritability inheritability, int bufferSize)
        {
            Debug.Assert(direction != PipeDirection.InOut, "Anonymous pipe direction shouldn't be InOut");
            // Ignore bufferSize.  It's optional, and the fcntl F_SETPIPE_SZ for changing it is Linux specific.

            SafePipeHandle?serverHandle = null, clientHandle = null;

            try
            {
                if (direction == PipeDirection.In)
                {
                    CreateAnonymousPipe(reader: out serverHandle, writer: out clientHandle);
                }
                else
                {
                    CreateAnonymousPipe(reader: out clientHandle, writer: out serverHandle);
                }
            }
            catch
            {
                serverHandle?.Dispose();
                clientHandle?.Dispose();
                throw;
            }

            // We always create pipes with both file descriptors being O_CLOEXEC.
            // If inheritability is requested, we clear the O_CLOEXEC flag
            // from the child descriptor so that it can be passed to a child process.
            // We assume that the HandleInheritability only applies to the child fd,
            // as if we allowed the server fd to be inherited, then when this process
            // closes its end of the pipe, the client won't receive an EOF or broken
            // pipe notification, as the child will still have open its dup of the fd.
            if (inheritability == HandleInheritability.Inheritable &&
                Interop.Sys.Fcntl.SetFD(clientHandle, 0) == -1)
            {
                throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo());
            }

            // Configure the pipe.  For buffer size, the size applies to the pipe, rather than to
            // just one end's file descriptor, so we only need to do this with one of the handles.
            // bufferSize is just advisory and ignored if platform does not support setting pipe capacity via fcntl.
            if (bufferSize > 0 && Interop.Sys.Fcntl.CanGetSetPipeSz)
            {
                Interop.Sys.Fcntl.SetPipeSz(serverHandle, bufferSize); // advisory, ignore errors
            }

            // We're connected.  Finish initialization using the newly created handles.
            InitializeHandle(serverHandle, isExposed: false, isAsync: false);
            _clientHandle = clientHandle;
            State         = PipeState.Connected;
        }
Example #11
0
        private bool TryConnect(int timeout, CancellationToken cancellationToken)
        {
            // timeout and cancellationToken aren't used as Connect will be very fast,
            // either succeeding immediately if the server is listening or failing
            // immediately if it isn't.  The only delay will be between the time the server
            // has called Bind and Listen, with the latter immediately following the former.
            var            socket       = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
            SafePipeHandle?clientHandle = null;

            try
            {
                socket.Connect(new UnixDomainSocketEndPoint(_normalizedPipePath !));
                clientHandle = new SafePipeHandle(socket);
                ConfigureSocket(socket, clientHandle, _direction, 0, 0, _inheritability);
            }
            catch (SocketException e)
            {
                clientHandle?.Dispose();
                socket.Dispose();

                switch (e.SocketErrorCode)
                {
                // Retryable errors
                case SocketError.AddressAlreadyInUse:
                case SocketError.AddressNotAvailable:
                case SocketError.ConnectionRefused:
                    return(false);

                // Non-retryable errors
                default:
                    throw;
                }
            }

            try
            {
                ValidateRemotePipeUser(clientHandle);
            }
            catch (Exception)
            {
                clientHandle.Dispose();
                socket.Dispose();
                throw;
            }

            InitializeHandle(clientHandle, isExposed: false, isAsync: (_pipeOptions & PipeOptions.Asynchronous) != 0);
            State = PipeState.Connected;
            return(true);
        }
Example #12
0
            public void Dispose()
            {
                // Dispose the registration prior to disposing of the pipe handles.
                // Otherwise a concurrent cancellation request could try to use
                // the already disposed pipe.
                _registration.Dispose();

                if (_send != null)
                {
                    _send.Dispose();
                }
                if (_poll != null)
                {
                    _poll.Dispose();
                }
            }
Example #13
0
        protected override void Dispose(bool disposing)
        {
            try
            {
                // Nothing will be done differently based on whether we are
                // disposing vs. finalizing.
                if (_handle != null && !_handle.IsClosed)
                {
                    _handle.Dispose();
                }
            }
            finally
            {
                base.Dispose(disposing);
            }

            _state = PipeState.Closed;
        }
        private void HandleAcceptedSocket(Socket acceptedSocket)
        {
            var serverHandle = new SafePipeHandle(acceptedSocket);

            try
            {
                ConfigureSocket(acceptedSocket, serverHandle, _direction, _inBufferSize, _outBufferSize, _inheritability);
            }
            catch
            {
                serverHandle.Dispose();
                acceptedSocket.Dispose();
                throw;
            }

            InitializeHandle(serverHandle, isExposed: false, isAsync: (_options & PipeOptions.Asynchronous) != 0);
            State = PipeState.Connected;
        }
Example #15
0
        public void WaitForConnection()
        {
            CheckConnectOperationsServer();
            if (State == PipeState.Connected)
            {
                throw new InvalidOperationException(SR.InvalidOperation_PipeAlreadyConnected);
            }

            // Binding to an existing path fails, so we need to remove anything left over at this location.
            // There's of course a race condition here, where it could be recreated by someone else between this
            // deletion and the bind below, in which case we'll simply let the bind fail and throw.
            Interop.Sys.Unlink(_path); // ignore any failures
            var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);

            try
            {
                socket.Bind(new UnixDomainSocketEndPoint(_path));
                socket.Listen(1);

                Socket         acceptedSocket = socket.Accept();
                SafePipeHandle serverHandle   = new SafePipeHandle(acceptedSocket);
                try
                {
                    ConfigureSocket(acceptedSocket, serverHandle, _direction, _inBufferSize, _outBufferSize, _inheritability);
                }
                catch
                {
                    serverHandle.Dispose();
                    acceptedSocket.Dispose();
                    throw;
                }

                InitializeHandle(serverHandle, isExposed: false, isAsync: (_options & PipeOptions.Asynchronous) != 0);
                State = PipeState.Connected;
            }
            finally
            {
                // Bind will have created a file.  Now that the client is connected, it's no longer necessary, so get rid of it.
                Interop.Sys.Unlink(_path); // ignore any failures; worst case is we leave a tmp file

                // Clean up the listening socket
                socket.Dispose();
            }
        }
Example #16
0
        public async Task <bool> CreateNewNamedPipeAsync()
        {
            try
            {
                if (ClientStream != null)
                {
                    if (!ClientStream.IsConnected)
                    {
                        ClientStream.Dispose();
                        ClientStream = null;
                        PipeHandle.Dispose();
                        PipeHandle = null;

                        GUID = Guid.NewGuid();
                    }
                    else
                    {
                        return(true);
                    }
                }

                if (WindowsVersionChecker.IsNewerOrEqual(Version.Windows10_2004))
                {
                    await Controller.RequestCreateNewPipeLineAsync(GUID).ConfigureAwait(true);

                    PipeHandle = WIN_Native_API.GetHandleFromNamedPipe($"Explorer_And_FullTrustProcess_NamedPipe-{GUID}");

                    ClientStream = new NamedPipeClientStream(PipeDirection.InOut, false, true, PipeHandle);

                    return(true);
                }
                else
                {
                    return(false);
                }
            }
            catch (Exception ex)
            {
                LogTracer.Log(ex, $"{ nameof(CreateNewNamedPipeAsync)} throw an error");
                return(false);
            }
        }
Example #17
0
        /// <summary>
        /// Helper method to open a named pipe via native APIs and return in
        /// .Net NamedPipeClientStream wrapper object.
        /// </summary>
        private NamedPipeClientStream OpenNamedPipe()
        {
            // Create pipe flags.
            uint pipeFlags = NamedPipeNative.FILE_FLAG_OVERLAPPED;

            // Get handle to pipe.
            SafePipeHandle pipeHandle = NamedPipeNative.CreateFile(
                _pipeName,
                NamedPipeNative.GENERIC_READ | NamedPipeNative.GENERIC_WRITE,
                0,
                IntPtr.Zero,
                NamedPipeNative.OPEN_EXISTING,
                pipeFlags,
                IntPtr.Zero);

            int lastError = Marshal.GetLastWin32Error();

            if (pipeHandle.IsInvalid)
            {
                throw new System.ComponentModel.Win32Exception(lastError);
            }

            try
            {
                return(new NamedPipeClientStream(
                           PipeDirection.InOut,
                           true,            // IsAsync
                           true,            // IsConnected
                           pipeHandle));
            }
            catch (Exception e)
            {
                CommandProcessorBase.CheckForSevereException(e);
                pipeHandle.Dispose();
                throw;
            }
        }
Example #18
0
        /// <summary>
        /// Helper method to create a PowerShell transport named pipe via native API, along
        /// with a returned .Net NamedPipeServerStream object wrapping the named pipe.
        /// </summary>
        /// <param name="pipeName">Named pipe core name.</param>
        /// <returns>An instance of the <see cref="NamedPipeServerStream"/> class.</returns>
        public static NamedPipeServerStream CreateNamedPipe(string pipeName, uint maxNumberOfServerInstances, PipeSecurity pipeSecurity)
        {
            string fullPipeName = @"\\.\pipe\" + pipeName;

            var securityDesc = new CommonSecurityDescriptor(false, false, pipeSecurity.GetSecurityDescriptorBinaryForm(), 0);

            // Create optional security attributes based on provided PipeSecurity.
            SecurityAttributes securityAttributes = null;
            GCHandle?          securityDescHandle = null;

            if (securityDesc != null)
            {
                byte[] securityDescBuffer = new byte[securityDesc.BinaryLength];
                securityDesc.GetBinaryForm(securityDescBuffer, 0);

                securityDescHandle = GCHandle.Alloc(securityDescBuffer, GCHandleType.Pinned);
                securityAttributes = CoreHelpers.GetSecurityAttributes(securityDescHandle.Value);
            }

            uint openMode = (uint)Access.Duplex | (uint)File.Overlapped;

            if (maxNumberOfServerInstances == 1)
            {
                openMode |= (uint)File.FirstPipeInstance;
            }

            // Create named pipe.
            SafePipeHandle pipeHandle = CreateNamedPipeW(
                fullPipeName,
                openMode,
                (uint)Type.Byte | (uint)Read.Byte,
                maxNumberOfServerInstances,
                1,
                1,
                0,
                securityAttributes);

            if (securityDescHandle != null)
            {
                securityDescHandle.Value.Free();
            }

            if (pipeHandle.IsInvalid)
            {
                throw new InvalidOperationException("Error code: " + Marshal.GetLastWin32Error().ToString());
            }

            // Create the .Net NamedPipeServerStream wrapper.
            try
            {
                return(new NamedPipeServerStream(
                           PipeDirection.InOut,
                           true,                // IsAsync
                           false,               // IsConnected
                           pipeHandle));
            }

            catch (Exception)
            {
                pipeHandle.Dispose();
                throw;
            }
        }
Example #19
0
        /// <summary>
        /// Helper method to create a PowerShell transport named pipe via native API, along
        /// with a returned .Net NamedPipeServerStream object wrapping the named pipe.
        /// </summary>
        /// <param name="serverName">Named pipe server name.</param>
        /// <param name="namespaceName">Named pipe namespace name.</param>
        /// <param name="coreName">Named pipe core name.</param>
        /// <param name="securityDesc"></param>
        /// <returns>NamedPipeServerStream</returns>
        private NamedPipeServerStream CreateNamedPipe(
            string serverName,
            string namespaceName,
            string coreName,
            CommonSecurityDescriptor securityDesc)
        {
            if (serverName == null)
            {
                throw new PSArgumentNullException("serverName");
            }
            if (namespaceName == null)
            {
                throw new PSArgumentNullException("namespaceName");
            }
            if (coreName == null)
            {
                throw new PSArgumentNullException("coreName");
            }

            string fullPipeName = @"\\" + serverName + @"\" + namespaceName + @"\" + coreName;

            // Create optional security attributes based on provided PipeSecurity.
            NamedPipeNative.SECURITY_ATTRIBUTES securityAttributes = null;
            GCHandle?securityDescHandle = null;

            if (securityDesc != null)
            {
                byte[] securityDescBuffer = new byte[securityDesc.BinaryLength];
                securityDesc.GetBinaryForm(securityDescBuffer, 0);
                securityDescHandle = GCHandle.Alloc(securityDescBuffer, GCHandleType.Pinned);
                securityAttributes = NamedPipeNative.GetSecurityAttributes(securityDescHandle.Value);
            }

            // Create named pipe.
            SafePipeHandle pipeHandle = NamedPipeNative.CreateNamedPipe(
                fullPipeName,
                NamedPipeNative.PIPE_ACCESS_DUPLEX | NamedPipeNative.FILE_FLAG_FIRST_PIPE_INSTANCE | NamedPipeNative.FILE_FLAG_OVERLAPPED,
                NamedPipeNative.PIPE_TYPE_MESSAGE | NamedPipeNative.PIPE_READMODE_MESSAGE,
                1,
                _namedPipeBufferSizeForRemoting,
                _namedPipeBufferSizeForRemoting,
                0,
                securityAttributes);

            int lastError = Marshal.GetLastWin32Error();

            if (securityDescHandle != null)
            {
                securityDescHandle.Value.Free();
            }

            if (pipeHandle.IsInvalid)
            {
                throw new PSInvalidOperationException(
                          StringUtil.Format(RemotingErrorIdStrings.CannotCreateNamedPipe, lastError));
            }

            // Create the .Net NamedPipeServerStream wrapper.
            try
            {
                return(new NamedPipeServerStream(
                           PipeDirection.InOut,
                           true,                // IsAsync
                           false,               // IsConnected
                           pipeHandle));
            }
            catch (Exception e)
            {
                CommandProcessorBase.CheckForSevereException(e);
                pipeHandle.Dispose();
                throw;
            }
        }
        /// <summary>
        /// Helper method to create a PowerShell transport named pipe via native API, along
        /// with a returned .Net NamedPipeServerStream object wrapping the named pipe.
        /// </summary>
        /// <param name="serverName">Named pipe server name.</param>
        /// <param name="namespaceName">Named pipe namespace name.</param>
        /// <param name="coreName">Named pipe core name.</param>
        /// <param name="securityDesc"></param>
        /// <returns>NamedPipeServerStream.</returns>
        private static NamedPipeServerStream CreateNamedPipe(
            string serverName,
            string namespaceName,
            string coreName,
            CommonSecurityDescriptor securityDesc)
        {
            if (serverName == null)
            {
                throw new PSArgumentNullException(nameof(serverName));
            }

            if (namespaceName == null)
            {
                throw new PSArgumentNullException(nameof(namespaceName));
            }

            if (coreName == null)
            {
                throw new PSArgumentNullException(nameof(coreName));
            }

#if !UNIX
            string fullPipeName = @"\\" + serverName + @"\" + namespaceName + @"\" + coreName;

            // Create optional security attributes based on provided PipeSecurity.
            NamedPipeNative.SECURITY_ATTRIBUTES securityAttributes = null;
            GCHandle?securityDescHandle = null;
            if (securityDesc != null)
            {
                byte[] securityDescBuffer = new byte[securityDesc.BinaryLength];
                securityDesc.GetBinaryForm(securityDescBuffer, 0);
                securityDescHandle = GCHandle.Alloc(securityDescBuffer, GCHandleType.Pinned);
                securityAttributes = NamedPipeNative.GetSecurityAttributes(securityDescHandle.Value);
            }

            // Create named pipe.
            SafePipeHandle pipeHandle = NamedPipeNative.CreateNamedPipe(
                fullPipeName,
                NamedPipeNative.PIPE_ACCESS_DUPLEX | NamedPipeNative.FILE_FLAG_FIRST_PIPE_INSTANCE | NamedPipeNative.FILE_FLAG_OVERLAPPED,
                NamedPipeNative.PIPE_TYPE_MESSAGE | NamedPipeNative.PIPE_READMODE_MESSAGE,
                1,
                _namedPipeBufferSizeForRemoting,
                _namedPipeBufferSizeForRemoting,
                0,
                securityAttributes);

            int lastError = Marshal.GetLastWin32Error();
            if (securityDescHandle != null)
            {
                securityDescHandle.Value.Free();
            }

            if (pipeHandle.IsInvalid)
            {
                throw new PSInvalidOperationException(
                          StringUtil.Format(RemotingErrorIdStrings.CannotCreateNamedPipe, lastError));
            }

            // Create the .Net NamedPipeServerStream wrapper.
            try
            {
                return(new NamedPipeServerStream(
                           PipeDirection.InOut,
                           true,                // IsAsync
                           false,               // IsConnected
                           pipeHandle));
            }
            catch (Exception)
            {
                pipeHandle.Dispose();
                throw;
            }
#else
            return(new NamedPipeServerStream(
                       pipeName: coreName,
                       direction: PipeDirection.InOut,
                       maxNumberOfServerInstances: 1,
                       transmissionMode: PipeTransmissionMode.Byte,
                       options: PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly,
                       inBufferSize: _namedPipeBufferSizeForRemoting,
                       outBufferSize: _namedPipeBufferSizeForRemoting));
#endif
        }
Example #21
0
        /// <summary>
        /// P/Invoke native APIs related to named pipe operations to create the named pipe.
        /// System.IO.Pipes in Unity is missing crucial types/methods for performing reliable and
        /// accurate transfers. Such as bytesSents/bytesReceived.
        /// </summary>
        public static void Run()
        {
            while (!KillServerRequested)
            {
                // ----------------------------------------------------------------------------------------------------------------
                // Create the named pipe.
                using (SafePipeHandle hNamedPipe = NativeMethod.CreateNamedPipe(
                           IPCServer.FullPipeName,          // The unique pipe name.
                           PipeOpenMode.PIPE_ACCESS_DUPLEX, // The pipe is duplex
                           PipeMode.PIPE_TYPE_MESSAGE |     // Message type pipe
                           PipeMode.PIPE_READMODE_MESSAGE | // Message-read mode
                           PipeMode.PIPE_WAIT,              // Blocking mode is on
                           2,                               // Max server instances
                           IPCServer.BufferSize,            // Output buffer size
                           IPCServer.BufferSize,            // Input buffer size
                           NMPWAIT_USE_DEFAULT_WAIT         // Time-out interval
                           ))
                {
                    try
                    {
                        if (hNamedPipe.IsInvalid)
                        {
                            throw new Win32Exception();
                        }

                        pipeHandle = hNamedPipe;
                        Console.WriteLine("[IPC Server Waiting for Connection] - \"{0}\"", IPCServer.FullPipeName);

                        // ----------------------------------------------------------------------------------------------------------------
                        // Wait for the connections. Runs on background thread.
                        if (!NativeMethod.ConnectNamedPipe(hNamedPipe, IntPtr.Zero))
                        {
                            if (Marshal.GetLastWin32Error() != ERROR_PIPE_CONNECTED)
                            {
                                throw new Win32Exception();
                            }
                        }
                        Console.WriteLine("[IPC Server Status] - Client Connected");

                        // ----------------------------------------------------------------------------------------------------------------
                        // Received a request from client.
                        string message;
                        bool   finishRead = false;
                        do
                        {
                            byte[] bRequest = new byte[IPCServer.BufferSize];
                            int    cbRequest = bRequest.Length, cbRead;

                            finishRead = NativeMethod.ReadFile(
                                hNamedPipe,             // Handle of the pipe
                                bRequest,               // Buffer to receive data
                                cbRequest,              // Size of buffer in bytes
                                out cbRead,             // Number of bytes read
                                IntPtr.Zero             // Not overlapped
                                );

                            if (!finishRead && Marshal.GetLastWin32Error() != ERROR_MORE_DATA)
                            {
                                throw new Win32Exception();
                            }

                            // UTF8-encode the received byte array and trim all the '\0' characters at the end.
                            message = Encoding.UTF8.GetString(bRequest).Replace("\0", "");
                            Console.WriteLine("[IPC Server Received {0} bytes] Message: {1}\r\n", cbRead, message);
                        }while (!finishRead); // Repeat loop if ERROR_MORE_DATA

                        // If message is not KILL_SERVER, then process client request
                        if (message != "KILL_SERVER")
                        {
                            //Get our message header and data
                            string[] msgArray = message.Split(new string[] { "|:|" }, StringSplitOptions.None);
                            string   header   = msgArray[0];
                            string   data     = msgArray[1];

                            // Process Client Requests Here based off request header
                            Console.WriteLine("    Message Header: " + header);
                            Order order = JsonConvert.DeserializeObject <Order>(data);
                            Console.WriteLine("    Message Data: {0} ordered {1} {2}, delivery address: {3}\r\n", order.CustomerName, order.Quantity, order.ProductName, order.Address);
                        }

                        // ----------------------------------------------------------------------------------------------------------------
                        // Send a message received response to client.
                        string rmessage = IPCServer.ResponseMessage;
                        byte[] bResponse = Encoding.UTF8.GetBytes(rmessage);
                        int    cbResponse = bResponse.Length, cbWritten;

                        if (!NativeMethod.WriteFile(
                                hNamedPipe,             // Handle of the pipe
                                bResponse,              // Message to be written
                                cbResponse,             // Number of bytes to write
                                out cbWritten,          // Number of bytes written
                                IntPtr.Zero             // Not overlapped
                                ))
                        {
                            throw new Win32Exception();
                        }

                        Console.WriteLine("[IPC Server Sent {0} bytes] Message: {1}", cbWritten, rmessage.Replace("\0", ""));

                        if (message == "KILL_SERVER")
                        {
                            KillServerRequested = true;
                        }

                        // ----------------------------------------------------------------------------------------------------------------
                        // Flush the pipe to allow the client to read the pipe's contents before disconnecting. Then disconnect the client's connection.
                        NativeMethod.FlushFileBuffers(hNamedPipe);
                        NativeMethod.DisconnectNamedPipe(hNamedPipe);
                    }
                    catch (Exception ex)
                    {
                        if (ex.Message != "Thread was being aborted")
                        {
                            Console.WriteLine("[IPC Server ERROR] - {0}", ex.Message);
                        }

                        hNamedPipe.Close();
                        hNamedPipe.Dispose();
                        NativeMethod.DisconnectNamedPipe(hNamedPipe);
                    }
                    finally
                    {
                        if (hNamedPipe != null)
                        {
                            hNamedPipe.Close();
                            hNamedPipe.Dispose();
                            NativeMethod.DisconnectNamedPipe(hNamedPipe);
                        }
                    }
                }
            }

            if (KillServerRequested)
            {
                _ipcServer.StopServer();
            }
        }
Example #22
0
        /// <summary>
        /// Helper method to create a PowerShell transport named pipe via native API, along
        /// with a returned .Net NamedPipeServerStream object wrapping the named pipe.
        /// </summary>
        /// <param name="pipeName">Named pipe core name.</param>
        /// <param name="securityDesc"></param>
        /// <returns>NamedPipeServerStream</returns>
        internal static NamedPipeServerStream CreateNamedPipe(
            string serverName,
            string namespaceName,
            string pipeName,
            PipeSecurity pipeSecurity)

        {
            if (serverName == null)
            {
                throw new ArgumentNullException("serverName");
            }
            if (namespaceName == null)
            {
                throw new ArgumentNullException("namespaceName");
            }
            if (pipeName == null)
            {
                throw new ArgumentNullException("pipeName");
            }


            string fullPipeName = @"\\" + serverName + @"\" + namespaceName + @"\" + pipeName;

            CommonSecurityDescriptor securityDesc = new CommonSecurityDescriptor(false, false, pipeSecurity.GetSecurityDescriptorBinaryForm(), 0);

            // Create optional security attributes based on provided PipeSecurity.
            NamedPipeNative.SECURITY_ATTRIBUTES securityAttributes = null;
            GCHandle?securityDescHandle = null;

            if (securityDesc != null)
            {
                byte[] securityDescBuffer = new byte[securityDesc.BinaryLength];
                securityDesc.GetBinaryForm(securityDescBuffer, 0);

                securityDescHandle = GCHandle.Alloc(securityDescBuffer, GCHandleType.Pinned);
                securityAttributes = NamedPipeNative.GetSecurityAttributes(securityDescHandle.Value);
            }

            if (!NamedPipeNative.WaitNamedPipe(fullPipeName, System.Threading.Timeout.Infinite))
            {
                int errorCode = Marshal.GetLastWin32Error();
                if (errorCode != ERROR_FILE_NOT_FOUND)
                {
                    throw new InvalidOperationException();
                }
            }

            // Create named pipe.
            SafePipeHandle pipeHandle = NamedPipeNative.CreateNamedPipe(
                fullPipeName,
                NamedPipeNative.PIPE_ACCESS_DUPLEX | NamedPipeNative.FILE_FLAG_OVERLAPPED,
                NamedPipeNative.PIPE_TYPE_BYTE | NamedPipeNative.PIPE_READMODE_BYTE,
                255,
                65536,
                65536,
                0,
                securityAttributes);

            int lastError = Marshal.GetLastWin32Error();

            if (securityDescHandle != null)
            {
                securityDescHandle.Value.Free();
            }

            if (pipeHandle.IsInvalid)
            {
                throw new InvalidOperationException();
            }
            // Create the .Net NamedPipeServerStream wrapper.
            try
            {
                return(new NamedPipeServerStream(
                           PipeDirection.InOut,
                           true,               // IsAsync
                           true,               // IsConnected
                           pipeHandle));
            }
            catch (Exception)
            {
                pipeHandle.Dispose();
                throw;
            }
        }
Example #23
0
        // This overload is used in Mono to implement public constructors.
        private void Create(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), SR.ArgumentOutOfRange_AnonymousReserved);
            }

            if (IsCurrentUserOnly)
            {
                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) |
                           (maxNumberOfServerInstances == 1 ? Interop.Kernel32.FileOperations.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;
            }

            GCHandle pinningHandle = default;

            try
            {
                Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(inheritability, pipeSecurity, ref pinningHandle);
                SafePipeHandle handle = Interop.Kernel32.CreateNamedPipe(fullPipeName, openMode, pipeModes,
                                                                         maxNumberOfServerInstances, outBufferSize, inBufferSize, 0, ref secAttrs);

                if (handle.IsInvalid)
                {
                    Exception e = Win32Marshal.GetExceptionForLastWin32Error();
                    handle.Dispose();
                    throw e;
                }

                InitializeHandle(handle, false, (options & PipeOptions.Asynchronous) != 0);
            }
            finally
            {
                if (pinningHandle.IsAllocated)
                {
                    pinningHandle.Free();
                }
            }
        }
        // Waits for a pipe instance to become available. This method may return before WaitForConnection is called
        // on the server end, but WaitForConnection will not return until we have returned.  Any data written to the
        // pipe by us after we have connected but before the server has called WaitForConnection will be available
        // to the server after it calls WaitForConnection.
        private bool TryConnect(int timeout, CancellationToken cancellationToken)
        {
            Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(_inheritability);

            // 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
            // CreateNamedPipeClient that were not defined in the enumeration.
            int _pipeFlags = (int)(_pipeOptions & ~PipeOptions.CurrentUserOnly);

            if (_impersonationLevel != TokenImpersonationLevel.None)
            {
                _pipeFlags |= Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT;
                _pipeFlags |= (((int)_impersonationLevel - 1) << 16);
            }

            int access = 0;

            if ((PipeDirection.In & _direction) != 0)
            {
                access |= Interop.Kernel32.GenericOperations.GENERIC_READ;
            }
            if ((PipeDirection.Out & _direction) != 0)
            {
                access |= Interop.Kernel32.GenericOperations.GENERIC_WRITE;
            }

            SafePipeHandle handle = CreateNamedPipeClient(_normalizedPipePath, ref secAttrs, _pipeFlags, access);

            if (handle.IsInvalid)
            {
                int errorCode = Marshal.GetLastPInvokeError();

                handle.Dispose();

                // CreateFileW: "If the CreateNamedPipe function was not successfully called on the server prior to this operation,
                // a pipe will not exist and CreateFile will fail with ERROR_FILE_NOT_FOUND"
                // WaitNamedPipeW: "If no instances of the specified named pipe exist,
                // the WaitNamedPipe function returns immediately, regardless of the time-out value."
                // We know that no instances exist, so we just quit without calling WaitNamedPipeW.
                if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND)
                {
                    return(false);
                }

                if (errorCode != Interop.Errors.ERROR_PIPE_BUSY)
                {
                    throw Win32Marshal.GetExceptionForWin32Error(errorCode);
                }

                if (!Interop.Kernel32.WaitNamedPipe(_normalizedPipePath, timeout))
                {
                    errorCode = Marshal.GetLastPInvokeError();

                    if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND || // server has been closed
                        errorCode == Interop.Errors.ERROR_SEM_TIMEOUT)
                    {
                        return(false);
                    }

                    throw Win32Marshal.GetExceptionForWin32Error(errorCode);
                }

                // Pipe server should be free. Let's try to connect to it.
                handle = CreateNamedPipeClient(_normalizedPipePath, ref secAttrs, _pipeFlags, access);

                if (handle.IsInvalid)
                {
                    errorCode = Marshal.GetLastPInvokeError();

                    handle.Dispose();

                    // WaitNamedPipe: "A subsequent CreateFile call to the pipe can fail,
                    // because the instance was closed by the server or opened by another client."
                    if (errorCode == Interop.Errors.ERROR_PIPE_BUSY ||    // opened by another client
                        errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND) // server has been closed
                    {
                        return(false);
                    }

                    throw Win32Marshal.GetExceptionForWin32Error(errorCode);
                }
            }

            // Success!
            InitializeHandle(handle, false, (_pipeOptions & PipeOptions.Asynchronous) != 0);
            State = PipeState.Connected;
            ValidateRemotePipeUser();
            return(true);