private void ToggleState(bool enable) { int error = 0; // // All privilege operations must take place on the same thread // if (!this.currentThread.Equals(Thread.CurrentThread)) { throw new InvalidOperationException("Operation must take place on the thread that created the object"); } // // This privilege was already altered and needs to be reverted before it can be altered again // if (this.NeedToRevert) { throw new InvalidOperationException("Must revert the privilege prior to attempting this operation"); } // // Need to make this block of code non-interruptible so that it would preserve // consistency of thread oken state even in the face of catastrophic exceptions // RuntimeHelpers.PrepareConstrainedRegions(); try { // // The payload is entirely in the finally block // This is how we ensure that the code will not be // interrupted by catastrophic exceptions // } finally { try { // // Retrieve TLS state // this.tlsContents = Thread.GetData(tlsSlot) as TlsContents; if (this.tlsContents == null) { this.tlsContents = new TlsContents(); Thread.SetData(tlsSlot, this.tlsContents); } else { this.tlsContents.IncrementReferenceCount(); } NativeMethods.TOKEN_PRIVILEGE newState = new NativeMethods.TOKEN_PRIVILEGE(); newState.PrivilegeCount = 1; newState.Privilege.Luid = this.luid; newState.Privilege.Attributes = enable ? NativeMethods.SE_PRIVILEGE_ENABLED : NativeMethods.SE_PRIVILEGE_DISABLED; NativeMethods.TOKEN_PRIVILEGE previousState = new NativeMethods.TOKEN_PRIVILEGE(); uint previousSize = 0; // // Place the new privilege on the thread token and remember the previous state. // if (false == NativeMethods.AdjustTokenPrivileges( this.tlsContents.ThreadHandle, false, ref newState, ( uint )Marshal.SizeOf(previousState), ref previousState, ref previousSize)) { error = Marshal.GetLastWin32Error(); } else if (NativeMethods.ERROR_NOT_ALL_ASSIGNED == Marshal.GetLastWin32Error()) { error = NativeMethods.ERROR_NOT_ALL_ASSIGNED; } else { // // This is the initial state that revert will have to go back to // this.initialState = ((previousState.Privilege.Attributes & NativeMethods.SE_PRIVILEGE_ENABLED) != 0); // // Remember whether state has changed at all // this.stateWasChanged = (this.initialState != enable); // // If we had to impersonate, or if the privilege state changed we'll need to revert // this.needToRevert = this.tlsContents.IsImpersonating || this.stateWasChanged; } } finally { if (!this.needToRevert) { this.Reset(); } } } if (error == NativeMethods.ERROR_NOT_ALL_ASSIGNED) { throw new PrivilegeNotHeldException(privileges[this.luid] as string); } if (error == NativeMethods.ERROR_NOT_ENOUGH_MEMORY) { throw new OutOfMemoryException(); } else if (error == NativeMethods.ERROR_ACCESS_DENIED || error == NativeMethods.ERROR_CANT_OPEN_ANONYMOUS) { throw new UnauthorizedAccessException("The caller does not have the right to change the privilege"); } else if (error != 0) { throw new Win32Exception(error); } }
public void Revert() { int error = 0; // // All privilege operations must take place on the same thread // if (!this.currentThread.Equals(Thread.CurrentThread)) { throw new InvalidOperationException("Operation must take place on the thread that created the object"); } if (!this.NeedToRevert) { return; } // // This code must be eagerly prepared and non-interruptible. // RuntimeHelpers.PrepareConstrainedRegions(); try { // // The payload is entirely in the finally block // This is how we ensure that the code will not be // interrupted by catastrophic exceptions // } finally { bool success = true; try { // // Only call AdjustTokenPrivileges if we're not going to be reverting to self, // on this Revert, since doing the latter obliterates the thread token anyway // if (this.stateWasChanged && (this.tlsContents.ReferenceCountValue > 1 || !this.tlsContents.IsImpersonating)) { NativeMethods.TOKEN_PRIVILEGE newState = new NativeMethods.TOKEN_PRIVILEGE(); newState.PrivilegeCount = 1; newState.Privilege.Luid = this.luid; newState.Privilege.Attributes = (this.initialState ? NativeMethods.SE_PRIVILEGE_ENABLED : NativeMethods.SE_PRIVILEGE_DISABLED); NativeMethods.TOKEN_PRIVILEGE previousState = new NativeMethods.TOKEN_PRIVILEGE(); uint previousSize = 0; if (false == NativeMethods.AdjustTokenPrivileges( this.tlsContents.ThreadHandle, false, ref newState, ( uint )Marshal.SizeOf(previousState), ref previousState, ref previousSize)) { error = Marshal.GetLastWin32Error(); success = false; } } } finally { if (success) { this.Reset(); } } } if (error == NativeMethods.ERROR_NOT_ENOUGH_MEMORY) { throw new OutOfMemoryException(); } else if (error == NativeMethods.ERROR_ACCESS_DENIED) { throw new UnauthorizedAccessException("Caller does not have the permission to change the privilege"); } else if (error != 0) { throw new Win32Exception(error); } }