This article describes some ways how to set the security on a folder using JWSCL. Usually, we want to add some rights for a particular user to a folder so she gets access. I can say that is a heck of work to do with WinAPI. But still with JWSCL we need to consider some things.

The following code creates a folder named “JWSCLTest” and applies a DACL that allows full control to everyone. The folder will inherit its security settings to child folders and files (check the afXXX flags).

const JWSCLTestFolder = 'JWSCLTestFolder';

var
  SD : TJwSecurityDescriptor;
  pSA : PSecurityAttributes;
begin
  JwInitWellKnownSIDs;

  SD := TJwSecurityDescriptor.Create;
  try
    SD.DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create(nil,
      [afContainerInheritAce, afObjectInheritAce], FILE_ALL_ACCESS, JwWorldSID));

    pSA := SD.Create_SA();
    try
      Win32Check(CreateDirectory(JWSCLTestFolder, pSA));
    finally
      SD.Free_SA(pSA); //remember to free pointer
    end;
  finally
    SD.Free;
  end;
end.

CreateDirectory receives a security attributes structure that is applied to the folder directly. However, in this way the parent security descriptor is not inherited to our folder. This is called a protected DACL because the inheritance flow is stopped. So we get a folder with only one Access Control Entry (ACE) : Everyone (aka World SID). To remedy that we can copy the ACEs from the parent folder to our own folder:

procedure MergeParentDACL(const Location : String; TargetSD : TJwSecurityDescriptor);
var DirSD : TJwSecureFileObject;
begin
  DirSD := TJwSecureFileObject.Create(Location);
  try
    TargetSD.DACL.AddACEs(DirSD.DACL);
  finally
    DirSD.Free;
  end;
end;

var
  DirSD : TJwSecureFileObject;

  SD, SD2 : TJwSecurityDescriptor;
  pSA : PSecurityAttributes;
begin
  JwInitWellKnownSIDs;

  SD := TJwSecurityDescriptor.Create;

  try
    SD.DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create(nil,
      [afContainerInheritAce, afObjectInheritAce], FILE_ALL_ACCESS, JwWorldSID));

    MergeParentDACL('.', SD);

    pSA := SD.Create_SA();
    try
      Win32Check(CreateDirectory(JWSCLTestFolder, pSA));
    finally
      SD.Free_SA(pSA);
    end;
  finally
    SD.Free;
  end;
end.

The function MergeParentDACL receives the location of the parent folder and retrieves its security settings. Then its DACL is copied to the target security descriptor. JWSCL with TargetSD.DACL.AddACEs makes sure that the order of the ACEs are still correct (first deny then allow entries) by moving them accordingly.

In addition, there is a second, much easier way to achieve the same result.

var
  SD : TJwSecurityDescriptor;
  DirSD : TJwSecureFileObject;
begin
  JwInitWellKnownSIDs;

  Win32Check(CreateDirectory(JWSCLTestFolder, nil));

  DirSD := TJwSecureFileObject.Create(JWSCLTestFolder);
  try
    SD := DirSD.GetSecurityDescriptor([siDaclSecurityInformation]);
    try
      SD.DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create(nil,
        [afContainerInheritAce, afObjectInheritAce], FILE_ALL_ACCESS, JwWorldSID));

      DirSD.SetSecurityDescriptor(SD, [siDaclSecurityInformation]);
    finally
      SD.Free;
    end;
  finally
    DirSD.Free;
  end;

In this way we didn’t set the security descriptor directly when the folder was created. Nevertheless we get a combination of inheritace ACEs plus the explicit one (JwWorldSID).

Note

It is always a good idea to check whether SD.DACL (in above codes) is nil and if so ignore it or create a new and empty one to be used instead. It is always possible that a file or folder comes with a nil DACL which means either no access at all (flag DACLpresent) or everyone has full access (flag DACLpresent not available).

I used the following JEDI units:

uses
  JwaWindows,

  JwsclDescriptor,
  JwsclTypes,
  JwsclConstants,
  JwsclKnownSid,
  JwsclAcl,
  JwsclMapping,
  JwsclSecureObjects,
  JwsclSid,