我尝试使用PipeSecurity
来保护NamedPipeServerStream
。当我在下面的代码段中调用this.pipeServer.SetAccessControl(pipeSecurity)
时,我得到以下异常:
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)
代码:
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);
我做错了什么想法?
使用System.IO.AccessControl nuget包在.NET Framework(目标net451)和.NET Standard 1.6中发生这种情况:
https://www.nuget.org/packages/System.IO.Pipes.AccessControl/
修改:
我能够使用#ifdef来使用适用于.NET Framework的the following constructor:
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)
但是,.NET Standard中不存在此构造函数。我尝试使用添加到.NET Core的this function:
PipesAclExtensions.SetAccessControl(PipeStream, PipeSecurity)
但是从那之前就产生了同样的例外。
答案 0 :(得分:4)
最近,在将项目转换为.Net Core时遇到相同的问题。
我添加了一个nuget包来帮助进行过渡:https://www.nuget.org/packages/NamedPipeServerStream.NetFrameworkVersion/
Install-Package NamedPipeServerStream.NetFrameworkVersion
using System.IO.Pipes;
var pipeSecurity = new PipeSecurity();
pipeSecurity.AddAccessRule(new PipeAccessRule(WindowsIdentity.GetCurrent().Owner, PipeAccessRights.ReadWrite, AccessControlType.Allow));
using var serverStream = NamedPipeServerStreamConstructors.New(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, 0, 0, pipeSecurity);
答案 1 :(得分:1)
我只是遇到了同样的问题,并试图对其进行跟踪。
当前状态(2019年2月)令人难过,但确实如此:它不适用于当今NET标准中提供的类。
在这种情况下,有趣的还可能是与* nix相关的
一个人仍然可以使用本机API调用来按需要设置安全性,但这并不是出于胆小。基本上需要执行以下步骤:
SECURITY_ATTRIBUTES
structure CreateNamedPipe()
SafeHandle
PS:至少我们现在可以在碰壁的代码中查找它。试想一下20年前有这个问题...
答案 2 :(得分:1)
我设法提出了可能的解决方法JensG。我使用此示例进行构建: https://code.msdn.microsoft.com/CSNamedPipeServer-4c760c2c/sourcecode?fileId=21684&pathId=1498714400
public static class NativeNamedPipeServer
{
public static SafePipeHandle CreateNamedPipeServer(string pipeName, string sddl)
{
return NativeMethod.CreateNamedPipe(
@"\\.\pipe\" + pipeName, // The unique pipe name.
PipeOpenMode.PIPE_ACCESS_DUPLEX | PipeOpenMode.ASYNCHRONOUS,
PipeMode.PIPE_TYPE_BYTE,
1, // Max server instances
1024 * 16, // Output buffer size
1024 * 16, // Input buffer size
NMPWAIT_USE_DEFAULT_WAIT, // Time-out interval
CreateNativePipeSecurity(sddl) // Pipe security attributes
);
}
/// <summary>
/// The CreateNativePipeSecurity function creates and initializes a new
/// SECURITY_ATTRIBUTES object to allow Authenticated Users read and
/// write access to a pipe, and to allow the Administrators group full
/// access to the pipe.
/// </summary>
/// <returns>
/// A SECURITY_ATTRIBUTES object that allows Authenticated Users read and
/// write access to a pipe, and allows the Administrators group full
/// access to the pipe.
/// </returns>
/// <see cref="http://msdn.microsoft.com/en-us/library/aa365600(VS.85).aspx"/>
private static SECURITY_ATTRIBUTES CreateNativePipeSecurity(string sddl)
{
if (!NativeMethod.ConvertStringSecurityDescriptorToSecurityDescriptor(
sddl, 1, out var pSecurityDescriptor, IntPtr.Zero))
{
throw new Win32Exception();
}
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.nLength = Marshal.SizeOf(sa);
sa.lpSecurityDescriptor = pSecurityDescriptor;
sa.bInheritHandle = false;
return sa;
}
#region Native API Signatures and Types
/// <summary>
/// Named Pipe Open Modes
/// http://msdn.microsoft.com/en-us/library/aa365596.aspx
/// </summary>
[Flags]
internal enum PipeOpenMode : uint
{
PIPE_ACCESS_INBOUND = 0x00000001, // Inbound pipe access.
PIPE_ACCESS_OUTBOUND = 0x00000002, // Outbound pipe access.
PIPE_ACCESS_DUPLEX = 0x00000003, // Duplex pipe access.
// added from C# PipeOptions.cs
WRITE_THROUGH = 0x80000000,
ASYNCHRONOUS = 0x40000000,
CURRENT_USER_ONLY = 0x20000000
}
/// <summary>
/// Named Pipe Type, Read, and Wait Modes
/// http://msdn.microsoft.com/en-us/library/aa365605.aspx
/// </summary>
[Flags]
internal enum PipeMode : uint
{
// Type Mode
PIPE_TYPE_BYTE = 0x00000000, // Byte pipe type.
PIPE_TYPE_MESSAGE = 0x00000004, // Message pipe type.
// Read Mode
PIPE_READMODE_BYTE = 0x00000000, // Read mode of type Byte.
PIPE_READMODE_MESSAGE = 0x00000002, // Read mode of type Message.
// Wait Mode
PIPE_WAIT = 0x00000000, // Pipe blocking mode.
PIPE_NOWAIT = 0x00000001 // Pipe non-blocking mode.
}
/// <summary>
/// Uses the default time-out specified in a call to the
/// CreateNamedPipe method.
/// </summary>
internal const uint NMPWAIT_USE_DEFAULT_WAIT = 0x00000000;
/// <summary>
/// The SECURITY_ATTRIBUTES structure contains the security descriptor for
/// an object and specifies whether the handle retrieved by specifying
/// this structure is inheritable. This structure provides security
/// settings for objects created by various functions, such as CreateFile,
/// CreateNamedPipe, CreateProcess, RegCreateKeyEx, or RegSaveKeyEx.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class SECURITY_ATTRIBUTES
{
public int nLength;
public SafeLocalMemHandle lpSecurityDescriptor;
public bool bInheritHandle;
}
/// <summary>
/// Represents a wrapper class for a local memory pointer.
/// </summary>
[SuppressUnmanagedCodeSecurity,
HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
internal sealed class SafeLocalMemHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeLocalMemHandle() : base(true)
{
}
public SafeLocalMemHandle(IntPtr preexistingHandle, bool ownsHandle)
: base(ownsHandle)
{
base.SetHandle(preexistingHandle);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success),
DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LocalFree(IntPtr hMem);
protected override bool ReleaseHandle()
{
return (LocalFree(base.handle) == IntPtr.Zero);
}
}
/// <summary>
/// The class exposes Windows APIs to be used in this code sample.
/// </summary>
[SuppressUnmanagedCodeSecurity]
internal class NativeMethod
{
/// <summary>
/// Creates an instance of a named pipe and returns a handle for
/// subsequent pipe operations.
/// </summary>
/// <param name="pipeName">Pipe name</param>
/// <param name="openMode">Pipe open mode</param>
/// <param name="pipeMode">Pipe-specific modes</param>
/// <param name="maxInstances">Maximum number of instances</param>
/// <param name="outBufferSize">Output buffer size</param>
/// <param name="inBufferSize">Input buffer size</param>
/// <param name="defaultTimeout">Time-out interval</param>
/// <param name="securityAttributes">Security attributes</param>
/// <returns>If the function succeeds, the return value is a handle
/// to the server end of a named pipe instance.</returns>
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern SafePipeHandle CreateNamedPipe(string pipeName,
PipeOpenMode openMode, PipeMode pipeMode, int maxInstances,
int outBufferSize, int inBufferSize, uint defaultTimeout,
SECURITY_ATTRIBUTES securityAttributes);
/// <summary>
/// The ConvertStringSecurityDescriptorToSecurityDescriptor function
/// converts a string-format security descriptor into a valid,
/// functional security descriptor.
/// </summary>
/// <param name="sddlSecurityDescriptor">
/// A string containing the string-format security descriptor (SDDL)
/// to convert.
/// </param>
/// <param name="sddlRevision">
/// The revision level of the sddlSecurityDescriptor string.
/// Currently this value must be 1.
/// </param>
/// <param name="pSecurityDescriptor">
/// A pointer to a variable that receives a pointer to the converted
/// security descriptor.
/// </param>
/// <param name="securityDescriptorSize">
/// A pointer to a variable that receives the size, in bytes, of the
/// converted security descriptor. This parameter can be IntPtr.Zero.
/// </param>
/// <returns>
/// If the function succeeds, the return value is true.
/// </returns>
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(
string sddlSecurityDescriptor, int sddlRevision,
out SafeLocalMemHandle pSecurityDescriptor,
IntPtr securityDescriptorSize);
}
#endregion
}
创建:
var safePipeHandle = NativeNamedPipeServer.CreateNamedPipeServer(_pipeName,
pipeSecurity.GetSecurityDescriptorSddlForm(AccessControlSections.Access));
var stream = new NamedPipeServerStream(PipeDirection.InOut, true, false, safePipeHandle);
最棘手的部分是使异步工作,因为原始源没有PipeOpenMode.ASYNCHRONOUS
标志。通过检查.NET Core 3.0代码了解了这一点。奇怪的是,它们在其中拥有所有管道安全代码,但没有该代码的构造函数。因此,替代方法实际上可能是反思。
答案 3 :(得分:0)
在NET 5中,您可以通过定义如下内容来创建供所有用户帐户使用的 NamedPipeServerStream :
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();
// ...
}
请注意,这仅适用于Windows操作系统。