Is there some series of flags that will allow LogonUser
to return a token useable for impersonation of a local user when the computer is NOT connected to a network (but all accounts already exist locally).
I have the domain account executing the app
MYDOMAIN\FooUser
and I'm trying to get an impersonation token for
MYLAPTOP\TestUser
Then I read a series of text files in a folder which all can be read by FooUser
, but some have the read privilege denied for TestUser
.
If I login to Windows and run the app from TestUser
the privileges map correctly and permissions are denied on the files. If I'm connected to my domain and run the app from FooUser
I can also impersonate TestUser
and the file permissions again properly deny access as expected (using LOGON32_LOGON_INTERACTIVE
).
The problem occurs when my Ethernet cable is unplugged and I try to call LogonUser
for TestUser
and I expected that I'd be able to somehow validate local credentials... locally?
Using LOGON32_LOGON_INTERACTIVE
:
- Entering credentials for
TestUser
returns error indicating "Bad username or password"
- Entering credentials for
FooUser
returns error indicating "No logon servers available" (makes sense, I'm not complaining... except how did I sign into Windows in the first place when not connected to my domain?)
Using LOGON32_LOGON_NEW_CREDENTIALS
:
- Entering gibberish credentials returns a token that appears to have the same access as
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);
}
}