c# .net-3.5 named-pipes

c# - El servidor de tuberías con nombre lanza una excepción no autorizada de acceso cuando crea una segunda instancia si se establece PipeSecurity



.net-3.5 named-pipes (6)

Estoy tratando de escribir un servicio (privilegio elevado) que hablará con una aplicación winforms no privilegiada. Tuve la oportunidad de tener dos aplicaciones de consola (una elevada no) sin problemas, pero tengo un problema al hacer un servicio y una aplicación winforms.

La primera instancia de la tubería funciona perfectamente. Sin embargo, después de que mi cliente se conecta e intento crear una nueva instancia, estará lista si se conecta un segundo cliente, pero el constructor de NamedPipeServerStream lanza una excepción.

System.UnauthorizedAccessException was unhandled Message=Access to the path is denied. Source=System.Core StackTrace: at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.Pipes.NamedPipeServerStream.Create(String fullPipeName, PipeDirection direction, Int32 maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, Int32 inBufferSize, Int32 outBufferSize, PipeAccessRights rights, SECURITY_ATTRIBUTES secAttrs) at System.IO.Pipes.NamedPipeServerStream..ctor(String pipeName, PipeDirection direction, Int32 maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, Int32 inBufferSize, Int32 outBufferSize, PipeSecurity pipeSecurity, HandleInheritability inheritability, PipeAccessRights additionalAccessRights) at System.IO.Pipes.NamedPipeServerStream..ctor(String pipeName, PipeDirection direction, Int32 maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, Int32 inBufferSize, Int32 outBufferSize, PipeSecurity pipeSecurity) at PipeServer.Server.Client..ctor(String pipeName, List`1 container) in E:/Visual Studio 2010/Projects/Sandbox Service/PipeServer.cs:line 27 at PipeServer.Server.ListenForClients() in E:/Visual Studio 2010/Projects/Sandbox Service/PipeServer.cs:line 148 at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException:

Ejemplo eliminado Vea el ejemplo en la parte inferior para un caso de prueba más simple

La primera iteración funciona bien. es cuando el cliente se conecta y se llama al client = new Client se llama por segunda vez, lo que a su vez llama a Pipe = new NamedPipeServerStream y eso generará la excepción.

¿Alguien puede ver qué error estoy cometiendo?

Un poco más de información, por curiosidad volví a mi aplicación de consola. Para probar varias instancias, simplemente ejecuté el exe varias veces. Cuando coloco dos new NamedPipeServerStream en el mismo ejecutable, obtengo el mismo error ... Entonces, ¿por qué está bien si tienes un exe que actúa como el servidor que apunta a la misma dirección de canalización con nombre pero está prohibido hacerlo dentro del mismo exe? ?

static void Main() { PipeAccessRule pr = new PipeAccessRule("Users", PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow); PipeSecurity ps = new PipeSecurity(); ps.AddAccessRule(pr); using (NamedPipeServerStream pipeServer = new NamedPipeServerStream("testpipe",PipeDirection.InOut,10, PipeTransmissionMode.Message, PipeOptions.WriteThrough,4028,4028,ps)) using (NamedPipeServerStream pipeServer2 = //v-- Throws the execption, but if you comment this out and run the EXE twice it works fine. creating a new instance of ps and pr does not change anything. new NamedPipeServerStream("testpipe", PipeDirection.InOut, 10, PipeTransmissionMode.Message, PipeOptions.WriteThrough, 4028, 4028, ps)) {

Más información:

Si no configuro PipeSecurity , no se produce la excepción, pero cuando establezco la seguridad, lo hará. No importa si paso ambas instancias la misma PipeSecurity o dos instancias con la misma configuración, todavía se produce la excepción.


"Propietario del creador" se puede reemplazar por System.Security.Principal.WindowsIdentity.GetCurrent (). Nombre y elimine PipeAccessRights.CreateNewInstance para cualquier usuario.

static void Main() { PipeSecurity ps = new PipeSecurity(); ps.AddAccessRule(new PipeAccessRule("Users", PipeAccessRights.ReadWrite, AccessControlType.Allow)); ps.AddAccessRule(new PipeAccessRule(System.Security.Principal.WindowsIdentity.GetCurrent().Name, PipeAccessRights.FullControl, AccessControlType.Allow)); ps.AddAccessRule(new PipeAccessRule("SYSTEM", PipeAccessRights.FullControl, AccessControlType.Allow)); ps.AddAccessRule(pa);


Esto hará que el servidor sea accesible para todos para leer y escribir. También funcionará en el sistema operativo con todos los idiomas, ya que el nombre de usuario no está codificado.

public NamedPipeServerInstance(string pipeName, int maxNumberOfServerInstances) { var ps = new PipeSecurity(); var sid = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null); var everyone = sid.Translate(typeof(NTAccount)); ps.SetAccessRule(new PipeAccessRule(everyone, PipeAccessRights.ReadWrite, AccessControlType.Allow)); server = new NamedPipeServerStream(pipeName, PipeDirection.InOut, maxNumberOfServerInstances, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 4028, 4028, ps); var asyncResult = server.BeginWaitForConnection(OnConnected, null); } client = new NamedPipeClientStream(".", pipeName, PipeDirection.Out, PipeOptions.Asynchronous);


Hay dos cosas que pueden hacer que la creación de instancias de un segundo o posterior NamedPipeServerStream en el mismo canal falle:

  • el argumento ctor maxNumberOfServerInstances debe haberse establecido en más de 1 cuando se creó la primera instancia del servidor de tuberías. De lo contrario, la segunda llamada fallará a menos que la primera instancia ya se haya cerrado por completo.
  • el proceso que llama al ctor debe tener el derecho de acceso representado por PipeAccessRights.CreateNewInstance. Este es un derecho poderoso que el servidor de tuberías debería proteger celosamente, ya que le permite a su poseedor la capacidad de actuar como un servidor de tuberías.

El proceso de servicio debe establecer la seguridad de la tubería por lo tanto:

PipeSecurity ps = new PipeSecurity(); ps.AddAccessRule(new PipeAccessRule(myPipeUsersGroup, PipeAccessRights.ReadWrite, AccessControlType.Allow)); ps.AddAccessRule(new PipeAccessRule(myPipeServerIdentity, PipeAccessRights.FullControl, AccessControlType.Allow));

dónde:

  • myPipeUsersGroup es un marcador de posición para un grupo que contiene todas las identidades de clientes potenciales que se conectarán a la tubería. Dependiendo de sus necesidades / caso de uso, esto podría ser una identidad de cliente específica, un grupo personalizado o un grupo integrado como "Usuarios" o "Administradores".
  • myPipeServerIdentity es un marcador de posición para la identidad del servicio. Esto se puede establecer, por ejemplo, en WindowsIdentity.GetCurrent().Owner . Cuando el servidor de tuberías está alojado en un servicio de Windows, incluso mejor (pero mucho más difícil de implementar) sería la identidad SID de inicio de sesión del proceso de servicio; esto garantizaría que solo el proceso de servicio específico podría crear instancias de la tubería.

Si desea asegurarse de que el acceso a las tuberías esté restringido solo a los usuarios que han iniciado sesión localmente, es decir, para evitar el acceso remoto a través de una red, también puede agregar un ACE de denegación para los usuarios de la red en la ACL de seguridad de las tuberías.


La solución que funciona en versiones localizadas de Windows:

pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), accessRights, PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow)); pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.CreatorOwnerSid, null), PipeAccessRights.FullControl, AccessControlType.Allow)); pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null), PipeAccessRights.FullControl, AccessControlType.Allow));


Me lo imaginé.

static void Main() { PipeSecurity ps = new PipeSecurity(); ps.AddAccessRule(new PipeAccessRule("Users", PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow)); ps.AddAccessRule(new PipeAccessRule("CREATOR OWNER", PipeAccessRights.FullControl, AccessControlType.Allow)); ps.AddAccessRule(new PipeAccessRule("SYSTEM", PipeAccessRights.FullControl, AccessControlType.Allow)); ps.AddAccessRule(pa); using (NamedPipeServerStream pipeServer = new NamedPipeServerStream("testpipe",PipeDirection.InOut,10, PipeTransmissionMode.Message, PipeOptions.WriteThrough, 1024,1024,ps)) using (NamedPipeServerStream pipeServer2 = new NamedPipeServerStream("testpipe", PipeDirection.InOut, 10, PipeTransmissionMode.Message, PipeOptions.WriteThrough,1024,1024,ps)) {

Al agregar los derechos PipeAccessRights.CreateNewInstance ahora funciona bien.

Hice otro problema pero lo resolví, pero quería publicarlo en caso de que otras personas lo encontraran a través de Google. Al proporcionar su propio objeto de seguridad Pipe, elimina el objeto predeterminado, de modo que si lo necesita, debe volver a agregar el grupo del sistema para que pueda comunicarse con la tubería si está escribiendo un servicio. Actualicé mi código anterior a lo que solía obtener para un servicio elevado y una aplicación de formularios de Windows no elevados para hablar entre nosotros (el propietario del creador probablemente no sea necesario)


Sé que hay muchas respuestas a esta pregunta, pero solucioné un problema similar al establecer el nivel de requestExecutionLevel para requireAdministrator en el archivo app.manifest del proyecto donde reside el código de mi pipa con nombre. Y esto solucionó la excepciónAutcessAccessException para mí