/// <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;
            }
        }
Exemple #2
0
        public override void Start()
        {
            try
            {
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    PipeSecurity pipeSecurity = new PipeSecurity();

                    WindowsIdentity  identity  = WindowsIdentity.GetCurrent();
                    WindowsPrincipal principal = new WindowsPrincipal(identity);

                    if (principal.IsInRole(WindowsBuiltInRole.Administrator))
                    {
                        // Allow the Administrators group full access to the pipe.
                        pipeSecurity.AddAccessRule(new PipeAccessRule(
                                                       new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null).Translate(typeof(NTAccount)),
                                                       PipeAccessRights.FullControl, AccessControlType.Allow));
                    }
                    else
                    {
                        // Allow the current user read/write access to the pipe.
                        pipeSecurity.AddAccessRule(new PipeAccessRule(
                                                       WindowsIdentity.GetCurrent().User,
                                                       PipeAccessRights.ReadWrite, AccessControlType.Allow));
                    }

                    // Unfortunately, .NET Core does not support passing in a PipeSecurity object into the constructor for
                    // NamedPipeServerStream so we are creating native Named Pipes and securing them using native APIs. The
                    // issue on .NET Core regarding Named Pipe security is here: https://github.com/dotnet/corefx/issues/30170
                    // 99% of this code was borrowed from PowerShell here:
                    // https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs#L124-L256
                    this.pipeServer = NamedPipeNative.CreateNamedPipe(pipeName, pipeSecurity);
                }
                else
                {
                    // This handles the Unix case since PipeSecurity is not supported on Unix.
                    // Instead, we use chmod in Start-EditorServices.ps1
                    this.pipeServer = new NamedPipeServerStream(
                        pipeName: pipeName,
                        direction: PipeDirection.InOut,
                        maxNumberOfServerInstances: 1,
                        transmissionMode: PipeTransmissionMode.Byte,
                        options: PipeOptions.Asynchronous);
                }
                ListenForConnection();
            }
            catch (IOException e)
            {
                this.logger.Write(
                    LogLevel.Verbose,
                    "Named pipe server failed to start due to exception:\r\n\r\n" + e.Message);

                throw e;
            }
        }