Issue Details (XML | Word | Printable)

Key: CORE-5376
Type: Bug Bug
Status: Open Open
Priority: Major Major
Assignee: Unassigned
Reporter: Dimitry Sibiryakov
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
Firebird Core

New API example crashes

Created: 14/Oct/16 01:58 PM   Updated: 21/Nov/16 03:12 PM
Component/s: API / Client Library
Affects Version/s: 3.0.1
Fix Version/s: None

Environment: Windows, Delphi 2006, Firebird 3.0.1

QA Status: No test


 Description  « Hide
Example 01.create.pas crashes on run because master.getUtilInterface returns nil.

 All   Comments   Change History   Subversion Commits      Sort Order: Ascending order - Click to sort in descending order
Alexander Peshkov added a comment - 14/Oct/16 02:11 PM
Not reproduced on fpc:

# fpc -Fu../../src/include/gen/ -Mdelphi 01.create.pas
Free Pascal Compiler version 2.6.4 [2014/11/16] for x86_64
Copyright (c) 1993-2014 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling 01.create.pas
Compiling /usr/home/firebird/B3_0_Release/src/include/gen/Firebird.pas
Linking 01.create
13224 lines compiled, 1.4 sec
localhost interfaces # ./01.create
Database fbtests.fdb created
Re-attached database fbtests.fdb
Table dates_table created
Record inserted into dates_table
localhost interfaces #

Afraid I hurried a bit trying to help with win-specific issue

Dimitry Sibiryakov added a comment - 14/Oct/16 03:20 PM
Yes, with FPC 3.0.0 it works. The issue should be related to Delphi.

Boris Vinkler added a comment - 20/Oct/16 06:12 AM
I wrote the code below in Delphi XE 3 (the code is written from the example "01.create.pas").
When I want to open an allready encrypted database by passing the encryption key via my application then the application freezes at line "att := prov.attachDatabase(st, 'fbtests.fdb', dpb.getBufferLength(st), dpb.getBuffer(st));" (the function "Callback" is triggered).

Could anyone please help me to manage how to pass the encryption key from delphi application to the Firebird server?

Program create;
{$APPTYPE CONSOLE}

uses
  Sysutils,Firebird,Windows;

var
st : IStatus;
master : IMaster;
util : IUtil;
dpb : IXpbBuilder;
prov : IProvider;
att : IAttachment;
tra : ITransaction;

procedure PrintError(s : IStatus);
var
maxMessage : Integer;
outMessage : PAnsiChar;
begin
maxMessage := 256;
outMessage := PAnsiChar(StrAlloc(maxMessage));
util.formatStatus(outMessage, maxMessage, s);
writeln(outMessage);
StrDispose(outMessage);
end;

type
IKeyCallback = class(ICryptKeyCallbackImpl)
function callback(dataLength: Cardinal; data: Pointer; bufferLength: Cardinal; buffer: Pointer): Cardinal; override;
end;

function IKeyCallback.callback(dataLength: Cardinal; data: Pointer; bufferLength: Cardinal; buffer: Pointer): Cardinal;
var Key: PAnsiChar;
    KeyLength:Integer;
begin
  KeyLength := 1;
If (bufferLength > 0) and (buffer <> nil) then
begin
    WriteLn('Sending key');
    Key := '1234567890abcdef';
    KeyLength := Length(Key);
    WriteLn('got key request: '+Key+':'+IntToStr(KeyLength));
    Move(Key, buffer^, KeyLength);
end;
Result := KeyLength;
end;

var param1:String;

begin
  if ParamCount>0 then
  begin
    param1 := ParamStr(1);
  end;
  if param1<>'open' then
    param1 := 'create';

WriteLn('starting...('+param1+')');
master := fb_get_master_interface;
if master = nil then
     begin
      WriteLn('master is nil');
      Exit;
     end;
    Write('getting util interface...');
util := master.getUtilInterface;
    WriteLn('done.');

    Write('getting status and dispatcher...');
st := master.getStatus;
prov := master.getDispatcher;
    WriteLn('done.');
if (util = nil) or (st = nil) or (prov = nil) then
begin
WriteLn('null pointers');
Exit;
end;

try
prov.setDbCryptCallback(st, IKeyCallback.create);
Write('Generating DPB...');
// create DPB
dpb := util.getXpbBuilder(st, IXpbBuilder.DPB, nil, 0);
Write('page size...');
dpb.insertInt(st, isc_dpb_page_size, 4 * 1024);
Write('user name...');
dpb.insertString(st, isc_dpb_user_name, 'sysdba');
Write('password...');
dpb.insertString(st, isc_dpb_password, 'masterkey');
WriteLn('done.');

    //create empty database
    if param1='create' then
    begin
att := prov.createDatabase(st, 'fbtests.fdb', dpb.getBufferLength(st), dpb.getBuffer(st));
writeln ('Database fbtests.fdb created');

      // start transaction
      tra := att.startTransaction(st, 0, nil);

      // Encrypt database
      att.execute(st, tra, 0, 'alter database encrypt with aes128', 3,
        nil, nil, nil, nil); // Input parameters and output data not used

      // commit transaction (will close interface)
      tra.commit(st);
      tra := nil;

      WriteLn('Press Enter to continue');
      ReadLn;

      // detach from database
      att.detach(st);
      att := nil;

      // remove unneeded any more tag from DPB
      if dpb.findFirst(st, isc_dpb_page_size)
        then dpb.removeCurrent(st);

      // attach it once again
      att := prov.attachDatabase(st, 'fbtests.fdb', dpb.getBufferLength(st), dpb.getBuffer(st));
      writeln ('Re-attached database fbtests.fdb');

      // start transaction
      tra := att.startTransaction(st, 0, nil);

      // create table
      att.execute(st, tra, 0, 'create table dates_table (d1 date)', 3,
        nil, nil, nil, nil); // Input parameters and output data not used

      // commit transaction retaining
      tra.commitRetaining(st);
      writeln ('Table dates_table created');

      // insert a record into dates_table
      att.execute(st, tra, 0, 'insert into dates_table values (CURRENT_DATE)', 3,
        nil, nil, nil, nil); // Input parameters and output data not used

      // commit transaction (will close interface)
      tra.commit(st);
      tra := nil;

      writeln ('Record inserted into dates_table');
    end

    //open database
    else if param1='open' then
    begin
      att := prov.attachDatabase(st, 'fbtests.fdb', dpb.getBufferLength(st), dpb.getBuffer(st));
      writeln ('Database fbtests.fdb Opened');
      exit;
    end;

// detach from database (will close interface)
att.detach(st);
att := nil;

dpb.dispose;
dpb := nil;
except
on e: FbException do PrintError(e.getStatus);
end;

prov.release;
end.

Paul Beach added a comment - 21/Nov/16 11:57 AM - edited
According to Alexey Kovyazin this compiles fine using Delphi XE6 or XE7, I wonder if there is a problem with earlier versions of Delphi? On cross checking this code will run as well... i.e. Alexey did manage to get the code to also work with an encrypt library and passed the key via the application. So the version of Delphi does seem to be an issue.

Dimitry Sibiryakov added a comment - 21/Nov/16 12:07 PM
Yes, the problem is data types. Especially NativeInt.