This discussion continues How to use a SecurityAttribute structure.

Last time we used the SecurityAttribute parameter in CreateFile to change the security descriptor of the newly created file. However this approach did not add inherited access control elements from the parent folder. We are about to change that.

Filesystem and Registry-key inheritance is implemented since Windows 2000 and also can be added to Windows NT 4 by installing an update. It is a really convenient way to set security over many files in a complex folder tree.

So what did we last time?

var SD : TJwSecurityDescriptor;
     AliceSid : TJwSecurityId;
     SecAttrPtr : PSecurityAttributes;
     Handle : THandle;
begin
  DeleteFile(‘testfile’);

  SD := TJwSecurityDescriptor.CreateDefaultByToken();
  AliceSid := TJwSecurityId.Create(,‘Alice’);
  SD.DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create(nil, [], GENERIC_READ, AliceSid, true));

  SecAttrPtr := SD.Create_SA();

  try
    Handle := jwaWindows.CreateFile(‘testfile’, FILE_ALL_ACCESS, 0,
                      Pointer(SecAttrPtr),
                      CREATE_NEW, FILE_ATTRIBUTE_NORMAL,0);
    if handle = ERROR_INVALID_HANDLE then
      RaiseLastOSError;
  finally
    SD.Free;
  end;

This code assigns a simple security descriptor. In my tests there was no way to let CreateFile add the inherited elements to the DACL. Luckily there are several ways to do so.

  1. Get the inherited access elements from the parent and add them to our DACL by hand
  2. Let the system handle inheritance
  3. Do the second way much faster

1. Get the inherited access elements from the parent and add them to our DACL by hand

The first choice needs a lot of work to do. First we need all the inheritable access control elements from the parent folders. This would become very nasty if we had to recursively go up to all parent folders to get the elements. However we are lucky because all inherited ACEs are always available through the direct parent container (if they are not blocked).
Because I will need more time to describe this approach. I’m going to skip this part for now and discuss it in a separate blog entry.

2. Let the system handle inheritance

JWSCL supports inheritance of file, folder and registry keys with the classes TJwSecureFileObject and TJwSecureRegistryKey. We are going to use only TJwSecureFileObject for our task. However changing permissons and inheritance of a registry key is straight forward and is much the same job as it is with files and folders.

TJwSecureFileObject offers three ways to adapt security of a file or folder. You can use a file/folder handle (retrieved by CreateFile), a file or folder name or you use the VCL class TFileStream. However the last variant has some disadvantages like not being able to work with folders.

var SD : TJwSecurityDescriptor;
    AliceSid : TJwSecurityId;
    SecAttrPtr : PSecurityAttributes;
    Handle : THandle;
    Sec : TJwSecureFileObject;
    DACL : TJwDAccessControlList;
begin

  …
  SecAttrPtr := SD.Create_SA();

  try
    Handle := jwaWindows.CreateFile(‘testfile’, FILE_ALL_ACCESS, 0,
                      Pointer(SecAttrPtr),
                      CREATE_NEW, FILE_ATTRIBUTE_NORMAL,0);
    if handle = ERROR_INVALID_HANDLE then
      RaiseLastOSError;
  finally
    SD.Free;
  end;

  CloseHandle(Handle);
  Sec := TJwSecureFileObject.Create(‘testfile’);
  DACL := Sec.GetDACL;
  try
    Sec.SetDACL(DACL,apUnprotected);
  finally
    DACL.Free;
    Sec.Free;
  end;

TJwSecureFileObject retrieves the DACL of the file after newly created file was opened. The method SetDACL sets the DACL back but also removes the protection flag from security descriptor control. Thus all the inherited access elements flow to the file’s access control list.

3. Do the second way which is much less to write

TJwSecureFileObject offers class methods to act with file or folders much faster. We can either restore the inheritance flow by using the file/folder name…

begin
  DeleteFile(‘testfile’);
  …
  TJwSecureFileObject.RestoreInheritanceFlow(‘testfile’);
  …

or reestablish the inheritance flow by using a file handle.

begin
  DeleteFile(‘testfile’);
  try
    Handle := jwaWindows.CreateFile(‘testfile’, FILE_ALL_ACCESS, 0,
                      Pointer(SecAttrPtr),
                      CREATE_NEW, FILE_ATTRIBUTE_NORMAL,0);
     if handle = ERROR_INVALID_HANDLE then
       RaiseLastOSError;
    TJwSecureFileObject.RestoreInheritanceFlow(Handle);
  finally      
    SD.Free;  
  end;

You can use one way or the other.

Tell me how you liked this blog entry by adding a comment.