I have to impersonate call to log on when diferent user is on.

Below is a code to test if i can open specific document made by another user.
I have made test on my home pc  and i have got:
'not impersonated call failed, this is good.'

But then problems came because of:
if LogonUser('aaaabc','abbbbc', 'abcccc1000', LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, h)

And  because now on my pc i have set just Login, and there is no need for password, i just type "enter" for any user.
So i have to enable all settings of log on window as below:

Login:

Password:

Log on to:

a si have it in office .

My app is a tool for archiving of some data in specific file directly from machine. This file will be locked in windows for all users except one. And my app will also use this user account.
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    SpeedButton1: TSpeedButton;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var h:cardinal;
    s:string;
    d:cardinal;
begin
  try with tfilestream.create('c:\testdir2\test.txt', fmcreate) do
    try
    finally
      free;
    end;
    showmessage('not impersonated call succeeded. THIS IS BAD.');
  except
    showmessage('not impersonated call failed, this is good.');
  end;
  //////////////
  if LogonUser('aaaabc','abbbbc', 'abcccc1000', LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, h) then  begin
    try
      if ImpersonateLoggedOnUser(h) then   begin
      d:=0;
      GetUserName(nil, d);
      setlength(s, d+1);
      GetUserName(pchar(s), d);
      showmessage('ok: '+s);
           try
           speedbutton1.Font.Color:=clgreen;

              with tfilestream.create('c:\testdir2\test.txt', fmcreate) do
                try
               finally
                free;
                end;
              
               showmessage('Impersonated call succeeded, this is good.');

           except
            showmessage('Impersonated call failed. THIS IS BAD.');
           end;
        end else
        showmessage(syserrormessage(getlasterror));
      finally
       closehandle(h);
     end;
    end else
   showmessage(syserrormessage(getlasterror));
   end;


end.

Open in new window

pr2501Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jimyXCommented:
Sorry not catching you, what you have wrong here? You mean there is an error?
pr2501Author Commented:
On my pc i have

Login:  ....

Password: (i just click enter)

In log on window when system boots.

But  how to set?

Login:

Password:

Log on to:

pr2501Author Commented:
So i can test my code above?
Amazon Web Services

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

jimyXCommented:
You need to adjust some settings in the registry or the Local Security Policy to accept blank passwords.

Just call the following procedure before using LogonUser():

 
Uses Registry;

procedure TForm1.DisableLsa(Disable: Boolean);
var
  MyReg: TRegistry;
begin
  MyReg:=TRegistry.Create;
  try
    MyReg.RootKey:=HKEY_LOCAL_MACHINE;
    MyReg.OpenKey('System\CurrentControlSet\Control\Lsa', true);
    if Disable then
      begin
        MyReg.WriteInteger('LimitBlankPasswordUse',0);
      end
    else
      begin
        MyReg.WriteInteger('LimitBlankPasswordUse',1);
      end;
    MyReg.CloseKey;
  finally
    MyReg.Free;
  end;
end;

Open in new window



DisableLsa(true);
LogonUser(...); // the password parameter to be PChar('') or nil if it is blank

http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_24133495.html
pr2501Author Commented:
Sorry , i need window  which has :

Login:

Password:

Log on to:

jimyXCommented:
What do you mean by you want a window?
If you mean you want the user to add the values at the moment of using your application then you can add three edit boxes to your form:

Edit1 is for Username (Login)
Edit2 is for password
Edit3 is for Domain (Log on to):

And in the FormCreate just assign those values to LogonUser(), as follows:

 
Uses Registry;

procedure TForm1.DisableLsa(Disable: Boolean);
var
  MyReg: TRegistry;
begin
  MyReg:=TRegistry.Create;
  try
    MyReg.RootKey:=HKEY_LOCAL_MACHINE;
    MyReg.OpenKey('System\CurrentControlSet\Control\Lsa', true);
    if Disable then
      begin
        MyReg.WriteInteger('LimitBlankPasswordUse',0);
      end
    else
      begin
        MyReg.WriteInteger('LimitBlankPasswordUse',1);
      end;
    MyReg.CloseKey;
  finally
    MyReg.Free;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  h:cardinal;
  User, Pass, Domain : String;
begin
  User := Edit1.text;
  Pass := Edit2.text;
  Domain := Edit3.text;

// if user can not be nil either show error message and exit or accept if it is OK with you
  if User = '' then
    begin
      //showmessage('User can not be empty');
      //exit;
    end;

  DisableLsa(true);

  if LogonUser(Pchar(User),Pchar(Domain), Pchar(Pass), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, h) then
    begin
      try
        if ImpersonateLoggedOnUser(h) then
          begin
            ... // your code goes here
          end;
      finally
       closehandle(h);
     end;
    end
  else
   showmessage(syserrormessage(getlasterror));
end;

Open in new window


If I am away from your point can you explain more please.
pr2501Author Commented:
Windows start login window must have it.
pr2501Author Commented:
Thank you.
jimyXCommented:
Which Operating System you are using? if it is Win xp, is it Professional or Home edition?
jimyXCommented:
Do you have a server with domain that you want to join?

You can review the following step-by-step guide on how to join a domain.
http://www.windowsnetworking.com/articles_tutorials/wxpjoind.html

In Win xp home Edition you will not be able to join domain.
pr2501Author Commented:
II have professional edition.Can i do everything with just one/my PC?
( I have try it. I checked the option to ignore hardware connection, but no success...)
jimyXCommented:
If you do not have a domain you can just use PChar('') as domain parameter, or just put nil, in the LogonUser(). So it becomes:

 
LogonUser(Pchar(User),PChar(''), Pchar(Pass), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, h)

Open in new window


Otherwise you need to turn your PC to a server by having your own domain that others can join requires network knowledge. While it is not required here all you have to do is provide domain if the user is on domain or nil if there is no domain.
pr2501Author Commented:
I need instructions for:
"Otherwise you need to turn your PC to a server"

I have try with instructions from yours link, which explains how to get to window in attached picture, but i can't do it.


win.JPG
jimyXCommented:
This requires networking knowledge, which at the moment I can not help much with, but I will find out for you.

If I may ask why is that? Because you can write and test your application without domain.
pr2501Author Commented:
I must log at network with domain.
pr2501Author Commented:
Real network in office where i work.
jimyXCommented:
I do not think it makes any difference if you finish your code in your own PC having the domain as nil and when you want to move it to a PC that is part of domain you can change it and add that domain. You do not have to have domain at your own PC to get your code working.

i.e.:
In a PC that has no Domain use:
LogonUser(Pchar(User),PChar(''), Pchar(Pass), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, h)

But in a PC that must identify domain use:
LogonUser(Pchar(User),PChar(Domain), Pchar(Pass), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, h)
pr2501Author Commented:
I have set:
"In a PC that has no Domain use"
and have used

DisableLsa(true);

when i was logged everything was ok but when i logged as other user and started my app

 i have got next message (attached picture);

I have  added TRichedit and TButton to my app. When i click on a button impersonation starts and text from TRichedit has to be copied into C:\testdier\test.txt
The point of my app is to change data in file which i created  when i was logged on that PC.
So then when someone else is logged i can still work with specific file when i use my app.

procedure TForm1.Button1Click(Sender: TObject);
var h:cardinal;
    s:string;
    d:cardinal;

   TextText: textfile;
begin
DisableLsa(true);    //disable password
  try with tfilestream.create('c:\testdir2\test.txt', fmcreate) do
    try
    finally
      free;
    end;
    showmessage('not impersonated call succeeded. THIS IS BAD.');
  except
    showmessage('not impersonated call failed, this is good.');
  end;
  //////////////
  ///

  //  In a PC that has no Domain use:
 if LogonUser(Pchar('aaa'),PChar(''), Pchar(''), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, h)    then begin
    try
      if ImpersonateLoggedOnUser(h) then   begin
      d:=0;
      GetUserName(nil, d);
      setlength(s, d+1);
      GetUserName(pchar(s), d);
      showmessage('ok: '+s);
           try
           speedbutton1.Font.Color:=clgreen;              


              with tfilestream.create('c:\testdir2\test.txt', fmcreate) do
                try

               finally
                free;
                end;
                 
               Richedit1.Lines.SaveToFile('C:\testdir2\test.txt');

               showmessage('Impersonated call succeeded, this is good.');

           except
            showmessage('Impersonated call failed. THIS IS BAD.');
           end;
        end else
        showmessage(syserrormessage(getlasterror));
      finally
       closehandle(h);
     end;
    end else
   showmessage(syserrormessage(getlasterror));
   end;

Open in new window

passw.JPG
jimyXCommented:
>  ...when i logged as other user and started my app

Did you log in with administrator account or limited account?

Users who have limited accounts can not change this property.
pr2501Author Commented:
Blank password?

Or maybe  should i look to find out how to make users with loggin and  passwords also.

jimyXCommented:
The error "Failed to set data for 'LimitBlankPasswordUse'" occurs because the account type that you used is not Administrator and it does not have privileges to change the Registry and set its values.

Make sure the accounts that you are using are Administrator Accounts.
pr2501Author Commented:
I have to store data in specific file.

This data can't be accessible to anyone.  But to only specific user: "one".

So i have to create  file as  a user "one". And then to log off. So then when other  user "two" will log on he would not be able to copy or change this data. So data will be protected.
But my app  may impersonate user "one" and store data into specific file when user"two" will be logged on.

If user "two" is administrator he can also change my specific file.  And this a can't allow.
pr2501Author Commented:
I have also made    user one as administrator.
pr2501Author Commented:
But still the same message. How can i set use of passwords when i have to log on?
jimyXCommented:
All you have to do is to set the Registry "LimitBlankPasswordUse" by using Administrator user for the first time only as this is required only once and the registry will save this setting and the next user will not be required to change the registry again. So no need to call the procedure DisableLsa(); always in your program to enable the LogonUser() to accept blank passwords. You can just test if it was set to accept blank passwords then ignore set of registry and proceed to the rest of the code otherwise inform the user that the registry must be set and Administrator User must run your program at least once. Something as follows:

 
procedure TForm1.DisableLsa(Disable: Boolean);
var
  MyReg: TRegistry;
begin
  MyReg:=TRegistry.Create;
  try
    MyReg.RootKey:=HKEY_LOCAL_MACHINE;
    MyReg.OpenKey('System\CurrentControlSet\Control\Lsa', true);
    try
      if Disable then
        begin
          MyReg.WriteInteger('LimitBlankPasswordUse',0);
        end
      else
        begin
          MyReg.WriteInteger('LimitBlankPasswordUse',1);
        end;
    except
      // can not set the registry value
      if MyReg.ReadInteger('LimitBlankPasswordUse') = 1 then
        showmessage('Blank passwords will not be accepted and the Registry can not be changed by the current user to enable that option.');
    end;
    MyReg.CloseKey;
  finally
    MyReg.Free;
  end;
end;

Open in new window


It is exactly like installing programs or setup of software, you need Administrator User to install them but later any user can use the programs. Your program should set the Registry value at the first time by Administrator and then no need to change it but you can test the value of "LimitBlankPasswordUse" if it is "1" then it means the current user can not open the file if the password if blank.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
pr2501Author Commented:
Next code can write to text file just once. Why?
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Buttons,Registry, StdCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    SpeedButton1: TSpeedButton;
    RichEdit1: TRichEdit;
    Button1: TButton;
  
    procedure DisableLsa(Disable: Boolean) ;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
   
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
   DisableLsa(true);    //disable password
end;

procedure TForm1.DisableLsa(Disable: Boolean);
var
  MyReg: TRegistry;
begin
  MyReg:=TRegistry.Create;
  try
    MyReg.RootKey:=HKEY_LOCAL_MACHINE;
    MyReg.OpenKey('System\CurrentControlSet\Control\Lsa', true);
    try
      if Disable then
        begin
          MyReg.WriteInteger('LimitBlankPasswordUse',0);
        end
      else
        begin
          MyReg.WriteInteger('LimitBlankPasswordUse',1);
        end;
    except
      // can not set the registry value
      if MyReg.ReadInteger('LimitBlankPasswordUse') = 1 then
        showmessage('Blank passwords will not be accepted and the Registry can not be changed by the current user to enable that option.');
    end;
    MyReg.CloseKey;
  finally
    MyReg.Free;
  end;
end;


procedure TForm1.Button1Click(Sender: TObject);
var h:cardinal;
    s:string;
    d:cardinal;

   TextText: textfile;
begin

  try with tfilestream.create('c:\testdir2\test.txt', fmcreate) do
    try
    finally
      free;
    end;
    showmessage('not impersonated call succeeded. THIS IS BAD.');
  except
    showmessage('not impersonated call failed, this is good.');
  end;
  //////////////
  ///
 // if LogonUser('aaaa','bbbbbbbb', 'ccccccccc', LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, h) then  begin
  //  In a PC that has no Domain use:
 if LogonUser(Pchar('onnnnnnnnnnnn'),PChar(''), Pchar(''), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, h)    then begin
    try
      if ImpersonateLoggedOnUser(h) then   begin
      d:=0;
      GetUserName(nil, d);
      setlength(s, d+1);
      GetUserName(pchar(s), d);
      showmessage('ok: '+s);
           try
           speedbutton1.Font.Color:=clgreen;              


              with tfilestream.create('c:\testdir2\test.txt', fmcreate) do
                try

               finally
                free;
                end;
                 
               Richedit1.Lines.SaveToFile('C:\testdir2\test.txt');

               showmessage('Impersonated call succeeded, this is good.');

           except
            showmessage('Impersonated call failed. THIS IS BAD.');
           end;
        end else
        showmessage(syserrormessage(getlasterror));
      finally
       closehandle(h);
     end;
    end else
   showmessage(syserrormessage(getlasterror));
   end;


end.

Open in new window

jimyXCommented:
What do you mean, is there an error message or it simply does not save after the first time? Because it runs OK in my PC and saves the text from the Richedit to the file whenever the button is clicked.
pr2501Author Commented:
Here am not logged as administrator.
Today i worked on other things. Thank you for your patience.You are very kind.
I  will continue next year;)

If code is correct. There must be some difficulties about.: how to log?
First as user ?, then as user?.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.