Many developers know that mysterious parameter some WinAPI function offer to use. What I am talking about is a parameter called lpSecurityAttributes. The documentation states that it allows to change the security descriptor of the desired element. The most known function is CreateFile which I want to use here. It allows to create a file and more. But we stay to create a file. Usually we set the parameter lpSecurityAttributes simply to NULL/nil because this sets the default security configuration we want to use in most of the times (this also includes file/folder inheritance).

However sometimes we want to use our own security configuration to allow other participants to access a resource we created. JWSCL makes this task much more simple than using the security runtime function written in plain C. We do not have to create the security descriptor from scratch. The JWSCL methods allow us to get the default security descriptor and adapt it to our needs.

Let’s start with the required classes and methods we need to add another user who wants access.

That’s all.

Since the system already creates us an adequate security access list we want to continue using it. For this reason TJwSecurityDescriptor implements a constructor called CreateDefaultByToken that creates such a security access list automatically.

uses JwaWindows,…,JwsclDescriptor, JwsclAcl, JwsclTypes, JwsclStrings;
var SD : TJwSecurityDescriptor;
begin
  SD := TJwSecurityDescriptor.CreateDefaultByToken();
  Writeln(SD.Text);

The output may look like this, depending on your Windows system.

Owner: chris@ Christian (S-1-5-21-2735234258-346234578-4357623456-1000) []
Group: chris@ None (S-1-5-21-2735234258-346234578-4357623456-513) [sidaGroupMandatory]
DACL:
ACE Count: 3
\#0
ClassName: TJwDiscretionaryAccessControlEntryAllow
AceType: Allow
Flags:
Accessmask: No map class given. 268435456, 0×10000000
SID: chris@ Christian (S-1-5-21-2735234258-346234578-4357623456-1000) []
#1
ClassName: TJwDiscretionaryAccessControlEntryAllow
AceType: Allow
Flags:
Accessmask: No map class given. 268435456, 0×10000000
SID: NT-AUTORIT-T@ SYSTEM (S-1-5-18) []
#2
ClassName: TJwDiscretionaryAccessControlEntryAllow
AceType: Allow
Flags:
Accessmask: No map class given. 2684354560, 0xA0000000
SID: (S-1-5-5-0-151391) []

SACL:
ACE Count: 0
\

(No map class given is shown because the security descriptor class does not know the type of secured object. A map class (derived from TJwSecurityGenericMapping) can convert the AccessMask to an human readable string)

The system sets the owner to the current token owner of the process or thread. It also adds my user account and the SYSTEM principal with full access (0×10000000 = GENERIC_ALL). The unknown principal with the Sid S-1-5-5-0-151391 describes the loggon session Sid. At a later point we will remove it.
For the discussion we want to add another principal called Alice so she can get read access to the file/folder. Because we need the Alice’s Sid we have to add another variable called AliceSid.

var SD : TJwSecurityDescriptor;
    AliceSid : TJwSecurityId;
begin
   SD := TJwSecurityDescriptor.CreateDefaultByToken();

   AliceSid := TJwSecurityId.Create(,‘Alice’);

   SD.DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create(nil, [], GENERIC_READ, AliceSid, true));
   Writeln(SD.Text);

In the code above a new class instance of TJwDiscretionaryAccessControlEntryAllow is added to the DACL. Because we create just a simple file we do not need special flags thus an empty flag set [] is applied. The access mask parameter will receive GENERIC_READ as the maximum possible access to this file granted to Alice. The last parameter (OwnSid) is set to true and defines that the access control list (here property DACL) destroys the instance AliceSid at the end.

The resulting security descriptor has now a new access control entry. The output is the same like above but with this additional element.

ClassName: TJwDiscretionaryAccessControlEntryAllow
AceType: Allow
Flags:
Accessmask: No map class given. 2147483648, 0×80000000
SID: chris@ Alice (S-1-5-21-2735234258-346234578-4357623456-1008) []

Now we can arrive at the part where CreateFile comes in. How can we create a pointer to a TSecurityAttribute type? It is really simple! We just have to declare some more helper variables that CreateFile needs and use Create_SA.

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;

Create_SA from TJwSecurityDescriptor creates the necessary memory structure (SecurityAttributes) and returns a pointer of type PSecurityAttributes. The pointer is used in CreateFile to apply our own security descriptor. Our access control list of the newly created file will contain all the elements you see above as output. In tests, both the creation flags CREATE_NEW and CREATE_ALWAYS never change the security attributes after the file has already been created. Although MSDN explains it correctly for CREATE_ALWAYS it does not say anything about CREATE_NEW in this context. Because of this we simply delete the file everytime.

The security editor of Windows Explorer shows us the new descriptor.

Bild

As you can see we did not remove the LogonSession Sid from the security descriptor. The logon SID resides in the principal’s token. It is used to add allow or deny access to a secured object but only for the time the user is logged on. This is because every time the user logs on, a new session Sid is generated. Additionally all calls to the LogonUser API get their own session Sid so a logon Sid is a fine grained access control that allows us not only to restrict access between users but also control access between several different instances of a user (consider the user itself as a class and all user tokens as instances of this class) .
However removing this LogonSID will be our next task because we do not need it here.

JWSCL supports us with a function that returns a TJwSecurityId of the logon session. The function is called JwGetLogonSID and resides in unit JwsclKnownSid that we have to include additionally. Unfortunately there is a bug in revision 316 that makes it impossible to use it. For this reason I added an adapted version of the whole unit JwsclKnownSid . You can get it here.

Let’s see how we can get rid of the logon sid.

var SD : TJwSecurityDescriptor;
    LogonSid,
    AliceSid : TJwSecurityId;
    SecAttrPtr : PSecurityAttributes;
    Handle : THandle;
    PosInt : Integer;
begin
  SD := TJwSecurityDescriptor.CreateDefaultByToken();

  LogonSid := JwGetLogonSID;

  PosInt := SD.DACL.FindSID(LogonSid);
  if PosInt >= 0 then
     SD.DACL.Remove(PosInt);
  LogonSid.Free;

JwGetLogonSid returns a new instance that can be used to search for the logon Sid in the DACL. The method FindSID in TJwDAccessControlList goes through the whole access control list and returns the zero based index of the entry we search for. If it were not to be found we would get a negative result value, but this is not the case here (although we check for it because it is good programming style). At the end do not forget to remove the instance.

Bild

The new security descriptor does not contain the annoying logon Sid anymore. Eventually we can use this discussed approach not only for CreateFile but also for CreatePipe, CreateProcess, RegCreateKeyEx, RegSaveKeyEx, CreateFileMapping and many more. I used CreateFile so you can easily look up the descriptor in the security editor of Windows Explorer.

The next article will discuss how we can use inheritance and why there are no inherited access control elements in our created security descriptor although the parent folder hand them down.

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

Update

Fixed all the links to the JWSCL Documentation. I didn’t recognize that Doc-O-Matic changed the output tree format of the HTML Help.