You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

122 lines
3.9 KiB

using System;
using System.Runtime.InteropServices;
namespace Microsoft.Win32.Security
{
using DWORD = UInt32;
using BOOL = Int32;
/// <summary>
/// Encapsulation of a Win32 token handle.
/// The object is disposable because it maintains the Win32 handle.
/// </summary>
public abstract class AccessToken : DisposableObject
{
/// The win32 token handle.
private IntPtr _handle;
protected internal AccessToken(IntPtr handle)
{
_handle = handle;
}
protected override void Dispose(bool disposing)
{
if (_handle != IntPtr.Zero)
{
// We don't want to throw an exception here, because there's not
// much we can do when failing to close a handle.
BOOL rc = Win32.CloseHandle(_handle);
if (rc != Win32.FALSE)
_handle = IntPtr.Zero;
}
}
/// <summary>
/// Enable a single privilege on the process.
/// </summary>
/// <param name="privilege"></param>
/// <exception cref="">Throws an exception if the privilege is not present
/// in the privilege list of the process</exception>
public void EnablePrivilege(TokenPrivilege privilege)
{
var privs = new TokenPrivileges {privilege};
EnableDisablePrivileges(privs);
}
private void EnableDisablePrivileges(TokenPrivileges privileges)
{
UnsafeEnableDisablePrivileges(privileges);
}
private unsafe void UnsafeEnableDisablePrivileges(TokenPrivileges privileges)
{
byte[] privBytes = privileges.GetNativeTokenPrivileges();
fixed (byte* priv = privBytes)
{
UInt32 cbLength;
Win32.SetLastError(Win32.SUCCESS);
BOOL rc = Win32.AdjustTokenPrivileges(
_handle,
Win32.FALSE,
(IntPtr) priv,
0,
IntPtr.Zero,
out cbLength);
Win32.CheckCall(rc);
// Additional check: privilege can't be added, and in that case,
// rc indicates a success, but GetLastError() has a specific meaning.
if (Marshal.GetLastWin32Error() == Win32.ERROR_NOT_ALL_ASSIGNED)
Win32.ThrowLastError();
}
}
}
/// <summary>
/// Access token for a process
/// </summary>
public class AccessTokenProcess : AccessToken
{
public AccessTokenProcess(int pid, TokenAccessType desiredAccess)
: base(OpenProcessToken(pid, desiredAccess))
{
}
private static IntPtr TryOpenProcessToken(int pid, TokenAccessType desiredAccess)
{
IntPtr processHandle = Win32.OpenProcess(
ProcessAccessType.PROCESS_QUERY_INFORMATION,
Win32.FALSE,
(uint) pid);
if (processHandle == IntPtr.Zero)
return IntPtr.Zero;
Win32.CheckCall(processHandle);
try
{
IntPtr handle;
BOOL rc = Win32.OpenProcessToken(processHandle, desiredAccess, out handle);
if (rc == Win32.FALSE)
return IntPtr.Zero;
return handle;
}
finally
{
Win32.CloseHandle(processHandle);
}
}
private static IntPtr OpenProcessToken(int pid, TokenAccessType desiredAccess)
{
IntPtr handle = TryOpenProcessToken(pid, desiredAccess);
if (handle == IntPtr.Zero)
Win32.ThrowLastError();
return handle;
}
}
}