NamedPipeClientStream在连接时抛出UnauthorizedAccessException异常

3

我遇到了连接“写入”管道到正在运行的服务时,和其他人一样的问题:UnauthorizedAccessException。我尝试了各种解决方案,但没有一种可以成功连接。

情景是有一个低完整性的C#/WPF应用程序在系统托盘中运行,使用命名管道从Windows服务接收通知,并且可以告诉服务取消某些操作或等待更多数据(因此需要一个写入管道到服务)。从服务的管道读取正常,我使用了两个管道对象(一个从服务到客户端,另一个从客户端到服务)。

服务运行在域用户帐户下,但管道无论以什么身份运行都无法连接,包括本地系统。

服务器管道是这样创建的:

PipeSecurity ps = new PipeSecurity();

// Production service runs under current user credentials.
ps.AddAccessRule(new PipeAccessRule(WindowsIdentity.GetCurrent().User, PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow));

// Test service runs under local system credentials.
ps.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null), PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow));

// Add world just for the hell of it, still won't work.
ps.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), PipeAccessRights.FullControl, AccessControlType.Allow));

this.readPipe = new NamedPipeServerStream(clientPipeName, PipeDirection.In);
this.writePipe = new NamedPipeServerStream(serverPipeName, PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.None, 1024, 1024, ps);

客户端管道的创建方式如下:

this.readPipe = new NamedPipeClientStream(".", serverPipeName, PipeDirection.In);
this.writePipe = new NamedPipeClientStream(".", clientPipeName, PipeDirection.Out);

// This doesn't make a difference.
//this.writePipe = new NamedPipeClientStream(".", clientPipeName, PipeAccessRights.FullControl, PipeOptions.None, TokenImpersonationLevel.None, HandleInheritability.None);
1个回答

2

我不想让这个问题一直开着,因为它已经得到解决并且下面的代码正在使用中。

  • Server pipe must have ACL list carefully constructed to allow connections from low-integrity client pipes, as long as users are authenticated or administrators. See CreateNativePipeSecurity().
  • Client pipe is created as usual

    /// <summary>
    /// Creates the client and server pipes.
    /// </summary>
    private void CreatePipes()
    {
        string serverPipeName = string.Format("{0}server", this.pipeName);
        string clientPipeName = string.Format("{0}client", this.pipeName);
    
        if (this.readPipe != null)
        {
            this.readPipe.Dispose();
        }
    
        if (this.writePipe != null)
        {
            this.writePipe.Dispose();
        }
    
        if (this.server)
        {
            // Create a write pipe for sending notifications to client.
            this.writePipe = new NamedPipeServerStream(clientPipeName, PipeDirection.Out);
    
            // Create a read pipe for receiving notifications from the client.
            // Creating a pipe to high integrity process from low integrity process requires native access list creation (.NET bug).
            NativeMethods.SECURITY_ATTRIBUTES securityAttributes = this.CreateNativePipeSecurity();
            IntPtr securityAttributesPtr = Marshal.AllocHGlobal(Marshal.SizeOf(securityAttributes));
            Marshal.StructureToPtr(securityAttributes, securityAttributesPtr, false);
    
            string nativePipeName = string.Format(@"\\.\pipe\{0}", serverPipeName);
    
            SafePipeHandle nativePipe = NativeMethods.CreateNamedPipe(
                nativePipeName,
                NativeMethods.PipeOpenMode.PIPE_ACCESS_INBOUND,
                0,
                NativeMethods.PipeInstances.PIPE_UNLIMITED_INSTANCES,
                0,
                0,
                NativeMethods.PipeWait.NMPWAIT_WAIT_FOREVER,
                securityAttributesPtr);
    
            int error = Marshal.GetLastWin32Error();
    
            Marshal.FreeHGlobal(securityAttributesPtr);
    
            if (nativePipe.IsInvalid)
            {                    
                throw new Win32Exception(error);
            }
    
            this.readPipe = new NamedPipeServerStream(PipeDirection.In, false, false, nativePipe);
        }
        else
        {
            // Create a read pipe for receiving notifications from server.
            this.readPipe = new NamedPipeClientStream(".", clientPipeName, PipeDirection.In);
    
            // Create a write pipe for sending notifications to the server.
            this.writePipe = new NamedPipeClientStream(".", serverPipeName, PipeDirection.Out);
        }
    }
    
    /// <summary>
    /// Generate security attributes to allow low integrity process to connect to high integrity service.
    /// </summary>
    /// <returns>A structure filled with proper attributes.</returns>
    private NativeMethods.SECURITY_ATTRIBUTES CreateNativePipeSecurity()
    {
        // Define the SDDL for the security descriptor.
        string sddl = "D:" +        // Discretionary ACL
            "(A;OICI;GRGW;;;AU)" +  // Allow read/write to authenticated users
            "(A;OICI;GA;;;BA)";     // Allow full control to administrators
    
        IntPtr securityDescriptor = IntPtr.Zero;
    
        if (NativeMethods.ConvertStringSecurityDescriptorToSecurityDescriptor(
            sddl, 1, out securityDescriptor, IntPtr.Zero) == 0)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
    
        NativeMethods.SECURITY_ATTRIBUTES sa = new NativeMethods.SECURITY_ATTRIBUTES();
        sa.nLength = Marshal.SizeOf(sa);
        sa.lpSecurityDescriptor = securityDescriptor;
        sa.bInheritHandle = 0;
    
        return sa;
    }
    

还可以在这里看一下:https://social.msdn.microsoft.com/Forums/en-US/6ce43c90-00da-47e6-8e8c-4fdb2f7cc13e/named-pipe-error-systemunauthorizedaccessexception-access-to-the-path-is-denied?forum=netfxnetcom:PipeSecurity ps = new PipeSecurity(); PipeAccessRule psRule = new PipeAccessRule(@"Everyone", PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow); ps.AddAccessRule(psRule); NamedPipeServerStream pipeServer = new NamedPipeServerStream("datapipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 1, 1, ps); - MBWise
你使用了哪个NuGet或库来处理NativeMethods? - spmoolman
@spmoolman 这些是由pinvoke.net自动生成的API导入和声明。 - Valeriy Novytskyy
在我的情况下,我发现在NamedPipeServerStream上使用PipeDirection.Out将会产生标题中提到的异常,无论PipeSecurity如何设置。即使我的管道服务器只向管道写入而从未从中读取。 - Vector

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接