Win32 API LogonUser离线访问本地帐户

本文关键字:访问 API LogonUser 离线 Win32 | 更新日期: 2023-09-27 18:03:17

是否有一些标志系列允许LogonUser返回可用于模拟本地用户的令牌,当计算机未连接到网络时(但所有帐户已在本地存在)

我有执行应用程序的域帐户

MYDOMAIN ' FooUser

和我试图获得一个模拟令牌

MYLAPTOP ' TestUser

然后我读取一个文件夹中的一系列文本文件,这些文件都可以被FooUser读取,但有些文件具有TestUser拒绝的读取权限。

如果我登录到Windows并从TestUser运行应用程序,特权映射正确,权限在文件上被拒绝。如果我连接到我的域并从FooUser运行应用程序,我也可以模拟TestUser和文件权限再次正确地拒绝访问,如预期的(使用LOGON32_LOGON_INTERACTIVE)。

问题发生时,我的以太网电缆拔掉,我试图调用LogonUser TestUser,我希望我能够以某种方式验证本地凭据…在本地吗?

使用LOGON32_LOGON_INTERACTIVE:

  • 输入TestUser的凭据返回"错误的用户名或密码"错误
  • 输入FooUser的凭据返回错误指示"没有登录服务器可用"(有意义,我不是抱怨…除了当我没有连接到我的域时,我是如何登录到Windows的?)

使用LOGON32_LOGON_NEW_CREDENTIALS:

  • 输入乱码凭证返回一个看起来与FooUser具有相同访问权限的令牌
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using Common.NativeMethods.Enumerations;
namespace Common.NativeMethods
{
    public static class AdvApi32
    {
        // http://www.pinvoke.net/default.aspx/advapi32.logonuser
        // http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.securestringtoglobalallocunicode(v=vs.100).aspx
        // PInvoke into the Win32 API to provide access to the  
        // LogonUser and CloseHandle functions.
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern bool LogonUser(
            IntPtr username,
            IntPtr domain,
            IntPtr password,
            LogonType logonType,
            LogonProvider logonProvider,
            ref IntPtr token
        );
        public static WindowsIdentity LogonUser(SecureString p_userName, SecureString p_password, SecureString p_domainName)
        {
            IntPtr UserAccountToken = IntPtr.Zero;
            IntPtr UserNamePointer = IntPtr.Zero;
            IntPtr PasswordPointer = IntPtr.Zero;
            IntPtr DomainNamePointer = IntPtr.Zero;
            try
            {
                // Marshal the SecureString to unmanaged memory.
                UserNamePointer = Marshal.SecureStringToGlobalAllocUnicode(p_password);
                PasswordPointer = Marshal.SecureStringToGlobalAllocUnicode(p_userName);
                DomainNamePointer = Marshal.SecureStringToGlobalAllocUnicode(p_domainName);
                // Call LogonUser, passing the unmanaged (and decrypted) copy of the SecureString password.
                bool ReturnValue =
                    AdvApi32
                        .LogonUser(
                            UserNamePointer,
                            DomainNamePointer,
                            PasswordPointer,
                            LogonType.LOGON32_LOGON_INTERACTIVE, //.LOGON32_LOGON_NEW_CREDENTIALS,
                            LogonProvider.LOGON32_PROVIDER_DEFAULT, //.LOGON32_PROVIDER_WINNT50,
                            ref UserAccountToken);
                // Get the Last win32 Error and throw an exception. 
                if (!ReturnValue && UserAccountToken == IntPtr.Zero)
                {
                    int error = Marshal.GetLastWin32Error();
                    throw
                        new Win32Exception(error);
                }
                // The token that is passed to the following constructor must  
                // be a primary token in order to use it for impersonation.
                return
                    new WindowsIdentity(UserAccountToken);
            }
            finally
            {
                // Zero-out and free the unmanaged string reference.
                Marshal.ZeroFreeGlobalAllocUnicode(UserNamePointer);
                Marshal.ZeroFreeGlobalAllocUnicode(PasswordPointer);
                Marshal.ZeroFreeGlobalAllocUnicode(DomainNamePointer);
                // Close the token handle.
                Kernel32.CloseHandle(UserAccountToken);
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.ConstrainedExecution;
using System.Security;
namespace Common.NativeMethods
{
    // http://msdn.microsoft.com/en-us/library/system.security.principal.windowsimpersonationcontext%28v=vs.100%29.aspx
    public static class Kernel32
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal extern static bool CloseHandle(IntPtr handle);
    }
}

Win32 API LogonUser离线访问本地帐户

哎呀…我在重构的时候打错字了。LogonUser工作只是很好,没有连接到域;如果你指向正确的参数,至少。

 UserNamePointer = Marshal.SecureStringToGlobalAllocUnicode(p_password);
 PasswordPointer = Marshal.SecureStringToGlobalAllocUnicode(p_userName);

固定
 UserNamePointer = Marshal.SecureStringToGlobalAllocUnicode(p_userName);
 PasswordPointer = Marshal.SecureStringToGlobalAllocUnicode(p_password);