LogonUser issues

G

Guest

Having a few strage behaviours with this function, mainly in that when I try
to logon to another computer with a different name/pass to the current user
of the local machine, it tries to impersonate me, not the credentials I gave
it.

LogonUser succeeds only when using LOGON32_LOGON_NEW_CREDENTIALS (9). Any
other LogonType causes error 126: Specified module could not be found -
whatever that means...

The initial WindowsIdentity.GetCurrent() reveals "DELLWING\Trent" as the
user, which is my local account. Upon success of LogonUser I create a new
WindowsIdentity with the received token. Printing out the details reveals
"DELLWING\Trent" as the user, even though I supplied "Administrator" and the
password of the remote box. I then get "Unable to Impersonate User" when
trying Impersonate().

Why would the token come back represent me when I specified a whole nother
user and computer?

My code looks like this currently (thanks to Willy Denoyette).
-----------------------
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;

namespace SecurityTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class SecurityTest
{
[DllImport("advapi32.DLL")]
public static extern int LogonUser(string lpszUsername, string lpszDomain,
string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr
phToken);

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
IntPtr admin_token;

// This works fine
WindowsIdentity wid_current = WindowsIdentity.GetCurrent();
Console.WriteLine("Current Name: " + wid_current.Name);
Console.WriteLine("Current Token: " + wid_current.Token);

if (LogonUser("Administrator", "192.168.0.5", "password", 9, 0, out
admin_token) != 0)
{
WindowsIdentity wid_admin = new WindowsIdentity(admin_token);
Console.WriteLine("Remote Name: " + wid_admin.Name);
Console.WriteLine("Remote Token: " + wid_admin.Token);


WindowsImpersonationContext wic = null;
try
{
wic = wid_admin.Impersonate();
// Always get an exception here after Impersonate

System.IO.File.Copy("C:\\test_read\\test.txt",
"\\\\192.168.0.5\\trent\\test.txt", true);

}
catch (System.Exception se)
{
Console.WriteLine(se.Message);
}
finally
{
if (wic != null) wic.Undo();
}
}
else
{
int ret = Marshal.GetLastWin32Error();
Console.WriteLine(ret.ToString(), "Error");
}
}
}
 
W

Willy Denoyette [MVP]

BLiTZWiNG said:
Having a few strage behaviours with this function, mainly in that when I
try
to logon to another computer with a different name/pass to the current
user
of the local machine, it tries to impersonate me, not the credentials I
gave
it.

LogonUser succeeds only when using LOGON32_LOGON_NEW_CREDENTIALS (9). Any
other LogonType causes error 126: Specified module could not be found -
whatever that means...

The initial WindowsIdentity.GetCurrent() reveals "DELLWING\Trent" as the
user, which is my local account. Upon success of LogonUser I create a new
WindowsIdentity with the received token. Printing out the details reveals
"DELLWING\Trent" as the user, even though I supplied "Administrator" and
the
password of the remote box. I then get "Unable to Impersonate User" when
trying Impersonate().

Why would the token come back represent me when I specified a whole nother
user and computer?

My code looks like this currently (thanks to Willy Denoyette).
-----------------------
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;

namespace SecurityTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class SecurityTest
{
[DllImport("advapi32.DLL")]
public static extern int LogonUser(string lpszUsername, string lpszDomain,
string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr
phToken);

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
IntPtr admin_token;

// This works fine
WindowsIdentity wid_current = WindowsIdentity.GetCurrent();
Console.WriteLine("Current Name: " + wid_current.Name);
Console.WriteLine("Current Token: " + wid_current.Token);

if (LogonUser("Administrator", "192.168.0.5", "password", 9, 0, out
admin_token) != 0)
{
WindowsIdentity wid_admin = new WindowsIdentity(admin_token);
Console.WriteLine("Remote Name: " + wid_admin.Name);
Console.WriteLine("Remote Token: " + wid_admin.Token);


WindowsImpersonationContext wic = null;
try
{
wic = wid_admin.Impersonate();
// Always get an exception here after Impersonate

System.IO.File.Copy("C:\\test_read\\test.txt",
"\\\\192.168.0.5\\trent\\test.txt", true);

}
catch (System.Exception se)
{
Console.WriteLine(se.Message);
}
finally
{
if (wic != null) wic.Undo();
}
}
else
{
int ret = Marshal.GetLastWin32Error();
Console.WriteLine(ret.ToString(), "Error");
}
}
}

A few remarks:
LogonUser returns or a "direct" token or an "impersonation" token. A direct
token kan be used to impersonate, an impersonation token cannot and will
return an error.
Both LOGON32_LOGON_NEW_CREDENTIALS (9) and LOGON32_LOGON_NETWORK_CLEARTEXT
Logontypes returns a direct token, but LOGON32_LOGON_NETWORK does not.

Why the error 126? The reason is that the original error code is lost in the
call chain. To prevent this you should add SetLastError=true in the
DllImport.

[DllImport("advapi32.DLL"), SetLastError=true]

Why is the local identity still the same, simply because logontype 9 returns
a clone of the current token but also creates a hidden secondary token.
The clone will be used to access local resources while the secondary token
will ONLY be used when accessing remote resources.

Logontype 9 requires a "negotiate" logon provider (W2K or higher), when
running on W2K the default however is NTLM, so it's better to specify
LOGON32_PROVIDER_WINNT50 (5) a logon provider to make sure negotiate is used
in all cases.

if (LogonUser("Administrator", "192.168.0.5", "password", 9, 5, out
admin_token) != 0)

Willy.
 
G

Guest

Thanks again Willy. I will try what you have suggested here.

However note that I used unmanaged function ImpersonateLoggedOnUser and
succeeded with the copy, so I at least have a solution. I'm not sure if there
are downsides to that way though. I am still going to persist with the
managed way.

Also note that the 2k3 server I'm trying to copy to is now suffering UserEnv
errors 1058 (unable to save group policy object) :/ I can see there is a fix
for it but I have to discuss it with my boss.

Willy Denoyette said:
BLiTZWiNG said:
Having a few strage behaviours with this function, mainly in that when I
try
to logon to another computer with a different name/pass to the current
user
of the local machine, it tries to impersonate me, not the credentials I
gave
it.

LogonUser succeeds only when using LOGON32_LOGON_NEW_CREDENTIALS (9). Any
other LogonType causes error 126: Specified module could not be found -
whatever that means...

The initial WindowsIdentity.GetCurrent() reveals "DELLWING\Trent" as the
user, which is my local account. Upon success of LogonUser I create a new
WindowsIdentity with the received token. Printing out the details reveals
"DELLWING\Trent" as the user, even though I supplied "Administrator" and
the
password of the remote box. I then get "Unable to Impersonate User" when
trying Impersonate().

Why would the token come back represent me when I specified a whole nother
user and computer?

My code looks like this currently (thanks to Willy Denoyette).
-----------------------
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;

namespace SecurityTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class SecurityTest
{
[DllImport("advapi32.DLL")]
public static extern int LogonUser(string lpszUsername, string lpszDomain,
string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr
phToken);

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
IntPtr admin_token;

// This works fine
WindowsIdentity wid_current = WindowsIdentity.GetCurrent();
Console.WriteLine("Current Name: " + wid_current.Name);
Console.WriteLine("Current Token: " + wid_current.Token);

if (LogonUser("Administrator", "192.168.0.5", "password", 9, 0, out
admin_token) != 0)
{
WindowsIdentity wid_admin = new WindowsIdentity(admin_token);
Console.WriteLine("Remote Name: " + wid_admin.Name);
Console.WriteLine("Remote Token: " + wid_admin.Token);


WindowsImpersonationContext wic = null;
try
{
wic = wid_admin.Impersonate();
// Always get an exception here after Impersonate

System.IO.File.Copy("C:\\test_read\\test.txt",
"\\\\192.168.0.5\\trent\\test.txt", true);

}
catch (System.Exception se)
{
Console.WriteLine(se.Message);
}
finally
{
if (wic != null) wic.Undo();
}
}
else
{
int ret = Marshal.GetLastWin32Error();
Console.WriteLine(ret.ToString(), "Error");
}
}
}

A few remarks:
LogonUser returns or a "direct" token or an "impersonation" token. A direct
token kan be used to impersonate, an impersonation token cannot and will
return an error.
Both LOGON32_LOGON_NEW_CREDENTIALS (9) and LOGON32_LOGON_NETWORK_CLEARTEXT
Logontypes returns a direct token, but LOGON32_LOGON_NETWORK does not.

Why the error 126? The reason is that the original error code is lost in the
call chain. To prevent this you should add SetLastError=true in the
DllImport.

[DllImport("advapi32.DLL"), SetLastError=true]

Why is the local identity still the same, simply because logontype 9 returns
a clone of the current token but also creates a hidden secondary token.
The clone will be used to access local resources while the secondary token
will ONLY be used when accessing remote resources.

Logontype 9 requires a "negotiate" logon provider (W2K or higher), when
running on W2K the default however is NTLM, so it's better to specify
LOGON32_PROVIDER_WINNT50 (5) a logon provider to make sure negotiate is used
in all cases.

if (LogonUser("Administrator", "192.168.0.5", "password", 9, 5, out
admin_token) != 0)

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top