【问题标题】:NamedPipeClientStream throws UnauthorizedAccessException on ConnectNamedPipeClientStream 在 Connect 上抛出 UnauthorizedAccessException
【发布时间】:2025-12-15 16:15:01
【问题描述】:

在将“写入”管道连接到正在运行的服务时,我遇到了与其他人相同的问题: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);

【问题讨论】:

    标签: c# named-pipes


    【解决方案1】:

    不想让这个打开,因为这个问题已经解决了,下面的代码正在生产中。

    • 服务器管道必须仔细构建 ACL 列表,以允许来自低完整性客户端管道的连接,只要用户经过身份验证或管理员身份验证。请参阅 CreateNativePipeSecurity()。
    • 客户端管道照常创建

      /// <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;
      }
      

    【讨论】:

    • 也看看这里:social.msdn.microsoft.com/Forums/en-US/…>: 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);
    • 你为 NativeMethods 使用了什么 nuget 或库?
    • @spmoolman 这些是 pinvoke.net 自动生成的 API 导入和声明
    • 在我的例子中,我发现 NamedPipeServerStream 上的 PipeDirection.Out 会为客户端产生标题中提到的异常,无论 PipeSecurity 是如何设置的。即使我的管道服务器只写入管道而从未从中读取。