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:
These classes are stored in the JWSCL units. We use the following ones:
The units above are necessary and contain all the classes described earlier Of course we have to declare the classes:
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.
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.
We can check both version in one call.
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 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.
And finally we reset the 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
Owner.Free;
UserToken.Free;
end;
end.
Since I cut the source code into pieces, I’ll show it here in full glory
{$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.
3 Responses
GunSmoker
15|Jul|2008 1Great post, thank you!
mtjs
05|Feb|2009 2Hi,
Situation: users login on a domein controler.
I would like : to have a directory on the LOCAL computer where that everyone has access to. Normally the directory would be
C:\Documents and Settings\All Users\Application Data
Yet is not so if you login under a domain.
I’ve tried via a service (so with the SYSTEM account) to make a directory with all rights for everyone yet this fails. I use :
DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create(nil, [], GENERIC_ALL, JwUsersSID, false));
What am I doing wrong ?
Thanx!
Kind regards,
mtjs.
Christian Wimmer
05|Feb|2009 3Please consider the following:
1. The everyone SID is “JwWorldSID”
2. The empty set (you see []) is the way to define how the ACE is inherited to the folder’s childs. You must set it for folders.
3. On Vista the given folder is not valid. It has changed to sth. similar like C:\Users\Default\AppData (don’t rely on that info from me though)
4. The DACL is really changed in the line with SetDACL not where the ACE object is added to a separate list.
5. Check the any exception.
6. The folder is even protected against SYSTEM access if SYSTEM has no ACE in the DACL.
Leave a reply