Search code examples
delphiwinapiacllazarus

Modifying File-ACL in Lazarus / Delphi


I'm trying to get a function working in Lazarus that should add a File-ACL to the yet existing ACL of that object. Obviously I'm doing somethinh wrong: The program crashes with a SIGSEGV when it reaches BuildExplicitAccessWithName. Regarding the debugger, this function calls BuildTrusteeWithObjectsAndName iternally which then leads to the SIGSEGV. What am I doing wrong here? Here's my code:

program acltest;

uses JwaWindows;

function AddFileACL(Filename, TrusteeName: AnsiString; AccessMode: ACCESS_MODE; Inheritance: dWord): Boolean; stdcall;
var
  pExplicitAccess : PEXPLICIT_ACCESS;
  ExistingDacl : PACL;
  pExistingDacl : PPACL;
  NewAcl : PACL;
  psd : PSECURITY_DESCRIPTOR;
begin
  NewAcl := nil;
  psd := nil;
  pExistingDacl := nil;
  Result := false;
  try
    if ERROR_SUCCESS = GetNamedSecurityInfo(pAnsiChar(Filename), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, pExistingDacl, nil, psd) then
    begin
      try
        BuildExplicitAccessWithName(pExplicitAccess, PAnsiChar(TrusteeName), GENERIC_ALL, AccessMode, Inheritance);
        ExistingDacl := pExistingDacl^;
        if ERROR_SUCCESS = SetEntriesInAcl(1, pExplicitAccess, ExistingDacl, NewAcl) then
        begin
          if ERROR_SUCCESS = SetNamedSecurityInfo(pAnsiChar(Filename), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, NewAcl, nil) then
          begin
            Result := true;
          end;
        end;
      finally
      end;
    end;
  finally
  end;
end;

begin
  if AddFileACL('C:\Users\keckc\Desktop\test.txt', 'Everyone', GRANT_ACCESS, SUB_CONTAINERS_AND_OBJECTS_INHERIT) = true then
  begin
    writeln('Yep, it works!');
  end
  else begin
    writeln('Nope, try again!');
  end;
end.

Solution

  • You pass pExplicitAccess which is an uninitialized pointer variable of type PEXPLICIT_ACCESS. You are expected instead to allocate an EXPLICIT_ACCESS structure, and pass its address.

    var
      ExplicitAccess: EXPLICIT_ACCESS;
    ....
    BuildExplicitAccessWithName(@ExplicitAccess, ...);
    

    In the call to GetNamedSecurityInfo, passing psd is somewhat pointless. Since it has the value nil, you may as well delete pass nil. At which point you'll be able to remove the psd variable.

    As for pExistingDacl, again you initialise it to nil. And so pExistingDacl^ is going to be another SIGSEV. Instead you should remove the pExistingDacl variable, and pass @ExistingDacl.

    It would seem that you have similar problems with the calls to SetEntriesInAcl and SetNamedSecurityInfo, but hopefully by now, you can understand the pattern and will be able to resolve the problems.

    Finally, I do also wonder why you are using the ANSI version of the function rather than the Unicode version.