Win32::Security::ACE - Win32 ACE manipulation
Win32::Security::ACE
use Win32::Security::ACE; my $ace = Win32::Security::ACE->new('FILE', $rawace); my $ace2 = Win32::Security::ACE->new('FILE', $type, $flags, $mask, $trustee); my $ace3 = Win32::Security::ACE->new('FILE', $type, $flags, $mask, $sid); $ace->objectType(); $ace->aceType(); $ace->aceFlags(); $ace->accessMask(); $ace->sid(); $ace->trustee(); $ace->explainAceFlags(); $ace->explainAccessMask(); $ace->rawAce(); $ace->rawAceType(); $ace->rawAceFlags(); $ace->rawAccessMask(); my(@container_inheritable_aces) = $ace->inheritable('CONTAINER'); my(@object_inheritable_aces) = $ace->inheritable('OBJECT');
Win32::Security::ACE and its subclasses provide an interface for interacting with Win32 ACEs (Access Control Entries). The subclasses allow for variation in mask behavior (different privileges apply to files than apply to registry keys and so forth) and for variation in ACE behavior (OBJECT_ACE_TYPE varieties).
OBJECT_ACE_TYPE
Win32::Security::ACE uses the flyweight design pattern in conjunction with an in-memory cache of demand-computed properties. The result is that parsing of ACEs is only done once for each unique ACE, and that the ACE objects themselves are very lightweight. Double-indirection is used in the ACE objects to provide for mutability without invalidating the cache.
This installs as part of Win32-Security. See Win32::Security::NamedObject for more information.
Win32-Security
Win32::Security::NamedObject
It depends upon Class::Prototyped and Data::BitMask, which should be installable via PPM or available on CPAN. It also depends upon Win32::Security::Raw and Win32::Security::SID , which are installed as part of Win32-Security.
Class::Prototyped
Data::BitMask
Win32::Security::Raw
Win32::Security::SID
Win32::Security::ACE uses some OO tricks to boost performance and clean up the design. Here's a quick overview of the internal architecture, should you care! It is possible to use Win32::Security::ACE objects without understanding or reading any of this, because the public interface is designed to hide as much of the details as possible. After all, that's the point of OO design. If, however, you want to boost performance or to muck about in the internals, it's worth understanding how things were done.
Win32::Security::ACE uses multiple inheritance in a diamond pattern. This was deemed to be the best solution to an otherwise ugly situation.
Each ACE comes in a variety of forms - six at current count - and some of these forms (notably the OBJECT_ACE_TYPE varieties) use a different internal structure. While the code doesn't currently support the OBJECT_ACE_TYPE varieties, it was important to architect the code to support that for future expansion.
Each ACE can be applied to a wide variety of Named Objects as well. For better or worse, the behavior of the Access Masks for Named Objects varies according to the type of Named Object (think files vs. Active Directory objects). This behavioral variation extends to the realm of applying inherited GENERIC Access Masks to objects.
Much internal debate (I love arguing with myself) was expended over attempting to reconcile these two orthogonal forms of variation without multiple inheritance before deciding to just bite the bullet.
The obvious ugliness is that number_of_ace_types * number_of_object_types classes have to be created. Luckily I'd already made Win32::Security::Recursor dependent upon Class::Prototyped, so it was deemed acceptable to make Win32::Security::ACE and Win32::Security::ACL dependent upon it as well.
number_of_ace_types * number_of_object_types
Win32::Security::Recursor
Win32::Security::ACL
With that in mind, the base class hierarchy looks like this:
Base class of everything. Includes rawAce, new, clone, dbmAceType, and the dbmObjectType methods.
rawAce
new
clone
dbmAceType
dbmObjectType
Win32::Security::ACE::_AceType
Abstract base class for behavior linked to the ACE type. This includes the /.*[aA]ceType$/, /.*[aA]ceFlags$/, sid, trustee, buildRawAce, and /^inheritable.*/ methods. All of the direct subclasses of _AceType are abstract as well. The package names have been collapsed by leaving out _AceType to keep things manageable.
/.*[aA]ceType$/
/.*[aA]ceFlags$/
sid
trustee
buildRawAce
/^inheritable.*/
_AceType
Win32::Security::ACE::ACCESS_ALLOWED_ACE_TYPE
Win32::Security::ACE::ACCESS_DENIED_ACE_TYPE
Win32::Security::ACE::SYSTEM_AUDIT_ACE_TYPE
Win32::Security::ACE::_ObjectType
Abstract base class for behavior linked to the Named Object type. This includes the objectType and /.*[aA]ccessMask$/ methods. In addition, as will later be discussed, each of the following classes is responsible for storing the cached instance data for all ACEs they run into. Just like in _AceType, all of the direct subclasses of _ObjectType are abstract as well and the package names have been collapsed.
objectType
/.*[aA]ccessMask$/
_ObjectType
Win32::Security::ACE::SE_FILE_OBJECT
The concrete classes are named Win32::Security::ACE::$objectType::$aceType (i.e. Win32::Security::ACE::SE_FILE_OBJECT::ACCESS_ALLOWED_ACE_TYPE) and inherit from both the Win32::Security::ACE::$objectType and Win32::Security::ACE::$aceType classes in that order. The concrete classes are automatically generated using Class::Prototyped.
Win32::Security::ACE::$objectType::$aceType
Win32::Security::ACE::SE_FILE_OBJECT::ACCESS_ALLOWED_ACE_TYPE
Win32::Security::ACE::$objectType
Win32::Security::ACE::$aceType
On the typical computer systems, there are very few unique ACEs. There may be hundred or thousands, but usually there are orders of magnitude fewer ACEs than there are objects to which they are applied. In order to reduce the computation involved in analyzing them, Win32::Security::ACE caches all the information computed about each ACE in a central store (actually, multiple central stores - one for each Named Object type) based on the binary form (rawAce). The object returned by a call to new is a reference to a reference to the hash for that rawAce in the central store. Because it isn't a direct reference to the hash, it is possible to switch which hash the object points to on the fly. This allows the Win32::Security::ACE objects to be mutable while maintaining the immutability of the central store. It also makes each individual Win32::Security::ACE object incredibly lightweight, since it is only composed of a single blessed scalar. The properties are computed as needed, but the results are cached in the central store.
For instance, once explainAccessMask has been computed for a given rawAce, it can be found from the object as $$self->{explainAccessMask}. This should be used with care, although in some instances it is possible to reduce the number of method calls (should this be necessary for performance reasons) by making calls like so:
explainAccessMask
$$self->{explainAccessMask}
$$ace->{explainAccessMask} || $ace->explainAccessMask();
That provides a fail-safe should the explainAccessMask value have not yet been computed while eliminating the method call if it has been.
In order to defend against accidental manipulation, return values from the calls (although not from the direct access, obviously) are deep-copied one layer deep. That means that the results of $ace->explainAccessMask() can be safely manipulated without harming the ACE, but that the results of $$ace->{explainAccessMask} should be treated as read-only. Win32::Security::ACE objects returned are cloned (using inlined code to reduce the performance hit). The values returned from the /^dbm.*/ calls are not cloned, however, so be careful there.
$ace->explainAccessMask()
$$ace->{explainAccessMask}
/^dbm.*/
Creates a new Win32::Security::ACE object.
The various calling forms are:
Win32::Security::ACE->new($objectType, $rawAce)
Win32::Security::ACE->new($objectType, $aceType, @aceParams)
"Win32::Security::ACE::$objectType"->new($rawAce)
"Win32::Security::ACE::$objectType"->new($aceType, @aceParams)
"Win32::Security::ACE::$objectType\::$aceType"->new($rawAce)
"Win32::Security::ACE::$objectType\::$aceType"->new(@aceParams)
$ace_object->new($rawAce)
$ace_object->new(@aceParams)
Note that when using $objectType and $aceType in the package name, the values need to be canonicalized (i.e. SE_FILE_OBJECT, not the alias FILE). Also note that the $aceType is extractable from the $rawAce. When those values are passed as part of the parameter list, any of the valid aliases are permitted. If the $objectType or $aceType has already been canonicalized, improved performance can be realized by making the call on the more fully-qualified package name and thus avoiding the calls to redo the canonicalization. It is important that if $aceType is specified for a $rawAce that the values match. The backslash preceding the final :: in the final two class name calls is a fast way of ensuring that $objectType rather than $objectType:: is the interpolated variable name.
$objectType
$aceType
SE_FILE_OBJECT
FILE
$rawAce
::
$objectType::
For ACCESS_ALLOWED_ACE_TYPE, ACCESS_DENIED_ACE_TYPE, and SYSTEM_AUDIT_ACE_TYPE, the @aceParams array consists of aceFlags, accessMask, and either the sid or trustee. The aceType, aceFlags, and accessMask can be passed as integers or in any acceptable format for Data::BitMask (i.e. '|' separated constants in a string, an anonmous array of constants, or an anonymous hash of constants). See Data::BitMask::buildRawMask for more information.
ACCESS_ALLOWED_ACE_TYPE
ACCESS_DENIED_ACE_TYPE
SYSTEM_AUDIT_ACE_TYPE
@aceParams
aceFlags
accessMask
aceType
'|'
Data::BitMask::buildRawMask
This creates a new Win32::Security::ACE object that is identical in all forms, except for identity, to the original object. Because of the flyweight design pattern, this is a very inexpensive operation. However, should you wish to avoid the overhead of a method call, you can inline the code like so:
bless(\(my $o = ${$obj}), ref($obj));
Basically, it derefences the scalar reference, assigns it to a temporary lexical, creates a reference to that, and then blesses it into the original package. Nifty, eh? Syntax stolen (with a few modifications) from Data::Dumper output.
Data::Dumper
dump
This returns a dump of the Win32::Security::ACL object in a format useful for debugging.
Returns the binary string form of the ACE. If passed a value, changes the binary string form of the ACE to the new value and returns $self.
$self
Returns the Data::BitMask object for interacting with ACE Types. Standard Win32 constants for ACE_TYPE are supported along with several aliases. The standard ACE_TYPE constants are ACCESS_ALLOWED_ACE_TYPE, ACCESS_DENIED_ACE_TYPE, SYSTEM_AUDIT_ACE_TYPE, SYSTEM_ALARM_ACE_TYPE, ACCESS_ALLOWED_COMPOUND_ACE_TYPE, ACCESS_ALLOWED_OBJECT_ACE_TYPE, ACCESS_DENIED_OBJECT_ACE_TYPE, SYSTEM_AUDIT_OBJECT_ACE_TYPE, SYSTEM_ALARM_OBJECT_ACE_TYPE, ACCESS_MIN_MS_ACE_TYPE, ACCESS_MAX_MS_V2_ACE_TYPE, ACCESS_MAX_MS_V3_ACE_TYPE, ACCESS_MIN_MS_OBJECT_ACE_TYPE, ACCESS_MAX_MS_OBJECT_ACE_TYPE, ACCESS_MAX_MS_V4_ACE_TYPE, and ACCESS_MAX_MS_ACE_TYPE.
ACE_TYPE
SYSTEM_ALARM_ACE_TYPE
ACCESS_ALLOWED_COMPOUND_ACE_TYPE
ACCESS_ALLOWED_OBJECT_ACE_TYPE
ACCESS_DENIED_OBJECT_ACE_TYPE
SYSTEM_AUDIT_OBJECT_ACE_TYPE
SYSTEM_ALARM_OBJECT_ACE_TYPE
ACCESS_MIN_MS_ACE_TYPE
ACCESS_MAX_MS_V2_ACE_TYPE
ACCESS_MAX_MS_V3_ACE_TYPE
ACCESS_MIN_MS_OBJECT_ACE_TYPE
ACCESS_MAX_MS_OBJECT_ACE_TYPE
ACCESS_MAX_MS_V4_ACE_TYPE
ACCESS_MAX_MS_ACE_TYPE
The aliases are:
ALLOWED or ALLOW (ACCESS_ALLOWED_ACE_TYPE)
ALLOWED
ALLOW
DENIED or DENY (ACCESS_DENIED_ACE_TYPE)
DENIED
DENY
AUDIT (SYSTEM_AUDIT_ACE_TYPE)
AUDIT
Returns the Data::BitMask object for interacting with Named Object Types. The standard Object Types are SE_UNKNOWN_OBJECT_TYPE, SE_FILE_OBJECT, SE_SERVICE, SE_PRINTER, SE_REGISTRY_KEY, SE_LMSHARE, SE_KERNEL_OBJECT, SE_WINDOW_OBJECT, SE_DS_OBJECT, SE_DS_OBJECT_ALL, and SE_PROVIDER_DEFINED_OBJECT.
SE_UNKNOWN_OBJECT_TYPE
SE_SERVICE
SE_PRINTER
SE_REGISTRY_KEY
SE_LMSHARE
SE_KERNEL_OBJECT
SE_WINDOW_OBJECT
SE_DS_OBJECT
SE_DS_OBJECT_ALL
SE_PROVIDER_DEFINED_OBJECT
There are a number of aliases as well:
FILE (SE_FILE_OBJECT)
SERVICE (SE_SERVICE)
SERVICE
PRINTER (SE_PRINTER)
PRINTER
REG (SE_REGISTRY_KEY)
REG
REGISTRY (SE_REGISTRY_KEY)
REGISTRY
SHARE (SE_LMSHARE)
SHARE
rawAceType
Returns the integer form of the ACE Type. Useful for equality checks with other calls to rawAceType.
Returns the Data::BitMask::explain_const form of the ACE Type (i.e. a string constant, such as 'ACCESS_ALLOWED_ACE_TYPE' or 'ACCESS_DENIED_ACE_TYPE').
Data::BitMask::explain_const
'ACCESS_ALLOWED_ACE_TYPE'
'ACCESS_DENIED_ACE_TYPE'
dbmAceFlags
Returns the Data::BitMask object for interacting with ACE Flags. Standard Win32 constants for ACE_FLAGS are supported along with some aliases. The standard ACE_FLAGS constants are OBJECT_INHERIT_ACE, CONTAINER_INHERIT_ACE, NO_PROPAGATE_INHERIT_ACE, INHERIT_ONLY_ACE, INHERITED_ACE, SUCCESSFUL_ACCESS_ACE_FLAG, and FAILED_ACCESS_ACE_FLAG.
ACE_FLAGS
OBJECT_INHERIT_ACE
CONTAINER_INHERIT_ACE
NO_PROPAGATE_INHERIT_ACE
INHERIT_ONLY_ACE
INHERITED_ACE
SUCCESSFUL_ACCESS_ACE_FLAG
FAILED_ACCESS_ACE_FLAG
SUBFOLDERS_AND_FILES_ONLY (CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE)
SUBFOLDERS_AND_FILES_ONLY
CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE
FULL_INHERIT or FI (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE)
FULL_INHERIT
FI
OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE
FILES_ONLY (INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE)
FILES_ONLY
INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE
SUBFOLDERS_ONLY (CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE)
SUBFOLDERS_ONLY
CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE
CI (CONTAINER_INHERIT_ACE)
CI
OI (OBJECT_INHERIT_ACE)
OI
IO (INHERIT_ONLY_ACE)
IO
NP (NO_PROPAGATE_INHERIT_ACE)
NP
rawAceFlags
Returns the integer form of the ACE Flags. Useful for equality checks with other calls to rawAceFlags.
If called with a passed parameter, mutates the ACE to that new aceFlags value. All forms of aceFlags access accept all forms as parameters when used as a setter.
Returns the Data::BitMask::break_mask form of the ACE Flags (i.e. a hash containing all matching constants for the Flags mask of the ACE).
Data::BitMask::break_mask
explainAceFlags
Returns the Data::BitMask::explain_mask form of the ACE Flags (i.e. a hash containing a set of constants sufficient to recreate and explain the flags mask of the ACE).
Data::BitMask::explain_mask
Returns the SID in binary form. Useful for equality checks with other SIDs.
If called with a passed parameter, mutates the ACE to that new SID. Both sid and trustee accepts SID and Trustee names as passed parameters when used as a setter.
Returns the Trustee for the SID as generated by Win32::Security::SID::ConvertSidToName.
Win32::Security::SID::ConvertSidToName
If called with a passed parameter, mutates the ACE to that new trustee. Both sid and trustee accepts SID and Trustee names as passed parameters when used as a setter.
Creates a binary string ACE from parameters. This should always be called on a full class (i.e. Win32::Security::ACE::$objectType::$aceType). Each implementation accepts different parameters.
These accept AceFlags, AccessMask, and either Sid or Trustee.
AceFlags
AccessMask
Sid
Trustee
buildRawAceNamed
Creates a binary string ACE from named parameters. This should always be called on a full class (i.e. Win32::Security::ACE::$objectType::$aceType) or on an existing ACE. Each implementation accepts different parameters. If called on an existing ACE, missing parameters will be supplied from the existing ACE. As an example, to create a new rawAce value based on an existing ACE, but with the Access Mask set to READ:
READ
$ace->buildRawAceNamed(accessMask => 'READ');
These accept aceFlags, accessMask, and trustee (as either a SID or Trustee name). The names are case-sensitive.
inheritable
Accepts a type (either 'OBJECT' or 'CONTAINER') and calls inheritable_OBJECT or inheritable_CONTAINER as appropriate.
'OBJECT'
'CONTAINER'
inheritable_OBJECT
inheritable_CONTAINER
Those methods return the list of ACEs that would be inherited by a newly created child OBJECT or CONTAINER if the parent has this ACE. In most cases, there will be either none (non-inheritable ACE) or one (inheritable ACE) ACEs returned. In the case of ACEs that use GENERIC_.* permissions or that use CREATOR OWNER, there may be two ACEs returned - one to implement the permissions on that specific container, and the other to perpetuate the inheritable ACE. In the case of an CREATOR OWNER ACE, the ACE that implements the actual permissions on the container will be given a null SID.
OBJECT
CONTAINER
GENERIC_.*
CREATOR OWNER
The methods take care of checking the flags to determine whether the ACE should be inherited as well as adjusting the flags for any inherited ACE appropriately.
Note that it is not sufficient to simply concatenate the ACEs of a DACL to generate the inheritable DACL because Win2K and WinXP remove occluded permissions (for instance, if an container has an inherited permission granting READ access to Domain Users and someone grants explicit fully-inheritable FULL access to Domain Users to that container, child objects will not receive the inherited READ access because it is fully occluded by the also inherited FULL access).
FULL
See inheritable for an explanation.
Returns the type of object to which the ACE is or should be attached.
dbmAccessMask
Returns the Data::BitMask object for interacting with the Access Mask. The default is Win32 constants for Standard Rights. Some of the Object Types define additional rights. The Standard Rights are DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, SYNCHRONIZE, STANDARD_RIGHTS_REQUIRED, STANDARD_RIGHTS_READ, STANDARD_RIGHTS_WRITE, STANDARD_RIGHTS_EXECUTE, STANDARD_RIGHTS_ALL, SPECIFIC_RIGHTS_ALL, ACCESS_SYSTEM_SECURITY, MAXIMUM_ALLOWED, GENERIC_READ, GENERIC_WRITE, GENERIC_EXECUTE, and GENERIC_ALL.
DELETE
READ_CONTROL
WRITE_DAC
WRITE_OWNER
SYNCHRONIZE
STANDARD_RIGHTS_REQUIRED
STANDARD_RIGHTS_READ
STANDARD_RIGHTS_WRITE
STANDARD_RIGHTS_EXECUTE
STANDARD_RIGHTS_ALL
SPECIFIC_RIGHTS_ALL
ACCESS_SYSTEM_SECURITY
MAXIMUM_ALLOWED
GENERIC_READ
GENERIC_WRITE
GENERIC_EXECUTE
GENERIC_ALL
Win32 constants for both Standard Rights and File Rights, along with a number of aliases. The File Rights are FILE_READ_DATA, FILE_LIST_DIRECTORY, FILE_WRITE_DATA, FILE_ADD_FILE, FILE_APPEND_DATA, FILE_ADD_SUBDIRECTORY, FILE_CREATE_PIPE_INSTANCE, FILE_READ_EA, FILE_WRITE_EA, FILE_EXECUTE, FILE_TRAVERSE, FILE_DELETE_CHILD, FILE_READ_ATTRIBUTES, FILE_WRITE_ATTRIBUTES, FILE_ALL_ACCESS, FILE_GENERIC_READ, FILE_GENERIC_WRITE, and FILE_GENERIC_EXECUTE.
FILE_READ_DATA
FILE_LIST_DIRECTORY
FILE_WRITE_DATA
FILE_ADD_FILE
FILE_APPEND_DATA
FILE_ADD_SUBDIRECTORY
FILE_CREATE_PIPE_INSTANCE
FILE_READ_EA
FILE_WRITE_EA
FILE_EXECUTE
FILE_TRAVERSE
FILE_DELETE_CHILD
FILE_READ_ATTRIBUTES
FILE_WRITE_ATTRIBUTES
FILE_ALL_ACCESS
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
FULL or F (STANDARD_RIGHTS_ALL | FILE_GENERIC_READ |FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | FILE_DELETE_CHILD)
F
STANDARD_RIGHTS_ALL | FILE_GENERIC_READ |FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | FILE_DELETE_CHILD
MODIFY or M (FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE)
MODIFY
M
FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE
READ or R (FILE_GENERIC_READ | FILE_GENERIC_EXECUTE)
R
FILE_GENERIC_READ | FILE_GENERIC_EXECUTE
Win32 constants for Registry Key Rights. The Registry Key Rights are KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_LINK, KEY_WOW64_64, KEY_WOW64_32KEY, KEY_READ, KEY_WRITE, KEY_EXECUTE, and KEY_ALL_ACCESS.
KEY_QUERY_VALUE
KEY_SET_VALUE
KEY_CREATE_SUB_KEY
KEY_ENUMERATE_SUB_KEYS
KEY_NOTIFY
KEY_CREATE_LINK
KEY_WOW64_64
KEY_WOW64_32KEY
KEY_READ
KEY_WRITE
KEY_EXECUTE
KEY_ALL_ACCESS
SE_REGISTRY_KEY support is still under development.
rawAccessMask
Returns the integer form of the Access Mask. Useful for equality checks and bitwise comparisons with other calls to rawmask.
rawmask
If called with a passed parameter, mutates the ACE to that new accessMask value. All forms of accessMask access accept all forms as parameters when used as a setter.
Returns the Data::BitMask::break_mask form of the Access Mask (i.e. a hash containing all matching constants for the Access Mask of the ACE).
Returns the Data::BitMask::explain_mask form of the Access Mask (i.e. a hash containing a set of constants sufficient to recreate and explain the Access Mask of the ACE).
cleansedAccessMask
This returns an Access Mask cleansed of GENERIC_ permissions for the ACE in question. Some of the Object Types define special behavior for this.
GENERIC_
Clears the GENERIC_READ, GENERIC_WRITE, GENERIC_EXECUTE, and GENERIC_ALL bits and replaces them with the constants FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, and FULL respectively. This is required for correctly interpreting inheritance of some INHERIT_ONLY_ACE ACEs.
Toby Ovod-Everett, toby@ovod-everett.org
To install Win32::Security::SID, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Win32::Security::SID
CPAN shell
perl -MCPAN -e shell install Win32::Security::SID
For more information on module installation, please visit the detailed CPAN module installation guide.