Win32::Security::ACE - Win32 ACE manipulation |
new
clone
dump
rawAce
dbmAceType
dbmObjectType
rawAceType
aceType
dbmAceFlags
rawAceFlags
aceFlags
explainAceFlags
sid
trustee
buildRawAce
buildRawAceNamed
inheritable
inheritable_CONTAINER
inheritable_OBJECT
objectType
dbmAccessMask
rawAccessMask
accessMask
explainAccessMask
cleansedAccessMask
Win32::Security::ACE
- Win32 ACE manipulation
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).
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.
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
.
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.
With that in mind, the base class hierarchy looks like this:
Win32::Security::ACE
rawAce
, new
, clone
, dbmAceType
,
and the dbmObjectType
methods.
Win32::Security::ACE::_AceType
/.*[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.
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
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.
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
.
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:
$$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 clone
d (using inlined code to
reduce the performance hit). The values returned from the /^dbm.*/
calls are
not cloned, however, so be careful there.
new
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.
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.
clone
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.
dump
This returns a dump of the Win32::Security::ACL
object in a format useful for
debugging.
rawAce
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
.
dbmAceType
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
.
The aliases are:
ALLOWED
or ALLOW
(ACCESS_ALLOWED_ACE_TYPE
)
DENIED
or DENY
(ACCESS_DENIED_ACE_TYPE
)
AUDIT
(SYSTEM_AUDIT_ACE_TYPE
)
dbmObjectType
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
.
There are a number of aliases as well:
FILE
(SE_FILE_OBJECT
)
SERVICE
(SE_SERVICE
)
PRINTER
(SE_PRINTER
)
REG
(SE_REGISTRY_KEY
)
REGISTRY
(SE_REGISTRY_KEY
)
SHARE
(SE_LMSHARE
)
rawAceType
Returns the integer form of the ACE Type. Useful for equality checks with other
calls to rawAceType
.
aceType
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'
).
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
.
The aliases are:
SUBFOLDERS_AND_FILES_ONLY
(CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE
)
FULL_INHERIT
or FI
(OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE
)
FILES_ONLY
(INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE
)
SUBFOLDERS_ONLY
(CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE
)
CI
(CONTAINER_INHERIT_ACE
)
OI
(OBJECT_INHERIT_ACE
)
IO
(INHERIT_ONLY_ACE
)
NP
(NO_PROPAGATE_INHERIT_ACE
)
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.
aceFlags
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).
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.
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).
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.
sid
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.
trustee
Returns the Trustee for the SID as generated by
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.
buildRawAce
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.
ACCESS_ALLOWED_ACE_TYPE
, ACCESS_DENIED_ACE_TYPE
, SYSTEM_AUDIT_ACE_TYPE
AceFlags
, AccessMask
, and either Sid
or 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
:
$ace->buildRawAceNamed(accessMask => 'READ');
ACCESS_ALLOWED_ACE_TYPE
, ACCESS_DENIED_ACE_TYPE
, SYSTEM_AUDIT_ACE_TYPE
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.
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.
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).
inheritable_CONTAINER
See inheritable
for an explanation.
inheritable_OBJECT
See inheritable
for an explanation.
objectType
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
.
SE_FILE_OBJECT
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
.
The aliases are:
FULL
or 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
)
READ
or R
(FILE_GENERIC_READ | FILE_GENERIC_EXECUTE
)
SE_REGISTRY_KEY
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
.
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
.
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.
accessMask
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).
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.
explainAccessMask
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).
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.
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.
SE_FILE_OBJECT
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
Win32::Security::ACE - Win32 ACE manipulation |