Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Attempted to perform an unauthorized operation" when calling NamedPipeServerStream.SetAccessControl

I'm trying to use PipeSecurity to secure a NamedPipeServerStream. When I call this.pipeServer.SetAccessControl(pipeSecurity) in the snippet below I get the following exception:

Attempted to perform an unauthorized operation.
    at System.Security.AccessControl.Win32.SetSecurityInfo(ResourceType type, String name, SafeHandle handle, SecurityInfos securityInformation, SecurityIdentifier owner, SecurityIdentifier group, GenericAcl sacl, GenericAcl dacl)
    at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, SafeHandle handle, AccessControlSections includeSections, Object exceptionContext)
    at System.Security.AccessControl.NativeObjectSecurity.Persist(SafeHandle handle, AccessControlSections includeSections, Object exceptionContext)
    at System.IO.Pipes.PipeSecurity.Persist(SafeHandle handle)

code:

this.pipeServer =
    new NamedPipeServerStream(
        pipeName,
        PipeDirection.InOut,
        1,
        PipeTransmissionMode.Byte,
        PipeOptions.Asynchronous);

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 current user read and write access to the pipe.
    pipeSecurity.AddAccessRule(new PipeAccessRule(
        WindowsIdentity.GetCurrent().User,
        PipeAccessRights.ReadWrite, AccessControlType.Allow));
}

this.pipeServer.SetAccessControl(pipeSecurity);

Any ideas of what I'm doing wrong?

This is happening in .NET Framework (targeting net451) and .NET Standard 1.6 using the System.IO.AccessControl nuget package:

https://www.nuget.org/packages/System.IO.Pipes.AccessControl/

Edit:

I was able to use an #ifdef to use the following constructor that worked for .NET Framework:

public NamedPipeServerStream (string pipeName, System.IO.Pipes.PipeDirection direction, int maxNumberOfServerInstances, System.IO.Pipes.PipeTransmissionMode transmissionMode, System.IO.Pipes.PipeOptions options, int inBufferSize, int outBufferSize, System.IO.Pipes.PipeSecurity pipeSecurity)

However, this constructor does not exist in .NET Standard. I tried using this function that was added to .NET Core:

PipesAclExtensions.SetAccessControl(PipeStream, PipeSecurity)

But that yields the same exception from before.

I created a gist to show this.

like image 634
Tyler James Leonhardt Avatar asked Jun 06 '18 02:06

Tyler James Leonhardt


2 Answers

I just had the same issue and tried to track it down.

TL;DR

The current status (Feb-2019) is sad but true: it just does not work with the classes that are given in today's NET Standard.

Ticket references

  • issue 30170 “unauthorized operation” on NamedPipeServerStream.SetAccessControl
  • issue 31190 System.IO.Pipes.AccessControl package does not work
  • issue 24040 NamedPipeServerStream: Provide support for WRITE_DAC

Also interesting in this context could be the *nix-related

  • issue 34400 mechanism for lower privileged user to connect to a privileged user's pipe

Possible workaround

One still can use native API calls to get security set up as desired, but that's not for the faint of heart. One basically needs to implement these steps:

  • set up a security descriptor in binary representation
  • connect it to the SECURITY_ATTRIBUTES structure
  • create the pipe via Windows API CreateNamedPipe()
  • wrap the resulting handle into a SafeHandle
  • and feed that into the right NamedPipeServerStream CTOR variant

PS: At least we now can look it up in the code where it is hitting the wall. Just imagine having that problem 20 years ago ...

like image 106
JensG Avatar answered Sep 27 '22 19:09

JensG


In NET 5 you can create a NamedPipeServerStream available to all user accounts by defining it like this:

PipeSecurity pipeSecurity = new PipeSecurity();
pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), PipeAccessRights.ReadWrite, AccessControlType.Allow));
using (var pipe = NamedPipeServerStreamAcl.Create("MyAppPipeName", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.None, 0, 0, pipeSecurity))
{
    pipe.WaitForConnection();
    // ...
}

Please note that this is for Windows operating system only.

like image 20
Alexandru Dicu Avatar answered Sep 27 '22 21:09

Alexandru Dicu