OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

Can't communicate between different levels of admin privileges using named pipes in .NET 8

  • Thread starter Thread starter haxonek
  • Start date Start date
H

haxonek

Guest
I have a program which is composed of a Windows Service and a GUI. The windows service runs under a local system account, and the GUI runs on a user account and receives information about the service through a named pipe.

The issue I'm having is the pipe can't communicate with the GUI unless the GUI was run with admin privileges. If I try to access the pipe without admin privileges, I get an access to path is denied error. I have also tried passing in a PipeSecurity value, however then I get an error saying The operation has timed out.

Here is the code I'm running with the PipeSecurity option passed in;

Code:
private async Task ListenForPipeRequests(CancellationToken token)
{
    while (!token.IsCancellationRequested) {
        PipeSecurity security = CreatePipeSecurity();
        
        using (var server = NamedPipeServerStreamAcl.Create(
            "my_unique_pipe_name",
            PipeDirection.InOut,
            1, // maxNumberOfServerInstances
            PipeTransmissionMode.Byte,
            PipeOptions.Asynchronous,
            1024, // inBufferSize
            1024, // outBufferSize
            security, // pipeSecurity
            HandleInheritability.Inheritable,
            PipeAccessRights.FullControl))
        {            
            try
            {
                await server.WaitForConnectionAsync(token);

                using (var reader = new StreamReader(server))
                using (var writer = new StreamWriter(server) { AutoFlush = true })
                {
                    string? message;
                    while ((message = await reader.ReadLineAsync()) != null)
                    {
                        // Process the received message
                        string response2 = HandleRequest(message);

                        // Optionally send a response
                        await writer.WriteLineAsync(response2);
                    }
                }

            }
            catch (OperationCanceledException ex)
            {
                // Handle cancellation
                SaveToLog("Cancelation: " + ex.Message);
            }
            catch (IOException ioex)
            {
                // Handle pipe broken or other IO exceptions
                SaveToLog("IO Exception: " + ioex.Message);
            }
            catch (Exception ex)
            {
                SaveToLog("Exception: " + ex.Message);
            }
        }
    }
}

private PipeSecurity CreatePipeSecurity()
{
    var pipeSecurity = new PipeSecurity();

    // Grant full control to the current user
    var currentUser = WindowsIdentity.GetCurrent().User;
    pipeSecurity.AddAccessRule(new PipeAccessRule(
        currentUser,
        PipeAccessRights.FullControl,
        AccessControlType.Allow));

    // Grant full control to the Local System account
    pipeSecurity.AddAccessRule(new PipeAccessRule(
        new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null),
        PipeAccessRights.FullControl,
        AccessControlType.Allow));

    // Grant full control to Administrators
    pipeSecurity.AddAccessRule(new PipeAccessRule(
        new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null),
        PipeAccessRights.FullControl,
        AccessControlType.Allow));

    // Grant read/write access to everyone
    pipeSecurity.AddAccessRule(new PipeAccessRule(
        new SecurityIdentifier(WellKnownSidType.WorldSid, null),
        PipeAccessRights.ReadWrite,
        AccessControlType.Allow));

    return pipeSecurity;
}

When I'm not debugging with Acl, I'm just using the NamedPipeStream like this

Code:
using (var server = new NamedPipeServerStream("my_unique_pipe_name", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
{ ... }

However as mentioned this doesn't work when I don't access the pipe from an application running under admin rights, instead giving me an access to path denied error.

Does anyone have any thought on what could be causing my issue? This seems like it should be a common issue, however I can't find any threads that use a recent version of .NET. The AddAccessRules are perhaps overly generous right now, but that's because I can't figure out what's wrong. I'm installing the service using sc.exe, and I'm running the gui using the visual studio debugger if that matters.

I really appreciate any input you have; thanks!
<p>I have a program which is composed of a Windows Service and a GUI. The windows service runs under a local system account, and the GUI runs on a user account and receives information about the service through a named pipe.</p>
<p>The issue I'm having is the pipe can't communicate with the GUI unless the GUI was run with admin privileges. If I try to access the pipe without admin privileges, I get an <code>access to path is denied</code> error. I have also tried passing in a <code>PipeSecurity</code> value, however then I get an error saying <code>The operation has timed out</code>.</p>
<p>Here is the code I'm running with the <code>PipeSecurity</code> option passed in;</p>
<pre><code>private async Task ListenForPipeRequests(CancellationToken token)
{
while (!token.IsCancellationRequested) {
PipeSecurity security = CreatePipeSecurity();

using (var server = NamedPipeServerStreamAcl.Create(
"my_unique_pipe_name",
PipeDirection.InOut,
1, // maxNumberOfServerInstances
PipeTransmissionMode.Byte,
PipeOptions.Asynchronous,
1024, // inBufferSize
1024, // outBufferSize
security, // pipeSecurity
HandleInheritability.Inheritable,
PipeAccessRights.FullControl))
{
try
{
await server.WaitForConnectionAsync(token);

using (var reader = new StreamReader(server))
using (var writer = new StreamWriter(server) { AutoFlush = true })
{
string? message;
while ((message = await reader.ReadLineAsync()) != null)
{
// Process the received message
string response2 = HandleRequest(message);

// Optionally send a response
await writer.WriteLineAsync(response2);
}
}

}
catch (OperationCanceledException ex)
{
// Handle cancellation
SaveToLog("Cancelation: " + ex.Message);
}
catch (IOException ioex)
{
// Handle pipe broken or other IO exceptions
SaveToLog("IO Exception: " + ioex.Message);
}
catch (Exception ex)
{
SaveToLog("Exception: " + ex.Message);
}
}
}
}

private PipeSecurity CreatePipeSecurity()
{
var pipeSecurity = new PipeSecurity();

// Grant full control to the current user
var currentUser = WindowsIdentity.GetCurrent().User;
pipeSecurity.AddAccessRule(new PipeAccessRule(
currentUser,
PipeAccessRights.FullControl,
AccessControlType.Allow));

// Grant full control to the Local System account
pipeSecurity.AddAccessRule(new PipeAccessRule(
new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null),
PipeAccessRights.FullControl,
AccessControlType.Allow));

// Grant full control to Administrators
pipeSecurity.AddAccessRule(new PipeAccessRule(
new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null),
PipeAccessRights.FullControl,
AccessControlType.Allow));

// Grant read/write access to everyone
pipeSecurity.AddAccessRule(new PipeAccessRule(
new SecurityIdentifier(WellKnownSidType.WorldSid, null),
PipeAccessRights.ReadWrite,
AccessControlType.Allow));

return pipeSecurity;
}
</code></pre>
<p>When I'm not debugging with Acl, I'm just using the NamedPipeStream like this</p>
<pre><code>using (var server = new NamedPipeServerStream("my_unique_pipe_name", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
{ ... }
</code></pre>
<p>However as mentioned this doesn't work when I don't access the pipe from an application running under admin rights, instead giving me an <code>access to path denied</code> error.</p>
<p>Does anyone have any thought on what could be causing my issue? This seems like it should be a common issue, however I can't find any threads that use a recent version of .NET. The AddAccessRules are perhaps overly generous right now, but that's because I can't figure out what's wrong. I'm installing the service using sc.exe, and I'm running the gui using the visual studio debugger if that matters.</p>
<p>I really appreciate any input you have; thanks!</p>
Continue reading...
 
Top