File: //proc/self/root/usr/lib/python3.9/site-packages/ansible/module_utils/csharp/Ansible.Become.cs
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Text;
using Ansible.AccessToken;
using Ansible.Process;
namespace Ansible.Become
{
internal class NativeHelpers
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct KERB_S4U_LOGON
{
public UInt32 MessageType;
public UInt32 Flags;
public LSA_UNICODE_STRING ClientUpn;
public LSA_UNICODE_STRING ClientRealm;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct LSA_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
[MarshalAs(UnmanagedType.LPStr)] public string Buffer;
public static implicit operator string(LSA_STRING s)
{
return s.Buffer;
}
public static implicit operator LSA_STRING(string s)
{
if (s == null)
s = "";
LSA_STRING lsaStr = new LSA_STRING
{
Buffer = s,
Length = (UInt16)s.Length,
MaximumLength = (UInt16)(s.Length + 1),
};
return lsaStr;
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct LSA_UNICODE_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public IntPtr Buffer;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_LOGON_SESSION_DATA
{
public UInt32 Size;
public Luid LogonId;
public LSA_UNICODE_STRING UserName;
public LSA_UNICODE_STRING LogonDomain;
public LSA_UNICODE_STRING AuthenticationPackage;
public SECURITY_LOGON_TYPE LogonType;
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_SOURCE
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public char[] SourceName;
public Luid SourceIdentifier;
}
public enum SECURITY_LOGON_TYPE
{
System = 0, // Used only by the System account
Interactive = 2,
Network,
Batch,
Service,
Proxy,
Unlock,
NetworkCleartext,
NewCredentials,
RemoteInteractive,
CachedInteractive,
CachedRemoteInteractive,
CachedUnlock
}
}
internal class NativeMethods
{
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool AllocateLocallyUniqueId(
out Luid Luid);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CreateProcessWithTokenW(
SafeNativeHandle hToken,
LogonFlags dwLogonFlags,
[MarshalAs(UnmanagedType.LPWStr)] string lpApplicationName,
StringBuilder lpCommandLine,
Process.NativeHelpers.ProcessCreationFlags dwCreationFlags,
Process.SafeMemoryBuffer lpEnvironment,
[MarshalAs(UnmanagedType.LPWStr)] string lpCurrentDirectory,
Process.NativeHelpers.STARTUPINFOEX lpStartupInfo,
out Process.NativeHelpers.PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll")]
public static extern UInt32 GetCurrentThreadId();
[DllImport("user32.dll", SetLastError = true)]
public static extern NoopSafeHandle GetProcessWindowStation();
[DllImport("user32.dll", SetLastError = true)]
public static extern NoopSafeHandle GetThreadDesktop(
UInt32 dwThreadId);
[DllImport("secur32.dll", SetLastError = true)]
public static extern UInt32 LsaDeregisterLogonProcess(
IntPtr LsaHandle);
[DllImport("secur32.dll", SetLastError = true)]
public static extern UInt32 LsaFreeReturnBuffer(
IntPtr Buffer);
[DllImport("secur32.dll", SetLastError = true)]
public static extern UInt32 LsaGetLogonSessionData(
ref Luid LogonId,
out SafeLsaMemoryBuffer ppLogonSessionData);
[DllImport("secur32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern UInt32 LsaLogonUser(
SafeLsaHandle LsaHandle,
NativeHelpers.LSA_STRING OriginName,
LogonType LogonType,
UInt32 AuthenticationPackage,
IntPtr AuthenticationInformation,
UInt32 AuthenticationInformationLength,
IntPtr LocalGroups,
NativeHelpers.TOKEN_SOURCE SourceContext,
out SafeLsaMemoryBuffer ProfileBuffer,
out UInt32 ProfileBufferLength,
out Luid LogonId,
out SafeNativeHandle Token,
out IntPtr Quotas,
out UInt32 SubStatus);
[DllImport("secur32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern UInt32 LsaLookupAuthenticationPackage(
SafeLsaHandle LsaHandle,
NativeHelpers.LSA_STRING PackageName,
out UInt32 AuthenticationPackage);
[DllImport("advapi32.dll")]
public static extern UInt32 LsaNtStatusToWinError(
UInt32 Status);
[DllImport("secur32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern UInt32 LsaRegisterLogonProcess(
NativeHelpers.LSA_STRING LogonProcessName,
out SafeLsaHandle LsaHandle,
out IntPtr SecurityMode);
}
internal class SafeLsaHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeLsaHandle() : base(true) { }
protected override bool ReleaseHandle()
{
UInt32 res = NativeMethods.LsaDeregisterLogonProcess(handle);
return res == 0;
}
}
internal class SafeLsaMemoryBuffer : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeLsaMemoryBuffer() : base(true) { }
protected override bool ReleaseHandle()
{
UInt32 res = NativeMethods.LsaFreeReturnBuffer(handle);
return res == 0;
}
}
internal class NoopSafeHandle : SafeHandle
{
public NoopSafeHandle() : base(IntPtr.Zero, false) { }
public override bool IsInvalid { get { return false; } }
protected override bool ReleaseHandle() { return true; }
}
[Flags]
public enum LogonFlags
{
WithProfile = 0x00000001,
NetcredentialsOnly = 0x00000002
}
public class BecomeUtil
{
private static List<string> SERVICE_SIDS = new List<string>()
{
"S-1-5-18", // NT AUTHORITY\SYSTEM
"S-1-5-19", // NT AUTHORITY\LocalService
"S-1-5-20" // NT AUTHORITY\NetworkService
};
private static int WINDOWS_STATION_ALL_ACCESS = 0x000F037F;
private static int DESKTOP_RIGHTS_ALL_ACCESS = 0x000F01FF;
public static Result CreateProcessAsUser(string username, string password, string command)
{
return CreateProcessAsUser(username, password, LogonFlags.WithProfile, LogonType.Interactive,
null, command, null, null, "");
}
public static Result CreateProcessAsUser(string username, string password, LogonFlags logonFlags, LogonType logonType,
string lpApplicationName, string lpCommandLine, string lpCurrentDirectory, IDictionary environment,
string stdin)
{
byte[] stdinBytes;
if (String.IsNullOrEmpty(stdin))
stdinBytes = new byte[0];
else
{
if (!stdin.EndsWith(Environment.NewLine))
stdin += Environment.NewLine;
stdinBytes = new UTF8Encoding(false).GetBytes(stdin);
}
return CreateProcessAsUser(username, password, logonFlags, logonType, lpApplicationName, lpCommandLine,
lpCurrentDirectory, environment, stdinBytes);
}
/// <summary>
/// Creates a process as another user account. This method will attempt to run as another user with the
/// highest possible permissions available. The main privilege required is the SeDebugPrivilege, without
/// this privilege you can only run as a local or domain user if the username and password is specified.
/// </summary>
/// <param name="username">The username of the runas user</param>
/// <param name="password">The password of the runas user</param>
/// <param name="logonFlags">LogonFlags to control how to logon a user when the password is specified</param>
/// <param name="logonType">Controls what type of logon is used, this only applies when the password is specified</param>
/// <param name="lpApplicationName">The name of the executable or batch file to executable</param>
/// <param name="lpCommandLine">The command line to execute, typically this includes lpApplication as the first argument</param>
/// <param name="lpCurrentDirectory">The full path to the current directory for the process, null will have the same cwd as the calling process</param>
/// <param name="environment">A dictionary of key/value pairs to define the new process environment</param>
/// <param name="stdin">Bytes sent to the stdin pipe</param>
/// <returns>Ansible.Process.Result object that contains the command output and return code</returns>
public static Result CreateProcessAsUser(string username, string password, LogonFlags logonFlags, LogonType logonType,
string lpApplicationName, string lpCommandLine, string lpCurrentDirectory, IDictionary environment, byte[] stdin)
{
// While we use STARTUPINFOEX having EXTENDED_STARTUPINFO_PRESENT causes a parameter validation error
Process.NativeHelpers.ProcessCreationFlags creationFlags = Process.NativeHelpers.ProcessCreationFlags.CREATE_UNICODE_ENVIRONMENT;
Process.NativeHelpers.PROCESS_INFORMATION pi = new Process.NativeHelpers.PROCESS_INFORMATION();
Process.NativeHelpers.STARTUPINFOEX si = new Process.NativeHelpers.STARTUPINFOEX();
si.startupInfo.dwFlags = Process.NativeHelpers.StartupInfoFlags.USESTDHANDLES;
SafeFileHandle stdoutRead, stdoutWrite, stderrRead, stderrWrite, stdinRead, stdinWrite;
ProcessUtil.CreateStdioPipes(si, out stdoutRead, out stdoutWrite, out stderrRead, out stderrWrite,
out stdinRead, out stdinWrite);
FileStream stdinStream = new FileStream(stdinWrite, FileAccess.Write);
// $null from PowerShell ends up as an empty string, we need to convert back as an empty string doesn't
// make sense for these parameters
if (lpApplicationName == "")
lpApplicationName = null;
if (lpCurrentDirectory == "")
lpCurrentDirectory = null;
// A user may have 2 tokens, 1 limited and 1 elevated. GetUserTokens will return both token to ensure
// we don't close one of the pairs while the process is still running. If the process tries to retrieve
// one of the pairs and the token handle is closed then it will fail with ERROR_NO_SUCH_LOGON_SESSION.
List<SafeNativeHandle> userTokens = GetUserTokens(username, password, logonType);
try
{
using (Process.SafeMemoryBuffer lpEnvironment = ProcessUtil.CreateEnvironmentPointer(environment))
{
bool launchSuccess = false;
StringBuilder commandLine = new StringBuilder(lpCommandLine);
foreach (SafeNativeHandle token in userTokens)
{
// GetUserTokens could return null if an elevated token could not be retrieved.
if (token == null)
continue;
if (NativeMethods.CreateProcessWithTokenW(token, logonFlags, lpApplicationName,
commandLine, creationFlags, lpEnvironment, lpCurrentDirectory, si, out pi))
{
launchSuccess = true;
break;
}
}
if (!launchSuccess)
throw new Process.Win32Exception("CreateProcessWithTokenW() failed");
}
return ProcessUtil.WaitProcess(stdoutRead, stdoutWrite, stderrRead, stderrWrite, stdinStream, stdin,
pi.hProcess);
}
finally
{
userTokens.Where(t => t != null).ToList().ForEach(t => t.Dispose());
}
}
private static List<SafeNativeHandle> GetUserTokens(string username, string password, LogonType logonType)
{
List<SafeNativeHandle> userTokens = new List<SafeNativeHandle>();
SafeNativeHandle systemToken = null;
bool impersonated = false;
string becomeSid = username;
if (logonType != LogonType.NewCredentials)
{
// If prefixed with .\, we are becoming a local account, strip the prefix
if (username.StartsWith(".\\"))
username = username.Substring(2);
NTAccount account = new NTAccount(username);
becomeSid = ((SecurityIdentifier)account.Translate(typeof(SecurityIdentifier))).Value;
// Grant access to the current Windows Station and Desktop to the become user
GrantAccessToWindowStationAndDesktop(account);
// Try and impersonate a SYSTEM token, we need a SYSTEM token to either become a well known service
// account or have administrative rights on the become access token.
// If we ultimately are becoming the SYSTEM account we want the token with the most privileges available.
// https://github.com/ansible/ansible/issues/71453
bool mostPrivileges = becomeSid == "S-1-5-18";
systemToken = GetPrimaryTokenForUser(new SecurityIdentifier("S-1-5-18"),
new List<string>() { "SeTcbPrivilege" }, mostPrivileges);
if (systemToken != null)
{
try
{
TokenUtil.ImpersonateToken(systemToken);
impersonated = true;
}
catch (Process.Win32Exception) { } // We tried, just rely on current user's permissions.
}
}
// We require impersonation if becoming a service sid or becoming a user without a password
if (!impersonated && (SERVICE_SIDS.Contains(becomeSid) || String.IsNullOrEmpty(password)))
throw new Exception("Failed to get token for NT AUTHORITY\\SYSTEM required for become as a service account or an account without a password");
try
{
if (becomeSid == "S-1-5-18")
userTokens.Add(systemToken);
// Cannot use String.IsEmptyOrNull() as an empty string is an account that doesn't have a pass.
// We only use S4U if no password was defined or it was null
else if (!SERVICE_SIDS.Contains(becomeSid) && password == null && logonType != LogonType.NewCredentials)
{
// If no password was specified, try and duplicate an existing token for that user or use S4U to
// generate one without network credentials
SecurityIdentifier sid = new SecurityIdentifier(becomeSid);
SafeNativeHandle becomeToken = GetPrimaryTokenForUser(sid);
if (becomeToken != null)
{
userTokens.Add(GetElevatedToken(becomeToken));
userTokens.Add(becomeToken);
}
else
{
becomeToken = GetS4UTokenForUser(sid, logonType);
userTokens.Add(null);
userTokens.Add(becomeToken);
}
}
else
{
string domain = null;
switch (becomeSid)
{
case "S-1-5-19":
logonType = LogonType.Service;
domain = "NT AUTHORITY";
username = "LocalService";
break;
case "S-1-5-20":
logonType = LogonType.Service;
domain = "NT AUTHORITY";
username = "NetworkService";
break;
default:
// Trying to become a local or domain account
if (username.Contains(@"\"))
{
string[] userSplit = username.Split(new char[1] { '\\' }, 2);
domain = userSplit[0];
username = userSplit[1];
}
else if (!username.Contains("@"))
domain = ".";
break;
}
SafeNativeHandle hToken = TokenUtil.LogonUser(username, domain, password, logonType,
LogonProvider.Default);
// Get the elevated token for a local/domain accounts only
if (!SERVICE_SIDS.Contains(becomeSid))
userTokens.Add(GetElevatedToken(hToken));
userTokens.Add(hToken);
}
}
finally
{
if (impersonated)
TokenUtil.RevertToSelf();
}
return userTokens;
}
private static SafeNativeHandle GetPrimaryTokenForUser(SecurityIdentifier sid,
List<string> requiredPrivileges = null, bool mostPrivileges = false)
{
// According to CreateProcessWithTokenW we require a token with
// TOKEN_QUERY, TOKEN_DUPLICATE and TOKEN_ASSIGN_PRIMARY
// Also add in TOKEN_IMPERSONATE so we can get an impersonated token
TokenAccessLevels dwAccess = TokenAccessLevels.Query |
TokenAccessLevels.Duplicate |
TokenAccessLevels.AssignPrimary |
TokenAccessLevels.Impersonate;
SafeNativeHandle userToken = null;
int privilegeCount = 0;
foreach (SafeNativeHandle hToken in TokenUtil.EnumerateUserTokens(sid, dwAccess))
{
// Filter out any Network logon tokens, using become with that is useless when S4U
// can give us a Batch logon
NativeHelpers.SECURITY_LOGON_TYPE tokenLogonType = GetTokenLogonType(hToken);
if (tokenLogonType == NativeHelpers.SECURITY_LOGON_TYPE.Network)
continue;
List<string> actualPrivileges = TokenUtil.GetTokenPrivileges(hToken).Select(x => x.Name).ToList();
// If the token has less or the same number of privileges than the current token, skip it.
if (mostPrivileges && privilegeCount >= actualPrivileges.Count)
continue;
// Check that the required privileges are on the token
if (requiredPrivileges != null)
{
int missing = requiredPrivileges.Where(x => !actualPrivileges.Contains(x)).Count();
if (missing > 0)
continue;
}
// Duplicate the token to convert it to a primary token with the access level required.
try
{
userToken = TokenUtil.DuplicateToken(hToken, TokenAccessLevels.MaximumAllowed,
SecurityImpersonationLevel.Anonymous, TokenType.Primary);
privilegeCount = actualPrivileges.Count;
}
catch (Process.Win32Exception)
{
continue;
}
// If we don't care about getting the token with the most privileges, escape the loop as we already
// have a token.
if (!mostPrivileges)
break;
}
return userToken;
}
private static SafeNativeHandle GetS4UTokenForUser(SecurityIdentifier sid, LogonType logonType)
{
NTAccount becomeAccount = (NTAccount)sid.Translate(typeof(NTAccount));
string[] userSplit = becomeAccount.Value.Split(new char[1] { '\\' }, 2);
string domainName = userSplit[0];
string username = userSplit[1];
bool domainUser = domainName.ToLowerInvariant() != Environment.MachineName.ToLowerInvariant();
NativeHelpers.LSA_STRING logonProcessName = "ansible";
SafeLsaHandle lsaHandle;
IntPtr securityMode;
UInt32 res = NativeMethods.LsaRegisterLogonProcess(logonProcessName, out lsaHandle, out securityMode);
if (res != 0)
throw new Process.Win32Exception((int)NativeMethods.LsaNtStatusToWinError(res), "LsaRegisterLogonProcess() failed");
using (lsaHandle)
{
NativeHelpers.LSA_STRING packageName = domainUser ? "Kerberos" : "MICROSOFT_AUTHENTICATION_PACKAGE_V1_0";
UInt32 authPackage;
res = NativeMethods.LsaLookupAuthenticationPackage(lsaHandle, packageName, out authPackage);
if (res != 0)
throw new Process.Win32Exception((int)NativeMethods.LsaNtStatusToWinError(res),
String.Format("LsaLookupAuthenticationPackage({0}) failed", (string)packageName));
int usernameLength = username.Length * sizeof(char);
int domainLength = domainName.Length * sizeof(char);
int authInfoLength = (Marshal.SizeOf(typeof(NativeHelpers.KERB_S4U_LOGON)) + usernameLength + domainLength);
IntPtr authInfo = Marshal.AllocHGlobal((int)authInfoLength);
try
{
IntPtr usernamePtr = IntPtr.Add(authInfo, Marshal.SizeOf(typeof(NativeHelpers.KERB_S4U_LOGON)));
IntPtr domainPtr = IntPtr.Add(usernamePtr, usernameLength);
// KERB_S4U_LOGON has the same structure as MSV1_0_S4U_LOGON (local accounts)
NativeHelpers.KERB_S4U_LOGON s4uLogon = new NativeHelpers.KERB_S4U_LOGON
{
MessageType = 12, // KerbS4ULogon
Flags = 0,
ClientUpn = new NativeHelpers.LSA_UNICODE_STRING
{
Length = (UInt16)usernameLength,
MaximumLength = (UInt16)usernameLength,
Buffer = usernamePtr,
},
ClientRealm = new NativeHelpers.LSA_UNICODE_STRING
{
Length = (UInt16)domainLength,
MaximumLength = (UInt16)domainLength,
Buffer = domainPtr,
},
};
Marshal.StructureToPtr(s4uLogon, authInfo, false);
Marshal.Copy(username.ToCharArray(), 0, usernamePtr, username.Length);
Marshal.Copy(domainName.ToCharArray(), 0, domainPtr, domainName.Length);
Luid sourceLuid;
if (!NativeMethods.AllocateLocallyUniqueId(out sourceLuid))
throw new Process.Win32Exception("AllocateLocallyUniqueId() failed");
NativeHelpers.TOKEN_SOURCE tokenSource = new NativeHelpers.TOKEN_SOURCE
{
SourceName = "ansible\0".ToCharArray(),
SourceIdentifier = sourceLuid,
};
// Only Batch or Network will work with S4U, prefer Batch but use Network if asked
LogonType lsaLogonType = logonType == LogonType.Network
? LogonType.Network
: LogonType.Batch;
SafeLsaMemoryBuffer profileBuffer;
UInt32 profileBufferLength;
Luid logonId;
SafeNativeHandle hToken;
IntPtr quotas;
UInt32 subStatus;
res = NativeMethods.LsaLogonUser(lsaHandle, logonProcessName, lsaLogonType, authPackage,
authInfo, (UInt32)authInfoLength, IntPtr.Zero, tokenSource, out profileBuffer, out profileBufferLength,
out logonId, out hToken, out quotas, out subStatus);
if (res != 0)
throw new Process.Win32Exception((int)NativeMethods.LsaNtStatusToWinError(res),
String.Format("LsaLogonUser() failed with substatus {0}", subStatus));
profileBuffer.Dispose();
return hToken;
}
finally
{
Marshal.FreeHGlobal(authInfo);
}
}
}
private static SafeNativeHandle GetElevatedToken(SafeNativeHandle hToken)
{
TokenElevationType tet = TokenUtil.GetTokenElevationType(hToken);
// We already have the best token we can get, no linked token is really available.
if (tet != TokenElevationType.Limited)
return null;
SafeNativeHandle linkedToken = TokenUtil.GetTokenLinkedToken(hToken);
TokenStatistics tokenStats = TokenUtil.GetTokenStatistics(linkedToken);
// We can only use a token if it's a primary one (we had the SeTcbPrivilege set)
if (tokenStats.TokenType == TokenType.Primary)
return linkedToken;
else
return null;
}
private static NativeHelpers.SECURITY_LOGON_TYPE GetTokenLogonType(SafeNativeHandle hToken)
{
TokenStatistics stats = TokenUtil.GetTokenStatistics(hToken);
SafeLsaMemoryBuffer sessionDataPtr;
UInt32 res = NativeMethods.LsaGetLogonSessionData(ref stats.AuthenticationId, out sessionDataPtr);
if (res != 0)
// Default to Network, if we weren't able to get the actual type treat it as an error and assume
// we don't want to run a process with the token
return NativeHelpers.SECURITY_LOGON_TYPE.Network;
using (sessionDataPtr)
{
NativeHelpers.SECURITY_LOGON_SESSION_DATA sessionData = (NativeHelpers.SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(
sessionDataPtr.DangerousGetHandle(), typeof(NativeHelpers.SECURITY_LOGON_SESSION_DATA));
return sessionData.LogonType;
}
}
private static void GrantAccessToWindowStationAndDesktop(IdentityReference account)
{
GrantAccess(account, NativeMethods.GetProcessWindowStation(), WINDOWS_STATION_ALL_ACCESS);
GrantAccess(account, NativeMethods.GetThreadDesktop(NativeMethods.GetCurrentThreadId()), DESKTOP_RIGHTS_ALL_ACCESS);
}
private static void GrantAccess(IdentityReference account, NoopSafeHandle handle, int accessMask)
{
GenericSecurity security = new GenericSecurity(false, ResourceType.WindowObject, handle, AccessControlSections.Access);
security.AddAccessRule(new GenericAccessRule(account, accessMask, AccessControlType.Allow));
security.Persist(handle, AccessControlSections.Access);
}
private class GenericSecurity : NativeObjectSecurity
{
public GenericSecurity(bool isContainer, ResourceType resType, SafeHandle objectHandle, AccessControlSections sectionsRequested)
: base(isContainer, resType, objectHandle, sectionsRequested) { }
public new void Persist(SafeHandle handle, AccessControlSections includeSections) { base.Persist(handle, includeSections); }
public new void AddAccessRule(AccessRule rule) { base.AddAccessRule(rule); }
public override Type AccessRightType { get { throw new NotImplementedException(); } }
public override AccessRule AccessRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited,
InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)
{ throw new NotImplementedException(); }
public override Type AccessRuleType { get { return typeof(AccessRule); } }
public override AuditRule AuditRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited,
InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags)
{ throw new NotImplementedException(); }
public override Type AuditRuleType { get { return typeof(AuditRule); } }
}
private class GenericAccessRule : AccessRule
{
public GenericAccessRule(IdentityReference identity, int accessMask, AccessControlType type) :
base(identity, accessMask, false, InheritanceFlags.None, PropagationFlags.None, type)
{ }
}
}
}