To the main page...The list of my products...Some texts...Sample applications, tips, tricks...If you need support...
 

 
ACL Editor
Step 4. The ACL editor form

This step has a key role in this example. It will illustrate the usage of TsvACLCenter component.

Well, create a new form and place the following components and controls on it:

  • Three buttons with captions 'Add', 'Delete' and 'Merge'
  • List view control and a label to it with caption 'ACL Entries'
  • TsvACLCneter component with name 'ACLC'
  • TsvSidCenter component with name 'SidC'

The resulting form will look like shown below:

This form will be main form of our application so you will need to make changes in the project options. Go to the Project|Options dialog, select the Forms tab and change the main form of application to the newly created form.

Well, now is a time to implement code of our form. Let's add the code to the 'Add' button:







 
 
 
 
 

 
 
 
 
 
 
 
 

 

 

procedure TACLEditorForm.BnAddClick(Sender: TObject);
var ULF: TUsersListForm;
    i: Integer;
    LI: TListItem;
    EA: PExplicitAccess;
begin
    ULF:=TUsersListForm.Create(nil);
    try
        if ULF.ShowModal <> mrOK then exit;
        for i:=0 to ULF.LVSelected.Items.Count-1 do
        begin
            LI:=ULF.LVSelected.Items[i];
            EA:=ACLC.AddEntry;
            SidC.Sid:=LI.Data;
            EA.Trustee.ptstrName:=SidC.GetSidCopy;
            EA.grfAccessMode:=ULF.AccessMode;
            EA.grfAccessPermissions:=ULF.AccessMask;
            AddListItem(EA);
        end;
    finally
        ULF.Release;
    end;
end;

I think that this code needs some comments. As you can see this handle creates an instance of TUsersListForm and shows it in the modal mode. As you remember TUsersListForm contains three important things: list of users (SIDs), access mask value and access mode value. If the form returns with ModalResult = mrOK then we iterate through all selected users and add the ExplicitAccessEntry for each user. To do it we use AddEntry of the ACLC component. This method adds new entry to the list of entries and returns a pointer to it. We use this pointer to initialize ExplicitAccessEntry fields. As you can see the following fields are necessary:

  • ptstrName - this filed points to the user's SID or the user's name. The TrusteeForm field is used to determine what form of user identification is used. In our example we do not modify the TrusteeForm field that is zero by default. The zero value corresponds to the TRUSTEE_IS_SID constant so we initialize the ptstrName field by SID pointer. Note that we use SidCenter component to get SID copy. The thing is that the UsersListForm will be released at the end of this event handler and original SID values will be lost.
  • grfAccessMode - this field receives the access mode value selected in TUsersListForm dialog.
  • grfAccessPermission - this field stores the access mask.

After initializing the ExplicitAccessEntry structure we need to add new item to the ListView. I've placed this code into separate function:







 
 

 

 
 


 


 
 
 
 
 

 


 
 
 

 
 

 
 

 

 
 

procedure TACLEditorForm.AddListItem(EA: PExplicitAccess);
var LI: TListItem;
    i: Integer;
    S: String;
    j: DWORD;
begin
    LI:=LvACL.Items.Add;

    if EA.Trustee.TrusteeForm = TRUSTEE_IS_SID then // convert to string
    begin
        SIDC.SID:=EA.Trustee.ptstrName; // SIDCenter will get info for us
        LI.Caption:=SIDC.Domain+'\'+SIDC.UserName;
    end else
    begin
        LI.Caption:=StrPas(EA.Trustee.ptstrName);
    end;

    case EA.grfAccessMode of
        GRANT_ACCESS: LI.SubItems.Add('Grant');
        SET_ACCESS: LI.SubItems.Add('Set');
        DENY_ACCESS: LI.SubItems.Add('Deny');
        REVOKE_ACCESS: LI.SubItems.Add('Revoke');
    else
        LI.SubItems.Add('???'); // It is error
    end;

    S:='';
    j:=1;
    for i:=1 to 32 do
    begin
        if (EA.grfAccessPermissions and j) <> 0 then
            S:='1'+S
        else
            S:='0'+S;
        j:=j shl 1;
    end;
    LI.SubItems.Add(S);

    LI.Data:=EA;
end;

This function looks large enough but it it`s work is simple :-). At first it adds new item to the ListView. Then it gets the readable name from the ptstrName field (do not forget that it can contain SID or name as a string) and assigns the ListItem caption. The next part of this function simply adds the subitem to the ListItem. This subitem shows the access mode. And finally this function generates one more ListItem subitem that consists of 32 symbols ('0' or '1') to illustrate bits of the access mask.

Well, now we can add items to the ListView and you can test our example now. Let's continue with adding 'Delete' button OnClick handler:






 
 
 

 

 
 
 
 



 

 
 
 
 

 

 

procedure TACLEditorForm.BnDeleteClick(Sender: TObject);
var i: Integer;
    L: TList;
    LI: TListItem;
begin
    L:=TList.Create;
    try
        // Place all selected items into list
        for i:=0 to LvACL.Items.Count-1 do
        begin
            LI:=LvACL.Items[i];
            if not LI.Selected then continue;
            L.Add(LI);
        end;

        // Delete all selected items
        // with associated access entries
        for i:=L.Count-1 downto 0 do
        begin
            LI:=TListItem(L[i]);
            ACLC.DeleteEntry(LI.Index);
            LI.Free;
        end;
    finally
        L.Free;
    end;
end;

There is nothing specific in this handler simply note how we use the DeleteEntry method of ACLC component. Finally let's add the OnClick handler for the 'Merge' button.





 
 
 

 

 
 
 

 
 

 
 
 

procedure TACLEditorForm.BnMergeClick(Sender: TObject);
var i: Integer;
    EA: PExplicitAccess;
begin
    ACLC.ACL:=ACLC.GetACLCopy;
    LvACL.Items.Clear;

    for i:=0 to ACLC.EntryCount-1 do
    begin
        EA:=ACLC.Entries[i];
        if EA.grfAccessMode = SET_ACCESS then
             EA.grfAccessMode:=GRANT_ACCESS;

        if EA.grfAccessMode = REVOKE_ACCESS then
             EA.grfAccessMode:=DENY_ACCESS;

        AddListItem(EA);
    end;
end;

This small piece of code is of great importance for understanding of ACLC component work. This component manipulates two forms of Access Control List. The first form is ACL pointer itself and the other form is the set of ExplicitAccessEntries. We can read both ACL property and the Entries property and the only question is: what property is the primary source and what property is slave. The answer is simple: the last changed property is used as primary source of ACL. So the simple lines of code






    ACLC.ACL:=ACLC.GetACLCopy;
    ... ACLC.EntryCount ... 

do a lot of work in background:

  • If the ACL property is not primary source of data (it will be slave after 'Add' or 'Delete' clicks) then Entries must be converted to the ACL. This conversion performed by ACLCenter internally and includes reordering of access control entries (deny entries first) and merges entries if necessary (access mode defines the rules).
  • It gets the copy of ACL. This copy will not be modified if we change properties of ACLCenter and we should not care about memory allocation/deallocation. The ACLC component will care about it.
  • Now it assigns ACL property of ACLC component. The ACL property is the primary source of access control data now!
  • Getting the EntryCount causes ACLC component to convert ACL back to the ExplicitAccessEntries set.

The only thing we should do after this conversion is to clear ListView and fill it with items again. Only one additional action is necessary. The thing is that the AccessMode field equals to SET_ACCESS or REVOKE_ACCESS after our conversion. The role of access modes is described in MS documentation. In brief it could be described as follows: When the set of ExplicitAccessEntries is converted into ACL each new entry to be added can affect entries added before. If access mode of newly added entry is SET_ACCESS then all existing entries with the same SID/user should be deleted. In other words SET_ACCESS access mode works like assignment operator that is previous variable value disappears and new sets. The GRANT_ACCESS access mode changes the previously added entries too. Of course only entries with the same user/SID are changed. In contrast to SET_ACCESS this mode does not discards previously added entries, it simply merges with them. It means that access mask of denying entries will loose bits that are set in the newly added entry while access allowing entries will get these bits. The DENY_ACCESS and REVOKE_ACCESS are the same as GRANT_ACCESS and SET_ACCESS modes except they are used to deny access. Returning to our code we see that changing of access mode in it is necessary. Let's imagine that after merge we have two entries in ACL for the same SID, one entry allows some access and the other denies some other access. What occurs at the second merge? If we retain SET_ACCESS and REVOKE_ACCESS modes in the code above then only one access control entry will be left after the second merge! The second entry will be discarded and the resulting ACL will be corrupted. The only way to protect both entries from deletion is to change the access modes :-).

Well, after these changes and explanations we are ready to test our example. We shall do it on the next step. Let's continue.

<< | Index | Step 1 | Step 2 | Step 3 | Step 4 | Step 5 | >>
Add your comment | Read comments


 
© 1998-2001 Alexey Dynnikov
My ICQ # is 18267212