using System; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Linq; using Vanara.PInvoke; using static Vanara.PInvoke.AdvApi32; namespace Vanara.Security.AccessControl { /// Privilege determining the type of system operations that can be performed. [TypeConverter(typeof(SystemPrivilegeTypeConverter))] public enum SystemPrivilege { /// Required to logon interactively. InteractiveLogon = 0x00000001, /// Required for an account to log on using the network logon type. NetworkLogon = 0x00000002, /// Required for an account to log on using the batch logon type. BatchLogon = 0x00000004, /// Required for an account to log on using the service logon type. ServiceLogon = 0x00000010, /// Explicitly denies an account the right to log on using the interactive logon type. DenyInteractiveLogon = 0x00000040, /// Explicitly denies an account the right to log on using the network logon type. DenyNetworkLogon = 0x00000080, /// Explicitly denies an account the right to log on using the batch logon type. DenyBatchLogon = 0x00000100, /// Explicitly denies an account the right to log on using the service logon type. DenyServiceLogon = 0x00000200, /// Remote interactive logon RemoteInteractiveLogon = 0x00000400, /// Explicitly denies an account the right to log on remotely using the interactive logon type. DenyRemoteInteractiveLogon = 0x00000800, /// Privilege to replace a process-level token. AssignPrimaryToken = 0x00001000, /// Privilege to generate security audits. Audit, /// Privilege to backup files and directories. Backup, /// Privilege to bypass traverse checking. ChangeNotify, /// Privilege to create global objects. CreateGlobal, /// Privilege to create a pagefile. CreatePageFile, /// Privilege to create permanent shared objects. CreatePermanent, /// Privilege to create symbolic links. CreateSymbolicLink, /// Privilege to create a token object. CreateToken, /// Privilege to debug programs. Debug, /// Privilege to delegate session using user impersonation. DelegateSessionUserImpersonate, /// Privilege to enable computer and user accounts to be trusted for delegation. EnableDelegation, /// Privilege to impersonate a client after authentication. Impersonate, /// Privilege to increase scheduling priority. IncreaseBasePriority, /// Privilege to adjust memory quotas for a process. IncreaseQuota, /// Privilege to increase a process working set. IncreaseWorkingSet, /// Privilege to load and unload device drivers. LoadDriver, /// Privilege to lock pages in memory. LockMemory, /// Privilege to add workstations to domain. MachineAccount, /// Privilege to manage the files on a volume. ManageVolume, /// Privilege to profile single process. ProfileSingleProcess, /// Privilege to modify an object label. Relabel, /// Privilege to force shutdown from a remote system. RemoteShutdown, /// Privilege to restore files and directories. Restore, /// Privilege to manage auditing and security log. Security, /// Privilege to shut down the system. Shutdown, /// Privilege to synchronize directory service data. SyncAgent, /// Privilege to modify firmware environment values. SystemEnvironment, /// Privilege to profile system performance. SystemProfile, /// Privilege to change the system time. SystemTime, /// Privilege to take ownership of files or other objects. TakeOwnership, /// Privilege to act as part of the operating system. TrustedComputerBase, /// Privilege to change the time zone. TimeZone, /// Privilege to access Credential Manager as a trusted caller. TrustedCredentialManagerAccess, /// Privilege to remove computer from docking station. Undock, /// Privilege to read unsolicited input from a terminal device. UnsolicitedInput } /// Extension methods for for working with privileges. public static class PrivilegeExtension { /// Adjusts a specified privilege on a security token to have the supplied attributes. /// The security token object. /// The privilege to adjust. /// The attribute to change. /// The privious privileges. public static TOKEN_PRIVILEGES AdjustPrivilege(this SafeHTOKEN hObj, SystemPrivilege priv, PrivilegeAttributes attr) => AdjustPrivileges(hObj, new TOKEN_PRIVILEGES(priv.GetLUID(), attr)); /// Adjusts the specified privileges on a security token to have the supplied attributes. /// The security token object. /// The privileges to change. /// The privious privileges. public static TOKEN_PRIVILEGES AdjustPrivileges(this SafeHTOKEN hObj, params PrivilegeAndAttributes[] privileges) { if (privileges == null || privileges.Length == 0) throw new ArgumentNullException(nameof(privileges)); return AdjustPrivileges(hObj, new TOKEN_PRIVILEGES(privileges.Select(pa => new LUID_AND_ATTRIBUTES(pa.Privilege.GetLUID(), pa.Attributes)).ToArray())); } /// Adjusts the specified privileges on a security token to have the supplied attributes. /// The security token object. /// The privileges to change. /// The privious privileges. public static TOKEN_PRIVILEGES AdjustPrivileges(this SafeHTOKEN hObj, in TOKEN_PRIVILEGES privileges) { AdjustTokenPrivileges(hObj, false, privileges, out var ret).ThrowIfFailed(); return ret; } /// Gets the for this . /// The system privilege to lookup. /// /// Name of the system on which to check for the LUID value. A will use the local system. /// /// The associated LUID. public static LUID GetLUID(this SystemPrivilege systemPrivilege, string systemName = null) => SystemPrivilegeTypeConverter.GetLUID(systemPrivilege, systemName); /// Gets the value for this . /// The luid. /// /// Name of the system on which to check for the LUID value. A will use the local system. /// /// The associated . public static SystemPrivilege GetPrivilege(this LUID luid, string systemName = null) => SystemPrivilegeTypeConverter.GetPrivilege(luid, systemName); /// Enumerates all the privileges held by a security token. /// The security token object. /// A sequence of held privileges. public static IEnumerable GetPrivileges(this SafeHTOKEN hObj) => hObj.GetInfo(TOKEN_INFORMATION_CLASS.TokenPrivileges).Privileges; /// Determines whether the specified security token has a privilege. /// The security token object. /// The privilege to assess. /// if the specified token has the supplied privilege; otherwise, . public static bool HasPrivilege(this SafeHTOKEN hObj, SystemPrivilege priv) => HasPrivileges(hObj, true, priv); /// Determines whether the specified security token has multiple privileges. /// The security token object. /// /// if set to this method will only return if all supplied privileges all held. /// /// The privileges to check. /// if the specified token has the supplied privileges; otherwise, . public static bool HasPrivileges(this SafeHTOKEN hObj, bool requireAll, params SystemPrivilege[] privs) { if (!PrivilegeCheck(hObj, new PRIVILEGE_SET((PrivilegeSetControl)(requireAll ? 1 : 0), privs.Select(p => new LUID_AND_ATTRIBUTES(p.GetLUID(), PrivilegeAttributes.SE_PRIVILEGE_ENABLED)).ToArray()), out var ret)) Win32Error.ThrowLastError(); return ret; } } internal class SystemPrivilegeTypeConverter : TypeConverter { internal static readonly Dictionary PrivLookup = new Dictionary(35) { { SystemPrivilege.AssignPrimaryToken, "SeAssignPrimaryTokenPrivilege" }, { SystemPrivilege.Audit, "SeAuditPrivilege" }, { SystemPrivilege.Backup, "SeBackupPrivilege" }, { SystemPrivilege.ChangeNotify, "SeChangeNotifyPrivilege" }, { SystemPrivilege.CreateGlobal, "SeCreateGlobalPrivilege" }, { SystemPrivilege.CreatePageFile, "SeCreatePagefilePrivilege" }, { SystemPrivilege.CreatePermanent, "SeCreatePermanentPrivilege" }, { SystemPrivilege.CreateSymbolicLink, "SeCreateSymbolicLinkPrivilege" }, { SystemPrivilege.CreateToken, "SeCreateTokenPrivilege" }, { SystemPrivilege.Debug, "SeDebugPrivilege" }, { SystemPrivilege.DelegateSessionUserImpersonate, "SeDelegateSessionUserImpersonatePrivilege" }, { SystemPrivilege.EnableDelegation, "SeEnableDelegationPrivilege" }, { SystemPrivilege.Impersonate, "SeImpersonatePrivilege" }, { SystemPrivilege.IncreaseBasePriority, "SeIncreaseBasePriorityPrivilege" }, { SystemPrivilege.IncreaseQuota, "SeIncreaseQuotaPrivilege" }, { SystemPrivilege.IncreaseWorkingSet, "SeIncreaseWorkingSetPrivilege" }, { SystemPrivilege.LoadDriver, "SeLoadDriverPrivilege" }, { SystemPrivilege.LockMemory, "SeLockMemoryPrivilege" }, { SystemPrivilege.MachineAccount, "SeMachineAccountPrivilege" }, { SystemPrivilege.ManageVolume, "SeManageVolumePrivilege" }, { SystemPrivilege.ProfileSingleProcess, "SeProfileSingleProcessPrivilege" }, { SystemPrivilege.Relabel, "SeRelabelPrivilege" }, { SystemPrivilege.RemoteShutdown, "SeRemoteShutdownPrivilege" }, { SystemPrivilege.Restore, "SeRestorePrivilege" }, { SystemPrivilege.Security, "SeSecurityPrivilege" }, { SystemPrivilege.Shutdown, "SeShutdownPrivilege" }, { SystemPrivilege.SyncAgent, "SeSyncAgentPrivilege" }, { SystemPrivilege.SystemEnvironment, "SeSystemEnvironmentPrivilege" }, { SystemPrivilege.SystemProfile, "SeSystemProfilePrivilege" }, { SystemPrivilege.SystemTime, "SeSystemTimePrivilege" }, { SystemPrivilege.TakeOwnership, "SeTakeOwnershipPrivilege" }, { SystemPrivilege.TrustedComputerBase, "SeTcbPrivilege" }, { SystemPrivilege.TimeZone, "SeTimeZonePrivilege" }, { SystemPrivilege.TrustedCredentialManagerAccess, "SeTrustedCredManAccessPrivilege" }, { SystemPrivilege.Undock, "SeUndockPrivilege" }, { SystemPrivilege.UnsolicitedInput, "SeUnsolicitedInputPrivilege" }, { SystemPrivilege.InteractiveLogon, "SeInteractiveLogonRight" }, { SystemPrivilege.NetworkLogon, "SeNetworkLogonRight" }, { SystemPrivilege.BatchLogon, "SeBatchLogonRight" }, { SystemPrivilege.ServiceLogon, "SeServiceLogonRight" }, { SystemPrivilege.DenyInteractiveLogon, "SeDenyInteractiveLogonRight" }, { SystemPrivilege.DenyNetworkLogon, "SeDenyNetworkLogonRight" }, { SystemPrivilege.DenyBatchLogon, "SeDenyBatchLogonRight" }, { SystemPrivilege.DenyServiceLogon, "SeDenyServiceLogonRight" }, { SystemPrivilege.RemoteInteractiveLogon, "SeRemoteInteractiveLogonRight" }, { SystemPrivilege.DenyRemoteInteractiveLogon, "SeDenyRemoteInteractiveLogonRight" }, }; private static readonly Dictionary luidLookup = new Dictionary(); public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => sourceType == typeof(string) || sourceType == typeof(LUID) || base.CanConvertFrom(context, sourceType); public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) => destinationType == typeof(string) || destinationType == typeof(LUID) || base.CanConvertTo(context, destinationType); public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value is string s) { try { var val = (SystemPrivilege)Enum.Parse(typeof(SystemPrivilege), s, true); return val; } catch { } try { return ConvertKnownString(s); } catch { } } if (value is LUID luid) return GetPrivilege(luid); return base.ConvertFrom(context, culture, value); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string)) return PrivLookup[(SystemPrivilege)value]; if (destinationType == typeof(LUID)) return GetLUID((SystemPrivilege)value); return base.ConvertTo(context, culture, value, destinationType); } internal static SystemPrivilege ConvertKnownString(string s) { try { return PrivLookup.First(v => string.Equals(s, v.Value, StringComparison.OrdinalIgnoreCase)).Key; } catch { throw new ArgumentOutOfRangeException(nameof(s), "Unrecognized privilege string."); } } internal static LUID GetLUID(SystemPrivilege systemPrivilege, string systemName = null) { LUID val; lock (luidLookup) { if (!luidLookup.TryGetValue(systemPrivilege, out val)) { val = LUID.FromName(PrivLookup[systemPrivilege], systemName); luidLookup.Add(systemPrivilege, val); } } return val; } internal static SystemPrivilege GetPrivilege(LUID luid, string systemName = null) => ConvertKnownString(luid.GetName(systemName)); } }