Setting file security with JWSCL
28
Apr
Posted by: Christian Wimmer in: JEDI Windows Security Code Lib
Sometimes it is necessary to change the security settings of a file or folder for getting or denying write access. With JWSCL this task is made very easy. However there are some pitfalls to avoid.
The following code will also be available in the example section of the source code. The application gets a file or folder name as parameter and tries to add the user with full access control. It even tries to get ownership if it can’t change the access control list.
First of all we need some JWSCL classes:
- TJwSecurityDescriptor
A security descriptor contains all information about security of an object. It contains the owner and the access control list (also some other thing, we don’t need here)
- TJwSecureFileObject
This class provides methods to read and write security information on a file or folder. Despite its name it does also support folders. It even supports inheritance.
You can access a file or folder through its name, a handle or the VCL class TFileStream.
- TJwDAccessControlList
This class contains methods to maintain a discreationary access control list (DACL). A DACL contains a list of users and their possible access on the object.
- TJwSecurityId
Every user is identified by a unique number which is maintained by this class.
- TJwSecurityToken
Every logged on user gets a security pass which contains information what she can do or not. We mainly use it to retrieve the user’s SID (TJwSecurityID)
These classes are stored in the JWSCL units. We use the following ones:
-
uses
-
JwaWindows,
-
JwsclSid,
-
JwsclToken,
-
JwsclACl,
-
JwsclDescriptor,
-
JwsclSecureObjects,
-
JwsclKnownSid;
The units above are necessary and contain all the classes described earlier Of course we have to declare the classes:
-
var
-
UserToken : TJwSecurityToken;
-
SD : TJwSecurityDescriptor;
-
FileObject : TJwSecureFileObject;
-
Owner : TJwSecurityId;
-
DACL : TJwDAccessControlList;
-
begin
-
if not FileExists(ParamStr(1)) then
-
exit;
This example also shows how we can add well known Security Identifiers (SID) to a secured object. We have to initialize them. The variable JwWorldSID will then contain the correct SID for group Everyone. If we didn’t call it, we would get nil instead.
JwInitWellKnownSIDs;
The next steps are creating the classes. We get the user name through her token and save the SID into Owner.
Later we will use the Owner instance to add it into the security information of the object.
-
UserToken := TJwSecurityToken.CreateTokenEffective(MAXIMUM_ALLOWED);
-
Owner := UserToken.GetTokenOwner;
-
try
-
FileObject := TJwSecureFileObject.Create(ParamStr(1));
The actual class which does all the work on the file/folder is TJwSecureFileObject. We just apply the first parameter.
Notice: A user can only change security information of an object if she has the right to do it. There are two options to allow it.
- The user is listed in the DACL. Additionally the right WRITE_DAC is granted for her.
- The user is the owner. In this case she don’t need to be listed and allowed in the DACL. It is automatically granted
We can check both version in one call.
-
try
-
if not FileObject.AccessCheck(WRITE_DAC)
-
begin
This call is very easy. If we can’t change the DACL, we can try to become the owner. The only way to become an owner is to enable a privilege called SE_TAKE_OWNERSHIP_NAME. It is usually only granted to Administrators.
-
JwEnablePrivilege(SE_TAKE_OWNERSHIP_NAME, pst_Enable);
-
FileObject.Owner := Owner;
-
end;
JwEnablePrivilege will fail, if it can’t activate the privilege. Otherwise we can set the file/folder’s owner to the token user.
The main work is done here. We get the default DACL from the existing object and adapt it.
Adaption is done by adding the user to the DACL with full control. We additionally allow the Everyone group to demonstrate the well known Sids initialized by JwInitWellKnownSIDs. The last parameters (false) define that we don’t want the list to free the given SIDs (Owner and JwWorldSid) automatically.
-
DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create
-
(nil, [], GENERIC_ALL, Owner, false));
-
DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create
-
(nil, [], GENERIC_READ, JwWorldSID, false));
And finally we reset the DACL.
-
FileObject.SetDACL(DACL);
The DACL of the file or folder will receive the newly created control entries in addition to its existing ones. If it contains inherited entries (entries from a parent folder) they will be conserved. However if you don’t retrieve the DACL and just use an empty one, all previously existing entries which are not inherited will be removed. Of course the inherited entries will still remain intact.
And of course we free all allocated resources
-
finally
-
FileObject.Free;
-
end;
-
-
finally
-
Owner.Free;
-
UserToken.Free;
-
end;
-
end.
Since I cut the source code into pieces, I’ll show it here in full glory
-
program SetFileSecurity;
-
-
{$APPTYPE CONSOLE}
-
-
uses
-
SysUtils,
-
JwaWindows,
-
JwsclSid,
-
JwsclToken,
-
JwsclAcl,
-
JwsclDescriptor,
-
JwsclSecureObjects,
-
JwsclKnownSid;
-
-
var
-
UserToken : TJwSecurityToken;
-
SD : TJwSecurityDescriptor;
-
FileObject : TJwSecureFileObject;
-
Owner : TJwSecurityId;
-
DACL : TJwDAccessControlList;
-
begin
-
if not FileExists(ParamStr(1)) then
-
exit;
-
-
JwInitWellKnownSIDs;
-
-
UserToken := TJwSecurityToken.CreateTokenEffective(MAXIMUM_ALLOWED);
-
Owner := UserToken.GetTokenOwner;
-
try
-
FileObject := TJwSecureFileObject.Create(ParamStr(1));
-
try
-
//Make me owner if we cant access DACL
-
if not FileObject.AccessCheck(WRITE_DAC) then
-
begin
-
//try to become owner
-
JwEnablePrivilege(SE_TAKE_OWNERSHIP_NAME, pst_Enable);
-
FileObject.Owner := Owner;
-
end;
-
-
DACL := FileObject.DACL;
-
DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create(nil, [], GENERIC_ALL, Owner, false));
-
DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create(nil, [], GENERIC_READ, JwWorldSID, false));
-
-
FileObject.SetDACL(DACL);
-
finally
-
FileObject.Free;
-
end;
-
-
finally
-
Owner.Free;
-
UserToken.Free;
-
end;
-
end.
convert this post to pdf.
One Response
GunSmoker
15|Jul|2008 1Great post, thank you!
Leave a reply