1

A program running on computer "A" wants to download a file "F" in map "M" from computer "B". I use the following preparaions:

  dlgSelectImportFile.InitialDir := '\\192.168.1.59';
  dlgSelectImportFile.Options :=[ofOldStyleDialog];

As computer "B" wants authorization I get the Windows-Security-dialog. I want to avoid this by giving the correct username and password automatically. I guess there is something in the API of this dialog that could help here but I have not found anything.

larand
  • 773
  • 1
  • 9
  • 26

1 Answers1

1

You can store the credentials in the Credential Vault, here is some sample code (uses Jedi Apilib):

procedure StoreCredentials(const Server: String; const Username: String; const Password: String);
var
  CredTargetInfo: CREDENTIAL_TARGET_INFORMATION;
  Creds: CREDENTIAL;
  CredType: DWORD;
  bRes: Boolean;
  LastError: DWORD;
begin
  CredType := CRED_TYPE_DOMAIN_PASSWORD;

  ZeroMemory(@CredTargetInfo, sizeof(CredTargetInfo));
  CredTargetInfo.TargetName := PChar(Server);
  CredTargetInfo.CredTypeCount := 1;
  CredTargetInfo.CredTypes := @CredType;

  ZeroMemory(@Creds, sizeof(Creds));
  Creds.TargetName := PChar(Server);
  Creds.Type_ := CRED_TYPE_DOMAIN_PASSWORD;
  Creds.CredentialBlobSize := ByteLength(Password);
  Creds.CredentialBlob := PByte(PChar(Password));
  Creds.UserName := PChar(Username);
  Creds.Persist := CRED_PERSIST_ENTERPRISE;

  bRes := CredWriteDomainCredentials(@CredTargetInfo,@Creds, 0);
  if bRes then
  begin
    DbgOut('Successfully stored %s Credentials for %s', [Username, Server]);
  end
  else begin
    LastError := GetLastError;
    DbgOut('CredWriteDomainCredentials failed with %d (%s)', [LastError, SysErrorMessage(LastError)]);
  end;
end;

Here's an example how to delete stored credentials:

procedure DeleteCredentials;
var
  Count: DWORD;
  Creds: PPCredentialArray;
  i: Cardinal;
  bRes: Boolean;
begin
  DbgOut('Deleting Old Credentials');
  if not CredEnumerate(nil, 0, Count, PCREDENTIAL(Creds)) then
    Exit;

  DbgOut('Found %d old credentials', [Count]);

  try
    for i := Count-1 downto 0 do
    begin

      bRes := CredDelete(Creds^[i]^.TargetName, Creds^[i]^.Type_, 0);
      DbgOut('Deleting credential %d (%s to %s) returned %s', [i, Creds^[i]^.UserName, Creds^[i]^.TargetName, BoolToStr(bRes, True)]);
    end;

  finally
    CredFree(Creds);
  end;
end;

Note: the sample code is copy/pasted off an old project so things like DbgOut can simply be removed. The sample code was for a case where an Active Directory domain was used, it might need some changes for non domain situation.

Remko
  • 7,214
  • 2
  • 32
  • 52
  • `PByte` and `PChar` indicate the ANSI version being used (*A), so usernames and passwords beyond ASCII might fail and the *W versions should be used then, if not even right away. – AmigoJack Oct 09 '19 at 11:34
  • The cast to PByte is because the `CredentialBlob` member of the `CREDENTIAL` structure is of type `LPBYTE` (see https://learn.microsoft.com/en-us/windows/win32/api/wincred/ns-wincred-credentialw). `PChar` maps to `PWideChar` on Unicode versions of Delphi. The code was used with Delphi 2010 (thus Unicode) but should compile/work on non Unicode versions as well... – Remko Oct 10 '19 at 07:28