Edit: I modified the code according to Andrei Galatyn's comment and hints that I shall not rely on token being nil when invalid, but it's still not working for PC's that are not part of the domain.
I want to verify if a user entered a username/password combination that is valid in a LDAP server.
Currently I use this code:
function CheckWinUserAccount(Username, Password, Domain : string) : boolean;
var token: THandle;
begin
result:=False;
if LogonUser( PChar(Username), PChar(Domain), PChar(Password),
LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, token) then
begin
CloseHandle(token);
result:=True;
end;
end;
It works perfectly if executed on a PC that is part of the LDAP domain, but not on a PC that only uses the LDAP PC as DNS but is not part of the domain.
My data:
- Domain: graz.local
- Username: LDTest
I tried entering the username as LDTest
, as graz\LDTest
and as graz.local\LDTest
.
I also tried specifying the domain as graz
, graz.local
, ldap://graz.local
None of that worked. Any idea?
Btw: I was not sure if this is possible at all (accessing the domain server from a non-domain-PC), but using the LDAP Administrator (by Softerra) this works.
As noted by Andrei Galatyn use LOGON32_LOGON_NETWORK instead of
LOGON32_LOGON_INTERACTIVE when calling "LogonUser". The username
should not include the domain name, the domain name can either be the
NetBIOS domain name ("graz") or the DNS domain name ("graz.local").
EDIT: Using "LogonUser" only works if the client has already established a connection to the domain.
Here is the code which performs the authentication using LDAP.
{$APPTYPE CONSOLE}
uses
SysUtils,
Windows,
JwaWinLDAP,
JwaRpcDce;
var
sUsername, sDomain, sPassword, sDC : String;
LDAP : PLDAP;
SWAI : SEC_WINNT_AUTH_IDENTITY;
begin
if (ParamCount <> 4) then
begin
WriteLn ('WinLdapTest [username] [domain] [password] [domain controller]');
Halt (1);
end; { if }
sUsername := ParamStr (1);
sDomain := ParamStr (2);
sPassword := ParamStr (3);
sDC := ParamStr (4);
LDAP := ldap_openW (PChar (sDC), LDAP_PORT);
if (Assigned (LDAP)) then
try
SWAI.User := PChar (sUserName);
SWAI.UserLength := Length (sUserName);
SWAI.Domain := PChar (sDomain);
SWAI.DomainLength := Length (sDomain);
SWAI.Password := PChar (sPassword);
SWAI.PasswordLength := Length (sPassword);
SWAI.Flags := SEC_WINNT_AUTH_IDENTITY_UNICODE;
if (ldap_bind_sW (LDAP, PChar (sDC), PChar (@SWAI),
LDAP_AUTH_NTLM) = LDAP_SUCCESS) then
WriteLN ('"ldap_bind" success')
else WriteLN ('"ldap_bind" failure');
finally
ldap_unbind (LDAP);
end { try / finally }
else WriteLn ('"ldap_open" failed');
end.
The code uses the JEDI API library and assumes that you're using Delphi 2009 or higher (Unicode strings). To automatically retrieve the DC name you could call DsGetDcName.