As if you didn't have enough approaches, I put together a quick little hack
in C# that alllows for verification of the password by means of the native
function LogonUser(). I just tested it logging in to the local machine as
well as a domain. Seems to work OK. I'll post it, if you think it will help
you.
> I have tested each of these on Windows 2000,
> Windows XP, Windows 2003. But I have not found
> a solution that works for all of them consitantly.
For one of the methods, at least, this is by design.
Before XP, in order to use the LogonUser() function the owner of the calling
thread must have the SE_TCB_NAME privilege (friendly name "act as part of
the operating system"). The LocalSystem account has the privilege out of the
box but to give other accounts such an elevated privilege is scary. So,
beginning with XP, the privilege is no longer required. This _could_ be the
source of _some_ of the perceived inconsistency.
Regards,
Will
I'll look into that privilage issue on the 2000 servers that I have here.
The amusing thing is that on my 2000 servers I was only able to verify the
user name and password that I was currently using but if I entered anything
else that would not work. Really strange I know... :P This all could be
just user issues.
"William DePalo [MVP VC++]" <willd....@mvps.org> wrote in message
news:uBDTGUXC...@TK2MSFTNGP11.phx.gbl...
OK, sure.
First the disclaimer: I am a C++/Win32 kinda guy. For now, any C#/.Net I do
is strictly for fun. So I make no claim about best practices. My little hack
uses the runtime's Platform Invoke service to get at the Win32 API that I
know well. The C# wrapper class uses some "unsafe" methods.
A very quick scan of the docs seems to indicate that the WindowsIdentity
class may hold some promise and in fact be a better approach.
That said, this program prints the user name under which it is running,
tries to log in to a domain account and if successful switches the thread
context to that of a domain user. It demonstrates that by printing the name
of the user a second time. I tested it here, on Windows XP Pro/SP2, logging
in once to an account on the local machine and once to a domain account.
This is the test program:
using System;
class Class1
{
[STAThread]
static void Main(string[] args)
{
Win32User user;
Console.WriteLine("User is {0}", Win32User.getUserName() );
user = new Win32User("MyDomain", "MyUserName", "MyPassword");
if ( user.logon() )
{
Console.WriteLine("Logon succeeds, begin impersonating ...");
user.beginImpersonation();
Console.WriteLine(" ... {0}", Win32User.getUserName() );
Console.WriteLine("end impersonation, we are now ...");
user.endImpersonation();
Console.WriteLine(" ... {0}", Win32User.getUserName() );
user.logoff();
}
else
Console.WriteLine("Logon fails with error code {0}",
user.getErrorCode() );
}
}
This is the class that wraps the API functions LogonUser(),
ImpersonateLoggedOnUser(), RevertToSelf() etc
using System;
using System.Runtime.InteropServices;
public class Win32User
{
[ DllImport("advapi32.dll", SetLastError = true) ]
public unsafe static extern int LogonUser(String name, String domain,
String password,
int type, int provider, int *phandle);
[ DllImport("advapi32.dll", SetLastError = true) ]
public static extern int RevertToSelf();
[ DllImport("advapi32.dll", SetLastError = true) ]
public static extern int ImpersonateLoggedOnUser(int handle);
[ DllImport("kernel32.dll") ]
public static extern bool CloseHandle(int handle);
[ DllImport("secur32.dll", SetLastError = true) ]
public unsafe static extern int GetUserNameEx(int type, sbyte *user, int
*size);
private int handle;
private int err;
private String dom;
private String nam;
private String pwd;
public const int Interactive = 2;
public const int Batch = 4;
public const int Network = 3;
public const int Service = 5;
// Domain user
public Win32User(String domain, String name, String password)
{
dom = domain;
nam = name;
pwd = password;
handle = 0;
}
// Local machine user
public Win32User(String name, String password): this(null, name, password)
{
}
// Logs on the specified user in the specified mode
unsafe public bool logon(int typ)
{
int status;
bool ok;
if ( handle != 0 )
CloseHandle(handle);
handle = 0;
fixed ( int *ph = &handle )
{
status = LogonUser(nam, dom, pwd, typ, 0, ph);
}
ok = status != 0;
if ( ok )
err = 0;
else
err = Marshal.GetLastWin32Error();
return ok;
}
// logs on interactively
public bool logon()
{
return logon(Win32User.Interactive);
}
// logs off - call this method after logon or a handle leak results
public void logoff()
{
if ( handle != 0 )
CloseHandle(handle);
handle = 0;
}
// causes the calling thread to impersonate the logged on user;
// logon must have been called previously
public bool beginImpersonation()
{
int status;
bool ok;
if ( handle == 0 )
{
ok = false;
err = 1245;
}
else
{
status = ImpersonateLoggedOnUser(handle);
ok = status != 0;
if ( ok )
err = 0;
else
err = Marshal.GetLastWin32Error();
}
return ok;
}
// ends impersonation, reverts to self
public bool endImpersonation()
{
int status;
bool ok;
status = RevertToSelf();
ok = status != 0;
if ( ok )
err = 0;
else
err = Marshal.GetLastWin32Error();
return ok;
}
// returns a SAM compatible string describing the user context of the
calling thread
static unsafe public String getUserName()
{
int status, size;
int *psize;
String result;
sbyte[] name;
size = 1024;
psize = &size;
name = new sbyte[size];
fixed ( sbyte* pname = name )
{
status = GetUserNameEx(2, pname, psize);
if ( status == 0 )
result = null;
else
result = new String(pname, 0, size - 1);
}
return result;
}
// returns the last Win32 error code of a failed method
public int getErrorCode()
{
return err;
}
}
Regards,
Will
http://spaces.msn.com/members/staceyw/Blog/cns!1pnsZpX0fPvDxLKC6rAAhLsQ!283.entry |
"Reader" <post...@news.group> wrote in message news:uTGKBMV...@TK2MSFTNGP09.phx.gbl...