Global Variables in a DLL?

<b>Some background</b>
I'd like to create an intranet-site were passwords can be safely stored/retrieved in a Database. However I must provide a mechanism so that administrators cannot grant access to the passwords. Therefore the passwords cannot be stored on the server, or on the client and may not be stored in cookies. Server-side decryption is also not an option, since I want to protect against network-sniffers. All encryption/decryption must be done on the client-side.

I had an idea in mind where the encryption/decryption would be performed in a client-side DLL. The DLL would be loaded from VBScript from within a HTML-page.

<b>The Problem</b>
The first time a decryption is perfomed, it should popup a form to ask for a password. From then on, the password is kept in memory, as long as the computer stays online. All encryption/decryption functions should then use this same password.

<b>What I already have</b>
My current prototype popups a form, where I can enter a password, and then nicely decrypts the message. But as soon as the VBScript has finished, the secret-password is no longer accessible.
It looks like when VBScript has finished, it always unloads the DLL.

I currently have an ActiveX Library, an Automation Object and a Form.

I tried using different techniques, overriding DllCanUnloadNow, tried to create 'Global Variables' in all the different Units... I changed Instancing and Threading Model... but did not succeed.

Any suggestions?
Br_narAsked:
Who is Participating?
 
Russell LibbySoftware Engineer, Advisory Commented:
Hmmm...
Figures that it doesn't work the way it is supposed to (according to the MS docs). It does close the handle as soon as the process goes away. In fact, even the following is not enough to keep the handle open

     // Protect the handle
     SetHandleInformation(FHandle, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);

Leaves you with very few choices:
1.) Inject your library into a running system process, so it always remains running.
3.) Start another process (hidden), then use the DuplicateHandle function so the new process has access to the handle (and thus keeps it open).
2.) Persist the information to a file or the registry entry

Sorry I could not help further.

Russell
0
 
Russell LibbySoftware Engineer, Advisory Commented:

What about saving this data in a shared block of memory allocated via CreateFileMapping? The only difference from most implementations (using shared mem) is that the creator would not call UnmapViewOfFile on the shared memory, thus leaving this named memory available until the computer restarted?

If you need some code examples, I would be more than happy to provide them.

Regards,
Russell
0
 
Br_narAuthor Commented:
I found the following Unit, but same problem here. As soon as the DLL i unloaded, the FileMapping disappears (or at least is inaccessible). Any suggestions on how to keep these FileMappings in memory? Or any other way how to keep the DLL in memory? Or another way of creating 'Global Variables'?




// Code of how I called the Unit from my DLL (Also tried to call this in a separate program)
function TApplication.GetKey: String;
var
  mySharedMem : TSharedMemory;
begin
  mySharedMem:=TSharedMemory.Create(nil);
  mySharedMem.Handle:='ClientCrypto';
  if Length(mySharedMem.Contents)=0 then
  begin
    PasswordDlg:=TPasswordDlg.Create(nil);
    PasswordDlg.ShowModal;
    mySharedMem.Contents:=PasswordDlg.Password.Text;
  end;
  result:=mySharedMem.Contents;
end;




// Source of the Unit I found, and modified as follows
// *  I removed UnmapViewOfFile
// *  I emptied the Destructor
// *  I added code for SecurityDescriptors; I thought maybe Windows does not allow me to read the data...

unit SharedMem;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TSharedMemory = class( TComponent )
  private
    hFileMapping: THandle;
    FHandle: string;
    lp: pointer;
    FSize: integer;
    procedure SetContents(const Value: string);
    procedure SetHandle(const Value: string);
    function GetContents: string;
    procedure SetSize(const Value: integer);
  protected
  public
    constructor Create( AOwner: TComponent ); override;
    destructor Destroy; override;
    property Contents: string read GetContents write SetContents;
  published
    property Handle: string read FHandle write SetHandle;
    property Size: integer read FSize write SetSize default 255;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents( 'Silicon Commander', [TSharedMemory] );
end;

constructor TSharedMemory.Create(AOwner: TComponent);
begin
  inherited Create( AOwner );
  FSize := 255;
end;

destructor TSharedMemory.Destroy;
begin
  inherited Destroy;
//  if lp <> nil then
//    UnmapViewOfFile( lp );
//  if hFileMapping <> 0 then
//    CloseHandle( hFileMapping );
end;

function TSharedMemory.GetContents: string;
begin
  if lp = nil then
    Result := ''
  else
    Result := StrPas( lp );
end;

procedure TSharedMemory.SetContents(const Value: string);
begin
  if ( csDesigning in ComponentState ) then
    Exit;
(* If a mapping does not exist, do nothing *)
  if lp = nil then
    Exit;
  StrPCopy( lp, Value );
end;

procedure TSharedMemory.SetHandle(const Value: string);
const
  SECURITY_DESCRIPTOR_REVISION = 1;
var
  SecurityDescriptor:TSecurityDescriptor;
  SecurityAttr:TSecurityAttributes;
  RetVal:Integer;
function IsNT: Boolean;
var
  OS: TOSVERSIONINFO;
begin
  OS.dwOSVersionInfoSize := SizeOf(TOSVERSIONINFO);
  GetVersionEx(OS);
  Result := (OS.dwPlatformId = VER_PLATFORM_WIN32_NT);
end;
begin
  if FHandle = Value then
    Exit;
  FHandle := Value;
  if ( csDesigning in ComponentState ) then
    Exit;
(* Close down any file mapping that may be currently open *)
//  if lp <> nil then
//    UnmapViewOfFile( lp );
  if hFileMapping <> 0 then
    CloseHandle( hFileMapping );
(* See if a file mapping already exists with this name *)
  hFileMapping := OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, PChar( FHandle ) );
(* If not, create a new one *)
  if hFileMapping = 0 then

//    lpHookRec:=NIL;
    if (IsNT) then
    begin
      SecurityAttr.nLength:=SizeOf(SECURITY_ATTRIBUTES);
      SecurityAttr.bInheritHandle:=TRUE;
      SecurityAttr.lpSecurityDescriptor:=@SecurityDescriptor;
      if not InitializeSecurityDescriptor(@SecurityDescriptor,SECURITY_DESCRIPTOR_REVISION) then
      begin
          RetVal:=GetLastError;
          raise Exception.CreateFmt('Unable to initialize security descriptor. Windows error=%d', [RetVal]);
      end;
      if not SetSecurityDescriptorDacl(@SecurityDescriptor,TRUE,NIL,FALSE) then
      begin
          RetVal:=GetLastError;
          raise Exception.CreateFmt('Unable to set security descriptor dacl. Windows error=%d', [RetVal]);
      end;
      if not SetKernelObjectSecurity(GetCurrentProcess,DACL_SECURITY_INFORMATION,@SecurityDescriptor) then
      begin
          RetVal:=GetLastError;
          raise Exception.CreateFmt( 'Unable to set kernel object security. Windows error=%d', [RetVal]);
      end;
      hFileMapping:=CreateFileMapping($FFFFFFFF, @SecurityAttr, PAGE_READWRITE or SEC_COMMIT, 0, FSize, PChar( FHandle ));
    end else
    begin
      hFileMapping := CreateFileMapping( $ffffffff, nil, PAGE_READWRITE or SEC_COMMIT, 0, FSize, PChar( FHandle ) );
    end;

  if hFileMapping = 0 then
    raise Exception.Create( 'CreateFileMapping failed with error code ' + IntToStr( GetLastError) );
(* Map the view of the file *)
  lp := MapViewOfFile( hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, FSize );
  if lp = nil then
    raise Exception.Create( 'MapViewOfFile failed with error code ' + IntToStr( GetLastError ) );
end;

procedure TSharedMemory.SetSize(const Value: integer);
begin
  FSize := Value;
end;

end.

0
Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

 
DragonSlayerCommented:
Russell, it's 1, 2, 3... not 1, 3, 2... time to go back to elementary school ;-)
0
 
Russell LibbySoftware Engineer, Advisory Commented:
;-) Funny guy.....

Regards,
Russell
0
 
Br_narAuthor Commented:
I tried HANDLE_FLAG_PROTECT_FROM_CLOSE, but as you say it didn't work...

But as you say, I can fix it by having the DLL interact with a 'running process'. The user enters his password in the 'unlock program' which creates a FileMapping (containing the password).

The DLL will check for the FileMapping and use it to decrypt/encrypt the data. If the FileMapping is not present decryption will return 'No Access'.

Thanks for the suggestions!
0
 
Russell LibbySoftware Engineer, Advisory Commented:
Glad I could assist, and thank you

Russell
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.