cyanfish / grpc-dotnet-namedpipes

Named pipe transport for gRPC in C#/.NET
Apache License 2.0
190 stars 48 forks source link

System.UnauthorizedAccessException when contacting gRPC server from another user #38

Closed LAB02-Admin closed 1 year ago

LAB02-Admin commented 2 years ago

Hi again,

I'm running a service under SYSTEM account, and want to contact it from a normal user. I've already set CurrentUserOnly = false in both the client and server, but I still get a System.UnauthorizedAccessException whenever I try to connect.

If I run my client application elevated, it works fine, but that's not an option for deployment.

I don't see any options to set the security options like in this thread,

I'm guessing that has to do with the fact that I'm using .NET 6. In the past I've used this library NamedPipeServerStream.NetFrameworkVersion to restore the security options from .NET Framework. Is that something that could be used here?

LAB02-Admin commented 2 years ago

Update: I enabled PipeSecurity by adding NET6_0 to NamedPipeServerOptions.cs in your library:

#if NETFRAMEWORK || NET5_0 || NET6_0
        /// <summary>
        /// Gets or sets a value indicating the access control to be used for the pipe.
        /// </summary>
        public PipeSecurity PipeSecurity { get; set; }
#endif

Also added net6.0-windows as a target framework. I can make a PR if you want.

However, the problem's still there. I initialize the server with these settings (took them from GrpcNamedPipeTests.cs -> SimpleUnaryWithACLs():

var pipeSecurity = new PipeSecurity();
var usersSid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
var systemSid = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
pipeSecurity.AddAccessRule(new PipeAccessRule(usersSid, PipeAccessRights.ReadWrite, AccessControlType.Allow));
pipeSecurity.AddAccessRule(new PipeAccessRule(systemSid, PipeAccessRights.FullControl, AccessControlType.Allow));

var serverOptions = new NamedPipeServerOptions
{
    PipeSecurity = pipeSecurity
};

Tried with CurrentUserOnly = false as well. The service runs as SYSTEM, the client as a normal user.

I initialize the client's channel as such:

private readonly NamedPipeChannel _serviceChannel = new(".", Variables.PipeName, new NamedPipeChannelOptions 
{ 
        ConnectionTimeout = (int)TimeSpan.FromSeconds(10).TotalMilliseconds
});

Tried a bunch of TokenImpersonationLevel types as well, and CurrentUserOnly = false - no luck.

Any idea what I'm missing or doing wrong? Thanks!

LAB02-Admin commented 2 years ago

Okay, I fixed it. Had to add NET6_0 to ServerStreamPool.cs as well:

#if NET5_0 || NET6_0
            return NamedPipeServerStreamAcl.Create(_pipeName,
                PipeDirection.InOut,
                NamedPipeServerStream.MaxAllowedServerInstances,
                PipeTransmissionMode.Message,
                pipeOptions,
                0,
                0,
                _options.PipeSecurity);
#else
            return new NamedPipeServerStream(_pipeName,
                PipeDirection.InOut,
                NamedPipeServerStream.MaxAllowedServerInstances,
                PipeTransmissionMode.Message,
                pipeOptions);
#endif

Let me know if you want me to make a PR for this, if it's the solution you'd recommend.

cyanfish commented 2 years ago

Hi, thanks for figuring that out! I'd merge a PR that uses NET5_0_OR_GREATER instead of NET5_0.

LAB02-Admin commented 2 years ago

Done: https://github.com/cyanfish/grpc-dotnet-namedpipes/pull/39

LAB02-Admin commented 2 years ago

Hey @cyanfish, could you please take a look at the PR and possible merge it? I now compiled and added my own library and its dependencies, but it'd be cleaner if I could just add your package again :)

Thanks!

cyanfish commented 1 year ago

Sorry I didn't get to this until now, but this should be in 2.0.0 (along with some other changes listed in the changelog).

LAB02-Admin commented 1 year ago

Awesome! ❤️