4

My app will be used on LAN on a client desktop computer. In this LAN, there is one dedicated Windows 2k server. There is no AD.

The user have to fill in a server's user account informations so the app can then do some remote operations with this account (Map network drives)

How can I check the user credentials against this server?

When mapping drivers, I will have the error if the user account authentication is not ok, but I would like to have this information before trying to map.

Something like LogonUser API function, but working on a remote computer.

Thanks,

Fred
  • 1,607
  • 20
  • 33

2 Answers2

3

I use the unit SSPIValidatePassword.pas from http://www.michael-puff.de/Programmierung/Delphi/Units/ which does the job right for me. The only exported function in that unit SSPLogonUser returns true or false....

mrabat
  • 802
  • 7
  • 15
  • Thanks, but I can't figure a way to make it works. I tried with an other implementation (http://delphi-kb.blogspot.fr/2010/07/logonuser-win-api-call-vs-sspi-call.html) and I can't make it works either with a domain controller, or a workgroup server – Fred Nov 26 '12 at 13:26
  • +1 for the SSPI solution! SSPI is the preferred way of validating credentials under Windows, as Microsoft suggests: http://support.microsoft.com/kb/180548; Also good reading: http://stackoverflow.com/questions/7111618/win32-how-to-validate-credentials-against-active-directory – iPath ツ Nov 26 '12 at 19:02
  • @Fred, the SSPI implementation is Ansi based, but in Delphi >= 2009 "string" type is unicode - may be this is why the code isn't working? – iPath ツ Nov 26 '12 at 19:22
  • @Fred, in fact SSPIValidatePassword.pas compiles and runs as expected under Delphi 7. So it's about PAnsiChar / PWideChar and unicode string type in Delphi >= 2009 – iPath ツ Nov 26 '12 at 19:56
  • Thanks for the comment, I agree with you that using SSPI is the right way to do it but I can't find a way to make it works. I compiled a test sample under D7. On a test network, I have 2 pc in the same workgroup, an XP client, and a 2k server. On the server I have an admin account. With this test sample, It always return false, but with the same credentials, i can mount network drives or connect to the server – Fred Nov 27 '12 at 13:47
3

You can use the WNetUseConnection function with CONNECT_INTERACTIVE and CONNECT_PROMPT flags. That will in combination with empty user ID and password parameters invoke the credentials dialog and connect to a network resource when you enter correct credentials:

procedure TForm1.Button1Click(Sender: TObject);
var
  BufferSize: DWORD;
  ResultFlag: DWORD;
  NetResource: TNetResource;
begin
  NetResource.dwType := RESOURCETYPE_DISK;
  NetResource.lpLocalName := nil;
  NetResource.lpRemoteName := '\\MySuperSecret\Place';
  NetResource.lpProvider := nil;
  if WNetUseConnection(Handle, NetResource, nil, nil, CONNECT_INTERACTIVE or
    CONNECT_PROMPT, nil, BufferSize, ResultFlag) = NO_ERROR
  then
    ShowMessage('Connected!');
end;

To connect to a network resource without prompting for credentials remove the flags specified above as it's shown in the following function, which should return True, when the connection succeed, False when it fails. Here's the parameter description:

  • RemoteName (string) - remote network name
  • UserName (string) - user name used to connect to a network resource
  • Password (string) - password used to connect to a network resource

function TryConnect(const RemoteName, UserName, Password: string): Boolean;
var
  BufferSize: DWORD;
  ResultFlag: DWORD;
  NetResource: TNetResource;
begin
  NetResource.dwType := RESOURCETYPE_DISK;
  NetResource.lpLocalName := nil;
  NetResource.lpRemoteName := PChar(RemoteName);
  NetResource.lpProvider := nil;
  Result := WNetUseConnection(0, NetResource, PChar(UserName), PChar(Password),
    0, nil, BufferSize, ResultFlag) = NO_ERROR;
end;
TLama
  • 75,147
  • 17
  • 214
  • 392
  • Thanks, I was aware of this way to do the job. The thing is that my app is a sort of a setup app, credentials are asked at beginning and then, after several setup style pages, it tries to silently map network resources with provided credentials. I am looking for a way to check the credentials at start – Fred Nov 26 '12 at 13:25
  • Then you can try to remove those flags. The first one, the `CONNECT_INTERACTIVE` specifies that *operating system may interact with the user for authentication purposes*, so now it should cover your needs. – TLama Nov 26 '12 at 13:58
  • Thanks for your input, I have implemented your solution – Fred Nov 28 '12 at 16:35
  • Just a last thing : I figured out that in case of Result := True, I have to do WNetCancelConnection2(PChar(FRemoteLocation), 0, True); to avoid bad results. In case of a first try ok, and then I unplug network cable and I retry, Result was still True See: http://stackoverflow.com/questions/2296918/calling-wnetaddconnection2-with-empty-local-name – Fred Nov 29 '12 at 10:59