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;
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
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!
WellKnownSidType.AuthenticatedUserSid
? stackoverflow.com/questions/51546328/…NamedPipeServerStreamAcl.Create
function instead ofNamedPipeServerStream
, and then I had to get rid of theHandleInheritability.Inheritable, PipeAccessRights.FullControl
variables from the constructor which were in my example. Otherwise it works now!