using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Security.Principal;
namespace ZeroLevel.Services.Impersonation
{
///
/// Класс реализует перевод исполнения программы на права указанного пользователя
///
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class Impersonation : IDisposable
{
WindowsImpersonationContext impersonationContext;
#region Private methods
///
/// Назначение текущему процессу прав от указанного процесса, путем копирования его токена
///
/// Указатель на процесс
private void ImpersonateByProcess(IntPtr hProcess)
{
MySafeTokenHandle token;
if (!ImpersonationNativeMethods.OpenProcessToken(hProcess, ImpersonationNativeMethods.TokenDesiredAccess.TOKEN_DUPLICATE, out token))
throw new ApplicationException("Не удалось получить токен процесса. Win32 код ошибки: " + Marshal.GetLastWin32Error());
ImpersonateToken(token);
}
///
/// Метод назначает текущему процессу дубликат переданного токена
///
/// Токен
private void ImpersonateToken(MySafeTokenHandle token)
{
MySafeTokenHandle tokenDuplicate;
WindowsIdentity tempWindowsIdentity;
using (token)
{
if (ImpersonationNativeMethods.DuplicateToken(token, (int)ImpersonationNativeMethods.SecurityImpersonationLevel.SecurityImpersonation, out tokenDuplicate) != 0)
{
using (tokenDuplicate)
{
if (!tokenDuplicate.IsInvalid)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate.DangerousGetHandle());
impersonationContext = tempWindowsIdentity.Impersonate();
return;
}
}
}
else
throw new Exception("Не удалось создать дубликат указанного токена. Win32 код ошибки: " + Marshal.GetLastWin32Error());
}
}
#endregion
#region Public methods
///
/// Вход от имени указанного пользователя
///
/// Имя пользователя
/// Домен
/// Пароль
/// false - если не удалось выполнить вход по указанным данным
public void ImpersonateByUser(String userName, String domain, String password)
{
MySafeTokenHandle token;
if (ImpersonationNativeMethods.LogonUserA(userName, domain, password, (int)ImpersonationNativeMethods.LogonType.LOGON32_LOGON_INTERACTIVE, (int)ImpersonationNativeMethods.LogonProvider.LOGON32_PROVIDER_DEFAULT, out token) != 0)
{
ImpersonateToken(token);
}
else
{
throw new Exception("LogonUser failed: " + Marshal.GetLastWin32Error().ToString());
}
}
///
/// Вход от имени указанного пользователя с указанием способа авторизации
///
/// Имя пользователя
/// Домен
/// Пароль
/// Тип авторизации
public void ImpersonateByUser(String userName, String domain, String password, ImpersonationNativeMethods.LogonType logonType)
{
MySafeTokenHandle token;
if (ImpersonationNativeMethods.LogonUserA(userName, domain, password, (int)logonType, (int)ImpersonationNativeMethods.LogonProvider.LOGON32_PROVIDER_DEFAULT, out token) != 0)
{
ImpersonateToken(token);
}
else
{
throw new Exception("LogonUser failed: " + Marshal.GetLastWin32Error().ToString());
}
}
///
/// Копирование прав указанного процесса
///
/// Имя процесса
public void ImpersonateByProcess(string ProcessName)
{
Process[] myProcesses = Process.GetProcesses();
foreach (Process currentProcess in myProcesses)
{
if (currentProcess.ProcessName.Equals(ProcessName, StringComparison.OrdinalIgnoreCase))
{
ImpersonateByProcess(currentProcess.Handle);
break;
}
}
}
///
/// Копирование прав указанного процесса
///
/// Идентификатор процесса
public void ImpersonateByProcess(int ProcessID)
{
Process[] myProcesses = Process.GetProcesses();
foreach (Process currentProcess in myProcesses)
{
if (currentProcess.Id == ProcessID)
{
ImpersonateByProcess(currentProcess.Handle);
break;
}
}
}
#endregion
///
/// При освобождении рессурсов вернем предыдущего пользователя
///
public void Dispose()
{
impersonationContext?.Undo();
impersonationContext?.Dispose();
GC.SuppressFinalize(this);
}
}
}