TokenPrivilegeHelper.cs 4.1 KB

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