通过WindowsIdentity模拟当前计算机

时间:2009-10-22 06:00:27

标签: .net security impersonation

我正在尝试获取当前用户登录的计算机帐户的WindowsIdentity。

目前,我使用以下代码获取当前用户的组成员资格:

WindowsIdentity currentIdent = WindowsIdentity.GetCurrent();
foreach (IdentityReference indentity in currentGroups)
{
  String groupName = indentity.Translate(typeof(NTAccount)).ToString();
}

这很好用,但我也需要对当前的计算机帐户执行相同操作,最好不要查询AD。

我相信我必须使用模仿来做这件事,但却无法找到方法。

1 个答案:

答案 0 :(得分:1)

本地计算机上有两个具有其域帐户组成员身份的位置:domain \ computer $的用户令牌和域\ computer $的Kerberos票证。每当本地计算机需要其用户令牌时,它将被设置为SYSTEM,而不是domain \ computer $,因此这不是一个选项。从domain \ computer $ Kerberos票证获取用户令牌的唯一方法是以SYSTEM身份运行,因为您需要其密钥来解密票证(同样,您需要将Act作为操作系统权限的一部分,甚至然后我不知道如何从票证中创建令牌。

所以,你必须查询AD:

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
using System.Security.Principal;
using System.ComponentModel;
using System.DirectoryServices;

public static SecurityIdentifier[] GetLocalComputerGroups()
{
    string sAMAccountName = PInvoke.GetSYSTEMsAMAccountName();
    DirectorySearcher searcher = new DirectorySearcher("(sAMAccountName=" + sAMAccountName + ")");
    DirectoryEntry entry = searcher.FindOne().GetDirectoryEntry();
    entry.RefreshCache(new string[] { "tokenGroups" });
    List<SecurityIdentifier> groupSids = new List<SecurityIdentifier>();
    foreach(byte[] byteSid in entry.Properties["tokenGroups"])
    {
        groupSids.Add(new SecurityIdentifier(byteSid, 0));
    }
    return groupSids.ToArray();
}

public class PInvoke
{
    public const int STATUS_SUCCESS = 0;
    public static readonly IntPtr NULL = IntPtr.Zero;

    public enum SECURITY_LOGON_TYPE
    {
        UndefinedLogonType = 0,
        Interactive = 2,
        Network,
        Batch,
        Service,
        Proxy,
        Unlock,
        NetworkCleartext,
        NewCredentials,
        RemoteInteractive,
        CachedInteractive,
        CachedRemoteInteractive,
        CachedUnlock
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LARGE_INTEGER
    {
        public uint LowPart;
        public int HighPart;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LUID
    {
        public uint LowPart;
        public int HighPart;

        public static LUID GetSYSTEMLuid()
        {
            return new LUID() { LowPart = 0x3E7, HighPart = 0 };
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LSA_UNICODE_STRING
    {
        public ushort Length;
        public ushort MaximumLength;
        public IntPtr Buffer;

        public override string ToString()
        {
            if (Buffer == NULL) return null;
            return Marshal.PtrToStringUni(Buffer, Length / UnicodeEncoding.CharSize);
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_LOGON_SESSION_DATA
    {
        public uint Size;
        public LUID LogonId;
        public LSA_UNICODE_STRING UserName;
        public LSA_UNICODE_STRING LogonDomain;
        public LSA_UNICODE_STRING AuthenticationPackage;
        public SECURITY_LOGON_TYPE LogonType;
        public uint Session;
        public IntPtr Sid;
        public LARGE_INTEGER LogonTime;
        public LSA_UNICODE_STRING LogonServer;
        public LSA_UNICODE_STRING DnsDomainName;
        public LSA_UNICODE_STRING Upn;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_LOGON_SESSION_Managed
    {
        public LUID LogonId;
        public string UserName;
        public string LogonDomain;
        public string AuthenticationPackage;
        public SECURITY_LOGON_TYPE LogonType;
        public uint Session;
        public SecurityIdentifier Sid;
        public LARGE_INTEGER LogonTime;
        public string LogonServer;
        public string DnsDomainName;
        public string Upn;

        public SECURITY_LOGON_SESSION_DATA_Managed(IntPtr pSecurityLogonSessionData)
        {
            SECURITY_LOGON_SESSION_DATA data = (SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(pSecurityLogonSessionData, typeof(SECURITY_LOGON_SESSION_DATA));
            this.LogonId = data.LogonId;
            this.UserName = data.UserName.ToString();
            this.LogonDomain = data.LogonDomain.ToString();
            this.AuthenticationPackage = data.AuthenticationPackage.ToString();
            this.LogonType = data.LogonType;
            this.Session = data.Session;
            this.Sid = new SecurityIdentifier(ConvertPSIDToString(data.Sid));
            this.LogonTime = data.LogonTime;
            this.LogonServer = data.LogonServer.ToString();
            this.DnsDomainName = data.DnsDomainName.ToString();
            this.Upn = data.Upn.ToString();
        }
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr LocalFree(IntPtr hMem);

    [DllImport("advapi32.dll", SetLastError = true)]
    protected static extern bool ConvertSidToStringSidW(IntPtr Sid, out IntPtr StringSid);

    public static string ConvertPSIDToString(IntPtr pSid)
    {
        IntPtr pString;
        if (ConvertSidToStringSidW(pSid, out pString))
        {
            try
            {
                return Marshal.PtrToStringUni(pString);
            }
            finally
            {
                LocalFree(pString);
            }
        }
        else
        {
            throw new Win32Exception();
        }
    }

    [DllImport("advapi32.dll")]
    protected static extern int LsaNtStatusToWinError(uint Status);

    public static Win32Exception NtStatusToWinException(uint ntstatus)
    {
        return new Win32Exception(LsaNtStatusToWinError(ntstatus);
    }

    [DllImport("secur32.dll")]
    public static extern uint LsaFreeReturnBuffer(IntPtr Buffer);

    [DllImport("secur32.dll")]
    protected static extern uint LsaGetLogonSessionData(ref LUID LogonId, out IntPtr ppLogonSessionData);

    public static SECURITY_LOGON_SESSION_DATA_Managed GetLogonSessionData(LUID logonId)
    {
        IntPtr pLogonSessionData;
        uint ntstatus = LsaGetLogonSessionData(ref logonId, out pLogonSessionData);
        if(ntstatus != STATUS_SUCCESS)
        {
            throw NtStatusToWinException(ntstatus);
        }

        try
        {
            return new SECURITY_LOGON_SESSION_DATA_Managed(pLogonSessionData);
        }
        finally
        {
            LsaFreeReturnBuffer(pLogonSessionData);
        }
    }

    public static string GetSYSTEMsAMAccountName()
    {
        LUID systemLuid = LUID.GetSYSTEMLuid();
        SECURITY_LOGON_SESSION_DATA_Managed systemData = GetLogonSessionData(systemLuid);
        return systemData.UserName;
    }
}