Vanara/Windows.Forms/Dialogs/AccessControlEditor/SecuredObject.cs

379 lines
12 KiB
C#
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

using System;
using System.Reflection;
using System.Security.AccessControl;
using Vanara.Extensions;
using Vanara.Extensions.Reflection;
namespace Vanara.Security.AccessControl
{
/* Derivatives of NativeObjectSecurity: (default is Group|Owner|Access)
Security Object.GetSecurityControl() V Sec Nm
=========== =========================== == === ===
System.IO.Pipes.PipeSecurity System.IO.Pipes.PipeStream 3.5 N
EventWaitHandleSecurity System.Threading.EventWaitHandle 2 N
FileSystemSecurity System.IO.DirectoryInfo, FileInfo 2 Y Name
FileSystemSecurity System.IO.FileStream 2 N Name
MutexSecurity System.Threading.Mutex 2 N
ObjectSecurity<T> 4 N
RegistrySecurity System.Win32.RegistryKey 2 Y Name
SemaphoreSecurity System.Threading.Semaphore 2 N
System.IO.MemoryMappedFiles.MemoryMappedFileSecurity System.IO.MemoryMappedFiles.MemoryMappedFile 4 N
*/
internal class SecuredObject
{
private static readonly string[] nonContainerTypes = new string[] { "FileSecurity", "PipeSecurity", "CryptoKeySecurity", "MemoryMappedFileSecurity", "TaskSecurity" };
public SecuredObject(CommonObjectSecurity security, string objName, string displayName)
{
ObjectSecurity = security;
ObjectName = objName;
DisplayName = displayName;
IsContainer = IsContainerObject(ObjectSecurity);
MandatoryLabel = new SystemMandatoryLabel(ObjectSecurity);
}
/// <summary>Initializes with the specified known object.</summary>
/// <param name="knownObject">The known object. See Remarks section for acceptable object types.</param>
/// <remarks>
/// Known objects can include:
/// <list type="bullet">
/// <item><description>System.IO.Pipes.PipeStream</description></item>
/// <item><description><see cref="System.Threading.EventWaitHandle"/></description></item>
/// <item><description><see cref="System.IO.DirectoryInfo"/></description></item>
/// <item><description><see cref="System.IO.FileInfo"/></description></item>
/// <item><description><see cref="System.IO.FileStream"/></description></item>
/// <item><description><see cref="System.Threading.Mutex"/></description></item>
/// <item><description>System.Win32.RegistryKey</description></item>
/// <item><description><see cref="System.Threading.Semaphore"/></description></item>
/// <item><description>System.IO.MemoryMappedFiles.MemoryMappedFile</description></item>
/// <item><description><see cref="System.Security.AccessControl.CommonObjectSecurity"/> or derived class. <c>Note:</c> When using this option, be sure to
/// set the <see cref="IsContainer"/>, <see cref="ResourceType"/>, <see cref="ObjectName"/>, and <see cref="TargetServer"/> properties.</description></item>
/// <item><description>Any object that supports the following methods and properties:
/// <list type="bullet"><item><description><code>GetAccessControl()</code> or <code>GetAccessControl(AccessControlSections)</code> method</description></item>
/// <item><description><code>SetAccessControl(CommonObjectSecurity)</code> method</description></item>
/// <item><description><code>Name</code> or <code>FullName</code> property</description></item>
/// </list>
/// </description></item>
/// </list>
/// </remarks>
public SecuredObject(object knownObject)
{
// Special handling for Tasks
if (knownObject.GetType().FullName == "Microsoft.Win32.TaskScheduler.Task" || knownObject.GetType().FullName == "Microsoft.Win32.TaskScheduler.TaskFolder")
{
IsContainer = knownObject.GetType().Name == "TaskFolder";
TargetServer = knownObject.GetPropertyValue<object>("TaskService").GetPropertyValue<string>("TargetServer");
}
// Get the security object using the standard "GetAccessControl" method
try
{
ObjectSecurity = knownObject.InvokeMethod<CommonObjectSecurity>("GetAccessControl", AccessControlSections.All);
}
catch (TargetInvocationException)
{
try
{
ObjectSecurity = knownObject.InvokeMethod<CommonObjectSecurity>("GetAccessControl",
AccessControlSections.Access | AccessControlSections.Group | AccessControlSections.Owner);
}
catch { }
}
catch { }
if (ObjectSecurity == null)
{
try
{
ObjectSecurity = knownObject.InvokeMethod<CommonObjectSecurity>("GetAccessControl");
}
catch { }
}
if (ObjectSecurity == null)
throw new ArgumentException("Object must be valid and have a GetAccessControl member.");
// Get the object names
switch (knownObject.GetType().Name)
{
case "RegistryKey":
ObjectName = knownObject.GetPropertyValue<string>("Name");
DisplayName = System.IO.Path.GetFileNameWithoutExtension(ObjectName);
break;
case "Task":
DisplayName = knownObject.GetPropertyValue<string>("Name");
ObjectName = knownObject.GetPropertyValue<string>("Path");
break;
default:
ObjectName = knownObject.GetPropertyValue<string>("FullName");
DisplayName = knownObject.GetPropertyValue<string>("Name");
if (ObjectName == null) ObjectName = DisplayName;
break;
}
// Set the base object
BaseObject = knownObject;
IsContainer = IsContainerObject(ObjectSecurity);
MandatoryLabel = new SystemMandatoryLabel(ObjectSecurity);
}
public enum SystemMandatoryLabelLevel
{
None = 0,
Low = 0x1000,
Medium = 0x2000,
High = 0x3000
}
[Flags]
public enum SystemMandatoryLabelPolicy
{
None = 0,
NoWriteUp = 1,
NoReadUp = 2,
NoExecuteUp = 4
}
public object BaseObject { get; }
public string DisplayName { get; set; }
public bool IsContainer { get; set; }
public SystemMandatoryLabel MandatoryLabel { get; }
public string ObjectName { get; set; }
public CommonObjectSecurity ObjectSecurity { get; }
public ResourceType ResourceType => GetResourceType(ObjectSecurity);
public string TargetServer { get; set; }
public static object GetAccessMask(CommonObjectSecurity acl, AuthorizationRule rule)
{
if (rule.GetType() == acl.AccessRuleType || rule.GetType() == acl.AuditRuleType)
{
var accRightType = acl.AccessRightType;
foreach (var pi in rule.GetType().GetProperties())
if (pi.PropertyType == accRightType)
return Enum.ToObject(accRightType, pi.GetValue(rule, null));
}
throw new ArgumentException();
}
public static object GetKnownObject(ResourceType resType, string objName, string serverName)
{
object obj = null;
switch (resType)
{
case ResourceType.FileObject:
if (!string.IsNullOrEmpty(serverName))
objName = System.IO.Path.Combine(serverName, objName);
if (System.IO.File.Exists(objName))
obj = new System.IO.FileInfo(objName);
else if (System.IO.Directory.Exists(objName))
obj = new System.IO.DirectoryInfo(objName);
break;
case ResourceType.RegistryKey:
obj = GetKeyFromKeyName(objName, serverName);
break;
case Windows.Forms.AccessControlEditorDialog.taskResourceType:
obj = GetTaskObj(objName, serverName);
break;
}
if (obj == null)
throw new ArgumentException("Unable to create an object from supplied arguments.");
return obj;
}
public static ResourceType GetResourceType(CommonObjectSecurity sec)
{
switch (sec.GetType().Name)
{
case "FileSecurity":
case "DirectorySecurity":
case "CryptoKeySecurity":
return ResourceType.FileObject;
case "PipeSecurity":
case "EventWaitHandleSecurity":
case "MutexSecurity":
case "MemoryMappedFileSecurity":
case "SemaphoreSecurity":
return ResourceType.KernelObject;
case "RegistrySecurity":
return ResourceType.RegistryKey;
case "TaskSecurity":
return Windows.Forms.AccessControlEditorDialog.taskResourceType;
}
return ResourceType.Unknown;
}
public static bool IsContainerObject(CommonObjectSecurity sec)
{
var secTypeName = sec.GetType().Name;
return !Array.Exists(nonContainerTypes, s => secTypeName == s);
}
public object GetAccessMask(AuthorizationRule rule) => GetAccessMask(ObjectSecurity, rule);
public void Persist(object newBase = null)
{
var obj = newBase ?? BaseObject;
if (obj == null)
throw new ArgumentNullException(nameof(newBase), @"Either newBase or BaseObject must not be null.");
var mi = obj.GetType().GetMethod("SetAccessControl", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
if (mi == null)
throw new InvalidOperationException("Either newBase or BaseObject must represent a securable object.");
mi.Invoke(obj, new object[] { ObjectSecurity });
}
private static Microsoft.Win32.RegistryKey GetKeyFromKeyName(string keyName, string serverName)
{
if (keyName == null)
return null;
var index = keyName.IndexOf('\\');
var str = index != -1 ? keyName.Substring(0, index).ToUpper(System.Globalization.CultureInfo.InvariantCulture) : keyName.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
Microsoft.Win32.RegistryHive hive;
switch (str)
{
case "HKEY_CURRENT_USER":
hive = Microsoft.Win32.RegistryHive.CurrentUser;
break;
case "HKEY_LOCAL_MACHINE":
hive = Microsoft.Win32.RegistryHive.LocalMachine;
break;
case "HKEY_CLASSES_ROOT":
hive = Microsoft.Win32.RegistryHive.ClassesRoot;
break;
case "HKEY_USERS":
hive = Microsoft.Win32.RegistryHive.Users;
break;
case "HKEY_PERFORMANCE_DATA":
hive = Microsoft.Win32.RegistryHive.PerformanceData;
break;
case "HKEY_CURRENT_CONFIG":
hive = Microsoft.Win32.RegistryHive.CurrentConfig;
break;
default:
return null;
}
if (serverName == null)
serverName = string.Empty;
var retVal = Microsoft.Win32.RegistryKey.OpenRemoteBaseKey(hive, serverName);
if ((index == -1) || (index == keyName.Length))
return retVal;
var subKeyName = keyName.Substring(index + 1, (keyName.Length - index) - 1);
return retVal.OpenSubKey(subKeyName);
}
private static object GetTaskObj(string objName, string serverName)
{
try
{
var tsType = Vanara.Extensions.ReflectionExtensions.LoadType("Microsoft.Win32.TaskScheduler.TaskService", "Microsoft.Win32.TaskScheduler.dll") ??
Vanara.Extensions.ReflectionExtensions.LoadType("Microsoft.Win32.TaskScheduler.TaskService", "Microsoft.Win32.TaskScheduler-Merged.dll");
if (tsType != null)
{
var ts = Activator.CreateInstance(tsType, serverName, null, null, null, false);
if (ts != null)
{
try
{
var r = ts.InvokeMethod<object>("GetFolder", objName);
if (r != null)
return r;
}
catch { }
try
{
var r = ts.InvokeMethod<object>("GetTask", objName);
if (r != null)
return r;
}
catch { }
try
{
var r = ts.InvokeMethod<object>("FindTask", objName, true);
if (r != null)
return r;
}
catch { }
}
}
}
catch { }
return null;
}
public class SystemMandatoryLabel
{
public SystemMandatoryLabel(CommonObjectSecurity sec)
{
Policy = SystemMandatoryLabelPolicy.None;
Level = SystemMandatoryLabelLevel.None;
try
{
var sd = new RawSecurityDescriptor(sec.GetSecurityDescriptorBinaryForm(), 0);
if (sd.SystemAcl != null)
{
foreach (var ace in sd.SystemAcl)
{
if ((int)ace.AceType == 0x11)
{
var aceBytes = new byte[ace.BinaryLength];
ace.GetBinaryForm(aceBytes, 0);
//_policy = new IntegrityPolicy(aceBytes, 4);
//_level = new IntegrityLevel(aceBytes, 8);
}
}
}
}
catch { }
/*byte[] saclBinaryForm = new byte[sd.SystemAcl.BinaryLength];
sd.SystemAcl.GetBinaryForm(saclBinaryForm, 0);
GenericAce ace = null;
if (null != saclBinaryForm)
{
RawAcl aclRaw = new RawAcl(saclBinaryForm, 0);
if (0 >= aclRaw.Count) throw new ArgumentException("No ACEs in ACL", "saclBinaryForm");
ace = aclRaw[0];
if (Win32.SYSTEM_MANDATORY_LABEL_ACE_TYPE != (int)ace.AceType)
throw new ArgumentException("No Mandatory Integrity Label in ACL", "saclBinaryForm");
byte[] aceBytes = new byte[ace.BinaryLength];
ace.GetBinaryForm(aceBytes, 0);
_policy = new IntegrityPolicy(aceBytes, 4);
_level = new IntegrityLevel(aceBytes, 8);
return;
}
throw new ArgumentNullException("saclBinaryForm");*/
}
public bool IsSet => Policy != SystemMandatoryLabelPolicy.None && Level != SystemMandatoryLabelLevel.None;
public SystemMandatoryLabelLevel Level { get; }
public SystemMandatoryLabelPolicy Policy { get; }
}
}
}