TokenPrivilegeHelper.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.Security;
  4. namespace Optimizer
  5. {
  6. /*
  7. * Allows clients to obtain a Windows token privilege for a well-defined scope simply by "using" an instance of this class.
  8. */
  9. sealed class TokenPrivilegeHelper : IDisposable
  10. {
  11. private enum PrivilegeAction : uint
  12. {
  13. Disable = 0x0,
  14. Enable = 0x2
  15. }
  16. public static TokenPrivilegeHelper Backup => new TokenPrivilegeHelper("SeBackupPrivilege");
  17. public static TokenPrivilegeHelper Restore => new TokenPrivilegeHelper("SeRestorePrivilege");
  18. public static TokenPrivilegeHelper TakeOwnership => new TokenPrivilegeHelper("SeTakeOwnershipPrivilege");
  19. private readonly string privilegeName;
  20. private TokenPrivilegeHelper(string privilegeName)
  21. {
  22. this.privilegeName = privilegeName;
  23. Apply(PrivilegeAction.Enable);
  24. }
  25. private void Apply(PrivilegeAction action)
  26. {
  27. OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out IntPtr tokenHandle);
  28. LookupPrivilegeValue(null, privilegeName, out Luid luid);
  29. var tokenPrivilege = new TokenPrivileges(luid, (uint)action);
  30. UpdateTokenPrivileges(tokenHandle, tokenPrivilege);
  31. }
  32. private void UpdateTokenPrivileges(IntPtr tokenHandle, TokenPrivileges privilegeInfo)
  33. {
  34. bool successful = AdjustTokenPrivileges(tokenHandle, false, ref privilegeInfo, 0, IntPtr.Zero, IntPtr.Zero);
  35. if (!successful || Marshal.GetLastWin32Error() == ERROR_NOT_ALL_ASSIGNED)
  36. throw new SecurityException($"Can't adjust token privilege {privilegeName}");
  37. }
  38. public void Dispose()
  39. {
  40. Apply(PrivilegeAction.Disable);
  41. }
  42. #region P/Invoke structs and methods
  43. private const int ERROR_NOT_ALL_ASSIGNED = 1300;
  44. [StructLayout(LayoutKind.Sequential)]
  45. private struct TokenPrivileges
  46. {
  47. // We can use this struct only with one privilege since CLR doesn't support marshalling dynamic-sized arrays
  48. public TokenPrivileges(Luid luid, uint attributes)
  49. {
  50. Count = 1;
  51. Privileges = new[] {
  52. new LuidAndAttributes(luid, attributes)
  53. };
  54. }
  55. private uint Count;
  56. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
  57. private LuidAndAttributes[] Privileges;
  58. }
  59. [StructLayout(LayoutKind.Sequential)]
  60. private readonly struct LuidAndAttributes
  61. {
  62. public LuidAndAttributes(Luid luid, uint attributes)
  63. {
  64. Luid = luid;
  65. Attributes = attributes;
  66. }
  67. private readonly Luid Luid;
  68. private readonly uint Attributes;
  69. }
  70. [StructLayout(LayoutKind.Sequential)]
  71. private readonly struct Luid
  72. {
  73. private readonly uint LowPart;
  74. private readonly int HighPart;
  75. }
  76. private const int TOKEN_QUERY = 0x8;
  77. private const int TOKEN_ADJUST_PRIVILEGES = 0x20;
  78. [DllImport("advapi32.dll", SetLastError = true)]
  79. private static extern bool AdjustTokenPrivileges(IntPtr tokenHandle,
  80. bool disableAllPrivileges,
  81. ref TokenPrivileges newState,
  82. int bufferLength,
  83. IntPtr previousState,
  84. IntPtr returnLength);
  85. [DllImport("kernel32.dll")]
  86. private static extern IntPtr GetCurrentProcess();
  87. [DllImport("advapi32.dll", SetLastError = true)]
  88. private static extern bool OpenProcessToken(IntPtr processHandle, int desiredAccess, out IntPtr tokenHandle);
  89. [DllImport("advapi32.dll", SetLastError = true)]
  90. private static extern bool LookupPrivilegeValue(string systemName, string privilegeName, out Luid privilegeLuid);
  91. #endregion
  92. }
  93. }